SockServ.C

Go to the documentation of this file.
00001 /*!@file Beowulf/SockServ.C A simple multi-client socket server */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Beowulf/SockServ.C $
00035 // $Id: SockServ.C 12451 2010-01-02 23:51:24Z lior $
00036 //
00037 
00038 #include "Beowulf/SockServ.H"
00039 
00040 #include "Beowulf/BeowulfOpts.H"
00041 #include "Beowulf/TCPdefs.H"
00042 #include "Component/OptionManager.H"
00043 #include "Util/log.H"
00044 
00045 #include <arpa/inet.h>
00046 #include <ctype.h>
00047 #include <errno.h>
00048 #include <netdb.h>
00049 #include <netinet/in.h>
00050 #include <stdio.h>
00051 #include <string.h>
00052 #include <sys/socket.h>
00053 #include <sys/time.h>
00054 #include <sys/types.h>
00055 #include <time.h>
00056 #include <unistd.h>
00057 
00058 #define MYLOGID sock
00059 
00060 //! internal states (in 'state' member):
00061 #define SOCKSERV_UNCONFIGURED 0
00062 #define SOCKSERV_RUNNING      1
00063 #define SOCKSERV_BOGUS        2
00064 
00065 //! timeout for termination of idle clients, in seconds:
00066 #define CLITIMEOUT 3000
00067 
00068 // ######################################################################
00069 SockServ::SockServ(OptionManager& mgr, const std::string& descrName,
00070                    const std::string& tagName) :
00071   ModelComponent(mgr, descrName, tagName),
00072   itsPort(&OPT_SockServPort, this),
00073   itsServ("SockServServiceName", this, "uscbeo"),
00074   itsServType("SockServServiceType", this, "tcp"),
00075   itsCliTout("SockServCliTout", this, 3000),
00076   itsQlen("SockServQlen", this, 256)
00077 { state = SOCKSERV_UNCONFIGURED; }
00078 
00079 // ######################################################################
00080 SockServ::~SockServ()
00081 { IDLDEBUG("Terminating."); }
00082 
00083 // ######################################################################
00084 void SockServ::start1()
00085 {
00086   state = SOCKSERV_BOGUS;  // in case we terminate early
00087   nbclients = 0; nbnewcli = 0; nbrcli = 0; nbecli = 0; nbwcli = 0; nbnucli = 0;
00088 
00089   // fds which we monitor: nothing
00090   FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
00091 
00092   // find out our port from /etc/services if it is unset:
00093   if (itsPort.getVal() == 0) {
00094     struct servent *sv =
00095       getservbyname(itsServ.getVal().c_str(), itsServType.getVal().c_str());
00096     if (sv == NULL)
00097       {
00098         LERROR("%s/%s not set in /etc/services -- USING DEFAULT PORT",
00099                itsServ.getVal().c_str(), itsServType.getVal().c_str());
00100         itsPort.setVal(DEFPORT);
00101       }
00102     else
00103       itsPort.setVal(ntohs(sv->s_port));
00104     LINFO("Listening to port %d...", itsPort.getVal());
00105   }
00106 
00107   // ########## setup server:
00108   sock = socket(AF_INET, SOCK_STREAM, 0);
00109   if (sock == -1) { PLERROR("Cannot create server socket"); return; }
00110 
00111   struct sockaddr_in addr;
00112   addr.sin_family = AF_INET;
00113   addr.sin_addr.s_addr = htonl(INADDR_ANY);  // accept from any host
00114   addr.sin_port = htons(itsPort.getVal());
00115   if (bind(sock, (struct sockaddr*)(&addr), sizeof(addr)) == -1)
00116     {
00117       IDPLFATAL("Cannot bind server socket to port %d",
00118                 int(itsPort.getVal()));
00119       return;
00120     }
00121   if (listen(sock, itsQlen.getVal()) == -1)
00122     { IDPLFATAL("Cannot setup server listen queue"); return; }
00123   IDLDEBUG("Listen queue (len=%d) configured", itsQlen.getVal());
00124 
00125   // monitor server socket for read (=new client) and error
00126   FD_SET(sock, &readfds); FD_SET(sock, &exceptfds);
00127   state = SOCKSERV_RUNNING;
00128 }
00129 
00130 // ######################################################################
00131 void SockServ::stop2()
00132 {
00133   while(nbnewcli)
00134     { IDLDEBUG("Terminating new client %d", newcli[nbnewcli-1]);
00135     close(newcli[--nbnewcli]); }
00136   while(nbclients)
00137     { IDLDEBUG("Terminating client %d", cli[nbclients-1]);
00138     close(cli[--nbclients]); }
00139   if (sock != -1)
00140     { IDLDEBUG("Terminating server"); close(sock); sock = -1; }
00141 
00142   // fds which we monitor: nothing
00143   FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
00144 
00145   // get ready for a restart:
00146   nbclients = 0; nbnewcli = 0; nbrcli = 0; nbecli = 0; nbwcli = 0; nbnucli = 0;
00147   state = SOCKSERV_UNCONFIGURED;
00148 }
00149 
00150 // ######################################################################
00151 int SockServ::check(const int stimeout, const int utimeout)
00152 {
00153   if (state != SOCKSERV_RUNNING) return SOCKSERV_BUG;
00154   struct timeval timeout; timeout.tv_sec=stimeout; timeout.tv_usec=utimeout;
00155 
00156   // did we take care of all new clients since last check?
00157   if (nbnewcli) {
00158     IDLERROR("Terminating %d new clients from previous check", nbnewcli);
00159     for (int i = 0; i < nbnewcli; i ++) disconnect(newcli[i]);
00160     nbnewcli = 0;
00161   }
00162 
00163   // wait for activity on some of our fds:
00164   memcpy(&rfds, &readfds, sizeof(fd_set));
00165   memcpy(&wfds, &writefds, sizeof(fd_set));
00166   memcpy(&efds, &exceptfds, sizeof(fd_set));
00167   nbrcli = 0; nbwcli = 0; nbecli = 0;
00168 
00169   //  if (LOG_FLAGS & LOG_FULLTRACE) debug("Monitoring: ");
00170 
00171   int result = select(FD_SETSIZE, &rfds, &wfds, &efds, &timeout);
00172 
00173   //  if (LOG_FLAGS & LOG_FULLTRACE) debug("Activated:  "); printf("\n");
00174 
00175   if (result == -1) { IDPLERROR("Error in select"); return SOCKSERV_BUG; }
00176   else if (result > 0) {
00177     int tim = time(NULL);  // for timout of idle fds
00178 
00179     // ##### first, check activity on the server socket:
00180     if (FD_ISSET(sock, &rfds)) {                               // a new client!
00181       FD_CLR(sock, &rfds); // clear so we don't interpret it in client loop
00182       // establish connection with new client:
00183       struct sockaddr_in clientaddr;
00184       socklen_t client_addrlen = sizeof(clientaddr);
00185       int clientfd = accept(sock, (struct sockaddr *)(&clientaddr),
00186                             &client_addrlen);
00187       if (clientfd == -1)
00188         IDPLDEBUG("Accept failed. Bogus client ignored.");
00189       else {
00190         cliIP[clientfd] = ntohl(clientaddr.sin_addr.s_addr);
00191         cliPort[clientfd] = ntohs(clientaddr.sin_port);
00192 
00193         IDLDEBUG("Connect -- Adding %s:%hu as client %d",
00194                  inet_ntoa(clientaddr.sin_addr), cliPort[clientfd], clientfd);
00195         newcli[nbnewcli++] = clientfd;
00196       }
00197     }
00198     if (FD_ISSET(sock, &efds)) {
00199       FD_CLR(sock, &efds); IDLFATAL("I got messed-up"); state = SOCKSERV_BOGUS;
00200       return SOCKSERV_BUG;
00201     }
00202 
00203     // ##### now, check what's going on with the clients:
00204     for (int i = 0; i < nbclients; i ++) {
00205       int fd = cli[i];
00206       // check for clients ready to read from:
00207       if (FD_ISSET(fd, &rfds))
00208         { rcli[nbrcli++] = fd; if (clitimeout[fd] != -1) clitimeout[fd]=tim; }
00209       // check for clients ready for writing to them:
00210       if (FD_ISSET(fd, &wfds))
00211         { wcli[nbwcli++] = fd; if (clitimeout[fd] != -1) clitimeout[fd]=tim; }
00212       // check for errored clients:
00213       if (FD_ISSET(fd, &efds)) ecli[nbecli++] = fd;
00214       // check for timed-out clients:
00215       else if (clitimeout[fd] != -1 && tim - clitimeout[fd] > CLITIMEOUT)
00216         { IDLDEBUG("Timeout on client %d", fd); ecli[nbecli++] = fd; }
00217     }
00218   } else {  // select returned 0 (timeout); just check for timed-out clients
00219     int tim = time(NULL);  // for timout of idle fds
00220     for (int i = 0; i < nbclients; i ++)
00221       if (clitimeout[cli[i]] != -1 && tim - clitimeout[cli[i]] > CLITIMEOUT)
00222         { IDLDEBUG("Timeout on client %d", cli[i]); ecli[nbecli++] = cli[i]; }
00223   }
00224 
00225   if (nbnewcli == 0 && nbrcli == 0 && nbwcli == 0 && nbecli == 0)
00226     return SOCKSERV_IDLE;  // nothing interesting happened...
00227 
00228   // if we got some new clients, register them:
00229   if (nbnewcli) addNewClients();
00230 
00231   return SOCKSERV_ACTIV;
00232 }
00233 
00234 // ######################################################################
00235 int SockServ::getNewClient()
00236 { if (nbnewcli) return newcli[--nbnewcli]; else return 0; }
00237 
00238 // ######################################################################
00239 int SockServ::getReadClient()
00240 { if (nbrcli) return rcli[--nbrcli]; else return 0; }
00241 
00242 // ######################################################################
00243 int SockServ::getWriteClient()
00244 { if (nbwcli) return wcli[--nbwcli]; else return 0; }
00245 
00246 // ######################################################################
00247 int SockServ::getErrorClient()
00248 { if (nbecli) return ecli[--nbecli]; else return 0; }
00249 
00250 // ######################################################################
00251 in_addr_t SockServ::getClientIP(const int clifd) const
00252 {
00253   for (int i = 0; i < nbclients; i ++)
00254     if (cli[i] == clifd) return cliIP[clifd];
00255   IDLERROR("Unknown client %d", clifd);
00256   return 0;
00257 }
00258 
00259 // ######################################################################
00260 short int SockServ::getClientPort(const int clifd) const
00261 {
00262   for (int i = 0; i < nbclients; i ++)
00263     if (cli[i] == clifd) return cliPort[clifd];
00264   IDLERROR("Unknown client %d", clifd);
00265   return 0;
00266 }
00267 
00268 // ######################################################################
00269 int SockServ::getRWClient()
00270 {
00271   if (nbwcli) return wcli[--nbwcli];
00272   if (nbrcli) return rcli[--nbrcli];
00273   return 0;
00274 }
00275 
00276 // ######################################################################
00277 void SockServ::disconnect(const int client)
00278 {
00279   if (hasClient(client))
00280     {
00281       IDLDEBUG("Disconnecting client %d", client);
00282       FD_CLR(client, &readfds); FD_CLR(client, &writefds);
00283       FD_CLR(client, &exceptfds);
00284       close(client);  // terminate the connection
00285       deleteClient(client);
00286     }
00287   else
00288     IDLDEBUG("No client %d. Ignored.", client);
00289 }
00290 
00291 // ######################################################################
00292 bool SockServ::addUserClient(void* data)
00293 {
00294   if (nbnucli == MAXNBNUCLI) return false;
00295   nuclidata[nbnucli++] = data; return true;
00296 }
00297 
00298 // ######################################################################
00299 void* SockServ::getNewUserClient()
00300 {
00301   if (nbnucli) return nuclidata[--nbnucli];
00302   return NULL;
00303 }
00304 
00305 // ######################################################################
00306 void SockServ::addNewClients()
00307 { for (int i = 0; i < nbnewcli; i ++) addClient(newcli[i]); }
00308 
00309 // ######################################################################
00310 void SockServ::deleteClient(const int client)
00311 {
00312   for (int i = 0; i < nbclients; i ++)
00313     if (cli[i] == client) {  // found it
00314       for (int j = i+1; j < nbclients; j ++) cli[j-1] = cli[j];
00315       nbclients --; break;
00316     }
00317 }
00318 
00319 // ######################################################################
00320 bool SockServ::hasClient(const int client)
00321 {
00322   if (client == sock) // this is the server...
00323     { IDLDEBUG("Called on server socket!"); return false; }
00324   for (int i = 0; i < nbclients; i ++) if (cli[i] == client) return true;
00325   return false;
00326 }
00327 
00328 // ######################################################################
00329 bool SockServ::monitorRead(const int client, const bool startstop)
00330 {
00331   if (hasClient(client)) {
00332     if (startstop) FD_SET(client, &readfds); else FD_CLR(client, &readfds);
00333     return true;
00334   }
00335   return false;
00336 }
00337 
00338 // ######################################################################
00339 bool SockServ::monitorWrite(const int client, const bool startstop)
00340 {
00341   if (hasClient(client)) {
00342     if (startstop) FD_SET(client, &writefds); else FD_CLR(client, &writefds);
00343     return true;
00344   }
00345   return false;
00346 }
00347 
00348 // ######################################################################
00349 bool SockServ::monitorError(const int client, const bool startstop)
00350 {
00351   if (hasClient(client)) {
00352     if (startstop) FD_SET(client, &exceptfds); else FD_CLR(client, &exceptfds);
00353     return true;
00354   }
00355   return false;
00356 
00357 }
00358 
00359 // ######################################################################
00360 bool SockServ::noTimeOut(const int client)
00361 {
00362   if (hasClient(client)) { clitimeout[client] = -1; return true; }
00363   return false;
00364 }
00365 
00366 // ######################################################################
00367 void SockServ::resetTimeOut(const int client)
00368 { if (hasClient(client)) clitimeout[client] = time(NULL); }
00369 
00370 // ######################################################################
00371 void SockServ::addClient(const int client)
00372 {
00373   if (client < 0 || client >= FD_SETSIZE)
00374     { IDLDEBUG("Invalid client number %d. Ignored.", client); return; }
00375   if (hasClient(client)) IDLDEBUG("Already have client %d. Ignored.", client);
00376   else { cli[nbclients++] = client; clitimeout[client] = time(NULL); }
00377 }
00378 
00379 // ######################################################################
00380 void SockServ::debug(const char *label)
00381 {
00382   printf("%s",label);
00383   for (int i = 0; i < FD_SETSIZE; i ++)
00384     if (FD_ISSET(i, &rfds) || FD_ISSET(i, &wfds) || FD_ISSET(i, &efds)) {
00385       printf("%d(", i);
00386       if (FD_ISSET(i, &rfds)) printf("R");
00387       if (FD_ISSET(i, &wfds)) printf("W");
00388       if (FD_ISSET(i, &efds)) printf("E");
00389       printf(") ");
00390     }
00391   printf("\n");
00392 }
00393 
00394 // ######################################################################
00395 /* So things look consistent in everyone's emacs... */
00396 /* Local Variables: */
00397 /* indent-tabs-mode: nil */
00398 /* End: */
Generated on Sun May 8 08:04:33 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3