# 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
{
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). */
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);
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] =
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},
};
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 */
/***********************************************************************
- * WSAGetLastError (WINSOCK.111)
* WSAGetLastError (WS2_32.111)
*/
INT WINAPI WSAGetLastError(void)
/* ----------------------------------- 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;
+ }
+}
/**********************************************************************/
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) {
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):
}
}
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;
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;
}
*
* 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;
if (status != STATUS_PENDING)
{
iosb->u.Status = status;
- iosb->Information = *total = result;
+ iosb->Information = result;
+ *apc = ws2_async_apc;
}
return status;
}
*
* 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;
if (status != STATUS_PENDING)
{
iosb->u.Status = status;
- iosb->Information = *total = result;
+ iosb->Information = result;
+ *apc = ws2_async_apc;
}
return status;
}
*
* 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;
status = err ? wsaErrno() : STATUS_SUCCESS;
break;
}
- *total = 0;
iosb->u.Status = status;
+ iosb->Information = 0;
+ *apc = ws2_async_apc;
return status;
}
{
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 );
}
SOCKET WINAPI WS_accept(SOCKET s, struct WS_sockaddr *addr,
int *addrlen32)
{
+ NTSTATUS status;
SOCKET as;
BOOL is_blocking;
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;
}
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);
}
{
release_sock_fd( s, fd );
SetLastError(WSAEAFNOSUPPORT);
- return INVALID_SOCKET;
+ return SOCKET_ERROR;
}
}
#endif
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;
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;
}/* 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)
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)
/***********************************************************************
- * htons (WINSOCK.9)
* htons (WS2_32.9)
*/
WS_u_short WINAPI WS_htons(WS_u_short hostshort)
/***********************************************************************
- * inet_addr (WINSOCK.10)
* inet_addr (WS2_32.11)
*/
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)
/***********************************************************************
- * ntohs (WINSOCK.15)
* ntohs (WS2_32.15)
*/
WS_u_short WINAPI WS_ntohs(WS_u_short netshort)
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 */
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;
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",
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());
{
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 );
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;
break;
default:
- FIXME("Unknown level: 0x%08x\n", level);
+ WARN("Unknown level: 0x%08x\n", level);
+ SetLastError(WSAEINVAL);
return SOCKET_ERROR;
} /* end switch(level) */
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)
*/
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)
{
#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,
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);
}
}
/***********************************************************************
- * WSAIsBlocking (WINSOCK.114)
* WSAIsBlocking (WS2_32.114)
*/
BOOL WINAPI WSAIsBlocking(void)
}
/***********************************************************************
- * WSACancelBlockingCall (WINSOCK.113)
* WSACancelBlockingCall (WS2_32.113)
*/
INT WINAPI WSACancelBlockingCall(void)
/* ----- 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;
}
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)
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;
}
{
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 );
/***********************************************************************
* 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
}
/***********************************************************************
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
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
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)
{
return SOCKET_ERROR;
}
+ *lenstr = size;
strcpy( string, buffer );
return 0;
}
*
* 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;
}