Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phServerSocket.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008     
00009     This file is part of Phission.
00010 
00011     Phission is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU Lesser 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     Phission is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public License
00022     along with Phission; if not, write to the Free Software
00023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025  ---------------------------------------------------------------------------*/
00026 /* -------------------------------------------------------------------------- *
00027  * phServerSocket.cpp: C++ Wrapper class for server socket programming        *
00028  *                                                                            *
00029  * -------------------------------------------------------------------------- *
00030  * This code is mostly from the Phission code base.                           *
00031  * This code was originally coded by John R. Watson in the Fall of 2003-2006 and   *
00032  * added to Phission by myself. Since then I've added some necessary          *
00033  * functionality for use in a streaming JPEG/Image server/client for Phission.*
00034  * I'm using it here to further stretch/test it's functionality               *
00035  * 
00036  * -------------------------------------------------------------------------- */
00037 #ifdef HAVE_CONFIG_H
00038     #include <phissionconfig.h>
00039 #endif
00040 
00041 #define PH_USE_SOCKET_PRIVATE 1
00042 #include <phSocketPrivate.h>
00043 
00044 #if defined(WIN32)
00045     #define __USE_W32_SOCKETS 1
00046     #ifndef _MSC_VER
00047         #include <windows.h>
00048         #include <winsock2.h>
00049     #else
00050         #include <winsock2.h>
00051         #include <windows.h>
00052     #endif
00053     #define ph_socket_listen      ::listen
00054     #define ph_socket_bind        ::bind
00055     #define ph_socket_accept      ::accept
00056     #define ph_socket_shutdown    shutdown
00057     #define ph_socket_close       close
00058     #define ph_socket_setsockopt  setsockopt
00059     #define ph_socket_gethostname gethostname
00060     #define ph_socket_select      select
00061 #endif
00062 
00063 #if defined(HAVE_SYS_SOCKET_H) && !defined(WIN32)
00064     #include <sys/socket.h>
00065     #define ph_socket_listen      ::listen
00066     #define ph_socket_bind        ::bind
00067     #define ph_socket_accept      ::accept
00068     #define ph_socket_shutdown    shutdown
00069     #define ph_socket_close       close
00070     #define ph_socket_setsockopt  setsockopt
00071     #define ph_socket_gethostname gethostname
00072     #define ph_socket_select      select
00073 #endif /* defined(HAVE_SYS_SOCKET_H) && !defined(WIN32) */
00074 
00075 #if !defined(WIN32)
00076     #if defined(HAVE_UNISTD_H)
00077         #include <unistd.h>
00078     #endif
00079     #if defined(HAVE_ERRNO_H)
00080         #include <errno.h>
00081     #endif
00082 #endif
00083 
00084 #include <phStandard.h>
00085 
00086 #include <phObject.h>
00087 #include <phMutex.h>
00088 #include <phSocket.h>
00089 
00090 #include <phServerSocket.h>
00091 
00092 #include <phError.h>
00093 #include <phMemory.h>
00094 #include <phPrint.h>
00095 
00096 #if defined(HAVE_LWIP_SOCKETS_H)
00097     #define LWIP_PROVIDE_ERRNO
00098     #include <lwip/sockets.h>
00099     #include <lwip/cglobals.h>
00100     #include <lwip/inet.h>
00101     #undef accept
00102     #undef bind
00103     #undef shutdown
00104     #undef close
00105     #undef connect
00106     #undef getsockname
00107     #undef getpeername
00108     #undef setsockopt
00109     #undef getsockopt
00110     #undef listen
00111     #undef recv
00112     #undef read
00113     #undef recvfrom
00114     #undef send
00115     #undef sendto
00116     #undef socket
00117     #undef write
00118     #undef select
00119     #undef ioctlsocket
00120     
00121     #define ph_socket_accept(a,b,c)         lwip_accept(a,b,c)
00122     #define ph_socket_bind(a,b,c)           lwip_bind(a,b,c)
00123     #define ph_socket_shutdown(a,b)         lwip_shutdown(a,b)
00124     #define ph_socket_close(s)              lwip_close(s)
00125     #define ph_socket_connect(a,b,c)        lwip_connect(a,b,c)
00126     #define ph_socket_getsockname(a,b,c)    lwip_getsockname(a,b,c)
00127     #define ph_socket_getpeername(a,b,c)    lwip_getpeername(a,b,c)
00128     #define ph_socket_setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)
00129     #define ph_socket_getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)
00130     #define ph_socket_listen(a,b)           lwip_listen(a,b)
00131     #define ph_socket_recv(a,b,c,d)         lwip_recv(a,b,c,d)
00132     #define ph_socket_read(a,b,c)           lwip_read(a,b,c)
00133     #define ph_socket_recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)
00134     #define ph_socket_send(a,b,c,d)         lwip_send(a,b,c,d)
00135     #define ph_socket_sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f)
00136     #define ph_socket_socket(a,b,c)         lwip_socket(a,b,c)
00137     #define ph_socket_write(a,b,c)          lwip_write(a,b,c)
00138     #define ph_socket_select(a,b,c,d,e)     lwip_select(a,b,c,d,e)
00139     #define ph_socket_ioctlsocket(a,b,c)    lwip_ioctl(a,b,c)
00140     
00141     #define ph_socket_gethostaddr(iface,buf) gethostaddr(iface,buf)
00142 #endif
00143 
00144 #if !defined(WIN32) && \
00145     defined(HAVE_FCNTL_H) && \
00146     defined(HAVE_NETINET_IN_H) && \
00147     defined(HAVE_ARPA_INET_H) && \
00148     defined(HAVE_NETDB_H)
00149     #include <fcntl.h>
00150     #include <netinet/in.h>
00151     #include <arpa/inet.h>
00152     #include <netdb.h>
00153 #endif /* !WIN32 */
00154 
00155 /* ----------------------------------------------------------------------------
00156  * phServerSocket: communications object constructor
00157  * ------------------------------------------------------------------------- */
00158 phServerSocket::phServerSocket(int port,int backlog) 
00159 {
00160     phFUNCTION("phServerSocket::phServerSocket")
00161     int locked = 0;
00162     
00163     phTHIS_LOOSE_LOCK(locked);
00164 
00165     this->setName("phServerSocket");
00166     
00167     /* If the constructing function passed port and/or
00168      * backlog, set them here; otherwise the constructor
00169      * initializes them to the defaults using the default 
00170      * parameter values */
00171     this->m_backlog = 10;
00172 
00173     rc = this->setPort(port);
00174     rc = this->setBackLog(backlog);
00175     
00176     phTHIS_LOOSE_UNLOCK(locked);
00177 }
00178 
00179 /* ----------------------------------------------------------------------------
00180  * ~phServerSocket: communications object destructor
00181  * ------------------------------------------------------------------------- */
00182 phServerSocket::~phServerSocket()
00183 {
00184     phFUNCTION("phServerSocket::~phServerSocket")
00185     int locked = 0;
00186 
00187     phTHIS_LOOSE_LOCK(locked);
00188     
00189     /* shutdown the socket */
00190     if (this->getSocket() != 0)
00191     {
00192         if (this->m_call_shutdown)
00193         {
00194 #if phHAVE(SHUTDOWN)
00195             /* Use shutdown on the server accept socket to cleanly
00196              * shutdown the server socket and get rid of it's binding */
00197             rc = ph_socket_shutdown(this->getSocket(),phSHUT_RDWR);
00198             if (this->lastSocketError() == phENOTCONN) 
00199                 rc = phSUCCESS; /* ignore endpoint not connected */
00200             phPRINT_RC(rc,"shutdown","shutdown failed");
00201 #else
00202             #error "Don\'t have shutdown"
00203 #endif
00204         }
00205 #if defined(WIN32) && phHAVE(CLOSESOCKET)
00206         rc = closesocket(this->getSocket());
00207 #elif (!defined(WIN32))
00208         rc = ph_socket_close(this->getSocket());
00209 #else
00210     #if defined(WIN32)
00211         #error "Don\'t have closesocket"
00212     #else
00213         #error "Don\'t have close"
00214     #endif
00215 #endif
00216         /* Set socket back to the default */
00217         this->setSocket(0);
00218     }
00219 }
00220 
00221 /* -------------------------------------------------------------------------- *
00222  * copy:
00223  * -------------------------------------------------------------------------- */
00224 int phServerSocket::copy( phObject *copyto_obj ) 
00225 {
00226     return phObject::copy(copyto_obj); 
00227 }
00228 
00229 /* -------------------------------------------------------------------------- *
00230  * swap:
00231  * -------------------------------------------------------------------------- */
00232 int phServerSocket::swap( phObject *obj )
00233 { 
00234     return phObject::swap(obj); 
00235 }
00236 
00237 /* -------------------------------------------------------------------------- *
00238  * setPort:
00239  * -------------------------------------------------------------------------- */
00240 int phServerSocket::setPort(int port) 
00241 {
00242     return this->phSocket::setSrcPort(port); 
00243 }
00244 
00245 /* -------------------------------------------------------------------------- *
00246  * getPort:
00247  * -------------------------------------------------------------------------- */
00248 int phServerSocket::getPort()
00249 {
00250     return this->phSocket::getSrcPort(); 
00251 }
00252 
00253 /* -------------------------------------------------------------------------- *
00254  * setBackLog:
00255  * -------------------------------------------------------------------------- */
00256 int phServerSocket::setBackLog(int backlog)
00257 {
00258     phFUNCTION("phServerSocket::setBackLog")
00259     int locked = 0;
00260     
00261     phTHIS_LOCK(locked);
00262 
00263     /* Assign the passed backlog value */
00264     this->m_backlog = backlog;
00265     
00266     phTHIS_UNLOCK(locked);
00267 
00268     return phSUCCESS;
00269 error:
00270     phTHIS_ERROR_UNLOCK(locked);
00271 
00272     return phFAIL;
00273 }
00274 
00275 /* -------------------------------------------------------------------------- *
00276  * getBackLog: 
00277  * -------------------------------------------------------------------------- */
00278 int phServerSocket::getBackLog()
00279 {
00280     phFUNCTION("phServerSocket::getBackLog")
00281     int ret_val = 0;
00282     int locked = 0;
00283     
00284     phTHIS_LOCK(locked);
00285 
00286     /* Store the return value in a temp variable,
00287      * while thje object is locked */
00288     ret_val = this->m_backlog;
00289     
00290 error:
00291     phTHIS_ERROR_UNLOCK(locked);
00292 
00293     return ret_val;
00294 }
00295 
00296 /* ----------------------------------------------------------------------------
00297  * setBlocking:
00298  * ------------------------------------------------------------------------- */
00299 int phServerSocket::setBlocking(int set_blocking ) 
00300 { 
00301     return this->phSocket::setBlocking(set_blocking);
00302 }
00303 
00304 /* ----------------------------------------------------------------------------
00305  * wakeup:
00306  * ------------------------------------------------------------------------- */
00307 void phServerSocket::wakeup()
00308 {
00309     phFUNCTION("phServerSocket::wakeup")
00310 
00311     /* Call the parent wakeup */
00312     this->phSocket::wakeup();
00313     
00314     if (this->m_call_shutdown)
00315     {
00316 #if phHAVE(SHUTDOWN)
00317         /* Use shutdown on the socket to cleanly
00318          * shutdown the socket and get rid of it */
00319         rc = ph_socket_shutdown(this->getSocket(),phSHUT_RDWR);
00320         if (this->lastSocketError() == phENOTCONN) rc = phSUCCESS; /* ignore endpoint not connected */
00321         phPRINT_RC(rc,"shutdown","shutdown failed");
00322 #else
00323         #error "Don\'t have shutdown"
00324 #endif
00325     }
00326     /* Just force the close of the socket, it's atomic at the kernel level */
00327     /* This should drop it out of an blocking calls */
00328 #if defined(WIN32) && phHAVE(CLOSESOCKET)
00329         rc = closesocket(this->getSocket());
00330 #elif (!defined(WIN32))
00331         rc = ph_socket_close(this->getSocket());
00332 #else
00333     #if defined(WIN32)
00334         #error "Don\'t have closesocket"
00335     #else
00336         #error "Don\'t have close"
00337     #endif
00338 #endif
00339         
00340     /* Set socket back to the default */
00341     this->setSocket(0);
00342 }
00343 
00344 /* ------------------------------------------------------------------------- */
00345 int phServerSocket::isSockValid() 
00346 { 
00347     return (this->getSocket() > 0) ? 1 : 0; 
00348 }
00349 
00350 /* ----------------------------------------------------------------------------
00351  * listen: create a socket and listen on port for connections
00352  * ------------------------------------------------------------------------- */
00353 int phServerSocket::listen(const int port, const int backlog)
00354 {
00355     phFUNCTION("phServerSocket::listen")
00356     int                 val     = 0;
00357     int                 retrc   = phFAIL;
00358     int                 locked  = 0;
00359     int                 b_log   = 0;
00360     struct  sockaddr_in bind_sin;
00361     const int           bind_retries = 100;
00362     int                 bind_counter = -1;
00363 
00364     phTHIS_LOCK(locked);
00365   
00366     /* Check to make sure the port numbers are valid port numbers */
00367     /* Check the passed port value, and use it if it's valid */
00368     if ((port >= phSOCKET_PORTMIN) && (port <= phSOCKET_PORTMAX))
00369     {
00370         rc = this->setPort(port);
00371         phCHECK_RC(rc,NULL,"setPort");
00372     }
00373     /* if the member variable port number is invalid then phCHECK_RC -1 to 
00374      * return by way of 'error'. if the passed port is invalid and
00375      * the member port is invalid, we're hosed. */
00376     if (!((this->m_src_port >= phSOCKET_PORTMIN) && (this->m_src_port <= phSOCKET_PORTMAX )))
00377     {
00378         phCHECK_RC(-1,NULL,"Bad parameter: this->m_src_port not in range (%d,%d)",
00379                  phSOCKET_PORTMIN,
00380                  phSOCKET_PORTMAX);
00381     }
00382 
00383     rc = this->initSocketVar();
00384     phCHECK_RC(rc,NULL,"initSocketVar");
00385 
00386     /* if we get killed (unlikely) and are unable to close our sockets,
00387      * this will let us bind() to the same port immedately.
00388      * 
00389      * This allows the port address to be REUSED.
00390      */ 
00391     val = 1;
00392 #if phHAVE(SETSOCKOPT)
00393     rc = ph_socket_setsockopt(this->getSocket(),
00394                               SOL_SOCKET,
00395                               SO_REUSEADDR,
00396                               ph_setsockopt_val_cast() &val,
00397                               sizeof(int));
00398 #else
00399     #error "Don\'t have setsockopt"
00400 #endif
00401 #if 0
00402     if (rc < 0)
00403     {
00404         /* If there is an error, then return by way of error with
00405          * the error return value for this specific part of the method*/
00406         if (this->m_warning_level > 0)
00407         {
00408             phSOCK_ERR_PRINT("setsockopt() failed with %d",rc);
00409         }
00410         retrc = -2;
00411         goto error;
00412     }
00413 #endif
00414     
00415     /* Copy the address structure from the settings to the temporary 
00416      * structure */
00417     phMemcpy(&bind_sin,
00418              (struct sockaddr_in*)this->getSrcSinPtr(),
00419              sizeof(struct sockaddr_in));
00420             
00421     /* Set up the socket information structure with the
00422      * listening socket parameters */
00423     bind_sin.sin_addr.s_addr = htonl(INADDR_ANY);
00424 
00425     /* bind the socket */
00426     do
00427     {
00428 #if phHAVE(BIND)
00429         rc = ph_socket_bind(this->getSocket(),
00430                   (struct sockaddr*)&(bind_sin),
00431                   sizeof(struct sockaddr_in));
00432 #else
00433     #error "Don\'t have bind"
00434 #endif
00435         bind_counter++;
00436 
00437         /* try to work around the self connect bug that will
00438          * cause this to return with "port in use" when a socket
00439          * connects to itself */
00440     } while ((rc < 0) && (bind_counter < bind_retries));
00441     if (rc < 0)
00442     {
00443         if (this->m_warning_level > 0)
00444         {
00445             phSOCK_ERR_PRINT("bind() on port %u failed", 
00446                              this->m_src_port); 
00447         }
00448         retrc = -3;
00449         goto error;
00450     }
00451    
00452     /* Decide what the backlog value should be...
00453      * if it was passed to this method, use it... */
00454     if (backlog != -1)
00455     {
00456         b_log = backlog;
00457     }
00458     /* ... otherwise use the saved backlog value */
00459     else if (this->m_backlog <= 0)
00460     {
00461         b_log = 10;
00462     }
00463     
00464     /* Set outself as the source */
00465     rc = this->allocBuffer((uint8_t **)&(this->m_temp_buf),
00466                            &(this->m_temp_buf_size),
00467                            255);
00468     phPRINT_RC(rc,NULL,"allocBuffer(temp_buf,temp_buf_size,255)");
00469 
00470 #if phHAVE(GETHOSTNAME)
00471     rc = ph_socket_gethostname(this->m_temp_buf,this->m_temp_buf_size);
00472     phPRINT_RC(rc,"gethostname","gethostname failed.");
00473 #elif phHAVE(GETHOSTADDR)
00474     rc = ph_socket_gethostaddr(0,this->m_temp_buf);
00475     if (!rc)
00476     {
00477         phPRINT_RC(-1,"gethostaddr","gethostaddr failed (rc = %d)",rc);
00478     }
00479 #else
00480     #error "Don\'t have gethostname or gethostaddr"
00481 #endif
00482 
00483     rc = this->setSrcHost(this->m_temp_buf);
00484     phPRINT_RC(rc,NULL,"setSrcHost");
00485     
00486     /* start listening on the port */
00487 #if phHAVE(LISTEN)
00488     rc = ph_socket_listen(this->getSocket(), b_log);
00489 #else
00490     #error "Don\'t have listen"
00491 #endif
00492     if (rc < 0)
00493     {
00494         if (this->m_warning_level > 0)
00495         {
00496             phSOCK_ERR_PRINT("listen() on port %u failed", 
00497                              this->m_src_port);
00498         }
00499         retrc = -4;
00500         goto error;
00501     }
00502 
00503     phTHIS_UNLOCK(locked);
00504     
00505     return phSUCCESS;
00506 error:
00507     phTHIS_ERROR_UNLOCK(locked);
00508 
00509     return retrc;
00510 }
00511     
00512 /* ----------------------------------------------------------------------------
00513  * accept: accept a client connection
00514  * ------------------------------------------------------------------------- */
00515 phSocket *phServerSocket::accept()
00516 {
00517     phFUNCTION("phServerSocket::accept")
00518     phSocket *clientSocket = NULL;
00519     int clientSock = -1;
00520     int client_accepted = 0;
00521     int locked = 0;
00522     
00523     /* Permit sending and recving at the same time, release the lock before
00524      * sending to prevent the recv from being blocked */
00525     rc = this->m_accept_lock.lock();
00526     phPRINT_RC(rc,NULL,"this->m_accept_lock.lock() failed.");
00527     
00528     phTHIS_LOCK(locked);
00529     
00530     /* reset the trigger */
00531     this->m_exit_trigger = 0;
00532     
00533     /* Loop until we've accepted a client */
00534     while (client_accepted == 0)
00535     {
00536         /* return if the trigger has been set */
00537         if (this->m_exit_trigger == 1)
00538         {
00539             goto error;
00540         }
00541     
00542         /* check to see if the socket is ready so we
00543          * can poll in this accept loop and allow the loop to be
00544          * canceled using the 'wakeup' feature that sets the 
00545          * m_exit_trigger variable */
00546         if (this->isReady())
00547         {
00548             phTHIS_UNLOCK(locked);
00549             
00550 #if phHAVE(ACCEPT)
00551             clientSock = ph_socket_accept((int)this->getSocket(), NULL, NULL);
00552 #else
00553             #error "Don\'t have accept"
00554 #endif
00555             phTHIS_LOCK(locked);
00556             
00557             if (clientSock < 0)
00558             {
00559                 /* Disable handling of a few of the errno cases so
00560                  * they can be handled more cleanly by phSocket */
00561                 switch (this->lastSocketError())
00562                 {
00563                     case phEINTR:
00564                         break;
00565                     case phEWOULDBLOCK:
00566                         break;
00567                     case phECONNABORTED:
00568                         break;
00569 #if !defined(WIN32)
00570                     case phEPROTO:
00571                         break;
00572 #endif                    
00573                     default:
00574                         if (this->m_warning_level > 0)
00575                         {
00576                             phSOCK_ERR_PRINT("accept() on port %u failed", 
00577                                              this->m_src_port);
00578                         }
00579                         goto error;
00580                 }
00581             }
00582             else
00583             {
00584                 rc = this->m_accept_lock.unlock();
00585                 phPRINT_RC(rc,NULL,"this->m_accept_lock.unlock() failed.");
00586                 
00587                 /* This is the exit condition, when accept 
00588                  * returns a valid socket */
00589                 phTHIS_LOOSE_UNLOCK(locked);
00590                 locked = 0;
00591                 
00592                 client_accepted = 1;
00593             }
00594         }
00595         else
00596         {
00597             /* Slow the loop intensity by yielding */
00598             phYield();
00599         }
00600     }
00601 
00602     if (client_accepted == 1)
00603     {
00604         /* Create a new client socket object, set the socket # and return it */
00605         clientSocket = new phSocket();
00606         clientSocket->setSock(clientSock);
00607         clientSocket->setCallShutdown(1);
00608         clientSocket->setLinger(phNOLINGER);
00609     }
00610     
00611     return clientSocket;
00612 error:
00613             
00614     rc = this->m_accept_lock.unlock();
00615     phPRINT_RC(rc,NULL,"this->m_accept_lock.unlock() failed.");
00616     
00617     phTHIS_ERROR_UNLOCK(locked);
00618 
00619     return NULL;
00620 }
00621 
00622 /* ------------------------------------------------------------------------- *
00623  * print_object:
00624  * -------------------------------------------------------------------------- */
00625 int phServerSocket::print_object(FILE *fd)
00626 {
00627     phFUNCTION("phServerSocket::print_object")
00628     int retrc = phSUCCESS;
00629     int locked = 0;
00630 
00631     if (fd == NULL) return phFAIL;
00632     
00633     phTHIS_LOCK(locked);
00634 
00635     fprintf(fd,"\nphServerSocket[ %s:%d <- Net ]\n\n",
00636             this->getSrcHost(),
00637             this->getPort() );
00638     fflush(fd);        
00639 
00640 error:
00641     phTHIS_ERROR_UNLOCK(locked);
00642 
00643     return retrc;
00644 }




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:02 2007 for phission by  doxygen 1.4.4