oleaut32: Improved ICreateTypeInfo2_SetFuncAndParamNames implementation.
[wine] / dlls / ws2_32 / socket.c
index e44b2e3..1af90b1 100644 (file)
 # define HAVE_IPX
 #endif
 
+#ifdef HAVE_LINUX_IRDA_H
+# ifdef HAVE_LINUX_TYPES_H
+#  include <linux/types.h>
+# endif
+# include <linux/irda.h>
+# define HAVE_IRDA
+#endif
+
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
 #include "ws2spi.h"
 #include "wsipx.h"
 #include "mstcpip.h"
+#include "af_irda.h"
 #include "winnt.h"
 #include "iphlpapi.h"
 #include "wine/server.h"
 #include "wine/debug.h"
+#include "wine/exception.h"
 #include "wine/unicode.h"
 
 #ifdef HAVE_IPX
 #endif
 
 WINE_DEFAULT_DEBUG_CHANNEL(winsock);
+WINE_DECLARE_DEBUG_CHANNEL(winediag);
 
 /* critical section to protect some non-reentrant net function */
-extern CRITICAL_SECTION csWSgetXXXbyYYY;
+static CRITICAL_SECTION csWSgetXXXbyYYY;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+    0, 0, &csWSgetXXXbyYYY,
+    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": csWSgetXXXbyYYY") }
+};
+static CRITICAL_SECTION csWSgetXXXbyYYY = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 union generic_unix_sockaddr
 {
@@ -170,10 +188,37 @@ union generic_unix_sockaddr
 static inline const char *debugstr_sockaddr( const struct WS_sockaddr *a )
 {
     if (!a) return "(nil)";
-    return wine_dbg_sprintf("{ family %d, address %s, port %d }",
-                            ((const struct sockaddr_in *)a)->sin_family,
-                            inet_ntoa(((const struct sockaddr_in *)a)->sin_addr),
-                            ntohs(((const struct sockaddr_in *)a)->sin_port));
+    switch (a->sa_family)
+    {
+    case WS_AF_INET:
+        return wine_dbg_sprintf("{ family AF_INET, address %s, port %d }",
+                                inet_ntoa(((const struct sockaddr_in *)a)->sin_addr),
+                                ntohs(((const struct sockaddr_in *)a)->sin_port));
+    case WS_AF_INET6:
+    {
+        char buf[46];
+        const char *p;
+        struct WS_sockaddr_in6 *sin = (struct WS_sockaddr_in6 *)a;
+
+        p = WS_inet_ntop( WS_AF_INET6, &sin->sin6_addr, buf, sizeof(buf) );
+        if (!p)
+            p = "(unknown IPv6 address)";
+        return wine_dbg_sprintf("{ family AF_INET6, address %s, port %d }",
+                                p, ntohs(sin->sin6_port));
+    }
+    case WS_AF_IRDA:
+    {
+        DWORD addr;
+
+        memcpy( &addr, ((const SOCKADDR_IRDA *)a)->irdaDeviceID, sizeof(addr) );
+        addr = ntohl( addr );
+        return wine_dbg_sprintf("{ family AF_IRDA, addr %08x, name %s }",
+                                addr,
+                                ((const SOCKADDR_IRDA *)a)->irdaServiceName);
+    }
+    default:
+        return wine_dbg_sprintf("{ family %d }", a->sa_family);
+    }
 }
 
 /* HANDLE<->SOCKET conversion (SOCKET is UINT_PTR). */
@@ -234,10 +279,18 @@ struct per_thread_data
     int pe_len;
 };
 
+/* internal: routing description information */
+struct route {
+    struct in_addr addr;
+    DWORD interface;
+    DWORD metric;
+};
+
 static INT num_startup;          /* reference counter */
 static FARPROC blocking_hook = (FARPROC)WSA_DefaultBlockingHook;
 
 /* function prototypes */
+static struct WS_hostent *WS_create_he(char *name, int aliases, int addresses, int fill_addresses);
 static struct WS_hostent *WS_dup_he(const struct hostent* p_he);
 static struct WS_protoent *WS_dup_pe(const struct protoent* p_pe);
 static struct WS_servent *WS_dup_se(const struct servent* p_se);
@@ -245,9 +298,6 @@ static struct WS_servent *WS_dup_se(const struct servent* p_se);
 int WSAIOCTL_GetInterfaceCount(void);
 int WSAIOCTL_GetInterfaceName(int intNumber, char *intName);
 
-UINT wsaErrno(void);
-UINT wsaHerrno(int errnr);
-
 #define MAP_OPTION(opt) { WS_##opt, opt }
 
 static const int ws_sock_map[][2] =
@@ -301,6 +351,9 @@ static const int ws_af_map[][2] =
     MAP_OPTION( AF_INET6 ),
 #ifdef HAVE_IPX
     MAP_OPTION( AF_IPX ),
+#endif
+#ifdef AF_IRDA
+    MAP_OPTION( AF_IRDA ),
 #endif
     {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
 };
@@ -369,6 +422,99 @@ static const int ws_eai_map[][2] =
 
 static const char magic_loopback_addr[] = {127, 12, 34, 56};
 
