HAVE_IPX cleanup

Francois Gouget fgouget at free.fr
Wed Sep 12 18:19:22 CDT 2001


   This patch attempts to clean up the ws_sockaddr_ipx to sockaddr_ipx
conversions (and vice versa).
   I would really like if people could try this out: I don't have a
working IPX network here. At least my very rudimentary tests indicate
that this should still work for the TCP/IP case.

   More details on the patch:
 * all ws_sockaddr structures must be considered to have a potentially
different layout from their Unix counterparts. Sure for now we just
borrow the Unix structs anyway but even sockaddr_in does not have the
exact same fields on FreeBSD and Linux (although the binary layout is
the same). And hopefully we will not borrow the Unix structs for long
anyway. FreeBSD testing is another aspect I would appreciate help with
(sin_len worries me).
 * the ws_sockaddr_ipx fields did not match those used by windows. Also
ws_sockaddr_ipx was declared in the wrong header.
 * all conversions are now done in two functions: ws_sockaddr_ws2u and
ws_sockaddr_u2ws. If there is a conversion to do then these are the only
two places that should be affected. SUPPORTED_PF returns whether a given
protocol family is supported or not.
 * the sockaddr* pointers may point to structures that are more than 16
bytes, typically 28 bytes for IP v6. I tried to take this into account,
I hope I did not mess up (but I'm not sure Wine would support TCP/IP v6
anyway).
 * I modified WSOCK32_accept to call WSOCK32_getpeername thus avoiding
the conversion issue entirely in WSOCK32_accept.
 * all other functions that were doing such conversions were modified to
use the above functions. I also tried to make the error handling code
more consistent wrt. WSAENOTSOCK, WSAEAFNOSUPPORT, etc.
 * removed ugly casts in the traces




--
Francois Gouget         fgouget at free.fr        http://fgouget.free.fr/
                         "Utilisateur" (nom commun) :
        Mot utilisé par les informaticiens en lieu et place d'"idiot".
-------------- next part --------------
Index: include/winsock.h
===================================================================
RCS file: /home/wine/wine/include/winsock.h,v
retrieving revision 1.34
diff -u -r1.34 winsock.h
--- include/winsock.h	2001/08/24 19:14:56	1.34
+++ include/winsock.h	2001/09/12 18:23:10
@@ -441,17 +441,6 @@
 
 #define WS_AF_MAX          27
 
-#include "pshpack1.h"
-
-struct ws_sockaddr_ipx
-{
-	SHORT		sipx_family;
-	UINT		sipx_network;
-	CHAR		sipx_node[6];
-	WORD		sipx_port;
-};
-
-#include "poppack.h"
 
 #ifdef __cplusplus
 }
Index: include/wsipx.h
===================================================================
RCS file: /home/wine/wine/include/wsipx.h,v
retrieving revision 1.1
diff -u -r1.1 wsipx.h
--- include/wsipx.h	2001/01/12 23:15:55	1.1
+++ include/wsipx.h	2001/09/12 18:23:10
@@ -1,13 +1,21 @@
 /* WCIPX.H
  */
 
-#ifndef _WINE_WCIPX_
-#define _WINE_WCIPX_
+#ifndef _WINE_WSIPX_
+#define _WINE_WSIPX_
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* defined(__cplusplus) */
 
+typedef struct ws_sockaddr_ipx
+{
+    short sa_family;
+    char sa_netnum[4];
+    char sa_nodenum[6];
+    unsigned short sa_socket;
+} SOCKADDR_IPX, *PSOCKADDR_IPX, *LPSOCKADDR_IPX;
+
 /*
  * constants
  */
@@ -20,4 +28,4 @@
 }      /* extern "C" */
 #endif /* defined(__cplusplus) */
 
-#endif /* _WINE_WCIPX_ */
+#endif /* _WINE_WSIPX_ */
Index: dlls/winsock/socket.c
===================================================================
RCS file: /home/wine/wine/dlls/winsock/socket.c,v
retrieving revision 1.60
diff -u -r1.60 socket.c
--- dlls/winsock/socket.c	2001/09/07 15:26:18	1.60
+++ dlls/winsock/socket.c	2001/09/12 18:22:55
@@ -91,6 +91,7 @@
 #include "wingdi.h"
 #include "winuser.h"
 #include "winsock2.h"
+#include "wsipx.h"
 #include "wine/winsock16.h"
 #include "winnt.h"
 #include "heap.h"
@@ -153,6 +154,7 @@
 int WS_dup_he(struct hostent* p_he, int flag);
 int WS_dup_pe(struct protoent* p_pe, int flag);
 int WS_dup_se(struct servent* p_se, int flag);
