socket.c

Go to the documentation of this file.
00001 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <ctype.h>
00038 #include "ctl/ctldef.h"
00039 #include "ctl/pool.h"
00040 #include "ctl/ctlnew.h"
00041 #include "ctl/socket.h"
00042 
00043 /* Some things to glue Winsock/BSD Sockets together more nicely */
00044 #ifdef WIN32
00045 #include <ws2tcpip.h>
00046 #define EWOULDBLOCK         WSAEWOULDBLOCK
00047 #define SHUT_RDRW           SD_BOTH
00048 #define SocketError()       WSAGetLastError()
00049 #define SocketSetError(e)   WSASetLastError(e)
00050 #else
00051 #define INVALID_SOCKET      -1
00052 #define SOCKET_ERROR        -1
00053 #define closesocket         close
00054 #define SocketError()       errno
00055 #define SocketSetError(e)   (errno = (e))
00056 #include <fcntl.h>
00057 #include <stropts.h>
00058 #endif
00059 
00060 /* Something to write at ends of buffers to detect overwrites */
00061 static const uint32 GUARD_BYTES = 0xDEADBAB4; 
00062 
00063 /*
00064  * Declare socket memory pool
00065  */
00066 ctl_fp_decl( Socket, MAX_SOCKETS, SocketPool );
00067 static SocketPool* sockPool;
00068 
00069 /*
00070  * Declare list of active Sockets
00071  */
00072 dll_autolist(Socket,active, socksActive);
00073 static void Socket_Free( Socket* sock );
00074 /*
00075  * Declare testpoint data 
00076  */
00077 static size_t cSockActive = 0;
00078 static size_t cSockFree = MAX_SOCKETS;
00079 /*
00080  * Declare socket buffer pool
00081  */
00082 ppWindows(static WSADATA wsaData;)
00083 static const size_t cSockTotal = MAX_SOCKETS;
00084 static size_t sockInSize;
00085 static size_t sockOutSize;
00086 static size_t sockHeapSize;
00087 static size_t sockBufferSize;
00088 static size_t sockOffsetOut;
00089 static size_t sockOffsetEnd;
00090 static size_t bufferSize;
00091 static uint8* bufferSpace = NULL;   /* Space reserved for socket I/O buffers */
00092 static size_t sockUserSize;
00093 static size_t userSize;
00094 static uint8* userSpace = NULL;     /* Space reserved for user heaps */
00095 #define SOCK_INPUT_DEFAULTPTR(index)    (bufferSpace + (index * sockBufferSize))
00096 #define SOCK_OUTPUT_DEFAULTPTR(index)   ((bufferSpace + (index * sockBufferSize)) + sockOffsetOut)
00097 #define SOCK_HEAP_DEFAULTPTR(index)     (userSpace + (index * sockUserSize))
00098 
00104 uint32 SocketID( const Socket* sock )
00105 {
00106     assertobjconst(sock);
00107     if( !ctl_fp_valid(SocketPool, sockPool, sock ) )
00108         return 0;
00109     if( Socket_ShouldIgnore(sock) )
00110         return 0;
00111     return sock->id;
00112 }
00113 
00119 Socket* SocketLut( uint32 id )
00120 {
00121     Socket* sock = ctl_fp_lut(SocketPool, sockPool, id&0xffff );
00122     if( NULL == sock )
00123         return NULL;
00124     if( sock->id != id )
00125         return NULL;
00126     if( Socket_ShouldIgnore(sock) )
00127         return NULL;
00128     return sock;
00129 }
00130 
00138 Socket* SocketFind( const char* label )
00139 {
00140     assertconst(label,1);
00141     {
00142         socket_foreach( sock )
00143         {
00144             assertobjptr(sock);
00145             if( !Socket_ShouldIgnore(sock) && !strcmp(sock->label,label) )
00146             {
00147                 return sock;
00148             }
00149         }
00150     }
00151     return NULL;
00152 }
00153 
00154 /* Default do-nothing socket callbacks */
00155 static void Socket_DefaultReceived( Socket* sock, ctl_serial* packet )
00156 {
00157     assertobjptr(sock);
00158     assertobjptr(packet);
00159 }
00160 /* Default do-nothing socket callbacks */
00161 static void Socket_DefaultCallback( Socket* sock )
00162 {
00163     assertobjptr(sock);
00164 }
00165 
00166 static NewSocketCallback login_callback = Socket_DefaultCallback;
00167 static NewSocketCallback user_callback = Socket_DefaultCallback;
00168 
00174 NewSocketCallback SocketsSetLogin( NewSocketCallback callback )
00175 {
00176     NewSocketCallback cb_old = login_callback;
00177     login_callback = NULL == callback ? Socket_DefaultCallback : callback;
00178     assertcodeptr(login_callback);
00179     return cb_old;
00180 }
00181 
00187 NewSocketCallback SocketsSetUser( NewSocketCallback callback )
00188 {
00189     NewSocketCallback cb_old = user_callback;
00190     user_callback = NULL == callback ? Socket_DefaultCallback : callback;
00191     assertcodeptr(user_callback);
00192     return cb_old;
00193 }
00194 
00195 
00205 bool SocketsInit( size_t input, size_t output, size_t heap )
00206 {
00207     trace(("SocketsInit()\n"));
00208     sockInSize = input;
00209     sockOutSize = output;
00210     sockHeapSize = heap;
00211     sockBufferSize = (sockInSize + sockOutSize + (2*sizeof(uint32)));
00212     sockOffsetOut = sockInSize + sizeof(uint32);
00213     sockOffsetEnd = sockOffsetOut + sizeof(uint32);
00214     bufferSize = MAX_SOCKETS * sockBufferSize;
00215     sockUserSize = sockHeapSize + sizeof(uint32);
00216     userSize = MAX_SOCKETS * sockUserSize;
00217 
00218 #ifdef WIN32
00219     {
00220         /* Setup Winsock */
00221         int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
00222         if (iResult != 0) 
00223         {
00224             SocketsLogLastError( LOG_ERROR, "WSAStartup failed: %d\n", iResult );
00225             return false;
00226         }
00227         LOG( LOG_STARTUP,"%s - %s\n", wsaData.szDescription, wsaData.szSystemStatus  );
00228     }
00229 #endif
00230 
00231     /* Initialize socket pool */
00232     ctl_alloctype(sockPool,SocketPool);
00233     ctl_fp_init( SocketPool, sockPool );
00234     /* 
00235      * Allocate all the socket storage at once
00236      * I'd rather die right away for insufficient space than at 2:00am when the 834th user logs in
00237      */
00238     ctl_malloc( bufferSpace, bufferSize );
00239     ctl_malloc( userSpace, userSize );
00240     return true;
00241 }
00242 
00246 void SocketsShutdown(void)
00247 {
00248     trace(("SocketsShutdown()\n"));
00249     {
00250         /* Shutdown all sockets */
00251         socket_foreach( sock )
00252         {
00253             assertobjptr(sock);
00254             Socket_Close(sock);
00255         }
00256     }
00257     {
00258         /* Free all sockets */
00259         socket_foreach_deletable( sock )
00260         {
00261             assertobjptr(sock);
00262             Socket_Free(sock);
00263         }
00264     }
00265     /* Free socket pool */
00266     ctl_free(sockPool);
00267     /* Free reserved socket buffers */
00268     ctl_free(bufferSpace);
00269     /* Free reserved user data */
00270     ctl_free(userSpace);
00271     /* Make sure active list is clear */
00272     dll_initlist(Socket,active, socksActive);
00273     /* Reset statistics */
00274     assert( 0 == cSockActive );
00275     assert( MAX_SOCKETS == cSockFree );
00276     cSockActive = 0;
00277     cSockFree = MAX_SOCKETS;
00278 #ifdef WIN32
00279     WSACleanup();
00280 #endif
00281 }
00282 
00288 bool SocketsCycle( unsigned ms )
00289 {
00290     mstime tick = ctl_mstime();
00291 #ifdef WIN32
00292     /*
00293      * Under Windows, select() SUCKS.  Under WinSock, fd_set is an array of  
00294      * handles that is searched linearly.  A call to FD_SET in that case could  
00295      * scan through hundreds, even thousands of handles every time, times  
00296      * hundreds, even thousands of handles.  It makes it much more efficient to  
00297      * poll every socket and Sleep(1), even with the OS context switches.   
00298      * The replacement in the Winsock API is to set up threads for every  
00299      * socket, or have a WindowProc receive a message, or there's one that will 
00300      * check up to 64 handles at a time....  Just ugly.
00301      * 
00302      * For WIN32, we yield up time to the rest of the OS, since this will 
00303      * otherwise be a hard loop.  Makes CPU usage (on a given core) go from 
00304      * 100% to around 3%, so though not quite as good as select, it will do 
00305      * to keep the system running for testing in a Windows environment.
00306      */
00307     Sleep( 1 );
00308 
00309     /* Free dead sockets */
00310     {
00311         socket_foreach_deletable( sock )
00312         {
00313             assertobjptr(sock);
00314             if( tick - sock->lastmsg > sock->timeout )
00315             {   /* Close timed-out sockets */
00316                 SocketLogIP(sock,LOG_INFO,"Timed out:");
00317                 Socket_Close(sock);
00318             }
00319             if( stUninitialized == sock->type )
00320             {
00321                 Socket_Free(sock);
00322             }
00323         }
00324     }
00325 #else
00326     /*
00327      * Under Linux/Unix/etc. select() is THE way to go.  The server can go to 
00328      * sleep nicely when there's nothing to do, and you don't have to do  
00329      * thousands of context switches between application and OS to see if  
00330      * anything needs to happen.  The fd_set structure and macros under a BSD  
00331      * implementation are a set of bit masks.  Accessing the list is an indexed
00332      * lookup with some masking, and entries in the list are one bit, so the 
00333      * data is 1/32 the size of the list of handles you get in Windows, too.
00334      */
00335     static fd_set fdreads;
00336     static fd_set fdwrites;
00337     /* Maybe see about cacheing fd_set data...? */
00338     FD_ZERO(&fdreads);
00339     FD_ZERO(&fdwrites);
00340     {
00341         int nfds = -1;
00342         socket_foreach_deletable( sock )
00343         {
00344             assertobjptr(sock);
00345             if( stUninitialized != sock->type && INVALID_SOCKET != sock->socket )
00346             {
00347                 if( tick - sock->lastmsg > sock->timeout )
00348                 {   /* Close timed-out sockets */
00349                     SocketLogIP(sock,LOG_INFO,"Timed out:");
00350                     Socket_Close(sock);
00351                 }
00352                 else
00353                 {
00354                     SOCKET sockCurr = sock->socket;
00355                     if( stSendingFinal != sock->type )
00356                     {
00357                         /* Don't listen for more incoming messages from closing sockets */
00358                         FD_SET( sockCurr, &fdreads );
00359                     }
00360                     if( !RingBuff_IsEmpty(&sock->output) )
00361                     {
00362                         FD_SET( sockCurr, &fdwrites );
00363                     }
00364                     if( sock->socket > nfds )
00365                     {
00366                         nfds = sockCurr;
00367                     }
00368                 }
00369             }
00370             if( stUninitialized == sock->type )
00371             {
00372                 Socket_Free(sock);
00373             }
00374         }
00375         /* Do select on all sockets, time-out appropriately as passed in */
00376         {
00377             struct timeval timeout = { ms/1000, (ms%1000)*1000 };
00378             nfds = select( 1+nfds, &fdreads, &fdwrites, NULL, 0 == ms ? NULL : &timeout );
00379         }
00380         if( 0 == nfds )
00381         {
00382             return true;
00383         }
00384         else if( SOCKET_ERROR == nfds )
00385         {
00386             int save_errno = SocketError();
00387             switch( save_errno )
00388             {
00389             case EBADF:
00390                 /*
00391                  * One handle might be invalid - scan them all
00392                  * Shouldn't ever happen, but if one fd somehow becomes invalid,
00393                  * should we crash & nuke everyone, or just the 'invalid' one?
00394                  * I'll just assume you want to close the invalid one.
00395                  */
00396                 {
00397                     SocketsLogLastError( LOG_ERROR, "select() EBADF.\n" );
00398                     bool bFound = false;
00399                     socket_foreach_deletable( suspect )
00400                     {
00401                         int tmp;
00402                         int ret = ioctl( suspect->socket, I_GETSIG, &tmp );
00403                         if( (-1 == ret) && (EBADF == SocketError()) )
00404                         {
00405                             Socket_LogError( suspect, LOG_ERROR, "select() BAD HANDLE: %d.\n", suspect->socket );
00406                             Socket_Close( suspect );
00407                             bFound = true;
00408                         }
00409                     }
00410                     /* If we couldn't find the 'bad' socket, something else is 
00411                      * wrong, and that's probably fatal. */
00412                     return bFound;
00413                 }
00414                 break;
00415             case EAGAIN:
00416             case EINTR:
00417                 /* Time-out. */
00418                 break;
00419             case EINVAL:
00420                 
00421                 /* nfds arg might be <0 or >FD_SETSIZE */
00422                 if( (1+nfds < 0) || (1+nfds > FD_SETSIZE) )
00423                 {
00424                     SocketsLogLastError( LOG_ERROR, "select() nfds out of range.\n" );
00425                     return false;
00426                 }
00427                 
00428                 /* Invalid timeout interval (not likely, and a bug, anyways) */
00429 
00430                 /* STREAM or multiplexer downstream from multiplexer */
00431                 
00432                 /* Fall-through to default error handler */
00433             default:
00434                 SocketsLogLastError( LOG_ERROR, "select() failed.\n" );
00435                 // Make sure previous function(s) don't overwrite error status
00436                 SocketSetError(save_errno);
00437                 return false;
00438             }
00439         }
00440     }
00441 
00442 #endif
00443 
00444     /* Attempt to write sockets first, to make room for side-effects of reading sockets */
00445     {
00446         socket_foreach( sock )
00447         {
00448             assertobjptr(sock);
00449             if( stUninitialized != sock->type ppNotWindows(&& FD_ISSET(sock->socket,&fdwrites)) )
00450             {
00451                 assertcodeptr(sock->vtab->WriteCycle);
00452                 sock->vtab->WriteCycle(sock);
00453             }
00454         }
00455     }
00456 
00457     /* Attempt to read sockets */
00458     {
00459         socket_foreach( sock )
00460         {
00461             assertobjptr(sock);
00462             if( !Socket_ShouldIgnore(sock) ppNotWindows(&& FD_ISSET(sock->socket,&fdreads)) )
00463             {
00464                 assertcodeptr(sock->vtab->ReadCycle);
00465                 sock->vtab->ReadCycle(sock);
00466             }
00467         }
00468     }
00469 
00470     /* Normal-looking status */
00471     return true;
00472 }
00473 
00478 const char* SocketsLastErrorString(void)
00479 {
00480 #ifdef WIN32
00481     static char szError[512]; // <- Multithread risk
00482     DWORD dw = SocketError(); 
00483     FormatMessage(
00484         FORMAT_MESSAGE_FROM_SYSTEM | 
00485         FORMAT_MESSAGE_IGNORE_INSERTS |
00486         FORMAT_MESSAGE_MAX_WIDTH_MASK,
00487         NULL, 
00488         dw, 
00489         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00490         szError, sizeof(szError)/sizeof(*szError), 
00491         NULL);
00492     return szError;
00493 #else
00494     return strerror(SocketError());
00495 #endif
00496 }
00497 
00503 void SocketsLogLastError( unsigned mask, const char*fmt, ... )
00504 {
00505     va_list args;
00506     va_start( args, fmt );
00507     assertconst(fmt,1);
00508     debug_vlog(mask, fmt, args );
00509     LOG( mask, "%s\n", SocketsLastErrorString() );
00510 }
00511 
00521 struct addrinfo *SocketsParseAddress( const char* szAddress )
00522 {
00523     char ipbuff[256];
00524     const char* port;
00525     const char* address;
00526     const char* scan;
00527     assertconst(szAddress,1);
00528     scan = address = szAddress;
00529     /* Look for colon */
00530     while( ':' != *scan )
00531     {
00532         if( 0 == *scan )
00533             return NULL;
00534         scan++;
00535     }
00536     /* If we found '://', skip over protocol and search for ':' */
00537     if( *scan == '/' )
00538     {
00539         ++scan;
00540         if( *scan == '/' )
00541         {
00542             address = ++scan;
00543             while( ':' != *scan )
00544             {
00545                 if( 0 == *scan )
00546                 {
00547                     LOG( LOG_ERROR, "SocketsParseAddress(%s) no ':port'.\n", szAddress );
00548                     return NULL;
00549                 }
00550                 scan++;
00551             }
00552         }
00553         else
00554         {
00555             LOG( LOG_ERROR, "SocketsParseAddress(%s) found ':/' instead of '://'.\n", szAddress );
00556             return NULL;
00557         }
00558     }
00559     if( *scan == ':' )
00560     {
00561         size_t address_len;
00562         port = scan+1;
00563         address_len = (scan-address);
00564         if( address_len > sizeof(ipbuff) )
00565         {
00566             LOG( LOG_ERROR, "SocketsParseAddress(%s) address too long.\n", szAddress );
00567             return NULL;
00568         }
00569         memcpy(ipbuff,address,address_len);
00570         ipbuff[address_len] = 0;
00571         SocketsLogHostent( LOG_INFO, ipbuff );
00572         {
00573             struct addrinfo aiHints;
00574             struct addrinfo *aiList = NULL;
00575             memset(&aiHints, 0, sizeof(aiHints));
00576             aiHints.ai_family = AF_INET;
00577             aiHints.ai_socktype = SOCK_STREAM;
00578             aiHints.ai_flags = AI_CANONNAME;
00579             aiHints.ai_protocol = IPPROTO_TCP;
00580             if( 0 != getaddrinfo(ipbuff, port, &aiHints, &aiList) )
00581             {
00582                 SocketsLogLastError( LOG_ERROR, "SocketsParseAddress(%s) failed.\n", szAddress );
00583                 return NULL;
00584             }
00585 #if 1
00586             {
00587                 struct addrinfo *ai = aiList;
00588                 while( NULL != ai )
00589                 {
00590                     trace(( "%s: ", ai->ai_canonname ));
00591                     traceip("Address:",ai->ai_addr);
00592                     ai = ai->ai_next;
00593                 }
00594             }
00595 #endif
00596             return aiList;
00597         }
00598     }
00599     return NULL;
00600 }
00601 
00605 void SocketsLogHostent( uint32 logmask, const char* name )
00606 {
00607     /* Mine connection details out of sockets */
00608     struct hostent* hostEntry;
00609     assertconst(name,1);
00610     hostEntry = gethostbyname(name);
00611     if( NULL == hostEntry )
00612     {
00613         struct in_addr ina;
00614 #ifdef WIN32
00615         uint32 inu = inet_addr(name);
00616         ina = *((struct in_addr*)&inu);
00617 #else
00618         if( 0 == inet_aton( name, &ina) )
00619         {
00620             SocketsLogLastError( LOG_ERROR, "inet_aton  failed.\n" );
00621             return;
00622         }
00623 #endif
00624         hostEntry = gethostbyaddr( ppWindows((const char*))&ina, sizeof(ina), AF_INET );
00625         if( NULL == hostEntry )
00626         {
00627             SocketsLogLastError( LOG_ERROR, "gethostbyaddr  failed.\n" );
00628             return;
00629         }
00630     }
00631     LOG( logmask, "Official name: %s\n", hostEntry->h_name);
00632     LOG( logmask, "Alternate names:\n");
00633     {
00634         const char** p = (const char** )hostEntry->h_aliases;
00635         while( *p )
00636         {
00637             LOG( logmask, "\t%s\n", *p++ );
00638         }
00639     }
00640     LOG( logmask, "Address type: ");
00641     switch (hostEntry->h_addrtype) 
00642     {
00643     case AF_INET:
00644         LOG( logmask, "AF_INET\n");
00645         break;
00646     case AF_INET6:
00647         LOG( logmask, "AF_INET6\n");
00648         break;
00649     default:
00650         LOG( logmask, " %d\n", hostEntry->h_addrtype);
00651         break;
00652     }
00653     /*LOG( logmask, "Address length: %d\n", hostEntry->h_length); */
00654     if( hostEntry->h_length >= 4 )
00655     {
00656         struct in_addr **p = (struct in_addr **)hostEntry->h_addr_list;
00657         LOG( logmask, "Addresses Available:\n" );
00658         while(*p)
00659         {
00660             LOG( logmask, "\t%s\n", inet_ntoa(**p) );
00661             ++p;
00662         }
00663     }
00664 }
00665 
00666 
00671 static void Socket_Options( Socket* sock )
00672 {
00673     assertobjptr(sock);
00674 #ifdef WIN32
00675     { 
00676         /* Set non-blocking */
00677         uint32 iMode = 1; 
00678         if( SOCKET_ERROR == ioctlsocket(sock->socket, FIONBIO, &iMode) )
00679         {
00680             SocketsLogLastError( LOG_ERROR, "%s ioctlsocket(%d)n", sock->label, sock->socket );
00681         }
00682     }
00683 #if 0
00684     {
00685         /* Needs <mstcpip.h> */
00686         /* Ping connection to make sure it's alive */
00687         BOOL bOptVal = TRUE;
00688         DWORD dwError = 0L ;
00689         DWORD dwBytes = 0L ;
00690         struct tcp_keepalive sKA_Settings = {0}, sReturned = {0} ;
00691         setsockopt( sock->socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, sizeof(BOOL) );
00692         sKA_Settings.onoff = 1 ;
00693         sKA_Settings.keepalivetime = 30000 ; /* Keep Alive in 30 sec. */
00694         sKA_Settings.keepaliveinterval = 5000 ; /* Resend if No-Reply */
00695         if (WSAIoctl( sock->socket, SIO_KEEPALIVE_VALS, &sKA_Settings,
00696             sizeof(sKA_Settings), &sReturned, sizeof(sReturned), &dwBytes,
00697             NULL, NULL) != 0)
00698         {
00699             SocketsLogLastError( LOG_ERROR, "Keepalive setup(%s)\n", sock->label );
00700         }
00701     }
00702 #endif
00703 #else
00704     {
00705         /* Set non-blocking */
00706         int flags = fcntl( sock->socket, F_GETFL, 0 );
00707         if (-1 == flags )
00708         {
00709             SocketsLogLastError( LOG_ERROR, "%s fcntl(%d)n", sock->label, sock->socket );
00710         }
00711         else
00712         {
00713             flags |= O_NONBLOCK;
00714             fcntl( sock->socket, F_SETFL, flags  );
00715         }
00716     }
00717 #endif
00718 }
00719 
00720 
00724 static void Generic_WriteCycle( Socket* sock )
00725 {
00726     int attempts;
00727     assertobjptr(sock);
00728     for( attempts = 0; attempts < 2; ++attempts )
00729     {
00730         size_t remain;
00731         if( (remain = RingBuff_Remain( &sock->output )) )
00732         {
00733             const uint8* buff;
00734             RingBuff_Peek( &sock->output, &buff, remain );
00735             int bytes = send( sock->socket, buff, remain, 0 );
00736             if( SOCKET_ERROR == bytes )
00737             {
00738                 switch( SocketError() )
00739                 {
00740                 case 0:
00741                     /* No error */
00742                 case EWOULDBLOCK:
00743                     /* No space to send */
00744                     return;
00745                 default:
00746                     /* Some error or other */
00747                     SocketsLogLastError( LOG_ERROR, "Generic_WriteCycle(%s) receive failed\n", sock->label );
00748                     Socket_Close( sock );
00749                     return;
00750                 }
00751             }
00752             else if( bytes > 0 )
00753             {
00754                 /* Consume sent bytes off queue */
00755                 RingBuff_Pop( &sock->output, &buff, bytes );
00756                 if( bytes < remain )
00757                 {
00758                     /* Don't loop on partial send */
00759                     return;
00760                 }
00761             }
00762             if( stSendingFinal == sock->type && RingBuff_IsEmpty(&sock->output) )
00763             {
00764                 /* Complete graceful shutdown */
00765                 Socket_Close( sock );
00766                 return;
00767             }
00768         }
00769         else
00770         {
00771             /* Nothing to do here. */
00772             return;
00773         }
00774     }
00775 }
00776 
00782 static void Generic_ReadCycle( Socket* sock )
00783 {
00784     /*
00785      * This is based on reading one, and only one packet from the input stream at a time.
00786      *
00787      * I don't want to fill local memory with unhandled packets, giving the 
00788      * network layer permission to ask the client for more.  
00789      *
00790      * Let them back up on the client.  This is a single-threaded environment 
00791      * and we're popping one command every other cycle not only because it's
00792      * easier, but because I don't want assholes to write their own clients
00793      * (very easy to do) and flood everybody else out while 'experimenting'.
00794      */
00795     /* Try to read data into buffer */
00796     size_t available;
00797     assertobjptr(sock);
00798     available = RingBuff_Free(&sock->input);
00799     if( 0 < available )
00800     {   /* Try to get non-zero bytes when there's space */
00801         uint8* space;
00802         RingBuff_Space( &sock->input, &space, available );
00803         int bytes = recv( sock->socket, space, available, 0 );
00804         Socket_Validate(sock);
00805         if( 0 == bytes )
00806         {   /* Disconnected */
00807             Socket_Close( sock );
00808             return;
00809         }
00810         if( SOCKET_ERROR == bytes )
00811         {
00812             if( EWOULDBLOCK != SocketError() )
00813             {
00814                 SocketsLogLastError( LOG_ERROR, "Generic_ReadCycle(%s) receive failed\n", sock->label );
00815                 Socket_Close( sock );
00816             }
00817             return;
00818         }
00819         //debug_loghex( LOG_INFO, sock->input.tail, bytes );
00820         RingBuff_Add( &sock->input, &space, (size_t)bytes );
00821     }
00822     ctl_serial serial;
00823     if( RingBuff_PopSerial( &sock->input, &serial ) )
00824     {
00825         sock->lastmsg = ctl_mstime();
00826         sock->appReceived( sock, &serial );
00827     }
00828 }
00829 
00830 /*
00831  * Client connection has been shut down
00832  */
00833 static void Client_Close( Socket* sock )
00834 {
00835 }
00836 SockVTAB ClientVTAB =
00837 {
00838     Generic_ReadCycle,
00839     Generic_WriteCycle,
00840     Client_Close
00841 };
00842 
00843 
00849 Socket* Socket_Create_Client( const char* address )
00850 {
00851     Socket* sock;
00852     assertconst(address,1);
00853     sock = Socket_Create();
00854     if( NULL == sock )
00855         return NULL;
00856     sock->type = stClient;
00857     sock->timeout = int64_max;
00858     LOG( LOG_INFO, "Socket_Create_Client(%s)\n", address );
00859     sock->vtab = &ClientVTAB;
00860     strncpy(sock->label, "Client", countof(sock->label) );
00861     return sock;
00862 }
00863 Socket* Socket_Client_Connect( Socket* sock, const char* address )
00864 {
00865     /* Resolve address and connect */
00866     struct addrinfo * service = SocketsParseAddress( address );
00867     if( NULL == service )
00868     {
00869         Socket_Close( sock );
00870         return NULL;
00871     }
00872     sock->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00873     if( sock->socket == INVALID_SOCKET ) 
00874     {
00875         SocketsLogLastError( LOG_ERROR, "Socket_Create_Client(%s) socket failed\n", address );
00876         Socket_Close( sock );
00877         return NULL;
00878     }
00879     /* Setup socket */
00880     Socket_Options( sock );
00881     memcpy( &sock->socka_buff, service->ai_addr, min(service->ai_addrlen,sizeof(sock->socka_buff)) );
00882     LOG( LOG_INFO, "Client: %s\n", service->ai_canonname );
00883     freeaddrinfo(service);
00884     SocketLogIP(sock,LOG_INFO,"Address: ");
00885     if( SOCKET_ERROR == connect( sock->socket, (struct sockaddr*)&sock->address, sizeof(sock->address)) ) 
00886     {
00887         SocketsLogLastError( LOG_ERROR, "Socket_Create_Client(%s) connect failed.\n", address );
00888         Socket_Close( sock );
00889         return NULL;
00890     }
00891     return sock;
00892 }
00893 /*
00894  * Accept incoming connections and make Logins out of them
00895  */
00896 static void Listener_ReadCycle(struct Socket* sock)
00897 {
00898     /* Accept any incoming connection. */
00899     SOCKET client;
00900     assertobjptr(sock);
00901     client = accept( sock->socket, NULL, NULL );
00902     if( INVALID_SOCKET == client ) 
00903     {
00904         if( EWOULDBLOCK != SocketError() )
00905         {
00906             SocketsLogLastError( LOG_ERROR, "Listener_ReadCycle(%s) accept failed\n", sock->label );
00907         }
00908     }
00909     else
00910     {
00911         sock->lastmsg = ctl_mstime();
00912         Socket_Create_Login( client );
00913     }
00914 }
00915 /*
00916  * Listener has been shut down
00917  */
00918 static void Listener_Close( Socket* sock )
00919 {
00920     LOG( LOG_INFO, "%s Closed\n", sock->label );
00921 }
00922 /*
00923  * Listener does not write
00924  */
00925 static void Listener_WriteCycle( Socket* sock )
00926 {
00927     RingBuff_Reset(&sock->output);
00928 }
00929 SockVTAB ListenerVTAB =
00930 {
00931     Listener_ReadCycle,
00932     Listener_WriteCycle,
00933     Listener_Close
00934 };
00935 
00944 Socket* Socket_Create_Listener( const char* label, const char* address )
00945 {
00946     Socket* sock;
00947     struct addrinfo * service;
00948     assertconst(label,1);
00949     assertconst(address,1);
00950     LOG(LOG_STARTUP,"Socket_Create_Listener(%s,%s)\n", label, address );
00951     service = SocketsParseAddress( address );
00952     if( NULL == service )
00953         return NULL;
00954     sock = Socket_Create();
00955     if( NULL == sock )
00956         return NULL;
00957     sock->vtab = &ListenerVTAB;
00958     sock->type = stListener;
00959     sock->timeout = int64_max;
00960     strncpy( sock->label, label, countof(sock->label) );
00961     sock->socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP);
00962     if( sock->socket == INVALID_SOCKET ) 
00963     {
00964         SocketsLogLastError( LOG_ERROR, "Socket_Create_Listener(%s,%s) socket failed\n", sock->label,address );
00965         Socket_Close( sock );
00966         return NULL;
00967     }
00968     /* Setup socket */
00969     Socket_Options( sock );
00970     {
00971         /* Resolve port and listen */
00972         memcpy( &sock->socka_buff, service->ai_addr, min(service->ai_addrlen,sizeof(sock->socka_buff)) );
00973         LOG( LOG_STARTUP, "Listen: %s\n", service->ai_canonname );
00974         freeaddrinfo(service);
00975         SocketLogIP(sock,LOG_INFO,"Address: ");
00976         if( SOCKET_ERROR == bind( sock->socket, (struct sockaddr*)&sock->ip, sizeof(sock->ip)) ) 
00977         {
00978             SocketsLogLastError( LOG_ERROR, "Socket_Create_Listener(%s,%s) bind failed.\n", sock->label,address );
00979             Socket_Close( sock );
00980             return NULL;
00981         }
00982     }
00983     /* Listen for connections, and allow a back-log of half the users trying to get on at once */
00984     if( SOCKET_ERROR == listen( sock->socket, MAX_SOCKETS/2 ) )
00985     {
00986         SocketsLogLastError( LOG_ERROR, "Socket_Create_Listener(%s,%s) listen failed.\n", sock->label,address );
00987         Socket_Close( sock );
00988         return NULL;
00989     }
00990     return sock;
00991 }
00992 
00993 /*
00994  * Default bogus HTTP response string
00995  *
00996  * This response just puts up a 'NOT A WEB SERVER' message.
00997  * 
00998  * YOUR response should immediately redirect to an appropriate web site 
00999  */
01000 const char* defcbHTTP(void)
01001 {
01002     return
01003         "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\">"
01004         "<body bgcolor=\"#000000\" text=\"#ff0000\" link=\"#ff0000\" vlink=\"#800000\">"
01005         "<font size=\"7\"><center><br/><br/><br/><br/><b>"
01006             "<a href=\"http://en.wikipedia.org/wiki/Liar_paradox\">NOT A WEB SERVER</a>"
01007         "</b></center></font></body></html>"
01008         "\n";
01009 }
01010 
01011 /* 
01012  * Default FLASH policy file string
01013  *
01014  * This response tells Flash to connect wherever it likes.
01015  * 
01016  * YOUR response should be a policy file containing a list of explicit URLs to
01017  * web sites and ports that Flash can connect to and/or receive content from.  
01018  */
01019 const char* defcbFlashPolicy(void)
01020 {
01021     return
01022         "<?xml version=\"1.0\"?>\n"
01023         "<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n"
01024         "<cross-domain-policy>\n"
01025         "   <allow-access-from domain=\"*\" to-ports=\"*\" />\n"    /* This is the important bit */
01026         "</cross-domain-policy>\n";
01027 }
01028 
01029 static MLCallback cbHTTP = defcbHTTP;
01030 static MLCallback cbFlashPolicy = defcbFlashPolicy;
01035 MLCallback SocketsSetHTTP( MLCallback callback )
01036 {
01037     MLCallback prev = cbHTTP;
01038     cbHTTP = NULL == callback ? defcbHTTP: callback;
01039     assertcodeptr(cbHTTP);
01040     return prev;
01041 }
01046 MLCallback SocketsSetFlashPolicy( MLCallback callback )
01047 {
01048     MLCallback prev = cbFlashPolicy;
01049     cbFlashPolicy = NULL == callback ? defcbFlashPolicy: callback;
01050     assertcodeptr(cbFlashPolicy);
01051     return prev;
01052 }
01053 
01054 /*
01055  * Do read cycle for Login, watching for special cases and doing lots of 
01056  * checks for bogus inputs from the great unwashed.
01057  */
01058 static void Login_ReadCycle(struct Socket* sock)
01059 {
01060     /* Try to read data into buffer */
01061     size_t available;
01062     assertobjptr(sock);
01063     available = RingBuff_Free(&sock->input);
01064     if( 0 < available )
01065     {
01066         uint8* space;
01067         RingBuff_Space(&sock->input,&space,available);
01068         int bytes = recv( sock->socket, space, available, 0 );
01069         Socket_Validate(sock);
01070         if( 0 == bytes )
01071         {   /* Disconnected */
01072             Socket_Close( sock );
01073             return;
01074         }
01075         if( SOCKET_ERROR == bytes )
01076         {
01077             if( EWOULDBLOCK != SocketError() )
01078             {
01079                 SocketsLogLastError( LOG_ERROR, "Login_ReadCycle(%s) receive failed\n", sock->label );
01080                 Socket_Close( sock );
01081             }
01082             return;
01083         }
01084         //debug_loghex( LOG_INFO, sock->input.tail, bytes );
01085         RingBuff_Add( &sock->input, &space, (size_t)bytes );
01086     }
01087     available = RingBuff_Remain(&sock->input);
01088     {   
01089         /* Check for Flash 'security' input */
01090         const char szGET[] = "GET / HTTP";  /* Substring */
01091         const char szQuery[] = "<policy-file-request/>"; /* Includes NUL */
01092         if( sizeof(szQuery) == available )
01093         {
01094             const uint8* peek;
01095             if( RingBuff_Peek( &sock->input, &peek, sizeof(szQuery) ) 
01096              && 0 == memcmp( peek, szQuery, sizeof(szQuery) ) )
01097             {
01098                 /* Flash client asked for assurance that I allow connections. */
01099                 /* Send a policy file to let it know it CAN connect. */
01100                 const char* xmlSpew = cbFlashPolicy();
01101                 RingBuff_Reset( &sock->input );
01102                 Socket_Write( sock, xmlSpew, 1+strlen(xmlSpew) );
01103                 /* Client re-opens a NEW connection once this is received, so just blow it away once the data has cleared */
01104                 sock->type = stSendingFinal;
01105                 sock->timeout = 10000;  /* Allow ten seconds, then just drop it */
01106                 Socket_Validate(sock);
01107                 strncpy(sock->label,szconst(char,szQuery),countof(sock->label));
01108                 return;
01109             }
01110         }
01111         if( sizeof(szGET) < available )
01112         {
01113             const uint8* peek;
01114             if( RingBuff_Peek( &sock->input, &peek, sizeof(szQuery) ) 
01115              && 0 == memcmp( peek, szGET, sizeof(szGET)-1 ) )
01116             {
01117                 /* Client asked for web page. */
01118                 /* Send an html snippet to tell it no. */
01119                 /* When 'live', should probably link to the service home page */
01120                 /* It may be a good idea to use the www port, as this is almost never blocked anywhere */
01121                 const char htmlSpewHead[] = 
01122                     "HTTP/1.1 200 OK\n"
01123                     "Content-Type: text/html\n"
01124                     "\n";
01125                 const char* htmlSpewBody = cbHTTP();
01126                 RingBuff_Reset( &sock->input );
01127                 Socket_Write( sock, htmlSpewHead, sizeof(htmlSpewHead)-1 );
01128                 Socket_Write( sock, htmlSpewBody, strlen(htmlSpewBody) );
01129                 /* Client re-opens a NEW connection once this is received, so just blow it away once the data has cleared */
01130                 sock->type = stSendingFinal;
01131                 sock->timeout = 10000; /* Allow ten seconds, then drop it */
01132                 Socket_Validate(sock);
01133                 strncpy(sock->label,szconst(char,szGET),countof(sock->label));
01134                 SocketLogIP( sock, LOG_SECURITY, "Bogus HTTP connection: " );
01135                 return;
01136             }
01137         }
01138         if( available >= 2 )
01139         {   /* Try to pop a 16 bit length-encoded serial packet */
01140             ctl_serial serial;
01141             if( RingBuff_PopSerial( &sock->input, &serial ) )
01142             {
01143                 sock->lastmsg = ctl_mstime();
01144                 sock->appReceived( sock, &serial );
01145             }
01146         }
01147     }
01148 }
01149 
01150 /*
01151  * Login connection has been shut down
01152  */
01153 static void Login_Close( Socket* sock )
01154 {
01155 }
01156 SockVTAB LoginVTAB =
01157 {
01158     Login_ReadCycle,
01159     Generic_WriteCycle,
01160     Login_Close
01161 };
01162 
01168 Socket* Socket_Create_Login( SOCKET isock )
01169 {
01170     Socket* sock = Socket_Create();
01171     if( NULL == sock )
01172         return NULL;
01173     sock->vtab = &LoginVTAB;
01174     sock->type = stLogin;
01175     sock->socket = isock;
01176     sock->timeout = 5000; /* We expect a messages immediately upon connection */
01177     {
01178         /* Grab address from connecting client */
01179         size_t addrlen = sizeof(sock->socka_buff);
01180         getpeername( sock->socket, &sock->address, &addrlen );
01181     }
01182     cstrncpy(char)( sock->label, "Login", countof(sock->label) );
01183     /*traceip("Socket_Create_Login:",&sock->address); */
01184     /* Setup socket */
01185     Socket_Options( sock );
01186     /* Call application callback for dynamically created Login socket */
01187     assertcodeptr(login_callback);
01188     login_callback(sock);
01189     return sock;
01190 }
01191 
01192 /*
01193  * User connection has been shut down
01194  */
01195 static void User_Close( Socket* sock )
01196 {
01197 }
01198 SockVTAB UserVTAB =
01199 {
01200     Generic_ReadCycle,
01201     Generic_WriteCycle,
01202     User_Close
01203 };
01214 Socket* Socket_Create_User( Socket* sock, const char* label )
01215 {
01216     assertobjptr(sock);
01217     assertconst(label,1);
01218     sock->vtab = &UserVTAB;
01219     sock->type = stUser;
01220     sock->timeout = (15*60*1000); /* Let user go idle for 15 minutes */
01221     cstrncpy(char)(sock->label, label, countof(sock->label));
01222     /*trace(("Socket_Create_User(%s)\n", sock->label )); */
01223     /* Call application callback for dynamically created User socket */
01224     assertcodeptr(user_callback);
01225     user_callback(sock);
01226     return sock;
01227 }
01228 
01229 /*
01230  * Raw connection read cycle
01231  */
01232 static void Raw_ReadCycle( Socket* sock )
01233 {
01234     /* Try to read data into buffer */
01235     size_t available;
01236     assertobjptr(sock);
01237     available = RingBuff_Free(&sock->input);
01238     if( 0 < available )
01239     {   /* Try to get non-zero bytes when there's space */
01240         uint8* space;
01241         RingBuff_Space(&sock->input, &space, available );
01242         int bytes = recv( sock->socket, space, available, 0 );
01243         if( 0 == bytes )
01244         {   /* Disconnected */
01245             Socket_Close( sock );
01246             return;
01247         }
01248         if( SOCKET_ERROR == bytes )
01249         {
01250             if( EWOULDBLOCK != SocketError() )
01251             {
01252                 SocketsLogLastError( LOG_ERROR, "Raw_ReadCycle(%s) receive failed\n", sock->label );
01253                 Socket_Close( sock );
01254             }
01255             return;
01256         }
01257         //debug_loghex( LOG_INFO, sock->input.tail, bytes );
01258         RingBuff_Add( &sock->input, &space, (size_t)bytes );
01259     }
01260     {
01261         size_t remain = RingBuff_Remain(&sock->input);
01262         const uint8* peek;
01263         if( RingBuff_Peek( &sock->input, &peek, remain ) )
01264         {
01265             ctl_serial packet;
01266             sock->lastmsg = ctl_mstime();
01267             ctl_serial_init( &packet, (uint8*)peek, peek+remain );
01268             /* 
01269              * App must call Socket_Raw_Consume() to eat bytes in the queue
01270              * This is because at this level, 'Raw' doesn't know what is a complete packet 
01271              * App is expectected to keep looking at the data until it knows what to do
01272              * with it, then {do it} and remove the packet data from the input queue.
01273              */
01274             sock->appReceived( sock, &packet );
01275         }
01276     }
01277 }
01284 const uint8* Socket_Raw_Consume( Socket* sock, size_t size )
01285 {
01286     const uint8* data;
01287     assertobjptr(sock);
01288     RingBuff_Pop( &sock->input, &data, size );
01289     return data;
01290 }
01291 
01292 /*
01293  * Raw connection has been shut down
01294  */
01295 static void Raw_Close( Socket* sock )
01296 {
01297 }
01298 SockVTAB RawVTAB =
01299 {
01300     Raw_ReadCycle,
01301     Generic_WriteCycle,
01302     Raw_Close
01303 };
01312 Socket* Socket_Create_Raw( Socket* sock )
01313 {
01314     assertobjptr(sock);
01315     sock->vtab = &RawVTAB;
01316     sock->type = stRaw;
01317     sock->timeout = 15000;
01318     cstrncpy(char)( sock->label, "Raw", countof(sock->label) );
01319     /*trace(("Socket_Create_Raw(%s)\n", sock->label )); */
01320     /* Call application callback for dynamically created Raw socket */
01321     assertcodeptr(user_callback);
01322     user_callback(sock);
01323     return sock;
01324 }
01325 
01330 Socket* Socket_Create(void)
01331 {
01332     Socket* sock;
01333     size_t index;
01334     /* Allocate & clear it; all values should be zero */
01335     ctl_fp_calloc(SocketPool, sockPool, sock );
01336     if( NULL == sock )
01337         return NULL;
01338     sock->type = stUninitialized;
01339     sock->timeout = 5000;
01340     ++cSockActive;
01341     --cSockFree;
01342     sock->created = sock->lastmsg = ctl_mstime();
01343 
01344     {   
01345         /*
01346          * Confusion reduction (or confusion enhancement)
01347          * Socket->id is 16 bits AND a 16 bit sequence counter.  
01348          *
01349          * This will reduce the likelihood that a socket ID freed and reused 
01350          * will end up being the same ID, and help spot slightly stale identifier 
01351          * references.
01352          *
01353          * Very, very stale identifiers may not be identified because there's still 
01354          * a very small chance that the counter will wrap around and make an old 
01355          * identifier look valid again.
01356          */
01357         static uint32 seq = 0;
01358         index = ctl_fp_index(SocketPool, sockPool, sock );
01359         sock->id = index | (seq++&0xffff)<<16;
01360     }
01361 
01362 
01363     /* Add to active list */
01364     dll_push_back(Socket,active, socksActive, sock );
01365         
01366     /* Set socket to invalid value */
01367     sock->socket = INVALID_SOCKET;
01368 
01369     /* Give it a default label */
01370     strncpy(sock->label, "Socket", countof(sock->label) );
01371 
01372     /* Alocate socket storage separately */
01373     /* Keep the socket structure data small because it's iterated */
01374     /* Preallocate everything ONCE to keep server from dying at some odd time due to insufficient resources.  Die immediately, please. */
01375     /* Allocated from pool we initialized at startup */
01376     Socket_Customize( sock, 0,0,0 );
01377 
01378     /* Setup default application callbacks */
01379     sock->appReceived = Socket_DefaultReceived;
01380     sock->appDisconnect = Socket_DefaultCallback;
01381     return sock;
01382 }
01383 
01384 /* Free up dead socket */
01385 static void Socket_Free( Socket* sock )
01386 {
01387     size_t index;
01388     Socket_Validate(sock);
01389     index = ctl_fp_index(SocketPool, sockPool, sock );
01390     assert( index >= 0 && index < MAX_SOCKETS );
01391     sock->type = stUninitialized;
01392     sock->id = 0;
01393 
01394     /* Free any customized buffers */
01395     if( NULL != sock->pInput && SOCK_INPUT_DEFAULTPTR(index) != sock->pInput )
01396         ctl_free( sock->pInput );
01397     if( NULL != sock->pOutput && SOCK_OUTPUT_DEFAULTPTR(index) != sock->pOutput )
01398         ctl_free( sock->pOutput );
01399     if( NULL != sock->pAppHeap && SOCK_HEAP_DEFAULTPTR(index) != sock->pAppHeap )
01400         ctl_free( sock->pAppHeap );
01401 
01402     dll_erase(Socket,active, socksActive, sock );
01403     ctl_fp_free(SocketPool, sockPool, sock );
01404     --cSockActive;
01405     ++cSockFree;
01406 }
01407 
01421 Socket* Socket_Customize( Socket* sock, size_t input, size_t output, size_t heap )
01422 {
01423     size_t index;
01424     assertobjptr(sock);
01425     index = ctl_fp_index(SocketPool, sockPool, sock );
01426     assert( index >= 0 && index < MAX_SOCKETS );
01427     /* Free previously customized buffers (I don't wanna leak even if you're doing it wrong) */
01428     if( NULL != sock->pInput && SOCK_INPUT_DEFAULTPTR(index) != sock->pInput )
01429         ctl_free( sock->pInput );
01430     if( NULL != sock->pOutput && SOCK_OUTPUT_DEFAULTPTR(index) != sock->pOutput )
01431         ctl_free( sock->pOutput );
01432     if( NULL != sock->pAppHeap && SOCK_HEAP_DEFAULTPTR(index) != sock->pAppHeap )
01433         ctl_free( sock->pAppHeap );
01434     if( input > sockInSize )
01435     {
01436         ctl_malloc( sock->pInput, input + sizeof(uint32));
01437     }
01438     else
01439     {
01440         input = sockInSize;
01441         sock->pInput = SOCK_INPUT_DEFAULTPTR(index);
01442     }
01443     if( output > sockOutSize )
01444     {
01445         ctl_malloc( sock->pOutput, output + sizeof(uint32) );
01446     }
01447     else
01448     {
01449         output = sockOutSize;
01450         sock->pOutput= SOCK_OUTPUT_DEFAULTPTR(index);
01451     }
01452     if( heap > sockHeapSize )
01453     {
01454         ctl_malloc( sock->pAppHeap, heap + sizeof(uint32) );
01455     }
01456     else
01457     {
01458         heap = sockHeapSize;
01459         sock->pAppHeap = SOCK_HEAP_DEFAULTPTR(index);
01460     }
01461     /* Setup input/output ring buffers */
01462     memset( sock->pInput, 0, input );
01463     RingBuff_Init( &sock->input, sock->pInput, sockInSize );
01464     memset( sock->pInput, 0, output );
01465     RingBuff_Init( &sock->output, sock->pOutput, sockOutSize );
01466     /* Setup application heap */
01467     memset( sock->pAppHeap, 0, heap );
01468     ctl_heap_init( &sock->appheap, sock->pAppHeap, sockHeapSize );
01469     /* Initialize guard bytes whether we're checking them or not (memory dump friendly) */
01470     *((uint32*)(sock->pInput + input)) = GUARD_BYTES;
01471     *((uint32*)(sock->pOutput + output)) = GUARD_BYTES;
01472     *((uint32*)(sock->pAppHeap + heap)) = GUARD_BYTES;
01473     return sock;
01474 }
01475 
01476 
01483 void Socket_LogError( Socket* sock, unsigned mask, const char*fmt, ... )
01484 {
01485     va_list args;
01486     va_start( args, fmt );
01487     int save_errno = SocketError();
01488     assertconst(fmt,1);
01489     debug_vlog(mask, fmt, args );
01490     SocketLogIP(sock,mask,"");
01491     SocketSetError(save_errno);
01492     LOG( mask, "%s\n", SocketsLastErrorString() );
01493 }
01494 
01495 #ifdef DEBUG
01496 
01500 void Socket_Validate( Socket* sock )
01501 {
01502     size_t index;
01503     assertobjptr(sock);
01504     index = ctl_fp_index(SocketPool, sockPool, sock );
01505     assert( NULL != sock->pInput );
01506     assert( NULL != sock->pOutput );
01507     assert( NULL != sock->pAppHeap );
01508     if( SOCK_INPUT_DEFAULTPTR(index) == sock->pInput )
01509     {
01510         assert( *((uint32*)(sock->pInput + sockInSize)) == GUARD_BYTES );
01511     }
01512     else
01513     {
01514         assert( *((uint32*)(sock->pInput + ctl_size(sock->pInput) - sizeof(uint32))) == GUARD_BYTES );
01515     }
01516     if( SOCK_OUTPUT_DEFAULTPTR(index) == sock->pOutput )
01517     {
01518         assert( *((uint32*)(sock->pOutput + sockOutSize)) == GUARD_BYTES );
01519     }
01520     else
01521     {
01522         assert( *((uint32*)(sock->pOutput + ctl_size(sock->pOutput) - sizeof(uint32))) == GUARD_BYTES );
01523     }
01524     if( SOCK_HEAP_DEFAULTPTR(index) == sock->pAppHeap )
01525     {
01526         assert( *((uint32*)(sock->pAppHeap + sockHeapSize)) == GUARD_BYTES );
01527     }
01528     else
01529     {
01530         assert( *((uint32*)(sock->pAppHeap + ctl_size(sock->pAppHeap) - sizeof(uint32))) == GUARD_BYTES );
01531     }
01532 }
01533 #endif
01534 
01539 void Socket_Close( Socket* sock )
01540 {
01541     assertobjptr(sock);
01542     trace(( "Socket_Close(%s)\n", sock->label ));
01543     /* Debug: See if socket got shredded */
01544     Socket_Validate(sock);
01545     sock->type = stUninitialized;
01546     sock->id = 0;
01547 
01548     /* Close socket handle */
01549     if( INVALID_SOCKET != sock->socket )
01550     {
01551         if( SOCKET_ERROR == closesocket(sock->socket) )
01552             SocketsLogLastError( LOG_ERROR, "Socket_Close(%d,%s) closesocket failed.\n", sock->socket, sock->label );
01553         sock->socket = INVALID_SOCKET;
01554     }
01555     
01556     /* Tell app to clean up after its self */
01557     assertcodeptr(sock->appDisconnect);
01558     sock->appDisconnect(sock);
01559 
01560     /* Tell Socket to clean up after its self */
01561     assertcodeptr(sock->vtab->Close);
01562     sock->vtab->Close(sock);
01563 
01564     /* Restore default application callbacks. */
01565     /* App will receive nothing more about this instance. */
01566     sock->appReceived = Socket_DefaultReceived;
01567     sock->appDisconnect = Socket_DefaultCallback;
01568 }
01569 
01577 bool Socket_Write( Socket* sock, const void* buff, size_t count )
01578 {
01579     assertobjptr(sock);
01580     assertconst(buff,count);
01581     if( Socket_ShouldIgnore(sock) )
01582     {
01583         return false;
01584     }
01585     else
01586     {
01587         bool bRet = RingBuff_CopyTo( &sock->output, buff, count );
01588         if( !bRet )
01589         {
01590             SocketsLogLastError( LOG_ERROR, "Socket_Write(%s,%u) failed\n", sock->label, count );
01591             Socket_Close( sock );
01592             return false;
01593         }
01594         return true;
01595     }
01596 }
01597 
01605 bool Socket_Alloc_Serial( Socket* sock, ctl_serial* serial, size_t size )
01606 {
01607     assertobjptr(sock);
01608     assertobjptr(serial);
01609     if( Socket_ShouldIgnore(sock) )
01610     {
01611         return false;
01612     }
01613     else
01614     {
01615         bool bRet = RingBuff_AddSerial( &sock->output, serial, size + 2 );
01616         if( bRet )
01617         {
01618             return true;
01619         }
01620         else
01621         {   /* Not enough room left! */
01622             SocketsLogLastError( LOG_ERROR, "Socket_Alloc_Serial(%s,%u) failed\n", sock->label, size );
01623             Socket_Close( sock );
01624             return false;
01625         }
01626     }
01627 }
01628 
01635 bool Socket_Write_Serial( Socket* sock, const ctl_serial* serial )
01636 {
01637     assertobjptr(sock);
01638     assertobjconst(serial);
01639     if( Socket_ShouldIgnore(sock) )
01640     {
01641         return false;
01642     }
01643     else
01644     {
01645         size_t length = ctl_serial_total( serial );
01646         bool bRet = RingBuff_CopyTo( &sock->output, serial->begin, length );
01647         if( !bRet )
01648         {   /* Not enough room left! */
01649             SocketsLogLastError( LOG_ERROR, "Socket_Write_Serial(%s,%u) failed\n", sock->label, length );
01650             Socket_Close( sock );
01651             return false;
01652         }
01653         return true;
01654     }
01655 }

Generated on Fri Jan 2 15:28:35 2009 for Squat by  doxygen 1.5.6