]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/gsocket.c
Added VC++ 5 wxWin project files (not generated sample project files)
[wxWidgets.git] / src / msw / gsocket.c
index a4f45084d8bad41a602e15a3cae89807695735e5..350c4a8bbd7150975b36a3c979df06112519b401 100644 (file)
@@ -6,8 +6,9 @@
  * -------------------------------------------------------------------------
  */
 
+#if defined(__GSOCKET_STANDALONE__) || defined(wxUSE_SOCKETS)
 
-#ifdef __WXMSW__
+#ifndef __GSOCKET_STANDALONE__
 
 #include "wx/setup.h"
 #include "wx/msw/gsockmsw.h"
  * be available and it must containt the app's instance
  * handle.
  */
-#define INSTANCE hInst    
+#define INSTANCE hInst
 
-#endif /* __WXMSW__ */
+#endif /* __GSOCKET_STANDALONE__ */
 
 
-#if !defined(__WXMSW__) || (defined(__WXMSW__) && wxUSE_SOCKETS)
-
 #include <assert.h>
 #include <string.h>
 #include <stdio.h>
@@ -99,7 +98,6 @@ bool GSocket_Init()
   }
   firstAvailable = 0;
 
-
   /* Initialize WinSocket */
   return (WSAStartup((1 << 8) | 1, &wsaData) == 0);
 }
@@ -107,7 +105,7 @@ bool GSocket_Init()
 void GSocket_Cleanup()
 {
   /* Destroy internal window */
-  DestroyWindow(WINDOWNAME);
+  DestroyWindow(hWin);
   UnregisterClass(CLASSNAME, INSTANCE);
 
   /* Delete critical section */
@@ -139,7 +137,7 @@ GSocket *GSocket_new()
   socket->m_stream          = TRUE;
   socket->m_non_blocking    = FALSE;
   socket->m_timeout.tv_sec  = 10 * 60;  /* 10 minutes */
-  socket->m_timeout.tv_usec = 0;        
+  socket->m_timeout.tv_usec = 0;
 
   /* Allocate a new message number for this socket */
   EnterCriticalSection(&critical);
@@ -201,7 +199,6 @@ void GSocket_Shutdown(GSocket *socket)
   /* If socket has been created, we shutdown it */
   if (socket->m_fd != INVALID_SOCKET)
   {
-    /* TODO: Guilhem only does this for connection oriented sockets (?) */
     shutdown(socket->m_fd, 2);
     closesocket(socket->m_fd);
     socket->m_fd = INVALID_SOCKET;
@@ -345,7 +342,6 @@ GSocketError GSocket_SetServer(GSocket *sck)
 
   /* Create the socket */
   sck->m_fd = socket(sck->m_local->m_realfamily, SOCK_STREAM, 0);
-  ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg);
 
   if (sck->m_fd == INVALID_SOCKET)
   {
@@ -353,6 +349,9 @@ GSocketError GSocket_SetServer(GSocket *sck)
     return GSOCK_IOERR;
   }
 
+  ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg);
+  _GSocket_Configure_Callbacks(sck);
+
   /* Bind the socket to the LOCAL address */
   if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) != 0)
   {
@@ -372,7 +371,7 @@ GSocketError GSocket_SetServer(GSocket *sck)
   }
 
   return GSOCK_NOERROR;
-}    
+}
 
 /* GSocket_WaitConnection:
  *  Waits for an incoming client connection.
@@ -409,12 +408,15 @@ GSocket *GSocket_WaitConnection(GSocket *sck)
   }
 
   connection->m_fd = accept(sck->m_fd, NULL, NULL);
-  ioctlsocket(connection->m_fd, FIONBIO, (u_long FAR *) &arg);
 
   if (connection->m_fd == INVALID_SOCKET)
   {
+    if (WSAGetLastError() == WSAEWOULDBLOCK)
+      sck->m_error = GSOCK_WOULDBLOCK;
+    else
+      sck->m_error = GSOCK_IOERR;
+
     GSocket_destroy(connection);
-    sck->m_error = GSOCK_IOERR;
     return NULL;
   }
 
@@ -423,6 +425,9 @@ GSocket *GSocket_WaitConnection(GSocket *sck)
   connection->m_stream   = TRUE;
   connection->m_oriented = TRUE;
 
+  ioctlsocket(connection->m_fd, FIONBIO, (u_long FAR *) &arg);
+  _GSocket_Configure_Callbacks(connection);
+
   return connection;
 }
 
@@ -453,7 +458,6 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
 
   /* Create the socket */
   sck->m_fd = socket(sck->m_local->m_realfamily, SOCK_DGRAM, 0);