+int WINAPI WSOCK32_getpeername(SOCKET s, ws_sockaddr *name, int *namelen);
 
 typedef void	WIN_hostent;
 typedef void	WIN_protoent;
@@ -736,10 +738,13 @@
 
 /* ----------------------------------- i/o APIs */
 
-/***********************************************************************
- *		accept		(WS2_32.1)
- */
-static void WSOCK32_async_accept(SOCKET s, SOCKET as)
+#ifdef HAVE_IPX
+#define SUPPORTED_PF(pf) ((pf)==AF_INET || (pf)== AF_IPX)
+#else
+#define SUPPORTED_PF(pf) ((pf)==AF_INET)
+#endif
+
+static void ws2_async_accept(SOCKET s, SOCKET as)
 {
     int q;
     /* queue socket for WSAAsyncSelect */
@@ -755,13 +760,131 @@
 }
 
 /**********************************************************************/
+
+/* Returns the converted address if successful, NULL if it was too small to 
+ * start with. Note that the returned pointer may be the original pointer 
+ * if no conversion is necessary.
+ */
+const struct sockaddr* ws_sockaddr_ws2u(const ws_sockaddr* wsaddr, int wsaddrlen, int *uaddrlen)
+{
+    switch (wsaddr->sa_family)
+    {
+#ifdef HAVE_IPX
+    case WS_AF_IPX:
+        {
+            struct ws_sockaddr_ipx* wsipx=(struct ws_sockaddr_ipx*)wsaddr;
+            struct sockaddr_ipx* uipx;
+
+            if (wsaddrlen<sizeof(struct ws_sockaddr_ipx))
+                return NULL;
+
+            *uaddrlen=sizeof(struct sockaddr_ipx);
+            uipx=malloc(*uaddrlen);
+            uipx->sipx_family=AF_IPX;
+            uipx->sipx_port=wsipx->sa_socket;
+            /* copy sa_netnum and sa_nodenum to sipx_network and sipx_node 
+             * in one go
+             */
+            memcpy(&uipx->sipx_network,wsipx->sa_netnum,sizeof(uipx->sipx_network)+sizeof(uipx->sipx_node));
+            uipx->sipx_type=IPX_FRAME_NONE;
+            uipx->sipx_zero=0;
+            return (const struct sockaddr*)uipx;
+        }
+#endif
+
+    default:
+        if (wsaddrlen<sizeof(ws_sockaddr))
+            return NULL;
+
+        /* No conversion needed, just return the original address */
+        *uaddrlen=wsaddrlen;
+        return (const struct sockaddr*)wsaddr;
+    }
+    return NULL;
+}
 