+/* ----------------------------------- error handling */
+
+static UINT wsaErrno(void)
+{
+    int        loc_errno = errno;
+    WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
+
+    switch(loc_errno)
+    {
+       case EINTR:             return WSAEINTR;
+       case EBADF:             return WSAEBADF;
+       case EPERM:
+       case EACCES:            return WSAEACCES;
+       case EFAULT:            return WSAEFAULT;
+       case EINVAL:            return WSAEINVAL;
+       case EMFILE:            return WSAEMFILE;
+       case EWOULDBLOCK:       return WSAEWOULDBLOCK;
+       case EINPROGRESS:       return WSAEINPROGRESS;
+       case EALREADY:          return WSAEALREADY;
+       case ENOTSOCK:          return WSAENOTSOCK;
+       case EDESTADDRREQ:      return WSAEDESTADDRREQ;
+       case EMSGSIZE:          return WSAEMSGSIZE;
+       case EPROTOTYPE:        return WSAEPROTOTYPE;
+       case ENOPROTOOPT:       return WSAENOPROTOOPT;
+       case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
+       case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
+       case EOPNOTSUPP:        return WSAEOPNOTSUPP;
+       case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
+       case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
+       case EADDRINUSE:        return WSAEADDRINUSE;
+       case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
+       case ENETDOWN:          return WSAENETDOWN;
+       case ENETUNREACH:       return WSAENETUNREACH;
+       case ENETRESET:         return WSAENETRESET;
+       case ECONNABORTED:      return WSAECONNABORTED;
+       case EPIPE:
+       case ECONNRESET:        return WSAECONNRESET;
+       case ENOBUFS:           return WSAENOBUFS;
+       case EISCONN:           return WSAEISCONN;
+       case ENOTCONN:          return WSAENOTCONN;
+       case ESHUTDOWN:         return WSAESHUTDOWN;
+       case ETOOMANYREFS:      return WSAETOOMANYREFS;
+       case ETIMEDOUT:         return WSAETIMEDOUT;
+       case ECONNREFUSED:      return WSAECONNREFUSED;
+       case ELOOP:             return WSAELOOP;
+       case ENAMETOOLONG:      return WSAENAMETOOLONG;
+       case EHOSTDOWN:         return WSAEHOSTDOWN;
+       case EHOSTUNREACH:      return WSAEHOSTUNREACH;
+       case ENOTEMPTY:         return WSAENOTEMPTY;
+#ifdef EPROCLIM
+       case EPROCLIM:          return WSAEPROCLIM;
+#endif
+#ifdef EUSERS
+       case EUSERS:            return WSAEUSERS;
+#endif
+#ifdef EDQUOT
+       case EDQUOT:            return WSAEDQUOT;
+#endif
+#ifdef ESTALE
+       case ESTALE:            return WSAESTALE;
+#endif
+#ifdef EREMOTE
+       case EREMOTE:           return WSAEREMOTE;
+#endif
+
+       /* just in case we ever get here and there are no problems */
+       case 0:                 return 0;
+        default:
+               WARN("Unknown errno %d!\n", loc_errno);
+               return WSAEOPNOTSUPP;
+    }
+}
+
+static UINT wsaHerrno(int loc_errno)
+{
+
+    WARN("h_errno %d.\n", loc_errno);
+
+    switch(loc_errno)
+    {
+       case HOST_NOT_FOUND:    return WSAHOST_NOT_FOUND;
+       case TRY_AGAIN:         return WSATRY_AGAIN;
+       case NO_RECOVERY:       return WSANO_RECOVERY;
+       case NO_DATA:           return WSANO_DATA;
+       case ENOBUFS:           return WSAENOBUFS;
+
+       case 0:                 return 0;
+        default:
+               WARN("Unknown h_errno %d!\n", loc_errno);
+               return WSAEOPNOTSUPP;
+    }
+}
+
 static inline DWORD NtStatusToWSAError( const DWORD status )
 {
     /* We only need to cover the status codes set by server async request handling */
@@ -776,7 +922,6 @@ INT WINAPI WSACleanup(void)
 
 
 /***********************************************************************
- *      WSAGetLastError                (WINSOCK.111)
  *      WSAGetLastError                (WS2_32.111)
  */
 INT WINAPI WSAGetLastError(void)
@@ -832,11 +977,25 @@ static struct WS_protoent *check_buffer_pe(int size)
 
 /* ----------------------------------- i/o APIs */
 
+static inline BOOL supported_pf(int pf)
+{
+    switch (pf)
+    {
+    case WS_AF_INET:
+    case WS_AF_INET6:
+        return TRUE;
 #ifdef HAVE_IPX
-#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET || (pf)== WS_AF_IPX || (pf) == WS_AF_INET6)
-#else
-#define SUPPORTED_PF(pf) ((pf)==WS_AF_INET || (pf) == WS_AF_INET6)
+    case WS_AF_IPX:
+        return TRUE;
+#endif
+#ifdef HAVE_IRDA
+    case WS_AF_IRDA:
+        return TRUE;
 #endif
+    default:
+        return FALSE;
+    }
+}
 
 
 /**********************************************************************/
@@ -909,6 +1068,32 @@ static unsigned int ws_sockaddr_ws2u(const struct WS_sockaddr* wsaddr, int wsadd
         memcpy(&uin->sin_addr,&win->sin_addr,4); /* 4 bytes = 32 address bits */
         break;
     }
+#ifdef HAVE_IRDA
+    case WS_AF_IRDA: {
+        struct sockaddr_irda *uin = (struct sockaddr_irda *)uaddr;
+        const SOCKADDR_IRDA *win = (const SOCKADDR_IRDA *)wsaddr;
+
+        if (wsaddrlen < sizeof(SOCKADDR_IRDA))
+            return 0;
+        uaddrlen = sizeof(struct sockaddr_irda);
+        memset( uaddr, 0, uaddrlen );
+        uin->sir_family = AF_IRDA;
+        if (!strncmp( win->irdaServiceName, "LSAP-SEL", strlen( "LSAP-SEL" ) ))
+        {
+            unsigned int lsap_sel;
+
+            sscanf( win->irdaServiceName, "LSAP-SEL%u", &lsap_sel );
+            uin->sir_lsap_sel = lsap_sel;
+        }
+        else
+        {
+            uin->sir_lsap_sel = LSAP_ANY;
+            memcpy( uin->sir_name, win->irdaServiceName, 25 );
+        }
+        memcpy( &uin->sir_addr, win->irdaDeviceID, sizeof(uin->sir_addr) );
+        break;
+    }
+#endif
     case WS_AF_UNSPEC: {
         /* Try to determine the needed space by the passed windows sockaddr space */
         switch (wsaddrlen) {
@@ -920,6 +1105,11 @@ static unsigned int ws_sockaddr_ws2u(const struct WS_sockaddr* wsaddr, int wsadd
         case sizeof(struct WS_sockaddr_ipx):
             uaddrlen = sizeof(struct sockaddr_ipx);
             break;
+#endif
+#ifdef HAVE_IRDA
+        case sizeof(SOCKADDR_IRDA):
+            uaddrlen = sizeof(struct sockaddr_irda);
+            break;
 #endif
         case sizeof(struct WS_sockaddr_in6):
         case sizeof(struct WS_sockaddr_in6_old):
@@ -1011,6 +1201,23 @@ static int ws_sockaddr_u2ws(const struct sockaddr* uaddr, struct WS_sockaddr* ws
             }
         }
         break;
+#endif
+#ifdef HAVE_IRDA
+    case AF_IRDA: {
+        const struct sockaddr_irda *uin = (const struct sockaddr_irda *)uaddr;
+        SOCKADDR_IRDA *win = (SOCKADDR_IRDA *)wsaddr;
+
+        if (*wsaddrlen < sizeof(SOCKADDR_IRDA))
+            return -1;
+        win->irdaAddressFamily = WS_AF_IRDA;
+        memcpy( win->irdaDeviceID, &uin->sir_addr, sizeof(win->irdaDeviceID) );
+        if (uin->sir_lsap_sel != LSAP_ANY)
+            sprintf( win->irdaServiceName, "LSAP-SEL%u", uin->sir_lsap_sel );
+        else
+            memcpy( win->irdaServiceName, uin->sir_name,
+                    sizeof(win->irdaServiceName) );
+        return 0;
+    }
 #endif
     case AF_INET6: {
         const struct sockaddr_in6* uin6 = (const struct sockaddr_in6*)uaddr;
@@ -1022,13 +1229,16 @@ static int ws_sockaddr_u2ws(const struct sockaddr* uaddr, struct WS_sockaddr* ws
         win6old->sin6_port     = uin6->sin6_port;
         win6old->sin6_flowinfo = uin6->sin6_flowinfo;
         memcpy(&win6old->sin6_addr,&uin6->sin6_addr,16); /* 16 bytes = 128 address bits */
-        *wsaddrlen = sizeof(struct WS_sockaddr_in6_old);
 #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
         if (*wsaddrlen >= sizeof(struct WS_sockaddr_in6)) {
             struct WS_sockaddr_in6* win6 = (struct WS_sockaddr_in6*)wsaddr;
             win6->sin6_scope_id = uin6->sin6_scope_id;
             *wsaddrlen = sizeof(struct WS_sockaddr_in6);
         }
+        else
+            *wsaddrlen = sizeof(struct WS_sockaddr_in6_old);
+#else
+        *wsaddrlen = sizeof(struct WS_sockaddr_in6_old);
 #endif
         return 0;
     }
@@ -1127,7 +1337,7 @@ static int WS2_recv( int fd, struct ws2_async *wsa )
  *
  * Handler for overlapped recv() operations.
  */
-static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, ULONG *total )
+static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, void **apc)
 {
     ws2_async* wsa = user;
     int result = 0, fd;
@@ -1163,7 +1373,8 @@ static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS stat
     if (status != STATUS_PENDING)
     {
         iosb->u.Status = status;
-        iosb->Information = *total = result;
+        iosb->Information = result;
+        *apc = ws2_async_apc;
     }
     return status;
 }
@@ -1228,7 +1439,7 @@ static int WS2_send( int fd, struct ws2_async *wsa )
  *
  * Handler for overlapped send() operations.
  */
-static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, ULONG *total )
+static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, void **apc)
 {
     ws2_async* wsa = user;
     int result = 0, fd;
@@ -1273,7 +1484,8 @@ static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS statu
     if (status != STATUS_PENDING)
     {
         iosb->u.Status = status;
-        iosb->Information = *total = result;
+        iosb->Information = result;
+        *apc = ws2_async_apc;
     }
     return status;
 }
@@ -1283,7 +1495,7 @@ static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS statu
  *
  * Handler for shutdown() operations on overlapped sockets.
  */
-static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS status, ULONG *total )
+static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc )
 {
     ws2_async* wsa = user;
     int fd, err = 1;
@@ -1303,8 +1515,9 @@ static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS
         status = err ? wsaErrno() : STATUS_SUCCESS;
         break;
     }
-    *total = 0;
     iosb->u.Status = status;
+    iosb->Information = 0;
+    *apc = ws2_async_apc;
     return status;
 }
 
