Main Page Class Hierarchy Compound List File List Compound Members File Members

# socket_ew_common.c

Go to the documentation of this file.

    00001
    00002 /*
    00003  *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
    00004  *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
    00005  *
    00006  *    $Id: socket__ew__common_8c-source.html 2161 2006-05-19 16:55:03Z paulf $
    00007  *
    00008  *    Revision history:
    00009  *     $Log$
    00009  *     Revision 1.1  2006/05/19 16:55:02  paulf
    00009  *     first inclusion
    00009  *
    00010  *     Revision 1.4  2000/12/01 23:48:54  lombard
    00011  *     Fixed a few more logit format errors.
    00012  *
    00013  *     Revision 1.3  2000/07/10 21:14:51  lombard
    00014  *     Fixed bug in recvfrom_ew where improper arguments were used in recvfrom calls
    00015  *
    00016  *     Revision 1.2  2000/06/28 17:17:54  lombard
    00017  *     Fixed bug in format for logit calls after select errors, several places
    00018  *
    00019  *     Revision 1.1  2000/02/14 18:51:48  lucky
    00020  *     Initial revision
    00021  *
    00022  *
    00023  */
    00024
    00025 /****************** socket_ew_common *************************/
    00026
    00027 /*
    00028  * Changes:
    00029  * 12/7/1999, PNL
    00030  * Accept_ew now sets the new socket to non-blocking mode.
    00031  *  Previously it was assumed that the new socket inherited non-blocking
    00032  *  from the original socket; this is not true in WinNT or Solaris 2.6.
    00033  * Errors from select() calls are now handled.
    00034  */
    00035 /********************* #INCLUDES *****************************/
    00036 /*************************************************************/
    00037 #include <errno.h>
    00038 #include <socket_ew.h>
    00039
    00040 /********************** GLOBAL *******************************/
    00041 /********************* VARIABLES *****************************/
    00042 /*************************************************************/
    00043 /* Timeout used for select() calls: 0.2 seconds */
    00044 int SELECT_TIMEOUT_SECONDS=0;
    00045 int SELECT_TIMEOUT_uSECONDS=200000;
    00046
    00047 int EW_SOCKET_DEBUG=0;       /* Set by setSocket_ewDebug() */
    00048
    00049 extern int SOCKET_SYS_INIT;  /* Global initialization flag.
    00050                                 Declared in sys-dependent socket_ew.c,
    00051                                 set in SocketSysInit(),
    00052                                 checked in socket_ew()  */
    00053
    00054 /********************* SOCKET_ew *****************************/
    00055 /*********** Internal Utility Function Prototypes ************/
    00056 /*************************************************************/
    00057 struct timeval FAR * resetTimeout(struct timeval FAR *);
    00058 Time_ew adjustTimeoutLength(int timeout_msec);
    00059
    00060
    00061 /********************* SOCKET_ew *****************************/
    00062 /********************* Functions *****************************/
    00063 /*************************************************************/
    00064
    00065 SOCKET socket_ew (int af, int type, int protocol)
    00066 {
    00067   /* socket_ew() allocates a socket descriptor and associated
    00068      resources. It first makes sure that the Socket system has
    00069      been initialized, then it calls socket(), and finally sets
    00070      the socket descriptor to non-blocking mode.
    00071      Arguments af, type and protocol are passed directly to socket().
    00072      No network I/O occurs.
    00073      Caller can call socketGetError_ew() for details about any
    00074      failures.
    00075   */
    00076
    00077   SOCKET newSocket;
    00078   static char * MyFuncName = "socket_ew()";
    00079   int retVal;
    00080   unsigned long lOnOff=1;
    00081
    00082   if (EW_SOCKET_DEBUG)
    00083     logit("et","Entering %s\n",MyFuncName);
    00084
    00085   if (!SOCKET_SYS_INIT)
    00086     SocketSysInit();
    00087
    00088   newSocket = socket(af,type,protocol);
    00089   if (newSocket == INVALID_SOCKET  && EW_SOCKET_DEBUG)
    00090     logit("et","Error: %d, occurred in %s\n",
    00091           socketGetError_ew(),MyFuncName);
    00092
    00093   if (newSocket != INVALID_SOCKET)
    00094   {
    00095     retVal=ioctlsocket(newSocket,FIONBIO,&lOnOff);
    00096     if (retVal==SOCKET_ERROR)
    00097     {
    00098       if(EW_SOCKET_DEBUG)
    00099         logit("et","Error: %d, occurred in %s during change to non-blocking\n",
    00100               socketGetError_ew(),MyFuncName);
    00101       closesocket(newSocket);
    00102       return(SOCKET_ERROR);
    00103     }
    00104   }
    00105
    00106   if(EW_SOCKET_DEBUG)
    00107     logit("et","Exiting %s\n",MyFuncName);
    00108   return(newSocket);
    00109 }
    00110
    00111 /*************************************************************/
    00112
    00113 int connect_ew(SOCKET s, struct sockaddr FAR* name,
    00114                int namelen, int timeout_msec)
    00115 {
    00116   /* connect_ew() attempts to create a socket connection during a
    00117    * period specified by timeout.
    00118    * Arguments s, name, and namelenare passed directly to connect().
    00119    * On success conect_ew() returns zero.
    00120    * On failure, either due to a network error, or a timeout, conect_ew
    00121    * closes the socket and returns SOCKET_ERROR.
    00122    * *Note:  The timeout clock starts after connect_ew() calls
    00123    * connect(), not when connect_ew() starts.
    00124    * A timeout value of -1 causes connect_ew() to revert to a blocking
    00125    * connect call.
    00126    * Caller can call socketGetError_ew() for details about any
    00127    * failures.
    00128    */
    00129
    00130    static char * MyFuncName = "connect_ew()";
    00131
    00132    int     retVal, ioctlRetVal, connectRetVal, selectRetVal;
    00133    fd_set  ConnectedSockets;
    00134    long    lOnOff;
    00135    int     lastError;
    00136    struct  timeval SelectTimeout;
    00137
    00138   if ( EW_SOCKET_DEBUG )
    00139     logit( "et" , "Entering %s\n", MyFuncName );
    00140
    00141 /* If there is no timeout, make the socket blocking
    00142    ************************************************/
    00143    if ( timeout_msec == -1 )
    00144    {
    00145      lOnOff = 0;
    00146      ioctlRetVal = ioctlsocket( s, FIONBIO, &lOnOff );
    00147      if ( ioctlRetVal < 0 )
    00148      {
    00149        if ( EW_SOCKET_DEBUG )
    00150          logit( "et", "Error: %d, occurred in %s during change to blocking\n",
    00151                 socketGetError_ew(), MyFuncName );
    00152        retVal = -1;
    00153        goto Done;
    00154      }
    00155
    00156 /* Try to get a connection (blocking)
    00157  **********************************/
    00158      if ( connect( s, name, namelen ) == 0 )     /* Got a connection */
    00159        retVal = 0;
    00160      else                                        /* Didn't get a connection */
    00161        retVal = -1;
    00162
    00163 /* Change the socket back to non-blocking so
    00164    we don't screw up any further operations
    00165    *****************************************/
    00166       lOnOff = 1;
    00167       ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00168       if ( ioctlRetVal < 0 )
    00169       {
    00170         logit( "et", "Error: %d, occurred in %s during change to non-blocking\n",
    00171                socketGetError_ew(), MyFuncName );
    00172         retVal = -1;
    00173       }
    00174       goto Done;
    00175    }
    00176
    00177 /* Initiate a non-blocking connection request
    00178    ******************************************/
    00179    connectRetVal = connect( s, name, namelen );
    00180
    00181    if ( connectRetVal == 0 )                         /* Got a connection */
    00182    {
    00183       retVal = 0;
    00184       goto Done;
    00185    }
    00186
    00187    lastError = socketGetError_ew();
    00188
    00189    if ( lastError != CONNECT_WOULDBLOCK_EW )         /* Connect() error */
    00190    {
    00191      logit( "et", "Connect request failed in connect_ew(): %s.\n",
    00192             strerror(lastError) );
    00193      retVal = -1;
    00194      goto Done;
    00195    }
    00196
    00197 /* Hang around in select() until connect is successful
    00198                         or until timeout period expires
    00199    ****************************************************/
    00200    FD_ZERO( &ConnectedSockets );
    00201    FD_SET( s, &ConnectedSockets );
    00202
    00203    SelectTimeout.tv_sec  = timeout_msec/1000;
    00204    SelectTimeout.tv_usec = (timeout_msec%1000)*1000;
    00205
    00206    selectRetVal = select( s+1, 0, &ConnectedSockets, 0, &SelectTimeout );
    00207
    00208 /* select() failed
    00209    ***************/
    00210    if ( selectRetVal == -1 )
    00211    {
    00212      logit( "et", "select() failed in connect_ew(). Error: %d\n",
    00213             socketGetError_ew() );
    00214      retVal = -1;
    00215    }
    00216
    00217 /* select() succeeded; connection may have been completed
    00218    ******************************************************/
    00219    else if ( selectRetVal > 0  &&  FD_ISSET( s, &ConnectedSockets ) )
    00220    {
    00221    /* NOTE: For Solaris, we must do one more connection test.
    00222     *       Other possible tests besides getsockopt(SO_ERROR) could
    00223     *       be a zero-length read() or a call to getpeername()
    00224     */
    00225      int error, len, rc;
    00226      error = 0;
    00227      len = sizeof(error);
    00228      rc  = getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&error, &len);
    00229
    00230      if ( rc < 0 )          /* Pending error on some systems  */
    00231      {
    00232        error = socketGetError_ew();
    00233        retVal = -1;
    00234      }
    00235      else if ( error )      /* Pending error on others systems */
    00236      {
    00237        retVal = -1;
    00238      }
    00239      else                   /* OK, got a connection! */
    00240      {
    00241        if ( EW_SOCKET_DEBUG )
    00242          logit( "et", "Got a connection\n" );
    00243        retVal = 0;
    00244      }
    00245
    00246      if ( retVal == -1  &&  EW_SOCKET_DEBUG )
    00247        logit("et", "connect_ew() connection failed; "
    00248              "getsockopt detected error: %s.\n",
    00249              strerror(error) );
    00250    }
    00251
    00252 /* Only other possibility: select timed out!
    00253    *****************************************/
    00254    else
    00255    {
    00256      if ( EW_SOCKET_DEBUG ) /* this line added by Alex 2/9/99 */
    00257        logit( "et", "connect timed out in connect_ew().\n" );
    00258      retVal = -1;
    00259    }
    00260
    00261 Done:
    00262    if ( retVal == -1 )
    00263    {
    00264      closesocket_ew( s, SOCKET_CLOSE_SIMPLY_EW ); /*skip setsockopt()*/
    00265      retVal = SOCKET_ERROR;
    00266    }
    00267
    00268    if ( EW_SOCKET_DEBUG )
    00269      logit("et","Exiting %s\n",MyFuncName);
    00270
    00271    return(retVal);
    00272 }
    00273
    00274 /*************************************************************/
    00275
    00276 int bind_ew (SOCKET s, struct sockaddr FAR* name, int namelen )
    00277 {
    00278   /* bind_ew() attempts to bind the socket s to a name/port number.
    00279      This is basicly same as normal bind() call, with some logging added.
    00280      Caller can call socketGetError_ew() for details about any failures.
    00281   */
    00282
    00283   int retVal;
    00284   static char * MyFuncName = "bind_ew()";
    00285
    00286   if(EW_SOCKET_DEBUG)
    00287     logit("et","Entering %s\n",MyFuncName);
    00288
    00289   retVal=bind(s,name,namelen);
    00290   if (retVal < 0  && EW_SOCKET_DEBUG)
    00291     logit("et","Error: %d, occurred in %s\n",
    00292           socketGetError_ew(),MyFuncName);
    00293
    00294   if(EW_SOCKET_DEBUG)
    00295     logit("et","Exiting %s\n",MyFuncName);
    00296
    00297   return(retVal);
    00298 }
    00299
    00300 /*************************************************************/
    00301
    00302 int listen_ew (SOCKET s, int backlog )
    00303 {
    00304   /* listen_ew() signals the mysterious protocol stack god, that the
    00305      socket is ready to accept connections.
    00306      Arguments are passed directly to listen().
    00307      Caller can call socketGetError_ew() for details about any failures.
    00308   */
    00309
    00310   int retVal;
    00311   static char * MyFuncName = "listen_ew()";
    00312
    00313   if(EW_SOCKET_DEBUG)
    00314     logit("et","Entering %s\n",MyFuncName);
    00315
    00316   retVal=listen(s, backlog);
    00317   if (retVal < 0  && EW_SOCKET_DEBUG)
    00318     logit("et","Error: %d, occurred in %s\n",
    00319           socketGetError_ew(),MyFuncName);
    00320
    00321   if(EW_SOCKET_DEBUG)
    00322     logit("et","Exiting %s\n",MyFuncName);
    00323
    00324   return(retVal);
    00325 }
    00326
    00327 /*************************************************************/
    00328
    00329 SOCKET accept_ew(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen,
    00330                  int timeout_msec)
    00331 {
    00332   /* accept_ew() attempts to accept a connection on a socket.
    00333      Arguments s, addr, addrlen are passed directly to accept(),
    00334      timeout_msec: length of time in milliseconds that accept_ew()
    00335       will wait before returning. Timeout is measure from the
    00336       point after the initial accept() call.
    00337      Pass timeout of -1 for accept_ew to revert to blocking
    00338       accept() call.
    00339      If no connection is accepted before the timeout expires,
    00340       or if an error occurs, the function returns INVALID_SOCKET.
    00341      Caller can call socketGetError_ew() for details about
    00342      any failures.
    00343      If the latest socket error was WOULDBLOCK_EW, then
    00344       no connections were made during the timeout period.
    00345   */
    00346
    00347   SOCKET newSocket;
    00348   static char * MyFuncName = "accept_ew()";
    00349   Time_ew StartTime;
    00350   fd_set AcceptedSockets;
    00351   struct timeval SelectTimeout;
    00352   Time_ew timeout=adjustTimeoutLength(timeout_msec);
    00353   int retVal;
    00354   long lOnOff;
    00355   int sel;
    00356
    00357   if(EW_SOCKET_DEBUG)
    00358     logit("et","Entering %s\n",MyFuncName);
    00359
    00360   /* If there is no timeout, make the socket blocking */
    00361   if(timeout_msec == -1)
    00362   {
    00363     lOnOff = 0;
    00364     retVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00365
    00366     if (retVal < 0)
    00367     {
    00368       if(EW_SOCKET_DEBUG)
    00369         logit("et","Error: %d, occurred in %s during change to blocking\n",
    00370               socketGetError_ew(),MyFuncName);
    00371       goto Abort;
    00372     }
    00373   }
    00374
    00375   newSocket=accept(s,addr,addrlen);
    00376
    00377   /* If there is no timeout, then the call was made blocking,
    00378      change it back so that we don't screw up any further operations
    00379   */
    00380   if(timeout_msec == -1)
    00381   {
    00382     lOnOff = 1;
    00383     retVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00384     if (retVal==SOCKET_ERROR)
    00385     {
    00386       if(EW_SOCKET_DEBUG)
    00387         logit("et","Error: %d, occurred in %s during change to non-blocking\n",
    00388               socketGetError_ew(),MyFuncName);
    00389       goto Abort;
    00390     }
    00391   }
    00392
    00393   if (newSocket == INVALID_SOCKET)
    00394   {
    00395     if (socketGetError_ew() == WOULDBLOCK_EW)
    00396     {
    00397       FD_ZERO(&AcceptedSockets);
    00398       FD_SET(s,&AcceptedSockets);
    00399       StartTime=GetTime_ew();
    00400       while( (sel = select(s+1, &AcceptedSockets, 0, 0,
    00401                            resetTimeout(&SelectTimeout))) == 0)
    00402       { /* select timed out; if timeout hasn't expired, reset and try again */
    00403         if ( GetTime_ew() - timeout > StartTime )
    00404           return INVALID_SOCKET;
    00405
    00406         FD_ZERO(&AcceptedSockets);
    00407         FD_SET(s,&AcceptedSockets);
    00408         sleep_ew(1000);  /* Sleep for a second, and then try again.*/
    00409       }
    00410       if (sel < 0 && EW_SOCKET_DEBUG)
    00411       {
    00412         logit("et", "Error %d occured during select() in %s\n",
    00413               socketGetError_ew(), MyFuncName);
    00414         goto Abort;
    00415       }
    00416       newSocket=accept(s,addr,addrlen);
    00417     }
    00418     if(newSocket == INVALID_SOCKET && EW_SOCKET_DEBUG)
    00419     {
    00420       logit("et","Error: %d, occurred in %s\n",
    00421             socketGetError_ew(),MyFuncName);
    00422     }
    00423   }
    00424
    00425   /* Set the new socket to non-blocking mode */
    00426   lOnOff = 1;
    00427   retVal = ioctlsocket(newSocket,FIONBIO,&lOnOff);
    00428   if (retVal == SOCKET_ERROR)
    00429   {
    00430     if (EW_SOCKET_DEBUG)
    00431       logit("et","Error: %d, occurred in %s setting new socket to non-blocking\n",
    00432             socketGetError_ew(),MyFuncName);
    00433     goto Abort;
    00434   }
    00435   return(newSocket);
    00436
    00437 Abort:
    00438   if (newSocket > 0) closesocket_ew(newSocket, 0);
    00439   newSocket = INVALID_SOCKET;
    00440   closesocket_ew(s, 0);
    00441   s = INVALID_SOCKET;
    00442   return(newSocket);
    00443 }
    00444
    00445 /*************************************************************/
    00446
    00447 int recv_all (SOCKET s,char FAR* buf,int len,int flags, int timeout_msec)
    00448 {
    00449   /* recv_all attempts to receive data on a connection oriented scoket.
    00450      buf:     buffer for incoming data, which must be provided by the caller
    00451      len:     number of bytes to read; buffer must be at least len + 1 bytes.
    00452      flags:   flags that are passed directly to recv().
    00453      timeout: length of time in milliseconds that the recv_ew() will wait
    00454      before returning(if no data is received), after making the initial recv()
    00455      call.
    00456
    00457      If timeout_msec > 0, recv_all() returns when the sooner of two things
    00458      happens:
    00459      1.  The timeout from the time of the first recv() call, expires;
    00460      2.  "len" bytes of data are received.
    00461
    00462      recv_all() returns the number of bytes of data received, or SOCKET_ERROR
    00463      on error.  The caller is responsible for noting any discrepencies in the
    00464      difference between the number of bytes requested to be sent, and the
    00465      number of reported bytes sent.  If there is a discrepency, then a timeout
    00466      or error occured. Caller can call socketGetError_ew() for details about
    00467      any failures.
    00468
    00469      If timeout_msec == -1, recv_all() sets the socket to blocking and returns
    00470      when:
    00471      1. "len" bytes of data are received.
    00472      2. EOF is detected by recv returning 0 bytes.
    00473      */
    00474
    00475   int retVal,ioctlRetVal;
    00476   static char * MyFuncName = "recv_all()";
    00477   fd_set ReadableSockets;
    00478   Time_ew StartTime;
    00479   struct timeval SelectTimeout;
    00480   Time_ew timeout=adjustTimeoutLength(timeout_msec);
    00481   int BytesToRecv = len;
    00482   int BytesRcvd = 0;
    00483   int BytesJustRcvd;
    00484   long lOnOff;
    00485   int sel;
    00486
    00487   if(EW_SOCKET_DEBUG)
    00488     logit("et","Entering %s\n",MyFuncName);
    00489
    00490   /* If there is no timeout, make the socket blocking */
    00491   if(timeout_msec == -1)
    00492   {
    00493     lOnOff = 0;
    00494     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00495     if (ioctlRetVal==SOCKET_ERROR)
    00496     {
    00497       if(EW_SOCKET_DEBUG)
    00498         logit("et","Error: %d, occurred in %s during change to blocking\n",
    00499               socketGetError_ew(),MyFuncName);
    00500       return ioctlRetVal;
    00501     }
    00502   }
    00503
    00504   StartTime = GetTime_ew();
    00505   while ( BytesRcvd < BytesToRecv )
    00506   {
    00507     if ( (timeout_msec > 0) && ((GetTime_ew() - timeout) > StartTime ))
    00508     {  /* Time is up; return what we got */
    00509       retVal = BytesRcvd;
    00510       goto Done;
    00511     }
    00512     BytesJustRcvd = recv(s, buf + BytesRcvd, BytesToRecv - BytesRcvd, flags);
    00513     if ( BytesJustRcvd == 0 )        /* apparently EOF */
    00514     {
    00515       retVal = BytesRcvd;
    00516       goto Done;
    00517     }
    00518     if ( BytesJustRcvd < 0 ) /* Error happened */
    00519     {
    00520       if ( socketGetError_ew() == WOULDBLOCK_EW )
    00521       {
    00522         FD_ZERO(&ReadableSockets);
    00523         FD_SET(s,&ReadableSockets);
    00524         while( (sel = select(s+1, &ReadableSockets, 0, 0,
    00525                        resetTimeout(&SelectTimeout))) == 0)
    00526         { /* select timed out; if timeout hasn't expired, reset and try again */
    00527           if ( GetTime_ew() - timeout > StartTime )
    00528           {
    00529             retVal = BytesRcvd;
    00530             goto Done;
    00531           }
    00532           FD_ZERO(&ReadableSockets);
    00533           FD_SET(s,&ReadableSockets);
    00534           sleep_ew(100);  /* Wait a while, and then try
    00535                              again */
    00536         }
    00537         if (sel < 0)
    00538         {
    00539           logit("et", "Error %d occured during select() in %s\n",
    00540                 socketGetError_ew(), MyFuncName);
    00541           retVal = BytesRcvd;
    00542           goto Done;
    00543         }
    00544
    00545         /* Set BytesJustRcvd, so that we are not kicked out of the
    00546            while loop because of a hard error on a recv.  Note: we
    00547            will still be kicked out if we have exceeded the timeout.
    00548         */
    00549         BytesJustRcvd = 0;
    00550       }
    00551       else  /* some other error occured */
    00552       {
    00553         if(EW_SOCKET_DEBUG)
    00554           logit("et","Error: %d, occurred in %s\n",
    00555                 socketGetError_ew(),MyFuncName);
    00556         retVal = BytesJustRcvd; /* the error condition */
    00557         goto Done;
    00558       }
    00559     }  /* End of If there was an error on recv() */
    00560     else
    00561     {
    00562       BytesRcvd += BytesJustRcvd;
    00563     }
    00564   }  /* End: while not all data sent */
    00565   retVal = BytesRcvd;
    00566
    00567  Done:
    00568   /* If there is no timeout, then the call was made blocking,
    00569      change it back so that we don't screw up any further operations
    00570   */
    00571   if(timeout_msec == -1)
    00572   {
    00573     lOnOff = 1;
    00574     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00575     if (ioctlRetVal==SOCKET_ERROR)
    00576     {
    00577       if(EW_SOCKET_DEBUG)
    00578         logit("et","Error: %d, occurred in %s during change to non-blocking\n",
    00579               socketGetError_ew(),MyFuncName);
    00580     }
    00581   }
    00582
    00583   if(EW_SOCKET_DEBUG)
    00584     logit("et","Exiting %s\n",MyFuncName);
    00585
    00586   return(retVal);
    00587 }
    00588
    00589 /*************************************************************/
    00590
    00591 int recv_ew (SOCKET s, char FAR* buf, int len, int flags, int timeout_msec)
    00592 {
    00593   /* recv_ew attempts to receive data on a connection oriented scoket.
    00594      buf:     buffer for incoming data, which must be provided by the caller
    00595      len:     length of the buffer.
    00596      flags:   flags that are passed directly to recv().
    00597      timeout: length of time in milliseconds. that the recv_ew() will wait
    00598      before returning(if no data is received), after making
    00599      the initial recv() call. If data (or a shutdown request) is not
    00600      received before the timeout expires, or if an error occurs, the
    00601      function returns SOCKET_ERROR. As soon as any data is received,
    00602      the function returns; the function does not attempt to completely
    00603      fill the buffer before returning.
    00604      Caller can call socketGetError_ew() for details about any failures.
    00605      If the latest socket error is WOULDBLOCK_EW, then recv_ew timed out
    00606      before receiving any data,
    00607
    00608      If (-1) is passed for timeout_msec, then recv_ew() reverts to a blocking
    00609      recv() call.
    00610   */
    00611
    00612   int retVal,ioctlRetVal;
    00613   static char * MyFuncName = "recv_ew()";
    00614   fd_set ReadableSockets;
    00615   Time_ew StartTime;
    00616   struct timeval SelectTimeout;
    00617   Time_ew timeout=adjustTimeoutLength(timeout_msec);
    00618   long lOnOff;
    00619   int sel;
    00620
    00621   if(EW_SOCKET_DEBUG)
    00622     logit("et","Entering %s\n",MyFuncName);
    00623
    00624   /* If there is no timeout, make the socket blocking */
    00625   if(timeout_msec == -1)
    00626   {
    00627     lOnOff = 0;
    00628     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00629     if (ioctlRetVal==SOCKET_ERROR)
    00630     {
    00631       logit("et","Error: %d, occurred in %s during change to blocking\n",
    00632             socketGetError_ew(),MyFuncName);
    00633     }
    00634   }
    00635   retVal=recv(s,buf,len,flags);
    00636
    00637   /* If there is no timeout, then the call was made blocking,
    00638      change it back so that we don't screw up any further operations
    00639   */
    00640   if(timeout_msec == -1)
    00641   {
    00642     lOnOff = 1;
    00643     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00644       if (ioctlRetVal==SOCKET_ERROR)
    00645       {
    00646         logit("et","Error: %d, occurred in %s during change to non-blocking\n",
    00647               socketGetError_ew(),MyFuncName);
    00648       }
    00649   }
    00650
    00651   /* Use select() to wait for something to read. We use a small time interval
    00652    * (0.2 seconds) in select, and check the clock against timeout_msec (here
    00653    * converted to seconds) in a while() loop.
    00654    */
    00655   if (retVal < 0 && socketGetError_ew() == WOULDBLOCK_EW)
    00656   {
    00657     FD_ZERO(&ReadableSockets);
    00658     FD_SET(s,&ReadableSockets);
    00659     StartTime=GetTime_ew();
    00660     while( (sel = select(s+1, &ReadableSockets, 0, 0,
    00661                          resetTimeout(&SelectTimeout))) == 0 )
    00662     {  /* select timed out; if timeout hasn't expired, reset and try again */
    00663
    00664       if ( GetTime_ew() - timeout > StartTime )
    00665         break;
    00666       FD_ZERO(&ReadableSockets);
    00667       FD_SET(s,&ReadableSockets);
    00668       sleep_ew(100);  /* Wait a while, and then try again */
    00669     }
    00670     if (sel < 0)
    00671     {
    00672       logit("et", "Error %d occured during select() in %s\n",
    00673             socketGetError_ew(), MyFuncName);
    00674       return(SOCKET_ERROR);
    00675     }
    00676     /* Try to read, even if select() timed out */
    00677     retVal=recv(s,buf,len,flags);
    00678   }
    00679
    00680   if(retVal <0  && EW_SOCKET_DEBUG)
    00681   {
    00682     if (sel == 0)
    00683       logit("et", "Timeout occured in %s\n", MyFuncName);
    00684     else
    00685       logit("et","Error: %d, occurred in %s\n",
    00686             socketGetError_ew(),MyFuncName);
    00687   }
    00688
    00689   if(EW_SOCKET_DEBUG)
    00690                 logit("et","Exiting %s\n",MyFuncName);
    00691
    00692   return(retVal);
    00693 }
    00694
    00695 /*************************************************************/
    00696
    00697 int recvfrom_ew (SOCKET s, char FAR* buf, int len, int flags,
    00698                           struct sockaddr FAR* from, int FAR* fromlen,
    00699                           int timeout_msec)
    00700 {
    00701
    00702   /* recvfrom_ew() is similar to recv_ew(), except used for datagram
    00703      sockets.  timeout is specified in milliseconds.  Caller can call
    00704      socketGetError_ew() for details about any failures.
    00705   */
    00706
    00707   int retVal, ioctlRetVal;
    00708   static char * MyFuncName = "recvfrom_ew()";
    00709   fd_set ReadableSockets;
    00710   Time_ew StartTime;
    00711   struct timeval SelectTimeout;
    00712   Time_ew timeout=adjustTimeoutLength(timeout_msec);
    00713   long lOnOff;
    00714   int sel, flen;
    00715
    00716   if(EW_SOCKET_DEBUG)
    00717     logit("et","Entering %s\n",MyFuncName);
    00718
    00719
    00720   /* If there is no timeout, make the socket blocking */
    00721   if(timeout_msec == -1)
    00722   {
    00723     lOnOff = 0;
    00724     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00725     if (ioctlRetVal==SOCKET_ERROR)
    00726     {
    00727       logit("et","Error: %d, occurred in %s during change to blocking\n",
    00728             socketGetError_ew(),MyFuncName);
    00729       /* Should we return this error, or continue? */
    00730     }
    00731   }
    00732   /* Use a local copy of fromlen (because recvfrom sets fromlen=0 if socket is
    00733      non-blocking and there's no data => fromlen=0 input to second recvfrom) */
    00734   flen = *fromlen;
    00735   retVal = recvfrom(s,buf,len,flags,from,&flen);
    00736
    00737   /* If there is no timeout, then the call was made blocking,
    00738      change it back so that we don't screw up any further operations */
    00739   if(timeout_msec == -1)
    00740   {
    00741     lOnOff = 1;
    00742     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00743     if (ioctlRetVal==SOCKET_ERROR)
    00744     {
    00745       logit("et","Error: %d, occurred in %s during change to non-blocking\n",
    00746             socketGetError_ew(),MyFuncName);
    00747     }
    00748   }
    00749
    00750   if (retVal < 0 && socketGetError_ew() == WOULDBLOCK_EW)
    00751   {
    00752     FD_ZERO(&ReadableSockets);
    00753     FD_SET(s,&ReadableSockets);
    00754     StartTime=GetTime_ew();
    00755     while( (sel = select(s+1, &ReadableSockets, 0, 0,
    00756                          resetTimeout(&SelectTimeout))) == 0 )
    00757     {  /* select timed out; if timeout hasn't expired, reset and try again */
    00758
    00759       if ( GetTime_ew() - timeout > StartTime )
    00760         break;
    00761
    00762       FD_ZERO(&ReadableSockets);
    00763       FD_SET(s,&ReadableSockets);
    00764       sleep_ew(100);  /* Wait a while, and then try
    00765                     again */
    00766     }
    00767     if (sel < 0)
    00768     {
    00769       logit("et", "Error %d occured during select() in %s\n",
    00770             socketGetError_ew(), MyFuncName);
    00771       return(SOCKET_ERROR);
    00772     }
    00773     /* Try to read, even if select() timed out */
    00774     flen = *fromlen;
    00775     retVal = recvfrom(s,buf,len,flags,from,&flen);
    00776   }
    00777
    00778   if(retVal <0  && EW_SOCKET_DEBUG)
    00779   {
    00780     logit("et","Error: %d, occurred in %s\n",
    00781               socketGetError_ew(),MyFuncName);
    00782   }
    00783
    00784   if(EW_SOCKET_DEBUG)
    00785                 logit("et","Exiting %s\n",MyFuncName);
    00786
    00787   *fromlen = flen;
    00788   return(retVal);
    00789 }
    00790
    00791 /*************************************************************/
    00792
    00793 int send_ew ( SOCKET s, const char FAR * buf, int len, int flags,
    00794               int timeout_msec)
    00795 {
    00796   /* Send `len' bytes from `buf' out a socket `s'.
    00797      Argument `flags' is passed directly to send().
    00798      If timeout_msec > 0, send_ew() returns when the sooner of two things
    00799      happens:
    00800      1.  The timeout measured in milliseconds expires;
    00801      2.  All of the data provided by the caller is sent.
    00802      If timeout_msec == -1, the socket is set to blocking and send_ew()
    00803      returns when all the data is sent or an error occured.
    00804      send_ew() always returns when an unexpected error occurs.
    00805      send_ew() returns the number of bytes of data sent, or
    00806      SOCKET_ERROR on error.  The caller is responsible for noting
    00807      any discrepencies in the difference between the number of bytes
    00808      requested to be sent, and the number of reported bytes sent.  If
    00809      there is a discrepency, then a timeout may have occured.
    00810      Caller can call socketGetError_ew() for details about any failures.
    00811      If the latest socket error was WOULDBLOCK_EW, then
    00812       the timeout occured before all the data was sent.
    00813      */
    00814
    00815   int retVal, ioctlRetVal;
    00816   static char * MyFuncName = "send_ew()";
    00817   int BytesToSend=len;
    00818   int BytesSent=0;
    00819   int BytesJustSent=0;
    00820   Time_ew StartTime;
    00821   fd_set WriteableSockets;
    00822   struct timeval SelectTimeout;
    00823   Time_ew timeout=adjustTimeoutLength(timeout_msec);
    00824   long lOnOff;
    00825   int sel;
    00826
    00827   if(EW_SOCKET_DEBUG)
    00828     logit("et","Entering %s\n",MyFuncName);
    00829
    00830   /* If there is no timeout, make the socket blocking */
    00831   if(timeout_msec == -1)
    00832   {
    00833     lOnOff = 0;
    00834     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00835     if (ioctlRetVal==SOCKET_ERROR)
    00836     {
    00837       if(EW_SOCKET_DEBUG)
    00838         logit("et","Error: %d, occurred in %s during change to blocking\n",
    00839               socketGetError_ew(),MyFuncName);
    00840       return (ioctlRetVal);
    00841     }
    00842   }
    00843
    00844   StartTime = GetTime_ew();
    00845   while( BytesSent < BytesToSend )
    00846   {
    00847     if ( (timeout_msec >= 0) && ((GetTime_ew() - timeout) > StartTime ))
    00848     {
    00849       retVal = BytesSent;
    00850       goto Done;
    00851     }
    00852     BytesJustSent = send(s, buf+BytesSent, min(len-BytesSent, MAXSENDSIZE_EW),
    00853                          flags);
    00854     if (BytesJustSent <= 0)
    00855     {
    00856       if (BytesJustSent == 0 || socketGetError_ew() == WOULDBLOCK_EW)
    00857       {
    00858         FD_ZERO(&WriteableSockets);
    00859         FD_SET(s,&WriteableSockets);
    00860         while( (sel = select(s+1, 0, &WriteableSockets, 0,
    00861                              resetTimeout(&SelectTimeout))) == 0)
    00862         {  /* select timed out; if timeout hasn't expired, reset and try again */
    00863           if ( GetTime_ew() - timeout > StartTime )
    00864           {
    00865             retVal = BytesSent;
    00866             goto Done;
    00867           }
    00868
    00869           FD_ZERO(&WriteableSockets);
    00870           FD_SET(s,&WriteableSockets);
    00871           sleep_ew(100);  /* Wait a while, and then try again */
    00872         }
    00873         if (sel < 0)
    00874         {
    00875           logit("et", "Error %d occured during select() in %s\n",
    00876                 socketGetError_ew(), MyFuncName);
    00877           retVal = BytesSent;
    00878           goto Done;
    00879         }
    00880
    00881         /* Set BytesJustSent, so that we are not kicked out of the
    00882         while loop because of a hard error on a send.  Note:  we
    00883         will still be kicked out if we have exceeded the timeout.
    00884         */
    00885         BytesJustSent = 0;
    00886       }
    00887       else  /* some other error occured */
    00888       {
    00889         if(EW_SOCKET_DEBUG)
    00890           logit("et","Error: %d, occurred in %s\n",
    00891                 socketGetError_ew(),MyFuncName);
    00892         retVal = BytesSent;
    00893         goto Done;
    00894       }
    00895     }  /* End of If there was an error on send() */
    00896     else
    00897     {
    00898       BytesSent += BytesJustSent;
    00899     }
    00900   }  /* End: while not all data sent */
    00901   retVal = BytesSent;
    00902
    00903 Done:
    00904   /* If there is no timeout, then the call was made blocking,
    00905   change it back so that we don't screw up any further operations
    00906   */
    00907   if(timeout_msec == -1)
    00908   {
    00909     lOnOff = 1;
    00910     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00911     if (ioctlRetVal < 0)
    00912     {
    00913       if(EW_SOCKET_DEBUG)
    00914         logit("et","Error: %d, occurred in %s during change to non-blocking\n",
    00915         socketGetError_ew(),MyFuncName);
    00916       retVal = SOCKET_ERROR;
    00917     }
    00918   }
    00919
    00920   if(EW_SOCKET_DEBUG)
    00921     logit("et","Exiting %s\n",MyFuncName);
    00922
    00923   return(retVal);
    00924 }
    00925
    00926 /*************************************************************/
    00927
    00928 int sendto_ew (SOCKET s, const char FAR * buf, int len,
    00929                int flags, const struct sockaddr FAR * to,
    00930                int tolen, int timeout_msec)
    00931 {
    00932   /* sendto_ew() is similar to send_ew(), except used for datagram
    00933      sockets. Once the socket is ready for sending, sendto_ew calls
    00934      sendto() only once. No checks are made to ensure all data is sent.
    00935      Arguments s, flags, to,  and tolen are passed directly to sendto().
    00936      Timeout is specified in milliseconds; value of -1 sets socket to
    00937      blocking mode and turns off timing.
    00938      Caller can call socketGetError_ew() for details about any failures.
    00939   */
    00940
    00941   int retVal, ioctlRetVal;
    00942   static char * MyFuncName = "sendto_ew()";
    00943   Time_ew StartTime;
    00944   fd_set WriteableSockets;
    00945   struct timeval SelectTimeout;
    00946   Time_ew timeout=adjustTimeoutLength(timeout_msec);
    00947   long lOnOff;
    00948   int sel;
    00949
    00950   if(EW_SOCKET_DEBUG)
    00951     logit("et","Entering %s\n",MyFuncName);
    00952
    00953   /* If there is no timeout, make the socket blocking */
    00954   if(timeout_msec == -1)
    00955   {
    00956     lOnOff = 0;
    00957     ioctlRetVal=ioctlsocket(s,FIONBIO,&lOnOff);
    00958     if (ioctlRetVal==SOCKET_ERROR)
    00959     {
    00960       if(EW_SOCKET_DEBUG)
    00961       {
    00962         logit("et","Error: %d, occurred in %s during change to blocking\n",
    00963               socketGetError_ew(),MyFuncName);
    00964       }
    00965       return ioctlRetVal;
    00966     }
    00967   }
    00968
    00969   StartTime=GetTime_ew();
    00970   retVal = sendto(s,buf,len,flags,to,tolen);
    00971
    00972   /* If there is no timeout, then the call was made blocking,
    00973      change it back so that we don't screw up any further operations
    00974   */
    00975   if(timeout_msec == -1)
    00976   {
    00977     lOnOff = 1;
    00978     ioctlRetVal = ioctlsocket(s,FIONBIO,&lOnOff);
    00979     if (ioctlRetVal < 0)
    00980     {
    00981       if(EW_SOCKET_DEBUG)
    00982         logit("et","Error: %d, occurred in %s during change to non-blocking\n",
    00983         socketGetError_ew(),MyFuncName);
    00984       return SOCKET_ERROR;
    00985     }
    00986   }
    00987
    00988   if (retVal < 0 && socketGetError_ew() == WOULDBLOCK_EW)
    00989   {
    00990     FD_ZERO(&WriteableSockets);
    00991     FD_SET(s,&WriteableSockets);
    00992     while( (sel = select(s+1, 0, &WriteableSockets, 0,
    00993                          resetTimeout(&SelectTimeout))) == 0)
    00994     {  /* select timed out; if timeout hasn't expired, reset and try again */
    00995       if ( GetTime_ew() - timeout > StartTime )
    00996         return SOCKET_ERROR;
    00997
    00998       FD_ZERO(&WriteableSockets);
    00999       FD_SET(s,&WriteableSockets);
    01000       sleep_ew(100);
    01001       /* Wait a while, and then try again */
    01002     }
    01003     if (sel < 0)
    01004     {
    01005       logit("et", "Error %d occured during select() in %s\n",
    01006             socketGetError_ew(), MyFuncName);
    01007       return SOCKET_ERROR;
    01008     }
    01009     retVal=sendto(s,buf,len,flags,to,tolen);
    01010   }
    01011
    01012   if(retVal <0  && EW_SOCKET_DEBUG)
    01013   {
    01014     logit("et","Error: %d, occurred in %s\n",
    01015           socketGetError_ew(),MyFuncName);
    01016   }
    01017
    01018   if(EW_SOCKET_DEBUG)
    01019     logit("et","Exiting %s\n",MyFuncName);
    01020
    01021   return(retVal);
    01022 }
    01023
    01024 /*************************************************************/
    01025
    01026 struct timeval FAR * resetTimeout(struct timeval FAR * pSelectTimeout)
    01027 {
    01028
    01029   /* resetTimeout() reinitializes the TIMEVAL structure used in
    01030      select() calls.  Depending on the OS, the timeout value
    01031      maybe altered during the select() call, and therefore needs
    01032      to be reinitialized before every select() call.
    01033      */
    01034   static char * MyFuncName = "resetTimeout()";
    01035   static int EW_SOCKET_DEBUG_R=0;
    01036   if(EW_SOCKET_DEBUG_R)
    01037     logit("et","Entering %s\n",MyFuncName);
    01038
    01039   pSelectTimeout->tv_sec=SELECT_TIMEOUT_SECONDS;
    01040   pSelectTimeout->tv_usec=SELECT_TIMEOUT_uSECONDS;
    01041
    01042   if(EW_SOCKET_DEBUG_R)
    01043     logit("et","Exiting %s\n",MyFuncName);
    01044
    01045   return(pSelectTimeout);
    01046 }
    01047
    01048 /*************************************************************/
    01049
    01050 int closesocket_ew(SOCKET s,int HowToClose)
    01051 {
    01052   /* closesocket_ew() closes the socket s.  HowToClose indicates
    01053      whether the socket should be closed gracefully or immediately.
    01054      Use SOCKET_CLOSE_IMMEDIATELY_EW or SOCKET_CLOSE_GRACEFULLY_EW
    01055      to indicate closure method.  Caller can call socketGetError_ew()
    01056      for details about any failures.
    01057   */
    01058
    01059   /*
    01060     #define SOCKET_CLOSE_IMMEDIATELY_EW 0
    01061     #define SOCKET_CLOSE_GRACEFULLY_EW -1
    01062     #define SOCKET_CLOSE_SIMPLY_EW     -2
    01063   */
    01064
    01065   static char * MyFuncName = "closesocket_ew()";
    01066   struct linger Linger_Value;
    01067   int retVal;
    01068
    01069   if(EW_SOCKET_DEBUG)
    01070     logit("et","Entering %s\n",MyFuncName);
    01071
    01072 /* Note1: setsockopt(SO_LINGER) doesn't seem to work on x86 Solaris 2.5,
    01073           at least when the socket isn't connected. WMK 981019
    01074    Note2: Added the case SOCKET_CLOSE_SIMPLY_EW to skip the call to
    01075           setsockopt. This case is used in connect_ew when the connection
    01076           has failed.  LDD 981022
    01077  *************************************************************************/
    01078   if ( HowToClose != SOCKET_CLOSE_SIMPLY_EW )
    01079   {
    01080     if ( HowToClose == SOCKET_CLOSE_IMMEDIATELY_EW )
    01081     {
    01082       Linger_Value.l_onoff=1;     /* Reset or hard close */
    01083       Linger_Value.l_linger=0;    /* Set timeout to 0 seconds */
    01084     }
    01085     else
    01086     {
    01087       Linger_Value.l_onoff=0;     /* Non-blocking graceful close (NBGC) */
    01088       Linger_Value.l_linger=0;
    01089     }
    01090
    01091     if ( setsockopt(s,SOL_SOCKET,SO_LINGER,(char *) &Linger_Value,
    01092                     sizeof(struct linger)) == -1 )
    01093     {
    01094       if(EW_SOCKET_DEBUG)
    01095         logit( "et", "closesocket_ew:setsockopt error: %s\n",
    01096                strerror(socketGetError_ew()) );
    01097     }
    01098   }
    01099
    01100   retVal=closesocket(s);
    01101
    01102   if(EW_SOCKET_DEBUG)
    01103     logit("et","Exiting %s\n",MyFuncName);
    01104
    01105   return (retVal);
    01106 }
    01107
    01108 /*************************************************************/
    01109
    01110 int select_ew (int nfds, fd_set FAR * readfds, fd_set FAR * writefds,
    01111                fd_set FAR * exceptfds,
    01112                int timeout_msec)
    01113
    01114      /* select_ew() determines the state of sets of sockets, by
    01115      calling select().  Timeout is in milliseconds, and is
    01116      converted by select_ew to the select() timeout structure, and
    01117      passed on (to select()). No "-1" feature here; if you are willing to
    01118      block indefinitely in select(), you might as well wait in the actual
    01119      I/O call instead.
    01120      Caller can call socketGetError_ew() for details about any failures.
    01121      */
    01122 {
    01123   int retVal;
    01124   static char * MyFuncName = "select_ew()";
    01125   struct timeval SelectTimeout={0,0};
    01126
    01127   if(EW_SOCKET_DEBUG)
    01128     logit("et","Entering %s\n",MyFuncName);
    01129
    01130   SelectTimeout.tv_usec=1000 * timeout_msec;
    01131
    01132   retVal = select(nfds,readfds,writefds,exceptfds,&SelectTimeout);
    01133   if (retVal < 0  && EW_SOCKET_DEBUG)
    01134     logit("et","Error: %d, occurred in %s\n",
    01135           socketGetError_ew(),MyFuncName);
    01136
    01137   if(EW_SOCKET_DEBUG)
    01138     logit("et","Exiting %s\n",MyFuncName);
    01139
    01140   return(retVal);
    01141 }
    01142
    01143 /*************************************************************/
    01144
    01145 int setSocket_ewDebug(int debug)
    01146 {
    01147   /* setSocket_ewDebug() turns debugging on or off for
    01148      the SOCKET_ew routines.
    01149   */
    01150   EW_SOCKET_DEBUG=debug;
    01151   return(0);
    01152 }
    01153
    01154 /*************************************************************/
    01155
    01156 int setSocket_ewSelectTimeout(unsigned int Timeout)
    01157 {
    01158   /* setSocket_ewSelectTimeout() sets the timeout period
    01159      passed to select() calls made internally within the
    01160      SOCKET_ew routines.  The timeout period is in
    01161      milliseconds.
    01162   */
    01163   SELECT_TIMEOUT_uSECONDS=1000*Timeout;
    01164   return(0);
    01165 }
    01166
    01167