-SOCKET WINAPI WSOCK32_accept(SOCKET s, struct sockaddr *addr,
-                                 INT *addrlen32)
+/* allocates a Unix sockaddr structure to receive the data */
+inline struct sockaddr* ws_sockaddr_alloc(const ws_sockaddr* wsaddr, int* wsaddrlen, int* uaddrlen)
 {
+    if (*wsaddrlen==0)
+        *uaddrlen=0;
+    else
+        *uaddrlen=max(sizeof(struct sockaddr),*wsaddrlen);
+    if (wsaddr==NULL)
+        return NULL;
+
+    return malloc(*uaddrlen);
+}
+
+/* Returns 0 if successful, -1 if the buffer is too small */
+int ws_sockaddr_u2ws(const struct sockaddr* uaddr, int uaddrlen, ws_sockaddr* wsaddr, int* wsaddrlen)
+{
+    int res;
+
+    switch(uaddr->sa_family)
+    {
 #ifdef HAVE_IPX
-    struct ws_sockaddr_ipx*  addr2 = (struct ws_sockaddr_ipx *)addr;
+    case AF_IPX:
+        {
+            struct sockaddr_ipx* uipx=(struct sockaddr_ipx*)uaddr;
+            struct ws_sockaddr_ipx* wsipx=(struct ws_sockaddr_ipx*)wsaddr;
+
+            res=-1;
+            switch (*wsaddrlen) /* how much can we copy? */
+            {
+            default:
+                res=0; /* enough */
+                wsipx->sa_socket=uipx->sipx_port;
+                /* fall through */
+            case 13:
+            case 12:
+                memcpy(wsipx->sa_nodenum,uipx->sipx_node,sizeof(wsipx->sa_nodenum));
+                /* fall through */
+            case 11:
+            case 10:
+            case 9:
+            case 8:
+            case 7:
+            case 6:
+                memcpy(wsipx->sa_netnum,&uipx->sipx_network,sizeof(wsipx->sa_netnum));
+                /* fall through */
+            case 5:
+            case 4:
+            case 3:
+            case 2:
+                wsipx->sa_family=AF_IPX;
+                /* fall through */
+            case 1:
+            case 0:
+                /* way too small */
+            }
+        }
+        break;
 #endif
+
+    default:
+        /* No conversion needed */
+        memcpy(wsaddr,uaddr,*wsaddrlen);
+        res=(*wsaddrlen<uaddrlen?-1:0);
+    }
+    return res;
+}
+
+/* to be called to free the memory allocated by ws_sockaddr_ws2u or 
+ * ws_sockaddr_alloc
+ */
+inline void ws_sockaddr_free(const struct sockaddr* uaddr, const ws_sockaddr* wsaddr)
+{
+    if (uaddr!=NULL && uaddr!=(const struct sockaddr*)wsaddr)
+        free((void*)uaddr);
+}
+
+/***********************************************************************
+ *		accept		(WS2_32.1)
+ */
+SOCKET WINAPI WSOCK32_accept(SOCKET s, ws_sockaddr *addr,
+                                 int *addrlen32)
+{
     int fd = _get_sock_fd(s);
 
     TRACE("socket %04x\n", (UINT16)s );
@@ -790,37 +913,23 @@
 	if (as)
 	{
 	    unsigned omask = _get_sock_mask( s );
-	    int fd = _get_sock_fd( as );
-	    if( getpeername(fd, addr, addrlen32) != -1 )
-	    {
-#ifdef HAVE_IPX
-		if (addr && ((struct sockaddr_ipx *)addr)->sipx_family == AF_IPX) {
-		    addr = (struct sockaddr *)
-				malloc(addrlen32 ? *addrlen32 : sizeof(*addr2));
-		    memcpy(addr, addr2,
-				addrlen32 ? *addrlen32 : sizeof(*addr2));
-		    addr2->sipx_family = WS_AF_IPX;
-		    addr2->sipx_network = ((struct sockaddr_ipx *)addr)->sipx_network;
-		    addr2->sipx_port = ((struct sockaddr_ipx *)addr)->sipx_port;
-		    memcpy(addr2->sipx_node,
-			((struct sockaddr_ipx *)addr)->sipx_node, IPX_NODE_LEN);
-		    free(addr);
-		}
-#endif
-	    } else SetLastError(wsaErrno());
-	    close(fd);
+	    WSOCK32_getpeername(fd, addr, addrlen32);
 	    if (omask & FD_WINE_SERVEVENT)
-		WSOCK32_async_accept(s, as);
+		ws2_async_accept(s, as);
 	    return as;
 	}
     }
+    else
+    {
+        SetLastError(WSAENOTSOCK);
+    }
     return INVALID_SOCKET;
 }
 
 /***********************************************************************
  *              accept		(WINSOCK.1)
  */
