From ba066c34dde204aa192d03a23a81356374d93731 Mon Sep 17 00:00:00 2001 From: chatty Date: Wed, 7 Apr 1993 11:50:31 +0000 Subject: Initial revision --- comm/OLD/portserv.cc | 653 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 653 insertions(+) create mode 100644 comm/OLD/portserv.cc (limited to 'comm/OLD/portserv.cc') diff --git a/comm/OLD/portserv.cc b/comm/OLD/portserv.cc new file mode 100644 index 0000000..5470fe3 --- /dev/null +++ b/comm/OLD/portserv.cc @@ -0,0 +1,653 @@ +/* + * The Unix Channel + * + * by Michel Beaudouin-Lafon + * + * Copyright 1990-1993 + * Laboratoire de Recherche en Informatique (LRI) + * + * Port server + * + * $Id$ + * $CurLog$ + */ + +#include "PortServerReq.h" +#include "PortServer.h" +#include "error.h" +#include "Datagram.h" +#include "ccu/List.h" +#include "ccu/RegExp.h" +#include "ccu/String.h" +#include "ccu/Time.h" + +#include +#include +#include +#include +#include +#include +#include + +//---------------- globals +// if SaveTime > 0, the state is saved to SaveFile +// SaveTime seconds after a modification +// if SaveTime < 0, saving is immediate +// if SaveTime is 0, no save +// if SaveFileIsFd >= 0, it is taken as output file descr instead of SaveFile +const char* SaveFile = 0; +int SaveFileIsFd = -1; +int SaveTime = 0; +int Mod = 0; +int NbEntries = 0; +bool Trace = FALSE; +const char* LoadFile; + +//---------------- constants +// if an auto-launch server has not registered for REG_TIME seconds +// and somebody inquires its address, it is killed and restarted. +#define REG_TIME 60000 +#define REG_STR "minute" + +// if an auto-launch server has been run within the last ALR_TIME seconds +// and has not yet registered and somebody inquires its address, +// is is _not_ run. +#define ALR_TIME 30000 +#define ALR_STR "30 seconds" + +struct Serv { + CcuString Key; + lword Host; + sword Port; + int Ident; + // auto-launch stuff + bool AutoLaunch; + bool Running; + Millisecond LastRun; + Millisecond LastRegistered; + char* CmdLine; // the line + char** RunCmd; // array to pointers to CmdLine (for execvp) +}; + +#ifndef CPLUS_BUG19 +CcuListOf ServList; +#else +CcuList ServList; +#endif + +//---------------- auto-launch stuff +char** +Parse (char* line) +{ + enum WHERE { IN_SPACE, IN_WORD, IN_QUOTE }; + char quote = '\0'; + register char* s = line; + register char* word = line; + register WHERE where = IN_SPACE; + char* words [256]; + int nw = 0; + + // split a line into words + // a word is a sequence of non blank characters, + // or a quoted string (' or "). + // '(', ')' and ',' are also ignored to allow for function like notation + for (; *s; s++) { + switch (where) { + case IN_WORD: + if (index (" \t(),", *s)) { + *s = '\0'; + where = IN_SPACE; + if (nw < 255) + words [nw++] = word; + else + return 0; + } + break; + case IN_QUOTE: + if (*s == quote) { + *s = '\0'; + where = IN_SPACE; + if (nw < 255) + words [nw++] = word; + else + return 0; + } + break; + case IN_SPACE: + if (*s == '\'' || *s == '\"') { + quote = *s; + *s = '\0'; + where = IN_QUOTE; + word = s+1; + } else + if (index (" \t(),", *s)) { + *s = '\0'; + } else { + where = IN_WORD; + word = s; + } + break; + } + } + if (where != IN_SPACE) + if (nw < 255) + words [nw++] = word; + else + return 0; + if (where == IN_QUOTE) + return 0; + + // if no argv specified, argv[0] = executable + if (nw == 3) + words [nw++] = words [2]; + // expected format: key dir exec argv + if (nw < 4) + return 0; + // null terminated array for execvp + words [nw++] = 0; + + // return a freshly allocated array + char** nwords = new char* [nw]; + for (int i = 0; i < nw; i++) + nwords [i] = words [i]; + return nwords; +} + +void +AutoLaunch (Serv* s) +{ + // s->RunCmd [0] service name + // s->RunCmd [1] directory + // s->RunCmd [2] executable + // s->RunCmd [3 ... ] argv [0 ...] + + CcuTimeStamp now; + if (s->LastRun + ALR_TIME > now) { +// Log ("AutoLaunch", "%s already launched in the past %s", s->RunCmd [0], ALR_STR); + return; + } +// Log ("AutoLaunch", "running %s dir=%s, exec=%s", s->RunCmd[0], s->RunCmd[1], s->RunCmd[2]); + if (! fork ()) { + // close everything but stdio + for (int i = 3; i < NFILE; i++) + close (i); + // detach from controlling terminal + setsid (); + // change directory + if (chdir (s->RunCmd [1]) < 0) + SysError (ErrFatal, s->RunCmd [1]); + // exec server + if (execvp (s->RunCmd [2], s->RunCmd + 3) < 0) + SysError (ErrFatal, s->RunCmd [2]); + } + s->LastRun = now; +} + +void +LoadConfig () +{ + char* l = getlogin (); + if (! l) + l = cuserid (0); + if (! l) + Error (ErrFatal, "LoadConfig", "getlogin failed"); + + FILE* f = fopen (LoadFile, "r"); + if (!f) + SysError (ErrFatal, LoadFile); + char line [2048]; + while (fgets (line, sizeof (line), f)) { + // empty line or comment + if (! line [0] || line [0] == '#') + continue; + + // expected format: servername dir exec argv0 ... + + // remove trailing newline and parse + line [strlen (line) -1] = 0; + char* nline = new char [strlen (line) + 1]; + strcpy (nline, line); + char** words = Parse (nline); + if (! words) { + Error (ErrWarn, "LoadConfig", "incorrect line ignored in file"); + delete nline; + continue; + } + Serv* s = new Serv; + char key [256]; // portserv:mbl:audioserver + sprintf (key, "portserv:%s:%s", l, words [0]); + s->Key = key; + s->Host = 0; + s->Port = 0; + s->Ident = 0; + s->AutoLaunch = TRUE; + s->Running = FALSE; + s->LastRun= 0; + s->LastRegistered = 0; + s->CmdLine = nline; + s->RunCmd = words; + ServList.Append (s); +// Log ("LoadConfig", "defined auto-launch server %s dir=%s exec=%s", +// s->RunCmd [0], s->RunCmd [1], s->RunCmd [2]); + } + fclose (f); +} + +void +KillProcesses () +{ + // kill all processes that have been autolaunched, + // assuming that their id is their pid. + Serv* s; +#ifndef CPLUS_BUG19 + CcuListIterOf iter (ServList); + while (s = *++iter) { +#else + CcuListIter iter (ServList); + while (s = (Serv*) *++iter) { +#endif + if (s->AutoLaunch && s->Ident) { +// Log ("KillProcesses", "killing %s pid=%d", s->RunCmd [2], (void*) s->Ident); + kill (s->Ident, SIGTERM); + } + } +} + +Serv* +Register (const char* key, lword host, sword port, int id) +{ + Serv* s = 0; + +#ifndef CPLUS_BUG19 + CcuListIterOf iter (ServList); + while (s = *++iter) { +#else + CcuListIter iter (ServList); + while (s = (Serv*) *++iter) { +#endif + if (strcmp (key, s->Key) == 0) + break; + } + if (! s) { + s = new Serv; + s->Key = key; + s->AutoLaunch = FALSE; + s->LastRun = 0; + s->CmdLine = 0; + s->RunCmd = 0; + ServList.Append (s); + } + s->Host = host; + s->Port = port; + s->Ident = id; + CcuTimeStamp now; + s->LastRegistered = now; + s->Running = TRUE; + return s; +} + +bool +Remove (const char* key, lword host, sword port, int id) +{ + Serv*s; +#ifndef CPLUS_BUG19 + CcuListIterOf iter (ServList); + CcuListIterOf trailing_iter (ServList); +#else + CcuListIter iter (ServList); + CcuListIter trailing_iter (ServList); +#endif + while (++iter) { +#ifndef CPLUS_BUG19 + s = *iter; +#else + s = (Serv*) *iter; +#endif + if (host == s->Host && port == s->Port && id == s->Ident && strcmp (key, s->Key) == 0) { + if (s->AutoLaunch) { + s->Running = FALSE; + s->LastRun = 0; + s->LastRegistered = 0; + s->Host = 0; + s->Port = 0; + s->Ident = 0; + } else { + s->Key = 0; + delete s; + ServList.RemoveAfter (trailing_iter); + } + return TRUE; + } + ++trailing_iter; + } + Error (ErrWarn, key, "not found for remove"); + return FALSE; +} + +Serv* +Inquire (const char* key) +{ + Serv*s; +#ifndef CPLUS_BUG19 + CcuListIterOf iter (ServList); +#else + CcuListIter iter (ServList); +#endif + while (++iter) { +#ifndef CPLUS_BUG19 + s = *iter; +#else + s = (Serv*) *iter; +#endif + + if (strcmp (key, s->Key) != 0) + continue; + + if (!s->AutoLaunch) + return s; + + if (s->Running) { + CcuTimeStamp now; + if (s->LastRegistered + REG_TIME < now) { +// Log ("Inquire", "%s not registered for the last %s: autolaunching it", s->RunCmd [0], REG_STR); + if (s->Ident) + kill (s->Ident, SIGTERM); + s->Host = 0; + s->Port = 0; + s->Ident = 0; + AutoLaunch (s); + } + } else + AutoLaunch (s); + return s; + } + Error (ErrWarn, key, "not found"); + return 0; +} + + +void +Match (const char* key, UchDatagram& portserv) +{ + UchMsgBuffer buf (256); + UchPortServerReq ans (PortServMatch); + int nb = 0; + + CcuRegExp re (key); + if (re.Compile ()) { + Serv*s; +#ifndef CPLUS_BUG19 + CcuListIterOf iter (ServList); + while (++iter) { + s = *iter; +#else + CcuListIter iter (ServList); + while (++iter) { + s = (Serv*) *iter; +#endif + if (re.Match (s->Key)) { +if (Trace) printf ("Match: %s\n", (const char*) s->Key); + ans.Host = s->Host; + ans.Port = s->Port; + ans.SetKey (s->Key); + buf.Append (ans); + portserv.Reply (buf); + nb++; + } + } + } else + nb = -1; + ans.Type = PortServEndMatch; + ans.Ident = nb; + ans.SetKey (0); + buf.Append (ans); + portserv.Reply (buf); +} + +int +Dump () +{ + Serv*s; +#ifndef CPLUS_BUG19 + CcuListIterOf iter (ServList); +#else + CcuListIter iter (ServList); +#endif + while (++iter) { +#ifndef CPLUS_BUG19 + s = *iter; +#else + s = (Serv*) *iter; +#endif + printf ("<%s> 0x%lx:%d (%d)\n", (const char*) s->Key, s->Host, s->Port, s->Ident); + } + return 0; +} + +int +DumpFile () +{ +if (Trace) printf ("dumping\n"); + int fd = SaveFileIsFd; + if (fd < 0 && (fd = creat (SaveFile, 0600)) < 0) { + SysError (ErrWarn, SaveFile); + return 0; + } + UchFilDes Fd (fd); + char buf [256]; + Serv*s; +#ifndef CPLUS_BUG19 + CcuListIterOf iter (ServList); +#else + CcuListIter iter (ServList); +#endif + while (++iter) { +#ifndef CPLUS_BUG19 + s = *iter; +#else + s = (Serv*) *iter; +#endif + sprintf (buf, "0x%lx:%d %s\n", s->Host, s->Port, (const char*) s->Key); + Fd.Write ((byte*) buf, strlen (buf)); + } + Mod = 0; + return 1; +} + +// for handlers +// +void +SigDump (int) +{ + Dump (); +} + +void +SigDumpFile (int) +{ + DumpFile (); +} + +void +Modified () +{ + if (! Mod && SaveTime > 0) { + Mod++; + alarm (SaveTime); + return; + } + if (SaveTime < 0) { + Mod++; + DumpFile (); + } +} + +void +Usage () +{ + Error (ErrUsage, "portserv", "[-t] [-s service] [-quit] [-save file [time]] [-load file]"); +} + +main (int argc, const char** argv) +{ + const char* servname = "portserv"; + int running = 1; + bool qflag = FALSE; + + ProgramName (argv [0]); + while (--argc) { + ++argv; + if (strcmp (*argv, "-quit") == 0) { + qflag = TRUE; + } else + if (strcmp (*argv, "-t") == 0) { + Trace = TRUE; + } else + if (strcmp (*argv, "-s") == 0) { + if (--argc < 1) + Usage (); + servname = *++argv; + } else + if (strcmp (*argv, "-save") == 0) { + if (--argc < 1) + Usage (); + SaveFile = *++argv; + if (strcmp (SaveFile, "-") == 0) + SaveFileIsFd = 1; + else if (strcmp (SaveFile, "--") == 0) + SaveFileIsFd = 2; + + if (argc > 1 && argv [1][0] != '-') { + SaveTime = atoi (*++argv); + --argc; + } else + SaveTime = -1; + } else if (strcmp (*argv, "-load") == 0 || strcmp (*argv, "-l") == 0) { + if (--argc < 1) + Usage (); + LoadFile = *++argv; + } else + Usage (); + } + + // special case: portserv -quit + // send a PortServQuit message to + // the portserver that is running + if (qflag) { + if (SaveFile || LoadFile) + Error (ErrFatal, "-quit", "incompatible with -save or -load"); + UchPortServer ps (servname, 0); + ps.Quit (); + exit (0); + } + + sword servport; + + // get service name + // + struct servent* service = getservbyname (servname, 0); + if (service) + servport = ntohs (service->s_port); + else { + const char* portno = getenv (servname); + if (portno) { + servport = atoi (portno); + } else + Error (ErrFatal, servname, "service not available"); + } + + // load file + // + if (LoadFile) + LoadConfig (); + + // open dgram socket + // +if (Trace) printf ("opening\n"); + UchDatagram portserv (new UchInetAddress (ANYADDR, servport), 0); + if (! portserv.Setup ()) +// Error (ErrFatal, "main", "Setup failed"); + SysError (ErrFatal, "main"); + + signal (SIGHUP, SigDump); + if (SaveTime > 0) + signal (SIGALRM, SigDumpFile); + + // handle requests + // + UchMsgBuffer buf (256); + UchPortServerReq req; + +if (Trace) printf ("looping\n"); + while (running) { + buf.Flush (); + int n = portserv.Receive (buf); + if (n <= 0) { + SysError (ErrFatal, "Receive", EINTR); + continue; + } +if (Trace) printf ("received\n"); + if (! buf.Get (&req)) { + Error (ErrWarn, "Receive", "could not read message"); + continue; + } + + // respond + switch (req.Type) { + case PortServRegister : +if (Trace) printf ("register\n"); + Register (req.Key, req.Host, req.Port, int (req.Ident)); + Modified (); + break; + + case PortServRemove : +if (Trace) printf ("remove\n"); + Remove (req.Key, req.Host, req.Port, int (req.Ident)); + Modified (); + break; + + case PortServInquire : + { +if (Trace) printf ("inquire\n"); + UchPortServerReq ans; + Serv* inq = Inquire (req.Key); + if (inq) { + ans.Type = PortServAnswer; + ans.Host = inq->Host; + ans.Port = inq->Port; + } else { + ans.Type = PortServFail; + ans.Host = 0; + ans.Port = 0; + } + buf.Flush (); + buf.Append (ans); + portserv.Reply (buf); + } + break; + + case PortServMatch : +if (Trace) printf ("match\n"); + Match (req.Key, portserv); + break; + + case PortServDump : +if (Trace) printf ("dump\n"); + Dump (); + break; + + case PortServQuit : +if (Trace) printf ("quit\n"); + if (SaveTime) + DumpFile (); + KillProcesses (); + running = 0; ////////dangerous + break; + + default: +if (Trace) printf ("unknown\n"); + Error (ErrWarn, "Receive", "unknown request"); + } + } +} + -- cgit v1.1