sms_serv.c
上传用户:eo_sii
上传日期:2007-01-05
资源大小:91k
文件大小:17k
源码类别:

手机短信编程

开发平台:

Unix_Linux

  1. /*==========================================================
  2.  * Program : sms_serv.c                    Project : smslink
  3.  * Authors : Philippe Andersson.
  4.  *           Philipp Klaus <pklaus@access.ch>.
  5.  * Date    : 25/02/00
  6.  * Version : 0.44b
  7.  * Notice  : (c) Les Ateliers du Heron, 1998 for Scitex Europe, S.A.
  8.  *           contributions (c) Internet Access AG, 1999.
  9.  * Comment : SMS Server for Linux. Main source file (daemon core).
  10.  *
  11.  * Modification History :
  12.  * - 0.01a (12/08/98) : Initial release.
  13.  * - 0.02a (13/08/98) : Simmultaneous clients handling (fork).
  14.  * - 0.03a (25/08/98) : Daemonized it. Started to implement
  15.  *   use of syslog facility. Added handling function for SIGTERM.
  16.  * - 0.10a (27/28/98) : Merge sms_serv with the parser module.
  17.  * - 0.11a (01/09/98) : Completed output migration to socket
  18.  *   (printf's to sprintf's).
  19.  * - 0.12a (01/09/98) : Start implementing restricted access
  20.  *   to non-sharable resources (modems) through semaphores.
  21.  * - 0.13a (03/09/98) : Completed implementation of crit.
  22.  *   sections through semaphores and shared memory.
  23.  * - 0.14a (24/09/98) : Improved error handling when forking.
  24.  * - 0.15a (27/09/98) : Display local hostname on server announce.
  25.  * - 0.16a (30/09/98) : Reordered two lines - cosmetics.
  26.  * - 0.17a (19/10/98) : Changed 'struct modem_def' to 'struct
  27.  *   gsms_def' ; changed 'modemsdef' to 'gsmdevices'. Added
  28.  *   GSM devices array init. from config file (GSMDEVFILE) for
  29.  *   improved flexibility. Cosmetics.
  30.  * - 0.20a (20/10/98) : Merge test program into main source
  31.  *   tree. Implements the actual SMS sending.
  32.  * ++++ Switch to Beta ++++
  33.  * - 0.21b (21/10/98) : First beta release.
  34.  * - 0.22b (23/10/98) : Added 'user' member in struct 'symbols'.
  35.  * - 0.30b (22/11/98) : Start implementing logic to regularly
  36.  *   check on incoming messages.
  37.  * - 0.31b (13/12/98) : Moved to sigaction() signal handling.
  38.  *   Adapted gsmdevices initialization for new "owner" member.
  39.  * - 0.32b (14/12/98) : Inserted a 1 sec. sleep time in the
  40.  *   main loop. Prevents sms_serv eating up all the CPU cycles.
  41.  *   The side effect is a slight delay when connecting - ok.
  42.  * - 0.33b (06/02/99) : Included an access-list mechanism
  43.  *   based on the client's IP address. Contributed by Philipp
  44.  *   Klaus <pklaus@access.ch>.
  45.  * - 0.34b (14/02/99) : Implemented a more flexible version
  46.  *   of the ACL handling.
  47.  * - 0.40b (16/05/99) : Added "starttime" variable for uptime
  48.  *   computation.
  49.  * - 0.41b (20/07/99) : Finalized incoming messages processing.
  50.  *   No change to this file.
  51.  * - 0.42b (18/08/99) : Added handling for a checkpoint file
  52.  *   (for interaction with a SMS to Mail gateway module). Also
  53.  *   modified a bit the order of appearance for unistd.h. Removed
  54.  *   the HPUX-specific code.
  55.  * - 0.43b (08/09/99) : Included version info in the server's
  56.  *   initial syslog message.
  57.  * - 0.44b (25/02/00) : Improved handling of the ckeckpoint file
  58.  *   by mbchecker.c. No change in this file.
  59.  *========================================================*/
  60. #include <unistd.h>                      /* for getopt () */
  61. #include <sys/types.h>
  62. #include <sys/socket.h>
  63. #include <sys/sem.h>           /* for semaphore functions */
  64. #include <sys/shm.h>       /* for shared memory functions */
  65. #include <sys/ipc.h>
  66. #include <netinet/in.h>     /* for AF_INET domain sockets */
  67. #include <arpa/inet.h>                /* for inet_addr () */
  68. #include <netdb.h>                /* for gethostbyname () */
  69. #include <fcntl.h>                        /* for fcntl () */
  70. #include <time.h>                      /* for difftime () */
  71. #include <syslog.h>
  72. #include <signal.h>
  73. #include <stdio.h>
  74. #include <stdlib.h>
  75. #include <errno.h>
  76. #include <string.h>               /* for strcpy & friends */
  77. /*--------------------------------------Personal includes */
  78. #include "sms_serv.h"
  79. /*========================================================*/
  80. /**********             LOCAL DEFINES              ********/
  81. /*========================================================*/
  82. /* For debugging purposes only - comment out for normal compile */
  83. /* #define INCL_DEBUG_CODE */
  84. /*========================================================*/
  85. /**********           GLOBAL VARIABLES             ********/
  86. /*========================================================*/
  87. int csfd;                             /* client socket FD */
  88. char *buffer;                    /* read and write buffer */
  89. struct symbols symbols;              /* msg-specific data */
  90. int global_sem;       /* sem. for global send crit. sect. */
  91. int shmem_sem;             /* sem. for shared mem. access */
  92. int shmem_id;                   /* shared mem. identifier */
  93. void *shared_memory = (void *)0;     /* shared mem. addr. */
  94. time_t starttime;               /* for uptime calculation */
  95. struct gsms_def *gsmdevices;
  96. acl_list gsm_acl;
  97. int ngsmdevs = 0;                /* # defined GSM devices */
  98. /* for flex input */
  99. char myinput[];
  100. char *myinputptr;              /* current pos. in myinput */
  101. char *myinputlim;                   /* ptr to end of data */
  102. /*========================================================*/
  103. /**********               FUNCTIONS                ********/
  104. /*========================================================*/
  105. /*========================================================*/
  106. /**********           MAIN PROGRAM LOOP            ********/
  107. /*========================================================*/
  108. main ()
  109. {
  110.   struct servent *sent;
  111.   struct sockaddr_in s_addr;     /* server socket address */
  112.   struct sockaddr_in c_addr;     /* client socket address */
  113.   int ssfd;                           /* server socket FD */
  114.   int sockflags;                /* socket attribute flags */
  115.   time_t lastchked;
  116.   int c_addr_len;  /* size of struct returned by accept() */
  117.   int nread;
  118.   char *destgsm;
  119.   char *message;
  120.   char *localhost;
  121.   int pid, ppid, gppid;             /* for fork() testing */
  122.   int i;
  123.   int optval;                     /* INA setsockopt value */
  124.   struct gsms_def *gsmitem;
  125.   struct sigaction sa_f;
  126.   
  127.   /*-------------------------First, let's become a daemon */
  128.   gppid = fork ();
  129.   if (gppid == -1)
  130.     syserr ("sms_serv: grand-father can't fork");
  131.   else if (gppid != 0)
  132.          exit (0);                /* grand-father's death */
  133.   
  134.   /* open connection with the syslog daemon - announce */
  135.   openlog ("sms_serv", (LOG_CONS | LOG_PID), FACILITY);
  136.   syslog ((FACILITY | LOG_INFO), "server starting (v. %s)...", SMS_SERV_VERSION);
  137.   
  138.   /* let's become group leader (thereby loosing my tty) */
  139.   if (setpgrp () == -1)
  140.     syserr ("sms_serv: can't become group leader");
  141.   
  142.   /*--------------------------------------Initialisations */
  143.   /* Signal Handling - ignore some */
  144.   sa_f.sa_handler = SIG_IGN;
  145.   if (sigemptyset (&sa_f.sa_mask) == -1)
  146.     syserr ("sms_serv: can't empty signal set");
  147.   sa_f.sa_flags = 0;
  148.   if (sigaction (SIGHUP, &sa_f, NULL) == -1)    /* hangup */
  149.     syserr ("sms_serv: can't ignore SIGHUP");
  150.   if (sigaction (SIGCHLD, &sa_f, NULL) == -1) 
  151.     syserr ("sms_serv: can't ignore SIGCHLD");
  152.   /* now do something meaningfull on SIGTERM */
  153.   sa_f.sa_handler = daemons_death;
  154.   if (sigfillset (&sa_f.sa_mask) == -1)
  155.     syserr ("sms_serv: can't fill signal set");
  156.   sa_f.sa_flags = 0;
  157.   if (sigaction (SIGTERM, &sa_f, NULL) == -1)
  158.     syserr ("sms_serv: can't catch SIGTERM");
  159.     
  160.   /* first fork */
  161.   ppid = fork ();
  162.   if (ppid == -1)
  163.     syserr ("sms_serv: father can't fork");
  164.   else if (ppid != 0)
  165.          exit (0);                      /* father's death */
  166.   /*-------------------------------Start of daemon itself */
  167.   /* set the file creation mask */
  168.   /* umask (0); */
  169.   /* change directory to ...? */
  170. #ifndef INCL_DEBUG_CODE       /* we want to keep stdout for printf's */
  171.   /* close unused file descriptors */
  172. #endif
  173.   /* how many GSM devices do we have ? */
  174.   syslog ((FACILITY | LOG_INFO), "loading GSM module definitions...");
  175.   if ((ngsmdevs = getgsmdevscount (TRUE)) == 0) {
  176.     syslog ((FACILITY | LOG_INFO), "no GSM module definition found, exiting.");
  177.     syserr ("sms_serv: no defined GSM device");
  178.   }
  179. #ifdef INCL_DEBUG_CODE
  180.   fprintf (stderr, "getgsmdevscount() reported %d valid configsn", ngsmdevs);
  181. #endif
  182.   if (ngsmdevs > MAXMODEMS) {
  183.     syslog ((FACILITY | LOG_INFO), "too many GSM module definitions found, exiting.");
  184.     syserr ("sms_serv: hardware can't support that many serial devices");
  185.   }
  186.     
  187.   /* create and initialize semaphores */
  188.   if ((global_sem = semget (IPC_PRIVATE, 1, (0660 | IPC_CREAT | IPC_EXCL))) == -1)
  189.     syserr ("sms_serv: can't create global semaphore");
  190.   if (set_semvalue (global_sem, ngsmdevs) == -1)
  191.     syserr ("sms_serv: unable to initialize global semaphore");
  192.     
  193.   if ((shmem_sem = semget (IPC_PRIVATE, 1, (0660 | IPC_CREAT | IPC_EXCL))) == -1)
  194.     syserr ("sms_serv: can't create shmem semaphore");
  195.   if (set_semvalue (shmem_sem, 1) == -1)
  196.     syserr ("sms_serv: unable to initialize shmem semaphore");
  197.   
  198.   /* create shared memory segment */
  199.   if ((shmem_id = shmget (IPC_PRIVATE, (ngsmdevs * sizeof (struct gsms_def)),
  200.      (0660 | IPC_CREAT))) == -1)
  201.     syserr ("sms_serv: can't create shared memory segment");
  202.   if ((shared_memory = shmat (shmem_id, (void *)0, 0)) == (void *)-1)
  203.     syserr ("sms_serv: can't attach shared memory segment");
  204.   gsmdevices = (struct gsms_def *)shared_memory;
  205.   
  206.   /* now initialize shared memory with GSM devices definition */
  207.   setgsmdevs;
  208.   for (i = 0; i < ngsmdevs; i++) {
  209.     if ((gsmitem = getnextgsmdev ()) != NULL) {
  210.       if (gsmdevcpy (&gsmdevices[i], gsmitem) == -1)
  211.         syserr ("sms_serv: error copying GSM instance");
  212.       gsmdevices[i].free = TRUE;
  213.       gsmdevices[i].owner = 0;
  214.     }
  215.     else {
  216.       syserr ("sms_serv: error while reading config. file");
  217.     }
  218.   }                                      /* for (i = 0... */
  219.   if (i != ngsmdevs) {
  220.     syslog ((FACILITY | LOG_INFO), "internal error: expected %d, found %d definition(s)",
  221.            ngsmdevs, i);
  222.     syserr ("sms_serv: internal error, not all GSM modules accounted for");
  223.   }
  224.     
  225.   syslog ((FACILITY | LOG_INFO), "found %d GSM module definition(s)", ngsmdevs);
  226.   /*================================Real start of program */
  227.   /* get the hostname I'm running on */
  228.   localhost = (char *) malloc ((MINIBUFF + 1) * sizeof (char));
  229.   if (gethostname (localhost, MINIBUFF) == -1)
  230.     syserr ("sms_serv: can't get host name");
  231.   /* get the port number we should listen to */
  232.   if ((sent = getservbyname ("sms", "tcp")) == NULL)
  233.     syserr ("sms_serv: can't get service port info");
  234. #ifdef INCL_DEBUG_CODE
  235. printf ("found port <%d> for service smsn", ntohs (sent->s_port));
  236. #endif
  237.     
  238.   /* now fill in the socket address structure */
  239.   s_addr.sin_family = AF_INET;
  240.   s_addr.sin_port = sent->s_port;
  241.   s_addr.sin_addr.s_addr = htonl (INADDR_ANY);
  242.   /* INADDR_ANY allows connection to any valid IP address for this
  243.      host, including the loopback address. */
  244.   
  245.   /* let's create the socket */
  246.   if ((ssfd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP)) == -1)
  247.     syserr ("sms_serv: can't create socket");
  248.   
  249.   /* set socket options (INA)*/
  250.   optval = 1;
  251.   if (setsockopt (ssfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof (optval))) {
  252.        syserr ("sms_serv: can't set socket options to reuse");
  253.   }
  254.   /* load access control list */
  255.   acl_list_init (&gsm_acl);
  256.   if (! read_acl (&gsm_acl)) {
  257.     syserr ("sms_serv: can't read access control list");
  258.   }
  259.   /* end INA */
  260.   /* now bind the socket to the server address */
  261.   if (bind (ssfd, (struct sockaddr *) &s_addr, sizeof (s_addr)) == -1)
  262.     syserr ("sms_serv: can't bind socket");
  263.     
  264.   /* create the client queue on the socket */
  265.   if (listen (ssfd, MAXCLIENTCONN) == -1)
  266.     syserr ("sms_serv: can't listen to that many connections");
  267.   /* set the flags to make the socket "non-blocking" */
  268.   if ((sockflags = fcntl (ssfd, F_GETFL, 0)) == -1)
  269.     syserr ("sms_serv: can't get socket descriptor attributes");
  270.   if (fcntl (ssfd, F_SETFL, (O_NONBLOCK | sockflags)) == -1)
  271.     syserr ("sms_serv: can't set socket descriptor attributes");
  272.   /* initialize "last checked" time */
  273.   lastchked = time (NULL);
  274.   starttime = lastchked;
  275.   
  276.   syslog ((FACILITY | LOG_INFO), "server now ready to answer requests.");
  277.   /*---------------------------Start real processing loop */
  278.   while (TRUE) {
  279.     /* wait for a client to connect */
  280.     if ((csfd = accept (ssfd, (struct sockaddr *) &c_addr, &c_addr_len)) == -1) {
  281.       /* no connection - check the reason of the "error" */
  282.       switch (errno) {
  283.         case EWOULDBLOCK:
  284.   /* no error - time to check the mailbox ? */
  285.   if (difftime (time (NULL), lastchked) >= MBCHKINTERVAL) {
  286.     syslog ((FACILITY | LOG_INFO), "initiating mailbox check.");
  287.     /* now fork a child to handle mailbox check */
  288.     pid = fork ();
  289.     switch (pid) {
  290.       case (-1):                         /* error */
  291. syserr ("sms_serv: can't fork");
  292.         break;
  293.       case (0):
  294.         /* ###########< I'm the child >########## */
  295.         /*----Initialize child-specific variables */
  296. /*------------------------------Now do it */
  297. mbcheck_wrapper ();
  298. /*----------------------------Child exits */
  299. exit (0);
  300.         break;           /* Just to be consistent */
  301.       default:
  302.         /* ##########< I'm the father >########## */
  303. /* re-initialize timer */
  304.         lastchked = time (NULL);
  305.         break;
  306.     }                             /* switch (pid) */
  307.   }                            /* if (difftime... */
  308.   break;
  309. default:
  310.   /* there was a "real" error */
  311.           syserr ("sms_serv: can't accept incoming connection");
  312.   break;
  313.       }                                 /* switch (errno) */
  314.     }
  315.     else { /* we have a connection - handle it */
  316.       /* first check it against the acl (INA) */
  317.       if (! check_acl (&c_addr.sin_addr, gsm_acl)) {
  318.         syslog ((FACILITY | LOG_WARNING), "illegal connect from [%s]", inet_ntoa (c_addr.sin_addr));
  319.         /* close the socket */
  320.         if (close (csfd) == -1)
  321.           syserr ("sms_serv: can't close client socket");
  322.         continue;
  323.       }
  324.       /* for logging purposes */
  325.       syslog ((FACILITY | LOG_NOTICE), "connect from [%s]", inet_ntoa (c_addr.sin_addr));
  326.     
  327.       /* Now fork a child to handle each individ. request & go on listening */
  328.       pid = fork ();
  329.       switch (pid) {
  330.         case (-1):                               /* error */
  331.           syserr ("sms_serv: can't fork");
  332.   break;
  333.         case (0):
  334.   /* ###############< I'm the child >############ */
  335.   /*----------Initialize child-specific variables */
  336.   /* allocate space for the symbols */
  337.   symbols.smsc = (char *) malloc ((MAXPHNUMLEN + 1) * sizeof (char));
  338.   symbols.destgsm = (char *) malloc ((MAXPHNUMLEN + 1) * sizeof (char));
  339.   symbols.message = (char *) malloc ((MAXMSGLEN + 1) * sizeof (char));
  340.   symbols.user = (char *) malloc ((MAXUIDLEN + 1) * sizeof (char));
  341.   /* set those symbols to their default values */
  342.   strcpy (symbols.smsc, DEFAULTSMSC);
  343.   symbols.destgsm[0] = '';
  344.   symbols.message[0] = '';
  345.   symbols.user[0] = '';
  346.   /* scratch space for communication with the client */
  347.   buffer = (char *) malloc ((BUFFSIZE + 1) * sizeof (char));
  348.   buffer[0] = '';  
  349.   /*------------------------------Server announce */
  350.   sprintf (buffer, "SMS-Link for Linux, ver %s (%s) on %srn", SMS_SERV_VERSION,
  351.             SMS_SERV_DATE, localhost);
  352.   tellsock (csfd, buffer);
  353.   sprintf (buffer, "(c) Les Ateliers du Heron, 1998 for Scitex Europe, S.A.rn"
  354.           "(c) Internet Access AG, 1999rnrn");
  355.   tellsock (csfd, buffer);
  356.   /* enter the parser module - handle dialogue with client */
  357.   while (1) {
  358.             /* display prompt */
  359.             sprintf (buffer, PROMPT);
  360.             tellsock (csfd, buffer);
  361.     /* get client data */
  362.     buffer[0] = '';
  363.     nread = read (csfd, buffer, BUFFSIZE);
  364.     if (nread == -1)
  365.       syserr ("sms_serv: error while reading from socket");
  366.     buffer[nread] = '';     /* may not be needed, but can't harm */
  367.             /* prepare variables to be used by flex in the new YYINPUT */
  368.     myinputptr = buffer;
  369.     myinputlim = buffer + strlen (buffer);
  370.     /* parse client data */
  371.     parser ();
  372.   }                                  /* while (1) */
  373.   /*--------------------------Close client socket */
  374.   if (close (csfd) == -1)
  375.     syserr ("sms_serv: can't close client socket");
  376.   /*---------------------------------Child exists */
  377.   exit (0);
  378.   break; /* just to be consistent */
  379.       
  380.         default:
  381.      /* #############< I'm the father >############# */
  382.   /*--------------------------Close client socket */
  383.   if (close (csfd) == -1)
  384.     syserr ("sms_serv: can't close client socket");
  385.   break;
  386.       }                                   /* switch (pid) */
  387.     }                           /* if accept() .. else .. */
  388.     /* give the CPU some rest */
  389.     sleep (1);
  390.   }                                          /* while (1) */
  391.   /*------------------------------------------Conclusions */
  392.   /* close server socket */
  393.   if (close (ssfd) == -1)
  394.     syserr ("sms_serv: can't close server socket");
  395.     
  396.   /* let's clean what's allocated on the heap */
  397.   free (buffer);
  398.   free (destgsm);
  399.   free (message);
  400.   free (localhost);
  401.   /*------------------------------------------End program */
  402.   exit (0);
  403. }                                              /* main () */
  404. /*==========================================================
  405.  * EOF : sms_serv.c
  406.  *===================*/