-SOCKET16 WINAPI WINSOCK_accept16(SOCKET16 s, struct sockaddr* addr,
+SOCKET16 WINAPI WINSOCK_accept16(SOCKET16 s, ws_sockaddr* addr,
                                  INT16* addrlen16 )
 {
     INT addrlen32 = addrlen16 ? *addrlen16 : 0;
@@ -832,80 +941,73 @@
 /***********************************************************************
  *		bind			(WS2_32.2)
  */
-INT WINAPI WSOCK32_bind(SOCKET s, struct sockaddr *name, INT namelen)
+int WINAPI WSOCK32_bind(SOCKET s, const ws_sockaddr* name, int namelen)
 {
-#ifdef HAVE_IPX
-    struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
-#endif
     int fd = _get_sock_fd(s);
+    int res;
 
-    TRACE("socket %04x, ptr %8x, length %d\n", s, (int) name, namelen);
+    TRACE("socket %04x, ptr %p, length %d\n", s, name, namelen);
 #if DEBUG_SOCKADDR
     dump_sockaddr(name);
 #endif
 
+    res=SOCKET_ERROR;
     if (fd != -1)
     {
-      /* FIXME: what family does this really map to on the Unix side? */
-      if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP)
-	((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC;
-#ifdef HAVE_IPX
-      else if (name &&
-		((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_IPX)
-      {
-	name = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx));
-	memset(name, '\0', sizeof(struct sockaddr_ipx));
-	((struct sockaddr_ipx *)name)->sipx_family = AF_IPX;
-	((struct sockaddr_ipx *)name)->sipx_port = name2->sipx_port;
-	((struct sockaddr_ipx *)name)->sipx_network = name2->sipx_network;
-	memcpy(((struct sockaddr_ipx *)name)->sipx_node,
-		name2->sipx_node, IPX_NODE_LEN);
-	namelen = sizeof(struct sockaddr_ipx);
-      }
-#endif
-      if ( namelen >= sizeof(*name) ) 
-      {
-	if ( name && (((struct ws_sockaddr_in *)name)->sin_family == AF_INET
-#ifdef HAVE_IPX
-             || ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX
-#endif
-           ))
+        if (!name || !SUPPORTED_PF(name->sa_family))
         {
-	  if ( bind(fd, name, namelen) < 0 ) 
-	  {
-	     int	loc_errno = errno;
-	     WARN("\tfailure - errno = %i\n", errno);
-	     errno = loc_errno;
-	     switch(errno)
-	     {
-		case EBADF: SetLastError(WSAENOTSOCK); break;
-		case EADDRNOTAVAIL: SetLastError(WSAEINVAL); break;
-		default: SetLastError(wsaErrno());break;
-	     }
-	  }
-	  else {
-#ifdef HAVE_IPX
-	    if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
-		free(name);
-#endif
-	    close(fd);
-	    return 0; /* success */
-	  }
-        } else SetLastError(WSAEAFNOSUPPORT);
-      } else SetLastError(WSAEFAULT);
-#ifdef HAVE_IPX
-      if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
-	free(name);
-#endif
-      close(fd);
+            SetLastError(WSAEAFNOSUPPORT);
+        }
+        else
+        {
+            const struct sockaddr* uaddr;
+            int uaddrlen;
+
+            uaddr=ws_sockaddr_ws2u(name,namelen,&uaddrlen);
+            if (uaddr == NULL)
+            {
+                SetLastError(WSAEFAULT);
+            }
+            else
+            {
+                if (bind(fd, uaddr, uaddrlen) < 0)
+                {
+                    int loc_errno = errno;
+                    WARN("\tfailure - errno = %i\n", errno);
+                    errno = loc_errno;
+                    switch (errno)
+                    {
+                    case EBADF:
+                        SetLastError(WSAENOTSOCK);
+                        break;
+                    case EADDRNOTAVAIL:
+                        SetLastError(WSAEINVAL);
+                        break;
+                    default:
+                        SetLastError(wsaErrno());
+                        break;
+                    }
+                }
+                else
+                {
+                    res=0; /* success */
+                }
+                ws_sockaddr_free(uaddr,name);
+            }
+        }
+        close(fd);
     }
-    return SOCKET_ERROR;
+    else
+    {
+        SetLastError(WSAENOTSOCK);
+    }
+    return res;
 }
 
 /***********************************************************************
  *              bind			(WINSOCK.2)
  */
-INT16 WINAPI WINSOCK_bind16(SOCKET16 s, struct sockaddr *name, INT16 namelen)
+INT16 WINAPI WINSOCK_bind16(SOCKET16 s, ws_sockaddr *name, INT16 namelen)
 {
   return (INT16)WSOCK32_bind( s, name, namelen );
 }
@@ -931,89 +1033,85 @@
 /***********************************************************************
  *		connect		(WS2_32.4)
  */
-INT WINAPI WSOCK32_connect(SOCKET s, struct sockaddr *name, INT namelen)
+int WINAPI WSOCK32_connect(SOCKET s, const ws_sockaddr* name, int namelen)
 {
-#ifdef HAVE_IPX
-  struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
-#endif
-  int fd = _get_sock_fd(s);
+    int fd = _get_sock_fd(s);
 
-  TRACE("socket %04x, ptr %8x, length %d\n", s, (int) name, namelen);
+    TRACE("socket %04x, ptr %p, length %d\n", s, name, namelen);
 #if DEBUG_SOCKADDR
-  dump_sockaddr(name);
+    dump_sockaddr(name);
 #endif
 
-  if (fd != -1)
-  {
-    if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_PUP)
-	((struct ws_sockaddr_ipx *)name)->sipx_family = AF_UNSPEC;
-#ifdef HAVE_IPX
-    else if (name && ((struct ws_sockaddr_ipx *)name)->sipx_family == WS_AF_IPX)
-    {
-	name = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx));
-	memset(name, '\0', sizeof(struct sockaddr_ipx));
-	((struct sockaddr_ipx *)name)->sipx_family = AF_IPX;
-	((struct sockaddr_ipx *)name)->sipx_port = name2->sipx_port;
-	((struct sockaddr_ipx *)name)->sipx_network = name2->sipx_network;
-	memcpy(((struct sockaddr_ipx *)name)->sipx_node,
-		name2->sipx_node, IPX_NODE_LEN);
-	namelen = sizeof(struct sockaddr_ipx);
-    }
-#endif
-    if (connect(fd, name, namelen) == 0) {
-	close(fd);
-	goto connect_success;
-    }
-    if (errno == EINPROGRESS)
+    if (fd != -1)
     {
-	/* tell wineserver that a connection is in progress */
-	_enable_event(s, FD_CONNECT|FD_READ|FD_WRITE,
-		      FD_CONNECT|FD_READ|FD_WRITE,
-		      FD_WINE_CONNECTED|FD_WINE_LISTENING);
-	if (_is_blocking(s))
-	{
-	    int result;
-	    /* block here */
-	    do_block(fd, 7);
-	    _sync_sock_state(s); /* let wineserver notice connection */
-	    /* retrieve any error codes from it */
-	    result = _get_sock_error(s, FD_CONNECT_BIT);
-	    if (result)
-		SetLastError(result);
-	    else {
-		close(fd);
-		goto connect_success;
-	    }
-	}
-	else SetLastError(WSAEWOULDBLOCK);
-	close(fd);
+        const struct sockaddr* uaddr;
+        int uaddrlen;
+
+        uaddr=ws_sockaddr_ws2u(name,namelen,&uaddrlen);
+        if (uaddr == NULL)
+        {
+            SetLastError(WSAEFAULT);
+        }
+        else
+        {
+            int rc;
+
+            rc=connect(fd, uaddr, uaddrlen);
+            ws_sockaddr_free(uaddr,name);
+            if (rc == 0)
+                goto connect_success;
+        }
+
+        if (errno == EINPROGRESS)
+        {
+            /* tell wineserver that a connection is in progress */
+            _enable_event(s, FD_CONNECT|FD_READ|FD_WRITE,
+                          FD_CONNECT|FD_READ|FD_WRITE,
+                          FD_WINE_CONNECTED|FD_WINE_LISTENING);
+            if (_is_blocking(s))
+            {
+                int result;
+                /* block here */
+                do_block(fd, 7);
+                _sync_sock_state(s); /* let wineserver notice connection */
+                /* retrieve any error codes from it */
+                result = _get_sock_error(s, FD_CONNECT_BIT);
+                if (result)
+                    SetLastError(result);
+                else
+                {
+                    goto connect_success;
+                }
+            }
+            else
+            {
+                SetLastError(WSAEWOULDBLOCK);
+            }
+        }
+        else
+        {
+            SetLastError(wsaErrno());
+        }
+        close(fd);
     }
     else
     {
-	SetLastError(wsaErrno());
-	close(fd);
+        SetLastError(WSAENOTSOCK);
     }
-  }
-#ifdef HAVE_IPX
-  if (name && ((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
-    free(name);
-#endif
-  return SOCKET_ERROR;
+    return SOCKET_ERROR;
+
 connect_success:
-#ifdef HAVE_IPX
-    if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX)
-	free(name);
-#endif
+    close(fd);
     _enable_event(s, FD_CONNECT|FD_READ|FD_WRITE,
-		  FD_WINE_CONNECTED|FD_READ|FD_WRITE,
-		  FD_CONNECT|FD_WINE_LISTENING);
-    return 0; 
+                  FD_WINE_CONNECTED|FD_READ|FD_WRITE,
+                  FD_CONNECT|FD_WINE_LISTENING);
+    return 0;
 }
 
 /***********************************************************************
  *              connect               (WINSOCK.4)
  */