@@ -1332,10 +1545,9 @@ static int WS2_register_async_shutdown( SOCKET s, int type )
     {
         req->type   = type;
         req->async.handle   = wine_server_obj_handle( wsa->hSocket );
-        req->async.callback = WS2_async_shutdown;
-        req->async.iosb     = &wsa->local_iosb;
-        req->async.arg      = wsa;
-        req->async.apc      = ws2_async_apc;
+        req->async.callback = wine_server_client_ptr( WS2_async_shutdown );
+        req->async.iosb     = wine_server_client_ptr( &wsa->local_iosb );
+        req->async.arg      = wine_server_client_ptr( wsa );
         req->async.cvalue   = 0;
         status = wine_server_call( req );
     }
@@ -1355,6 +1567,7 @@ static int WS2_register_async_shutdown( SOCKET s, int type )
 SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr,
                                  int *addrlen32)
 {
+    NTSTATUS status;
     SOCKET as;
     BOOL is_blocking;
 
@@ -1362,33 +1575,32 @@ SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr,
     is_blocking = _is_blocking(s);
 
     do {
-        if (is_blocking)
-        {
-            int fd = get_sock_fd( s, FILE_READ_DATA, NULL );
-            if (fd == -1) return INVALID_SOCKET;
-            /* block here */
-            do_block(fd, POLLIN, -1);
-            _sync_sock_state(s); /* let wineserver notice connection */
-            release_sock_fd( s, fd );
-            /* retrieve any error codes from it */
-            SetLastError(_get_sock_error(s, FD_ACCEPT_BIT));
-            /* FIXME: care about the error? */
-        }
+        /* try accepting first (if there is a deferred connection) */
         SERVER_START_REQ( accept_socket )
         {
             req->lhandle    = wine_server_obj_handle( SOCKET2HANDLE(s) );
             req->access     = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE;
             req->attributes = OBJ_INHERIT;
-            set_error( wine_server_call( req ) );
+            status = wine_server_call( req );
             as = HANDLE2SOCKET( wine_server_ptr_handle( reply->handle ));
         }
         SERVER_END_REQ;
-        if (as)
+        if (!status)
         {
             if (addr) WS_getpeername(as, addr, addrlen32);
             return as;
         }
-    } while (is_blocking);
+        if (is_blocking && status == WSAEWOULDBLOCK)
+        {
+            int fd = get_sock_fd( s, FILE_READ_DATA, NULL );
+            /* block here */
+            do_block(fd, POLLIN, -1);
+            _sync_sock_state(s); /* let wineserver notice connection */
+            release_sock_fd( s, fd );
+        }
+    } while (is_blocking && status == WSAEWOULDBLOCK);
+
+    set_error(status);
     return INVALID_SOCKET;
 }
 
@@ -1404,7 +1616,7 @@ int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
 
     if (fd != -1)
     {
-        if (!name || (name->sa_family && !SUPPORTED_PF(name->sa_family)))
+        if (!name || (name->sa_family && !supported_pf(name->sa_family)))
         {
             SetLastError(WSAEAFNOSUPPORT);
         }
@@ -1428,7 +1640,7 @@ int WINAPI WS_bind(SOCKET s, const struct WS_sockaddr* name, int namelen)
                     {
                         release_sock_fd( s, fd );
                         SetLastError(WSAEAFNOSUPPORT);
-                        return INVALID_SOCKET;
+                        return SOCKET_ERROR;
                     }
                 }
 #endif
@@ -1583,14 +1795,7 @@ int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen)
     int fd;
     int res;
 
-    TRACE("socket: %04lx, ptr %p, len %08x\n", s, name, *namelen);
-
-    /* Check if what we've received is valid. Should we use IsBadReadPtr? */
-    if( (name == NULL) || (namelen == NULL) )
-    {
-        SetLastError( WSAEFAULT );
-        return SOCKET_ERROR;
-    }
+    TRACE("socket: %04lx, ptr %p, len %08x\n", s, name, namelen?*namelen:0);
 
     fd = get_sock_fd( s, 0, NULL );
     res = SOCKET_ERROR;
@@ -1600,19 +1805,18 @@ int WINAPI WS_getpeername(SOCKET s, struct WS_sockaddr *name, int *namelen)
         union generic_unix_sockaddr uaddr;
         unsigned int uaddrlen = sizeof(uaddr);
 
-        if (getpeername(fd, &uaddr.addr, &uaddrlen) != 0)
+        if (getpeername(fd, &uaddr.addr, &uaddrlen) == 0)
         {
-            SetLastError(wsaErrno());
-        }
-        else if (ws_sockaddr_u2ws(&uaddr.addr, name, namelen) != 0)
-        {
-            /* The buffer was too small */
-            SetLastError(WSAEFAULT);
+            if (!name || !namelen)
+                SetLastError(WSAEFAULT);
+            else if (ws_sockaddr_u2ws(&uaddr.addr, name, namelen) != 0)
+                /* The buffer was too small */
+                SetLastError(WSAEFAULT);
+            else
+                res = 0;
         }
         else
-        {
-            res=0;
-        }
+            SetLastError(wsaErrno());
         release_sock_fd( s, fd );
     }
     return res;
@@ -1905,6 +2109,73 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
         }/* end switch(optname) */
     } /* end case NSPROTO_IPX */
 #endif
+
+#ifdef HAVE_IRDA
+    case WS_SOL_IRLMP:
+        switch(optname)
+        {
+        case WS_IRLMP_ENUMDEVICES:
+        {
+            static const int MAX_IRDA_DEVICES = 10;
+            char buf[sizeof(struct irda_device_list) +
+                     (MAX_IRDA_DEVICES - 1) * sizeof(struct irda_device_info)];
+            int fd, res;
+            socklen_t len = sizeof(buf);
+
+            if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
+                return SOCKET_ERROR;
+            res = getsockopt( fd, SOL_IRLMP, IRLMP_ENUMDEVICES, buf, &len );
+            if (res < 0)
+            {
+                SetLastError(wsaErrno());
+                return SOCKET_ERROR;
+            }
+            else
+            {
+                struct irda_device_list *src = (struct irda_device_list *)buf;
+                DEVICELIST *dst = (DEVICELIST *)optval;
+                INT needed = sizeof(DEVICELIST), i;
+
+                if (src->len > 0)
+                    needed += (src->len - 1) * sizeof(IRDA_DEVICE_INFO);
+                if (*optlen < needed)
+                {
+                    SetLastError(WSAEFAULT);
+                    return SOCKET_ERROR;
+                }
+                *optlen = needed;
+                TRACE("IRLMP_ENUMDEVICES: %d devices found:\n", src->len);
+                dst->numDevice = src->len;
+                for (i = 0; i < src->len; i++)
+                {
+                    TRACE("saddr = %08x, daddr = %08x, info = %s, hints = %02x%02x\n",
+                          src->dev[i].saddr, src->dev[i].daddr,
+                          src->dev[i].info, src->dev[i].hints[0],
+                          src->dev[i].hints[1]);
+                    memcpy( dst->Device[i].irdaDeviceID,
+                            &src->dev[i].daddr,
+                            sizeof(dst->Device[i].irdaDeviceID) ) ;
+                    memcpy( dst->Device[i].irdaDeviceName,
+                            &src->dev[i].info,
+                            sizeof(dst->Device[i].irdaDeviceName) ) ;
+                    memcpy( &dst->Device[i].irdaDeviceHints1,
+                            &src->dev[i].hints[0],
+                            sizeof(dst->Device[i].irdaDeviceHints1) ) ;
+                    memcpy( &dst->Device[i].irdaDeviceHints2,
+                            &src->dev[i].hints[1],
+                            sizeof(dst->Device[i].irdaDeviceHints2) ) ;
+                    dst->Device[i].irdaCharSet = src->dev[i].charset;
+                }
+                return 0;
+            }
+        }
+        default:
+            FIXME("IrDA optname:0x%x\n", optname);
+            return SOCKET_ERROR;
+        }
+        break; /* case WS_SOL_IRLMP */
+#endif
+
     /* Levels WS_IPPROTO_TCP and WS_IPPROTO_IP convert directly */
     case WS_IPPROTO_TCP:
         switch(optname)
@@ -1956,14 +2227,18 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
         FIXME("Unknown IPPROTO_IP optname 0x%08x\n", optname);
         return SOCKET_ERROR;
 
+    case WS_IPPROTO_IPV6:
+        FIXME("IPPROTO_IPV6 unimplemented (optname 0x%08x)\n", optname);
+        return SOCKET_ERROR;
+
     default:
