PATCH: Move recv() functionality to WS2_32 code
For the recv() family of functions, WSARecvFrom() becomes the work horse.
All other functions (WSARecv(), recv(), recvfrom(), ...) are only wrappers
around WSARecvFrom().
To provide the scatter/gather functionality of WSARecvFrom(), the Unix system call
used as backend is recvmsg() rather than recvfrom().
Patch against: Wine CVS 2002-04-04.
Test status: Compiles, no warnings.
Tested with 16 bit apps: FreeAgent (newsreader), Solstice mail,
nslookup, teraterm (telnet)
(16 bit apps now call WS2_32 code!)
Modified files:
dlls/winsock : socket.c, ws2_32.spec
diff -ruNX diffignore MW/wine/dlls/winsock/socket.c TMP/wine/dlls/winsock/socket.c
--- MW/wine/dlls/winsock/socket.c Thu Apr 4 09:37:38 2002
+++ TMP/wine/dlls/winsock/socket.c Thu Apr 4 10:58:53 2002
@@ -1797,34 +1797,13 @@
*/
int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags)
{
- int fd = _get_sock_fd(s);
-
- 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);
+ DWORD n, dwFlags = flags;
+ WSABUF wsabuf = { len, buf };
- 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;
}
/***********************************************************************
@@ -3302,34 +3234,129 @@
/***********************************************************************
+ * 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 */
+
+ struct iovec* iovec;
+ struct msghdr msghdr;
+ int fd, i, length, err = WSAENOTSOCK;
+
+ 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);
+
+ fd = _get_sock_fd(s);
- FIXME( "(%i,%p,%lu,%p,%p,%p,%p,%p,%p: stub\n",
- s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags,
- lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine );
+ if (fd == -1)
+ {
+ err = WSAENOTSOCK;
+ goto error;
+ }
- for( dwCount = 0, rc = 0; dwCount < dwBufferCount; dwCount++ )
- {
+ /* FIXME: should this be HeapAlloc() or WS_ALLOC ? */
+ iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) );
+ if ( !iovec )
+ {
+ err = WSAENOBUFS;
+ goto err_close;
+ }
- if( ( rc = WS_recvfrom(s, lpBuffers[ dwCount ].buf, (INT)lpBuffers[ dwCount ].len,
- (INT)*lpFlags, lpFrom, lpFromlen ) ) != 0 )
+ for (i = 0; i < dwBufferCount; i++)
{
- break;
+ iovec[i].iov_base = lpBuffers[i].buf;
+ iovec[i].iov_len = lpBuffers[i].len;
}
- }
+ msghdr.msg_name = NULL;
- return rc;
-}
+ 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 -ruNX diffignore MW/wine/dlls/winsock/ws2_32.spec TMP/wine/dlls/winsock/ws2_32.spec
--- MW/wine/dlls/winsock/ws2_32.spec Thu Apr 4 09:37:38 2002
+++ TMP/wine/dlls/winsock/ws2_32.spec Thu Apr 4 10:58:53 2002
@@ -79,7 +79,7 @@
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