/*
* based on Windows Sockets 1.1 specs
- * (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
- * Copyright (C) 2006 Kai Blin
+ * Copyright (C) 2006-2008 Kai Blin
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
-/* critical section to protect some non-rentrant net function */
+/* critical section to protect some non-reentrant net function */
extern CRITICAL_SECTION csWSgetXXXbyYYY;
union generic_unix_sockaddr
#ifdef HAVE_IPX
MAP_OPTION( AF_IPX ),
#endif
+ {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
};
static const int ws_socktype_map[][2] =
MAP_OPTION( SOCK_DGRAM ),
MAP_OPTION( SOCK_STREAM ),
MAP_OPTION( SOCK_RAW ),
+ {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
};
static const int ws_proto_map[][2] =
MAP_OPTION( IPPROTO_ICMP ),
MAP_OPTION( IPPROTO_IGMP ),
MAP_OPTION( IPPROTO_RAW ),
+ {FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO},
};
static const int ws_aiflag_map[][2] =
*/
};
+static const int ws_niflag_map[][2] =
+{
+ MAP_OPTION( NI_NOFQDN ),
+ MAP_OPTION( NI_NUMERICHOST ),
+ MAP_OPTION( NI_NAMEREQD ),
+ MAP_OPTION( NI_NUMERICSERV ),
+ MAP_OPTION( NI_DGRAM ),
+};
+
static const int ws_eai_map[][2] =
{
MAP_OPTION( EAI_AGAIN ),
{ 0, 0 }
};
+static const char magic_loopback_addr[] = {127, 12, 34, 56};
+
static inline DWORD NtStatusToWSAError( const DWORD status )
{
/* We only need to cover the status codes set by server async request handling */
return 0;
}
-static inline BOOL is_timeout_option( int optname )
-{
-#ifdef SO_RCVTIMEO
- if (optname == SO_RCVTIMEO) return TRUE;
-#endif
-#ifdef SO_SNDTIMEO
- if (optname == SO_SNDTIMEO) return TRUE;
-#endif
- return FALSE;
-}
-
/* ----------------------------------- Per-thread info (or per-process?) */
static char *strdup_lower(const char *str)
return 0;
uaddrlen = sizeof(struct sockaddr_ipx);
+ memset( uaddr, 0, uaddrlen );
uipx->sipx_family=AF_IPX;
uipx->sipx_port=wsipx->sa_socket;
/* copy sa_netnum and sa_nodenum to sipx_network and sipx_node
const struct WS_sockaddr_in6* win6 = (const struct WS_sockaddr_in6*)wsaddr;
/* 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
+ * scope_id, one without.
*/
if (wsaddrlen >= sizeof(struct WS_sockaddr_in6_old)) {
uaddrlen = sizeof(struct sockaddr_in6);
+ memset( uaddr, 0, uaddrlen );
uin6->sin6_family = AF_INET6;
uin6->sin6_port = win6->sin6_port;
uin6->sin6_flowinfo = win6->sin6_flowinfo;
if (wsaddrlen<sizeof(struct WS_sockaddr_in))
return 0;
uaddrlen = sizeof(struct sockaddr_in);
+ memset( uaddr, 0, 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 */
if ( (n = recvmsg(fd, &hdr, *lpFlags)) == -1 )
return -1;
- if ( lpFrom &&
+ /* if this socket is connected and lpFrom is not NULL, Linux doesn't give us
+ * msg_name and msg_namelen from recvmsg, but it does set msg_namelen to zero.
+ *
+ * quoting linux 2.6 net/ipv4/tcp.c:
+ * "According to UNIX98, msg_name/msg_namelen are ignored
+ * on connected socket. I was just happy when found this 8) --ANK"
+ *
+ * likewise MSDN says that lpFrom and lpFromlen are ignored for
+ * connection-oriented sockets, so don't try to update lpFrom.
+ */
+ if ( lpFrom && hdr.msg_namelen &&
ws_sockaddr_u2ws( &unix_sockaddr.addr, lpFrom, lpFromlen ) != 0 )
{
/* The from buffer was too small, but we read the data
*
* Handler for overlapped recv() operations.
*/
-static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status)
+static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, ULONG_PTR *total )
{
ws2_async* wsa = user;
int result = 0, fd;
if (status != STATUS_PENDING)
{
iosb->u.Status = status;
- iosb->Information = result;
+ iosb->Information = *total = result;
}
return status;
}
*
* Handler for overlapped send() operations.
*/
-static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status)
+static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, ULONG_PTR *total )
{
ws2_async* wsa = user;
int result = 0, fd;
if (status != STATUS_PENDING)
{
iosb->u.Status = status;
- iosb->Information = result;
+ iosb->Information = *total = result;
}
return status;
}
req->async.iosb = &wsa->local_iosb;
req->async.arg = wsa;
req->async.apc = ws2_async_apc;
+ req->async.cvalue = 0;
status = wine_server_call( req );
}
SERVER_END_REQ;
}
else
{
+#ifdef IPV6_V6ONLY
+ const struct sockaddr_in6 *in6 = (const struct sockaddr_in6*) &uaddr;
+ if (name->sa_family == WS_AF_INET6 &&
+ !memcmp(&in6->sin6_addr, &in6addr_any, sizeof(struct in6_addr)))
+ {
+ int enable = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(enable)) == -1)
+ {
+ release_sock_fd( s, fd );
+ SetLastError(WSAEAFNOSUPPORT);
+ return INVALID_SOCKET;
+ }
+ }
+#endif
+ if (name->sa_family == WS_AF_INET)
+ {
+ struct sockaddr_in *in4 = (struct sockaddr_in*) &uaddr;
+ if (memcmp(&in4->sin_addr, &magic_loopback_addr, 4) == 0)
+ {
+ /* Trying to bind to the default host interface, using
+ * INADDR_ANY instead*/
+ WARN("Trying to bind to magic IP address, using "
+ "INADDR_ANY instead.\n");
+ in4->sin_addr.s_addr = htonl(WS_INADDR_ANY);
+ }
+ }
if (bind(fd, &uaddr.addr, uaddrlen) < 0)
{
int loc_errno = errno;
}
else
{
+ if (name->sa_family == WS_AF_INET)
+ {
+ struct sockaddr_in *in4 = (struct sockaddr_in*) &uaddr;
+ if (memcmp(&in4->sin_addr, &magic_loopback_addr, 4) == 0)
+ {
+ /* Trying to connect to magic replace-loopback address,
+ * assuming we really want to connect to localhost */
+ TRACE("Trying to connect to magic IP address, using "
+ "INADDR_LOOPBACK instead.\n");
+ in4->sin_addr.s_addr = htonl(WS_INADDR_LOOPBACK);
+ }
+ }
+
if (connect(fd, &uaddr.addr, uaddrlen) == 0)
goto connect_success;
}
case WS_SO_KEEPALIVE:
case WS_SO_OOBINLINE:
case WS_SO_RCVBUF:
+ case WS_SO_REUSEADDR:
case WS_SO_SNDBUF:
case WS_SO_TYPE:
if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
return SOCKET_ERROR;
convert_sockopt(&level, &optname);
- if (getsockopt(fd,(int) level, optname, optval,
- (unsigned int *)optlen) != 0 )
+ if (getsockopt(fd, level, optname, optval, (unsigned int *)optlen) != 0 )
{
SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
ret = SOCKET_ERROR;
return SOCKET_ERROR;
convert_sockopt(&level, &optname);
- if (getsockopt(fd,(int) level, optname, &tv, &len) != 0 )
+ if (getsockopt(fd, level, optname, &tv, &len) != 0 )
{
SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
ret = SOCKET_ERROR;
return ret;
}
#endif
- /* As mentioned in setsockopt, the windows style SO_REUSEADDR is
- * not possible in Unix, so always return false here. */
- case WS_SO_REUSEADDR:
- if (!optlen || *optlen < sizeof(int) || !optval)
- {
- SetLastError(WSAEFAULT);
- return SOCKET_ERROR;
- }
- *(int *)optval = 0;
- *optlen = sizeof(int);
- return 0;
-
default:
TRACE("Unknown SOL_SOCKET optname: 0x%08x\n", optname);
SetLastError(WSAENOPROTOOPT);
if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
return SOCKET_ERROR;
convert_sockopt(&level, &optname);
- if (getsockopt(fd,(int) level, optname, optval,
- (unsigned int *)optlen) != 0 )
+ if (getsockopt(fd, level, optname, optval, (unsigned int *)optlen) != 0 )
{
SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
ret = SOCKET_ERROR;
if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
return SOCKET_ERROR;
convert_sockopt(&level, &optname);
- if (getsockopt(fd,(int) level, optname, optval,
- (unsigned int *)optlen) != 0 )
+ if (getsockopt(fd, level, optname, optval, (unsigned int *)optlen) != 0 )
{
SetLastError((errno == EBADF) ? WSAENOTSOCK : wsaErrno());
ret = SOCKET_ERROR;
}
release_sock_fd( s, fd );
return ret;
+ case WS_IP_DONTFRAGMENT:
+ FIXME("WS_IP_DONTFRAGMENT is always false!\n");
+ *(BOOL*)optval = FALSE;
+ return 0;
}
FIXME("Unknown IPPROTO_IP optname 0x%08x\n", optname);
return SOCKET_ERROR;
/***********************************************************************
* WSAHtonl (WS2_32.46)
- * From MSDN decription of error codes, this function should also
+ * From MSDN description of error codes, this function should also
* check if WinSock has been initialized and the socket is a valid
* socket. But why? This function only translates a host byte order
* u_long into a network byte order u_long...
/***********************************************************************
* WSAHtons (WS2_32.47)
- * From MSDN decription of error codes, this function should also
+ * From MSDN description of error codes, this function should also
* check if WinSock has been initialized and the socket is a valid
* socket. But why? This function only translates a host byte order
* u_short into a network byte order u_short...
addr = inet_addr(ptr->IpAddressList.IpAddress.String);
mask = inet_addr(ptr->IpAddressList.IpMask.String);
- bcast = addr | (addr & !mask);
+ bcast = addr | ~mask;
intArray->iiAddress.AddressIn.sin_family = AF_INET;
intArray->iiAddress.AddressIn.sin_port = 0;
intArray->iiAddress.AddressIn.sin_addr.WS_s_addr =
FIXME("SIO_FLUSH: stub.\n");
break;
+ case WS_SIO_GET_EXTENSION_FUNCTION_POINTER:
+ FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER %s: stub\n", debugstr_guid(lpvInBuffer));
+ WSASetLastError(WSAEOPNOTSUPP);
+ return SOCKET_ERROR;
+
default:
FIXME("unsupported WS_IOCTL cmd (%08x)\n", dwIoControlCode);
WSASetLastError(WSAEOPNOTSUPP);
return ret;
}
+/* helper to send completion messages for client-only i/o operation case */
+static void WS_AddCompletion( SOCKET sock, ULONG_PTR CompletionValue, NTSTATUS CompletionStatus, ULONG_PTR Information )
+{
+ NTSTATUS status;
+
+ SERVER_START_REQ( add_fd_completion )
+ {
+ req->handle = SOCKET2HANDLE(sock);
+ req->cvalue = CompletionValue;
+ req->status = CompletionStatus;
+ req->information = Information;
+ status = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+}
+
/***********************************************************************
* send (WS2_32.19)
unsigned int i, options;
int n, fd, err;
struct iovec iovec[WS_MSG_MAXIOVLEN];
+ ULONG_PTR cvalue = (lpOverlapped && ((ULONG_PTR)lpOverlapped->hEvent & 1) == 0) ? (ULONG_PTR)lpOverlapped : 0;
TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, to %p, tolen %d, ovl %p, func %p\n",
s, lpBuffers, dwBufferCount, dwFlags,
if (n == -1 && errno != EAGAIN)
{
err = wsaErrno();
+ if (cvalue) WS_AddCompletion( s, cvalue, err, 0 );
goto error;
}
req->async.arg = wsa;
req->async.apc = ws2_async_apc;
req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
+ req->async.cvalue = cvalue;
err = wine_server_call( req );
}
SERVER_END_REQ;
*lpNumberOfBytesSent = n;
if (!wsa->completion_func)
{
+ if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n );
SetEvent( lpOverlapped->hEvent );
HeapFree( GetProcessHeap(), 0, wsa );
}
struct pollfd pfd;
int timeout = GET_SNDTIMEO(fd);
- if (n > 0)
+ if (n >= 0)
{
*lpNumberOfBytesSent += n;
- if (iovec[first_buff].iov_len > n)
- iovec[first_buff].iov_len -= n;
- else
- {
- while (n > 0) n -= iovec[first_buff++].iov_len;
- if (first_buff >= dwBufferCount) break;
- }
+ while (first_buff < dwBufferCount && iovec[first_buff].iov_len <= n)
+ n -= iovec[first_buff++].iov_len;
+ if (first_buff >= dwBufferCount) break;
+ iovec[first_buff].iov_base = (char*)iovec[first_buff].iov_base + n;
+ iovec[first_buff].iov_len -= n;
}
if (timeout != -1)
{
- timeout -= timeout_start - GetTickCount();
+ timeout -= GetTickCount() - timeout_start;
if (timeout < 0) timeout = 0;
}
TRACE("socket: %04lx, level 0x%x, name 0x%x, ptr %p, len %d\n",
s, level, optname, optval, optlen);
+ /* some broken apps pass the value directly instead of a pointer to it */
+ if(IS_INTRESOURCE(optval))
+ {
+ SetLastError(WSAEFAULT);
+ return SOCKET_ERROR;
+ }
+
switch(level)
{
case WS_SOL_SOCKET:
case WS_SO_ERROR:
case WS_SO_KEEPALIVE:
case WS_SO_OOBINLINE:
+ /* BSD socket SO_REUSEADDR is not 100% compatible to winsock semantics.
+ * however, using it the BSD way fixes bug 8513 and seems to be what
+ * most programmers assume, anyway */
+ case WS_SO_REUSEADDR:
case WS_SO_SNDBUF:
case WS_SO_TYPE:
convert_sockopt(&level, &optname);
TRACE("setting global SO_OPENTYPE = 0x%x\n", *((int*)optval) );
return 0;
- /* SO_REUSEADDR allows two applications to bind to the same port at at
- * same time. There is no direct way to do that in unix. While Wineserver
- * might do this, it does not seem useful for now, so just ignore it.*/
- case WS_SO_REUSEADDR:
- TRACE("Ignoring SO_REUSEADDR, does not translate\n");
- return 0;
-
#ifdef SO_RCVTIMEO
case WS_SO_RCVTIMEO:
#endif
#endif
#if defined(SO_RCVTIMEO) || defined(SO_SNDTIMEO)
if (optval && optlen == sizeof(UINT32)) {
- /* WinSock passes miliseconds instead of struct timeval */
+ /* WinSock passes milliseconds instead of struct timeval */
tval.tv_usec = (*(const UINT32*)optval % 1000) * 1000;
tval.tv_sec = *(const UINT32*)optval / 1000;
- /* min of 500 milisec */
+ /* min of 500 milliseconds */
if (tval.tv_sec == 0 && tval.tv_usec < 500000)
tval.tv_usec = 500000;
optlen = sizeof(struct timeval);
case WS_IP_TTL:
convert_sockopt(&level, &optname);
break;
+ case WS_IP_DONTFRAGMENT:
+ FIXME("IP_DONTFRAGMENT is silently ignored!\n");
+ return 0;
default:
FIXME("Unknown IPPROTO_IP optname 0x%08x\n", optname);
return SOCKET_ERROR;
#else
LeaveCriticalSection( &csWSgetXXXbyYYY );
#endif
+ if (retval && retval->h_addr_list[0][0] == 127 &&
+ strcmp(name, "localhost") != 0)
+ {
+ /* hostname != "localhost" but has loopback address. replace by our
+ * special address.*/
+ memcpy(retval->h_addr_list[0], magic_loopback_addr, 4);
+ }
TRACE( "%s ret %p\n", debugstr_a(name), retval );
return retval;
}
}
}
-/* helper functions for getaddrinfo() */
+/* helper functions for getaddrinfo()/getnameinfo() */
static int convert_aiflag_w2u(int winflags) {
int i, unixflags = 0;
return unixflags;
}
+static int convert_niflag_w2u(int winflags) {
+ int i, unixflags = 0;
+
+ for (i=0;i<sizeof(ws_niflag_map)/sizeof(ws_niflag_map[0]);i++)
+ if (ws_niflag_map[i][0] & winflags) {
+ unixflags |= ws_niflag_map[i][1];
+ winflags &= ~ws_niflag_map[i][0];
+ }
+ if (winflags)
+ FIXME("Unhandled windows NI_xxx flags %x\n", winflags);
+ return unixflags;
+}
+
static int convert_aiflag_u2w(int unixflags) {
int i, winflags = 0;
*/
int WINAPI WS_getaddrinfo(LPCSTR nodename, LPCSTR servname, const struct WS_addrinfo *hints, struct WS_addrinfo **res)
{
-#if HAVE_GETADDRINFO
+#ifdef HAVE_GETADDRINFO
struct addrinfo *unixaires = NULL;
int result;
struct addrinfo unixhints, *punixhints = NULL;
/* getaddrinfo(3) is thread safe, no need to wrap in CS */
result = getaddrinfo(nodename, servname, punixhints, &unixaires);
- TRACE("%s, %s %p -> %p %d\n", nodename, servname, hints, res, result);
+ TRACE("%s, %s %p -> %p %d\n", debugstr_a(nodename), debugstr_a(servname), hints, res, result);
HeapFree(GetProcessHeap(), 0, node);
HeapFree(GetProcessHeap(), 0, serv);
freeaddrinfo(unixaires);
} else {
result = convert_eai_u2w(result);
+ *res = NULL;
}
return result;
int WINAPI WS_getnameinfo(const SOCKADDR *sa, WS_socklen_t salen, PCHAR host,
DWORD hostlen, PCHAR serv, DWORD servlen, INT flags)
{
-#if HAVE_GETNAMEINFO
+#ifdef HAVE_GETNAMEINFO
int ret;
union generic_unix_sockaddr sa_u;
unsigned int size;
WSASetLastError(WSAEFAULT);
return WSA_NOT_ENOUGH_MEMORY;
}
- ret = getnameinfo(&sa_u.addr, size, host, hostlen, serv, servlen, convert_aiflag_w2u(flags));
+ ret = getnameinfo(&sa_u.addr, size, host, hostlen, serv, servlen, convert_niflag_w2u(flags));
return convert_eai_u2w(ret);
#else
FIXME("getnameinfo() failed, not found during buildtime.\n");
return ret;
}
- /* check and convert the socket family */
+ /* convert the socket family and type */
af = convert_af_w2u(af);
- if (af == -1)
- {
- FIXME("Unsupported socket family %d!\n", af);
- SetLastError(WSAEAFNOSUPPORT);
- return INVALID_SOCKET;
- }
-
- /* check the socket type */
type = convert_socktype_w2u(type);
- if (type == -1)
- {
- SetLastError(WSAESOCKTNOSUPPORT);
- return INVALID_SOCKET;
- }
- /* check the protocol type */
- if ( protocol < 0 ) /* don't support negative values */
+ if (lpProtocolInfo)
{
- SetLastError(WSAEPROTONOSUPPORT);
- return INVALID_SOCKET;
+ if (af == FROM_PROTOCOL_INFO)
+ af = lpProtocolInfo->iAddressFamily;
+ if (type == FROM_PROTOCOL_INFO)
+ type = lpProtocolInfo->iSocketType;
+ if (protocol == FROM_PROTOCOL_INFO)
+ protocol = lpProtocolInfo->iProtocol;
}
if ( af == AF_UNSPEC) /* did they not specify the address family? */
if (GetLastError() == WSAEACCES) /* raw socket denied */
{
if (type == SOCK_RAW)
- MESSAGE("WARNING: Trying to create a socket of type SOCK_RAW, will fail unless running as root\n");
+ MESSAGE("WARNING: Trying to create a socket of type SOCK_RAW, this"
+ " will fail unless you have special permissions.\n");
else
- MESSAGE("WS_SOCKET: not enough privileges to create socket, try running as root\n");
+ MESSAGE("WS_SOCKET: Failed to create socket, this requires"
+ " special permissions.\n");
SetLastError(WSAESOCKTNOSUPPORT);
}
/* duplicate hostent entry
* and handle all Win16/Win32 dependent things (struct size, ...) *correctly*.
- * Dito for protoent and servent.
+ * Ditto for protoent and servent.
*/
static struct WS_hostent *WS_dup_he(const struct hostent* p_he)
{
int n, fd, err;
DWORD timeout_start = GetTickCount();
struct iovec iovec[WS_MSG_MAXIOVLEN];
+ ULONG_PTR cvalue = (lpOverlapped && ((ULONG_PTR)lpOverlapped->hEvent & 1) == 0) ? (ULONG_PTR)lpOverlapped : 0;
TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, from %p, fromlen %d, ovl %p, func %p\n",
s, lpBuffers, dwBufferCount, *lpFlags, lpFrom,
if (errno != EAGAIN)
{
err = wsaErrno();
+ if (cvalue) WS_AddCompletion( s, cvalue, err, 0 );
goto error;
}
}
req->async.arg = wsa;
req->async.apc = ws2_async_apc;
req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
+ req->async.cvalue = cvalue;
err = wine_server_call( req );
}
SERVER_END_REQ;
iosb->Information = n;
if (!wsa->completion_func)
{
+ if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n );
SetEvent( lpOverlapped->hEvent );
HeapFree( GetProcessHeap(), 0, wsa );
}
LPINT lpAddressLength)
{
INT res=0;
- struct in_addr inetaddr;
LPSTR workBuffer=NULL,ptrPort;
- TRACE( "(%s, %x, %p, %p, %p)\n", AddressString, AddressFamily, lpProtocolInfo,
- lpAddress, lpAddressLength );
+ TRACE( "(%s, %x, %p, %p, %p)\n", debugstr_a(AddressString), AddressFamily,
+ lpProtocolInfo, lpAddress, lpAddressLength );
if (!lpAddressLength || !lpAddress) return SOCKET_ERROR;
- if (AddressString)
+ if (!AddressString)
{
- workBuffer = HeapAlloc( GetProcessHeap(), 0, strlen(AddressString)+1 );
- if (workBuffer)
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ if (lpProtocolInfo)
+ FIXME("ProtocolInfo not implemented.\n");
+
+ workBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+ strlen(AddressString) + 1);
+ if (!workBuffer)
+ {
+ WSASetLastError(WSA_NOT_ENOUGH_MEMORY);
+ return SOCKET_ERROR;
+ }
+
+ strcpy(workBuffer, AddressString);
+
+ switch(AddressFamily)
+ {
+ case WS_AF_INET:
+ {
+ struct in_addr inetaddr;
+
+ /* If lpAddressLength is too small, tell caller the size we need */
+ if (*lpAddressLength < sizeof(SOCKADDR_IN))
{
- strcpy(workBuffer,AddressString);
- switch (AddressFamily)
- {
- case AF_INET:
- /* caller wants to know the size of the socket buffer */
- if (*lpAddressLength < sizeof(SOCKADDR_IN))
- {
- *lpAddressLength = sizeof(SOCKADDR_IN);
- res = WSAEFAULT;
- }
- else
- {
- /* caller wants to translate an AddressString into a SOCKADDR */
- if (lpAddress)
- {
- memset(lpAddress,0,sizeof(SOCKADDR_IN));
- ((LPSOCKADDR_IN)lpAddress)->sin_family = AF_INET;
- ptrPort = strchr(workBuffer,':');
- if (ptrPort)
- {
- ((LPSOCKADDR_IN)lpAddress)->sin_port = (WS_u_short)atoi(ptrPort+1);
- *ptrPort = '\0';
- }
- else
- ((LPSOCKADDR_IN)lpAddress)->sin_port = 0;
- if (inet_aton(workBuffer, &inetaddr) > 0)
- {
- ((LPSOCKADDR_IN)lpAddress)->sin_addr.WS_s_addr = inetaddr.s_addr;
- res = 0;
- }
- else
- res = WSAEINVAL;
- }
- }
- if (lpProtocolInfo)
- FIXME("(%s, %x, %p, %p, %p) - ProtocolInfo not implemented!\n",
- AddressString, AddressFamily,
- lpProtocolInfo, lpAddress, lpAddressLength);
+ *lpAddressLength = sizeof(SOCKADDR_IN);
+ res = WSAEFAULT;
+ break;
+ }
+ memset(lpAddress, 0, sizeof(SOCKADDR_IN));
- break;
- default:
- FIXME("(%s, %x, %p, %p, %p) - AddressFamiliy not implemented!\n",
- AddressString, AddressFamily,
- lpProtocolInfo, lpAddress, lpAddressLength);
- }
- HeapFree( GetProcessHeap(), 0, workBuffer );
+ ((LPSOCKADDR_IN)lpAddress)->sin_family = AF_INET;
+
+ ptrPort = strchr(workBuffer, ':');
+ if(ptrPort)
+ {
+ ((LPSOCKADDR_IN)lpAddress)->sin_port = (WS_u_short)atoi(ptrPort+1);
+ *ptrPort = '\0';
}
else
- res = WSA_NOT_ENOUGH_MEMORY;
+ {
+ ((LPSOCKADDR_IN)lpAddress)->sin_port = 0;
+ }
+
+ if(inet_aton(workBuffer, &inetaddr) > 0)
+ {
+ ((LPSOCKADDR_IN)lpAddress)->sin_addr.WS_s_addr = inetaddr.s_addr;
+ res = 0;
+ }
+ else
+ res = WSAEINVAL;
+
+ break;
+
}
- else
+ case WS_AF_INET6:
+ {
+ struct in6_addr inetaddr;
+ /* If lpAddressLength is too small, tell caller the size we need */
+ if (*lpAddressLength < sizeof(SOCKADDR_IN6))
+ {
+ *lpAddressLength = sizeof(SOCKADDR_IN6);
+ res = WSAEFAULT;
+ break;
+ }
+#ifdef HAVE_INET_PTON
+ memset(lpAddress, 0, sizeof(SOCKADDR_IN6));
+
+ ((LPSOCKADDR_IN6)lpAddress)->sin6_family = WS_AF_INET6;
+
+ /* This one is a bit tricky. An IPv6 address contains colons, so the
+ * check from IPv4 doesn't work like that. However, IPv6 addresses that
+ * contain a port are written with braces like [fd12:3456:7890::1]:12345
+ * so what we will do is to look for ']', check if the next char is a
+ * colon, and if it is, parse the port as in IPv4. */
+
+ ptrPort = strchr(workBuffer, ']');
+ if(ptrPort && *(++ptrPort) == ':')
+ {
+ ((LPSOCKADDR_IN6)lpAddress)->sin6_port = (WS_u_short)atoi(ptrPort+1);
+ *ptrPort = '\0';
+ }
+ else
+ {
+ ((LPSOCKADDR_IN6)lpAddress)->sin6_port = 0;
+ }
+
+ if(inet_pton(AF_INET6, workBuffer, &inetaddr) > 0)
+ {
+ memcpy(&((LPSOCKADDR_IN6)lpAddress)->sin6_addr, &inetaddr,
+ sizeof(struct in6_addr));
+ res = 0;
+ }
+ else
+#endif /* HAVE_INET_PTON */
+ res = WSAEINVAL;
+
+ break;
+ }
+ default:
+ /* According to MSDN, only AF_INET and AF_INET6 are supported. */
+ TRACE("Unsupported address family specified: %d.\n", AddressFamily);
res = WSAEINVAL;
+ }
+
+ HeapFree(GetProcessHeap(), 0, workBuffer);
if (!res) return 0;
WSASetLastError(res);