-        FIXME("Unknown level: 0x%08x\n", level);
+        WARN("Unknown level: 0x%08x\n", level);
+        SetLastError(WSAEINVAL);
         return SOCKET_ERROR;
     } /* end switch(level) */
 }
 
 /***********************************************************************
- *             htonl                   (WINSOCK.8)
  *             htonl                   (WS2_32.8)
  */
 WS_u_long WINAPI WS_htonl(WS_u_long hostlong)
@@ -1973,7 +2248,6 @@ WS_u_long WINAPI WS_htonl(WS_u_long hostlong)
 
 
 /***********************************************************************
- *             htons                   (WINSOCK.9)
  *             htons                   (WS2_32.9)
  */
 WS_u_short WINAPI WS_htons(WS_u_short hostshort)
@@ -2020,7 +2294,6 @@ int WINAPI WSAHtons(SOCKET s, WS_u_short hostshort, WS_u_short *lpnetshort)
 
 
 /***********************************************************************
- *             inet_addr               (WINSOCK.10)
  *             inet_addr               (WS2_32.11)
  */
 WS_u_long WINAPI WS_inet_addr(const char *cp)
@@ -2031,7 +2304,6 @@ WS_u_long WINAPI WS_inet_addr(const char *cp)
 
 
 /***********************************************************************
- *             ntohl                   (WINSOCK.14)
  *             ntohl                   (WS2_32.14)
  */
 WS_u_long WINAPI WS_ntohl(WS_u_long netlong)
@@ -2041,7 +2313,6 @@ WS_u_long WINAPI WS_ntohl(WS_u_long netlong)
 
 
 /***********************************************************************
- *             ntohs                   (WINSOCK.15)
  *             ntohs                   (WS2_32.15)
  */
 WS_u_short WINAPI WS_ntohs(WS_u_short netshort)
