diff deps/Platinum/ThirdParty/Neptune/Source/System/Bsd/NptBsdSockets.cpp @ 0:3425707ddbf6

Initial import (hopefully this mercurial stuff works...)
author fraserofthenight
date Mon, 06 Jul 2009 08:06:28 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/deps/Platinum/ThirdParty/Neptune/Source/System/Bsd/NptBsdSockets.cpp	Mon Jul 06 08:06:28 2009 -0700
@@ -0,0 +1,1987 @@
+/*****************************************************************
+|
+|   Neptune - Sockets :: BSD/Winsock Implementation
+|
+|   (c) 2001-2008 Gilles Boccon-Gibod
+|   Author: Gilles Boccon-Gibod (bok@bok.net)
+|
+ ****************************************************************/
+
+/*----------------------------------------------------------------------
+|   includes
++---------------------------------------------------------------------*/
+#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(__SYMBIAN32__)
+
+// Win32 includes
+#if !defined(__WIN32__) 
+#define __WIN32__
+#endif
+#endif
+#if defined(__WIN32__) && !defined(_XBOX)
+#define STRICT
+#define NPT_WIN32_USE_WINSOCK2
+#ifdef NPT_WIN32_USE_WINSOCK2
+/* it is important to include this in this order, because winsock.h and ws2tcpip.h */
+/* have different definitions for the same preprocessor symbols, such as IP_ADD_MEMBERSHIP */
+#include <winsock2.h>
+#include <ws2tcpip.h> 
+#else
+#include <winsock.h>
+#endif
+#include <windows.h>
+
+// XBox
+#elif defined(_XBOX)
+#include <xtl.h>
+#include <winsockx.h>
+
+#elif defined(__TCS__)
+
+// Trimedia includes
+#include <sockets.h>
+
+#elif defined(__PSP__)
+
+// PSP includes
+#include <psptypes.h>
+#include <kernel.h>
+#include <pspnet.h>
+#include <pspnet_error.h>
+#include <pspnet_inet.h>
+#include <pspnet_resolver.h>
+#include <pspnet_apctl.h>
+#include <pspnet_ap_dialog_dummy.h>
+#include <errno.h>
+#include <wlan.h>
+#include <pspnet/sys/socket.h>
+#include <pspnet/sys/select.h>
+#include <pspnet/netinet/in.h>
+
+#elif defined(__PPU__)
+
+// PS3 includes
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <netex/net.h>
+#include <netex/errno.h>
+
+#else
+
+// default includes
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#if !defined(__SYMBIAN32__)
+#include <netinet/tcp.h>
+#endif
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+
+#endif 
+
+
+#include "NptConfig.h"
+#include "NptTypes.h"
+#include "NptStreams.h"
+#include "NptThreads.h"
+#include "NptSockets.h"
+#include "NptUtils.h"
+#include "NptConstants.h"
+
+/*----------------------------------------------------------------------
+|   constants
++---------------------------------------------------------------------*/
+const int NPT_TCP_SERVER_SOCKET_DEFAULT_LISTEN_COUNT = 20;
+
+/*----------------------------------------------------------------------
+|   WinSock adaptation layer
++---------------------------------------------------------------------*/
+#if defined(__WIN32__) || defined(_XBOX)
+#if defined(_XBOX)
+#include "NptXboxNetwork.h"
+#define SO_ERROR    0x1007          /* unsupported */
+#else
+#include "NptWin32Network.h"
+#endif
+// force a reference to the initializer so that the linker does not optimize it out
+static NPT_WinsockSystem& WinsockInitializer = NPT_WinsockSystem::Initializer; 
+
+#if defined(SetPort)
+#undef SetPort
+#endif
+
+#define EWOULDBLOCK  WSAEWOULDBLOCK
+#define EINPROGRESS  WSAEINPROGRESS
+#define ECONNREFUSED WSAECONNREFUSED
+#define ECONNABORTED WSAECONNABORTED
+#define ECONNRESET   WSAECONNRESET
+#define ETIMEDOUT    WSAETIMEDOUT
+#define ENETRESET    WSAENETRESET
+#define EADDRINUSE   WSAEADDRINUSE
+#define ENETDOWN     WSAENETDOWN
+#define ENETUNREACH  WSAENETUNREACH
+#if !defined(EAGAIN)
+#define EAGAIN       WSAEWOULDBLOCK 
+#endif
+
+#if !defined(__MINGW32__)
+typedef int         ssize_t;
+#endif
+typedef int         socklen_t;
+typedef char*       SocketBuffer;
+typedef const char* SocketConstBuffer;
+typedef char*       SocketOption;
+typedef SOCKET      SocketFd;
+
+#define GetSocketError()                 WSAGetLastError()
+#define NPT_BSD_SOCKET_IS_INVALID(_s)    ((_s) == INVALID_SOCKET)
+#define NPT_BSD_SOCKET_CALL_FAILED(_e)   ((_e) == SOCKET_ERROR)
+#define NPT_BSD_SOCKET_SELECT_FAILED(_e) ((_e) == SOCKET_ERROR)
+
+/*----------------------------------------------------------------------
+|   Trimedia adaptation layer
++---------------------------------------------------------------------*/
+#elif defined(__TCS__)  // trimedia PSOS w/ Target TCP
+typedef void*       SocketBuffer;
+typedef const void* SocketConstBuffer;
+typedef void*       SocketOption;
+typedef int         SocketFd;
+
+#define GetSocketError()                 errno
+#define NPT_BSD_SOCKET_IS_INVALID(_s)    ((_s)  < 0)
+#define NPT_BSD_SOCKET_CALL_FAILED(_e)   ((_e)  < 0)
+#define NPT_BSD_SOCKET_SELECT_FAILED(_e) ((_e)  < 0)
+
+/*----------------------------------------------------------------------
+|   PSP adaptation layer
++---------------------------------------------------------------------*/
+#elif defined(__PSP__)
+typedef SceNetInetSocklen_t socklen_t;
+#define timeval SceNetInetTimeval
+#define inet_addr sceNetInetInetAddr
+#define select sceNetInetSelect
+#define socket sceNetInetSocket
+#define connect sceNetInetConnect
+#define bind sceNetInetBind
+#define accept sceNetInetAccept
+#define getpeername sceNetInetGetpeername
+#define getsockopt sceNetInetGetsockopt
+#define setsockopt sceNetInetSetsockopt
+#define listen sceNetInetListen
+#define getsockname sceNetInetGetsockname
+#define sockaddr SceNetInetSockaddr
+#define sockaddr_in SceNetInetSockaddrIn
+#define in_addr SceNetInetInAddr
+#define send  sceNetInetSend
+#define sendto sceNetInetSendto
+#define recv  sceNetInetRecv
+#define recvfrom sceNetInetRecvfrom
+#define closesocket sceNetInetClose
+#define htonl sceNetHtonl
+#define htons sceNetHtons
+#define ntohl sceNetNtohl
+#define ntohs sceNetNtohs
+#define SOL_SOCKET SCE_NET_INET_SOL_SOCKET
+#define AF_INET SCE_NET_INET_AF_INET
+#define SOCK_STREAM SCE_NET_INET_SOCK_STREAM
+#define SOCK_DGRAM SCE_NET_INET_SOCK_DGRAM
+#define SO_BROADCAST SCE_NET_INET_SO_BROADCAST
+#define SO_ERROR SCE_NET_INET_SO_ERROR
+#define IPPROTO_IP SCE_NET_INET_IPPROTO_IP
+#define IP_ADD_MEMBERSHIP SCE_NET_INET_IP_ADD_MEMBERSHIP
+#define IP_MULTICAST_IF SCE_NET_INET_IP_MULTICAST_IF
+#define IP_MULTICAST_TTL SCE_NET_INET_IP_MULTICAST_TTL
+#define SO_REUSEADDR SCE_NET_INET_SO_REUSEADDR
+#define INADDR_ANY SCE_NET_INET_INADDR_ANY
+#define ip_mreq SceNetInetIpMreq
+#ifdef fd_set
+#undef fd_set
+#endif
+#define fd_set SceNetInetFdSet
+#ifdef FD_ZERO
+#undef FD_ZERO
+#endif
+#define FD_ZERO SceNetInetFD_ZERO
+#ifdef FD_SET
+#undef FD_SET
+#endif
+#define FD_SET SceNetInetFD_SET
+#ifdef FD_CLR
+#undef FD_CLR
+#endif
+#define FD_CLR SceNetInetFD_CLR
+#ifdef FD_ISSET
+#undef FD_ISSET
+#endif
+#define FD_ISSET SceNetInetFD_ISSET
+
+#define RESOLVER_TIMEOUT (5 * 1000 * 1000)
+#define RESOLVER_RETRY    5
+
+typedef void*       SocketBuffer;
+typedef const void* SocketConstBuffer;
+typedef void*       SocketOption;
+typedef int         SocketFd;
+
+#define GetSocketError()                 sceNetInetGetErrno()
+#define NPT_BSD_SOCKET_IS_INVALID(_s)    ((_s) < 0)
+#define NPT_BSD_SOCKET_CALL_FAILED(_e)   ((_e) < 0)
+#define NPT_BSD_SOCKET_SELECT_FAILED(_e) ((_e) < 0)
+
+/*----------------------------------------------------------------------
+|   PS3 adaptation layer
++---------------------------------------------------------------------*/
+#elif defined(__PPU__)
+#undef EWOULDBLOCK    
+#undef ECONNREFUSED  
+#undef ECONNABORTED  
+#undef ECONNRESET    
+#undef ETIMEDOUT     
+#undef ENETRESET     
+#undef EADDRINUSE    
+#undef ENETDOWN      
+#undef ENETUNREACH   
+#undef EAGAIN        
+#undef EINTR     
+#undef EINPROGRESS
+
+#define EWOULDBLOCK   SYS_NET_EWOULDBLOCK 
+#define ECONNREFUSED  SYS_NET_ECONNREFUSED
+#define ECONNABORTED  SYS_NET_ECONNABORTED
+#define ECONNRESET    SYS_NET_ECONNRESET
+#define ETIMEDOUT     SYS_NET_ETIMEDOUT
+#define ENETRESET     SYS_NET_ENETRESET
+#define EADDRINUSE    SYS_NET_EADDRINUSE
+#define ENETDOWN      SYS_NET_ENETDOWN
+#define ENETUNREACH   SYS_NET_ENETUNREACH
+#define EAGAIN        SYS_NET_EAGAIN
+#define EINTR         SYS_NET_EINTR
+#define EINPROGRESS   SYS_NET_EINPROGRESS
+
+typedef void*        SocketBuffer;
+typedef const void*  SocketConstBuffer;
+typedef void*        SocketOption;
+typedef int          SocketFd;
+
+#define closesocket  socketclose
+#define select       socketselect
+
+#define GetSocketError()                 sys_net_errno
+#define NPT_BSD_SOCKET_IS_INVALID(_s)    ((_s) < 0)
+#define NPT_BSD_SOCKET_CALL_FAILED(_e)   ((_e) < 0)
+#define NPT_BSD_SOCKET_SELECT_FAILED(_e) ((_e) < 0)
+
+// network initializer 
+static struct NPT_Ps3NetworkInitializer {
+    NPT_Ps3NetworkInitializer() {
+        sys_net_initialize_network();
+    }
+    ~NPT_Ps3NetworkInitializer() {
+        sys_net_finalize_network();
+    }
+} Ps3NetworkInitializer;
+
+/*----------------------------------------------------------------------
+|   Default adaptation layer
++---------------------------------------------------------------------*/
+#else  
+typedef void*       SocketBuffer;
+typedef const void* SocketConstBuffer;
+typedef void*       SocketOption;
+typedef int         SocketFd;
+
+#define closesocket  close
+#define ioctlsocket  ioctl
+
+#define GetSocketError()                 errno
+#define NPT_BSD_SOCKET_IS_INVALID(_s)    ((_s)  < 0)
+#define NPT_BSD_SOCKET_CALL_FAILED(_e)   ((_e)  < 0)
+#define NPT_BSD_SOCKET_SELECT_FAILED(_e) ((_e)  < 0)
+
+#endif
+
+/*----------------------------------------------------------------------
+|   SocketAddressToInetAddress
++---------------------------------------------------------------------*/
+static void
+SocketAddressToInetAddress(const NPT_SocketAddress& socket_address, 
+                           struct sockaddr_in*      inet_address)
+{
+    // initialize the structure
+    for (int i=0; i<8; i++) inet_address->sin_zero[i]=0;
+
+    // setup the structure
+    inet_address->sin_family = AF_INET;
+    inet_address->sin_port = htons(socket_address.GetPort());
+    inet_address->sin_addr.s_addr = htonl(socket_address.GetIpAddress().AsLong());
+}
+
+/*----------------------------------------------------------------------
+|   InetAddressToSocketAddress
++---------------------------------------------------------------------*/
+static void
+InetAddressToSocketAddress(const struct sockaddr_in* inet_address,
+                           NPT_SocketAddress&        socket_address)
+{
+    // read the fields
+    socket_address.SetPort(ntohs(inet_address->sin_port));
+    socket_address.SetIpAddress(NPT_IpAddress(ntohl(inet_address->sin_addr.s_addr)));
+}
+
+/*----------------------------------------------------------------------
+|   MapErrorCode
++---------------------------------------------------------------------*/
+static NPT_Result 
+MapErrorCode(int error)
+{
+    switch (error) {
+        case ECONNRESET:
+        case ENETRESET:
+            return NPT_ERROR_CONNECTION_RESET;
+
+        case ECONNABORTED:
+            return NPT_ERROR_CONNECTION_ABORTED;
+
+        case ECONNREFUSED:
+            return NPT_ERROR_CONNECTION_REFUSED;
+
+        case ETIMEDOUT:
+            return NPT_ERROR_TIMEOUT;
+
+        case EADDRINUSE:
+            return NPT_ERROR_ADDRESS_IN_USE;
+
+        case ENETDOWN:
+            return NPT_ERROR_NETWORK_DOWN;
+
+        case ENETUNREACH:
+            return NPT_ERROR_NETWORK_UNREACHABLE;
+
+        case EINPROGRESS:
+        case EAGAIN:
+#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
+        case EWOULDBLOCK:
+#endif
+            return NPT_ERROR_WOULD_BLOCK;
+
+        default:
+            return NPT_FAILURE;
+    }
+}
+
+#if defined(_XBOX)
+
+struct hostent {
+    char    * h_name;           /* official name of host */
+    char    * * h_aliases;      /* alias list */
+    short   h_addrtype;         /* host address type */
+    short   h_length;           /* length of address */
+    char    * * h_addr_list;    /* list of addresses */
+#define h_addr  h_addr_list[0]  /* address, for backward compat */
+};
+
+typedef struct {
+    struct hostent server;
+    char name[128];
+    char addr[16];
+    char* addr_list[4];
+} HostEnt;
+
+/*----------------------------------------------------------------------
+|   gethostbyname
++---------------------------------------------------------------------*/
+static struct hostent* 
+gethostbyname(const char* name)
+{
+    struct hostent* host = NULL;
+    HostEnt*        host_entry = new HostEnt;
+    WSAEVENT        hEvent = WSACreateEvent();
+    XNDNS*          pDns = NULL;
+
+    INT err = XNetDnsLookup(name, hEvent, &pDns);
+    WaitForSingleObject(hEvent, INFINITE);
+    if (pDns) {
+        if (pDns->iStatus == 0) {
+            strcpy(host_entry->name, name);
+            host_entry->addr_list[0] = host_entry->addr;
+            memcpy(host_entry->addr, &(pDns->aina[0].s_addr), 4);
+            host_entry->server.h_name = host_entry->name;
+            host_entry->server.h_aliases = 0;
+            host_entry->server.h_addrtype = AF_INET;
+            host_entry->server.h_length = 4;
+            host_entry->server.h_addr_list = new char*[4];
+
+            host_entry->server.h_addr_list[0] = host_entry->addr_list[0];
+            host_entry->server.h_addr_list[1] = 0;
+
+            host = (struct hostent*)host_entry;
+        }
+        XNetDnsRelease(pDns);
+    }
+    WSACloseEvent(hEvent);
+    return host;
+};
+
+#endif // _XBOX
+
+/*----------------------------------------------------------------------
+|   NPT_IpAddress::ResolveName
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_IpAddress::ResolveName(const char* name, NPT_Timeout)
+{
+    // check parameters
+    if (name == NULL || name[0] == '\0') return NPT_ERROR_HOST_UNKNOWN;
+
+    // handle numerical addrs
+    NPT_IpAddress numerical_address;
+    if (NPT_SUCCEEDED(numerical_address.Parse(name))) {
+        /* the name is a numerical IP addr */
+        return Set(numerical_address.AsLong());
+    }
+
+#if defined(__TCS__)
+    Set(getHostByName(name));
+#elif defined(__PSP__)
+    int rid;
+    char buf[1024];
+    int buflen = sizeof(buf);
+
+    int ret = sceNetResolverCreate(&rid, buf, buflen);
+    if(ret < 0){
+        return NPT_FAILURE;
+    }
+    ret = sceNetResolverStartNtoA(rid, name, &address->sin_addr,
+        RESOLVER_TIMEOUT, RESOLVER_RETRY);
+    if(ret < 0){
+        return NPT_ERROR_HOST_UNKNOWN;
+    }
+    sceNetResolverDelete(rid);
+#else
+    // do a name lookup
+    struct hostent *host_entry = gethostbyname(name);
+    if (host_entry == NULL ||
+        host_entry->h_addrtype != AF_INET) {
+        return NPT_ERROR_HOST_UNKNOWN;
+    }
+    NPT_CopyMemory(m_Address, host_entry->h_addr, 4);
+
+#if defined(_XBOX)
+    delete host_entry;   
+#endif
+
+#endif
+    
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketFd
++---------------------------------------------------------------------*/
+class NPT_BsdSocketFd
+{
+public:
+    // constructors and destructor
+    NPT_BsdSocketFd(SocketFd fd) : 
+      m_SocketFd(fd), 
+      m_Blocking(true),
+      m_ReadTimeout(NPT_TIMEOUT_INFINITE), 
+      m_WriteTimeout(NPT_TIMEOUT_INFINITE),
+      m_Position(0) {
+#if !defined(__WIN32__) && !defined(_XBOX)
+        pipe(m_AbortPipe);
+#endif
+    }
+    ~NPT_BsdSocketFd() {
+#if !defined(__WIN32__) && !defined(_XBOX)
+        close(m_AbortPipe[0]);
+        close(m_AbortPipe[1]);
+        closesocket(m_SocketFd);
+#else
+        Disconnect();
+#endif
+    }
+
+    // methods
+    NPT_Result SetBlockingMode(bool blocking);
+    NPT_Result WaitUntilReadable();
+    NPT_Result WaitUntilWriteable();
+    void Disconnect() {
+        if (!m_SocketFd) return;
+
+#if !defined(__WIN32__) && !defined(_XBOX)
+        write(m_AbortPipe[1], "\0", 1);
+#else
+        // no pipe on win32, but closing the socket will
+        // unblock the socket
+        SocketFd socketFd = m_SocketFd;
+        m_SocketFd = 0;
+        if (socketFd) {
+            closesocket(socketFd);
+        }
+#endif
+    }
+
+    // members
+    SocketFd     m_SocketFd;
+    bool         m_Blocking;
+    NPT_Timeout  m_ReadTimeout;
+    NPT_Timeout  m_WriteTimeout;
+    NPT_Position m_Position;
+
+private:
+    // methods
+    friend class NPT_BsdTcpServerSocket;
+    NPT_Result WaitForCondition(bool readable, bool writeable, NPT_Timeout timeout);
+    
+public:
+    // members
+#if !defined(__WIN32__) && !defined(_XBOX)
+    int m_AbortPipe[2]; /* an array to store the file descriptors of the abort pipe. */
+#endif
+};
+
+typedef NPT_Reference<NPT_BsdSocketFd> NPT_BsdSocketFdReference;
+
+#if defined(__WIN32__) || defined(__TCS__) || defined(_XBOX)
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketFd::SetBlockingMode
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketFd::SetBlockingMode(bool blocking)
+{
+    unsigned long args = blocking?0:1;
+    if (ioctlsocket(m_SocketFd, FIONBIO, &args)) {
+        return NPT_ERROR_SOCKET_CONTROL_FAILED;
+    }
+    m_Blocking = blocking;
+    return NPT_SUCCESS;
+}
+#elif defined(__PSP__) || defined(__PPU__)
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketFd::SetBlockingMode
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketFd::SetBlockingMode(bool blocking)
+{
+    int args = blocking?0:1;
+    if (setsockopt(m_SocketFd, SOL_SOCKET, SO_NBIO, &args, sizeof(args))) {
+        return NPT_ERROR_SOCKET_CONTROL_FAILED;
+    }
+    m_Blocking = blocking;
+    return NPT_SUCCESS;
+}
+#else
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketFd::SetBlockingMode
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketFd::SetBlockingMode(bool blocking)
+{
+    int flags = fcntl(m_SocketFd, F_GETFL, 0);
+    if (blocking) {
+        flags &= ~O_NONBLOCK;
+    } else {
+        flags |= O_NONBLOCK;
+    }
+    if (fcntl(m_SocketFd, F_SETFL, flags)) {
+        return NPT_ERROR_SOCKET_CONTROL_FAILED;
+    }
+    m_Blocking = blocking;
+    return NPT_SUCCESS;
+}
+#endif
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketFd::WaitUntilReadable
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketFd::WaitUntilReadable()
+{
+    return WaitForCondition(true, false, m_ReadTimeout);
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketFd::WaitUntilWriteable
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketFd::WaitUntilWriteable()
+{
+    return WaitForCondition(false, true, m_WriteTimeout);
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketFd::WaitForCondition
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketFd::WaitForCondition(bool        wait_for_readable, 
+                                  bool        wait_for_writeable, 
+                                  NPT_Timeout timeout)
+{
+    // wait for incoming connection
+    NPT_Result result = NPT_SUCCESS;
+    fd_set read_set;
+    fd_set write_set;
+    fd_set except_set;
+    FD_ZERO(&read_set);
+    if (wait_for_readable) FD_SET(m_SocketFd, &read_set);
+    FD_ZERO(&write_set);
+    if (wait_for_writeable) FD_SET(m_SocketFd, &write_set);
+    FD_ZERO(&except_set);
+    FD_SET(m_SocketFd, &except_set);
+
+    struct timeval timeout_value;
+    if (timeout != NPT_TIMEOUT_INFINITE) {
+        timeout_value.tv_sec = timeout/1000;
+        timeout_value.tv_usec = 1000*(timeout-1000*(timeout/1000));
+    };
+    
+    int nfds = (int)m_SocketFd+1;
+
+#if !defined(__WIN32__) && !defined(_XBOX)
+    FD_SET(m_AbortPipe[0], &read_set);
+    nfds = (m_AbortPipe[0]>(int)m_SocketFd?m_AbortPipe[0]:(int)m_SocketFd)+1;
+#endif
+
+    int io_result = select(nfds, 
+                           &read_set, &write_set, &except_set, 
+                           timeout == NPT_TIMEOUT_INFINITE ? 
+                           NULL : &timeout_value);
+
+    if (io_result == 0) {
+        if (timeout == 0) {
+            // non-blocking call
+            result = NPT_ERROR_WOULD_BLOCK;
+        } else {
+            // timeout
+            result = NPT_ERROR_TIMEOUT;
+        }
+    } else if (NPT_BSD_SOCKET_SELECT_FAILED(io_result)) {
+        result = MapErrorCode(GetSocketError());
+    } else if ((wait_for_readable  && FD_ISSET(m_SocketFd, &read_set)) ||
+               (wait_for_writeable && FD_ISSET(m_SocketFd, &write_set))) {
+        result = NPT_SUCCESS;
+    } else if (FD_ISSET(m_SocketFd, &except_set)) {
+        result = MapErrorCode(GetSocketError());
+#if !defined(__WIN32__) && !defined(_XBOX)
+    } else if (FD_ISSET(m_AbortPipe[0], &read_set)) {
+        result = NPT_ERROR_CONNECTION_ABORTED;
+#endif
+    } else {
+        // should not happen
+        result = (m_SocketFd == 0)?NPT_ERROR_EOS:NPT_ERROR_INTERNAL;
+    }
+
+    return result;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketStream
++---------------------------------------------------------------------*/
+class NPT_BsdSocketStream
+{
+ public:
+    // methods
+    NPT_BsdSocketStream(NPT_BsdSocketFdReference& socket_fd) :
+       m_SocketFdReference(socket_fd) {}
+
+    // NPT_InputStream and NPT_OutputStream methods
+    NPT_Result Seek(NPT_Position) { return NPT_ERROR_NOT_SUPPORTED; }
+    NPT_Result Tell(NPT_Position& where) {
+        where = 0;
+        return NPT_SUCCESS;
+    }
+
+ protected:
+    // destructor
+     virtual ~NPT_BsdSocketStream() {}
+
+    // members
+    NPT_BsdSocketFdReference m_SocketFdReference;
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketInputStream
++---------------------------------------------------------------------*/
+class NPT_BsdSocketInputStream : public NPT_InputStream,
+                                 private NPT_BsdSocketStream
+{
+public:
+    // constructors and destructor
+    NPT_BsdSocketInputStream(NPT_BsdSocketFdReference& socket_fd) :
+      NPT_BsdSocketStream(socket_fd) {}
+
+    // NPT_InputStream methods
+    NPT_Result Read(void*     buffer, 
+                    NPT_Size  bytes_to_read, 
+                    NPT_Size* bytes_read);
+    NPT_Result Seek(NPT_Position offset) { 
+        return NPT_BsdSocketStream::Seek(offset); }
+    NPT_Result Tell(NPT_Position& where) {
+        return NPT_BsdSocketStream::Tell(where);
+    }
+    NPT_Result GetSize(NPT_LargeSize& size);
+    NPT_Result GetAvailable(NPT_LargeSize& available);
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketInputStream::Read
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketInputStream::Read(void*     buffer, 
+                               NPT_Size  bytes_to_read, 
+                               NPT_Size* bytes_read)
+{
+    // if we're blocking, wait until the socket is readable
+    if (m_SocketFdReference->m_Blocking && 
+        m_SocketFdReference->m_ReadTimeout != NPT_TIMEOUT_INFINITE) {
+        NPT_Result result = m_SocketFdReference->WaitUntilReadable();
+        if (result != NPT_SUCCESS) return result;
+    }
+
+    // read from the socket
+    ssize_t nb_read = recv(m_SocketFdReference->m_SocketFd, 
+                           (SocketBuffer)buffer, 
+                           bytes_to_read, 0);
+    if (nb_read > 0) {
+        if (bytes_read) *bytes_read = nb_read;
+        m_SocketFdReference->m_Position += nb_read;
+        return NPT_SUCCESS;
+    } else {
+        if (bytes_read) *bytes_read = 0;
+        if (nb_read == 0) {
+            return NPT_ERROR_EOS;
+        } else {
+            return MapErrorCode(GetSocketError());
+        }
+    }
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketInputStream::GetSize
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketInputStream::GetSize(NPT_LargeSize& size)
+{
+    // generic socket streams have no size
+    size = 0;
+    return NPT_ERROR_NOT_SUPPORTED;
+}
+
+#if defined(__PPU__)
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketInputStream::GetAvailable
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketInputStream::GetAvailable(NPT_LargeSize&)
+{
+    return NPT_ERROR_NOT_SUPPORTED;
+}
+#else
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketInputStream::GetAvailable
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketInputStream::GetAvailable(NPT_LargeSize& available)
+{
+    unsigned long ready = 0;
+    int io_result = ioctlsocket(m_SocketFdReference->m_SocketFd, FIONREAD, &ready); 
+    if (NPT_BSD_SOCKET_CALL_FAILED(io_result)) {
+        available = 0;
+        return NPT_ERROR_SOCKET_CONTROL_FAILED;
+    } else {
+        available = ready;
+        return NPT_SUCCESS;
+    }
+}
+#endif
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketOutputStream
++---------------------------------------------------------------------*/
+class NPT_BsdSocketOutputStream : public NPT_OutputStream,
+                                  private NPT_BsdSocketStream
+{
+public:
+    // constructors and destructor
+    NPT_BsdSocketOutputStream(NPT_BsdSocketFdReference& socket_fd) :
+        NPT_BsdSocketStream(socket_fd) {}
+
+    // NPT_OutputStream methods
+    NPT_Result Write(const void* buffer, 
+                     NPT_Size    bytes_to_write, 
+                     NPT_Size*   bytes_written);
+    NPT_Result Seek(NPT_Position offset) { 
+        return NPT_BsdSocketStream::Seek(offset); }
+    NPT_Result Tell(NPT_Position& where) {
+        return NPT_BsdSocketStream::Tell(where);
+    }
+    NPT_Result Flush();
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketOutputStream::Write
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketOutputStream::Write(const void*  buffer, 
+                                 NPT_Size     bytes_to_write, 
+                                 NPT_Size*    bytes_written)
+{
+    // if we're blocking, wait until the socket is writeable
+    if (m_SocketFdReference->m_Blocking && 
+        m_SocketFdReference->m_WriteTimeout != NPT_TIMEOUT_INFINITE) {
+        NPT_Result result = m_SocketFdReference->WaitUntilWriteable();
+        if (result != NPT_SUCCESS) return result;
+    }
+
+    int flags = 0;
+
+    // on some BSD implementations, signal we don't want a SIGPIPE
+    // but instead return EPIPE
+#ifdef MSG_NOSIGNAL
+    flags |= MSG_NOSIGNAL;
+#endif
+
+    // write to the socket
+    ssize_t nb_written = send(m_SocketFdReference->m_SocketFd, 
+                              (SocketConstBuffer)buffer, 
+                              bytes_to_write, flags);
+
+    if (nb_written > 0) {
+        if (bytes_written) *bytes_written = nb_written;
+        m_SocketFdReference->m_Position += nb_written;
+        return NPT_SUCCESS;
+    } else {
+        if (bytes_written) *bytes_written = 0;
+        if (nb_written == 0) {
+            return NPT_ERROR_CONNECTION_RESET;
+        } else {
+            return MapErrorCode(GetSocketError());
+        }
+    }
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocketOutputStream::Flush
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocketOutputStream::Flush()
+{
+    int       args = 0;
+    socklen_t size = sizeof(args);
+
+    // get the value of the nagle algorithm
+    if (getsockopt(m_SocketFdReference->m_SocketFd, 
+                  IPPROTO_TCP, 
+                  TCP_NODELAY, 
+                  (char*)&args, 
+                  &size)) {
+        return NPT_ERROR_GETSOCKOPT_FAILED;
+    }
+
+    // return now if nagle was already off
+    if (args == 1) return NPT_SUCCESS;
+
+    // disable the nagle algorithm
+    args = 1;
+    if (setsockopt(m_SocketFdReference->m_SocketFd, 
+                   IPPROTO_TCP, 
+                   TCP_NODELAY, 
+                   (const char*)&args, 
+                   sizeof(args))) {
+        return NPT_ERROR_SETSOCKOPT_FAILED;
+    }
+
+    // send an empty buffer to flush
+    char dummy;
+    send(m_SocketFdReference->m_SocketFd, &dummy, 0, 0); 
+
+    // restore the nagle algorithm to its original setting
+    args = 0;
+    if (setsockopt(m_SocketFdReference->m_SocketFd, 
+                   IPPROTO_TCP, 
+                   TCP_NODELAY, 
+                   (const char*)&args, 
+                   sizeof(args))) {
+        return NPT_ERROR_SETSOCKOPT_FAILED;
+    }
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket
++---------------------------------------------------------------------*/
+class NPT_BsdSocket : public NPT_SocketInterface
+{
+ public:
+    // constructors and destructor
+             NPT_BsdSocket() {}
+             NPT_BsdSocket(SocketFd fd, bool force_blocking=false);
+    virtual ~NPT_BsdSocket();
+
+    // methods
+    NPT_Result RefreshInfo();
+
+    // NPT_SocketInterface methods
+    NPT_Result Bind(const NPT_SocketAddress& address, bool reuse_address = true);
+    NPT_Result Connect(const NPT_SocketAddress& address, NPT_Timeout timeout);
+    NPT_Result Disconnect();
+    NPT_Result WaitForConnection(NPT_Timeout timeout);
+    NPT_Result GetInputStream(NPT_InputStreamReference& stream);
+    NPT_Result GetOutputStream(NPT_OutputStreamReference& stream);
+    NPT_Result GetInfo(NPT_SocketInfo& info);
+    NPT_Result SetBlockingMode(bool blocking);
+    NPT_Result SetReadTimeout(NPT_Timeout timeout);
+    NPT_Result SetWriteTimeout(NPT_Timeout timeout);
+
+ protected:
+    // members
+    NPT_BsdSocketFdReference m_SocketFdReference;
+    NPT_SocketInfo           m_Info;
+    bool                     m_Blocking;
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::NPT_BsdSocket
++---------------------------------------------------------------------*/
+NPT_BsdSocket::NPT_BsdSocket(SocketFd fd, bool force_blocking) : 
+    m_SocketFdReference(new NPT_BsdSocketFd(fd)),
+    m_Blocking(true)
+{
+    // disable the SIGPIPE signal
+#if defined(SO_NOSIGPIPE)
+    int option = 1;
+    setsockopt(m_SocketFdReference->m_SocketFd, 
+               SOL_SOCKET, 
+               SO_NOSIGPIPE, 
+               (SocketOption)&option, 
+               sizeof(option));
+#elif defined(SIGPIPE)
+    signal(SIGPIPE, SIG_IGN);
+#endif
+
+    if (force_blocking) m_SocketFdReference->SetBlockingMode(true);
+    RefreshInfo();
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::~NPT_BsdSocket
++---------------------------------------------------------------------*/
+NPT_BsdSocket::~NPT_BsdSocket()
+{
+    // release the socket fd reference
+    m_SocketFdReference = NULL;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::Bind
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::Bind(const NPT_SocketAddress& address, bool reuse_address)
+{
+    // on non windows, we need to set reuse address no matter what so
+    // that we can bind on the same port when the socket has closed 
+    // but is still in a timed-out mode
+#if !defined(__WIN32__) && !defined(_XBOX)
+    int option_ra = 1;
+    setsockopt(m_SocketFdReference->m_SocketFd,
+               SOL_SOCKET,
+               SO_REUSEADDR,
+               (SocketOption)&option_ra,
+               sizeof(option_ra));
+#endif
+
+    // set socket options
+    if (reuse_address) {
+        int option = 1;
+        // on macosx/linux, we need to use SO_REUSEPORT instead of SO_REUSEADDR
+#if defined(SO_REUSEPORT)
+        setsockopt(m_SocketFdReference->m_SocketFd, 
+                   SOL_SOCKET, 
+                   SO_REUSEPORT, 
+                   (SocketOption)&option, 
+                   sizeof(option));
+#else
+        setsockopt(m_SocketFdReference->m_SocketFd, 
+                   SOL_SOCKET, 
+                   SO_REUSEADDR, 
+                   (SocketOption)&option, 
+                   sizeof(option));
+#endif
+    }
+    
+    // convert the address
+    struct sockaddr_in inet_address;
+    SocketAddressToInetAddress(address, &inet_address);
+
+#ifdef _XBOX
+    if( address.GetIpAddress().AsLong() != NPT_IpAddress::Any.AsLong() ) {
+        //Xbox can't bind to specific address, defaulting to ANY
+        SocketAddressToInetAddress(NPT_SocketAddress(NPT_IpAddress::Any, address.GetPort()), &inet_address);
+    }
+#endif
+
+    // bind the socket
+    if (bind(m_SocketFdReference->m_SocketFd, 
+             (struct sockaddr*)&inet_address, 
+             sizeof(inet_address)) < 0) {
+        return NPT_ERROR_BIND_FAILED;
+    }
+
+    // refresh socket info
+    RefreshInfo();
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::Connect
++---------------------------------------------------------------------*/
+NPT_Result 
+NPT_BsdSocket::Connect(const NPT_SocketAddress&, NPT_Timeout)
+{
+    // this is unsupported unless overridden in a derived class
+    return NPT_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::Disconnect
++---------------------------------------------------------------------*/
+NPT_Result 
+NPT_BsdSocket::Disconnect()
+{
+    // check that we have a socket
+    if (m_SocketFdReference.IsNull()) return NPT_ERROR_INVALID_STATE;
+
+    m_SocketFdReference->Disconnect();
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::WaitForConnection
++---------------------------------------------------------------------*/
+NPT_Result 
+NPT_BsdSocket::WaitForConnection(NPT_Timeout)
+{
+    // this is unsupported unless overridden in a derived class
+    return NPT_ERROR_NOT_SUPPORTED;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::GetInputStream
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::GetInputStream(NPT_InputStreamReference& stream)
+{
+    // default value
+    stream = NULL;
+
+    // check that we have a socket
+    if (m_SocketFdReference.IsNull()) return NPT_ERROR_INVALID_STATE;
+
+    // create a stream
+    stream = new NPT_BsdSocketInputStream(m_SocketFdReference);
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::GetOutputStream
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::GetOutputStream(NPT_OutputStreamReference& stream)
+{
+    // default value
+    stream = NULL;
+
+    // check that the file is open
+    if (m_SocketFdReference.IsNull()) return NPT_ERROR_INVALID_STATE;
+
+    // create a stream
+    stream = new NPT_BsdSocketOutputStream(m_SocketFdReference);
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::GetInfo
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::GetInfo(NPT_SocketInfo& info)
+{
+    // return the cached info
+    info = m_Info;
+    
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::RefreshInfo
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::RefreshInfo()
+{
+    // check that we have a socket
+    if (m_SocketFdReference.IsNull()) return NPT_ERROR_INVALID_STATE;
+
+    // get the local socket addr
+    struct sockaddr_in inet_address;
+    socklen_t          name_length = sizeof(inet_address);
+    if (getsockname(m_SocketFdReference->m_SocketFd, 
+                    (struct sockaddr*)&inet_address, 
+                    &name_length) == 0) {
+        m_Info.local_address.SetIpAddress(ntohl(inet_address.sin_addr.s_addr));
+        m_Info.local_address.SetPort(ntohs(inet_address.sin_port));
+    }   
+
+    // get the peer socket addr
+    if (getpeername(m_SocketFdReference->m_SocketFd,
+                    (struct sockaddr*)&inet_address, 
+                    &name_length) == 0) {
+        m_Info.remote_address.SetIpAddress(ntohl(inet_address.sin_addr.s_addr));
+        m_Info.remote_address.SetPort(ntohs(inet_address.sin_port));
+    }   
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::SetBlockingMode
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::SetBlockingMode(bool blocking)
+{
+    if (m_Blocking != blocking) {
+        m_SocketFdReference->SetBlockingMode(blocking);
+        m_Blocking = blocking;
+    }
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::SetReadTimeout
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::SetReadTimeout(NPT_Timeout timeout)
+{
+    m_SocketFdReference->m_ReadTimeout = timeout;
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdSocket::SetWriteTimeout
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdSocket::SetWriteTimeout(NPT_Timeout timeout)
+{
+    m_SocketFdReference->m_WriteTimeout = timeout;
+    setsockopt(m_SocketFdReference->m_SocketFd,
+               SOL_SOCKET,
+               SO_SNDTIMEO,
+               (SocketOption)&timeout,
+               sizeof(timeout));
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_Socket::~NPT_Socket
++---------------------------------------------------------------------*/
+NPT_Socket::~NPT_Socket()
+{
+    delete m_SocketDelegate;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpSocket
++---------------------------------------------------------------------*/
+class NPT_BsdUdpSocket : public    NPT_UdpSocketInterface,
+                         protected NPT_BsdSocket
+                         
+{
+ public:
+    // constructor
+     NPT_BsdUdpSocket();
+    virtual ~NPT_BsdUdpSocket() {}
+
+    // NPT_SocketInterface methods
+    NPT_Result Connect(const NPT_SocketAddress& address,
+                       NPT_Timeout              timeout);
+
+    // NPT_UdpSocketInterface methods
+    NPT_Result Send(const NPT_DataBuffer&    packet, 
+                    const NPT_SocketAddress* address);
+    NPT_Result Receive(NPT_DataBuffer&     packet, 
+                       NPT_SocketAddress*  address);
+
+    // friends
+    friend class NPT_UdpSocket;
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpSocket::NPT_BsdUdpSocket
++---------------------------------------------------------------------*/
+NPT_BsdUdpSocket::NPT_BsdUdpSocket() : 
+    NPT_BsdSocket(socket(AF_INET, SOCK_DGRAM, 0))
+{
+    // set default socket options
+    int option = 1;
+    setsockopt(m_SocketFdReference->m_SocketFd, 
+               SOL_SOCKET, 
+               SO_BROADCAST, 
+               (SocketOption)&option, 
+               sizeof(option));
+
+#ifdef _XBOX
+    // set flag on the socket to allow sending of multicast
+    if (!NPT_BSD_SOCKET_IS_INVALID(m_SocketFdReference->m_SocketFd)) {
+        *(DWORD*)((char*)m_SocketFdReference->m_SocketFd+0xc) |= 0x02000000;
+    }
+#endif
+
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpSocket::Connect
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpSocket::Connect(const NPT_SocketAddress& address, 
+                          NPT_Timeout /* ignored */)
+{
+    // setup an address structure
+    struct sockaddr_in inet_address;
+    SocketAddressToInetAddress(address, &inet_address);
+
+    // connect so that we can have some addr bound to the socket
+    int io_result = connect(m_SocketFdReference->m_SocketFd, 
+                            (struct sockaddr *)&inet_address, 
+                            sizeof(inet_address));
+    if (NPT_BSD_SOCKET_CALL_FAILED(io_result)) { 
+        return MapErrorCode(GetSocketError());
+    }
+    
+    // refresh socket info
+    RefreshInfo();
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpSocket::Send
++---------------------------------------------------------------------*/
+NPT_Result 
+NPT_BsdUdpSocket::Send(const NPT_DataBuffer&    packet, 
+                       const NPT_SocketAddress* address) 
+{
+    // get the packet buffer
+    const NPT_Byte* buffer        = packet.GetData();
+    ssize_t         buffer_length = packet.GetDataSize();
+
+    // if we're blocking, wait until the socket is writeable
+    if (m_SocketFdReference->m_Blocking && 
+        m_SocketFdReference->m_WriteTimeout != NPT_TIMEOUT_INFINITE) {
+        NPT_Result result = m_SocketFdReference->WaitUntilWriteable();
+        if (result != NPT_SUCCESS) return result;
+    }
+
+    // send the packet buffer
+    int io_result;
+    if (address) {
+        // send to the specified address
+
+        // setup an address structure
+        struct sockaddr_in inet_address;
+        SocketAddressToInetAddress(*address, &inet_address);
+        io_result = sendto(m_SocketFdReference->m_SocketFd, 
+                           (SocketConstBuffer)buffer, 
+                           buffer_length, 
+                           0, 
+                           (struct sockaddr *)&inet_address, 
+                           sizeof(inet_address));
+    } else {
+        // send to whichever addr the socket is connected
+        io_result = send(m_SocketFdReference->m_SocketFd, 
+                         (SocketConstBuffer)buffer, 
+                         buffer_length,
+                         0);
+    }
+
+    // check result
+    if (NPT_BSD_SOCKET_CALL_FAILED(io_result)) {
+        return MapErrorCode(GetSocketError());
+    }
+
+    m_SocketFdReference->m_Position += buffer_length;
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpSocket::Receive
++---------------------------------------------------------------------*/
+NPT_Result 
+NPT_BsdUdpSocket::Receive(NPT_DataBuffer&    packet, 
+                          NPT_SocketAddress* address)
+{
+    // get the packet buffer
+    NPT_Byte* buffer      = packet.UseData();
+    ssize_t   buffer_size = packet.GetBufferSize();
+
+    // check that we have some space to receive
+    if (buffer_size == 0) {
+        return NPT_ERROR_INVALID_PARAMETERS;
+    }
+
+    // if we're blocking, wait until the socket is readable
+    if (m_SocketFdReference->m_Blocking && 
+        m_SocketFdReference->m_ReadTimeout != NPT_TIMEOUT_INFINITE) {
+        NPT_Result result = m_SocketFdReference->WaitUntilReadable();
+        if (result != NPT_SUCCESS) return result;
+    }
+
+    // receive a packet
+    int io_result;
+    if (address) {
+        struct sockaddr_in inet_address;
+        socklen_t          inet_address_length = sizeof(inet_address);
+        io_result = recvfrom(m_SocketFdReference->m_SocketFd, 
+                             (SocketBuffer)buffer, 
+                             buffer_size, 
+                             0, 
+                             (struct sockaddr *)&inet_address, 
+                             &inet_address_length);
+
+        // convert the address format
+        if (!NPT_BSD_SOCKET_CALL_FAILED(io_result)) {
+            if (inet_address_length == sizeof(inet_address)) {
+                InetAddressToSocketAddress(&inet_address, *address);
+            }
+        }
+    } else {
+        io_result = recv(m_SocketFdReference->m_SocketFd,
+                         (SocketBuffer)buffer,
+                         buffer_size,
+                         0);
+    }
+
+    // check result
+    if (NPT_BSD_SOCKET_CALL_FAILED(io_result)) {
+        packet.SetDataSize(0);
+        return MapErrorCode(GetSocketError());
+    } 
+
+    packet.SetDataSize(io_result);
+    m_SocketFdReference->m_Position += io_result;
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_UdpSocket::NPT_UdpSocket
++---------------------------------------------------------------------*/
+NPT_UdpSocket::NPT_UdpSocket()
+{
+    NPT_BsdUdpSocket* delegate = new NPT_BsdUdpSocket();
+    m_SocketDelegate    = delegate;
+    m_UdpSocketDelegate = delegate;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_UdpSocket::NPT_UdpSocket
++---------------------------------------------------------------------*/
+NPT_UdpSocket::NPT_UdpSocket(NPT_UdpSocketInterface* delegate) :
+    m_UdpSocketDelegate(delegate)
+{
+}
+
+/*----------------------------------------------------------------------
+|   NPT_UdpSocket::~NPT_UdpSocket
++---------------------------------------------------------------------*/
+NPT_UdpSocket::~NPT_UdpSocket()
+{
+    delete m_UdpSocketDelegate;
+
+    // set the delegate pointers to NULL because it is shared by the
+    // base classes, and we only want to delete the object once
+    m_UdpSocketDelegate = NULL;
+    m_SocketDelegate    = NULL;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket
++---------------------------------------------------------------------*/
+class NPT_BsdUdpMulticastSocket : public    NPT_UdpMulticastSocketInterface,
+                                  protected NPT_BsdUdpSocket
+                                  
+{
+ public:
+    // methods
+     NPT_BsdUdpMulticastSocket();
+    ~NPT_BsdUdpMulticastSocket();
+
+    // NPT_UdpMulticastSocketInterface methods
+    NPT_Result JoinGroup(const NPT_IpAddress& group,
+                         const NPT_IpAddress& iface);
+    NPT_Result LeaveGroup(const NPT_IpAddress& group,
+                          const NPT_IpAddress& iface);
+    NPT_Result SetTimeToLive(unsigned char ttl);
+    NPT_Result SetInterface(const NPT_IpAddress& iface);
+
+    // friends 
+    friend class NPT_UdpMulticastSocket;
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::NPT_BsdUdpMulticastSocket
++---------------------------------------------------------------------*/
+NPT_BsdUdpMulticastSocket::NPT_BsdUdpMulticastSocket()
+{
+#ifndef _XBOX
+        int option = 1;
+        setsockopt(m_SocketFdReference->m_SocketFd, 
+                   IPPROTO_IP, 
+                   IP_MULTICAST_LOOP,
+                   (SocketOption)&option,
+                   sizeof(option));
+#endif
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::~NPT_BsdUdpMulticastSocket
++---------------------------------------------------------------------*/
+NPT_BsdUdpMulticastSocket::~NPT_BsdUdpMulticastSocket()
+{
+}
+
+#if defined(_XBOX)
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::JoinGroup
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::JoinGroup(const NPT_IpAddress& group,
+                                     const NPT_IpAddress& iface)
+{
+    return NPT_SUCCESS;
+}
+#else
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::JoinGroup
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::JoinGroup(const NPT_IpAddress& group,
+                                     const NPT_IpAddress& iface)
+{
+    struct ip_mreq mreq;
+
+    // set the interface address
+    mreq.imr_interface.s_addr = htonl(iface.AsLong());
+
+    // set the group address
+    mreq.imr_multiaddr.s_addr = htonl(group.AsLong());
+
+    // set socket option
+    int io_result = setsockopt(m_SocketFdReference->m_SocketFd, 
+                               IPPROTO_IP, IP_ADD_MEMBERSHIP, 
+                               (SocketOption)&mreq, sizeof(mreq));
+    if (io_result == 0) {
+        return NPT_SUCCESS;
+    } else {
+        return MapErrorCode(GetSocketError());
+    }
+}
+#endif
+
+#if defined(_XBOX)
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::LeaveGroup
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::LeaveGroup(const NPT_IpAddress& group,
+                                      const NPT_IpAddress& iface)
+{
+    return NPT_SUCCESS;
+}
+#else
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::LeaveGroup
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::LeaveGroup(const NPT_IpAddress& group,
+                                      const NPT_IpAddress& iface)
+{
+    struct ip_mreq mreq;
+
+    // set the interface address
+    mreq.imr_interface.s_addr = htonl(iface.AsLong());
+
+    // set the group address
+    mreq.imr_multiaddr.s_addr = htonl(group.AsLong());
+
+    // set socket option
+    int io_result = setsockopt(m_SocketFdReference->m_SocketFd, 
+                               IPPROTO_IP, IP_DROP_MEMBERSHIP, 
+                               (SocketOption)&mreq, sizeof(mreq));
+    if (io_result == 0) {
+        return NPT_SUCCESS;
+    } else {
+        return MapErrorCode(GetSocketError());
+    }
+}
+#endif
+
+#if defined(_XBOX)
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::SetInterface
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::SetInterface(const NPT_IpAddress& iface)
+{
+    return NPT_SUCCESS;
+}
+#else
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::SetInterface
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::SetInterface(const NPT_IpAddress& iface)
+{
+    struct in_addr iface_addr;
+    // set the interface address
+    iface_addr.s_addr = htonl(iface.AsLong());
+
+    // set socket option
+    int io_result = setsockopt(m_SocketFdReference->m_SocketFd, 
+                               IPPROTO_IP, IP_MULTICAST_IF, 
+                               (char*)&iface_addr, sizeof(iface_addr));
+    if (io_result == 0) {
+        return NPT_SUCCESS;
+    } else {
+        return MapErrorCode(GetSocketError());
+    }
+}
+#endif
+
+#if defined(_XBOX)
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::SetTimeToLive
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::SetTimeToLive(unsigned char ttl)
+{
+    return NPT_ERROR_NOT_IMPLEMENTED;
+}
+#else
+/*----------------------------------------------------------------------
+|   NPT_BsdUdpMulticastSocket::SetTimeToLive
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdUdpMulticastSocket::SetTimeToLive(unsigned char ttl)
+{
+    unsigned char ttl_opt = ttl;
+
+    // set socket option
+    int io_result = setsockopt(m_SocketFdReference->m_SocketFd, 
+                               IPPROTO_IP, IP_MULTICAST_TTL, 
+                               (SocketOption)&ttl_opt, sizeof(ttl_opt));
+    if (io_result == 0) {
+        return NPT_SUCCESS;
+    } else {
+        return MapErrorCode(GetSocketError());
+    }
+}
+#endif
+
+/*----------------------------------------------------------------------
+|   NPT_UdpMulticastSocket::NPT_UdpMulticastSocket
++---------------------------------------------------------------------*/
+NPT_UdpMulticastSocket::NPT_UdpMulticastSocket() :
+    NPT_UdpSocket(NULL)
+{
+    NPT_BsdUdpMulticastSocket* delegate = new NPT_BsdUdpMulticastSocket();
+    m_SocketDelegate             = delegate;
+    m_UdpSocketDelegate          = delegate;
+    m_UdpMulticastSocketDelegate = delegate;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_UdpMulticastSocket::~NPT_UdpMulticastSocket
++---------------------------------------------------------------------*/
+NPT_UdpMulticastSocket::~NPT_UdpMulticastSocket()
+{
+    delete m_UdpMulticastSocketDelegate;
+
+    // set the delegate pointers to NULL because it is shared by the
+    // base classes, and we only want to delete the object once
+    m_SocketDelegate             = NULL;
+    m_UdpSocketDelegate          = NULL;
+    m_UdpMulticastSocketDelegate = NULL;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpClientSocket
++---------------------------------------------------------------------*/
+class NPT_BsdTcpClientSocket : protected NPT_BsdSocket
+{
+ public:
+    // methods
+     NPT_BsdTcpClientSocket();
+    ~NPT_BsdTcpClientSocket();
+
+    // NPT_SocketInterface methods
+    NPT_Result Connect(const NPT_SocketAddress& address,
+                       NPT_Timeout              timeout);
+    NPT_Result WaitForConnection(NPT_Timeout timeout);
+
+protected:
+    // methods
+    NPT_Result DoWaitForConnection(NPT_Timeout timeout);
+
+    // friends
+    friend class NPT_TcpClientSocket;
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpClientSocket::NPT_BsdTcpClientSocket
++---------------------------------------------------------------------*/
+NPT_BsdTcpClientSocket::NPT_BsdTcpClientSocket() : 
+    NPT_BsdSocket(socket(AF_INET, SOCK_STREAM, 0))
+{
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpClientSocket::~NPT_BsdTcpClientSocket
++---------------------------------------------------------------------*/
+NPT_BsdTcpClientSocket::~NPT_BsdTcpClientSocket()
+{
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpClientSocket::Connect
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdTcpClientSocket::Connect(const NPT_SocketAddress& address, 
+                                NPT_Timeout              timeout)
+{
+    bool was_blocking = m_Blocking;
+
+    // set the socket to nonblocking so that we can timeout on connect
+    if (m_Blocking) {
+        NPT_CHECK(m_SocketFdReference->SetBlockingMode(false));
+    }
+
+    // convert the address
+    struct sockaddr_in inet_address;
+    SocketAddressToInetAddress(address, &inet_address);
+
+    // initiate connection
+    int io_result;
+    io_result = connect(m_SocketFdReference->m_SocketFd, 
+                        (struct sockaddr *)&inet_address, 
+                        sizeof(inet_address));
+    if (io_result == 0) {
+        // immediate connection
+
+        // put the fd back in its original blocking mode
+        if (was_blocking) m_SocketFdReference->SetBlockingMode(true);
+
+        // get socket info
+        RefreshInfo();
+
+        return NPT_SUCCESS;
+    }
+
+    NPT_Result result = MapErrorCode(GetSocketError());
+    
+    if (was_blocking) {
+        // put the fd back in its original blocking mode
+        m_SocketFdReference->SetBlockingMode(true);
+
+        // wait for the connection to be done
+        if (result == NPT_ERROR_WOULD_BLOCK) return DoWaitForConnection(timeout);
+    }
+
+    return result;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpClientSocket::WaitForConnection
++---------------------------------------------------------------------*/
+NPT_Result 
+NPT_BsdTcpClientSocket::WaitForConnection(NPT_Timeout timeout)
+{
+    // this function can only be called directly for non-blocking sockets
+    if (m_Blocking) return NPT_ERROR_INVALID_STATE;
+
+    return DoWaitForConnection(timeout);
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpClientSocket::DoWaitForConnection
++---------------------------------------------------------------------*/
+NPT_Result 
+NPT_BsdTcpClientSocket::DoWaitForConnection(NPT_Timeout timeout)
+{
+    SocketFd   socket_fd = m_SocketFdReference->m_SocketFd;
+    NPT_Result result = NPT_SUCCESS;
+
+    // wait for connection to succeed or fail
+    fd_set read_set;
+    fd_set write_set;
+    fd_set except_set;
+    FD_ZERO(&read_set);
+    FD_SET(socket_fd, &read_set);
+    FD_ZERO(&write_set);
+    FD_SET(socket_fd, &write_set);
+    FD_ZERO(&except_set);
+    FD_SET(socket_fd, &except_set);
+
+    struct timeval timeout_value;
+    if (timeout != NPT_TIMEOUT_INFINITE) {
+        timeout_value.tv_sec = timeout/1000;
+        timeout_value.tv_usec = 1000*(timeout-1000*(timeout/1000));
+    };
+    
+    int nfds = (int)socket_fd+1;
+
+#if !defined(__WIN32__) && !defined(_XBOX)
+    FD_SET(m_SocketFdReference->m_AbortPipe[0], &read_set);
+    nfds = (m_SocketFdReference->m_AbortPipe[0]>(int)socket_fd?m_SocketFdReference->m_AbortPipe[0]:(int)socket_fd)+1;
+#endif
+
+    int io_result = select(nfds, 
+                           &read_set, &write_set, &except_set, 
+                           timeout == NPT_TIMEOUT_INFINITE ? 
+                           NULL : &timeout_value);
+
+    if (io_result == 0) {
+        if (timeout == 0) {
+            // non-blocking call
+            return NPT_ERROR_WOULD_BLOCK;
+        } else {
+            // timeout
+            return NPT_ERROR_TIMEOUT;
+        }
+    } else if (NPT_BSD_SOCKET_SELECT_FAILED(io_result)) {
+        return MapErrorCode(GetSocketError());
+    } else if (FD_ISSET(socket_fd, &read_set)   || 
+               FD_ISSET(socket_fd, &write_set)  ||
+               FD_ISSET(socket_fd, &except_set)) {
+#if defined(_XBOX)
+        if (FD_ISSET(socket_fd, &except_set)) return MapErrorCode(GetSocketError());
+#else
+        // get error status from socket
+        // (some systems return the error in errno, others
+        //  return it in the buffer passed to getsockopt)
+        int error = 0;
+        socklen_t length = sizeof(error);
+        io_result = getsockopt(socket_fd, 
+                               SOL_SOCKET, 
+                               SO_ERROR, 
+                               (SocketOption)&error, 
+                               &length);
+        if (NPT_BSD_SOCKET_CALL_FAILED(io_result)) {
+            return MapErrorCode(GetSocketError());
+        } else if (error) {
+            return MapErrorCode(error);
+        }
+#endif
+#if !defined(__WIN32__) && !defined(_XBOX)
+    } else if (FD_ISSET(m_SocketFdReference->m_AbortPipe[0], &read_set)) {
+        result = NPT_ERROR_CONNECTION_ABORTED;
+#endif
+    } else {
+        // should not happen
+        result = (socket_fd == 0)?NPT_ERROR_EOS:NPT_ERROR_INTERNAL;
+    }
+
+    
+    // get socket info
+    RefreshInfo();
+
+    return result;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_TcpClientSocket::NPT_TcpClientSocket
++---------------------------------------------------------------------*/
+NPT_TcpClientSocket::NPT_TcpClientSocket() :
+    NPT_Socket(new NPT_BsdTcpClientSocket())
+{
+}
+
+/*----------------------------------------------------------------------
+|   NPT_TcpClientSocket::NPT_TcpClientSocket
++---------------------------------------------------------------------*/
+NPT_TcpClientSocket::~NPT_TcpClientSocket()
+{
+    delete m_SocketDelegate;
+
+    // set the delegate pointer to NULL because it is shared by the
+    // base classes, and we only want to delete the object once
+    m_SocketDelegate = NULL;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpServerSocket
++---------------------------------------------------------------------*/
+class NPT_BsdTcpServerSocket : public    NPT_TcpServerSocketInterface,
+                               protected NPT_BsdSocket
+                               
+{
+ public:
+    // methods
+     NPT_BsdTcpServerSocket();
+    ~NPT_BsdTcpServerSocket();
+
+    // NPT_SocketInterface methods
+    NPT_Result Bind(const NPT_SocketAddress& address, bool reuse_address = true) {
+        // inherit
+        return NPT_BsdSocket::Bind(address, reuse_address);
+    }
+    NPT_Result Connect(const NPT_SocketAddress& address,
+                       NPT_Timeout              timeout) {
+        // inherit
+        return NPT_BsdSocket::Connect(address, timeout);
+    }
+    NPT_Result GetInputStream(NPT_InputStreamReference& stream) {
+        // no stream
+        stream = NULL;
+        return NPT_ERROR_NOT_SUPPORTED;
+    }
+    NPT_Result GetOutputStream(NPT_OutputStreamReference& stream) {
+        // no stream
+        stream = NULL;
+        return NPT_ERROR_NOT_SUPPORTED;
+    }
+    NPT_Result GetInfo(NPT_SocketInfo& info) {
+        // inherit
+        return NPT_BsdSocket::GetInfo(info);
+    }
+
+    // NPT_TcpServerSocket methods
+    NPT_Result Listen(unsigned int max_clients);
+    NPT_Result WaitForNewClient(NPT_Socket*& client, NPT_Timeout timeout);
+
+protected:
+    // members
+    unsigned int m_ListenMax;
+
+    // friends
+    friend class NPT_TcpServerSocket;
+};
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpServerSocket::NPT_BsdTcpServerSocket
++---------------------------------------------------------------------*/
+NPT_BsdTcpServerSocket::NPT_BsdTcpServerSocket() : 
+    NPT_BsdSocket(socket(AF_INET, SOCK_STREAM, 0)),
+    m_ListenMax(0)
+{
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpServerSocket::~NPT_BsdTcpServerSocket
++---------------------------------------------------------------------*/
+NPT_BsdTcpServerSocket::~NPT_BsdTcpServerSocket()
+{
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpServerSocket::Listen
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdTcpServerSocket::Listen(unsigned int max_clients)
+{
+    // listen for connections
+    if (listen(m_SocketFdReference->m_SocketFd, max_clients) < 0) {
+        m_ListenMax = 0;
+        return NPT_ERROR_LISTEN_FAILED;
+    }   
+    m_ListenMax = max_clients;
+
+    return NPT_SUCCESS;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_BsdTcpServerSocket::WaitForNewClient
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_BsdTcpServerSocket::WaitForNewClient(NPT_Socket*& client, 
+                                         NPT_Timeout  timeout)
+{
+    // default value
+    client = NULL;
+
+    // check that we are listening for clients
+    if (m_ListenMax == 0) {
+        Listen(NPT_TCP_SERVER_SOCKET_DEFAULT_LISTEN_COUNT);
+    }
+
+    // set the socket to nonblocking so that we can timeout on accept
+    bool was_blocking = m_Blocking;
+    if (m_Blocking) {
+        NPT_CHECK(m_SocketFdReference->SetBlockingMode(false));
+    }
+
+    NPT_Result result = m_SocketFdReference->WaitForCondition(true, true, timeout);
+    if (result != NPT_SUCCESS) return result;
+
+    struct sockaddr_in inet_address;
+    socklen_t          namelen = sizeof(inet_address);
+    SocketFd socket_fd = accept(m_SocketFdReference->m_SocketFd, (struct sockaddr*)&inet_address, &namelen); 
+    if (NPT_BSD_SOCKET_IS_INVALID(socket_fd)) {
+        result = MapErrorCode(GetSocketError());
+    } else {
+        client = new NPT_Socket(new NPT_BsdSocket(socket_fd, m_Blocking));
+    }
+
+    if (was_blocking) {
+        // put the fd back in its original blocking mode
+        m_SocketFdReference->SetBlockingMode(true);
+    }
+
+    // done
+    return result;    
+}
+
+/*----------------------------------------------------------------------
+|   NPT_TcpServerSocket::NPT_TcpServerSocket
++---------------------------------------------------------------------*/
+NPT_TcpServerSocket::NPT_TcpServerSocket()
+{
+    NPT_BsdTcpServerSocket* delegate = new NPT_BsdTcpServerSocket();
+    m_SocketDelegate          = delegate;
+    m_TcpServerSocketDelegate = delegate;
+}
+
+/*----------------------------------------------------------------------
+|   NPT_TcpServerSocket::NPT_TcpServerSocket
++---------------------------------------------------------------------*/
+NPT_TcpServerSocket::~NPT_TcpServerSocket()
+{
+    delete m_TcpServerSocketDelegate;
+
+    // set the delegate pointers to NULL because it is shared by the
+    // base classes, and we only want to delete the object once
+    m_SocketDelegate          = NULL;
+    m_TcpServerSocketDelegate = NULL;
+}