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