Figure 2    Single-threaded Blocking Socket


 SOCKET    sock;
 char      buff[256];
 int       done = 0;
 •
 •
 •
 
 while (!done) {
     Nbytes = recv(sock, buff, 65);
     If (Nbytes == -1)  {
         printf("error\n");
         return;
     }
     DoComputationOnData(buff);
 }

Figure 3     Multithreaded Blocking Socket

Common Variables

 // Initialize critical section (data) and create an auto-reset
 // event (hEvent) before creating the two threads
 CRITICAL_SECTION     data;
 HANDLE             hEvent;
 TCHAR             buff[MAX_BUFFER_SIZE];
 int                nbytes; 
Reader Thread
 void ReadThread(void) 
 {
     int    nTotal = 0, nRead = 0, nLeft = 0, nBytes = 0;
 
     while (!done)   
     {
         nTotal = 0;
         nLeft = NUM_BYTES_REQUIRED;
         while (nTotal != NUM_BYTES_REQUIRED) 
         {
             ReserveCriticalSection(&data);
             nRead = recv(sock, &(buff[MAX_BUFFER_SIZE – nBytes]),
                          nLeft);
             if (nRead == -1)  {
                 printf("error\n");
                 ExitThread();
             }
             nTotal += nRead;
             nLeft -= nRead;
 
             nBytes += nRead;
             ReleaseCriticalSection(&data);
         }
         SignalEvent(hEvent);
     }
 } 
Computation Thread
 void ProcessThread(void) 
 {
     WaitForSingleObject(hEvent);
 
     ReserveCriticalSection(&data);
     DoSomeComputationOnData(buff);
     
     // Remove the processed data from the input buffer, and shift the 
     // remaining data to the start of the array
     nbytes -= NUM_BYTES_REQUIRED;
 
     ReleaseCriticalSection(&data);
 }

Figure 4    Making a Socket Nonblocking


 SOCKET           s;
 unsigned long    ul=1;
 int              nRet;
 
 s = socket(AF_INET, SOCK_STREAM, 0);
 nRet = ioctlsocket(s, FIONBIO, (unsigned long *)&ul);
 if (nRet == SOCKET_ERROR) {
     // failed to put socket into nonblocking mode
 }

Figure 5     WSAEWOULDBLOCK Errors

Function Name Description
accept The application has not received a connection request. Call accept again to check for a connection.
closesocket In most cases this means that setsockopt was called with the SO_LINGER option and a timeout was set.
connect The connection is initiated. Call connect again to check for completion.
recv or recvfrom No data has been received. Check again later using select.
send and sentto No buffer space available for outgoing data. Try again later.


Figure 6    Checking for Socket State with select


 SOCKET      s;
 fd_set      fdread;
 int         ret;
 •
 •
 •
 
 // Create a socket and establish a connection
 
 •
 •
 •
 FD_ZERO(&fdread);          // clear the fd_set
 FD_SET(s, &fdread);        // add socket s to the socket set
 if ((ret = select(0, &fdread, NULL, NULL, NULL)) == SOCKET_ERROR) 
 {
     // error condition
 }
 if (ret > 0)
 {
     // At least 1 socket has pending data, in this case only s
 }

Figure 7    Valid Socket Options

Level Option Name Specific API Protocol
SOL_SOCKET SO_SECURE Both Winsock
SO_DEBUG Both Winsock
SO_ACCEPTCONN Both Winsock
SO_RESUSEADDR Both Winsock
SO_KEEPALIVE Both Winsock
SO_BROADCAST setsockopt Winsock
SO_LINGER Both Both
SO_SNDBUF getsockopt Winsock
SO_RCVBUF getsockopt Winsock
SO_TYPE getsockopt Winsock
SO_SNDTIMEO Both Winsock
SO_RCVTIMEO Both Winsock
IPPROTO_TCP TCP_NODELAY Both Winsock
IPPROTO_IP IP_MULTICAST_TTL Both Winsock
IP_MULTICAST_IF Both Winsock
IP_MULTICAST_LOOP Both Winsock
IP_ADD_MEMBERSHIP setsockopt Winsock
IP_DROP_MEMBERSHIP setsockopt Winsock
SOL_IRLMP IRLMP_ENUMDEVICES getsockopt IrSock
IRLMP_IAS_QUERY getsockopt IrSock
IRLMP_SEND_PDU_LEN getsockopt IrSock
IRLMP_EXCLUSIVE_MODE setsockopt IrSock
IRLMP_IRLPT_MODE setsockopt IrSock
IRLMP_9WIRE_MODE setsockopt IrSock
IRLMP_SHARP_MODE setsockopt IrSock
IRLMP_IAS_SET setsockopt IrSock


Figure 8     WSAIoctl and ioctlsocket Options

Function Option
WSAIoctl FIONBIO
FIONREAD
SIOCATMARK
SO_SSL_GET_FLAGS
SO_SSL_SET_FLAGS
SO_SSL_GET_PROTOCOLS
SO_SSL_SET_PROTOCOLS
SO_SSL_GET_VALIDATE_CERT_HOOK
SO_SSL_SET_VALIDATE_CERT_HOOK
SO_SSL_GET_CONNECTION_INFO
ioctlsocket FIONBIO
FIONREAD
SIOCATMARK


