ws2_32: Add support for WSARecvMsg and IP_PKTINFO.
This commit is contained in:
parent
39b260e8be
commit
54b4f836fd
|
@ -171,9 +171,9 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The actual definition of WSASendTo/WSARecvFrom, wrapped in a different
|
* The actual definition of WSASendTo, wrapped in a different function name
|
||||||
* function name, so that internal calls from ws2_32 itself will not trigger
|
* so that internal calls from ws2_32 itself will not trigger programs like
|
||||||
* programs like Garena, which hooks WSASendTo/WSARecvFrom calls.
|
* Garena, which hooks WSASendTo/WSARecvFrom calls.
|
||||||
*/
|
*/
|
||||||
static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
|
LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
|
||||||
|
@ -181,11 +181,16 @@ static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
LPWSAOVERLAPPED lpOverlapped,
|
LPWSAOVERLAPPED lpOverlapped,
|
||||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
|
||||||
|
|
||||||
static int WS2_recvfrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
/*
|
||||||
|
* Internal fundamental receive function, essentially WSARecvFrom with an
|
||||||
|
* additional parameter to support message control headers.
|
||||||
|
*/
|
||||||
|
static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
|
LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
|
||||||
struct WS_sockaddr *lpFrom,
|
struct WS_sockaddr *lpFrom,
|
||||||
LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
|
LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
|
||||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||||
|
LPWSABUF lpControlBuffer );
|
||||||
|
|
||||||
/* critical section to protect some non-reentrant net function */
|
/* critical section to protect some non-reentrant net function */
|
||||||
static CRITICAL_SECTION csWSgetXXXbyYYY;
|
static CRITICAL_SECTION csWSgetXXXbyYYY;
|
||||||
|
@ -261,6 +266,8 @@ typedef struct ws2_async
|
||||||
int *ptr; /* for recv operations */
|
int *ptr; /* for recv operations */
|
||||||
} addrlen;
|
} addrlen;
|
||||||
DWORD flags;
|
DWORD flags;
|
||||||
|
DWORD *lpFlags;
|
||||||
|
WSABUF *control;
|
||||||
unsigned int n_iovecs;
|
unsigned int n_iovecs;
|
||||||
unsigned int first_iovec;
|
unsigned int first_iovec;
|
||||||
struct iovec iovec[1];
|
struct iovec iovec[1];
|
||||||
|
@ -375,6 +382,9 @@ static const int ws_ip_map[][2] =
|
||||||
#endif
|
#endif
|
||||||
MAP_OPTION( IP_TOS ),
|
MAP_OPTION( IP_TOS ),
|
||||||
MAP_OPTION( IP_TTL ),
|
MAP_OPTION( IP_TTL ),
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
MAP_OPTION( IP_PKTINFO ),
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int ws_ipv6_map[][2] =
|
static const int ws_ipv6_map[][2] =
|
||||||
|
@ -468,6 +478,75 @@ static const int ws_eai_map[][2] =
|
||||||
|
|
||||||
static const char magic_loopback_addr[] = {127, 12, 34, 56};
|
static const char magic_loopback_addr[] = {127, 12, 34, 56};
|
||||||
|
|
||||||
|
#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
|
||||||
|
static inline WSACMSGHDR *fill_control_message(int level, int type, WSACMSGHDR *current, ULONG *maxsize, void *data, int len)
|
||||||
|
{
|
||||||
|
ULONG msgsize = sizeof(WSACMSGHDR) + WSA_CMSG_ALIGN(len);
|
||||||
|
char *ptr = (char *) current + sizeof(WSACMSGHDR);
|
||||||
|
|
||||||
|
/* Make sure there is at least enough room for this entry */
|
||||||
|
if (msgsize > *maxsize)
|
||||||
|
return NULL;
|
||||||
|
*maxsize -= msgsize;
|
||||||
|
/* Fill in the entry */
|
||||||
|
current->cmsg_len = sizeof(WSACMSGHDR) + len;
|
||||||
|
current->cmsg_level = level;
|
||||||
|
current->cmsg_type = type;
|
||||||
|
memcpy(ptr, data, len);
|
||||||
|
/* Return the pointer to where next entry should go */
|
||||||
|
return (WSACMSGHDR *) (ptr + WSA_CMSG_ALIGN(len));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int convert_control_headers(struct msghdr *hdr, WSABUF *control)
|
||||||
|
{
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
WSACMSGHDR *cmsg_win = (WSACMSGHDR *) control->buf, *ptr;
|
||||||
|
ULONG ctlsize = control->len;
|
||||||
|
struct cmsghdr *cmsg_unix;
|
||||||
|
|
||||||
|
ptr = cmsg_win;
|
||||||
|
/* Loop over all the headers, converting as appropriate */
|
||||||
|
for (cmsg_unix = CMSG_FIRSTHDR(hdr); cmsg_unix != NULL; cmsg_unix = CMSG_NXTHDR(hdr, cmsg_unix))
|
||||||
|
{
|
||||||
|
switch(cmsg_unix->cmsg_level)
|
||||||
|
{
|
||||||
|
case IPPROTO_IP:
|
||||||
|
switch(cmsg_unix->cmsg_type)
|
||||||
|
{
|
||||||
|
case IP_PKTINFO:
|
||||||
|
{
|
||||||
|
/* Convert the Unix IP_PKTINFO structure to the Windows version */
|
||||||
|
struct in_pktinfo *data_unix = (struct in_pktinfo *) CMSG_DATA(cmsg_unix);
|
||||||
|
struct WS_in_pktinfo data_win;
|
||||||
|
|
||||||
|
memcpy(&data_win.ipi_addr,&data_unix->ipi_addr.s_addr,4); /* 4 bytes = 32 address bits */
|
||||||
|
data_win.ipi_ifindex = data_unix->ipi_ifindex;
|
||||||
|
ptr = fill_control_message(WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize,
|
||||||
|
(void*)&data_win, sizeof(data_win));
|
||||||
|
if (!ptr) goto error;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
FIXME("Unhandled IPPROTO_IP message header type %d\n", cmsg_unix->cmsg_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FIXME("Unhandled message header level %d\n", cmsg_unix->cmsg_level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* Set the length of the returned control headers */
|
||||||
|
control->len = (ptr == NULL ? 0 : (char*)ptr - (char*)cmsg_win);
|
||||||
|
return (ptr != NULL);
|
||||||
|
#else /* IP_PKTINFO */
|
||||||
|
control->len = 0;
|
||||||
|
return 1;
|
||||||
|
#endif /* IP_PKTINFO */
|
||||||
|
}
|
||||||
|
#endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */
|
||||||
|
|
||||||
/* ----------------------------------- error handling */
|
/* ----------------------------------- error handling */
|
||||||
|
|
||||||
static NTSTATUS sock_get_ntstatus( int err )
|
static NTSTATUS sock_get_ntstatus( int err )
|
||||||
|
@ -1411,6 +1490,9 @@ static void WINAPI ws2_async_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserv
|
||||||
*/
|
*/
|
||||||
static int WS2_recv( int fd, struct ws2_async *wsa )
|
static int WS2_recv( int fd, struct ws2_async *wsa )
|
||||||
{
|
{
|
||||||
|
#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
|
||||||
|
char pktbuf[512];
|
||||||
|
#endif
|
||||||
struct msghdr hdr;
|
struct msghdr hdr;
|
||||||
union generic_unix_sockaddr unix_sockaddr;
|
union generic_unix_sockaddr unix_sockaddr;
|
||||||
int n;
|
int n;
|
||||||
|
@ -1431,14 +1513,30 @@ static int WS2_recv( int fd, struct ws2_async *wsa )
|
||||||
hdr.msg_accrights = NULL;
|
hdr.msg_accrights = NULL;
|
||||||
hdr.msg_accrightslen = 0;
|
hdr.msg_accrightslen = 0;
|
||||||
#else
|
#else
|
||||||
hdr.msg_control = NULL;
|
hdr.msg_control = pktbuf;
|
||||||
hdr.msg_controllen = 0;
|
hdr.msg_controllen = sizeof(pktbuf);
|
||||||
hdr.msg_flags = 0;
|
hdr.msg_flags = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( (n = recvmsg(fd, &hdr, wsa->flags)) == -1 )
|
if ( (n = recvmsg(fd, &hdr, wsa->flags)) == -1 )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
|
||||||
|
if (wsa->control)
|
||||||
|
{
|
||||||
|
ERR("Message control headers cannot be properly supported on this system.\n");
|
||||||
|
control->len = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (wsa->control && !convert_control_headers(&hdr, wsa->control))
|
||||||
|
{
|
||||||
|
WARN("Application passed insufficient room for control headers.\n");
|
||||||
|
*wsa->lpFlags |= WS_MSG_CTRUNC;
|
||||||
|
errno = EMSGSIZE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* if this socket is connected and lpFrom is not NULL, Linux doesn't give us
|
/* 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.
|
* msg_name and msg_namelen from recvmsg, but it does set msg_namelen to zero.
|
||||||
*
|
*
|
||||||
|
@ -1914,8 +2012,10 @@ static BOOL WINAPI WS2_AcceptEx(SOCKET listener, SOCKET acceptor, PVOID dest, DW
|
||||||
|
|
||||||
wsa->read->hSocket = wsa->accept_socket;
|
wsa->read->hSocket = wsa->accept_socket;
|
||||||
wsa->read->flags = 0;
|
wsa->read->flags = 0;
|
||||||
|
wsa->read->lpFlags = &wsa->read->flags;
|
||||||
wsa->read->addr = NULL;
|
wsa->read->addr = NULL;
|
||||||
wsa->read->addrlen.ptr = NULL;
|
wsa->read->addrlen.ptr = NULL;
|
||||||
|
wsa->read->control = NULL;
|
||||||
wsa->read->n_iovecs = 1;
|
wsa->read->n_iovecs = 1;
|
||||||
wsa->read->first_iovec = 0;
|
wsa->read->first_iovec = 0;
|
||||||
wsa->read->iovec[0].iov_base = wsa->buf;
|
wsa->read->iovec[0].iov_base = wsa->buf;
|
||||||
|
@ -1961,6 +2061,29 @@ static void WINAPI WS2_GetAcceptExSockaddrs(PVOID buffer, DWORD data_size, DWORD
|
||||||
*remote_addr = (struct WS_sockaddr *)(cbuf + sizeof(int));
|
*remote_addr = (struct WS_sockaddr *)(cbuf + sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* WSARecvMsg
|
||||||
|
*
|
||||||
|
* Perform a receive operation that is capable of returning message
|
||||||
|
* control headers. It is important to note that the WSAMSG parameter
|
||||||
|
* must remain valid throughout the operation, even when an overlapped
|
||||||
|
* receive is performed.
|
||||||
|
*/
|
||||||
|
static int WINAPI WS2_WSARecvMsg( SOCKET s, LPWSAMSG msg, LPDWORD lpNumberOfBytesRecvd,
|
||||||
|
LPWSAOVERLAPPED lpOverlapped,
|
||||||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
|
||||||
|
{
|
||||||
|
if (!msg)
|
||||||
|
{
|
||||||
|
SetLastError( WSAEFAULT );
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WS2_recv_base( s, msg->lpBuffers, msg->dwBufferCount, lpNumberOfBytesRecvd,
|
||||||
|
&msg->dwFlags, msg->name, &msg->namelen,
|
||||||
|
lpOverlapped, lpCompletionRoutine, &msg->Control );
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* bind (WS2_32.2)
|
* bind (WS2_32.2)
|
||||||
*/
|
*/
|
||||||
|
@ -2213,6 +2336,8 @@ static BOOL WINAPI WS2_ConnectEx(SOCKET s, const struct WS_sockaddr* name, int n
|
||||||
wsa->addr = NULL;
|
wsa->addr = NULL;
|
||||||
wsa->addrlen.val = 0;
|
wsa->addrlen.val = 0;
|
||||||
wsa->flags = 0;
|
wsa->flags = 0;
|
||||||
|
wsa->lpFlags = &wsa->flags;
|
||||||
|
wsa->control = NULL;
|
||||||
wsa->n_iovecs = sendBuf ? 1 : 0;
|
wsa->n_iovecs = sendBuf ? 1 : 0;
|
||||||
wsa->first_iovec = 0;
|
wsa->first_iovec = 0;
|
||||||
wsa->completion_func = NULL;
|
wsa->completion_func = NULL;
|
||||||
|
@ -2674,6 +2799,9 @@ INT WINAPI WS_getsockopt(SOCKET s, INT level,
|
||||||
case WS_IP_MULTICAST_LOOP:
|
case WS_IP_MULTICAST_LOOP:
|
||||||
case WS_IP_MULTICAST_TTL:
|
case WS_IP_MULTICAST_TTL:
|
||||||
case WS_IP_OPTIONS:
|
case WS_IP_OPTIONS:
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
case WS_IP_PKTINFO:
|
||||||
|
#endif
|
||||||
case WS_IP_TOS:
|
case WS_IP_TOS:
|
||||||
case WS_IP_TTL:
|
case WS_IP_TTL:
|
||||||
if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
|
if ( (fd = get_sock_fd( s, 0, NULL )) == -1)
|
||||||
|
@ -3199,7 +3327,8 @@ INT WINAPI WSAIoctl(SOCKET s,
|
||||||
}
|
}
|
||||||
else if ( IsEqualGUID(&wsarecvmsg_guid, lpvInBuffer) )
|
else if ( IsEqualGUID(&wsarecvmsg_guid, lpvInBuffer) )
|
||||||
{
|
{
|
||||||
FIXME("SIO_GET_EXTENSION_FUNCTION_POINTER: unimplemented WSARecvMsg\n");
|
*(LPFN_WSARECVMSG *)lpbOutBuffer = WS2_WSARecvMsg;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
else if ( IsEqualGUID(&wsasendmsg_guid, lpvInBuffer) )
|
else if ( IsEqualGUID(&wsasendmsg_guid, lpvInBuffer) )
|
||||||
{
|
{
|
||||||
|
@ -3459,7 +3588,7 @@ int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags)
|
||||||
wsabuf.len = len;
|
wsabuf.len = len;
|
||||||
wsabuf.buf = buf;
|
wsabuf.buf = buf;
|
||||||
|
|
||||||
if ( WS2_recvfrom(s, &wsabuf, 1, &n, &dwFlags, NULL, NULL, NULL, NULL) == SOCKET_ERROR )
|
if ( WS2_recv_base(s, &wsabuf, 1, &n, &dwFlags, NULL, NULL, NULL, NULL, NULL) == SOCKET_ERROR )
|
||||||
return SOCKET_ERROR;
|
return SOCKET_ERROR;
|
||||||
else
|
else
|
||||||
return n;
|
return n;
|
||||||
|
@ -3477,7 +3606,7 @@ int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags,
|
||||||
wsabuf.len = len;
|
wsabuf.len = len;
|
||||||
wsabuf.buf = buf;
|
wsabuf.buf = buf;
|
||||||
|
|
||||||
if ( WS2_recvfrom(s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL) == SOCKET_ERROR )
|
if ( WS2_recv_base(s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL, NULL) == SOCKET_ERROR )
|
||||||
return SOCKET_ERROR;
|
return SOCKET_ERROR;
|
||||||
else
|
else
|
||||||
return n;
|
return n;
|
||||||
|
@ -3743,6 +3872,8 @@ static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
wsa->addr = (struct WS_sockaddr *)to;
|
wsa->addr = (struct WS_sockaddr *)to;
|
||||||
wsa->addrlen.val = tolen;
|
wsa->addrlen.val = tolen;
|
||||||
wsa->flags = dwFlags;
|
wsa->flags = dwFlags;
|
||||||
|
wsa->lpFlags = &wsa->flags;
|
||||||
|
wsa->control = NULL;
|
||||||
wsa->n_iovecs = dwBufferCount;
|
wsa->n_iovecs = dwBufferCount;
|
||||||
wsa->first_iovec = 0;
|
wsa->first_iovec = 0;
|
||||||
for ( i = 0; i < dwBufferCount; i++ )
|
for ( i = 0; i < dwBufferCount; i++ )
|
||||||
|
@ -4139,6 +4270,9 @@ int WINAPI WS_setsockopt(SOCKET s, int level, int optname,
|
||||||
case WS_IP_MULTICAST_LOOP:
|
case WS_IP_MULTICAST_LOOP:
|
||||||
case WS_IP_MULTICAST_TTL:
|
case WS_IP_MULTICAST_TTL:
|
||||||
case WS_IP_OPTIONS:
|
case WS_IP_OPTIONS:
|
||||||
|
#ifdef IP_PKTINFO
|
||||||
|
case WS_IP_PKTINFO:
|
||||||
|
#endif
|
||||||
case WS_IP_TOS:
|
case WS_IP_TOS:
|
||||||
case WS_IP_TTL:
|
case WS_IP_TTL:
|
||||||
convert_sockopt(&level, &optname);
|
convert_sockopt(&level, &optname);
|
||||||
|
@ -5514,15 +5648,16 @@ int WINAPI WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
LPWSAOVERLAPPED lpOverlapped,
|
LPWSAOVERLAPPED lpOverlapped,
|
||||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
|
||||||
{
|
{
|
||||||
return WS2_recvfrom(s, lpBuffers, dwBufferCount, NumberOfBytesReceived, lpFlags,
|
return WS2_recv_base(s, lpBuffers, dwBufferCount, NumberOfBytesReceived, lpFlags,
|
||||||
NULL, NULL, lpOverlapped, lpCompletionRoutine);
|
NULL, NULL, lpOverlapped, lpCompletionRoutine, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int WS2_recvfrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct WS_sockaddr *lpFrom,
|
LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags,
|
||||||
|
struct WS_sockaddr *lpFrom,
|
||||||
LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
|
LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
|
||||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
|
||||||
|
LPWSABUF lpControlBuffer )
|
||||||
{
|
{
|
||||||
unsigned int i, options;
|
unsigned int i, options;
|
||||||
int n, fd, err;
|
int n, fd, err;
|
||||||
|
@ -5548,8 +5683,10 @@ static int WS2_recvfrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
|
|
||||||
wsa->hSocket = SOCKET2HANDLE(s);
|
wsa->hSocket = SOCKET2HANDLE(s);
|
||||||
wsa->flags = *lpFlags;
|
wsa->flags = *lpFlags;
|
||||||
|
wsa->lpFlags = lpFlags;
|
||||||
wsa->addr = lpFrom;
|
wsa->addr = lpFrom;
|
||||||
wsa->addrlen.ptr = lpFromlen;
|
wsa->addrlen.ptr = lpFromlen;
|
||||||
|
wsa->control = lpControlBuffer;
|
||||||
wsa->n_iovecs = dwBufferCount;
|
wsa->n_iovecs = dwBufferCount;
|
||||||
wsa->first_iovec = 0;
|
wsa->first_iovec = 0;
|
||||||
for (i = 0; i < dwBufferCount; i++)
|
for (i = 0; i < dwBufferCount; i++)
|
||||||
|
@ -5683,10 +5820,10 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
|
||||||
|
|
||||||
{
|
{
|
||||||
return WS2_recvfrom( s, lpBuffers, dwBufferCount,
|
return WS2_recv_base( s, lpBuffers, dwBufferCount,
|
||||||
lpNumberOfBytesRecvd, lpFlags,
|
lpNumberOfBytesRecvd, lpFlags,
|
||||||
lpFrom, lpFromlen,
|
lpFrom, lpFromlen,
|
||||||
lpOverlapped, lpCompletionRoutine );
|
lpOverlapped, lpCompletionRoutine, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
|
Loading…
Reference in New Issue