[mswsock.dll] TransmitFile part [1/2]

Łukasz Chróst lukost at gmail.com
Tue Jun 27 06:52:20 CDT 2006


changelog:
    - removed stubbed TransmitFile
    - created helper functions for socket handling
    - created new APC service function for sending data
    - created non-overlapped TransmitFile
    - created overlapped TransmitFile (they work differently - it is a
pity but they have to handle write timeouts different way)
    - created TransmitFile (as for now it doesn't utilize HighOffset)

--
Łukasz Chróst
-------------- next part --------------
Index: dlls/mswsock/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/mswsock/Makefile.in,v
retrieving revision 1.3
diff -u -r1.3 Makefile.in
--- dlls/mswsock/Makefile.in	9 May 2005 14:42:33 -0000	1.3
+++ dlls/mswsock/Makefile.in	25 Jun 2006 22:31:28 -0000
@@ -1,16 +1,20 @@
+EXTRADEFS = -DUSE_WS_PREFIX
 TOPSRCDIR = @top_srcdir@
 TOPOBJDIR = ../..
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = mswsock.dll
 IMPORTLIB = libmswsock.$(IMPLIBEXT)
-IMPORTS   = ws2_32 iphlpapi kernel32
+IMPORTS   = ws2_32 iphlpapi kernel32 ntdll
+
 
 C_SRCS = \
 	mswsock.c
 
 RC_SRCS = version.rc
 
+SUBDIRS = tests
+
 @MAKE_DLL_RULES@
 
 ### Dependencies:
Index: dlls/mswsock/mswsock.c
===================================================================
RCS file: /home/wine/wine/dlls/mswsock/mswsock.c,v
retrieving revision 1.4
diff -u -r1.4 mswsock.c
--- dlls/mswsock/mswsock.c	23 May 2006 12:48:20 -0000	1.4
+++ dlls/mswsock/mswsock.c	27 Jun 2006 11:31:06 -0000
@@ -19,18 +19,739 @@
  */
 
 #include "config.h"
+#include "wine/port.h"
 
 #include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_IPC_H
+# include <sys/ipc.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+# include <sys/sockio.h>
+#endif
 
+#if defined(__EMX__)
+# include <sys/so_ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_MSG_H
+# include <sys/msg.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <stdlib.h>
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+#ifdef HAVE_NET_IF_H
+# include <net/if.h>
+#endif
+
+#ifdef HAVE_NETIPX_IPX_H
+# include <netipx/ipx.h>
+# define HAVE_IPX
+#elif defined(HAVE_LINUX_IPX_H)
+# ifdef HAVE_ASM_TYPES_H
+#  include <asm/types.h>
+# endif
+# include <linux/ipx.h>
+# define HAVE_IPX
+#endif
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "winnls.h"
 #include "winsock2.h"
 #include "mswsock.h"
-
+#include "ws2tcpip.h"
+#include "ws2spi.h"
+#include "wsipx.h"
+#include "winnt.h"
+#include "iphlpapi.h"
+#include "thread.h"
+#include "wine/server.h"
 #include "wine/debug.h"
+#include "wine/unicode.h"
+
+#ifdef HAVE_IPX
+# include "wsnwlink.h"
+#endif
+
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# define sipx_network    sipx_addr.x_net
+# define sipx_node       sipx_addr.x_host.c_host
+#endif  /* __FreeBSD__ */
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ~0UL
+#endif
+
+/* ************************************************************************************************ */
+/* Handle validation against INVALID_HANDLE_VALUE */
+#define HANDLE_VALID(x) (!(x==INVALID_HANDLE_VALUE))
 
+/* free memory and set pointer to NULL */
+#ifndef SAFE_RELEASE
+#define SAFE_RELEASE(x) {if(x) {free(x); x=NULL;}}
+#endif
+
+/* CloseHandle and set it to INVALID_HANDLE_VALUE  */
+#ifndef SAFE_HRELEASE
+#define SAFE_HRELEASE(x) {if(HANDLE_VALID(x)) {CloseHandle(x); x=INVALID_HANDLE_VALUE;}}
+#endif
+/* ************************************************************************************************ */
+
+#define FILE_DATA_BUFFER_LENGTH 1024
+
+/* HANDLE<->SOCKET conversion (SOCKET is UINT_PTR). */
+#define SOCKET2HANDLE(s) ((HANDLE)(s))
+#define HANDLE2SOCKET(h) ((SOCKET)(h))
+
+#ifdef SO_SNDTIMEO
+#define GET_SNDTIMEO(fd) get_rcvsnd_timeo( (fd), SO_SNDTIMEO)
+#else
+#define GET_SNDTIMEO(fd) (-1)
+#endif
+
+/* ************************************************************************************************ */
 WINE_DEFAULT_DEBUG_CHANNEL(mswsock);
 
+
+/* ************************************************************************************************ */
+/* Async IO declarations */
+/* ************************************************************************************************ */
+typedef struct async_callinfo
+{
+	UCHAR   bAbortIOEvent;
+	UCHAR   bStartIOEvent;
+	
+	HANDLE  event;
+	DWORD  	dwCurrentId;	/* id of part that should be checked at the moment */
+	DWORD  	dwBytesSent;	/* how many bytes have been already sent */
+	DWORD  	dwPartsCount;	/* how many parts there are */
+	DWORD	dwFlags;
+	LPWSAOVERLAPPED	user_overlapped;	
+	HANDLE 	hSocket;
+	int		sd;				/* socket descriptor */
+	struct iovec	*iov;
+} async_callinfo;
+
+typedef struct msws_async
+{
+	DWORD 					packetID;	/* this packet id */
+	DWORD					dwElFlags; 	/* TP_ELEMENT_FILE || TP_ELEMENT_MEMORY */
+	ULONG					cLength;	/* how much data to send */
+	DWORD 					dwJunkSize;	
+	union 	/* simmilar to TRANSMIT_PACKETS_ELEMENT but we do not use HANDLE for file but fd */
+	{
+		struct
+		{
+			LARGE_INTEGER *lpFileOffset;
+			int			  fd;
+			HANDLE 		  hFile;
+		};
+		LPVOID	lpBuffer;
+	};
+	struct async_callinfo *	lpCallInfo; /* common  information  for all APC's for the function call*/
+}msws_async;
+
+/* ************************************************************************************************ */
+/* Prepare async_callinfo structure */
+static async_callinfo * MWS2_make_callinfo(SOCKET s, int sd, LPVOID iov,
+		LPWSAOVERLAPPED lpOverlapped, DWORD dwParts, DWORD dwFlags, IO_STATUS_BLOCK **piosb)
+{
+    struct async_callinfo *ci = HeapAlloc( GetProcessHeap(), 0, sizeof( struct async_callinfo ) );
+
+    TRACE( "ci %p\n", ci );
+
+    if (!ci)
+        return NULL;
+
+	memset(ci, 0, sizeof(struct async_callinfo));
+	
+	ci->bAbortIOEvent = 0;
+	ci->bStartIOEvent = 0;
+	
+    ci->hSocket = (HANDLE) s;
+	ci->dwPartsCount = dwParts;
+	ci->sd = sd;
+	ci->iov = iov;
+	ci->dwFlags = dwFlags;
+	ci->user_overlapped = lpOverlapped;
+    
+	if ( lpOverlapped )
+    {
+        *piosb = (IO_STATUS_BLOCK*)lpOverlapped;
+         ci->event = lpOverlapped->hEvent;
+         NtResetEvent(ci->event, NULL);
+    }
+    else if (!(*piosb = HeapAlloc( GetProcessHeap(), 0, sizeof(IO_STATUS_BLOCK))))
+        goto error;
+
+    (*piosb)->Information = 0;
+    (*piosb)->u.Status = STATUS_PENDING;		
+
+    return ci;
+error:
+	HeapFree( GetProcessHeap(), 0, ci );	
+	return NULL;
+	
+}
+
+/* ************************************************************************************************ */
+/* Prepare msws_async structure */
+static msws_async * MWS2_make_async(DWORD id, DWORD dwElFlags, ULONG length,
+	ULONG dwJunkSize, LARGE_INTEGER *lpOffset, int fd, HANDLE hFile, LPVOID pBuffer )
+{
+    struct msws_async *mswsa = HeapAlloc( GetProcessHeap(), 0, 
+											sizeof( struct msws_async ) );
+
+    TRACE( "mswsa %p\n", mswsa );
+
+    if (!mswsa)
+        return NULL;
+
+	memset(mswsa, 0, sizeof(struct msws_async));
+	
+	mswsa->cLength = length;
+	mswsa->dwJunkSize = dwJunkSize;
+	mswsa->packetID = id;
+	mswsa->dwElFlags = dwElFlags;
+	if(dwElFlags & TP_ELEMENT_FILE)
+	{
+		if(dwElFlags & TP_ELEMENT_MEMORY)
+			goto error;
+		mswsa->fd = fd;
+		mswsa->hFile = hFile;
+		mswsa->lpFileOffset = lpOffset;
+	}
+	else if(dwElFlags & TP_ELEMENT_MEMORY)
+	{
+		mswsa->lpBuffer = pBuffer;
+	}
+	else 
+	{
+		goto error;
+	}
+
+
+    return mswsa;
+error:
+	HeapFree( GetProcessHeap(), 0, mswsa );
+	return NULL;
+}
+
+/* ************************************************************************************************ */
+/* register APC */
+static void WINAPI WS2_async_send_mixed(void*, IO_STATUS_BLOCK*, ULONG);
+
+static DWORD MWS2_queue_async(struct msws_async * mswsa, IO_STATUS_BLOCK* iosb)
+{
+    PIO_APC_ROUTINE     apc;
+    int                 type;
+    NTSTATUS            status;
+
+    apc = WS2_async_send_mixed; type = ASYNC_TYPE_WRITE; 
+
+    SERVER_START_REQ( register_async )
+    {
+        req->handle = mswsa->lpCallInfo->hSocket;
+        req->io_apc = apc;
+        req->io_sb = iosb;
+        req->io_user = mswsa;
+        req->type = type;
+        req->count = iosb->Information;
+        status = wine_server_call( req );
+    }
+    SERVER_END_REQ;
+
+    if ( status ) iosb->u.Status = status;
+    if ( iosb->u.Status != STATUS_PENDING )
+    {
+        /* Note: we get here a non zero status when we couldn't queue the async
+         * in the server. Therefore, we simply terminate the async.
+         */
+        status = iosb->u.Status;
+/*        ws2_async_terminate(wsa, iosb);*/
+        return status;
+    }
+    NtCurrentTeb()->num_async_io++;
+    return STATUS_SUCCESS;
+}
+
+/* ************************************************************************************************ */
+inline static DWORD NtStatusToWSAError( const DWORD status )
+{
+    /* We only need to cover the status codes set by server async request handling */
+    DWORD wserr;
+    switch ( status )
+    {
+    case STATUS_SUCCESS:              wserr = 0;                     break;
+    case STATUS_PENDING:              wserr = WSA_IO_PENDING;        break;
+    case STATUS_INVALID_HANDLE:       wserr = WSAENOTSOCK;           break;  /* WSAEBADF ? */
+    case STATUS_INVALID_PARAMETER:    wserr = WSAEINVAL;             break;
+    case STATUS_PIPE_DISCONNECTED:    wserr = WSAESHUTDOWN;          break;
+    case STATUS_CANCELLED:            wserr = WSA_OPERATION_ABORTED; break;
+    case STATUS_TIMEOUT:              wserr = WSAETIMEDOUT;          break;
+    case STATUS_NO_MEMORY:            wserr = WSAEFAULT;             break;
+    default:
+        if ( status >= WSABASEERR && status <= WSABASEERR+1004 )
+            /* It is not a NT status code but a winsock error */
+            wserr = status;
+        else
+        {
+            wserr = RtlNtStatusToDosError( status );
+            FIXME( "Status code %08lx converted to DOS error code %lx\n", status, wserr );
+        }
+    }
+    return wserr;
+}
+
+/* ************************************************************************************************ */
+/* forward declarations... */
+UINT wsaErrno(void);
+
+/* ************************************************************************************************ */
+/* set last error code from NT status without mapping WSA errors */
+inline static unsigned int set_error( unsigned int err )
+{
+    if (err)
+    {
+        err = NtStatusToWSAError( err );
+        SetLastError( err );
+    }
+    return err;
+}
+
+/* ************************************************************************************************ */
+/* Get fd from socket via server call */
+inline static int get_sock_fd( SOCKET s, DWORD access, int *flags )
+{
+    int fd;
+    if (set_error( wine_server_handle_to_fd( SOCKET2HANDLE(s), access, &fd, flags ) ))
+        return -1;
+    return fd;
+}
+
+/* ************************************************************************************************ */
+/* release previous */
+inline static void release_sock_fd( SOCKET s, int fd )
+{
+    wine_server_release_fd( SOCKET2HANDLE(s), fd );
+}
+
+
+/* ************************************************************************************************ */
+/* Utility: get the SO_RCVTIMEO or SO_SNDTIMEO socket option
+ * from an fd and return the value converted to milli seconds
+ * or -1 if there is an infinite time out */
+static inline int get_rcvsnd_timeo( int fd, int optname)
+{
+  struct timeval tv;
+  unsigned int len = sizeof(tv);
+  int ret = getsockopt(fd, SOL_SOCKET, optname, &tv, &len);
+  if( ret >= 0)
+      ret = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+  if( ret <= 0 ) /* tv == {0,0} means infinite time out */
+      return -1;
+  return ret;
+}
+
+static inline void ws_sockaddr_free(const struct sockaddr* uaddr, const struct WS_sockaddr* wsaddr)
+{
+    if (uaddr!=(const struct sockaddr*)wsaddr)
+        HeapFree(GetProcessHeap(), 0, (void *)uaddr);
+}
+/* ************************************************************************************************ */
+/* utility: given an fd, will block until one of the events occurs */
+static inline int do_block( int fd, int events, int timeout )
+{
+  struct pollfd pfd;
+  int ret;
+
+  pfd.fd = fd;
+  pfd.events = events;
+
+  while ((ret = poll(&pfd, 1, timeout)) < 0)
+  {
+      if (errno != EINTR)
+          return -1;
+  }
+  if( ret == 0 )
+      return 0;
+  return pfd.revents;
+}
+
+/* ************************************************************************************************ */
+static void _enable_event( HANDLE s, unsigned int event,
+                           unsigned int sstate, unsigned int cstate )
+{
+    SERVER_START_REQ( enable_socket_event )
+    {
+        req->handle = s;
+        req->mask   = event;
+        req->sstate = sstate;
+        req->cstate = cstate;
+        wine_server_call( req );
+    }
+    SERVER_END_REQ;
+}
+
+/* ************************************************************************************************ */
+static int _is_blocking(SOCKET s)
+{
+    int ret;
+    SERVER_START_REQ( get_socket_event )
+    {
+        req->handle  = SOCKET2HANDLE(s);
+        req->service = FALSE;
+        req->c_event = 0;
+        wine_server_call( req );
+        ret = (reply->state & FD_WINE_NONBLOCKING) == 0;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/* ************************************************************************************************ *
+ *             MWS2_send                (INTERNAL)
+ *
+ * Workhorse for both synchronous and asynchronous send() operations.
+ */
+static int MWS2_send( int fd, struct iovec* iov, int count, DWORD dwFlags )
+{
+    struct msghdr hdr;
+    int n = -1;
+	
+	TRACE("fd: %d, iovec: %p, count: %d, dwFlags: %ld\n",
+			fd, iov, count, dwFlags);
+
+	memset(&hdr, 0, sizeof (struct msghdr));
+	
+    hdr.msg_iov = iov;
+    hdr.msg_iovlen = count;
+#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
+    hdr.msg_accrights = NULL;
+    hdr.msg_accrightslen = 0;
+#else
+    hdr.msg_control = NULL;
+    hdr.msg_controllen = 0;
+    hdr.msg_flags = 0;
+#endif
+	
+	ws_sockaddr_free( hdr.msg_name, (struct WS_sockaddr *)0 );
+    n = sendmsg(fd, &hdr, dwFlags);
+
+    return n;
+}
+
+/* ************************************************************************************************ *
+ *             MWS2_send_mixed                (INTERNAL)
+ *
+ * Workhorse for both synchronous and asynchronous send() operations.
+ */
+static int MWS2_send_mixed( struct msws_async * mswsa, DWORD dwFlags )
+{
+	DWORD dwBytesRead;
+	DWORD dwBytesSent;
+	
+	struct iovec iovec;
+	
+	TRACE("mswsa: %p, dwFlags: %ld\n",
+			mswsa, dwFlags);
+	
+	switch(mswsa->dwElFlags)
+	{
+		case TP_ELEMENT_FILE:
+			dwBytesRead = pread(mswsa->fd,
+				mswsa->lpCallInfo->iov[1].iov_base,
+				mswsa->dwJunkSize,
+				mswsa->lpFileOffset->u.LowPart);
+				
+			iovec.iov_base 	= mswsa->lpCallInfo->iov[1].iov_base;
+			iovec.iov_len	= dwBytesRead;
+				
+			if(dwBytesRead == -1)
+				goto e_exit;
+			
+			dwBytesSent = MWS2_send(mswsa->lpCallInfo->sd,
+				&iovec, 1, mswsa->lpCallInfo->dwFlags );				
+			
+			
+			if(dwBytesSent == -1)
+				goto e_exit;
+				
+			mswsa->cLength -= dwBytesSent; /* if zeroed the call would be finished, else - reissued */
+			mswsa->lpFileOffset->u.LowPart += dwBytesSent; /* in addition to above */
+			mswsa->lpCallInfo->dwBytesSent += dwBytesSent;
+			
+			return TRUE;
+			
+		case TP_ELEMENT_MEMORY:
+			iovec.iov_base = mswsa->lpBuffer;
+			iovec.iov_len  = mswsa->cLength;
+			TRACE("base: %p, len: %ld\n",
+				iovec.iov_base, iovec.iov_len);
+			dwBytesSent = MWS2_send( mswsa->lpCallInfo->sd, &iovec, 1, 
+				mswsa->lpCallInfo->dwFlags);
+
+			if(dwBytesSent == -1)
+				goto e_exit;
+
+			mswsa->cLength 	-= dwBytesSent; /* if zeroed the call would be finished, else - reissued */
+			mswsa->lpBuffer += dwBytesSent; /* risky, but the data here isn't dynamically allocated*/
+			mswsa->lpCallInfo->dwBytesSent += dwBytesSent ;
+			return TRUE;
+		default:
+			FIXME("Unknown element type!\n");
+			goto e_exit;
+	}
+e_exit:
+	ERR("send error\n");
+	return FALSE;
+}
+
+/* ************************************************************************************************ */
+/* WS2_async_send_mixed (INTERNAL) */
+/* Handler for overlapped multisend operations */
+static void WINAPI WS2_async_send_mixed(void *as, IO_STATUS_BLOCK *piosb, ULONG status)
+{
+	struct msws_async *mswsa = 0;
+	DWORD dwRetVal = 0;
+	int err = 0;
+
+	mswsa = (msws_async *)as;	
+	TRACE( "(%p %p %lx)\n", mswsa, piosb, status );
+	
+	if(status == STATUS_ALERTED)
+	{
+		if (piosb->u.Status != STATUS_PENDING) FIXME("wrong %08lx\n", piosb->u.Status);
+		 
+		/* check to see if we want to process the call */
+
+		if(!mswsa->lpCallInfo->bStartIOEvent)
+		{
+			/* no we don't -> regis;ter it again.... */
+			TRACE("Not ready for operation, reissuing request: %ld\n", mswsa->packetID);
+			dwRetVal = MWS2_queue_async(mswsa, piosb);
+			if(dwRetVal != STATUS_SUCCESS)
+			{
+				piosb->u.Status = dwRetVal ;
+				goto e_exit;
+			}
+		}
+		/* check to see if we shall abort the event */
+		if(mswsa->lpCallInfo->bAbortIOEvent)
+		{
+			TRACE("Aborting IO, id: %ld, left: %ld\n", mswsa->packetID, 
+				mswsa->lpCallInfo->dwPartsCount);
+			piosb->u.Status = EINTR;
+			goto e_exit; /* e_exit will do just OK */
+		}
+		
+		/* check to see if we are good number */
+		if(mswsa->packetID == mswsa->lpCallInfo->dwCurrentId)
+		{
+			dwRetVal = MWS2_send_mixed(  mswsa, mswsa->lpCallInfo->dwFlags );
+			if(dwRetVal) /* the operation succeded either this or hat way... */
+			{
+				/* check to see if it completed totaly or we still have some data to send.... */
+				_enable_event( mswsa->lpCallInfo->hSocket, FD_WRITE, 0, 0 );
+				if(mswsa->cLength)
+				{
+					/* reissue write to finish */
+					TRACE("Write operation reissued (uncomplete) id: %ld\n", mswsa->packetID);
+					dwRetVal = MWS2_queue_async(mswsa, piosb);
+					if(dwRetVal != STATUS_SUCCESS)
+					{
+						piosb->u.Status = dwRetVal ;
+						goto e_exit;
+					}
+				}
+				else
+				{
+					/* write finished */
+					TRACE("Write operation finished for part id: %ld\n", mswsa->packetID);
+					mswsa->lpCallInfo->dwCurrentId++;
+					mswsa->lpCallInfo->dwPartsCount--;
+
+					/* check to see if everything has been sent */
+					if(!mswsa->lpCallInfo->dwPartsCount)
+					{
+						TRACE("finished sending all parts.\n");
+						piosb->u.Status = STATUS_SUCCESS;
+						piosb->Information = mswsa->lpCallInfo->dwBytesSent;
+						NtSetEvent(mswsa->lpCallInfo->user_overlapped->hEvent,0);
+						/* free memory */
+						HeapFree( GetProcessHeap(), 0, 
+							mswsa->lpCallInfo->iov[1].iov_base);	
+						HeapFree( GetProcessHeap(), 0, 
+							mswsa->lpCallInfo->iov);	
+						wine_server_release_fd( mswsa->lpCallInfo->hSocket, mswsa->lpCallInfo->sd );			
+						TRACE("What about fd?!\n");
+						HeapFree( GetProcessHeap(), 0, 
+							mswsa->lpCallInfo);						
+				        HeapFree( GetProcessHeap(), 0, piosb );
+					}
+
+					/* free the call information, leave operational information intact */
+					HeapFree( GetProcessHeap(), 0, mswsa);	
+				}
+			}
+			else /* the function has returned an error */
+			{
+				err = wsaErrno();
+				if ( err == WSAEINTR )
+				{
+					piosb->u.Status = STATUS_PENDING;
+					_enable_event( mswsa->lpCallInfo->hSocket, FD_WRITE, 0, 0 );
+					TRACE( "still pending\n" );
+					dwRetVal = MWS2_queue_async(mswsa, piosb);
+					if(dwRetVal != STATUS_SUCCESS)
+					{
+						piosb->u.Status = dwRetVal ;
+						goto e_exit;
+					}					
+				}
+				else
+				{
+					/* We set the status to a winsock error code and check for that
+					   later in NtStatusToWSAError () */
+					piosb->u.Status = err;
+					TRACE( "Error: %x\n", err );
+					goto e_exit;
+				}
+			}
+
+		}
+		else /* wrong packet number */
+		{
+			if((mswsa->packetID) > (mswsa->lpCallInfo->dwCurrentId))
+			{
+				/* The packet came in wrong order. Requeue it...*/
+				TRACE("trying to reissue request, id: %ld, requested: %ld\n",
+					mswsa->packetID, mswsa->lpCallInfo->dwCurrentId);
+				dwRetVal = MWS2_queue_async(mswsa, piosb);
+				if(dwRetVal != STATUS_SUCCESS)
+				{
+					piosb->u.Status = dwRetVal ;
+					goto e_exit;
+				}
+			}
+			else
+			{
+				/* something really bad happened as it is totaly abnormal */
+				TRACE("packetID is to small\n");
+				piosb->u.Status = EALREADY;				
+				goto e_exit;
+			}
+		}
+	}
+	else /* wrong call status */
+	{
+		FIXME( "status: %ld\n", status );
+		piosb->u.Status = status;
+		FIXME("Terminate the IO\n");
+		goto e_exit;
+	}
+	return;
+
+e_exit:
+
+	/* terminate the IO */
+	TRACE("Do 'terminate the IO' stuff here\n");
+	
+	/* inform rest of requests that they shall close */
+	mswsa->lpCallInfo->bAbortIOEvent = 1;
+	mswsa->lpCallInfo->dwPartsCount --;
+	
+	/* no APC's for this function call left */
+	if(!mswsa->lpCallInfo->dwPartsCount)
+	{
+		NtSetEvent(mswsa->lpCallInfo->user_overlapped->hEvent,0);
+		HeapFree( GetProcessHeap(), 0, 
+			mswsa->lpCallInfo->iov[1].iov_base);	
+		HeapFree( GetProcessHeap(), 0, 
+			mswsa->lpCallInfo->iov);	
+		wine_server_release_fd( mswsa->lpCallInfo->hSocket, mswsa->lpCallInfo->sd );			
+		
+		TRACE("fd shall be released here\n");
+		
+
+		HeapFree( GetProcessHeap(), 0, 
+			mswsa->lpCallInfo);						
+        HeapFree( GetProcessHeap(), 0, piosb );
+    }
+	HeapFree( GetProcessHeap(), 0, mswsa);						
+}
+	
+
+/* ************************************************************************************************ */
+/* ************************************************************************************************ */
+
+
 /***********************************************************************
  *		AcceptEx (MSWSOCK.@)
  *
@@ -90,8 +811,237 @@
     FIXME("not implemented\n");
 }
 
+
 /***********************************************************************
- *		TransmitFile (MSWSOCK.@)
+ *		WSARecvEx (MSWSOCK.@)
+ */
+INT WINAPI WSARecvEx(
+	SOCKET s,   /* [in] Descriptor identifying a connected socket */
+	char *buf,  /* [out] Buffer for the incoming data */
+	INT len,    /* [in] Length of buf, in bytes */
+        INT *flags) /* [in/out] Indicator specifying whether the message is
+	               fully or partially received for datagram sockets */
+{
+    FIXME("not implemented\n");
+    
+    return SOCKET_ERROR;
+}
+
+
+
+/* *********************************************************************************** */
+/* TransmitFileNormal - blocking*/
+static DWORD TransmitFileNormal(SOCKET s, int sd, int fd, struct iovec *iovec, DWORD dwFlags, UINT dwJunkSize, ULONG nFileLength)
+{
+	int err = WSAENOTSOCK;
+	ULONG nBytesSent = 0;
+	ULONG nBytesRead = 0;
+	ULONG nBytesToSend = 0;
+
+	TRACE("s: %d, sd: %d, fd: %d, iovec: %p, dwFlags: %ld, dwJunkSize: %u, nFileLength: %ld\n",
+			s, sd, fd, iovec, dwFlags, dwJunkSize, nFileLength);
+			
+	
+	if(iovec[0].iov_len)
+	{
+		nBytesToSend = iovec[0].iov_len;
+		while(nBytesToSend)
+		{
+			nBytesSent = send( s, &((char*)(iovec[0].iov_base))[nBytesSent], nBytesToSend, dwFlags );
+			if(nBytesSent == -1)
+				goto error;
+			nBytesToSend -= nBytesSent;
+		}
+	}
+	
+	iovec[1].iov_base = HeapAlloc(GetProcessHeap(), 0, dwJunkSize+1);
+	
+	nBytesSent = 0;
+	while(nFileLength)
+	{
+		int n; 
+		
+		nBytesRead = pread(fd, iovec[1].iov_base, 
+			(dwJunkSize < nFileLength) ? dwJunkSize: nFileLength,
+			nBytesSent);	
+		iovec[1].iov_len = nBytesRead;
+		
+		n = MWS2_send( sd, &iovec[1], 1, dwFlags );
+		
+/*		n = send( s, iovec[1].iov_base, iovec[1].iov_len, dwFlags ); */
+		
+		if ( n == -1 )
+		{
+			err = wsaErrno();
+			if ( err == WSAEWOULDBLOCK )
+			{
+				_enable_event(SOCKET2HANDLE(s), FD_WRITE, 0, 0);
+				continue; /* We do not mind blocking, in fact they were expected to occur */
+			}
+			goto error;
+		}
+		nFileLength -= n;
+		nBytesSent+=n;
+	}
+	
+	nBytesSent = 0;
+	if(iovec[2].iov_len)
+	{
+		nBytesToSend = iovec[2].iov_len;
+		while(nBytesToSend)
+		{
+			nBytesSent = send( s, &((char *)iovec[2].iov_base)[nBytesSent], nBytesToSend, dwFlags );
+			if(nBytesSent == -1)
+				goto error;
+			nBytesToSend -= nBytesSent;
+		}
+	}
+	
+	return TRUE;
+	
+	error:
+	WSASetLastError( err); /*FIXME*/
+	return FALSE;
+}
+
+/* *********************************************************************************** */
+/* TransmitFileOverlapped */
+static DWORD TransmitFileOverlapped(SOCKET s, int sd, HANDLE hFile, int fd, struct iovec *iovec, 
+									DWORD dwFlags, UINT dwJunkSize, DWORD dwFileLength, 
+									LPWSAOVERLAPPED lpOverlapped)
+{
+	IO_STATUS_BLOCK *iosb		=	0;
+	struct 	async_callinfo * ci	=	0;
+	struct 	msws_async * mswsa	=	0;
+	DWORD 	nParts				=	0;
+	DWORD 	len					=	0;
+	int		err 				= WSAENOTSOCK;
+	ULONG	nBytesSent 			= 0;
+	ULONG	nBytesToSend		= 0;
+	ULONG	nBytesLeft			= 0;	
+	DWORD	dwRetVal 			= 0;
+	LARGE_INTEGER 		* pLI   = 0;
+	
+	len = dwFileLength + iovec[0].iov_len + iovec[2].iov_len;
+	
+	if(!len)
+	{
+		TRACE("Exiting with true while no data to send...\n");
+		WSASetLastError(0);
+		return TRUE;
+	}
+		
+	ci = MWS2_make_callinfo(s, sd, iovec, lpOverlapped, 0, dwFlags, &iosb);
+	
+	if ( !ci )
+	{
+		ERR("Can't create ci!\n");
+		err = WSAEFAULT;
+		goto e_exit;
+	}
+	
+	nBytesSent = 0;
+	nBytesToSend 	= iovec[0].iov_len;
+	nBytesLeft 		= nBytesToSend;
+
+	while(nBytesLeft)
+	{
+		nBytesToSend = (nBytesLeft < dwJunkSize) ? nBytesLeft : dwJunkSize;
+								
+		mswsa = MWS2_make_async(nParts, TP_ELEMENT_MEMORY, nBytesToSend, dwJunkSize,
+									0, 0, 0, &((char*)iovec[0].iov_base)[nBytesSent]);
+									
+		if(!mswsa)
+			goto e_exit;
+		
+		mswsa->lpCallInfo = ci;
+		dwRetVal = MWS2_queue_async(mswsa, iosb);
+		if(dwRetVal != STATUS_SUCCESS)
+			goto e_exit;
+		
+		nBytesSent += nBytesToSend;
+		nBytesLeft -= nBytesToSend;
+		
+		nParts ++;
+	}
+	
+	iovec[1].iov_base = HeapAlloc(GetProcessHeap(), 0, dwJunkSize+1);
+	
+	nBytesSent = 0;
+	nBytesLeft = dwFileLength;
+	while(nBytesLeft)
+	{
+		pLI = HeapAlloc(GetProcessHeap(), 0, sizeof(LARGE_INTEGER));
+		pLI->u.LowPart = lpOverlapped->u.s.Offset + nBytesSent;
+		pLI->u.HighPart = lpOverlapped->u.s.OffsetHigh;
+		
+		nBytesToSend = nBytesLeft;
+		mswsa =  MWS2_make_async(nParts, TP_ELEMENT_FILE, nBytesToSend, 
+				dwJunkSize, pLI,  fd, hFile,0);
+		
+		if(!mswsa)
+			goto e_exit;
+		
+		mswsa->lpCallInfo = ci;
+		dwRetVal = MWS2_queue_async(mswsa, iosb);
+		if(dwRetVal != STATUS_SUCCESS)
+			goto e_exit;
+		
+		nBytesSent += nBytesToSend;
+		nBytesLeft -= nBytesToSend;
+		
+		nParts ++;
+	}
+	
+	nBytesSent = 0;
+	nBytesToSend 	= iovec[2].iov_len;
+	nBytesLeft 		= nBytesToSend;
+	
+	while(nBytesLeft)
+	{
+		nBytesToSend = (nBytesLeft < dwJunkSize) ? nBytesLeft : dwJunkSize;
+		mswsa = MWS2_make_async(nParts, TP_ELEMENT_MEMORY, nBytesToSend, dwJunkSize,
+									0, 0, 0, &((char*)iovec[2].iov_base)[nBytesSent]);
+		if(!mswsa)
+			goto e_exit;
+		
+		mswsa->lpCallInfo = ci;
+		dwRetVal = MWS2_queue_async(mswsa, iosb);
+		if(dwRetVal != STATUS_SUCCESS)
+			goto e_exit;
+		
+		nBytesSent += nBytesToSend;
+		nBytesLeft -= nBytesToSend;
+		
+		nParts ++;
+	}
+	
+	if(ci)
+	{
+		ci->dwPartsCount = nParts;
+		ci->bStartIOEvent = 1;
+	}
+		
+	FIXME("no immediate completion test here\n");
+    WSASetLastError( WSA_IO_PENDING );	
+	return FALSE;
+	
+	e_exit:
+	/* cancel IO!!! */
+	if(ci)
+	{
+		ci->bAbortIOEvent=1;
+		ci->bStartIOEvent=1;
+	}
+		
+	WSASetLastError( err); /*FIXME*/
+    return SOCKET_ERROR;
+}
+
+ 
+
+ /***********************************************************************
+ *		TransmitFile(MSWSOCK.@)
  *
  * This function is used to transmit a file over socket.
  *
@@ -104,7 +1054,8 @@
 	HANDLE hFile,   /* [in] Handle to the open file that should be
                            transmited */
 	DWORD nNumberOfBytesToWrite, /* [in] Number of file bytes to 
-                                        transmit */
+                                      transmit - starting offset can be set through OVERLAPPED
+							Offset and OffsetHigh fields */
 	DWORD nNumberOfBytesPerSend, /* [in] Size in bytes of each block of
                                          data sent in each send operation */
 	LPOVERLAPPED lpOverlapped, /* [in] Specify in order to achieve an 
@@ -113,24 +1064,251 @@
 	LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, 
 		/* [in] Contains pointers to data to send before and after
                    the file data is sent */
-	DWORD dwFlags) /* [in] Flags */
+	DWORD dwFlags) /* [in] Flags */ 
 {
-    FIXME("not implemented\n");
+	unsigned int 	i			= 0;
+	long 		 	filelen		= 0;
+	DWORD 		 	filepos		= 0;
+	unsigned int 	nVectors 	= 0;
+	unsigned int	nFileJunks	= 0;
+	
+	int sd, fd , ret = 0;
+	struct iovec* iovec;
 
-    return FALSE;
+	int FD_flags;
+	int SD_flags;
+
+	long flen;
+	
+	iovec = 0;
+	
+
+ TRACE("hSocket %04x, hFile %p, nbytes %ld, npsize %ld,  ovl %p, tfbuf %p, flags %ld\n",
+			hSocket, hFile, nNumberOfBytesToWrite, nNumberOfBytesPerSend, 
+			lpOverlapped, lpTransmitBuffers, dwFlags);	    
+	
+	if(nNumberOfBytesPerSend > FILE_DATA_BUFFER_LENGTH)
+		nNumberOfBytesPerSend = FILE_DATA_BUFFER_LENGTH; //we are using local var anyway ;-)
+	if(!nNumberOfBytesPerSend)
+		nNumberOfBytesPerSend = FILE_DATA_BUFFER_LENGTH; //we are using local var anyway ;-)		
+	
+	//check if the socket is usable
+	sd = get_sock_fd(hSocket, FILE_WRITE_DATA, &SD_flags);
+	TRACE( "sd=%d, flags=%x\n", sd, SD_flags);
+
+	if ( sd == -1 ) 
+	{
+		TRACE("Can't get sd!\n");
+		WSASetLastError(WSAEFAULT);
+		return SOCKET_ERROR;
+	}
+	
+ 	if(dwFlags & TF_REUSE_SOCKET)
+	{
+		 FIXME("TF_REUSE_SOCKET not yet implemented\n");
+		 WSASetLastError(WSAEINVAL);
+		 return FALSE;
+	}
+	
+	if(dwFlags & TF_DISCONNECT)
+	{
+		FIXME("TF_DISCONNECT not yet implemented\n");
+		WSASetLastError(WSAEINVAL);		
+		return FALSE;
+	} 
+	
+	if(lpOverlapped)
+	{
+		if(lpOverlapped->u.s.OffsetHigh)
+		{
+			FIXME("High order offset not currently supported\n");
+			WSASetLastError(WSAEINVAL);
+			return FALSE;
+		}
+	}
+	
+	//process file length
+	if(hFile)
+	{
+		TRACE("Processing file...\n");
+		
+		if(wine_server_handle_to_fd( hFile, FILE_READ_DATA, &fd, &FD_flags ))
+		{
+			TRACE("Get fd: ERROR!\n");
+			WSASetLastError(WSA_INVALID_PARAMETER);
+			return FALSE; 
+		}
+		
+		if(lpOverlapped)
+			filepos = lpOverlapped->u.s.Offset;
+		else
+			filepos = 0;
+			
+		lseek(fd, filepos, SEEK_SET);		/* back to offset */
+		flen=lseek(fd, 0,SEEK_END); 						/*get file length */
+		lseek(fd, filepos, SEEK_SET);		/* back to offset */
+	
+		
+		filelen = (flen < 0) ? 0 : flen;
+		
+		if(nNumberOfBytesToWrite)
+			filelen = (filelen < nNumberOfBytesToWrite) ? filelen : nNumberOfBytesToWrite;
+			
+		nFileJunks = filelen / nNumberOfBytesPerSend;
+		
+		if(filelen % nNumberOfBytesPerSend)
+			nFileJunks++;
+	}
+		
+
+	iovec = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(struct iovec));
+	memset(iovec, 0, 3 * sizeof(struct iovec));
+	nVectors = 3;
+	
+
+	if(lpTransmitBuffers)
+	{
+		if(lpTransmitBuffers->Head && lpTransmitBuffers->HeadLength)
+		{
+			iovec[0].iov_base = lpTransmitBuffers->Head;
+			iovec[0].iov_len	= lpTransmitBuffers->HeadLength;
+		}
+		if(lpTransmitBuffers->Tail && lpTransmitBuffers->TailLength)
+		{
+			iovec[nVectors-1].iov_base = lpTransmitBuffers->Tail;
+			iovec[nVectors-1].iov_len	 = lpTransmitBuffers->TailLength;
+		}
+	}
+	
+	if ( lpOverlapped && SD_flags & FD_FLAG_OVERLAPPED )
+	{
+		if(TransmitFileOverlapped(hSocket,  sd,hFile, fd,  iovec, dwFlags, nNumberOfBytesPerSend,
+			filelen,  lpOverlapped))
+		{
+			ret = TRUE;
+			goto ok_exit;
+		}
+		else
+			return FALSE;
+	}
+	
+	ret = TransmitFileNormal(hSocket,sd,fd,  iovec, dwFlags, nNumberOfBytesPerSend, filelen);
+
+ok_exit:
+	release_sock_fd( hSocket, sd );
+	if(iovec)
+	{
+		if(iovec[1].iov_base)
+			HeapFree(GetProcessHeap(), 0 , iovec[i].iov_base);
+		HeapFree( GetProcessHeap(), 0, iovec );
+	}
+	
+	return ret;
+	
+e_exit:
+
+	release_sock_fd( hSocket, sd );
+	if(iovec)
+	{
+		if(iovec[1].iov_base)
+			HeapFree(GetProcessHeap(), 0 , iovec[i].iov_base);
+		HeapFree( GetProcessHeap(), 0, iovec );
+	}
+	return FALSE;
 }
 
