summaryrefslogtreecommitdiff
path: root/comm/OLD/portserv.cc
diff options
context:
space:
mode:
authorchatty1993-04-07 11:50:31 +0000
committerchatty1993-04-07 11:50:31 +0000
commitba066c34dde204aa192d03a23a81356374d93731 (patch)
tree39391f6235d2cf8a59a0634ac5ea430cdd21f5d4 /comm/OLD/portserv.cc
parent05ab076e1c2a9ca16472f9a6b47b8d22914b3783 (diff)
downloadivy-league-ba066c34dde204aa192d03a23a81356374d93731.zip
ivy-league-ba066c34dde204aa192d03a23a81356374d93731.tar.gz
ivy-league-ba066c34dde204aa192d03a23a81356374d93731.tar.bz2
ivy-league-ba066c34dde204aa192d03a23a81356374d93731.tar.xz
Initial revision
Diffstat (limited to 'comm/OLD/portserv.cc')
-rw-r--r--comm/OLD/portserv.cc653
1 files changed, 653 insertions, 0 deletions
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 <stdlib.h>
+#include <sys/file.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <netdb.h>
+
+//---------------- 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 <Serv> 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 <Serv> 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 <Serv> 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 <Serv> iter (ServList);
+ CcuListIterOf <Serv> 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 <Serv> 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 <Serv> 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 <Serv> 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 <Serv> 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");
+ }
+ }
+}
+