PATCH: Move send() functionality to WS2_32 code
In short, does the same to send() that the previous patch did to recv().
For the send() family of functions, WSASendTo() becomes the work horse. All other functions (WSASend(), send(), sendto(), ...) are only wrappers around WSASendTo().
To provide the scatter/gather functionality of WSASendTo(), the Unix system call used as backend is sendmsg() rather than sendto().
Patch against: Wine CVS 2002-04-03, with my previous patch (recv) applied.
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 TMP/wine/dlls/winsock/socket.c MW/wine/dlls/winsock/socket.c --- TMP/wine/dlls/winsock/socket.c Thu Apr 4 10:58:53 2002 +++ MW/wine/dlls/winsock/socket.c Thu Apr 4 11:01:03 2002 @@ -1944,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; }
/*********************************************************************** @@ -1982,43 +1961,106 @@ LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ) { - INT iFlags = 0; - INT rc = 0; - DWORD dwCount; - - /* 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 ); - - /* Convert setup flags */ - if( dwFlags & MSG_DONTROUTE ) - { - iFlags |= MSG_DONTROUTE; - } - - if( dwFlags & MSG_OOB ) - { - iFlags |= MSG_OOB; - } - - /* Indicate nothing yet sent */ - *lpNumberOfBytesSent = 0; - - /* 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 ) + return WSASendTo ( s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, + NULL, 0, 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; + + 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); + + fd = _get_sock_fd(s); + + if ( fd == -1 ) + goto error; + + iovec = WS_ALLOC ( dwBufferCount * sizeof (struct iovec) ); + + if ( !iovec ) + { + 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; + } + + 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) { - break; + err = wsaErrno(); + if ( err == WSAEWOULDBLOCK ) + _enable_event (s, FD_WRITE, 0, 0); + goto err_free; }
- /* Indicate that we've sent something */ - *lpNumberOfBytesSent += lpBuffers[ dwCount ].len; - } + *lpNumberOfBytesSent = n;
- return rc; + 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; }
/*********************************************************************** @@ -2035,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; - - 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; + DWORD n; + WSABUF wsabuf = { len, (char*) buf };
- 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; }
/*********************************************************************** diff -ruNX diffignore TMP/wine/dlls/winsock/ws2_32.spec MW/wine/dlls/winsock/ws2_32.spec --- TMP/wine/dlls/winsock/ws2_32.spec Thu Apr 4 10:58:53 2002 +++ MW/wine/dlls/winsock/ws2_32.spec Thu Apr 4 11:01:03 2002 @@ -86,7 +86,7 @@ 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