#5 in series Patch file: 005-recv.diff Purpose: Move recv() functionality to WS2_32 code Created: 2002-01-07 Applies: CVS 2002-01-07 (with 004-socket.diff applied) This patch moves the recv() functionality to WS2_32 functions that provide a superset of the functionality of their WS counterparts. 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 WSARecv() / WSARecvFrom(), the (only) unix function called is recvmsg(). This means some overhead for simple recv() calls, but allows for a single general "work" code. dlls/winsock/socket.c: WS_recv(): Is now a wrapper around WSARecv(). WS_recvfrom(): Is now a wrapper around WSARecvFrom(). WSARecv(): Is now a wrapper around WSARecvFrom(). WSARecvFrom(): Holds all "real" recv() functionality (formerly in WS_recv() / WS_recvfrom()). Calls recvmsg() to provide for scatter/gather functionality. dlls/winsock/ws2_32.spec: Add stdcall entry for WSARecv(). Martin Wilck <Martin.Wilck@Fujitsu-Siemens.com> diff -ru -X diffignore CVS/wine/dlls/winsock/socket.c MW/wine/dlls/winsock/socket.c --- CVS/wine/dlls/winsock/socket.c Mon Jan 7 12:55:24 2002 +++ MW/wine/dlls/winsock/socket.c Mon Jan 7 12:55:37 2002 @@ -1815,34 +1815,16 @@ */ int WINAPI WS_recv(SOCKET s, char *buf, int len, int flags) { - int fd = _get_sock_fd(s); + DWORD n; + WSABUF wsabuf = { len, buf }; + DWORD dwFlags = flags; 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 ( WSARecv (s, &wsabuf, 1, &n, &dwFlags, NULL, NULL) == SOCKET_ERROR ) + return SOCKET_ERROR; + else + return n; } /*********************************************************************** @@ -1860,60 +1842,14 @@ 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; - - TRACE("socket %04x, ptr %08x, len %d, flags %d\n", s, (unsigned)buf, len, flags); -#if DEBUG_SOCKADDR - if (from) - dump_sockaddr(from); - else - DPRINTF("from = NULL\n"); -#endif - - res=SOCKET_ERROR; - if (fd != -1) - { - struct sockaddr* uaddr; - int uaddrlen; - int length; + DWORD n; + WSABUF wsabuf = { len, buf }; + DWORD dwFlags = flags; - 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); - } + if ( WSARecvFrom (s, &wsabuf, 1, &n, &dwFlags, from, fromlen, NULL, NULL) == SOCKET_ERROR ) + return SOCKET_ERROR; else - { - SetLastError(WSAENOTSOCK); - WARN(" -> WSAENOTSOCK\n"); - } - return res; + return n; } /*********************************************************************** @@ -3404,34 +3340,132 @@ /*********************************************************************** + * 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); - FIXME( "(%i,%p,%lu,%p,%p,%p,%p,%p,%p: stub\n", - s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, - lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine ); + fd = _get_sock_fd(s); - for( dwCount = 0, rc = 0; dwCount < dwBufferCount; dwCount++ ) - { + if (fd == -1) + { + err = WSAENOTSOCK; + goto error; + } - if( ( rc = WS_recvfrom(s, lpBuffers[ dwCount ].buf, (INT)lpBuffers[ dwCount ].len, - (INT)*lpFlags, lpFrom, lpFromlen ) ) != 0 ) + /* FIXME: should this be HeapAlloc() or WS_ALLOC ? */ + iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) ); + if ( !iovec ) { - break; + err = WSAENOBUFS; + goto err_close; } - } + 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 ( 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 -ru -X diffignore CVS/wine/dlls/winsock/ws2_32.spec MW/wine/dlls/winsock/ws2_32.spec --- CVS/wine/dlls/winsock/ws2_32.spec Mon Jan 7 12:42:08 2002 +++ MW/wine/dlls/winsock/ws2_32.spec Mon Jan 7 12:55:37 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