@@ -2381,7 +2652,7 @@ INT WINAPI WSAIoctl(SOCKET s,
 int WINAPI WS_ioctlsocket(SOCKET s, LONG cmd, WS_u_long *argp)
 {
     int fd;
-    long newcmd  = cmd;
+    LONG newcmd  = cmd;
 
     TRACE("socket %04lx, cmd %08x, ptr %p\n", s, cmd, argp);
     /* broken apps like defcon pass the argp value directly instead of a pointer to it */
@@ -2405,25 +2676,11 @@ int WINAPI WS_ioctlsocket(SOCKET s, LONG cmd, WS_u_long *argp)
             SetLastError(WSAEINVAL);
             return SOCKET_ERROR;
         }
-        fd = get_sock_fd( s, 0, NULL );
-        if (fd != -1)
-        {
-            int ret;
-            if (*argp)
-            {
-                _enable_event(SOCKET2HANDLE(s), 0, FD_WINE_NONBLOCKING, 0);
-                ret = fcntl( fd, F_SETFL, O_NONBLOCK );
-            }
-            else
-            {
-                _enable_event(SOCKET2HANDLE(s), 0, 0, FD_WINE_NONBLOCKING);
-                ret = fcntl( fd, F_SETFL, 0 );
-            }
-            release_sock_fd( s, fd );
-            if (!ret) return 0;
-            SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
-        }
-        return SOCKET_ERROR;
+        if (*argp)
+            _enable_event(SOCKET2HANDLE(s), 0, FD_WINE_NONBLOCKING, 0);
+        else
+            _enable_event(SOCKET2HANDLE(s), 0, 0, FD_WINE_NONBLOCKING);
+        return 0;
 
     case WS_SIOCATMARK:
         newcmd=SIOCATMARK;
@@ -2628,6 +2885,8 @@ int WINAPI WS_select(int nfds, WS_fd_set *ws_readfds,
                      const struct WS_timeval* ws_timeout)
 {
     struct pollfd *pollfds;
+    struct timeval tv1, tv2;
+    int torig = 0;
     int count, ret, timeout = -1;
 
     TRACE("read %p, write %p, excp %p timeout %p\n",
@@ -2639,9 +2898,32 @@ int WINAPI WS_select(int nfds, WS_fd_set *ws_readfds,
         return SOCKET_ERROR;
     }
 
-    if (ws_timeout) timeout = (ws_timeout->tv_sec * 1000) + (ws_timeout->tv_usec + 999) / 1000;
+    if (ws_timeout)
+    {
+        torig = (ws_timeout->tv_sec * 1000) + (ws_timeout->tv_usec + 999) / 1000;
+        timeout = torig;
+        gettimeofday( &tv1, 0 );
+    }
+
+    while ((ret = poll( pollfds, count, timeout )) < 0)
+    {
+        if (errno == EINTR)
+        {
+            if (!ws_timeout) continue;
+            gettimeofday( &tv2, 0 );
+
+            tv2.tv_sec  -= tv1.tv_sec;
+            tv2.tv_usec -= tv1.tv_usec;
+            if (tv2.tv_usec < 0)
+            {
+                tv2.tv_usec += 1000000;
+                tv2.tv_sec  -= 1;
+            }
 
-    ret = poll( pollfds, count, timeout );
+            timeout = torig - (tv2.tv_sec * 1000) - (tv2.tv_usec + 999) / 1000;
+            if (timeout <= 0) break;
+        } else break;
+    }
     release_poll_fds( ws_readfds, ws_writefds, ws_exceptfds, pollfds );
 
     if (ret == -1) SetLastError(wsaErrno());
@@ -2785,10 +3067,9 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
             {
                 req->type           = ASYNC_TYPE_WRITE;
                 req->async.handle   = wine_server_obj_handle( wsa->hSocket );
-                req->async.callback = WS2_async_send;
-                req->async.iosb     = iosb;
-                req->async.arg      = wsa;
-                req->async.apc      = ws2_async_apc;
+                req->async.callback = wine_server_client_ptr( WS2_async_send );
+                req->async.iosb     = wine_server_client_ptr( iosb );
+                req->async.arg      = wine_server_client_ptr( wsa );
                 req->async.event    = wine_server_obj_handle( lpCompletionRoutine ? 0 : lpOverlapped->hEvent );
                 req->async.cvalue   = cvalue;
                 err = wine_server_call( req );
@@ -3022,7 +3303,7 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
                 tval.tv_usec = (*(const UINT32*)optval % 1000) * 1000;
                 tval.tv_sec = *(const UINT32*)optval / 1000;
                 /* min of 500 milliseconds */
-                if (tval.tv_sec == 0 && tval.tv_usec < 500000)
+                if (tval.tv_sec == 0 && tval.tv_usec && tval.tv_usec < 500000)
                     tval.tv_usec = 500000;
                 optlen = sizeof(struct timeval);
                 optval = (char*)&tval;
@@ -3123,7 +3404,8 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
         break;
 
     default:
-        FIXME("Unknown level: 0x%08x\n", level);
+        WARN("Unknown level: 0x%08x\n", level);
+        SetLastError(WSAEINVAL);
         return SOCKET_ERROR;
     } /* end switch(level) */
 
@@ -3266,6 +3548,132 @@ struct WS_hostent* WINAPI WS_gethostbyaddr(const char *addr, int len, int type)
     return retval;
 }
 
+/***********************************************************************
+ *             WS_get_local_ips                (INTERNAL)
+ *
+ * Returns the list of local IP addresses by going through the network
+ * adapters and using the local routing table to sort the addresses
+ * from highest routing priority to lowest routing priority. This
+ * functionality is inferred from the description for obtaining local
+ * IP addresses given in the Knowledge Base Article Q160215.
+ *
+ * Please note that the returned hostent is only freed when the thread
+ * closes and is replaced if another hostent is requested.
+ */
+static struct WS_hostent* WS_get_local_ips( char *hostname )
+{
+    int last_metric, numroutes = 0, i, j;
+    PIP_ADAPTER_INFO adapters = NULL, k;
+    struct WS_hostent *hostlist = NULL;
+    PMIB_IPFORWARDTABLE routes = NULL;
+    struct route *route_addrs = NULL;
+    DWORD adap_size, route_size;
+
+    /* Obtain the size of the adapter list and routing table, also allocate memory */
+    if (GetAdaptersInfo(NULL, &adap_size) != ERROR_BUFFER_OVERFLOW)
+        return NULL;
+    if (GetIpForwardTable(NULL, &route_size, FALSE) != ERROR_INSUFFICIENT_BUFFER)
+        return NULL;
+    adapters = HeapAlloc(GetProcessHeap(), 0, adap_size);
+    routes = HeapAlloc(GetProcessHeap(), 0, route_size);
+    route_addrs = HeapAlloc(GetProcessHeap(), 0, 0); /* HeapReAlloc doesn't work on NULL */
+    if (adapters == NULL || routes == NULL || route_addrs == NULL)
+        goto cleanup;
+    /* Obtain the adapter list and the full routing table */
+    if (GetAdaptersInfo(adapters, &adap_size) != NO_ERROR)
+        goto cleanup;
+    if (GetIpForwardTable(routes, &route_size, FALSE) != NO_ERROR)
+        goto cleanup;
+    /* Store the interface associated with each route */
+    for (i = 0; i < routes->dwNumEntries; i++)
+    {
+        DWORD ifindex, ifmetric, exists = FALSE;
+
+        if (routes->table[i].dwForwardType != MIB_IPROUTE_TYPE_DIRECT)
+            continue;
+        ifindex = routes->table[i].dwForwardIfIndex;
+        ifmetric = routes->table[i].dwForwardMetric1;
+        /* Only store the lowest valued metric for an interface */
+        for (j = 0; j < numroutes; j++)
+        {
+            if (route_addrs[j].interface == ifindex)
+            {
+                if (route_addrs[j].metric > ifmetric)
+                    route_addrs[j].metric = ifmetric;
+                exists = TRUE;
+            }
+        }
+        if (exists)
+            continue;
+        route_addrs = HeapReAlloc(GetProcessHeap(), 0, route_addrs, (numroutes+1)*sizeof(struct route));
+        if (route_addrs == NULL)
+            goto cleanup; /* Memory allocation error, fail gracefully */
+        route_addrs[numroutes].interface = ifindex;
+        route_addrs[numroutes].metric = ifmetric;
+        /* If no IP is found in the next step (for whatever reason)
+         * then fall back to the magic loopback address.
+         */
+        memcpy(&(route_addrs[numroutes].addr.s_addr), magic_loopback_addr, 4);
+        numroutes++;
+    }
+   if (numroutes == 0)
+       goto cleanup; /* No routes, fall back to the Magic IP */
+    /* Find the IP address associated with each found interface */
+    for (i = 0; i < numroutes; i++)
+    {
+        for (k = adapters; k != NULL; k = k->Next)
+        {
+            char *ip = k->IpAddressList.IpAddress.String;
+
+            if (route_addrs[i].interface == k->Index)
+                route_addrs[i].addr.s_addr = (in_addr_t) inet_addr(ip);
+        }
+    }
+    /* Allocate a hostent and enough memory for all the IPs,
+     * including the NULL at the end of the list.
+     */
+    hostlist = WS_create_he(hostname, 1, numroutes+1, TRUE);
+    if (hostlist == NULL)
+        goto cleanup; /* Failed to allocate a hostent for the list of IPs */
+    hostlist->h_addr_list[numroutes] = NULL; /* NULL-terminate the address list */
+    hostlist->h_aliases[0] = NULL; /* NULL-terminate the alias list */
+    hostlist->h_addrtype = AF_INET;
+    hostlist->h_length = sizeof(struct in_addr); /* = 4 */
+    /* Reorder the entries when placing them in the host list, Windows expects
+     * the IP list in order from highest priority to lowest (the critical thing
+     * is that most applications expect the first IP to be the default route).
+     */
+    last_metric = -1;
+    for (i = 0; i < numroutes; i++)
+    {
+       struct in_addr addr;
+       int metric = 0xFFFF;
+
+       memcpy(&addr, magic_loopback_addr, 4);
+       for (j = 0; j < numroutes; j++)
+       {
+           int this_metric = route_addrs[j].metric;
+
+           if (this_metric > last_metric && this_metric < metric)
+           {
+               addr = route_addrs[j].addr;
+               metric = this_metric;
+           }
+       }
+       last_metric = metric;
+       (*(struct in_addr *) hostlist->h_addr_list[i]) = addr;
+    }
+
+    /* Cleanup all allocated memory except the address list,
+     * the address list is used by the calling app.
+     */
+cleanup:
+    HeapFree(GetProcessHeap(), 0, route_addrs);
+    HeapFree(GetProcessHeap(), 0, adapters);
+    HeapFree(GetProcessHeap(), 0, routes);
+    return hostlist;
+}
+
 /***********************************************************************
  *             gethostbyname           (WS2_32.52)
  */
@@ -3279,35 +3687,44 @@ struct WS_hostent* WINAPI WS_gethostbyname(const char* name)
     struct hostent hostentry;
     int locerr = ENOBUFS;
 #endif
-    char buf[100];
+    char hostname[100];
+    if( gethostname( hostname, 100) == -1) {
+        SetLastError( WSAENOBUFS); /* appropriate ? */
+        return retval;
+    }
     if( !name || !name[0]) {
-        name = buf;
-        if( gethostname( buf, 100) == -1) {
-            SetLastError( WSAENOBUFS); /* appropriate ? */
-            return retval;
-        }
+        name = hostname;
     }
+    /* If the hostname of the local machine is requested then return the
+     * complete list of local IP addresses */
+    if(strcmp(name, hostname) == 0)
+        retval = WS_get_local_ips(hostname);
+    /* If any other hostname was requested (or the routing table lookup failed)
+     * then return the IP found by the host OS */
+    if(retval == NULL)
+    {
 #ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
-    host = NULL;
-    extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
-    while(extrabuf) {
-        int res = gethostbyname_r(name, &hostentry, extrabuf, ebufsize, &host, &locerr);
-        if( res != ERANGE) break;
-        ebufsize *=2;
-        extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
-    }
-    if (!host) SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
+        host = NULL;
+        extrabuf=HeapAlloc(GetProcessHeap(),0,ebufsize) ;
+        while(extrabuf) {
+            int res = gethostbyname_r(name, &hostentry, extrabuf, ebufsize, &host, &locerr);
+            if( res != ERANGE) break;
+            ebufsize *=2;
+            extrabuf=HeapReAlloc(GetProcessHeap(),0,extrabuf,ebufsize) ;
+        }
+        if (!host) SetLastError((locerr < 0) ? wsaErrno() : wsaHerrno(locerr));
 #else
-    EnterCriticalSection( &csWSgetXXXbyYYY );
-    host = gethostbyname(name);
-    if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
+        EnterCriticalSection( &csWSgetXXXbyYYY );
+        host = gethostbyname(name);
+        if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
 #endif
-    if (host) retval = WS_dup_he(host);
+        if (host) retval = WS_dup_he(host);
 #ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
-    HeapFree(GetProcessHeap(),0,extrabuf);
+        HeapFree(GetProcessHeap(),0,extrabuf);
 #else
-    LeaveCriticalSection( &csWSgetXXXbyYYY );
+        LeaveCriticalSection( &csWSgetXXXbyYYY );
 #endif
+    }
     if (retval && retval->h_addr_list[0][0] == 127 &&
         strcmp(name, "localhost") != 0)
     {
@@ -3583,13 +4000,151 @@ outofmem:
 #endif
 }
 
+static struct WS_addrinfoW *addrinfo_AtoW(const struct WS_addrinfo *ai)
+{
+    struct WS_addrinfoW *ret;
+
+    if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_addrinfoW)))) return NULL;
+    ret->ai_flags     = ai->ai_flags;
+    ret->ai_family    = ai->ai_family;
+    ret->ai_socktype  = ai->ai_socktype;
+    ret->ai_protocol  = ai->ai_protocol;
+    ret->ai_addrlen   = ai->ai_addrlen;
+    ret->ai_canonname = NULL;
+    ret->ai_addr      = NULL;
+    ret->ai_next      = NULL;
+    if (ai->ai_canonname)
+    {
+        int len = MultiByteToWideChar(CP_ACP, 0, ai->ai_canonname, -1, NULL, 0);
+        if (!(ret->ai_canonname = HeapAlloc(GetProcessHeap(), 0, len)))
+        {
+            HeapFree(GetProcessHeap(), 0, ret);
+            return NULL;
+        }
+        MultiByteToWideChar(CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len);
+    }
+    if (ai->ai_addr)
+    {
+        if (!(ret->ai_addr = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_sockaddr))))
+        {
+            HeapFree(GetProcessHeap(), 0, ret->ai_canonname);
+            HeapFree(GetProcessHeap(), 0, ret);
+            return NULL;
+        }
+        memcpy(ret->ai_addr, ai->ai_addr, sizeof(struct WS_sockaddr));
+    }
+    return ret;
+}
+
+static struct WS_addrinfoW *addrinfo_list_AtoW(const struct WS_addrinfo *info)
+{
+    struct WS_addrinfoW *ret, *infoW;
+
+    if (!(ret = infoW = addrinfo_AtoW(info))) return NULL;
+    while (info->ai_next)
+    {
+        if (!(infoW->ai_next = addrinfo_AtoW(info->ai_next)))
+        {
+            FreeAddrInfoW(ret);
+            return NULL;
+        }
+        infoW = infoW->ai_next;
+        info = info->ai_next;
+    }
+    return ret;
+}
+
+static struct WS_addrinfo *addrinfo_WtoA(const struct WS_addrinfoW *ai)
+{
+    struct WS_addrinfo *ret;
+
+    if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_addrinfo)))) return NULL;
+    ret->ai_flags     = ai->ai_flags;
+    ret->ai_family    = ai->ai_family;
+    ret->ai_socktype  = ai->ai_socktype;
+    ret->ai_protocol  = ai->ai_protocol;
+    ret->ai_addrlen   = ai->ai_addrlen;
+    ret->ai_canonname = NULL;
+    ret->ai_addr      = NULL;
+    ret->ai_next      = NULL;
+    if (ai->ai_canonname)
+    {
+        int len = WideCharToMultiByte(CP_ACP, 0, ai->ai_canonname, -1, NULL, 0, NULL, NULL);
+        if (!(ret->ai_canonname = HeapAlloc(GetProcessHeap(), 0, len)))
+        {
+            HeapFree(GetProcessHeap(), 0, ret);
+            return NULL;
+        }
+        WideCharToMultiByte(CP_ACP, 0, ai->ai_canonname, -1, ret->ai_canonname, len, NULL, NULL);
+    }
+    if (ai->ai_addr)
+    {
+        if (!(ret->ai_addr = HeapAlloc(GetProcessHeap(), 0, sizeof(struct WS_sockaddr))))
+        {
+            HeapFree(GetProcessHeap(), 0, ret->ai_canonname);
+            HeapFree(GetProcessHeap(), 0, ret);
+            return NULL;
+        }
+        memcpy(ret->ai_addr, ai->ai_addr, sizeof(struct WS_sockaddr));
+    }
+    return ret;
+}
+
 /***********************************************************************
  *             GetAddrInfoW            (WS2_32.@)
  */
 int WINAPI GetAddrInfoW(LPCWSTR nodename, LPCWSTR servname, const ADDRINFOW *hints, PADDRINFOW *res)
 {
-    FIXME("empty stub!\n");
-    return EAI_FAIL;
+    int ret, len;
+    char *nodenameA, *servnameA = NULL;
+    struct WS_addrinfo *resA, *hintsA = NULL;
+
+    if (!nodename) return WSAHOST_NOT_FOUND;
+
+    len = WideCharToMultiByte(CP_ACP, 0, nodename, -1, NULL, 0, NULL, NULL);
+    if (!(nodenameA = HeapAlloc(GetProcessHeap(), 0, len))) return EAI_MEMORY;
+    WideCharToMultiByte(CP_ACP, 0, nodename, -1, nodenameA, len, NULL, NULL);
+
+    if (servname)
+    {
+        len = WideCharToMultiByte(CP_ACP, 0, servname, -1, NULL, 0, NULL, NULL);
+        if (!(servnameA = HeapAlloc(GetProcessHeap(), 0, len)))
+        {
+            HeapFree(GetProcessHeap(), 0, nodenameA);
+            return EAI_MEMORY;
+        }
+        WideCharToMultiByte(CP_ACP, 0, servname, -1, servnameA, len, NULL, NULL);
+    }
+
+    if (hints) hintsA = addrinfo_WtoA(hints);
+    ret = WS_getaddrinfo(nodenameA, servnameA, hintsA, &resA);
+    WS_freeaddrinfo(hintsA);
+
+    if (!ret)
+    {
+        *res = addrinfo_list_AtoW(resA);
+        WS_freeaddrinfo(resA);
+    }
+
+    HeapFree(GetProcessHeap(), 0, nodenameA);
+    HeapFree(GetProcessHeap(), 0, servnameA);
+    return ret;
+}
+
+/***********************************************************************
+ *      FreeAddrInfoW        (WS2_32.@)
+ */
+void WINAPI FreeAddrInfoW(PADDRINFOW ai)
+{
+    while (ai)
+    {
+        ADDRINFOW *next;
+        HeapFree(GetProcessHeap(), 0, ai->ai_canonname);
+        HeapFree(GetProcessHeap(), 0, ai->ai_addr);
+        next = ai->ai_next;
+        HeapFree(GetProcessHeap(), 0, ai);
+        ai = next;
+    }
 }
 
 int WINAPI WS_getnameinfo(const SOCKADDR *sa, WS_socklen_t salen, PCHAR host,
@@ -3904,11 +4459,9 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol,
     if (GetLastError() == WSAEACCES) /* raw socket denied */
     {
         if (type == SOCK_RAW)
-            MESSAGE("WARNING: Trying to create a socket of type SOCK_RAW, this"
-                    " will fail unless you have special permissions.\n");
+            ERR_(winediag)("Failed to create a socket of type SOCK_RAW, this requires special permissions.\n");
         else
-            MESSAGE("WS_SOCKET: Failed to create socket, this requires"
-                    " special permissions.\n");
+            ERR_(winediag)("Failed to create socket, this requires special permissions.\n");
         SetLastError(WSAESOCKTNOSUPPORT);
     }
 
@@ -3949,7 +4502,6 @@ int WINAPI __WSAFDIsSet(SOCKET s, WS_fd_set *set)
 }
 
 /***********************************************************************
- *      WSAIsBlocking                  (WINSOCK.114)
  *      WSAIsBlocking                  (WS2_32.114)
  */
 BOOL WINAPI WSAIsBlocking(void)