Figure 9    Simple IrSock Client and Server

IrClient.c

 #include <windows.h>
 #include <winsock.h>
 #include <af_irda.h>
 
 #define MAX_RETRIES        5
 #define SEND_MESSAGE    "This is a test!"
 
 int LookupIrService(SOCKET sock, DEVICELIST *devList, int *nDevices, 
                     int maxretries)
 {
     int     cnt=0, devListLen = sizeof(*devList);
 
     devList->numDevice = 0;
     while ((devList->numDevice == 0) && (cnt <= maxretries))
     {
         getsockopt(sock, SOL_IRLMP, IRLMP_ENUMDEVICES, (char *)
                    devList, devListLen);
         if (*nDevices = devList.numDevice)continue;
         cnt++;
         Sleep(500); 
     } 
     if (cnt > maxretries) // Server device could not be located
         return 0;
     else
         return 1;
 }
 
 
 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPTSTR lpCmdLine, int nCmdShow )
 {    
     SOCKET            sock;
     SOCKADDR_IRDA     iraddr = {AF_IRDA, 0,0,0,0, "MyServer"};
     DEVICELIST        devList;    
     int               nDevices = 0, idx = 0, nRead, i;
     char              recvBuff[256];
     TCHAR             urecvBuff[256];
 
     Sock = socket(AF_IRDA, SOCK_STREAM, 0);
     
     DevList.numDevice = 0; 
     //
     // Look for any IrSock services out there
     //
     if (LookupIrService(sock, &devList, &nDevices, MAX_RETRIES) == 0)
     {
         MessageBox(NULL, 
                    TEXT("No IrDA services found"), NULL,
                    MB_OK);
         Return 1;
     }
 
     for(i=0; i < nDevices ;i++)
     {
         // Copy the device ID into the SOCKADDR_IRDA structure used
         // in the connect() call
         for (idx = 0; idx <= 3; idx++) 
             iraddr.irdaDeviceID[idx] = devList.Device[i].irdaDeviceID[idx];
         // Attempt a connection
         if (connect(sock, (struct sockaddr *)&iraddr, 
                     sizeof(SOCKADDR_IRDA)) == SOCKET_ERROR)
         {
             MessageBox(NULL, TEXT("Unable to estabilish a\ 
                                   Connection to a server"),
                                   NULL, MB_OK);
             continue;
         }
         send(sock, SEND_MESSAGE, strlen(SEND_MESSAGE)+1, 0);
     
         nRead = recv(sock, recvBuff, sizeof(recvBuff), 0);
         // Convert ASCII message to Unicode
         //
         for(idx=0; idx < nRead ;idx++)
             urecvBuff[idx] = recvBuff[idx];
         MessageBox(NULL, urecvBuff, TEXT("IR Client"), MB_OK);
 
         Closesocket(sock);
         Break;
     }
 
     return 0;
 }
 
IrServer.c
 #include <windows.h>
 #include <af_irda.h>
 
 #define SEND_MESSAGE "Hello Client!"
 
 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPTSTR lpCmdLine, int nCmdShow )
 {
     WSAData       wsaData;
     SOCKET        ServerSock,      // Socket for the Server
                   ClientSock;      // Socket for the Client
     SOCKADDR_IRDA    iraddr = {AF_IRDA, 0, 0, 0, 0, "MyServer"};
 
     char        asciiBuff[250];        // ASCII String 
     TCHAR       unicodeBuff[250];      // UNICODE String
     int         idx = 0, done = 0, nRead;
 
     if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
     {
         MessageBox(NULL, TEXT("Unable to perform WSAStartup"), NULL, 
                    MB_OK);
         Return 1;
     }
     //
     // Allocate a stream socket in the IrDA address domain
     //
     if ((ServerSock = socket(AF_IRDA, SOCK_STREAM, 0)) == INVALID_SOCKET)
     {
         wsprintf(unicodeBuff, TEXT("socket call failed with: %d"), 
                  WSAGetLastError());
         MessageBox(NULL, unicodeBuff, NULL, MB_OK);
         Return 1;
     }
     if (bind(ServerSock, (struct sockaddr *)&iraddr, sizeof(iraddr)) != 0)
     {
         wsprintf(unicodeBuff, TEXT("Unable to bind to socket: %d"), 
                  WSAGetLastError());
         MessageBox(NULL, unicodeBuff, NULL, MB_OK);
         Return 1;
     }
     listen(ServerSock, 8);
 
     while (!done)
     {
         // Wait for a client to contact us.  Blocking call.
         //
         ClientSock = accept(ServerSock, 0, 0);
 
         // Receive a string from the client
         nRead = recv(ClientSock, asciiBuff, sizeof(asciiBuff), 0);
 
         // Convert string from client to Unicode
         for (idx = 0; idx <= nRead; idx++)
              unicodeBuff[idx] = asciiBuff[idx];
 
         // Display string received from client
         MessageBox (NULL, unicodeBuff, TEXT("IR Server"), MB_OK);
 
         // Send a greeting back to the Client
         send(ClientSock, SEND_MESSAGE, strlen(SEND_MESSAGE)+1, 0);
 
         // Close Client Socket
         closesocket(ClientSock);
     }
     closesocket(ServerSock); // Close Server Socket
 
     WSACleanup();
     return 0;
 }