1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
5 # HANDLE and SOCKET are pointer-sized (they are 64 bit wide in 64-bit builds)
8 ctypedef unsigned long DWORD
9 # it's really a pointer, but we use it as an integer
10 ctypedef size_t ULONG_PTR
13 cdef extern from 'io.h':
14 long _get_osfhandle(int filehandle)
16 cdef extern from 'errno.h':
21 cdef extern from 'winsock2.h':
24 cdef extern from 'ws2tcpip.h':
27 cdef extern from 'windows.h':
28 ctypedef struct OVERLAPPED:
30 HANDLE CreateIoCompletionPort(HANDLE fileHandle, HANDLE existing, ULONG_PTR key, DWORD numThreads)
31 BOOL GetQueuedCompletionStatus(HANDLE port, DWORD *bytes, ULONG_PTR *key, OVERLAPPED **ov, DWORD timeout)
32 BOOL PostQueuedCompletionStatus(HANDLE port, DWORD bytes, ULONG_PTR key, OVERLAPPED *ov)
34 BOOL CloseHandle(HANDLE h)
39 cdef extern from 'python.h':
42 void *PyMem_Malloc(size_t n) except NULL
43 void PyMem_Free(void *p)
46 PyThreadState *PyEval_SaveThread()
47 void PyEval_RestoreThread(PyThreadState *tstate)
48 void Py_INCREF(object o)
49 void Py_XINCREF(object o)
50 void Py_DECREF(object o)
51 void Py_XDECREF(object o)
52 int PyObject_AsWriteBuffer(object obj, void **buffer, Py_ssize_t *buffer_len) except -1
53 int PyObject_AsReadBuffer(object obj, void **buffer, Py_ssize_t *buffer_len) except -1
54 object PyString_FromString(char *v)
55 object PyString_FromStringAndSize(char *v, Py_ssize_t len)
56 object PyBuffer_New(Py_ssize_t size)
57 char *PyString_AsString(object obj) except NULL
58 object PySequence_Fast(object o, char *m)
59 # object PySequence_Fast_GET_ITEM(object o, Py_ssize_t i)
60 PyObject** PySequence_Fast_ITEMS(object o)
61 PyObject* PySequence_ITEM(PyObject *o, Py_ssize_t i)
62 Py_ssize_t PySequence_Fast_GET_SIZE(object o)
66 unsigned short int sa_family
77 unsigned short int sin6_port
78 unsigned long int sin6_flowinfo
80 unsigned long int sin6_scope_id
81 int getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen)
90 ctypedef struct WSAPROTOCOL_INFO:
94 char *inet_ntoa(in_addr ina)
95 unsigned long inet_addr(char *cp)
96 unsigned short ntohs(unsigned short netshort)
97 unsigned short htons(unsigned short hostshort)
98 ctypedef struct WSABUF:
101 # cdef struct TRANSMIT_FILE_BUFFERS:
103 int WSARecv(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD *flags, OVERLAPPED *ov, void *crud)
104 int WSARecvFrom(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD *flags, sockaddr *fromaddr, int *fromlen, OVERLAPPED *ov, void *crud)
105 int WSASend(SOCKET s, WSABUF *buffs, DWORD buffcount, DWORD *bytes, DWORD flags, OVERLAPPED *ov, void *crud)
106 int WSAAddressToStringA(sockaddr *lpsaAddress, DWORD dwAddressLength,
107 WSAPROTOCOL_INFO *lpProtocolInfo,
108 char *lpszAddressString,
109 DWORD *lpdwAddressStringLength)
110 int WSAStringToAddressA(char *AddressString, int AddressFamily,
111 WSAPROTOCOL_INFO *lpProtocolInfo,
112 sockaddr *lpAddress, int *lpAddressLength)
114 cdef extern from 'string.h':
115 void *memset(void *s, int c, size_t n)
117 cdef extern from 'winsock_pointers.h':
118 int initWinsockPointers()
119 BOOL (*lpAcceptEx)(SOCKET listening, SOCKET accepting, void *buffer, DWORD recvlen, DWORD locallen, DWORD remotelen, DWORD *bytes, OVERLAPPED *ov)
120 void (*lpGetAcceptExSockaddrs)(void *buffer, DWORD recvlen, DWORD locallen, DWORD remotelen, sockaddr **localaddr, int *locallen, sockaddr **remoteaddr, int *remotelen)
121 BOOL (*lpConnectEx)(SOCKET s, sockaddr *name, int namelen, void *buff, DWORD sendlen, DWORD *sentlen, OVERLAPPED *ov)
122 # BOOL (*lpTransmitFile)(SOCKET s, HANDLE hFile, DWORD size, DWORD buffer_size, OVERLAPPED *ov, TRANSMIT_FILE_BUFFERS *buff, DWORD flags)
124 cdef struct myOVERLAPPED:
128 cdef myOVERLAPPED *makeOV() except NULL:
129 cdef myOVERLAPPED *res
130 res = <myOVERLAPPED *>PyMem_Malloc(sizeof(myOVERLAPPED))
133 memset(res, 0, sizeof(myOVERLAPPED))
136 cdef void raise_error(int err, object message) except *:
139 raise WindowsError(message, err)
142 def __init__(self, callback, owner, **kw):
143 self.callback = callback
145 for k, v in kw.items():
148 cdef class CompletionPort:
152 res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0)
154 raise_error(0, 'CreateIoCompletionPort')
157 def addHandle(self, HANDLE handle, size_t key=0):
159 res = CreateIoCompletionPort(handle, self.port, key, 0)
161 raise_error(0, 'CreateIoCompletionPort')
163 def getEvent(self, long timeout):
164 cdef PyThreadState *_save
165 cdef unsigned long bytes, rc
167 cdef myOVERLAPPED *ov
169 _save = PyEval_SaveThread()
170 rc = GetQueuedCompletionStatus(self.port, &bytes, &key, <OVERLAPPED **>&ov, timeout)
171 PyEval_RestoreThread(_save)
182 Py_DECREF(obj) # we are stealing a reference here
185 return (rc, bytes, key, obj)
187 def postEvent(self, unsigned long bytes, size_t key, obj):
188 cdef myOVERLAPPED *ov
189 cdef unsigned long rc
193 Py_INCREF(obj) # give ov its own reference to obj
194 ov.obj = <PyObject *>obj
198 rc = PostQueuedCompletionStatus(self.port, bytes, key, <OVERLAPPED *>ov)
203 raise_error(0, 'PostQueuedCompletionStatus')
206 CloseHandle(self.port)
208 def makesockaddr(object buff):
209 cdef void *mem_buffer
212 PyObject_AsReadBuffer(buff, &mem_buffer, &size)
213 # XXX: this should really return the address family as well
214 return _makesockaddr(<sockaddr *>mem_buffer, size)
216 cdef object _makesockaddr(sockaddr *addr, Py_ssize_t len):
217 cdef sockaddr_in *sin
218 cdef sockaddr_in6 *sin6
221 cdef DWORD buff_size = sizeof(buff)
224 if addr.sa_family == AF_INET:
225 sin = <sockaddr_in *>addr
226 return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port)
227 elif addr.sa_family == AF_INET6:
228 sin6 = <sockaddr_in6 *>addr
229 rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size)
230 if rc == SOCKET_ERROR:
231 raise_error(0, 'WSAAddressToString')
232 host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port)
233 host, port = host.rsplit(':', 1)
235 assert host[0] == '['
236 assert host[-1] == ']'
237 assert port == sa_port
238 return host[1:-1], port
240 return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data))
243 cdef object fillinetaddr(sockaddr_in *dest, object addr):
244 cdef unsigned short port
245 cdef unsigned long res
249 hoststr = PyString_AsString(host)
250 res = inet_addr(hoststr)
251 if res == INADDR_ANY:
252 raise ValueError, 'invalid IP address'
253 dest.sin_addr.s_addr = res
255 dest.sin_port = htons(port)
258 cdef object fillinet6addr(sockaddr_in6 *dest, object addr):
259 cdef unsigned short port
260 cdef unsigned long res
262 cdef int addrlen = sizeof(sockaddr_in6)
263 host, port, flow, scope = addr
264 host = host.split("%")[0] # remove scope ID, if any
266 hoststr = PyString_AsString(host)
267 cdef int parseresult = WSAStringToAddressA(hoststr, AF_INET6, NULL,
268 <sockaddr *>dest, &addrlen)
269 if parseresult == SOCKET_ERROR:
270 raise ValueError, 'invalid IPv6 address %r' % (host,)
272 raise RuntimeError, 'undefined error occurred during address parsing'
273 # sin6_host field was handled by WSAStringToAddress
274 dest.sin6_port = htons(port)
275 dest.sin6_flowinfo = flow
276 dest.sin6_scope_id = scope
279 def AllocateReadBuffer(int size):
280 return PyBuffer_New(size)
282 def maxAddrLen(long s):
283 cdef WSAPROTOCOL_INFO wsa_pi
286 size = sizeof(wsa_pi)
287 rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, <char *>&wsa_pi, &size)
288 if rc == SOCKET_ERROR:
289 raise_error(WSAGetLastError(), 'getsockopt')
290 return wsa_pi.iMaxSockAddr
292 cdef int getAddrFamily(SOCKET s) except *:
293 cdef WSAPROTOCOL_INFO wsa_pi
296 size = sizeof(wsa_pi)
297 rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, <char *>&wsa_pi, &size)
298 if rc == SOCKET_ERROR:
299 raise_error(WSAGetLastError(), 'getsockopt')
300 return wsa_pi.iAddressFamily
302 import socket # for WSAStartup
303 if not initWinsockPointers():
304 raise ValueError, 'Failed to initialize Winsock function vectors'
306 have_connectex = (lpConnectEx != NULL)
308 include 'acceptex.pxi'
309 include 'connectex.pxi'
310 include 'wsarecv.pxi'
311 include 'wsasend.pxi'