-  ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg);
 
   if (sck->m_fd == INVALID_SOCKET)
   {
@@ -461,6 +465,9 @@ GSocketError GSocket_SetNonOriented(GSocket *sck)
     return GSOCK_IOERR;
   }
 
+  ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg);
+  _GSocket_Configure_Callbacks(sck);
+
   /* Bind it to the LOCAL address */
   if (bind(sck->m_fd, sck->m_local->m_addr, sck->m_local->m_len) != 0)
   {
@@ -493,14 +500,16 @@ GSocketError GSocket_SetBroadcast(GSocket *sck)
 /* GSocket_Connect:
  *  Establishes a client connection to a server using the "Peer"
  *  field of GSocket. "Peer" must be set by GSocket_SetPeer() before
- *  GSocket_Connect() is called. Possible error codes are GSOCK_INVSOCK
- *  if the socket is alredy in use, GSOCK_INVADDR if the peer address
- *  has not been set, or GSOCK_IOERR for other internal errors.
+ *  GSocket_Connect() is called. Possible error codes are GSOCK_INVSOCK,
+ *  GSOCK_INVADDR, GSOCK_TIMEDOUT, GSOCK_WOULDBLOCK and GSOCK_IOERR.
+ *  If a socket is nonblocking and Connect() returns GSOCK_WOULDBLOCK,
+ *  the connection request can be completed later. Use GSocket_Select()
+ *  to check or wait for a GSOCK_CONNECTION event.
  */
 GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
 {
   u_long arg = 1;
-  int type, ret;
+  int type, ret, err;
 
   assert(sck != NULL);
 
@@ -528,7 +537,6 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
 
   /* Create the socket */
   sck->m_fd = socket(sck->m_peer->m_realfamily, type, 0);
-  ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg);
 
   if (sck->m_fd == INVALID_SOCKET)
   {
@@ -536,35 +544,53 @@ GSocketError GSocket_Connect(GSocket *sck, GSocketStream stream)
     return GSOCK_IOERR;
   }
 
-  /* Connect it to the PEER address, with a timeout */
+  ioctlsocket(sck->m_fd, FIONBIO, (u_long FAR *) &arg);
+  _GSocket_Configure_Callbacks(sck);
+
+  /* Connect it to the PEER address, with a timeout (see below) */
   ret = connect(sck->m_fd, sck->m_peer->m_addr, sck->m_peer->m_len);
 
   if (ret == SOCKET_ERROR)
   {
-    /* For blocking GSockets, if connect fails with an EWOULDBLOCK
-     * error, then we can select() the socket for the specified
-     * timeout and check for writability to see if the connection
-     * request completes. If the error is different than EWOULDBLOCK,
-     * or if the socket is nonblocking, the call to GSocket_Connect()
-     * has failed.
+    err = WSAGetLastError();
+
+    /* If connect failed with EWOULDBLOCK and the GSocket object
+     * is in blocking mode, we select() for the specified timeout
+     * checking for writability to see if the connection request
+     * completes.
      */
-    if ((!sck->m_non_blocking) && (WSAGetLastError() == WSAEWOULDBLOCK))
+    if ((err == WSAEWOULDBLOCK) && (!sck->m_non_blocking))
     {
       if (_GSocket_Output_Timeout(sck) == GSOCK_TIMEDOUT)
       {
         closesocket(sck->m_fd);
         sck->m_fd = INVALID_SOCKET;
-        /* sck->m_error is set in _GSocket_Input_Timeout */
+        /* sck->m_error is set in _GSocket_Output_Timeout */
         return GSOCK_TIMEDOUT;
       }
+      else
+        return GSOCK_NOERROR;
     }
-    else  /* error */
+
+    /* If connect failed with EWOULDBLOCK and the GSocket object
+     * is set to nonblocking, we set m_error to GSOCK_WOULDBLOCK
+     * (and return GSOCK_WOULDBLOCK) but we don't close the socket;
+     * this way if the connection completes, a GSOCK_CONNECTION
+     * event will be generated, if enabled.
+     */
+    if ((err == WSAEWOULDBLOCK) && (sck->m_non_blocking))
     {
-      closesocket(sck->m_fd);
-      sck->m_fd = INVALID_SOCKET;
-      sck->m_error = GSOCK_IOERR;
-      return GSOCK_IOERR;
+      sck->m_error = GSOCK_WOULDBLOCK;
+      return GSOCK_WOULDBLOCK;
     }
+
+    /* If connect failed with an error other than EWOULDBLOCK,
+     * then the call to GSocket_Connect has failed.
+     */
+    closesocket(sck->m_fd);
+    sck->m_fd = INVALID_SOCKET;
+    sck->m_error = GSOCK_IOERR;
+    return GSOCK_IOERR;
   }
 
   return GSOCK_NOERROR;
@@ -611,34 +637,68 @@ int GSocket_Write(GSocket *socket, const char *buffer, int size)
     return _GSocket_Send_Dgram(socket, buffer, size);
 }
 
