Added mapping between unix and windows sockaddr_in6(_old) and

sockaddr_in. Added address family, socket type mappers.
This commit is contained in:
Marcus Meissner 2005-11-16 11:21:57 +00:00 committed by Alexandre Julliard
parent f5af18f05f
commit aa730cc9e4
2 changed files with 203 additions and 39 deletions

View File

@ -3,6 +3,7 @@
* (ftp.microsoft.com:/Advsys/winsock/spec11/WINSOCK.TXT)
*
* Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
* Copyright (C) 2005 Marcus Meissner
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -285,6 +286,34 @@ static const int ws_ip_map[][2] =
{ 0, 0 }
};
static const int ws_af_map[][2] =
{
MAP_OPTION( AF_INET ),
MAP_OPTION( AF_INET6 ),
#ifdef HAVE_IPX
MAP_OPTION( AF_IPX ),
#endif
{ 0, 0 }
};
static const int ws_socktype_map[][2] =
{
MAP_OPTION( SOCK_DGRAM ),
MAP_OPTION( SOCK_STREAM ),
MAP_OPTION( SOCK_RAW ),
{ 0, 0 }
};
static const int ws_proto_map[][2] =
{
MAP_OPTION( IPPROTO_TCP ),
MAP_OPTION( IPPROTO_UDP ),
MAP_OPTION( IPPROTO_ICMP ),
MAP_OPTION( IPPROTO_IGMP ),
MAP_OPTION( IPPROTO_RAW ),
{ 0, 0 }
};
inline static DWORD NtStatusToWSAError( const DWORD status )
{
/* We only need to cover the status codes set by server async request handling */
@ -658,6 +687,73 @@ static inline int do_block( int fd, int events, int timeout )
return pfd.revents;
}
static int
convert_af_w2u(int windowsaf) {
int i;
for (i=0;ws_af_map[i][0];i++)
if (ws_af_map[i][0] == windowsaf)
return ws_af_map[i][1];
FIXME("unhandled Windows address family %d\n", windowsaf);
return -1;
}
static int
convert_af_u2w(int unixaf) {
int i;
for (i=0;ws_af_map[i][0];i++)
if (ws_af_map[i][1] == unixaf)
return ws_af_map[i][0];
FIXME("unhandled UNIX address family %d\n", unixaf);
return -1;
}
static int
convert_proto_w2u(int windowsproto) {
int i;
for (i=0;ws_proto_map[i][0];i++)
if (ws_proto_map[i][0] == windowsproto)
return ws_proto_map[i][1];
FIXME("unhandled Windows socket protocol %d\n", windowsproto);
return -1;
}
static int
convert_proto_u2w(int unixproto) {
int i;
for (i=0;ws_proto_map[i][0];i++)
if (ws_proto_map[i][1] == unixproto)
return ws_proto_map[i][0];
if (unixproto == 0) /* 0 is ok too as wild card */
return 0;
FIXME("unhandled UNIX socket protocol %d\n", unixproto);
return -1;
}
static int
convert_socktype_w2u(int windowssocktype) {
int i;
for (i=0;ws_socktype_map[i][0];i++)
if (ws_socktype_map[i][0] == windowssocktype)
return ws_socktype_map[i][1];
FIXME("unhandled Windows socket type %d\n", windowssocktype);
return -1;
}
static int
convert_socktype_u2w(int unixsocktype) {
int i;
for (i=0;ws_socktype_map[i][0];i++)
if (ws_socktype_map[i][1] == unixsocktype)
return ws_socktype_map[i][0];
FIXME("unhandled UNIX socket type %d\n", unixsocktype);
return -1;
}
/* ----------------------------------- API -----
*
@ -803,14 +899,53 @@ static const struct sockaddr* ws_sockaddr_ws2u(const struct WS_sockaddr* wsaddr,
return (const struct sockaddr*)uipx;
}
#endif
case WS_AF_INET6: {
struct sockaddr_in6* uin6;
const struct WS_sockaddr_in6* win6 = (struct WS_sockaddr_in6*)wsaddr;
const struct WS_sockaddr_in6_old* win6old = (struct WS_sockaddr_in6_old*)wsaddr;
default:
if (wsaddrlen<sizeof(struct WS_sockaddr))
/* Note: Windows has 2 versions of the sockaddr_in6 struct, one with
* scope_id, one without. Check:
* http://msdn.microsoft.com/library/en-us/winsock/winsock/sockaddr_2.asp
*/
if (wsaddrlen==sizeof(struct WS_sockaddr_in6_old)) {
*uaddrlen=sizeof(struct sockaddr_in6);
uin6=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *uaddrlen);
uin6->sin6_family = AF_INET6;
uin6->sin6_port = win6old->sin6_port;
uin6->sin6_flowinfo = win6old->sin6_flowinfo;
memcpy(&uin6->sin6_addr,&win6old->sin6_addr,16); /* 16 bytes = 128 address bits */
return (const struct sockaddr*)uin6;
}
if (wsaddrlen>=sizeof(struct WS_sockaddr_in6)) {
*uaddrlen=sizeof(struct sockaddr_in6);
uin6=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *uaddrlen);
uin6->sin6_family = AF_INET6;
uin6->sin6_port = win6->sin6_port;
uin6->sin6_flowinfo = win6->sin6_flowinfo;
uin6->sin6_scope_id = win6->sin6_scope_id;
memcpy(&uin6->sin6_addr,&win6->sin6_addr,16); /* 16 bytes = 128 address bits */
return (const struct sockaddr*)uin6;
}
FIXME("bad size %d for WS_sockaddr_in6\n",wsaddrlen);
return NULL;
}
case WS_AF_INET: {
struct sockaddr_in* uin;
const struct WS_sockaddr_in* win = (struct WS_sockaddr_in*)wsaddr;
if (wsaddrlen<sizeof(struct WS_sockaddr_in))
return NULL;
/* No conversion needed, just return the original address */
*uaddrlen=wsaddrlen;
return (const struct sockaddr*)wsaddr;
*uaddrlen=sizeof(struct sockaddr_in);
uin = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *uaddrlen);
uin->sin_family = AF_INET;
uin->sin_port = win->sin_port;
memcpy(&uin->sin_addr,&win->sin_addr,4); /* 4 bytes = 32 address bits */
return (const struct sockaddr*)uin;
}
default:
FIXME("Unknown address family %d, return NULL.\n", wsaddr->sa_family);
return NULL;
}
}
@ -882,16 +1017,47 @@ static int ws_sockaddr_u2ws(const struct sockaddr* uaddr, int uaddrlen, struct W
}
break;
#endif
case AF_INET6: {
const struct sockaddr_in6* uin6 = (struct sockaddr_in6*)uaddr;
struct WS_sockaddr_in6* win6 = (struct WS_sockaddr_in6*)wsaddr;
struct WS_sockaddr_in6_old* win6old = (struct WS_sockaddr_in6_old*)wsaddr;
default:
/* No conversion needed */
memcpy(wsaddr,uaddr,*wsaddrlen);
if (*wsaddrlen<uaddrlen) {
res=-1;
} else {
*wsaddrlen=uaddrlen;
res=0;
if (*wsaddrlen < sizeof(struct WS_sockaddr_in6_old))
return -1;
if (*wsaddrlen == sizeof(struct WS_sockaddr_in6_old)) {
win6old->sin6_family = WS_AF_INET6;
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);
return 0;
}
if (*wsaddrlen >= sizeof(struct WS_sockaddr_in6)) {
win6->sin6_family = WS_AF_INET6;
win6->sin6_port = uin6->sin6_port;
win6->sin6_flowinfo = uin6->sin6_flowinfo;
memcpy(&win6->sin6_addr,&uin6->sin6_addr,16); /* 16 bytes = 128 address bits */
win6->sin6_scope_id = uin6->sin6_scope_id;
*wsaddrlen = sizeof(struct WS_sockaddr_in6);
return 0;
}
return 0;
}
case AF_INET: {
struct sockaddr_in* uin = (struct sockaddr_in*)uaddr;
struct WS_sockaddr_in* win = (struct WS_sockaddr_in*)wsaddr;
if (*wsaddrlen < sizeof(struct WS_sockaddr_in))
return -1;
win->sin_family = WS_AF_INET;
win->sin_port = uin->sin_port;
memcpy(&win->sin_addr,&uin->sin_addr,4); /* 4 bytes = 32 address bits */
*wsaddrlen = sizeof(struct WS_sockaddr_in6);
return 0;
}
default:
FIXME("Unknown address family %d\n", uaddr->sa_family);
return -1;
}
return res;
}
@ -3123,35 +3289,21 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol,
return ret;
}
/* check the socket family */
switch(af)
/* check and convert the socket family */
af = convert_af_w2u(af);
if (af == -1)
{
#ifdef HAVE_IPX
case WS_AF_IPX: af = AF_IPX;
#endif
case AF_INET:
case AF_UNSPEC:
break;
default:
SetLastError(WSAEAFNOSUPPORT);
return INVALID_SOCKET;
FIXME("Unsupported socket family %d!\n", af);
SetLastError(WSAEAFNOSUPPORT);
return INVALID_SOCKET;
}
/* check the socket type */
switch(type)
type = convert_socktype_w2u(type);
if (type == -1)
{
case WS_SOCK_STREAM:
type=SOCK_STREAM;
break;
case WS_SOCK_DGRAM:
type=SOCK_DGRAM;
break;
case WS_SOCK_RAW:
type=SOCK_RAW;
break;
default:
SetLastError(WSAESOCKTNOSUPPORT);
return INVALID_SOCKET;
SetLastError(WSAESOCKTNOSUPPORT);
return INVALID_SOCKET;
}
/* check the protocol type */

