From f2203b40cf372462e5277b1b530561e929636ee1 Mon Sep 17 00:00:00 2001 From: chatty Date: Mon, 15 Feb 1999 09:17:36 +0000 Subject: Initial revision --- src/Makefile | 55 +++++++++++ src/inivyd.c | 221 +++++++++++++++++++++++++++++++++++++++++ src/ivyd.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/ivyd.h | 62 ++++++++++++ src/ivyecho.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 922 insertions(+) create mode 100644 src/Makefile create mode 100644 src/inivyd.c create mode 100644 src/ivyd.c create mode 100644 src/ivyd.h create mode 100644 src/ivyecho.c (limited to 'src') diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..b2e6a8b --- /dev/null +++ b/src/Makefile @@ -0,0 +1,55 @@ +# +# IvyDaemon, an Ivy gateway for short-lived agents +# +# Copyright (C) 1999 +# Centre d'Études de la Navigation Aérienne +# +# Makefile +# +# Author(s): Stephane Chatty +# +# $Id$ +# +# Please refer to file version.h for the +# copyright notice regarding this software +# +# + +INCDIRS = +CFLAGS = -g -Wall $(INCDIRS) + +PROGS = in.ivyd ivyd ivyecho #ivycat +OBJ = + +all: $(PROGS) + + +in.ivyd: inivyd.c ivyd.h + $(CC) $(CFLAGS) -o in.ivyd inivyd.c + +ivy: ivy.c ivyd.h + $(CC) $(CFLAGS) -o ivy ivy.c + +ivyd: ivyd.c ivyd.h + $(CC) $(CFLAGS) -o ivyd ivyd.c -livy + +ivycat: ivycat.c ivyd.h + $(CC) $(CFLAGS) -o ivycat ivycat.c + +ivyecho: ivyecho.c ivyd.h + $(CC) $(CFLAGS) -o ivyecho ivyecho.c + +clean: + -rm -f *.o *~ $(PROGS) + +install: all + test -d $(PREFIX)/usr/bin || mkdirhier $(PREFIX)/usr/bin + install -m 755 in.ivyd $(PREFIX)/usr/bin/in.ivyd + install -m 755 ivyd $(PREFIX)/usr/bin/ivyd + install -m 755 inecho $(PREFIX)/usr/bin/ivyecho + install -m 755 ivycat $(PREFIX)/usr/bin/ivycat + +rpm:: + /usr/bin/rpmize + + diff --git a/src/inivyd.c b/src/inivyd.c new file mode 100644 index 0000000..56d7106 --- /dev/null +++ b/src/inivyd.c @@ -0,0 +1,221 @@ +/* + * 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 + * + */ + +/* + * Le super-demon wixd. + * + * Il est normalement lance par inetd, avec la chaussette SOCK_DGRAM + * sur le descripteur 0, ou alors, si le symbole FROMBOOT est defini, il est + * lance depuis /etc/rc.local. + * + * Le serveur wixd: + * Il envoie un paquet connmsg de type MSG_SERVER contenant le numero + * de port sur lequel il a connecte sa chaussette. + * + * Les clients wix (wx, wxcat, etc ...): + * Ils envoient un paquet connmsg de type MSG_CLIENT ou ils demandent + * le port. + * + * 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 = "/usr/tmp/wixd.db"; +const int dumpfilemode = 0644; +const char* const servicename = "ivyd"; +const char* const port_env_variable = "INIVYD_PORT"; +const int default_port = 3006; + +/* + * Definition de la table geree par le super-demon + */ + +typedef struct { + short s_port; /* le port sur lequel le client communique avec son serveur */ + short s_uid; /* le numero de processus du serveur wixd */ +} serverinfo; + +#define TABSIZ 64 /* 64 connections simultanees, ca devrait aller */ +serverinfo si_table [TABSIZ]; + +/* + * GetInfo (name) + * + * Rend l'information concernant l'utilisateur uid. + */ + +serverinfo* +GetInfo (int uid) +{ + 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_uid != uid) + 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_uid, 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; + } + + if (boot) { + if (!debug) { + int s; + + if (fork ()) + exit (0); + + /* on ferme tous les descripteurs */ + for (s = getdtablesize (); --s >= 0;) + close (s); + + /* et on se debarrasse du terminal de controle */ + if (-1 != open ("/dev/tty", 2)) { + (void) ioctl (0, TIOCNOTTY, 0); + close (0); + } + } else + close (0); + + /* + * Ouvre la chaussette et l'attache a bon port + */ + 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); + } + + 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_uid); + switch (msg.msg_type) { + case MSG_SERVER: + si->s_port = msg.msg_port; + si->s_uid = msg.msg_uid; + break; + + 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; + } + + } +} + diff --git a/src/ivyd.c b/src/ivyd.c new file mode 100644 index 0000000..5a4f3d0 --- /dev/null +++ b/src/ivyd.c @@ -0,0 +1,271 @@ +/* + * IvyDaemon, an Ivy gateway for short-lived agents + * + * Copyright (C) 1999 + * Centre d'Études de la Navigation Aérienne + * + * Main file for the server + * + * Author(s): Stephane Chatty + * from code by Patrick Amar + * + * $Id$ + * + * Please refer to file version.h for the + * copyright notice regarding this software + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ivy.h" +#include "ivyd.h" + +const char* const servicename = "ivyd"; +const char* const port_env_variable = "INIVYD_PORT"; +const int default_port = DEFAULT_INIVYD_PORT; + +static char * HomeDir; +int debug = 0; + +static void +Usage (const char* progname) +{ + fprintf (stderr, "Usage: %s [-b bus][-d]\n", progname); + fprintf (stderr, " -d: does not fork so as to facilitate debugging\n"); + fprintf (stderr, " -b bus: selects Ivy bus on which to relay messages\n"); + exit (1); +} + + +/* + * Envoie un numero de port au super-serveur de la machine locale + */ +int +SendPort (int port) +{ + struct servent *serv; + u_short serv_port; + struct sockaddr_in sin; + struct connmsg msg; + int sock; + int res; + + 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; + + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock == -1) + return 0; + + memset (&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_port = serv_port; + sin.sin_addr.s_addr = LOCALHOST; + + msg.msg_uid = getuid (); + msg.msg_port = port; + msg.msg_type = MSG_SERVER; + + + res = sendto (sock, (char *)&msg, sizeof msg, 0, (struct sockaddr *)&sin, sizeof sin); + + /* We only detect local errors, but we have no guarantee that there is someone + at the other end. We should fix that someday (by going connected?) */ + + if (res == -1) + goto failed; + + (void) close (sock); + return 1; + +failed: + (void) close (sock); + return 0; +} + + +int +InitSocket () +{ + int s, i; + struct sockaddr_in addr; + + s = socket (AF_INET, SOCK_STREAM, 0); + if (s < 0) { + perror ("socket"); + return 0; + } + + memset (&addr, 0, sizeof addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind (s, &addr, sizeof (addr)) == -1) { + perror ("bind"); + return 0; + } + + i = sizeof addr; + if (getsockname (s, &addr, &i) == -1) { + perror ("bind"); + return 0; + } + + + if (debug) + printf ("Ivyd listens on port %d\n", ntohs (addr.sin_port)); + + if (! SendPort (addr.sin_port)) { + fprintf (stderr, "No Ivyd port server. Continuing with port = %d\n", + ntohs (addr.sin_port)); + } + + /* je me debarrasse du terminal de controle */ + +/* freopen ("/dev/tty", "r+", stderr); */ + for (i = 0; i < 32; i++) + if (i != fileno (stderr) && i != s) + close (i); + +#ifndef SYSV + i = open ("/dev/tty", 0); + if (i != -1) { + (void) ioctl (i, TIOCNOTTY, 0); + close (i); + } +#endif SYSV + open ("/dev/null", 2); dup (0); + + + if (listen (s, 5) == -1) { + perror ("listen"); + return 0; + } + return s; +} + + +void +HandleRequests (void* ch, int fd, void* data) +{ + request req; + char* p = (char*) &req; + int n = sizeof (request); + struct sockaddr_in addr; + int len = sizeof (addr); + + fprintf (stderr, "REQUEST on %d\n", fd); + + /* retrieve request */ + while (n > 0) { +#if 1 + int l = read (fd, p, n); +#else + int l = recvfrom (fd, p, n, 0, (struct sockaddr*) &addr, &len); +#endif + if (l < 0) { + perror ("Error retrieving request from client"); + exit (0); + return; + } else if (l == 0) { + if (debug) + fprintf (stderr, "closing connection for %d\n", fd); + IvyChannelClose (ch); + close (fd); + return; + } + n -= l; + p += l; + } + +#if 0 + answer ans; + ans.ok = 1; + write ( +#endif + fprintf (stderr, "REQUEST [%s]\n", req.buffer); + IvySendMsg (req.buffer); +} + +void +HandleConnections (void* ch, int fd, void* data) +{ + static struct sockaddr sa; + static int acc; + int newfd = accept (fd, &sa, &acc); + fprintf (stderr, "CONNECTION %d\n", newfd); + IvyChannelSetUp (newfd, 0, 0, HandleRequests); +} + + +void +main (int argc, char **argv) +{ + int sock; + char busbuf [128]; + const char* bus = 0; + int c; + + /* handle args */ + while ((c = getopt (argc, argv, "b:d")) != EOF) { + switch (c) { + case 'b': + strcpy (busbuf, optarg) ; + bus = busbuf; + break; + case 'd': + debug = 1; + break; + default: + Usage (argv[0]); + } + } + + /* detach from tty */ + if (! debug) + if (fork ()) + exit (0); + + /* create server port */ + sock = InitSocket (); + + signal (SIGTERM, exit); /* pour flinguer le serveur */ + +#if 0 + /* + * Charger le fichier de personnalisation. + */ + HomeDir = getenv ("HOME"); + + if (!HomeDir || !*HomeDir) + fprintf (stderr, "%s: No HOME environment variable.\n", argv0); + else + StartUp (HomeDir); +#endif + + /* Ivy initialization and main loop */ + IvyInit ("IVYD", 0, 0, 0, 0, 0, 0); + IvyChannelSetUp (sock, 0, 0, HandleConnections); + IvyStart (bus); + IvyMainLoop (0); +} + diff --git a/src/ivyd.h b/src/ivyd.h new file mode 100644 index 0000000..39f2691 --- /dev/null +++ b/src/ivyd.h @@ -0,0 +1,62 @@ +/* + * IvyDaemon, an Ivy gateway for short-lived agents + * + * Copyright (C) 1999 + * Centre d'Études de la Navigation Aérienne + * + * Header shared by server, superserver and clients + * + * Author(s): Stephane Chatty + * from code by Patrick Amar + * + * $Id$ + * + * Please refer to file version.h for the + * copyright notice regarding this software + * + */ + +/* exchanges with super-server (port registration) */ + +#ifndef DEFAULT_INIVYD_PORT +#define DEFAULT_INIVYD_PORT 3006 +#endif + +#define MSG_REPLY ((char) 0) +#define MSG_CLIENT ((char) 1) +#define MSG_SERVER ((char) 2) + +struct connmsg { + short msg_uid; /* identification de l'expediteur */ + short msg_port; /* le port a utiliser pour l'uid ci-dessus */ + char msg_type; /* type de messages */ + char msg_fill1, /* fillers */ + msg_fill2, + msg_fill3; + +}; + +/* exchanges between clients and server */ + +#define BUFSIZE 512 + +typedef struct { + char buffer [BUFSIZE]; +} request; + +typedef struct { + int ok; +} answer; + + +/* + * L'adresse de la machine locale + */ +#ifndef LOCALHOST +#ifdef INADDR_LOOPBACK +#define LOCALHOST htonl (INADDR_LOOPBACK) +#else +#define LOCALHOST htonl (0x7f000001) +#endif +#endif + diff --git a/src/ivyecho.c b/src/ivyecho.c new file mode 100644 index 0000000..2b8227e --- /dev/null +++ b/src/ivyecho.c @@ -0,0 +1,313 @@ +/* + * IvyDaemon, an Ivy gateway for short-lived agents + * + * Copyright (C) 1999 + * Centre d'Études de la Navigation Aérienne + * + * Main file for the client ivyecho + * + * Author(s): Stephane Chatty + * from code by Patrick Amar + * + * $Id$ + * + * Please refer to file version.h for the + * copyright notice regarding this software + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ivyd.h" + +const char* const servicename = "ivyd"; +const char* const port_env_variable = "INIVYD_PORT"; +const int default_port = DEFAULT_INIVYD_PORT; + +int debug = 0; + +void +Usage (const char* progname) { + fprintf (stderr, "Usage: %s [-b bus (ignored)][-s server] text\n", progname); + exit (1); +} + +/* Get in touch with super-server and retrieve server's port number */ +int +GetPort (long addr) +{ + struct servent *serv; + u_short serv_port; + struct sockaddr_in sin; + struct connmsg msg; + int sock; + int len; + + /* get service port number */ + 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; + + /* create and bind socket */ + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock == -1) { + perror ("Can't create socket: "); + return 0; + } + memset (&sin, 0, sizeof sin); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + if (-1 == bind (sock, &sin, sizeof sin)) { + perror ("Can't bind socket: "); + goto failed; + } + sin.sin_port = serv_port; + sin.sin_addr.s_addr = addr; + + /* build request */ + msg.msg_uid = getuid (); + msg.msg_port = 0; + msg.msg_type = MSG_CLIENT; + + /* send it */ + if (-1 == sendto (sock, (char *)&msg, sizeof msg, 0, (struct sockaddr *)&sin, sizeof sin)) { + perror ("Can't send on socket: "); + goto failed; + } + + /* wait for reply */ + len = sizeof sin; + if (-1 == recvfrom (sock, (char *)&msg, sizeof msg, 0, (struct sockaddr *)&sin, &len)) { + perror ("Can't receive on socket: "); + goto failed; + } + + /* OK, we're done, return reply */ + (void) close (sock); + return (int) msg.msg_port; + +failed: + (void) close (sock); + return 0; +} + +int +ServerOpen (const char *host) +{ + int sock; + static struct sockaddr_in addr; + struct hostent *hp; + + /* determine host name and address */ + if (!host) + host = getenv ("IVYD"); + + if (!host) + host = "localhost"; + + hp = gethostbyname (host); + if (hp == 0) { + fprintf (stderr, "Unknown host %s\n", host); + return 0; + } + + /* create socket */ + sock = socket (AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror ("Can't create socket: "); + return 0; + } + + + /* build address from host addr, asking port number to super-server */ + memcpy (&addr.sin_addr, hp->h_addr, hp->h_length); + addr.sin_family = AF_INET; + addr.sin_port = GetPort (addr.sin_addr.s_addr); + if (! addr.sin_port) + return 0; + + /* connect socket on address */ + if (connect (sock, &addr, sizeof (addr)) < 0) { + perror ("Can't connect socket: "); + return 0; + } + + return sock; +} + + +int +SendMsg (int sock, const char* s) +{ + request req; + + /* build request */ + strcpy (req.buffer, s); + + /* send request */ + /* we should handle return value more finely */ + if (write (sock, &req, sizeof (request)) != sizeof (request)) { + fprintf (stderr, "Unable to write %d bytes: ", sizeof (request)); + perror (""); + } + +#if 0 + answer ans; + register char *p = (char *) &ans; + register int n, l; + + /* retrieve answer (useless) */ + for (n = sizeof (answer); n > 0; p += l) { + n -= (l = read (sock, p, n)); + if (l <= 0) { + perror ("Error retrieving answer from server: "); + return 0; + } + } + return ans.ok; +#endif + return 1; +} + +void +HandleArgs (int sock, int index, int argc, char** argv) +{ + char buf [BUFSIZE]; + int space = 0; + int nbchars = 0; + + /* slice arguments into buffer */ + buf [0] = '\0'; + while (index < argc) { + const char* p = argv[index++]; + int l = strlen (p); + /* while we have pending chars for this arg... */ + while (l + space > 0) { + /* first try and fit space if needed */ + if (space) { + if (nbchars + space <= BUFSIZE - 1) { + strcat (buf, " "); + nbchars += space; + space = 0; + } else { + goto bufferfull; + } + } + + /* then look if we can fit all the chars we have */ + if (nbchars + l <= BUFSIZE - 1) { + /* if yes, go ahead */ + strcat (buf, p); + nbchars += l; + /* we'll need to insert space if there are other args */ + space = 1; + /* but let's make sure we don't keep looping */ + l = -1; + /* if buffer is full, handle it */ + if (nbchars == BUFSIZE - 1) + goto bufferfull; + /* otherwise, we're done anyway */ + else + continue; + + /* if not enough room, first fit what we can */ + } else { + int fitting = (BUFSIZE - 1) - nbchars; + if (fitting > 0) { + strncat (buf, p, fitting); + nbchars += fitting; + l -= fitting; + p += fitting; + } + } + + +bufferfull: /* now we have a full buffer */ + /* send it */ + if (debug) + printf ("Sending [%s]\n", buf); + SendMsg (sock, buf); + /* and prepare for next round */ + nbchars = 0; + buf [0] = '\0'; + } + } + if (nbchars > 0) { + if (debug) + printf ("Sending [%s]\n", buf); + SendMsg (sock, buf); + } +} + + +/* + * Demande un numero de port au super-serveur de la machine addr + */ + + +int +main (int argc, char** argv) +{ + char busbuf [128]; + const char* bus = 0; + char serverhostbuf [128]; + const char* serverhost = 0; + const struct option options [] = { + {"bus", required_argument, 0, 'b'}, + {"debug", no_argument, 0, 'd'}, + {"server", required_argument, 0, 's'}, + {0, 0, 0, 0} + }; + char c; + int servfd; + +#if 0 + if (strlen (argv0) >= 4 && !strcmp (argv0+strlen (argv0)-4, "wait")) + wflag = 1; +#endif + + /* handle options */ + while ((c = getopt_long (argc, argv, "+b:s:d", options, 0)) != EOF) { + switch (c) { + case 'b': + strcpy (busbuf, optarg) ; + bus = busbuf; + break; + case 's': + strcpy (serverhostbuf, optarg) ; + serverhost = serverhostbuf; + break; + case 'd': + debug = 1; + break; + } + } + + + /* Se connecter au serveur. */ + servfd = ServerOpen (serverhost); + if (!servfd) { + fprintf (stderr, "No server.\n"); + return 0; + } + + HandleArgs (servfd, optind, argc, argv); + + return 1; +} + -- cgit v1.1