-bool GSocket_DataAvailable(GSocket *socket)
+/* GSocket_Select:
+ *  Polls the socket to determine its status. This function will
+ *  check for the events specified in the 'flags' parameter, and
+ *  it will return a mask indicating which operations can be
+ *  performed. This function won't block, regardless of the
+ *  mode (blocking|nonblocking) of the socket.
+ */
+GSocketEventFlags GSocket_Select(GSocket *socket, GSocketEventFlags flags)
 {
-  fd_set read_set;
+  fd_set readfds, writefds, exceptfds;
   struct timeval tv;
+  GSocketEventFlags mask;
 
   assert(socket != NULL);
 
-  if (socket->m_fd == INVALID_SOCKET || socket->m_server)
+  if (socket->m_fd == INVALID_SOCKET)
   {
     socket->m_error = GSOCK_INVSOCK;
     return FALSE;
   }
 
-  FD_ZERO(&read_set);
-  FD_SET(socket->m_fd, &read_set);
+  FD_ZERO(&readfds);
+  FD_ZERO(&writefds);
+  FD_ZERO(&exceptfds);
+  FD_SET(socket->m_fd, &readfds);
+  FD_SET(socket->m_fd, &writefds);
+  FD_SET(socket->m_fd, &exceptfds);
 
   tv.tv_sec = 0;
   tv.tv_usec = 0;
+  select(socket->m_fd + 1, &readfds, &writefds, &exceptfds, &tv);
 
-  select(socket->m_fd + 1, &read_set, NULL, NULL, &tv);
+  mask = 0;
 
-  return FD_ISSET(socket->m_fd, &read_set);
+  /* If select() says that the socket is readable, then we have
+   * no way to distinguish if that means 'data available' (to
+   * recv) or 'incoming connection' (to accept). The same goes
+   * for writability: we cannot distinguish between 'you can
+   * send data' and 'connection request completed'. So we will
+   * assume the following: if the flag was set upon entry,
+   * that means that the event was possible.
+   */
+  if (FD_ISSET(socket->m_fd, &readfds))
+  {
+    mask |= (flags & GSOCK_CONNECTION_FLAG);
+    mask |= (flags & GSOCK_INPUT_FLAG);
+  }
+  if (FD_ISSET(socket->m_fd, &writefds))
+  {
+    mask |= (flags & GSOCK_CONNECTION_FLAG);
+    mask |= (flags & GSOCK_OUTPUT_FLAG);
+  }
+  if (FD_ISSET(socket->m_fd, &exceptfds))
+    mask |= (flags & GSOCK_LOST_FLAG);
+
+  return mask;
 }
 
 /* Flags */
 
 /* GSocket_SetNonBlocking:
- *  Sets the socket in non-blocking mode. This is useful if
+ *  Sets the socket to non-blocking mode. This is useful if
  *  we don't want to wait.
  */
 void GSocket_SetNonBlocking(GSocket *socket, bool non_block)