View File

@ -84,19 +84,31 @@ typedef struct WS(in_addr6)
u_char s6_addr[16]; /* IPv6 address */
} IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR;
/* check for sockaddr_in6 / sockaddr_in6_old madness:
* http://msdn.microsoft.com/library/en-us/winsock/winsock/sockaddr_2.asp
*/
typedef struct WS(sockaddr_in6)
{
short sin6_family; /* AF_INET6 */
u_short sin6_port; /* Transport level port number */
u_long sin6_flowinfo; /* IPv6 flow information */
struct WS(in_addr6) sin6_addr; /* IPv6 address */
u_long sin6_scope_id; /* IPv6 scope id */
} SOCKADDR_IN6,*PSOCKADDR_IN6, *LPSOCKADDR_IN6;
typedef struct WS(sockaddr_in6_old)
{
short sin6_family; /* AF_INET6 */
u_short sin6_port; /* Transport level port number */
u_long sin6_flowinfo; /* IPv6 flow information */
struct WS(in_addr6) sin6_addr; /* IPv6 address */
} SOCKADDR_IN6_OLD,*PSOCKADDR_IN6_OLD, *LPSOCKADDR_IN6_OLD;
typedef union sockaddr_gen
{
struct WS(sockaddr) Address;
struct WS(sockaddr_in) AddressIn;
struct WS(sockaddr_in6) AddressIn6;
struct WS(sockaddr_in6_old) AddressIn6;
} WS(sockaddr_gen);
/* Structure to keep interface specific information */