Make the recv() and send() family of functions use WSARecvFrom() and
WSASendTo().
diff --git a/dlls/winsock/socket.c b/dlls/winsock/socket.c
index 0908afc..a33ffbf 100644
--- a/dlls/winsock/socket.c
+++ b/dlls/winsock/socket.c
@@ -1797,34 +1797,13 @@
*/
int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags)
{
- int fd = _get_sock_fd(s);
+ DWORD n, dwFlags = flags;
+ WSABUF wsabuf = { len, buf };
- TRACE("socket %04x, buf %8x, len %d, flags %d\n", s, (unsigned)buf, len, flags);
-
- if (fd != -1)
- {
- INT length;
-
- if (_is_blocking(s))
- {
- /* block here */
- /* FIXME: OOB and exceptfds? */
- do_block(fd, 1);
- }
- if ((length = recv(fd, buf, len, flags)) >= 0)
- {
- TRACE(" -> %i bytes\n", length);
-
- close(fd);
- _enable_event(s, FD_READ, 0, 0);
- return length;
- }
- SetLastError(wsaErrno());
- close(fd);
- }
- else SetLastError(WSAENOTSOCK);
- WARN(" -> ERROR\n");
- return SOCKET_ERROR;
+ if ( WSARecvFrom (s, &wsabuf, 1, &n, &dwFlags, NULL, NULL, NULL, NULL) == SOCKET_ERROR )
+ return SOCKET_ERROR;
+ else
+ return n;
}
/***********************************************************************
@@ -1842,60 +1821,13 @@
int WINAPI WS_recvfrom(SOCKET s, char *buf, INT len, int flags,
struct WS_sockaddr *from, int *fromlen)
{
- int fd = _get_sock_fd(s);
- int res;
+ DWORD n, dwFlags = flags;
+ WSABUF wsabuf = { len, buf };
- TRACE("socket %04x, ptr %08x, len %d, flags %d\n", s, (unsigned)buf, len, flags);
-#if DEBUG_SOCKADDR
- if (from)
- dump_sockaddr(from);
+ if ( WSARecvFrom (s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL) == SOCKET_ERROR )
+ return SOCKET_ERROR;
else
- DPRINTF("from = NULL\n");
-#endif
-
- res=SOCKET_ERROR;
- if (fd != -1)
- {
- struct sockaddr* uaddr;
- int uaddrlen;
- int length;
-
- if (_is_blocking(s))
- {
- /* block here */
- /* FIXME: OOB and exceptfds */
- do_block(fd, 1);
- }
-
- uaddr=ws_sockaddr_alloc(from,fromlen,&uaddrlen);
- length=recvfrom(fd, buf, len, flags, uaddr, &uaddrlen);
- if (length < 0)
- {
- SetLastError(wsaErrno());
- WARN(" -> ERROR\n");
- }
- else if (ws_sockaddr_u2ws(uaddr,uaddrlen,from,fromlen) != 0)
- {
- /* The from buffer was too small, but we read the data
- * anyway. Is that really bad?
- */
- SetLastError(WSAEFAULT);
- WARN(" -> WSAEFAULT\n");
- }
- else
- {
- TRACE(" -> %i bytes\n", length);
- _enable_event(s, FD_READ, 0, 0);
- res=length;
- }
- close(fd);
- }
- else
- {
- SetLastError(WSAENOTSOCK);
- WARN(" -> WSAENOTSOCK\n");
- }
- return res;
+ return n;
}
/***********************************************************************
@@ -2012,34 +1944,13 @@
*/
int WINAPI WS_send(SOCKET s, const char *buf, int len, int flags)
{
- int fd = _get_sock_fd(s);
+ DWORD n;
+ WSABUF wsabuf = { len, (char*) buf };
- TRACE("socket %04x, ptr %p, length %d, flags %d\n", s, buf, len, flags);
- if (fd != -1)
- {
- int length;
-
- if (_is_blocking(s))
- {
- /* block here */
- /* FIXME: exceptfds */
- do_block(fd, 2);
- }
- if ((length = send(fd, buf, len, flags)) < 0 )
- {
- SetLastError(wsaErrno());
- if( GetLastError() == WSAEWOULDBLOCK )
- _enable_event(s, FD_WRITE, 0, 0);
- }
- else
- {
- close(fd);
- return length;
- }
- close(fd);
- }
- else SetLastError(WSAENOTSOCK);
- return SOCKET_ERROR;
+ if ( WSASendTo ( s, &wsabuf, 1, &n, flags, NULL, 0, NULL, NULL) == SOCKET_ERROR )
+ return SOCKET_ERROR;
+ else
+ return n;
}
/***********************************************************************
@@ -2050,43 +1961,106 @@
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
{
- INT iFlags = 0;
- INT rc = 0;
- DWORD dwCount;
+ return WSASendTo ( s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags,
+ NULL, 0, lpOverlapped, lpCompletionRoutine );
+}
- /* Overlapped is not supported or checked for */
- FIXME( "(%u,%p,0x%lx,%p,0x%lx,%p,%p): semi stub\n",
- s, lpBuffers, dwBufferCount, lpNumberOfBytesSent,
- dwFlags, lpOverlapped, lpCompletionRoutine );
+/***********************************************************************
+ * WSASendTo (WS2_32.74)
+ */
+INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
+ LPDWORD lpNumberOfBytesSent, DWORD dwFlags,
+ const struct WS_sockaddr *to, int tolen,
+ LPWSAOVERLAPPED lpOverlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
+{
+ int i, n, fd, err = WSAENOTSOCK;
+ struct iovec* iovec;
+ struct msghdr msghdr;
- /* Convert setup flags */
- if( dwFlags & MSG_DONTROUTE )
- {
- iFlags |= MSG_DONTROUTE;
- }
+ TRACE ("socket %04x, wsabuf %p, nbufs %ld, flags %ld, to %p, tolen %d, ovl %p, func %p\n",
+ s, lpBuffers, dwBufferCount, dwFlags,
+ to, tolen, lpOverlapped, lpCompletionRoutine);
- if( dwFlags & MSG_OOB )
- {
- iFlags |= MSG_OOB;
- }
+ fd = _get_sock_fd(s);
- /* Indicate nothing yet sent */
- *lpNumberOfBytesSent = 0;
+ if ( fd == -1 )
+ goto error;
- /* Send all buffers with the same flags */
- for(dwCount = 0; dwCount < dwBufferCount; dwCount++ )
- {
- if( ( rc = WS_send( s, lpBuffers[ dwCount ].buf,
- lpBuffers[ dwCount ].len, iFlags ) ) != 0 )
+ iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) );
+
+ if ( !iovec )
{
- break;
+ err = WSAENOBUFS;
+ goto err_close;
}
- /* Indicate that we've sent something */
- *lpNumberOfBytesSent += lpBuffers[ dwCount ].len;
- }
+ for ( i = 0; i < dwBufferCount; i++ )
+ {
+ iovec[i].iov_base = lpBuffers[i].buf;
+ iovec[i].iov_len = lpBuffers[i].len;
+ }
- return rc;
+ msghdr.msg_name = NULL;
+
+ if (to)
+ {
+#if DEBUG_SOCKADDR
+ dump_sockaddr (to);
+#endif
+ msghdr.msg_name = (void*) ws_sockaddr_ws2u (to, tolen, &msghdr.msg_namelen);
+ if ( !msghdr.msg_name )
+ {
+ err = WSAEFAULT;
+ goto err_free;
+ }
+ }
+ else
+ msghdr.msg_namelen = 0;
+
+ msghdr.msg_iov = iovec;
+ msghdr.msg_iovlen = dwBufferCount;
+ msghdr.msg_control = NULL;
+ msghdr.msg_controllen = 0;
+ msghdr.msg_flags = 0;
+
+ /* FIXME: Treat overlapped IO here */
+
+ if (_is_blocking(s))
+ {
+ /* FIXME: exceptfds? */
+ do_block(fd, 2);
+ }
+
+ /* FIXME: can we support MSG_PARTIAL ? How does it relate to sendmsg()'s msg_flags ? */
+
+ if ((n = sendmsg (fd, &msghdr, dwFlags)) == -1)
+ {
+ err = wsaErrno();
+ if ( err == WSAEWOULDBLOCK )
+ _enable_event (s, FD_WRITE, 0, 0);
+ goto err_free;
+ }
+
+ *lpNumberOfBytesSent = n;
+
+ ws_sockaddr_free ( msghdr.msg_name, to );
+ WS_FREE ( iovec );
+ close ( fd );
+
+ return 0;
+
+err_free:
+ ws_sockaddr_free ( msghdr.msg_name, to );
+ WS_FREE ( iovec );
+
+err_close:
+ close ( fd );
+
+error:
+ WARN (" -> ERROR %d\n", err);
+ SetLastError (err);
+ return SOCKET_ERROR;
}
/***********************************************************************
@@ -2103,46 +2077,13 @@
int WINAPI WS_sendto(SOCKET s, const char *buf, int len, int flags,
const struct WS_sockaddr *to, int tolen)
{
- int fd = _get_sock_fd(s);
- int res;
+ DWORD n;
+ WSABUF wsabuf = { len, (char*) buf };
- TRACE("socket %04x, ptr %p, length %d, flags %d\n", s, buf, len, flags);
-
- res=SOCKET_ERROR;
- if (fd != -1)
- {
- const struct sockaddr* uaddr;
- int uaddrlen;
-
- uaddr=ws_sockaddr_ws2u(to,tolen,&uaddrlen);
- if (uaddr == NULL)
- {
- SetLastError(WSAEFAULT);
- }
- else
- {
- if (_is_blocking(s))
- {
- /* block here */
- /* FIXME: exceptfds */
- do_block(fd, 2);
- }
- res=sendto(fd, buf, len, flags, uaddr, uaddrlen);
- if (res < 0 )
- {
- SetLastError(wsaErrno());
- if( GetLastError() == WSAEWOULDBLOCK )
- _enable_event(s, FD_WRITE, 0, 0);
- }
- ws_sockaddr_free(uaddr,to);
- }
- close(fd);
- }
+ if ( WSASendTo (s, &wsabuf, 1, &n, flags, to, tolen, NULL, NULL) == SOCKET_ERROR )
+ return SOCKET_ERROR;
else
- {
- SetLastError(WSAENOTSOCK);
- }
- return res;
+ return n;
}
/***********************************************************************
@@ -3302,35 +3243,130 @@
/***********************************************************************
+ * WSARecv (WS2_32.67)
+ */
+int WINAPI WSARecv (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
+ LPDWORD NumberOfBytesReceived, LPDWORD lpFlags,
+ LPWSAOVERLAPPED lpOverlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
+{
+ return WSARecvFrom (s, lpBuffers, dwBufferCount, NumberOfBytesReceived, lpFlags,
+ NULL, NULL, lpOverlapped, lpCompletionRoutine);
+}
+
+/***********************************************************************
* WSARecvFrom (WS2_32.69)
*/
INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct WS_sockaddr *lpFrom,
LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine )
+
{
- DWORD dwCount;
- INT rc;
+ /* Uses recvmsg() in order to provide scatter-gather I/O */
- FIXME( "(%i,%p,%lu,%p,%p,%p,%p,%p,%p: stub\n",
- s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags,
- lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine );
+ struct iovec* iovec;
+ struct msghdr msghdr;
+ int fd, i, length, err = WSAENOTSOCK;
- for( dwCount = 0, rc = 0; dwCount < dwBufferCount; dwCount++ )
- {
+ TRACE("socket %04x, wsabuf %p, nbufs %ld, flags %ld, from %p, fromlen %ld, ovl %p, func %p\n",
+ s, lpBuffers, dwBufferCount, *lpFlags, lpFrom,
+ (lpFromlen ? *lpFromlen : -1L),
+ lpOverlapped, lpCompletionRoutine);
- if( ( rc = WS_recvfrom(s, lpBuffers[ dwCount ].buf, (INT)lpBuffers[ dwCount ].len,
- (INT)*lpFlags, lpFrom, lpFromlen ) ) != 0 )
+ fd = _get_sock_fd(s);
+
+ if (fd == -1)
{
- break;
+ err = WSAENOTSOCK;
+ goto error;
}
- }
+ /* FIXME: should this be HeapAlloc() or WS_ALLOC ? */
+ iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) );
+ if ( !iovec )
+ {
+ err = WSAENOBUFS;
+ goto err_close;
+ }
- return rc;
+ for (i = 0; i < dwBufferCount; i++)
+ {
+ iovec[i].iov_base = lpBuffers[i].buf;
+ iovec[i].iov_len = lpBuffers[i].len;
+ }
+
+ msghdr.msg_name = NULL;
+
+ if ( lpFrom )
+ {
+#if DEBUG_SOCKADDR
+ dump_sockaddr (lpFrom);
+#endif
+
+ msghdr.msg_namelen = *lpFromlen;
+ msghdr.msg_name = ws_sockaddr_alloc (lpFrom, lpFromlen, &msghdr.msg_namelen);
+ }
+ else
+ msghdr.msg_namelen = 0;
+
+ msghdr.msg_iov = iovec;
+ msghdr.msg_iovlen = dwBufferCount;
+ msghdr.msg_control = NULL;
+ msghdr.msg_controllen = 0;
+ msghdr.msg_flags = 0;
+
+ /* FIXME: Treat overlapped IO here */
+
+ if (_is_blocking(s))
+ {
+ /* block here */
+ /* FIXME: OOB and exceptfds? */
+ do_block(fd, 1);
+ }
+
+ /* FIXME: can we support MSG_PARTIAL ?
+ How does it relate to recvmsg()'s msg_flags ? */
+
+ if ((length = recvmsg (fd, &msghdr, *lpFlags)) == -1)
+ {
+ err = wsaErrno();
+ goto err_free;
+ }
+
+ TRACE(" -> %i bytes\n", length);
+
+ if ( lpFrom && ws_sockaddr_u2ws (msghdr.msg_name, msghdr.msg_namelen, lpFrom, lpFromlen) != 0 )
+ {
+ /* The from buffer was too small, but we read the data
+ * anyway. Is that really bad?
+ */
+ SetLastError ( WSAEFAULT );
+ WARN ( " -> Address buffer too small\n" );
+ }
+
+ *lpNumberOfBytesRecvd = length;
+
+ WS_FREE (iovec);
+ ws_sockaddr_free ( msghdr.msg_name, lpFrom );
+ close(fd);
+ _enable_event(s, FD_READ, 0, 0);
+
+ return 0;
+
+err_free:
+ WS_FREE (iovec);
+ ws_sockaddr_free ( msghdr.msg_name, lpFrom );
+
+err_close:
+ close (fd);
+
+error:
+ WARN(" -> ERROR %d\n", err);
+ SetLastError ( err );
+ return SOCKET_ERROR;
}
-
/***********************************************************************
* WSCInstallProvider (WS2_32.88)
*/
diff --git a/dlls/winsock/ws2_32.spec b/dlls/winsock/ws2_32.spec
index 62294c1..34dfcee 100644
--- a/dlls/winsock/ws2_32.spec
+++ b/dlls/winsock/ws2_32.spec
@@ -79,14 +79,14 @@
64 stub WSANtohl
65 stub WSANtohs
66 stub WSAProviderConfigChange
-67 stub WSARecv
+67 stdcall WSARecv(long ptr long ptr ptr ptr ptr) WSARecv
68 stub WSARecvDisconnect
69 stdcall WSARecvFrom(long ptr long ptr ptr ptr ptr ptr ptr ) WSARecvFrom
70 stub WSARemoveServiceClass
71 forward WSAResetEvent KERNEL32.ResetEvent
72 stdcall WSASend(long ptr long ptr long ptr ptr) WSASend
73 stub WSASendDisconnect
-74 stub WSASendTo
+74 stdcall WSASendTo(long ptr long ptr long ptr long ptr ptr) WSASendTo
75 stub WSASetEvent
76 stub WSASetServiceA
77 stub WSASetServiceW