Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / internet / iocpreactor / iocpsupport / iocpsupport.pyx
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4
5 # HANDLE and SOCKET are pointer-sized (they are 64 bit wide in 64-bit builds)
6 ctypedef size_t HANDLE
7 ctypedef size_t SOCKET
8 ctypedef unsigned long DWORD
9 # it's really a pointer, but we use it as an integer
10 ctypedef size_t ULONG_PTR
11 ctypedef int BOOL
12
13 cdef extern from 'io.h':
14     long _get_osfhandle(int filehandle)
15
16 cdef extern from 'errno.h':
17     int errno
18     enum:
19         EBADF
20
21 cdef extern from 'winsock2.h':
22     pass
23
24 cdef extern from 'ws2tcpip.h':
25     pass
26
27 cdef extern from 'windows.h':
28     ctypedef struct OVERLAPPED:
29         pass
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)
33     DWORD GetLastError()
34     BOOL CloseHandle(HANDLE h)
35     enum:
36         INVALID_HANDLE_VALUE
37     void DebugBreak()
38
39 cdef extern from 'python.h':
40     struct PyObject:
41         pass
42     void *PyMem_Malloc(size_t n) except NULL
43     void PyMem_Free(void *p)
44     struct PyThreadState:
45         pass
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)
63
64 cdef extern from '':
65     struct sockaddr:
66         unsigned short int sa_family
67         char sa_data[0]
68     cdef struct in_addr:
69         unsigned long s_addr
70     struct sockaddr_in:
71         int sin_port
72         in_addr sin_addr
73     cdef struct in6_addr:
74         char s6_addr[16]
75     struct sockaddr_in6:
76         short int sin6_family
77         unsigned short int sin6_port
78         unsigned long int sin6_flowinfo
79         in6_addr sin6_addr
80         unsigned long int sin6_scope_id
81     int getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen)
82     enum:
83         SOL_SOCKET
84         SO_PROTOCOL_INFO
85         SOCKET_ERROR
86         ERROR_IO_PENDING
87         AF_INET
88         AF_INET6
89         INADDR_ANY
90     ctypedef struct WSAPROTOCOL_INFO:
91         int iMaxSockAddr
92         int iAddressFamily
93     int WSAGetLastError()
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:
99         long len
100         char *buf
101 #    cdef struct TRANSMIT_FILE_BUFFERS:
102 #        pass
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)
113
114 cdef extern from 'string.h':
115     void *memset(void *s, int c, size_t n)
116
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)
123
124 cdef struct myOVERLAPPED:
125     OVERLAPPED ov
126     PyObject *obj
127
128 cdef myOVERLAPPED *makeOV() except NULL:
129     cdef myOVERLAPPED *res
130     res = <myOVERLAPPED *>PyMem_Malloc(sizeof(myOVERLAPPED))
131     if not res:
132         raise MemoryError
133     memset(res, 0, sizeof(myOVERLAPPED))
134     return res
135
136 cdef void raise_error(int err, object message) except *:
137     if not err:
138         err = GetLastError()
139     raise WindowsError(message, err)
140
141 class Event:
142     def __init__(self, callback, owner, **kw):
143         self.callback = callback
144         self.owner = owner
145         for k, v in kw.items():
146             setattr(self, k, v)
147
148 cdef class CompletionPort:
149     cdef HANDLE port
150     def __init__(self):
151         cdef HANDLE res
152         res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0)
153         if not res:
154             raise_error(0, 'CreateIoCompletionPort')
155         self.port = res
156
157     def addHandle(self, HANDLE handle, size_t key=0):
158         cdef HANDLE res
159         res = CreateIoCompletionPort(handle, self.port, key, 0)
160         if not res:
161             raise_error(0, 'CreateIoCompletionPort')
162
163     def getEvent(self, long timeout):
164         cdef PyThreadState *_save
165         cdef unsigned long bytes, rc
166         cdef size_t key
167         cdef myOVERLAPPED *ov
168
169         _save = PyEval_SaveThread()
170         rc = GetQueuedCompletionStatus(self.port, &bytes, &key, <OVERLAPPED **>&ov, timeout)
171         PyEval_RestoreThread(_save)
172
173         if not rc:
174             rc = GetLastError()
175         else:
176             rc = 0
177
178         obj = None
179         if ov:
180             if ov.obj:
181                 obj = <object>ov.obj
182                 Py_DECREF(obj) # we are stealing a reference here
183             PyMem_Free(ov)
184
185         return (rc, bytes, key, obj)
186
187     def postEvent(self, unsigned long bytes, size_t key, obj):
188         cdef myOVERLAPPED *ov
189         cdef unsigned long rc
190
191         if obj is not None:
192             ov = makeOV()
193             Py_INCREF(obj) # give ov its own reference to obj
194             ov.obj = <PyObject *>obj
195         else:
196             ov = NULL
197
198         rc = PostQueuedCompletionStatus(self.port, bytes, key, <OVERLAPPED *>ov)
199         if not rc:
200             if ov:
201                 Py_DECREF(obj)
202                 PyMem_Free(ov)
203             raise_error(0, 'PostQueuedCompletionStatus')
204
205     def __del__(self):
206         CloseHandle(self.port)
207
208 def makesockaddr(object buff):
209     cdef void *mem_buffer
210     cdef Py_ssize_t size
211
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)
215
216 cdef object _makesockaddr(sockaddr *addr, Py_ssize_t len):
217     cdef sockaddr_in *sin
218     cdef sockaddr_in6 *sin6
219     cdef char buff[256]
220     cdef int rc
221     cdef DWORD buff_size = sizeof(buff)
222     if not len:
223         return None
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)
234         port = int(port)
235         assert host[0] == '['
236         assert host[-1] == ']'
237         assert port == sa_port
238         return host[1:-1], port
239     else:
240         return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data))
241
242
243 cdef object fillinetaddr(sockaddr_in *dest, object addr):
244     cdef unsigned short port
245     cdef unsigned long res
246     cdef char *hoststr
247     host, port = addr
248
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
254
255     dest.sin_port = htons(port)
256
257
258 cdef object fillinet6addr(sockaddr_in6 *dest, object addr):
259     cdef unsigned short port
260     cdef unsigned long res
261     cdef char *hoststr
262     cdef int addrlen = sizeof(sockaddr_in6)
263     host, port, flow, scope = addr
264     host = host.split("%")[0] # remove scope ID, if any
265
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,)
271     if parseresult != 0:
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
277
278
279 def AllocateReadBuffer(int size):
280     return PyBuffer_New(size)
281
282 def maxAddrLen(long s):
283     cdef WSAPROTOCOL_INFO wsa_pi
284     cdef int size, rc
285
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
291
292 cdef int getAddrFamily(SOCKET s) except *:
293     cdef WSAPROTOCOL_INFO wsa_pi
294     cdef int size, rc
295
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
301
302 import socket # for WSAStartup
303 if not initWinsockPointers():
304     raise ValueError, 'Failed to initialize Winsock function vectors'
305
306 have_connectex = (lpConnectEx != NULL)
307
308 include 'acceptex.pxi'
309 include 'connectex.pxi'
310 include 'wsarecv.pxi'
311 include 'wsasend.pxi'
312