Le mercredi 09 septembre 2009 à 21:41 -0700, Pavel Pergamenshchik a
écrit :
> On Wed, Sep 9, 2009 at 8:28 AM, Cedric Delfosse <cdelfo...@mandriva.com> 
> wrote:
> > Hello,
> >
> > Twisted Python 8.2.0 on Windows 2000 gives me this TB when I try to use
> > the IOCP reactor. Is it supported on this platform ? (Works very well on
> > Windows XP)
> >
> > The instance's SvcRun() method failed
> >  File "win32serviceutil.pyc", line 805, in SvcRun
> >  File "server-win32.pyc", line 81, in SvcDoRun
> >  File "twisted\internet\iocpreactor\__init__.pyc", line 8, in <module>
> >  File "twisted\internet\iocpreactor\reactor.pyc", line 19, in <module>
> >  File "twisted\internet\iocpreactor\iocpsupport.pyc", line 12, in <module>
> >  File "twisted\internet\iocpreactor\iocpsupport.pyc", line 10, in __load
> >  File "iocpsupport.pyx", line 242, in iocpsupport
> > <type 'exceptions.ValueError'>: Failed to initialize Winsock function 
> > vectors
> 
> iocpreactor is not supported on Windows 2000. iocpreactor relies on
> ConnectEx() API. It was introduced in Windows XP. It is,
> theoretically, possible to work around it, but nobody has done so.

Hello,

thanks a lot.

Unfortunately I'm not used at all to Windows programming. I tried to use
a library thats wrap missing API for Windows 2000, but with no luck (gpt
some obscure DLL issues):
http://win2kgaming.site90.com/phpBB2/viewtopic.php?t=7

Maybe the ConnectEx() API replacement used by this library could be a
solution ? (see code attached to this mail)

Regards,

-- 
Cedric Delfosse                                    Mandriva / Linbox
152, rue de Grigy - Technopole Metz              57070 METZ - FRANCE
tel: +33 (0)3 87 50 87 90                        http://mandriva.com

/*
  Windows 2000 XP API Wrapper Pack
  Copyright (C) 2008 OldCigarette

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#define _WIN32_WINNT 0x0500
#include <Winsock2.h>
#include <WS2tcpip.h>
#include <WSPiApi.h>
#include <MSWSock.h>
#include <windows.h>

#include "../common/win2k_xp_debug.h"
/*Debugging*/
int debugLevel;
DbgPrintf_t DbgPrintf;

GUID ConnectExGUID    = WSAID_CONNECTEX;
GUID DisconnectExGUID = WSAID_DISCONNECTEX;
GUID TransmitFileGUID = WSAID_TRANSMITFILE;

HANDLE hHeap = NULL;

#define MALLOC(x) HeapAlloc(hHeap, 0, x)
#define FREE(x) HeapFree(hHeap, 0, x)

typedef struct _CONNECTEX_CONNECT_DATA {
	SOCKET       s;
	PVOID        lpSendBuffer;
	DWORD        dwSendDataLength;
	LPOVERLAPPED lpOverlapped;
	WSAEVENT     event;
	HANDLE       WaitObject;
} CONNECTEX_CONNECT_DATA;

void FreeConnectData(CONNECTEX_CONNECT_DATA *data) {
	if(data->lpSendBuffer) FREE(data->lpSendBuffer);
	if(data->WaitObject) 
	if(data->event != WSA_INVALID_EVENT) WSACloseEvent(data->event);
	FREE(data);
}