@@ -649,6 +709,8 @@ void GSocket_SetNonBlocking(GSocket *socket, bool non_block)
 }
 
 /* GSocket_SetTimeout:
+ *  Sets the timeout for blocking calls. Time is
+ *  expressed in milliseconds.
  */
 void GSocket_SetTimeout(GSocket *socket, unsigned long millisecs)
 {
@@ -687,14 +749,14 @@ GSocketError GSocket_GetError(GSocket *socket)
  */
 
 /* GSocket_SetCallback:
- *  Enables the callbacks specified by 'event'. Note that 'event'
+ *  Enables the callbacks specified by 'flags'. Note that 'flags'
  *  may be a combination of flags OR'ed toghether, so the same
  *  callback function can be made to accept different events.
  *  The callback function must have the following prototype:
  *
  *  void function(GSocket *socket, GSocketEvent event, char *cdata)
  */
-void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event,
+void GSocket_SetCallback(GSocket *socket, GSocketEventFlags flags,
                          GSocketCallback callback, char *cdata)
 {
   int count;
@@ -704,7 +766,7 @@ void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event,
   for (count = 0; count < GSOCK_MAX_EVENT; count++)
   {
     /* We test each flag and enable the corresponding events */
-    if ((event & (1 << count)) != 0)
+    if ((flags & (1 << count)) != 0)
     {
       socket->m_cbacks[count] = callback;
       socket->m_data[count] = cdata;
@@ -715,10 +777,10 @@ void GSocket_SetCallback(GSocket *socket, GSocketEventFlags event,
 }
 
 /* GSocket_UnsetCallback:
- *  Disables all callbacks specified by 'event', which may be a
+ *  Disables all callbacks specified by 'flags', which may be a
  *  combination of flags OR'ed toghether.
  */
-void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags event)
+void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags flags)
 {
   int count = 0;
 
@@ -727,7 +789,7 @@ void GSocket_UnsetCallback(GSocket *socket, GSocketEventFlags event)
   for (count = 0; count < GSOCK_MAX_EVENT; count++)
   {
     /* We test each flag and disable the corresponding events */
-    if ((event & (1 << count)) != 0)
+    if ((flags & (1 << count)) != 0)
     {
       socket->m_cbacks[count] = NULL;
     }
@@ -744,6 +806,9 @@ void _GSocket_Configure_Callbacks(GSocket *socket)
   long mask = 0;
   int count;
 
+  if (socket->m_fd == INVALID_SOCKET)
+    return;
+
   for (count = 0; count < GSOCK_MAX_EVENT; count++)
   {
     if (socket->m_cbacks[count] != NULL)
@@ -754,7 +819,7 @@ void _GSocket_Configure_Callbacks(GSocket *socket)
         case GSOCK_OUTPUT:     mask |= FD_WRITE; break;
         case GSOCK_CONNECTION: mask |= (FD_ACCEPT | FD_CONNECT); break;
         case GSOCK_LOST:       mask |= FD_CLOSE; break;
-      }        
+      }
     }
   }
 
@@ -788,7 +853,14 @@ LRESULT CALLBACK _GSocket_Internal_WinProc(HWND hWnd,
         case FD_READ:    event = GSOCK_INPUT; break;
         case FD_WRITE:   event = GSOCK_OUTPUT; break;
         case FD_ACCEPT:  event = GSOCK_CONNECTION; break;
-        case FD_CONNECT: event = GSOCK_CONNECTION; break;
+        case FD_CONNECT:
+        {
+          if (WSAGETSELECTERROR(lParam) != 0)
+            event = GSOCK_LOST;
+          else
+            event = GSOCK_CONNECTION;
+          break;
+        }
         case FD_CLOSE:   event = GSOCK_LOST; break;
       }
 
@@ -820,7 +892,7 @@ GSocketError _GSocket_Input_Timeout(GSocket *socket)
 {
   fd_set readfds;
 
-  if (socket->m_non_blocking == FALSE)
+  if (!socket->m_non_blocking)
   {
     FD_ZERO(&readfds);
     FD_SET(socket->m_fd, &readfds);
@@ -841,7 +913,7 @@ GSocketError _GSocket_Output_Timeout(GSocket *socket)
 {
   fd_set writefds;
 
-  if (socket->m_non_blocking == FALSE)
+  if (!socket->m_non_blocking)
   {
     FD_ZERO(&writefds);
     FD_SET(socket->m_fd, &writefds);
@@ -857,7 +929,7 @@ GSocketError _GSocket_Output_Timeout(GSocket *socket)
 int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
 {
   int ret;
-   
+
   ret = recv(socket->m_fd, buffer, size, 0);
 
   if (ret == SOCKET_ERROR)
@@ -876,7 +948,7 @@ int _GSocket_Recv_Stream(GSocket *socket, char *buffer, int size)
 int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
 {
   struct sockaddr from;
-  SOCKLEN_T fromlen; 
+  SOCKLEN_T fromlen;
   int ret;
 
   fromlen = sizeof(from);
@@ -905,8 +977,8 @@ int _GSocket_Recv_Dgram(GSocket *socket, char *buffer, int size)
   }
   if (_GAddress_translate_from(socket->m_peer, &from, fromlen) != GSOCK_NOERROR)
   {
-    socket->m_error = GSOCK_MEMERR;     /* TODO: bug in Unix GSocket! */
-    GAddress_destroy(socket->m_peer);   /* TODO: bug in Unix GSocket! */
+    socket->m_error = GSOCK_MEMERR;
+    GAddress_destroy(socket->m_peer);
     return -1;
   }
 
@@ -1145,7 +1217,7 @@ GSocketError GAddress_INET_SetHostName(GAddress *address, const char *hostname)
   addr = &(((struct sockaddr_in *)address->m_addr)->sin_addr);
 
   addr->s_addr = inet_addr(hostname);
+
   /* If it is a numeric host name, convert it now */
   if (addr->s_addr == INADDR_NONE)
   {
@@ -1192,7 +1264,7 @@ GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port,
     address->m_error = GSOCK_INVPORT;
     return GSOCK_INVOP;
   }
+
   se = getservbyname(port, protocol);
   if (!se)
   {
@@ -1202,7 +1274,7 @@ GSocketError GAddress_INET_SetPortName(GAddress *address, const char *port,
 
       port_int = atoi(port);
       addr = (struct sockaddr_in *)address->m_addr;
-      addr->sin_port = htons(port_int);
+      addr->sin_port = htons((u_short) port_int);
       return GSOCK_NOERROR;
     }
 
@@ -1222,7 +1294,7 @@ GSocketError GAddress_INET_SetPort(GAddress *address, unsigned short port)
 
   assert(address != NULL);
   CHECK_ADDRESS(address, INET, GSOCK_INVADDR);
+
   addr = (struct sockaddr_in *)address->m_addr;
   addr->sin_port = htons(port);
 
@@ -1235,7 +1307,7 @@ GSocketError GAddress_INET_GetHostName(GAddress *address, char *hostname, size_t
   char *addr_buf;
   struct sockaddr_in *addr;
 
-  assert(address != NULL); 
+  assert(address != NULL);
   CHECK_ADDRESS(address, INET, GSOCK_INVADDR);
 
   addr = (struct sockaddr_in *)address->m_addr;
@@ -1257,8 +1329,8 @@ unsigned long GAddress_INET_GetHostAddress(GAddress *address)
 {
   struct sockaddr_in *addr;
 
-  assert(address != NULL); 
-  CHECK_ADDRESS(address, INET, 0); 
+  assert(address != NULL);
+  CHECK_ADDRESS(address, INET, 0);
 
   addr = (struct sockaddr_in *)address->m_addr;
 
@@ -1269,8 +1341,8 @@ unsigned short GAddress_INET_GetPort(GAddress *address)
 {
   struct sockaddr_in *addr;
 
-  assert(address != NULL); 
-  CHECK_ADDRESS(address, INET, 0); 
+  assert(address != NULL);
+  CHECK_ADDRESS(address, INET, 0);
 
   addr = (struct sockaddr_in *)address->m_addr;
   return ntohs(addr->sin_port);
@@ -1304,7 +1376,8 @@ GSocketError GAddress_UNIX_GetPath(GAddress *address, char *path, size_t sbuf)
 }
 
 
-#endif  /* !defined(__WXMSW__) || (defined(__WXMSW__) && wxUSE_SOCKETS) */
+#endif  /* defined(__GSOCKET_STANDALONE__) || defined(wxUSE_SOCKETS) */
+