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: */