BOOL CALLBACK ConnectEx_CONNECT (PVOID lpParameter, BOOLEAN TimerOrWaitFired) {
	fd_set fdset;
	WSABUF wsabuf;
	DWORD  sent, dwTemp;
	int r;
	BOOL ret = FALSE;
	CONNECTEX_CONNECT_DATA *data = (CONNECTEX_CONNECT_DATA *)lpParameter;
	
	if(data->WaitObject) UnregisterWait(data->WaitObject);
	
	//Do we have a connection?
	fdset.fd_count = 1;
	fdset.fd_array[0] = data->s;
	
	if(select(0, NULL, &fdset, NULL, NULL) == 1) {
		if(!data->lpSendBuffer) { ret = TRUE; goto cleanup; }
	
		//We are ready to send data
		wsabuf.len = data->dwSendDataLength;
		wsabuf.buf = data->lpSendBuffer;
		sent = 0;
		
		if(data->event == WSA_INVALID_EVENT) {
			//Blocking - will send everything
			r = WSASend(data->s, &wsabuf, 1, &sent, 0, NULL, NULL);
			if(r == SOCKET_ERROR && debugLevel)
				DbgPrintf(DBG_WARN, S_YELLOW "ws2_32: ConnectEx_CONNECT blocking send failed 0x%08X\n", WSAGetLastError());
		} else {
			r = WSAEventSelect(data->s, data->event, FD_WRITE);
			if(r == SOCKET_ERROR) {
				if(debugLevel)
					DbgPrintf(DBG_WARN, S_YELLOW "ws2_32: Could not connect event to FD_WRITE 0x%08X\n", WSAGetLastError());			
				goto cleanup;
			}
			
			while(r != SOCKET_ERROR) {
				r = WSASend(data->s, &wsabuf, 1, &dwTemp, 0, NULL, NULL);
								
				if(r == SOCKET_ERROR && debugLevel)
					DbgPrintf(DBG_WARN, S_YELLOW "ws2_32: ConnectEx_CONNECT blocking send failed 0x%08X\n", WSAGetLastError());
				
				sent += dwTemp;
				if(sent >= data->dwSendDataLength) { ret = TRUE; goto cleanup; }
			
				wsabuf.buf += dwTemp;
				wsabuf.len -= dwTemp;
				
				WaitForSingleObject(data->event, INFINITE);
			}
		}
	} else {
		if(debugLevel)
			DbgPrintf(DBG_WARN, S_YELLOW "ws2_32: ConnectEx_CONNECT socket is not ready\n");
	}
	
cleanup:
	if(data->lpOverlapped) WSASetEvent(data->lpOverlapped->hEvent);
	FreeConnectData(data);
	return ret;
}

CONNECTEX_CONNECT_DATA *CreateConnectData
  (SOCKET s, PVOID lpSendBuffer, DWORD dwSendDataLength, LPOVERLAPPED lpOverlapped, 
   WSAEVENT event) {
	CONNECTEX_CONNECT_DATA *data;
	data = (CONNECTEX_CONNECT_DATA *)MALLOC(sizeof(CONNECTEX_CONNECT_DATA));
	
	//Store the socket to send on
	data->s = s;
	
	//Copy the send buffer
	if(lpSendBuffer) {
		data->lpSendBuffer = (PVOID)MALLOC(dwSendDataLength);
		RtlCopyMemory(data->lpSendBuffer, lpSendBuffer, dwSendDataLength);
		data->dwSendDataLength = dwSendDataLength;
	} else {
		data->lpSendBuffer = NULL;
		data->dwSendDataLength = 0;
	}
	
	//Store the event we must close
	data->event = event;
	
	data->lpOverlapped = lpOverlapped;
	
	data->WaitObject = NULL;
	
	return data;
}

BOOL PASCAL XP_ConnectEx(SOCKET s, const struct sockaddr *name, int namelen,
  PVOID lpSendBuffer, DWORD dwSendDataLength, LPDWORD lpdwBytesSent,
  LPOVERLAPPED lpOverlapped) {
	int r;
	HANDLE h;
	BOOL ret;
	CONNECTEX_CONNECT_DATA *data;
	DWORD len = 0;
	WSAEVENT event = WSA_INVALID_EVENT;
	
	r = connect(s, name, namelen);
	if(r == SOCKET_ERROR) {
		if(WSAGetLastError() != WSAEWOULDBLOCK) return FALSE;
		//It's going to take us a bit to connect
		
		event = WSACreateEvent();
		if(event == WSA_INVALID_EVENT) {
			if(debugLevel)
				DbgPrintf(DBG_WARN, S_YELLOW "ws2_32: Could not create an event for ConnectEx 0x%08X\n", WSAGetLastError());
			return FALSE;
		}
		
		data = CreateConnectData(s, lpSendBuffer, dwSendDataLength, lpOverlapped, event);
		if(!RegisterWaitForSingleObject(&data->WaitObject, event, ConnectEx_CONNECT, data, INFINITE, WT_EXECUTEINIOTHREAD|WT_EXECUTEONLYONCE)) {
			if(debugLevel)
				DbgPrintf(DBG_WARN, S_YELLOW "ws2_32: Could not register event for ConnectEx 0x%08X\n", GetLastError());
			WSACloseEvent(event);
			FreeConnectData(data);
			return FALSE;
		}
		
		r = WSAEventSelect(s, event, FD_CONNECT);
		if(r == SOCKET_ERROR) {
			if(debugLevel)
				DbgPrintf(DBG_WARN, S_YELLOW "ws2_32: Could not connect event to FD_CONNECT 0x%08X\n", WSAGetLastError());
			WSACloseEvent(event);
			FreeConnectData(data);
			return FALSE;
		}
		
		WSASetLastError(ERROR_IO_PENDING);
		return FALSE;
	}
	
	data = CreateConnectData(s, lpSendBuffer, dwSendDataLength, lpOverlapped, WSA_INVALID_EVENT);
	ret = ConnectEx_CONNECT(data, FALSE);
	if(lpdwBytesSent) *lpdwBytesSent = dwSendDataLength;
	return ret;
}