@@ -3967,7 +4519,6 @@ BOOL WINAPI WSAIsBlocking(void)
 }
 
 /***********************************************************************
- *      WSACancelBlockingCall          (WINSOCK.113)
  *      WSACancelBlockingCall          (WS2_32.113)
  */
 INT WINAPI WSACancelBlockingCall(void)
@@ -4044,33 +4595,78 @@ static int list_dup(char** l_src, char** l_to, int item_size)
 
 /* ----- hostent */
 
-/* duplicate hostent entry
- * and handle all Win16/Win32 dependent things (struct size, ...) *correctly*.
- * Ditto for protoent and servent.
+/* create a hostent entry
+ *
+ * Creates the entry with enough memory for the name, aliases
+ * addresses, and the address pointers.  Also copies the name
+ * and sets up all the pointers.  If "fill_addresses" is set then
+ * sufficient memory for the addresses is also allocated and the
+ * address pointers are set to this memory.
+ *
+ * NOTE: The alias and address lists must be allocated with room
+ * for the NULL item terminating the list.  This is true even if
+ * the list has no items ("aliases" and "addresses" must be
+ * at least "1", a truly empty list is invalid).
  */
-static struct WS_hostent *WS_dup_he(const struct hostent* p_he)
+static struct WS_hostent *WS_create_he(char *name, int aliases, int addresses, int fill_addresses)
 {
-    char *p;
     struct WS_hostent *p_to;
+    char *p;
 
-    int size = (sizeof(*p_he) +
-                strlen(p_he->h_name) + 1 +
-                list_size(p_he->h_aliases, 0) +
-                list_size(p_he->h_addr_list, p_he->h_length));
+    int size = (sizeof(struct WS_hostent) +
+                strlen(name) + 1 +
+                sizeof(char *)*aliases +
+                sizeof(char *)*addresses);
+
+    /* Allocate enough memory for the addresses */
+    if (fill_addresses)
+        size += sizeof(struct in_addr)*addresses;
 
     if (!(p_to = check_buffer_he(size))) return NULL;
-    p_to->h_addrtype = p_he->h_addrtype;
-    p_to->h_length = p_he->h_length;
+    memset(p_to, 0, size);
 
     p = (char *)(p_to + 1);
     p_to->h_name = p;
-    strcpy(p, p_he->h_name);
+    strcpy(p, name);
     p += strlen(p) + 1;
 
     p_to->h_aliases = (char **)p;
-    p += list_dup(p_he->h_aliases, p_to->h_aliases, 0);
-
+    p += sizeof(char *)*aliases;
     p_to->h_addr_list = (char **)p;
+    p += sizeof(char *)*addresses;
+    if (fill_addresses)
+    {
+        int i;
+
+        /* NOTE: h_aliases must be filled in manually, leave these
+         * pointers NULL (already set to NULL by memset earlier).
+         */
+
+        /* Fill in the list of address pointers */
+        for (i = 0; i < addresses; i++)
+            p_to->h_addr_list[i] = (p += sizeof(struct in_addr));
+        p += sizeof(struct in_addr);
+    }
+    return p_to;
+}
+
+/* duplicate hostent entry
+ * and handle all Win16/Win32 dependent things (struct size, ...) *correctly*.
+ * Ditto for protoent and servent.
+ */
+static struct WS_hostent *WS_dup_he(const struct hostent* p_he)
+{
+    int addresses = list_size(p_he->h_addr_list, p_he->h_length);
+    int aliases = list_size(p_he->h_aliases, 0);
+    struct WS_hostent *p_to;
+
+    p_to = WS_create_he(p_he->h_name, aliases, addresses, FALSE);
+
+    if (!p_to) return NULL;
+    p_to->h_addrtype = p_he->h_addrtype;
+    p_to->h_length = p_he->h_length;
+
+    list_dup(p_he->h_aliases, p_to->h_aliases, 0);
     list_dup(p_he->h_addr_list, p_to->h_addr_list, p_he->h_length);
     return p_to;
 }
