Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

server.c

Go to the documentation of this file.
00001 /***************************************************************************
00002                                   server.c
00003                              -------------------
00004     begin                : Sun Nov 4 2001
00005     copyright            : (C) 2001-2002 by Christian Hoenig & Gunter Ohrner
00006     email                : pdepp@CustomCDROM.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00024 #include "common.h"
00025 
00026 #include <errno.h>
00027 
00028 // sys/types.h is a prerequisite for netinet/in.h on BSD
00029 #include <sys/types.h>
00030 // sys/socket.h is a prerequisite for netinet/in.h on BSD and MacOS X
00031 #include <sys/socket.h>
00032 #include <netinet/in.h>
00033 
00034 #include <pwd.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <time.h>
00038 #include <sys/time.h>
00039 #include <unistd.h>
00040 #include <grp.h>
00041 
00042 #include "server.h"
00043 
00044 #include "conftable.h"
00045 #include "conn_handler.h"
00046 #include "connhandlerlist.h"
00047 #include "logger.h"
00048 #include "signal_handler.h"
00049 #include "xmalloc.h"
00050 
00051 int changeUserGroupID();
00052 
00053 
00055 
00057 fd_set sock_recv_set;
00059 fd_set sock_send_set;
00061 fd_set sock_recv_ready_set, sock_send_ready_set;
00062 
00064 ConnHandlerList ch_list;
00065 
00066 
00077 int newServerSocket(unsigned short int port_num) {
00078   int server_sock;
00079   struct sockaddr_in local_addr;
00080 
00081   if ((server_sock = socket(PF_INET, SOCK_STREAM, 0)) == 0)
00082     return -1;
00083 
00084   local_addr.sin_family = AF_INET;
00085   local_addr.sin_port = htons((unsigned short) port_num);
00086   local_addr.sin_addr.s_addr = INADDR_ANY;
00087 
00088   if (bind(server_sock, (struct sockaddr *) &local_addr,
00089            sizeof(local_addr)) != 0)
00090     return -1;
00091 
00092   if (listen(server_sock, 10) != 0)
00093     return -1;
00094 
00095   return server_sock;
00096 }
00097 
00100 int svCloseConnection(ConnHandler ch)
00101 {
00102   int socket = chGetSocket(ch);
00103   if (FD_ISSET(socket, &sock_recv_set)) FD_CLR(socket, &sock_recv_set);
00104   if (FD_ISSET(socket, &sock_recv_ready_set)) FD_CLR(socket, &sock_recv_ready_set);
00105   if (FD_ISSET(socket, &sock_send_set)) FD_CLR(socket, &sock_send_set);
00106   if (FD_ISSET(socket, &sock_send_ready_set)) FD_CLR(socket, &sock_send_ready_set);
00107 
00108   chTerminate(ch);
00109   logger(PDEPP_CORE, NOTICE, "client connection closed");
00110   return 0;
00111 }
00112 
00116 int svMain(const int port)
00117 {
00118   int server_sock, sock_max, conn_count;
00119   time_t conn_timeout = getEntryDeflI(CONFENTRY_KEY_CONNTIMEOUT, STD_CONFENTRY_VAL_CONNTIMEOUT);
00120   int conn_maxcount = getEntryDeflI(CONFENTRY_KEY_CONNMAXCOUNT, STD_CONFENTRY_VAL_CONNMAXCOUNT);
00121 
00123   int err, sock_num, conn_sock;
00124 
00125   running = true;
00126   
00127   if (port < 1 || port > 65535)
00128   {
00129     logger(PDEPP_CORE, CRITICAL, "svMain: Invalid port range!");
00130     return -1;
00131   }
00132 
00133   logger(PDEPP_CORE, NOTICE, "server starting...");
00134 
00135   if (conn_maxcount > FD_SETSIZE)
00136   {
00137     logger(PDEPP_CORE, ERROR, "configured maximum number of concurrent connections is too high, "
00138                               "maxmimum number supported on this platform is %u", FD_SETSIZE);
00139     conn_maxcount = FD_SETSIZE;
00140   }
00141   
00142   server_sock = newServerSocket(port);
00143   if (server_sock < 0)
00144   {
00145     logerr(PDEPP_CORE, CRITICAL, errno,
00146            "svMain: could not initialize server socket");
00147     return -1;
00148   }
00149 
00150   logger(PDEPP_CORE, NOTICE, "server initialized");
00151 
00152   //degrade the user if whished
00153   if (changeUserGroupID() < 0)
00154     return -1;
00155 
00156   printf("server running at port %d\n", port);
00157 
00158   FD_ZERO(&sock_recv_set);
00159   FD_SET(server_sock, &sock_recv_set);
00160 
00161   FD_ZERO(&sock_send_set);
00162 
00163   ch_list = chListInit();
00164 
00165   sock_max = server_sock;
00166   conn_count = 1;
00167 
00168   while (running)
00169   {
00170 //    int sock_num;
00171 
00172     sock_recv_ready_set = sock_recv_set;
00173     sock_send_ready_set = sock_send_set;
00174 
00175     errno = 0;
00176 
00177     sock_num = select(sock_max+1, &sock_recv_ready_set, &sock_send_ready_set, NULL, NULL);
00178 
00179     if (sock_num == -1)
00180       switch(errno)
00181       {
00182 #ifndef NDEBUG
00183       case EINVAL:
00184       case EBADF:
00185         logerr(PDEPP_CORE, CRITICAL, errno,
00186                "svMain: internaol server error during select");
00187         abort();
00188 #endif
00189       case EINTR: // interrupted by signal, silently retry
00190         // logger(PDEPP_CORE, CRITICAL,
00191         //        "svMain: interrupted by signal %s, retrying", strsignal(caught_signal));
00192         continue;
00193       case ENOMEM:
00194         logerr(PDEPP_CORE, CRITICAL, errno,
00195                "svMain: select ran out of memory");
00196         return -1;
00197       default:
00198         logerr(PDEPP_CORE, WARNING, errno,
00199                "svMain: select failed, retrying");
00200         continue;
00201         // return -1;
00202       }
00203 #ifndef NDEBUG
00204     else
00205       if (sock_num == 0) // timeout, cannot currently happen
00206       {
00207         logerr(PDEPP_CORE, CRITICAL, errno, "svMain: select returned 0!!!");
00208         continue; // retry anyway!
00209       }
00210 #endif
00211 
00212     FD_ZERO(&sock_send_set);
00213 
00214     if (FD_ISSET(server_sock, &sock_recv_ready_set))
00215     {
00216       ConnHandler new_ch;
00217 
00218       new_ch = chInit(server_sock);
00219       if (new_ch != NULL)
00220       {
00221         int new_sock = chGetSocket(new_ch);
00222         if(conn_count < conn_maxcount) {
00223           FD_SET(new_sock, &sock_recv_set);
00224           chListAppend(ch_list, new_ch);
00225           sock_max = (new_sock > sock_max) ? new_sock : sock_max;
00226           ++conn_count;
00227         } else {
00228           // too many connections, reject
00229           chTerminate(new_ch);
00230           logger(PDEPP_CORE, WARNING, "rejected client: too many connections");
00231         }
00232       }
00233     }
00234     
00235     chListFirst(ch_list);
00236     while (!chListIsTail(ch_list))
00237     {
00238 //      int err = 0;
00239       ConnHandler ch = chListGetPayload(ch_list);
00240       err = 0;
00241       /*int*/ conn_sock = chGetSocket(ch);
00242 
00243       if (FD_ISSET(conn_sock, &sock_recv_ready_set))
00244         err = chReceive(ch);
00245       if (err == 0)
00246         err = chProcess(ch);
00247       if (err == 0 && FD_ISSET(conn_sock, &sock_send_ready_set))
00248         err = chSend(ch);
00249 
00250       if ((time(NULL) - chGetStamp(ch)) > conn_timeout)
00251       {
00252         logger(PDEPP_CORE, WARNING, "%u: client connection timed out", conn_sock);
00253         err = -1;
00254       }
00255 
00256       // socket still active?
00257       if (err == 0)
00258         if (chIsDataPending(ch))
00259           FD_SET(conn_sock, &sock_send_set);
00260 
00261       if (err != 0)
00262       {
00263         if (err != 1)
00264           logerr(PDEPP_CORE, NOTICE, chGetError(ch), "client connection error");
00265         svCloseConnection(ch);
00266         chListDelete(ch_list);
00267         --conn_count;
00268       } else
00269         chListNext(ch_list);
00270     }
00271   }
00272   
00273   // this is the beginning of the end of pdepp !!!
00274   // here the first things are cleared and freed, after (int)running is set to false by a signal
00275 
00276   if (caught_signal != 0)
00277   {
00278 #ifdef HAVE_STRSIGNAL
00279     logger(PDEPP_CORE, CRITICAL,
00280            "caught signal \"%s\", server terminating", strsignal(caught_signal));
00281 #else
00282     logger(PDEPP_CORE, CRITICAL,
00283            "caught signal %d, server terminating", caught_signal);
00284 #endif
00285   }
00286 
00287   // we first free and clear the connHandler list...
00288   chListFirst(ch_list);
00289   while(!chListIsTail(ch_list))
00290   {
00291     chTerminate(chListGetPayload(ch_list));
00292     chListDelete(ch_list);
00293   }
00294   chListTerminate(ch_list);
00295 
00296   // ...then return
00297   return 0;
00298 }
00299 
00300 
00308 int changeUserGroupID()
00309 {
00310   uid_t euid = geteuid();
00311   const char* new_user  = getEntryDefl(CONFENTRY_KEY_USER, STD_CONFENTRY_VAL_USER);
00312   const char* new_group = getEntryDefl(CONFENTRY_KEY_GROUP, STD_CONFENTRY_VAL_GROUP);
00313   struct passwd* pswd;
00314   struct group*  grp;
00315   
00316   //dont wonna change!
00317   if (strcmp(new_user, STD_CONFENTRY_VAL_USER) == 0
00318       && strcmp(new_group, STD_CONFENTRY_VAL_GROUP) == 0)
00319     return 0;
00320     
00321   //need to be root (== 0) to make the change
00322   if (euid != 0)
00323   {
00324     logger(PDEPP_CORE, CRITICAL, "Error changing user: You need to be root (check user/group settings in configfile)");
00325     return -1;
00326   }
00327 
00328   //convert the new_xx strings to numerical data to get the new_xxx pid/gid
00329   pswd = getpwnam(new_user);
00330   grp  = getgrnam(new_group);
00331   
00332   if (pswd == NULL)
00333   {
00334     logger(PDEPP_CORE, CRITICAL, "Error: Invalid user \"%s\" given!", new_user);
00335     return -1;
00336   }
00337   if (grp == NULL)
00338   {
00339     logger(PDEPP_CORE, CRITICAL, "Error: Invalid group \"%s\" given!", new_group);
00340     return -1;
00341   }
00342   
00343   //reset errno
00344   errno = 0;
00345 
00346   if (setgid(grp->gr_gid) < 0)
00347   {
00348     logger(PDEPP_CORE, CRITICAL,
00349            "Error: Could not change to given group \"%s\"!", new_group);
00350     return -1;
00351   }
00352   else if (setuid(pswd->pw_uid) < 0)
00353   {
00354     logger(PDEPP_CORE, CRITICAL,
00355            "Error: Could not change to given user \"%s\"!", new_user);
00356     return -1;
00357   }
00358   else
00359   {
00360     logger(PDEPP_CORE, INFO,
00361            "Successfully changed to user \"%s\" and group \"%s\"!"
00362            , new_user, new_group);
00363   }
00364 
00365   return 0;
00366 }

Generated on Fri Jan 25 22:40:31 2002 for PDepp Webserver by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001