[28683] in Source-Commits

home help back first fref pref prev next nref lref last post

messaged commit: re-write messaged in python

daemon@ATHENA.MIT.EDU (Anders Kaseorg)
Thu Sep 1 18:04:59 2016

Date: Thu, 1 Sep 2016 18:04:57 -0400
From: Anders Kaseorg <andersk@mit.edu>
Message-Id: <201609012204.u81M4vDl017724@drugstore.mit.edu>
To: source-commits@mit.edu

https://github.com/mit-athena/messaged/commit/97426f6b4ab9e59af8767dc46aaa41afa5cda654
commit 97426f6b4ab9e59af8767dc46aaa41afa5cda654
Author: Jonathon Weiss <jweiss@mit.edu>
Date:   Thu Sep 1 14:53:05 2016 -0400

    re-write messaged in python

 Makefile.in  |   39 -------------
 configure.in |   10 ---
 messaged     |   84 ++++++++++++++++++++++++++++
 messaged.c   |  174 ----------------------------------------------------------
 4 files changed, 84 insertions(+), 223 deletions(-)

diff --git a/Makefile.in b/Makefile.in
deleted file mode 100644
index 9614bdb..0000000
--- a/Makefile.in
+++ /dev/null
@@ -1,39 +0,0 @@
-# $Id: Makefile.in,v 1.2 2002-04-09 05:54:30 ghudson Exp $
-
-SHELL=/bin/sh
-VPATH=@srcdir@
-INSTALL=@INSTALL@
-INSTALL_PROGRAM=@INSTALL_PROGRAM@
-srcdir=@srcdir@
-top_srcdir=@top_srcdir@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-sbindir=@sbindir@
-
-CC=@CC@
-DEFS=@DEFS@
-CPPFLAGS=@CPPFLAGS@
-CFLAGS=@CFLAGS@ ${WARN_CFLAGS} ${ERROR_CFLAGS}
-LDFLAGS=@LDFLAGS@
-LIBS=-lgms -lcom_err @LIBS@
-ALL_CFLAGS=${CPPFLAGS} ${CFLAGS} ${DEFS}
-
-all: messaged
-
-OBJS=messaged.o
-
-messaged: ${OBJS}
-	${CC} ${LDFLAGS} -o messaged ${OBJS} ${LIBS}
-
-.c.o:
-	${CC} -c ${ALL_CFLAGS} $<
-
-install:
-	${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir}
-	${INSTALL_PROGRAM} messaged ${DESTDIR}${sbindir}
-
-clean:
-	rm -f messaged ${OBJS}
-
-distclean: clean
-	rm -f config.cache config.log config.status Makefile
diff --git a/configure.in b/configure.in
deleted file mode 100644
index 61761b2..0000000
--- a/configure.in
+++ /dev/null
@@ -1,10 +0,0 @@
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT(messaged.c)
-
-AC_PROG_CC
-AC_PROG_INSTALL
-
-AC_SEARCH_LIBS(sendto, socket)
-ATHENA_UTIL_COM_ERR
-
-AC_OUTPUT(Makefile)
diff --git a/messaged b/messaged
new file mode 100755
index 0000000..c6339e4
--- /dev/null
+++ b/messaged
@@ -0,0 +1,84 @@
+#!/usr/bin/python
+
+MESSAGE_VERS = 'GMS:0'
+# MESSAGE_SIZE used to be 2048, but messages bigger than 1472
+# bytes seem to get lost when crossing (some?) routers, so truncate
+# there instead.
+MESSAGE_SIZE = 1472
+MESSAGE_FILE = '/var/gms/Message'
+
+import argparse, errno, os, socket, sys, syslog
+
+parser = argparse.ArgumentParser()
+parser.add_argument("--log", help="syslog successful transactions",
+                    action="store_true")
+args = parser.parse_args()
+
+syslog.openlog (logoption=syslog.LOG_PID, facility=syslog.LOG_DAEMON)
+s = socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_DGRAM)
+try:
+    request, address = s.recvfrom(MESSAGE_SIZE)
+    localaddr = s.getsockname()
+    s.close()
+    request = request.rstrip()
+except socket_error as err:
+    syslog.syslog(syslog.LOG_INFO, "GMS daemon socket error reading: {0}".format(err))
+    sys.exit(err.errno)
+else:
+    if args.log:
+        syslog.syslog(syslog.LOG_INFO, "GMS request received successfully [%s] from %s" % (request, address))
+
+if request != MESSAGE_VERS:
+    syslog.syslog(syslog.LOG_INFO, "GMS bogus version [%s] from %s\n" % (request, address))
+    sys.exit(1)
+
+# Fork to avoid issues with waiting inetd
+pid = os.fork()
+if pid:
+    sys.exit(0)
+
+try:
+    s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+    s2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    s2.bind(localaddr)
+    s2.connect(address)
+except socket_error as err:
+    syslog.syslog(syslog.LOG_INFO, "GMS daemon socket error connecting for send: {0}".format(err))
+    sys.exit(err.errno)
+
+NO_MESSAGE = False
+try:
+    if os.stat(MESSAGE_FILE).st_size == 0:
+        NO_MESSAGE = True
+except OSError as err:
+    if err.errno != errno.ENOENT:
+        syslog.syslog(syslog.LOG_INFO, "GMS daemon open error reading message file %s: {0}".format(err) % MESSAGE_FILE)
+        sys.exit(err.errno)
+    else:
+        NO_MESSAGE = True
+
+if NO_MESSAGE:
+    try:
+        s2.send ("%s 0\n" % MESSAGE_VERS)
+        s2.close()
+        sys.exit(0)
+    except socket_error as err:
+        syslog.syslog(syslog.LOG_INFO, "GMS daemon socket error sending to %s: {0}".format(err) % address)
+        sys.exit(err.errno)
+else:
+    MESSAGE_FILE_MTIME = int(os.path.getmtime(MESSAGE_FILE))
+    with open(MESSAGE_FILE, 'r') as FD:
+        MESSAGE_FILE_CONTENTS = FD.read()
+    try:
+        msg = "%s %s\n%s" % (MESSAGE_VERS, MESSAGE_FILE_MTIME, MESSAGE_FILE_CONTENTS)
+        msg2 = msg[:MESSAGE_SIZE]
+        if msg2 != msg:
+            # 17 is the size of the header line contianing the GMS
+            # version string and file timestamp.
+            syslog.syslog(syslog.LOG_INFO, "GMS message too long, truncating.  (Keep file under %s bytes.)\n" % (MESSAGE_SIZE - 17))
+        s2.send (msg2)
+        s2.close()
+        sys.exit(0)
+    except socket_error as err:
+        syslog.syslog(syslog.LOG_INFO, "GMS daemon socket error sending to %s: {0}".format(err) % address)
+        sys.exit(err.errno)
diff --git a/messaged.c b/messaged.c
deleted file mode 100644
index 507bf23..0000000
--- a/messaged.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/* Copyright 1988, 1998 by the Massachusetts Institute of Technology.
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting
- * documentation, and that the name of M.I.T. not be used in
- * advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose.  It is provided "as is"
- * without express or implied warranty.
- */
-
-static const char rcsid[] = "$Id: messaged.c,v 1.2 2004-05-21 19:43:22 zacheiss Exp $";
-
-#include "globalmessage.h"
-#ifndef GMS_SERVER_MESSAGE
-#define GMS_SERVER_MESSAGE "/var/gms/Message"
-#endif /* GMS_SERVER_MESSAGE */
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <syslog.h>
-#include <com_err.h>
-
-/*
- * This version of the daemon is run out of inetd, with a conf line of:
- * globalmessage dgram udp wait unswitched nobody /usr/athena/etc/messaged messaged
- */
-
-#define saddr_list(sin) (unsigned)sin[0],(unsigned)sin[1],(unsigned)sin[2],(unsigned)sin[3]
-int main(int argc, char **argv)
-{
-  char buf[GMS_MAX_MESSAGE_LEN];
-  int readstat, readlen, msgfile;
-  struct sockaddr from;
-  /* these strange casts are so that I can print out the address of
-   * the incoming packet.
-   */
-  struct sockaddr_in *cast1 = (struct sockaddr_in *)&from;
-  char *cast2 = (char *)(&(cast1->sin_addr.s_addr));
-  int fromlen = sizeof(from);
-  time_t timestamp;
-  int headerlen;
-
-  /* initialize syslog connection for DAEMON */
-  /* log_pid has the side effect of forcing log messages to be unique,
-   * not listed as ``message the same, repeated 6 times'' but that
-   * shouldn't be a problem.
-   */
-  openlog(argv[0], LOG_PID, LOG_DAEMON);
-  
-  /* gms is just return values; the other com_err tables used will
-   * init themselves.
-   */
-  init_gms_err_tbl();
-
-  /* read the packet from the socket (stdin, since we run from inetd)
-   * and also record the from address so we can send a reply.
-   */
-  readstat = recvfrom(0, buf, GMS_MAX_MESSAGE_LEN, 0, &from, &fromlen);
-  if(readstat == -1) {
-    syslog(LOG_INFO, "GMS daemon recvfrom failure %s", error_message(errno));
-    exit(errno);
-  }
-
-  /* We got a packet successfully, so if logging is enabled record the
-   * requesting address.
-   */
-  if(argc>1 && !strcmp(argv[1],"-log")) {
-    syslog(LOG_INFO, "GMS request succeeded [%s] from %ud.%ud.%ud.%ud",
-	   buf, saddr_list(cast2));
-  }
-
-  /* Check the version number, and log if it is in error. */
-  if(strncmp(buf, GMS_VERSION_STRING, GMS_VERSION_STRING_LEN)) {
-    syslog(LOG_INFO, "GMS bogus version [%s] from %ud.%ud.%ud.%ud",
-	   buf, saddr_list(cast2));
-    exit(GMS_CLIENT_VERSION);
-  } 
-
-  /* Open the message file to read it in. Note that even were we to
-   * want to cache the data for efficiency, we must stat the file to
-   * make sure it hasn't changed under us. Since we're running, we
-   * must open it because we have no state.
-   */
-  msgfile = open(GMS_SERVER_MESSAGE, O_RDONLY, 0);
-
-  if(msgfile == -1) {
-    /* no file, special case of 0 timestamp indicating to also delete
-     * the remote cached copy. If the error is ENOENT, then we just
-     * assume it is an expected disappearance; all other errors are
-     * `interesting' and are logged. In any case, the tester can see
-     * that there is no new message.
-     */
-    if(errno == ENOENT) {
-      /* it didn't exist, we can deal with that... */
-      timestamp = 0;
-    } else {
-      /* something went wrong, but we can't do much about it;
-       * let's not trash the remote state -- just don't answer the
-       * connection.
-       */
-      syslog(LOG_INFO, "GMS daemon open error [%s] reading message file <%s>",
-	     error_message(errno), GMS_SERVER_MESSAGE);
-      exit(errno);
-    }
-  } else {
-    struct stat sbuf;
-    
-    fstat(msgfile, &sbuf);
-    if(sbuf.st_size == 0) {
-      /* an empty file means the same to the remote as a missing one. */
-      timestamp = 0;
-    } else {
-      /* for convenient maintenance, use the real timestamp as version
-       * number. */
-      timestamp = sbuf.st_mtime;
-    }
-  }
-  strcpy(buf,GMS_VERSION_STRING);
-  {
-    char tsbuf[GMS_TIMESTAMP_LEN];
-
-    /* sprintf (and _doprnt in general) are slow memory hogs. However,
-     * syslog is already including _doprnt, so it's already over; it
-     * is cheaper just to use sprintf here instead of coding or
-     * linking in the fast integer one.
-     * It is almost readable, too...
-     */
-    sprintf(tsbuf, " %lu\n", timestamp);
-    strcat(buf,tsbuf);
-    headerlen = strlen(buf);
-  }
-
-  /* Now that we have the header, we have to read the rest of the file
-   * into the packet after it. The length-1 specification is to
-   * preserve a NUL at the end of the buffer. Use msgfile to remember
-   * that we couldn't open it.
-   */
-  if(msgfile != -1) {
-    readlen = read(msgfile, buf + headerlen, GMS_MAX_MESSAGE_LEN-headerlen-1);
-    if(readlen == -1) {
-      /* read failed but open didn't, so record the error */
-      syslog(LOG_INFO, "GMS daemon read error [%s] reading message file <%s>",
-	     error_message(errno), GMS_SERVER_MESSAGE);
-      exit(errno);
-    }
-    /* protect the fencepost... */
-    buf[GMS_MAX_MESSAGE_LEN-1] = '\0';
-    close(msgfile);
-  } else {
-    readlen = 0;
-  }
-  /* send the packet back where it came from */
-  if(-1 == sendto(0, buf, readlen+headerlen, 0, &from, sizeof(from))) {
-    /* the send failed (probably a local error, or bad address or
-     * something so log the attempt.
-     */
-    syslog(LOG_INFO, "GMS daemon sendto failure [%s] to %d.%d.%d.%d",
-	   error_message(errno), saddr_list(cast2));
-    exit(errno);
-  }
-  /* everything worked, die happy... */
-  exit(0);
-}

home help back first fref pref prev next nref lref last post