@@ -4128,99 +4724,6 @@ static struct WS_servent *WS_dup_se(const struct servent* p_se)
     return p_to;
 }
 
-/* ----------------------------------- error handling */
-
-UINT wsaErrno(void)
-{
-    int        loc_errno = errno;
-    WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
-
-    switch(loc_errno)
-    {
-       case EINTR:             return WSAEINTR;
-       case EBADF:             return WSAEBADF;
-       case EPERM:
-       case EACCES:            return WSAEACCES;
-       case EFAULT:            return WSAEFAULT;
-       case EINVAL:            return WSAEINVAL;
-       case EMFILE:            return WSAEMFILE;
-       case EWOULDBLOCK:       return WSAEWOULDBLOCK;
-       case EINPROGRESS:       return WSAEINPROGRESS;
-       case EALREADY:          return WSAEALREADY;
-       case ENOTSOCK:          return WSAENOTSOCK;
-       case EDESTADDRREQ:      return WSAEDESTADDRREQ;
-       case EMSGSIZE:          return WSAEMSGSIZE;
-       case EPROTOTYPE:        return WSAEPROTOTYPE;
-       case ENOPROTOOPT:       return WSAENOPROTOOPT;
-       case EPROTONOSUPPORT:   return WSAEPROTONOSUPPORT;
-       case ESOCKTNOSUPPORT:   return WSAESOCKTNOSUPPORT;
-       case EOPNOTSUPP:        return WSAEOPNOTSUPP;
-       case EPFNOSUPPORT:      return WSAEPFNOSUPPORT;
-       case EAFNOSUPPORT:      return WSAEAFNOSUPPORT;
-       case EADDRINUSE:        return WSAEADDRINUSE;
-       case EADDRNOTAVAIL:     return WSAEADDRNOTAVAIL;
-       case ENETDOWN:          return WSAENETDOWN;
-       case ENETUNREACH:       return WSAENETUNREACH;
-       case ENETRESET:         return WSAENETRESET;
-       case ECONNABORTED:      return WSAECONNABORTED;
-       case EPIPE:
-       case ECONNRESET:        return WSAECONNRESET;
-       case ENOBUFS:           return WSAENOBUFS;
-       case EISCONN:           return WSAEISCONN;
-       case ENOTCONN:          return WSAENOTCONN;
-       case ESHUTDOWN:         return WSAESHUTDOWN;
-       case ETOOMANYREFS:      return WSAETOOMANYREFS;
-       case ETIMEDOUT:         return WSAETIMEDOUT;
-       case ECONNREFUSED:      return WSAECONNREFUSED;
-       case ELOOP:             return WSAELOOP;
-       case ENAMETOOLONG:      return WSAENAMETOOLONG;
-       case EHOSTDOWN:         return WSAEHOSTDOWN;
-       case EHOSTUNREACH:      return WSAEHOSTUNREACH;
-       case ENOTEMPTY:         return WSAENOTEMPTY;
-#ifdef EPROCLIM
-       case EPROCLIM:          return WSAEPROCLIM;
-#endif
-#ifdef EUSERS
-       case EUSERS:            return WSAEUSERS;
-#endif
-#ifdef EDQUOT
-       case EDQUOT:            return WSAEDQUOT;
-#endif
-#ifdef ESTALE
-       case ESTALE:            return WSAESTALE;
-#endif
-#ifdef EREMOTE
-       case EREMOTE:           return WSAEREMOTE;
-#endif
-
-       /* just in case we ever get here and there are no problems */
-       case 0:                 return 0;
-        default:
-               WARN("Unknown errno %d!\n", loc_errno);
-               return WSAEOPNOTSUPP;
-    }
-}
-
-UINT wsaHerrno(int loc_errno)
-{
-
-    WARN("h_errno %d.\n", loc_errno);
-
-    switch(loc_errno)
-    {
-       case HOST_NOT_FOUND:    return WSAHOST_NOT_FOUND;
-       case TRY_AGAIN:         return WSATRY_AGAIN;
-       case NO_RECOVERY:       return WSANO_RECOVERY;
-       case NO_DATA:           return WSANO_DATA;
-       case ENOBUFS:           return WSAENOBUFS;
-
-       case 0:                 return 0;
-        default:
-               WARN("Unknown h_errno %d!\n", loc_errno);
-               return WSAEOPNOTSUPP;
-    }
-}
-
 
 /***********************************************************************
  *             WSARecv                 (WS2_32.67)
@@ -4273,6 +4776,12 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
     wsa->first_iovec = 0;
     for (i = 0; i < dwBufferCount; i++)
     {
+        /* check buffer first to trigger write watches */
+        if (IsBadWritePtr( lpBuffers[i].buf, lpBuffers[i].len ))
+        {
+            err = WSAEFAULT;
+            goto error;
+        }
         wsa->iovec[i].iov_base = lpBuffers[i].buf;
         wsa->iovec[i].iov_len  = lpBuffers[i].len;
     }
