/* * IvyDaemon, an Ivy gateway for short-lived agents * * Copyright (C) 1999 * Centre d'Études de la Navigation Aérienne * * Main file for the super-daemon * * Author(s): Stephane Chatty * from code by Patrick Amar * * $Id$ * * Please refer to file version.h for the * copyright notice regarding this software * */ /* * The super-demon (in.ivyd): * * It is either launched by inetd with the socket SOCK_DGRAM on file descriptor 0, * or at boot time with the -boot flag. * * The daemon (ivyd): * * It sends the super-daemon a message connmsg of type MSG_SERVER that contains * the port number of the socket it connected to. * * The clients (ivyecho, ...): * * They send the super-daemon a message connmsg of type MSG_CLIENT * to ask for the port number * * L'identification de l'emetteur du paquet est le numero d'utilisateur. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ivyd.h" const char* const dumpfilename = "/tmp/in.ivyd.db"; const int dumpfilemode = 0644; const char* const servicename = "ivyd"; const char* const port_env_variable = "INIVYD_PORT"; const int default_port = 3006; /* * The association table managed by the super-daemon */ typedef struct { short s_port; /* port number */ short s_key; /* server id */ } serverinfo; #define TABSIZ 64 /* 64 simultaneous servers are allowed */ serverinfo si_table [TABSIZ]; serverinfo* GetInfo (int key) { register serverinfo *si; register serverinfo *res = 0; for (si = si_table; si - si_table < TABSIZ; ++si) { if (si->s_port == 0) { if (! res) res = si; continue; } if (si->s_key != key) continue; res = si; break; } return res; } /* * DumpInfo () * * Dumps to a file the contents of the table */ int DumpInfo () { register serverinfo *si; register int fd = creat (dumpfilename, dumpfilemode); char buf [512]; if (fd == -1) return 0; for (si = si_table; si - si_table < TABSIZ; ++si) { if (! si->s_port) continue; (void) sprintf (buf, "user %5d, port %d\n", si->s_key, ntohs (si->s_port)); (void) write (fd, buf, strlen (buf)); } (void) close (fd); return 1; } void SigHup (int sig) { DumpInfo (); } void main (int argc, const char **argv) { struct servent *serv; u_short serv_port = 0; struct sockaddr_in from; int fromlen; struct connmsg msg; register serverinfo *si; int boot = 0; int debug = 0; (void) signal (SIGHUP, SigHup); serv = getservbyname (servicename, 0); if (! serv) { char *pp = getenv (port_env_variable); serv_port = htons (pp ? atoi (pp) : default_port); if (serv_port <= 0) exit (0); } else serv_port = serv -> s_port; ++argv; while (argc > 1) { if (strcmp (*argv, "-boot") == 0 || strcmp (*argv, "-b") == 0) boot = 1; else if (strcmp (*argv, "-debug") == 0 || strcmp (*argv, "-d") == 0) debug = 1; else fprintf (stderr, "bad option %s\n", *argv); ++argv; --argc; } /* special case when launched at boot time (ie. not from inetd) */ if (boot) { /* in normal mode, we behave as a daemon with no terminal */ if (!debug) { int s; /* first let's fork... */ if (fork ()) exit (0); /* ...then let's close all descriptors... */ for (s = getdtablesize (); --s >= 0;) close (s); /* ... and get rid of our control terminal */ if (-1 != open ("/dev/tty", 2)) { (void) ioctl (0, TIOCNOTTY, 0); close (0); } } else close (0); /* Now it's time to open the socket for requests */ if (-1 == socket (AF_INET, SOCK_DGRAM, 0)) exit (1); memset (&from, 0, sizeof from); from.sin_family = AF_INET; from.sin_port = serv_port; from.sin_addr.s_addr = INADDR_ANY; if (-1 == bind (0, &from, sizeof from)) exit (1); } /* now we can handle messages and requests */ for (;;) { fromlen = sizeof from; if (recvfrom (0, (char *)&msg, sizeof msg, 0, (struct sockaddr *)&from, &fromlen) <= 0) { if (errno == EINTR) continue; exit (1); } si = GetInfo (msg.msg_key); switch (msg.msg_type) { /* message from server: we store the information */ case MSG_SERVER: si->s_port = msg.msg_port; si->s_key = msg.msg_key; break; /* message from a client: we retrieve and send the information */ case MSG_CLIENT: msg.msg_port = si->s_port; msg.msg_type = MSG_REPLY; (void) sendto (0, (char *)&msg, sizeof msg, 0, (struct sockaddr *)&from, fromlen); break; } } }