[28683] in Source-Commits
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);
-}