@@ -4311,10 +4820,9 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
                 {
                     req->type           = ASYNC_TYPE_READ;
                     req->async.handle   = wine_server_obj_handle( wsa->hSocket );
-                    req->async.callback = WS2_async_recv;
-                    req->async.iosb     = iosb;
-                    req->async.arg      = wsa;
-                    req->async.apc      = ws2_async_apc;
+                    req->async.callback = wine_server_client_ptr( WS2_async_recv );
+                    req->async.iosb     = wine_server_client_ptr( iosb );
+                    req->async.arg      = wine_server_client_ptr( wsa );
                     req->async.event    = wine_server_obj_handle( lpCompletionRoutine ? 0 : lpOverlapped->hEvent );
                     req->async.cvalue   = cvalue;
                     err = wine_server_call( req );
@@ -4560,25 +5068,46 @@ int WINAPI WSARemoveServiceClass(LPGUID info)
 /***********************************************************************
  *              inet_ntop                      (WS2_32.@)
  */
-PCSTR WINAPI WS_inet_ntop( INT family, PVOID addr, PSTR buffer, size_t len )
+PCSTR WINAPI WS_inet_ntop( INT family, PVOID addr, PSTR buffer, SIZE_T len )
 {
 #ifdef HAVE_INET_NTOP
-    union generic_unix_sockaddr unix_addr;
+    struct WS_in6_addr *in6;
+    struct WS_in_addr  *in;
+    PCSTR pdst;
+
+    TRACE("family %d, addr (%p), buffer (%p), len %ld\n", family, addr, buffer, len);
+    if (!buffer)
+    {
+        WSASetLastError( STATUS_INVALID_PARAMETER );
+        return NULL;
+    }
 
     switch (family)
     {
     case WS_AF_INET:
-        ws_sockaddr_ws2u( addr, sizeof(struct WS_sockaddr_in), &unix_addr );
-        return inet_ntop( AF_INET, &unix_addr, buffer, len );
+    {
+        in = addr;
+        pdst = inet_ntop( AF_INET, &in->WS_s_addr, buffer, len );
+        break;
+    }
     case WS_AF_INET6:
-        ws_sockaddr_ws2u( addr, sizeof(struct WS_sockaddr_in6), &unix_addr );
-        return inet_ntop( AF_INET6, &unix_addr, buffer, len );
+    {
+        in6 = addr;
+        pdst = inet_ntop( AF_INET6, in6->WS_s6_addr, buffer, len );
+        break;
     }
+    default:
+        WSASetLastError( WSAEAFNOSUPPORT );
+        return NULL;
+    }
+
+    if (!pdst) WSASetLastError( STATUS_INVALID_PARAMETER );
+    return pdst;
 #else
     FIXME( "not supported on this platform\n" );
-#endif
     WSASetLastError( WSAEAFNOSUPPORT );
     return NULL;
+#endif
 }
 
 /***********************************************************************
@@ -4637,7 +5166,7 @@ INT WINAPI WSAStringToAddressA(LPSTR AddressString,
         ptrPort = strchr(workBuffer, ':');
         if(ptrPort)
         {
-            ((LPSOCKADDR_IN)lpAddress)->sin_port = (WS_u_short)atoi(ptrPort+1);
+            ((LPSOCKADDR_IN)lpAddress)->sin_port = htons(atoi(ptrPort+1));
             *ptrPort = '\0';
         }
         else
@@ -4680,7 +5209,7 @@ INT WINAPI WSAStringToAddressA(LPSTR AddressString,
         ptrPort = strchr(workBuffer, ']');
         if(ptrPort && *(++ptrPort) == ':')
         {
-            ((LPSOCKADDR_IN6)lpAddress)->sin6_port = (WS_u_short)atoi(ptrPort+1);
+            ((LPSOCKADDR_IN6)lpAddress)->sin6_port = htons(atoi(ptrPort+1));
             *ptrPort = '\0';
         }
         else
@@ -4785,28 +5314,55 @@ INT WINAPI WSAAddressToStringA( LPSOCKADDR sockaddr, DWORD len,
                                 LPDWORD lenstr )
 {
     DWORD size;
-    CHAR buffer[22]; /* 12 digits + 3 dots + ':' + 5 digits + '\0' */
+    CHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
     CHAR *p;
 
     TRACE( "(%p, %d, %p, %p, %p)\n", sockaddr, len, info, string, lenstr );
 
-    if (!sockaddr || len < sizeof(SOCKADDR_IN)) return SOCKET_ERROR;
+    if (!sockaddr) return SOCKET_ERROR;
     if (!string || !lenstr) return SOCKET_ERROR;
 
-    /* sin_family is guaranteed to be the first u_short */
-    if (((SOCKADDR_IN *)sockaddr)->sin_family != AF_INET) return SOCKET_ERROR;
+    switch(sockaddr->sa_family)
+    {
+    case WS_AF_INET:
+        if (len < sizeof(SOCKADDR_IN)) return SOCKET_ERROR;
+        sprintf( buffer, "%u.%u.%u.%u:%u",
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 24 & 0xff),
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 16 & 0xff),
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 8 & 0xff),
+               (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) & 0xff),
+               ntohs( ((SOCKADDR_IN *)sockaddr)->sin_port ) );
+
+        p = strchr( buffer, ':' );
+        if (!((SOCKADDR_IN *)sockaddr)->sin_port) *p = 0;
+        break;
 
-    sprintf( buffer, "%u.%u.%u.%u:%u",
-             (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 24 & 0xff),
-             (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 16 & 0xff),
-             (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 8 & 0xff),
-             (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) & 0xff),
-             ntohs( ((SOCKADDR_IN *)sockaddr)->sin_port ) );
+    case WS_AF_INET6:
+    {
+        struct WS_sockaddr_in6 *sockaddr6 = (LPSOCKADDR_IN6) sockaddr;
 
-    p = strchr( buffer, ':' );
-    if (!((SOCKADDR_IN *)sockaddr)->sin_port) *p = 0;
+        buffer[0] = 0;
+        if (len < sizeof(SOCKADDR_IN6)) return SOCKET_ERROR;
+        if ((sockaddr6->sin6_port))
+            strcpy(buffer, "[");
+        if (!WS_inet_ntop(WS_AF_INET6, &sockaddr6->sin6_addr, buffer+strlen(buffer), sizeof(buffer)))
+        {
+            WSASetLastError(WSAEINVAL);
+            return SOCKET_ERROR;
+        }
+        if ((sockaddr6->sin6_scope_id))
+            sprintf(buffer+strlen(buffer), "%%%u", sockaddr6->sin6_scope_id);
+        if ((sockaddr6->sin6_port))
+            sprintf(buffer+strlen(buffer), "]:%u", ntohs(sockaddr6->sin6_port));
+        break;
+    }
 
-    size = strlen( buffer );
+    default:
+        WSASetLastError(WSAEINVAL);
+        return SOCKET_ERROR;
+    }
+
+    size = strlen( buffer ) + 1;
 
     if (*lenstr <  size)
     {
@@ -4815,6 +5371,7 @@ INT WINAPI WSAAddressToStringA( LPSOCKADDR sockaddr, DWORD len,
         return SOCKET_ERROR;
     }
 
+    *lenstr = size;
     strcpy( string, buffer );
     return 0;
 }
@@ -4837,45 +5394,33 @@ INT WINAPI WSAAddressToStringA( LPSOCKADDR sockaddr, DWORD len,
  *
  * NOTES
  *  The 'info' parameter is ignored.
- *
- * BUGS
- *  Only supports AF_INET addresses.
  */
 INT WINAPI WSAAddressToStringW( LPSOCKADDR sockaddr, DWORD len,
                                 LPWSAPROTOCOL_INFOW info, LPWSTR string,
                                 LPDWORD lenstr )
 {
+    INT   ret;
     DWORD size;
-    WCHAR buffer[22]; /* 12 digits + 3 dots + ':' + 5 digits + '\0' */
-    static const WCHAR format[] = { '%','u','.','%','u','.','%','u','.','%','u',':','%','u',0 };
-    WCHAR *p;
+    WCHAR buffer[54]; /* 32 digits + 7':' + '[' + '%" + 5 digits + ']:' + 5 digits + '\0' */
+    CHAR bufAddr[54];
 
-    TRACE( "(%p, %x, %p, %p, %p)\n", sockaddr, len, info, string, lenstr );
-
-    if (!sockaddr || len < sizeof(SOCKADDR_IN)) return SOCKET_ERROR;
-    if (!string || !lenstr) return SOCKET_ERROR;
-
-    /* sin_family is guaranteed to be the first u_short */
-    if (((SOCKADDR_IN *)sockaddr)->sin_family != AF_INET) return SOCKET_ERROR;
+    TRACE( "(%p, %d, %p, %p, %p)\n", sockaddr, len, info, string, lenstr );
 
-    sprintfW( buffer, format,
-              (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 24 & 0xff),
-              (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 16 & 0xff),
-              (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) >> 8 & 0xff),
-              (unsigned int)(ntohl( ((SOCKADDR_IN *)sockaddr)->sin_addr.WS_s_addr ) & 0xff),
-              ntohs( ((SOCKADDR_IN *)sockaddr)->sin_port ) );
+    size = *lenstr;
+    ret = WSAAddressToStringA(sockaddr, len, NULL, bufAddr, &size);
 
-    p = strchrW( buffer, ':' );
-    if (!((SOCKADDR_IN *)sockaddr)->sin_port) *p = 0;
+    if (ret) return ret;
 
-    size = strlenW( buffer );
+    MultiByteToWideChar( CP_ACP, 0, bufAddr, size, buffer, sizeof( buffer )/sizeof(WCHAR));
 
     if (*lenstr <  size)
     {
         *lenstr = size;
+        WSASetLastError(WSAEFAULT);
         return SOCKET_ERROR;
     }
 
+    *lenstr = size;
     lstrcpyW( string, buffer );
     return 0;
 }