-INT16 WINAPI WINSOCK_connect16(SOCKET16 s, struct sockaddr *name, INT16 namelen)
+INT16 WINAPI WINSOCK_connect16(SOCKET16 s, ws_sockaddr *name, INT16 namelen)
 {
   return (INT16)WSOCK32_connect( s, name, namelen );
 }
@@ -1021,44 +1119,47 @@
 /***********************************************************************
  *		getpeername		(WS2_32.5)
  */
-INT WINAPI WSOCK32_getpeername(SOCKET s, struct sockaddr *name,
-                                   INT *namelen)
+int WINAPI WSOCK32_getpeername(SOCKET s, ws_sockaddr *name, int *namelen)
 {
-#ifdef HAVE_IPX
-    struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
-#endif
     int fd = _get_sock_fd(s);
+    int res;
+
+    TRACE("socket: %04x, ptr %p, len %8x\n", s, name, *namelen);
 
-    TRACE("socket: %04x, ptr %8x, ptr %8x\n", s, (int) name, *namelen);
+    res=SOCKET_ERROR;
     if (fd != -1)
     {
-	if (getpeername(fd, name, namelen) == 0) {
-#ifdef HAVE_IPX
-	    if (((struct ws_sockaddr_ipx *)name)->sipx_family == AF_IPX) {
-		name = (struct sockaddr *)
-				malloc(namelen ? *namelen : sizeof(*name2));
-		memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
-		name2->sipx_family = WS_AF_IPX;
-		name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
-		name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
-		memcpy(name2->sipx_node,
-			((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
-		free(name);
-	    }
-#endif
-	    close(fd);
-	    return 0; 
-	}
-	SetLastError(wsaErrno());
-	close(fd);
+        struct sockaddr* uaddr;
+        int uaddrlen;
+
+        uaddr=ws_sockaddr_alloc(name,namelen,&uaddrlen);
+        if (getpeername(fd, uaddr, &uaddrlen) != 0)
+        {
+            SetLastError(wsaErrno());
+        }
+        else if (ws_sockaddr_u2ws(uaddr,uaddrlen,name,namelen) != 0)
+        {
+            /* The buffer was too small */
+            SetLastError(WSAEFAULT);
+        }
+        else
+        {
+            res=0;
+        }
+        ws_sockaddr_free(uaddr,name);
+        close(fd);
     }
-    return SOCKET_ERROR;
+    else
+    {
+        SetLastError(WSAENOTSOCK);
+    }
+    return res;
 }
 
 /***********************************************************************
  *              getpeername		(WINSOCK.5)
  */
-INT16 WINAPI WINSOCK_getpeername16(SOCKET16 s, struct sockaddr *name,
+INT16 WINAPI WINSOCK_getpeername16(SOCKET16 s, ws_sockaddr *name,
                                    INT16 *namelen16)
 {
     INT namelen32 = *namelen16;
@@ -1075,44 +1176,46 @@
 /***********************************************************************
  *		getsockname		(WS2_32.6)
  */
-INT WINAPI WSOCK32_getsockname(SOCKET s, struct sockaddr *name,
-                                   INT *namelen)
+int WINAPI WSOCK32_getsockname(SOCKET s, ws_sockaddr *name, int *namelen)
 {
-#ifdef HAVE_IPX
-    struct ws_sockaddr_ipx*  name2 = (struct ws_sockaddr_ipx *)name;
-#endif
     int fd = _get_sock_fd(s);
+    int res;
+
+    TRACE("socket: %04x, ptr %p, len %8x\n", s, name, *namelen);
 
-    TRACE("socket: %04x, ptr %8x, ptr %8x\n", s, (int) name, (int) *namelen);
+    res=SOCKET_ERROR;
     if (fd != -1)
     {
-	if (getsockname(fd, name, namelen) == 0) {
-#ifdef HAVE_IPX
-	    if (((struct sockaddr_ipx *)name)->sipx_family == AF_IPX) {
-		name = (struct sockaddr *)
-				malloc(namelen ? *namelen : sizeof(*name2));
-		memcpy(name, name2, namelen ? *namelen : sizeof(*name2));
-		name2->sipx_family = WS_AF_IPX;
-		name2->sipx_network = ((struct sockaddr_ipx *)name)->sipx_network;
-		name2->sipx_port = ((struct sockaddr_ipx *)name)->sipx_port;
-		memcpy(name2->sipx_node,
-			((struct sockaddr_ipx *)name)->sipx_node, IPX_NODE_LEN);
-		free(name);
-	    }
-#endif
-	    close(fd);
-	    return 0; 
-	}
-	SetLastError(wsaErrno());
-	close(fd);
+        struct sockaddr* uaddr;
+        int uaddrlen;
+
+        uaddr=ws_sockaddr_alloc(name,namelen,&uaddrlen);
+        if (getsockname(fd, uaddr, &uaddrlen) != 0)
+        {
+            SetLastError(wsaErrno());
+        }
+        else if (ws_sockaddr_u2ws(uaddr,uaddrlen,name,namelen) != 0)
+        {
+            /* The buffer was too small */
+            SetLastError(WSAEFAULT);
+        }
+        else
+        {
+            res=0;
+        }
+        close(fd);
     }
-    return SOCKET_ERROR;
+    else
+    {
+        SetLastError(WSAENOTSOCK);
+    }
+    return res;
 }
 
 /***********************************************************************
  *              getsockname		(WINSOCK.6)
  */
-INT16 WINAPI WINSOCK_getsockname16(SOCKET16 s, struct sockaddr *name,
+INT16 WINAPI WINSOCK_getsockname16(SOCKET16 s, ws_sockaddr *name,
                                    INT16 *namelen16)
 {
     INT retVal;
@@ -1684,77 +1787,70 @@
 /***********************************************************************
  *		recvfrom		(WS2_32.17)
  */
-INT WINAPI WSOCK32_recvfrom(SOCKET s, char *buf, INT len, INT flags, 
-                                struct sockaddr *from, INT *fromlen32)
+int WINAPI WSOCK32_recvfrom(SOCKET s, char *buf, INT len, int flags,
+                                ws_sockaddr *from, int *fromlen)
 {
-#ifdef HAVE_IPX
-    struct ws_sockaddr_ipx*  from2 = (struct ws_sockaddr_ipx *)from;
-#endif
     int fd = _get_sock_fd(s);
+    int res;
 
     TRACE("socket %04x, ptr %08x, len %d, flags %d\n", s, (unsigned)buf, len, flags);
 #if DEBUG_SOCKADDR
-    if( from ) dump_sockaddr(from);
-    else DPRINTF("from = NULL\n");
+    if (from)
+        dump_sockaddr(from);
+    else
+        DPRINTF("from = NULL\n");
 #endif
 
+    res=SOCKET_ERROR;
     if (fd != -1)
     {
-	int length;
+        struct sockaddr* uaddr;
+        int uaddrlen;
+        int length;
 
-	if (_is_blocking(s))
-	{
-	    /* block here */
-	    /* FIXME: OOB and exceptfds */
-	    do_block(fd, 1);
-	}
-	if ((length = recvfrom(fd, buf, len, flags, from, fromlen32)) >= 0)
-	{
-	    TRACE(" -> %i bytes\n", length);
+        if (_is_blocking(s))
+        {
+            /* block here */
+            /* FIXME: OOB and exceptfds */
+            do_block(fd, 1);
+        }
 
-#ifdef HAVE_IPX
-	if (from && ((struct sockaddr_ipx *)from)->sipx_family == AF_IPX) {
-	    from = (struct sockaddr *)
-				malloc(fromlen32 ? *fromlen32 : sizeof(*from2));
-	    memcpy(from, from2, fromlen32 ? *fromlen32 : sizeof(*from2));
-	    from2->sipx_family = WS_AF_IPX;
-	    from2->sipx_network = ((struct sockaddr_ipx *)from)->sipx_network;
-	    from2->sipx_port = ((struct sockaddr_ipx *)from)->sipx_port;
-	    memcpy(from2->sipx_node,
-			((struct sockaddr_ipx *)from)->sipx_node, IPX_NODE_LEN);
-	    free(from);
-	}
-#endif
-	    close(fd);
-	    _enable_event(s, FD_READ, 0, 0);
-	    return length;
-	}
-	SetLastError(wsaErrno());
-	close(fd);
+        uaddr=ws_sockaddr_alloc(from,fromlen,&uaddrlen);
+        length=recvfrom(fd, buf, len, flags, uaddr, &uaddrlen);
+        if (length < 0)
+        {
+            SetLastError(wsaErrno());
+            WARN(" -> ERROR\n");
+        }
+        else if (ws_sockaddr_u2ws(uaddr,uaddrlen,from,fromlen) != 0)
+        {
+            /* The from buffer was too small, but we read the data 
+             * anyway. Is that really bad?
+             */
+            SetLastError(WSAEFAULT);
+            WARN(" -> WSAEFAULT\n");
+        }
+        else
+        {
+            TRACE(" -> %i bytes\n", length);
+            _enable_event(s, FD_READ, 0, 0);
+            res=length;
+        }
+        close(fd);
     }
-    else SetLastError(WSAENOTSOCK);
-    WARN(" -> ERROR\n");
-#ifdef HAVE_IPX
-    if (from && ((struct sockaddr_ipx *)from)->sipx_family == AF_IPX) {
-	from = (struct sockaddr *)
-				malloc(fromlen32 ? *fromlen32 : sizeof(*from2));
-	memcpy(from, from2, fromlen32 ? *fromlen32 : sizeof(*from2));
-	from2->sipx_family = WS_AF_IPX;
-	from2->sipx_network = ((struct sockaddr_ipx *)from)->sipx_network;
-	from2->sipx_port = ((struct sockaddr_ipx *)from)->sipx_port;
-	memcpy(from2->sipx_node,
-		((struct sockaddr_ipx *)from)->sipx_node, IPX_NODE_LEN);
-	free(from);
+    else
+    {
+        SetLastError(WSAENOTSOCK);
+        WARN(" -> WSAENOTSOCK\n");
     }
-#endif
-    return SOCKET_ERROR;
+    return res;
 }
 
 /***********************************************************************
  *              recvfrom		(WINSOCK.17)
  */
 INT16 WINAPI WINSOCK_recvfrom16(SOCKET16 s, char *buf, INT16 len, INT16 flags,
-                                struct sockaddr *from, INT16 *fromlen16)
+                                ws_sockaddr *from, INT16 *fromlen16)
 {
     INT fromlen32;
     INT *p = &fromlen32;
@@ -1943,72 +2043,56 @@
 /***********************************************************************
  *		sendto		(WS2_32.20)
  */
-INT WINAPI WSOCK32_sendto(SOCKET s, char *buf, INT len, INT flags,
-                              struct sockaddr *to, INT tolen)
+int WINAPI WSOCK32_sendto(SOCKET s, const char *buf, int len, int flags,
+                              const ws_sockaddr *to, int tolen)
 {
-#ifdef HAVE_IPX
-    struct ws_sockaddr_ipx*  to2 = (struct ws_sockaddr_ipx *)to;
-#endif
     int fd = _get_sock_fd(s);
+    int res;
 
     TRACE("socket %04x, ptr %p, length %d, flags %d\n", s, buf, len, flags);
+
+    res=SOCKET_ERROR;
     if (fd != -1)
     {
-	INT	length;
+        const struct sockaddr* uaddr;
+        int uaddrlen;
 
-	if (to && ((struct ws_sockaddr_ipx *)to)->sipx_family == WS_AF_PUP)
-	    ((struct ws_sockaddr_ipx *)to)->sipx_family = AF_UNSPEC;
-#ifdef HAVE_IPX
-	else if (to &&
-		((struct ws_sockaddr_ipx *)to)->sipx_family == WS_AF_IPX)
-	{
-	    to = (struct sockaddr *) malloc(sizeof(struct sockaddr_ipx));
-	    memset(to, '\0', sizeof(struct sockaddr_ipx));
-	    ((struct sockaddr_ipx *)to)->sipx_family = AF_IPX;
-	    ((struct sockaddr_ipx *)to)->sipx_port = to2->sipx_port;
-	    ((struct sockaddr_ipx *)to)->sipx_network = to2->sipx_network;
-	    memcpy(((struct sockaddr_ipx *)to)->sipx_node,
-			to2->sipx_node, IPX_NODE_LEN);
-	    tolen = sizeof(struct sockaddr_ipx);
-	}
-#endif
-	if (_is_blocking(s))
-	{
-	    /* block here */
-	    /* FIXME: exceptfds */
-	    do_block(fd, 2);
-	}
-	if ((length = sendto(fd, buf, len, flags, to, tolen)) < 0 )
-	{
-	    SetLastError(wsaErrno());
-	    if( GetLastError() == WSAEWOULDBLOCK )
-		_enable_event(s, FD_WRITE, 0, 0);
-	} 
-	else {
-#ifdef HAVE_IPX
-	    if (to && ((struct sockaddr_ipx *)to)->sipx_family == AF_IPX) {
-		free(to);
-	    }
-#endif
-	    close(fd);
-	    return length;
-	}
-	close(fd);
+        uaddr=ws_sockaddr_ws2u(to,tolen,&uaddrlen);
+        if (uaddr == NULL)
+        {
+            SetLastError(WSAEFAULT);
+        }
+        else
+        {
+            if (_is_blocking(s))
+            {
+                /* block here */
+                /* FIXME: exceptfds */
+                do_block(fd, 2);
+            }
+            res=sendto(fd, buf, len, flags, uaddr, uaddrlen);
+            if (res < 0 )
+            {
+                SetLastError(wsaErrno());
+                if( GetLastError() == WSAEWOULDBLOCK )
+                    _enable_event(s, FD_WRITE, 0, 0);
+            }
+            ws_sockaddr_free(uaddr,to);
+        }
+        close(fd);
     }
-    else SetLastError(WSAENOTSOCK);
-#ifdef HAVE_IPX
-    if (to && ((struct sockaddr_ipx *)to)->sipx_family == AF_IPX) {
-	free(to);
+    else
+    {
+        SetLastError(WSAENOTSOCK);
     }
-#endif
-    return SOCKET_ERROR;
+    return res;
 }
 
 /***********************************************************************
  *              sendto		(WINSOCK.20)
  */
 INT16 WINAPI WINSOCK_sendto16(SOCKET16 s, char *buf, INT16 len, INT16 flags,
-                              struct sockaddr *to, INT16 tolen)
+                              ws_sockaddr *to, INT16 tolen)
 {
     return (INT16)WSOCK32_sendto( s, buf, len, flags, to, tolen );
 }


More information about the wine-devel mailing list