/*http://www.microsoft.com/mspress/books/sampchap/5726.aspx
  However, for Windows 2000 or Windows NT 4.0 it is possible to call
  TransmitFile with a null filehandle and buffers but specify the disconnect 
  and re-use flags, which will achieve the same results.*/
BOOL PASCAL XP_DisconnectEx(SOCKET s, LPOVERLAPPED lpOverlapped, DWORD dwFlags, DWORD dwReserved) {
	LPFN_TRANSMITFILE _TransmitFile;
	int r;
	DWORD bytes, flags;
	
	r = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &TransmitFileGUID, sizeof(GUID),
			&_TransmitFile, sizeof(LPFN_TRANSMITFILE), &bytes, NULL, NULL);
	
	if(r == SOCKET_ERROR) return FALSE;
	
	flags = TF_DISCONNECT;
	if(dwFlags & TF_REUSE_SOCKET) flags |= TF_REUSE_SOCKET;
	return _TransmitFile(s, NULL, 0, 0, lpOverlapped, NULL, flags);
}

int WSAAPI XP_WSAIoctl(SOCKET s, DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
  LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPWSAOVERLAPPED lpOverlapped,
  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) {
	int r;
	
	r = WSAIoctl(s, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer,
			lpcbBytesReturned, lpOverlapped, lpCompletionRoutine);

	if(dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER && 
	   lpvInBuffer &&
	   r == SOCKET_ERROR) {
		if(debugLevel) DbgPrintf(DBG_INFO, 
				"WSAIoctl SIO_GET_EXTENSION_FUNCTION_POINTER GUID=0x%08X\n",
				*(DWORD *)lpvInBuffer);
		if(memcmp(lpvInBuffer, &ConnectExGUID, sizeof(GUID)) == 0) {
			SetLastError(ERROR_SUCCESS);
			if(cbOutBuffer >= 4 && lpvOutBuffer)
				*(LPFN_CONNECTEX *)lpvOutBuffer = XP_ConnectEx;
			if(lpcbBytesReturned) *lpcbBytesReturned = 4;
			r = 0;
		} else if(memcmp(lpvInBuffer, &DisconnectExGUID, sizeof(GUID)) == 0) {
			SetLastError(ERROR_SUCCESS);
			if(cbOutBuffer >= 4 && lpvOutBuffer)
				*(LPFN_DISCONNECTEX *)lpvOutBuffer = XP_DisconnectEx;
			if(lpcbBytesReturned) *lpcbBytesReturned = 4;
			r = 0;
		} else if(debugLevel) {
			DbgPrintf(DBG_ERROR, 
				S_RED "WSAIoctl SIO_GET_EXTENSION_FUNCTION_POINTER GUID=0x%08X failed, WSALastError=0x%08X\n",
				*(DWORD *)lpvInBuffer, WSAGetLastError());
		}
	}
	
	return r;
}

//Cheers to Microsoft for doing the hard work!!!!

int WINAPI XP_getaddrinfo(const char* nodename, const char* servname, const struct addrinfo* hints, struct addrinfo** res) {
	return WspiapiLegacyGetAddrInfo(nodename, servname, hints, res);
}

void WINAPI XP_freeaddrinfo(struct addrinfo* ai) {
	WspiapiLegacyFreeAddrInfo(ai);
}

int WINAPI XP_getnameinfo(const struct sockaddr FAR* sa, socklen_t salen, char FAR* host,
                       DWORD hostlen, char FAR* serv, DWORD servlen, int flags) {
	return WspiapiLegacyGetNameInfo(sa, salen, host, hostlen, serv, servlen, flags);		   
}

void WINAPI XP_FreeAddrInfoW(PADDRINFOW pAddrInfo) {
	//well you can't get anything yet
}

BOOL WINAPI DllMain(
  HINSTANCE hinstDLL,
  DWORD fdwReason,
  LPVOID lpvReserved) {
	DebugLevel_t DebugLevel;
	
  	switch(fdwReason) {
		case DLL_PROCESS_ATTACH:
			if(!hHeap) hHeap = GetProcessHeap();
			
			//Init debug data
			DbgPrintf = GetDbgPrintf();
			DebugLevel = GetDebugLevel();
			
			if(DebugLevel) debugLevel = DebugLevel();
			else           debugLevel = 0;
			
			if(DbgPrintf) DbgPrintf(DBG_ALWAYS, "ws2_32: WS2_32.DLL Wrapper Init\n");
			break;
	}
	
	return TRUE;
}
_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to