sms_serv.c
上传用户:eo_sii
上传日期:2007-01-05
资源大小:91k
文件大小:17k
- /*==========================================================
- * Program : sms_serv.c Project : smslink
- * Authors : Philippe Andersson.
- * Philipp Klaus <pklaus@access.ch>.
- * Date : 25/02/00
- * Version : 0.44b
- * Notice : (c) Les Ateliers du Heron, 1998 for Scitex Europe, S.A.
- * contributions (c) Internet Access AG, 1999.
- * Comment : SMS Server for Linux. Main source file (daemon core).
- *
- * Modification History :
- * - 0.01a (12/08/98) : Initial release.
- * - 0.02a (13/08/98) : Simmultaneous clients handling (fork).
- * - 0.03a (25/08/98) : Daemonized it. Started to implement
- * use of syslog facility. Added handling function for SIGTERM.
- * - 0.10a (27/28/98) : Merge sms_serv with the parser module.
- * - 0.11a (01/09/98) : Completed output migration to socket
- * (printf's to sprintf's).
- * - 0.12a (01/09/98) : Start implementing restricted access
- * to non-sharable resources (modems) through semaphores.
- * - 0.13a (03/09/98) : Completed implementation of crit.
- * sections through semaphores and shared memory.
- * - 0.14a (24/09/98) : Improved error handling when forking.
- * - 0.15a (27/09/98) : Display local hostname on server announce.
- * - 0.16a (30/09/98) : Reordered two lines - cosmetics.
- * - 0.17a (19/10/98) : Changed 'struct modem_def' to 'struct
- * gsms_def' ; changed 'modemsdef' to 'gsmdevices'. Added
- * GSM devices array init. from config file (GSMDEVFILE) for
- * improved flexibility. Cosmetics.
- * - 0.20a (20/10/98) : Merge test program into main source
- * tree. Implements the actual SMS sending.
- * ++++ Switch to Beta ++++
- * - 0.21b (21/10/98) : First beta release.
- * - 0.22b (23/10/98) : Added 'user' member in struct 'symbols'.
- * - 0.30b (22/11/98) : Start implementing logic to regularly
- * check on incoming messages.
- * - 0.31b (13/12/98) : Moved to sigaction() signal handling.
- * Adapted gsmdevices initialization for new "owner" member.
- * - 0.32b (14/12/98) : Inserted a 1 sec. sleep time in the
- * main loop. Prevents sms_serv eating up all the CPU cycles.
- * The side effect is a slight delay when connecting - ok.
- * - 0.33b (06/02/99) : Included an access-list mechanism
- * based on the client's IP address. Contributed by Philipp
- * Klaus <pklaus@access.ch>.
- * - 0.34b (14/02/99) : Implemented a more flexible version
- * of the ACL handling.
- * - 0.40b (16/05/99) : Added "starttime" variable for uptime
- * computation.
- * - 0.41b (20/07/99) : Finalized incoming messages processing.
- * No change to this file.
- * - 0.42b (18/08/99) : Added handling for a checkpoint file
- * (for interaction with a SMS to Mail gateway module). Also
- * modified a bit the order of appearance for unistd.h. Removed
- * the HPUX-specific code.
- * - 0.43b (08/09/99) : Included version info in the server's
- * initial syslog message.
- * - 0.44b (25/02/00) : Improved handling of the ckeckpoint file
- * by mbchecker.c. No change in this file.
- *========================================================*/
- #include <unistd.h> /* for getopt () */
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/sem.h> /* for semaphore functions */
- #include <sys/shm.h> /* for shared memory functions */
- #include <sys/ipc.h>
- #include <netinet/in.h> /* for AF_INET domain sockets */
- #include <arpa/inet.h> /* for inet_addr () */
- #include <netdb.h> /* for gethostbyname () */
- #include <fcntl.h> /* for fcntl () */
- #include <time.h> /* for difftime () */
- #include <syslog.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h> /* for strcpy & friends */
- /*--------------------------------------Personal includes */
- #include "sms_serv.h"
- /*========================================================*/
- /********** LOCAL DEFINES ********/
- /*========================================================*/
- /* For debugging purposes only - comment out for normal compile */
- /* #define INCL_DEBUG_CODE */
- /*========================================================*/
- /********** GLOBAL VARIABLES ********/
- /*========================================================*/
- int csfd; /* client socket FD */
- char *buffer; /* read and write buffer */
- struct symbols symbols; /* msg-specific data */
- int global_sem; /* sem. for global send crit. sect. */
- int shmem_sem; /* sem. for shared mem. access */
- int shmem_id; /* shared mem. identifier */
- void *shared_memory = (void *)0; /* shared mem. addr. */
- time_t starttime; /* for uptime calculation */
- struct gsms_def *gsmdevices;
- acl_list gsm_acl;
- int ngsmdevs = 0; /* # defined GSM devices */
- /* for flex input */
- char myinput[];
- char *myinputptr; /* current pos. in myinput */
- char *myinputlim; /* ptr to end of data */
- /*========================================================*/
- /********** FUNCTIONS ********/
- /*========================================================*/
- /*========================================================*/
- /********** MAIN PROGRAM LOOP ********/
- /*========================================================*/
- main ()
- {
- struct servent *sent;
- struct sockaddr_in s_addr; /* server socket address */
- struct sockaddr_in c_addr; /* client socket address */
- int ssfd; /* server socket FD */
- int sockflags; /* socket attribute flags */
- time_t lastchked;
- int c_addr_len; /* size of struct returned by accept() */
- int nread;
- char *destgsm;
- char *message;
- char *localhost;
- int pid, ppid, gppid; /* for fork() testing */
- int i;
- int optval; /* INA setsockopt value */
- struct gsms_def *gsmitem;
- struct sigaction sa_f;
-
- /*-------------------------First, let's become a daemon */
- gppid = fork ();
- if (gppid == -1)
- syserr ("sms_serv: grand-father can't fork");
- else if (gppid != 0)
- exit (0); /* grand-father's death */
-
- /* open connection with the syslog daemon - announce */
- openlog ("sms_serv", (LOG_CONS | LOG_PID), FACILITY);
- syslog ((FACILITY | LOG_INFO), "server starting (v. %s)...", SMS_SERV_VERSION);
-
- /* let's become group leader (thereby loosing my tty) */
- if (setpgrp () == -1)
- syserr ("sms_serv: can't become group leader");
-
- /*--------------------------------------Initialisations */
- /* Signal Handling - ignore some */
- sa_f.sa_handler = SIG_IGN;
- if (sigemptyset (&sa_f.sa_mask) == -1)
- syserr ("sms_serv: can't empty signal set");
- sa_f.sa_flags = 0;
- if (sigaction (SIGHUP, &sa_f, NULL) == -1) /* hangup */
- syserr ("sms_serv: can't ignore SIGHUP");
- if (sigaction (SIGCHLD, &sa_f, NULL) == -1)
- syserr ("sms_serv: can't ignore SIGCHLD");
- /* now do something meaningfull on SIGTERM */
- sa_f.sa_handler = daemons_death;
- if (sigfillset (&sa_f.sa_mask) == -1)
- syserr ("sms_serv: can't fill signal set");
- sa_f.sa_flags = 0;
- if (sigaction (SIGTERM, &sa_f, NULL) == -1)
- syserr ("sms_serv: can't catch SIGTERM");
-
- /* first fork */
- ppid = fork ();
- if (ppid == -1)
- syserr ("sms_serv: father can't fork");
- else if (ppid != 0)
- exit (0); /* father's death */
- /*-------------------------------Start of daemon itself */
- /* set the file creation mask */
- /* umask (0); */
- /* change directory to ...? */
- #ifndef INCL_DEBUG_CODE /* we want to keep stdout for printf's */
- /* close unused file descriptors */
- #endif
- /* how many GSM devices do we have ? */
- syslog ((FACILITY | LOG_INFO), "loading GSM module definitions...");
- if ((ngsmdevs = getgsmdevscount (TRUE)) == 0) {
- syslog ((FACILITY | LOG_INFO), "no GSM module definition found, exiting.");
- syserr ("sms_serv: no defined GSM device");
- }
- #ifdef INCL_DEBUG_CODE
- fprintf (stderr, "getgsmdevscount() reported %d valid configsn", ngsmdevs);
- #endif
- if (ngsmdevs > MAXMODEMS) {
- syslog ((FACILITY | LOG_INFO), "too many GSM module definitions found, exiting.");
- syserr ("sms_serv: hardware can't support that many serial devices");
- }
-
- /* create and initialize semaphores */
- if ((global_sem = semget (IPC_PRIVATE, 1, (0660 | IPC_CREAT | IPC_EXCL))) == -1)
- syserr ("sms_serv: can't create global semaphore");
- if (set_semvalue (global_sem, ngsmdevs) == -1)
- syserr ("sms_serv: unable to initialize global semaphore");
-
- if ((shmem_sem = semget (IPC_PRIVATE, 1, (0660 | IPC_CREAT | IPC_EXCL))) == -1)
- syserr ("sms_serv: can't create shmem semaphore");
- if (set_semvalue (shmem_sem, 1) == -1)
- syserr ("sms_serv: unable to initialize shmem semaphore");
-
- /* create shared memory segment */
- if ((shmem_id = shmget (IPC_PRIVATE, (ngsmdevs * sizeof (struct gsms_def)),
- (0660 | IPC_CREAT))) == -1)
- syserr ("sms_serv: can't create shared memory segment");
- if ((shared_memory = shmat (shmem_id, (void *)0, 0)) == (void *)-1)
- syserr ("sms_serv: can't attach shared memory segment");
- gsmdevices = (struct gsms_def *)shared_memory;
-
- /* now initialize shared memory with GSM devices definition */
- setgsmdevs;
- for (i = 0; i < ngsmdevs; i++) {
- if ((gsmitem = getnextgsmdev ()) != NULL) {
- if (gsmdevcpy (&gsmdevices[i], gsmitem) == -1)
- syserr ("sms_serv: error copying GSM instance");
- gsmdevices[i].free = TRUE;
- gsmdevices[i].owner = 0;
- }
- else {
- syserr ("sms_serv: error while reading config. file");
- }
- } /* for (i = 0... */
- if (i != ngsmdevs) {
- syslog ((FACILITY | LOG_INFO), "internal error: expected %d, found %d definition(s)",
- ngsmdevs, i);
- syserr ("sms_serv: internal error, not all GSM modules accounted for");
- }
-
- syslog ((FACILITY | LOG_INFO), "found %d GSM module definition(s)", ngsmdevs);
- /*================================Real start of program */
- /* get the hostname I'm running on */
- localhost = (char *) malloc ((MINIBUFF + 1) * sizeof (char));
- if (gethostname (localhost, MINIBUFF) == -1)
- syserr ("sms_serv: can't get host name");
- /* get the port number we should listen to */
- if ((sent = getservbyname ("sms", "tcp")) == NULL)
- syserr ("sms_serv: can't get service port info");
- #ifdef INCL_DEBUG_CODE
- printf ("found port <%d> for service smsn", ntohs (sent->s_port));
- #endif
-
- /* now fill in the socket address structure */
- s_addr.sin_family = AF_INET;
- s_addr.sin_port = sent->s_port;
- s_addr.sin_addr.s_addr = htonl (INADDR_ANY);
- /* INADDR_ANY allows connection to any valid IP address for this
- host, including the loopback address. */
-
- /* let's create the socket */
- if ((ssfd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
- syserr ("sms_serv: can't create socket");
-
- /* set socket options (INA)*/
- optval = 1;
- if (setsockopt (ssfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval))) {
- syserr ("sms_serv: can't set socket options to reuse");
- }
- /* load access control list */
- acl_list_init (&gsm_acl);
- if (! read_acl (&gsm_acl)) {
- syserr ("sms_serv: can't read access control list");
- }
- /* end INA */
- /* now bind the socket to the server address */
- if (bind (ssfd, (struct sockaddr *) &s_addr, sizeof (s_addr)) == -1)
- syserr ("sms_serv: can't bind socket");
-
- /* create the client queue on the socket */
- if (listen (ssfd, MAXCLIENTCONN) == -1)
- syserr ("sms_serv: can't listen to that many connections");
- /* set the flags to make the socket "non-blocking" */
- if ((sockflags = fcntl (ssfd, F_GETFL, 0)) == -1)
- syserr ("sms_serv: can't get socket descriptor attributes");
- if (fcntl (ssfd, F_SETFL, (O_NONBLOCK | sockflags)) == -1)
- syserr ("sms_serv: can't set socket descriptor attributes");
- /* initialize "last checked" time */
- lastchked = time (NULL);
- starttime = lastchked;
-
- syslog ((FACILITY | LOG_INFO), "server now ready to answer requests.");
- /*---------------------------Start real processing loop */
- while (TRUE) {
- /* wait for a client to connect */
- if ((csfd = accept (ssfd, (struct sockaddr *) &c_addr, &c_addr_len)) == -1) {
- /* no connection - check the reason of the "error" */
- switch (errno) {
- case EWOULDBLOCK:
- /* no error - time to check the mailbox ? */
- if (difftime (time (NULL), lastchked) >= MBCHKINTERVAL) {
- syslog ((FACILITY | LOG_INFO), "initiating mailbox check.");
- /* now fork a child to handle mailbox check */
- pid = fork ();
- switch (pid) {
- case (-1): /* error */
- syserr ("sms_serv: can't fork");
- break;
- case (0):
- /* ###########< I'm the child >########## */
- /*----Initialize child-specific variables */
- /*------------------------------Now do it */
- mbcheck_wrapper ();
- /*----------------------------Child exits */
- exit (0);
- break; /* Just to be consistent */
- default:
- /* ##########< I'm the father >########## */
- /* re-initialize timer */
- lastchked = time (NULL);
- break;
- } /* switch (pid) */
- } /* if (difftime... */
- break;
- default:
- /* there was a "real" error */
- syserr ("sms_serv: can't accept incoming connection");
- break;
- } /* switch (errno) */
- }
- else { /* we have a connection - handle it */
- /* first check it against the acl (INA) */
- if (! check_acl (&c_addr.sin_addr, gsm_acl)) {
- syslog ((FACILITY | LOG_WARNING), "illegal connect from [%s]", inet_ntoa (c_addr.sin_addr));
- /* close the socket */
- if (close (csfd) == -1)
- syserr ("sms_serv: can't close client socket");
- continue;
- }
- /* for logging purposes */
- syslog ((FACILITY | LOG_NOTICE), "connect from [%s]", inet_ntoa (c_addr.sin_addr));
-
- /* Now fork a child to handle each individ. request & go on listening */
- pid = fork ();
- switch (pid) {
- case (-1): /* error */
- syserr ("sms_serv: can't fork");
- break;
-
- case (0):
- /* ###############< I'm the child >############ */
- /*----------Initialize child-specific variables */
- /* allocate space for the symbols */
- symbols.smsc = (char *) malloc ((MAXPHNUMLEN + 1) * sizeof (char));
- symbols.destgsm = (char *) malloc ((MAXPHNUMLEN + 1) * sizeof (char));
- symbols.message = (char *) malloc ((MAXMSGLEN + 1) * sizeof (char));
- symbols.user = (char *) malloc ((MAXUIDLEN + 1) * sizeof (char));
- /* set those symbols to their default values */
- strcpy (symbols.smsc, DEFAULTSMSC);
- symbols.destgsm[0] = ' ';
- symbols.message[0] = ' ';
- symbols.user[0] = ' ';
- /* scratch space for communication with the client */
- buffer = (char *) malloc ((BUFFSIZE + 1) * sizeof (char));
- buffer[0] = ' ';
- /*------------------------------Server announce */
- sprintf (buffer, "SMS-Link for Linux, ver %s (%s) on %srn", SMS_SERV_VERSION,
- SMS_SERV_DATE, localhost);
- tellsock (csfd, buffer);
- sprintf (buffer, "(c) Les Ateliers du Heron, 1998 for Scitex Europe, S.A.rn"
- "(c) Internet Access AG, 1999rnrn");
- tellsock (csfd, buffer);
- /* enter the parser module - handle dialogue with client */
- while (1) {
- /* display prompt */
- sprintf (buffer, PROMPT);
- tellsock (csfd, buffer);
- /* get client data */
- buffer[0] = ' ';
- nread = read (csfd, buffer, BUFFSIZE);
- if (nread == -1)
- syserr ("sms_serv: error while reading from socket");
- buffer[nread] = ' '; /* may not be needed, but can't harm */
- /* prepare variables to be used by flex in the new YYINPUT */
- myinputptr = buffer;
- myinputlim = buffer + strlen (buffer);
- /* parse client data */
- parser ();
- } /* while (1) */
- /*--------------------------Close client socket */
- if (close (csfd) == -1)
- syserr ("sms_serv: can't close client socket");
- /*---------------------------------Child exists */
- exit (0);
- break; /* just to be consistent */
-
- default:
- /* #############< I'm the father >############# */
- /*--------------------------Close client socket */
- if (close (csfd) == -1)
- syserr ("sms_serv: can't close client socket");
- break;
-
- } /* switch (pid) */
- } /* if accept() .. else .. */
- /* give the CPU some rest */
- sleep (1);
- } /* while (1) */
- /*------------------------------------------Conclusions */
- /* close server socket */
- if (close (ssfd) == -1)
- syserr ("sms_serv: can't close server socket");
-
- /* let's clean what's allocated on the heap */
- free (buffer);
- free (destgsm);
- free (message);
- free (localhost);
- /*------------------------------------------End program */
- exit (0);
- } /* main () */
- /*==========================================================
- * EOF : sms_serv.c
- *===================*/