-/***********************************************************************
- *		WSARecvEx (MSWSOCK.@)
- */
-INT WINAPI WSARecvEx(
-	SOCKET s,   /* [in] Descriptor identifying a connected socket */
-	char *buf,  /* [out] Buffer for the incoming data */
-	INT len,    /* [in] Length of buf, in bytes */
-        INT *flags) /* [in/out] Indicator specifying whether the message is
-	               fully or partially received for datagram sockets */
+
+
+/* *********************************************************************************** */
+/* ----------------------------------- error handling */
+
+UINT wsaErrno(void)
 {
-    FIXME("not implemented\n");
-    
-    return SOCKET_ERROR;
+    int	loc_errno = errno;
+    WARN("errno %d, (%s).\n", loc_errno, strerror(loc_errno));
+
+    switch(loc_errno)
+    {
+	case EINTR:		return WSAEINTR;
+	case EBADF:		return WSAEBADF;
+	case EPERM:
+	case EACCES:		return WSAEACCES;
+	case EFAULT:		return WSAEFAULT;
+	case EINVAL:		return WSAEINVAL;
+	case EMFILE:		return WSAEMFILE;
+	case EWOULDBLOCK:	return WSAEWOULDBLOCK;
+	case EINPROGRESS:	return WSAEINPROGRESS;
+	case EALREADY:		return WSAEALREADY;
+	case ENOTSOCK:		return WSAENOTSOCK;
+	case EDESTADDRREQ:	return WSAEDESTADDRREQ;
+	case EMSGSIZE:		return WSAEMSGSIZE;
+	case EPROTOTYPE:	return WSAEPROTOTYPE;
+	case ENOPROTOOPT:	return WSAENOPROTOOPT;
+	case EPROTONOSUPPORT:	return WSAEPROTONOSUPPORT;
+	case ESOCKTNOSUPPORT:	return WSAESOCKTNOSUPPORT;
+	case EOPNOTSUPP:	return WSAEOPNOTSUPP;
+	case EPFNOSUPPORT:	return WSAEPFNOSUPPORT;
+	case EAFNOSUPPORT:	return WSAEAFNOSUPPORT;
+	case EADDRINUSE:	return WSAEADDRINUSE;
+	case EADDRNOTAVAIL:	return WSAEADDRNOTAVAIL;
+	case ENETDOWN:		return WSAENETDOWN;
+	case ENETUNREACH:	return WSAENETUNREACH;
+	case ENETRESET:		return WSAENETRESET;
+	case ECONNABORTED:	return WSAECONNABORTED;
+	case EPIPE:
+	case ECONNRESET:	return WSAECONNRESET;
+	case ENOBUFS:		return WSAENOBUFS;
+	case EISCONN:		return WSAEISCONN;
+	case ENOTCONN:		return WSAENOTCONN;
+	case ESHUTDOWN:		return WSAESHUTDOWN;
+	case ETOOMANYREFS:	return WSAETOOMANYREFS;
+	case ETIMEDOUT:		return WSAETIMEDOUT;
+	case ECONNREFUSED:	return WSAECONNREFUSED;
+	case ELOOP:		return WSAELOOP;
+	case ENAMETOOLONG:	return WSAENAMETOOLONG;
+	case EHOSTDOWN:		return WSAEHOSTDOWN;
+	case EHOSTUNREACH:	return WSAEHOSTUNREACH;
+	case ENOTEMPTY:		return WSAENOTEMPTY;
+#ifdef EPROCLIM
+	case EPROCLIM:		return WSAEPROCLIM;
+#endif
+#ifdef EUSERS
+	case EUSERS:		return WSAEUSERS;
+#endif
+#ifdef EDQUOT
+	case EDQUOT:		return WSAEDQUOT;
+#endif
+#ifdef ESTALE
+	case ESTALE:		return WSAESTALE;
+#endif
+#ifdef EREMOTE
+	case EREMOTE:		return WSAEREMOTE;
+#endif
+
+       /* just in case we ever get here and there are no problems */
+	case 0:			return 0;
+        default:
+		WARN("Unknown errno %d!\n", loc_errno);
+		return WSAEOPNOTSUPP;
+    }
+}
+
+UINT wsaHerrno(int loc_errno)
+{
+
+    WARN("h_errno %d.\n", loc_errno);
+
+    switch(loc_errno)
+    {
+	case HOST_NOT_FOUND:	return WSAHOST_NOT_FOUND;
+	case TRY_AGAIN:		return WSATRY_AGAIN;
+	case NO_RECOVERY:	return WSANO_RECOVERY;
+	case NO_DATA:		return WSANO_DATA;
+	case ENOBUFS:		return WSAENOBUFS;
+
+	case 0:			return 0;
+        default:
+		WARN("Unknown h_errno %d!\n", loc_errno);
+		return WSAEOPNOTSUPP;
+    }
 }
Index: dlls/mswsock/mswsock.spec
===================================================================
RCS file: /home/wine/wine/dlls/mswsock/mswsock.spec,v
retrieving revision 1.4
diff -u -r1.4 mswsock.spec
--- dlls/mswsock/mswsock.spec	21 Nov 2005 11:58:49 -0000	1.4
+++ dlls/mswsock/mswsock.spec	25 Jun 2006 22:56:26 -0000
@@ -19,7 +19,8 @@
 @ stub StartWsdpService
 @ stub StopWsdpService
 @ stub SvchostPushServiceGlobals
-@ stdcall TransmitFile(long long long long ptr ptr long)
+@ stdcall TransmitFile(long long long long ptr ptr long) TransmitFile
+@ stub TransmitPackets
 @ stub WSARecvEx
 @ stub WSPStartup
 @ stub dn_expand


More information about the wine-patches mailing list