source: trunk/athena/etc/messaged/messaged.c @ 20491

Revision 20491, 5.9 KB checked in by zacheiss, 20 years ago (diff)
Replace BFSZ with GMS_MAX_MESSAGE_SIZE so that the client and server have the same idea of what the maximum message size is.
Line 
1/* Copyright 1988, 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16static const char rcsid[] = "$Id: messaged.c,v 1.2 2004-05-21 19:43:22 zacheiss Exp $";
17
18#include "globalmessage.h"
19#ifndef GMS_SERVER_MESSAGE
20#define GMS_SERVER_MESSAGE "/var/gms/Message"
21#endif /* GMS_SERVER_MESSAGE */
22
23#include <sys/types.h>
24#include <stdio.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <sys/socket.h>
28#include <netinet/in.h>
29#include <sys/stat.h>
30#include <string.h>
31#include <syslog.h>
32#include <com_err.h>
33
34/*
35 * This version of the daemon is run out of inetd, with a conf line of:
36 * globalmessage dgram udp wait unswitched nobody /usr/athena/etc/messaged messaged
37 */
38
39#define saddr_list(sin) (unsigned)sin[0],(unsigned)sin[1],(unsigned)sin[2],(unsigned)sin[3]
40int main(int argc, char **argv)
41{
42  char buf[GMS_MAX_MESSAGE_LEN];
43  int readstat, readlen, msgfile;
44  struct sockaddr from;
45  /* these strange casts are so that I can print out the address of
46   * the incoming packet.
47   */
48  struct sockaddr_in *cast1 = (struct sockaddr_in *)&from;
49  char *cast2 = (char *)(&(cast1->sin_addr.s_addr));
50  int fromlen = sizeof(from);
51  time_t timestamp;
52  int headerlen;
53
54  /* initialize syslog connection for DAEMON */
55  /* log_pid has the side effect of forcing log messages to be unique,
56   * not listed as ``message the same, repeated 6 times'' but that
57   * shouldn't be a problem.
58   */
59  openlog(argv[0], LOG_PID, LOG_DAEMON);
60 
61  /* gms is just return values; the other com_err tables used will
62   * init themselves.
63   */
64  init_gms_err_tbl();
65
66  /* read the packet from the socket (stdin, since we run from inetd)
67   * and also record the from address so we can send a reply.
68   */
69  readstat = recvfrom(0, buf, GMS_MAX_MESSAGE_LEN, 0, &from, &fromlen);
70  if(readstat == -1) {
71    syslog(LOG_INFO, "GMS daemon recvfrom failure %s", error_message(errno));
72    exit(errno);
73  }
74
75  /* We got a packet successfully, so if logging is enabled record the
76   * requesting address.
77   */
78  if(argc>1 && !strcmp(argv[1],"-log")) {
79    syslog(LOG_INFO, "GMS request succeeded [%s] from %ud.%ud.%ud.%ud",
80           buf, saddr_list(cast2));
81  }
82
83  /* Check the version number, and log if it is in error. */
84  if(strncmp(buf, GMS_VERSION_STRING, GMS_VERSION_STRING_LEN)) {
85    syslog(LOG_INFO, "GMS bogus version [%s] from %ud.%ud.%ud.%ud",
86           buf, saddr_list(cast2));
87    exit(GMS_CLIENT_VERSION);
88  }
89
90  /* Open the message file to read it in. Note that even were we to
91   * want to cache the data for efficiency, we must stat the file to
92   * make sure it hasn't changed under us. Since we're running, we
93   * must open it because we have no state.
94   */
95  msgfile = open(GMS_SERVER_MESSAGE, O_RDONLY, 0);
96
97  if(msgfile == -1) {
98    /* no file, special case of 0 timestamp indicating to also delete
99     * the remote cached copy. If the error is ENOENT, then we just
100     * assume it is an expected disappearance; all other errors are
101     * `interesting' and are logged. In any case, the tester can see
102     * that there is no new message.
103     */
104    if(errno == ENOENT) {
105      /* it didn't exist, we can deal with that... */
106      timestamp = 0;
107    } else {
108      /* something went wrong, but we can't do much about it;
109       * let's not trash the remote state -- just don't answer the
110       * connection.
111       */
112      syslog(LOG_INFO, "GMS daemon open error [%s] reading message file <%s>",
113             error_message(errno), GMS_SERVER_MESSAGE);
114      exit(errno);
115    }
116  } else {
117    struct stat sbuf;
118   
119    fstat(msgfile, &sbuf);
120    if(sbuf.st_size == 0) {
121      /* an empty file means the same to the remote as a missing one. */
122      timestamp = 0;
123    } else {
124      /* for convenient maintenance, use the real timestamp as version
125       * number. */
126      timestamp = sbuf.st_mtime;
127    }
128  }
129  strcpy(buf,GMS_VERSION_STRING);
130  {
131    char tsbuf[GMS_TIMESTAMP_LEN];
132
133    /* sprintf (and _doprnt in general) are slow memory hogs. However,
134     * syslog is already including _doprnt, so it's already over; it
135     * is cheaper just to use sprintf here instead of coding or
136     * linking in the fast integer one.
137     * It is almost readable, too...
138     */
139    sprintf(tsbuf, " %lu\n", timestamp);
140    strcat(buf,tsbuf);
141    headerlen = strlen(buf);
142  }
143
144  /* Now that we have the header, we have to read the rest of the file
145   * into the packet after it. The length-1 specification is to
146   * preserve a NUL at the end of the buffer. Use msgfile to remember
147   * that we couldn't open it.
148   */
149  if(msgfile != -1) {
150    readlen = read(msgfile, buf + headerlen, GMS_MAX_MESSAGE_LEN-headerlen-1);
151    if(readlen == -1) {
152      /* read failed but open didn't, so record the error */
153      syslog(LOG_INFO, "GMS daemon read error [%s] reading message file <%s>",
154             error_message(errno), GMS_SERVER_MESSAGE);
155      exit(errno);
156    }
157    /* protect the fencepost... */
158    buf[GMS_MAX_MESSAGE_LEN-1] = '\0';
159    close(msgfile);
160  } else {
161    readlen = 0;
162  }
163  /* send the packet back where it came from */
164  if(-1 == sendto(0, buf, readlen+headerlen, 0, &from, sizeof(from))) {
165    /* the send failed (probably a local error, or bad address or
166     * something so log the attempt.
167     */
168    syslog(LOG_INFO, "GMS daemon sendto failure [%s] to %d.%d.%d.%d",
169           error_message(errno), saddr_list(cast2));
170    exit(errno);
171  }
172  /* everything worked, die happy... */
173  exit(0);
174}
Note: See TracBrowser for help on using the repository browser.