From ed6cf489f88f768b062f6bff7794d3ea78b43724 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 1 May 2016 22:37:01 -0400 Subject: [PATCH 01/48] at least it compiles now... --- pywincffi/core/cdefs/headers/functions.h | 1 + pywincffi/core/cdefs/sources/main.c | 1 + pywincffi/core/dist.py | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 70069fe..44ea23c 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -46,3 +46,4 @@ BOOL ResetEvent(HANDLE); // Communications BOOL ClearCommError(HANDLE, LPDWORD, LPCOMSTAT); +int WSAEventSelect(int, HANDLE, long); diff --git a/pywincffi/core/cdefs/sources/main.c b/pywincffi/core/cdefs/sources/main.c index 1981324..75dee99 100644 --- a/pywincffi/core/cdefs/sources/main.c +++ b/pywincffi/core/cdefs/sources/main.c @@ -1,4 +1,5 @@ #include +#include #include // Extra constants which are not defined in all versions of Windows or diff --git a/pywincffi/core/dist.py b/pywincffi/core/dist.py index 7e46d9c..05c2677 100644 --- a/pywincffi/core/dist.py +++ b/pywincffi/core/dist.py @@ -57,7 +57,7 @@ SOURCE_FILES = ( resource_filename( "pywincffi", join("core", "cdefs", "sources", "main.c")), ) -LIBRARIES = ("kernel32", "user32") +LIBRARIES = ("kernel32", "user32", "Ws2_32") class Module(object): # pylint: disable=too-few-public-methods From 314e9ee1f8527749a36455aff10cc9acc733401c Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Wed, 4 May 2016 23:55:34 -0400 Subject: [PATCH 02/48] adding constants --- pywincffi/core/cdefs/headers/constants.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pywincffi/core/cdefs/headers/constants.h b/pywincffi/core/cdefs/headers/constants.h index 11ddbbc..5ff3fee 100644 --- a/pywincffi/core/cdefs/headers/constants.h +++ b/pywincffi/core/cdefs/headers/constants.h @@ -217,6 +217,19 @@ #define QS_SENDMESSAGE ... #define QS_TIMER ... +// WSAEventSelect +#define SOCKET_ERROR ... +#define FD_READ ... +#define FD_WRITE ... +#define FD_OOB ... +#define FD_ACCEPT ... +#define FD_CONNECT ... +#define FD_CLOSE ... +#define FD_QOS ... +#define FD_GROUP_QOS ... +#define FD_ROUTING_INTERFACE_CHANGE ... +#define FD_ADDRESS_LIST_CHANGE ... + // For the moment, we can't define this here. When cffi // parses the header this returns -1 and cffi seems to // only handle positive integers right now. From 8b9c2a0332778c028cd53f37c74954b42c8a8674 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Thu, 5 May 2016 00:12:19 -0400 Subject: [PATCH 03/48] adding socket errors --- pywincffi/core/cdefs/headers/constants.h | 98 ++++++++++++++++++++++++ pywincffi/core/cdefs/headers/functions.h | 1 + pywincffi/core/cdefs/sources/main.c | 1 + 3 files changed, 100 insertions(+) diff --git a/pywincffi/core/cdefs/headers/constants.h b/pywincffi/core/cdefs/headers/constants.h index 5ff3fee..839871f 100644 --- a/pywincffi/core/cdefs/headers/constants.h +++ b/pywincffi/core/cdefs/headers/constants.h @@ -230,6 +230,104 @@ #define FD_ROUTING_INTERFACE_CHANGE ... #define FD_ADDRESS_LIST_CHANGE ... +// Windows socket error codes +// https://msdn.microsoft.com/en-us/library/ms740668 +#define WSA_INVALID_HANDLE ... +#define WSA_NOT_ENOUGH_MEMORY ... +#define WSA_INVALID_PARAMETER ... +#define WSA_OPERATION_ABORTED ... +#define WSA_IO_INCOMPLETE ... +#define WSA_IO_PENDING ... +#define WSAEINTR ... +#define WSAEBADF ... +#define WSAEACCES ... +#define WSAEFAULT ... +#define WSAEINVAL ... +#define WSAEMFILE ... +#define WSAEWOULDBLOCK ... +#define WSAEINPROGRESS ... +#define WSAEALREADY ... +#define WSAENOTSOCK ... +#define WSAEDESTADDRREQ ... +#define WSAEMSGSIZE ... +#define WSAEPROTOTYPE ... +#define WSAENOPROTOOPT ... +#define WSAEPROTONOSUPPORT ... +#define WSAESOCKTNOSUPPORT ... +#define WSAEOPNOTSUPP ... +#define WSAEPFNOSUPPORT ... +#define WSAEAFNOSUPPORT ... +#define WSAEADDRINUSE ... +#define WSAEADDRNOTAVAIL ... +#define WSAENETDOWN ... +#define WSAENETUNREACH ... +#define WSAENETRESET ... +#define WSAECONNABORTED ... +#define WSAECONNRESET ... +#define WSAENOBUFS ... +#define WSAEISCONN ... +#define WSAENOTCONN ... +#define WSAESHUTDOWN ... +#define WSAETOOMANYREFS ... +#define WSAETIMEDOUT ... +#define WSAECONNREFUSED ... +#define WSAELOOP ... +#define WSAENAMETOOLONG ... +#define WSAEHOSTDOWN ... +#define WSAEHOSTUNREACH ... +#define WSAENOTEMPTY ... +#define WSAEPROCLIM ... +#define WSAEUSERS ... +#define WSAEDQUOT ... +#define WSAESTALE ... +#define WSAEREMOTE ... +#define WSASYSNOTREADY ... +#define WSAVERNOTSUPPORTED ... +#define WSANOTINITIALISED ... +#define WSAEDISCON ... +#define WSAENOMORE ... +#define WSAECANCELLED ... +#define WSAEINVALIDPROCTABLE ... +#define WSAEINVALIDPROVIDER ... +#define WSAEPROVIDERFAILEDINIT ... +#define WSASYSCALLFAILURE ... +#define WSASERVICE_NOT_FOUND ... +#define WSATYPE_NOT_FOUND ... +#define WSA_E_NO_MORE ... +#define WSA_E_CANCELLED ... +#define WSAEREFUSED ... +#define WSAHOST_NOT_FOUND ... +#define WSATRY_AGAIN ... +#define WSANO_RECOVERY ... +#define WSANO_DATA ... +#define WSA_QOS_RECEIVERS ... +#define WSA_QOS_SENDERS ... +#define WSA_QOS_NO_SENDERS ... +#define WSA_QOS_NO_RECEIVERS ... +#define WSA_QOS_REQUEST_CONFIRMED ... +#define WSA_QOS_ADMISSION_FAILURE ... +#define WSA_QOS_POLICY_FAILURE ... +#define WSA_QOS_BAD_STYLE ... +#define WSA_QOS_BAD_OBJECT ... +#define WSA_QOS_TRAFFIC_CTRL_ERROR ... +#define WSA_QOS_GENERIC_ERROR ... +#define WSA_QOS_ESERVICETYPE ... +#define WSA_QOS_EFLOWSPEC ... +#define WSA_QOS_EPROVSPECBUF ... +#define WSA_QOS_EFILTERSTYLE ... +#define WSA_QOS_EFILTERTYPE ... +#define WSA_QOS_EFILTERCOUNT ... +#define WSA_QOS_EOBJLENGTH ... +#define WSA_QOS_EFLOWCOUNT ... +#define WSA_QOS_EUNKOWNPSOBJ ... +#define WSA_QOS_EPOLICYOBJ ... +#define WSA_QOS_EFLOWDESC ... +#define WSA_QOS_EPSFLOWSPEC ... +#define WSA_QOS_EPSFILTERSPEC ... +#define WSA_QOS_ESDMODEOBJ ... +#define WSA_QOS_ESHAPERATEOBJ ... +#define WSA_QOS_RESERVED_PETYPE ... + // For the moment, we can't define this here. When cffi // parses the header this returns -1 and cffi seems to // only handle positive integers right now. diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 44ea23c..0651566 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -47,3 +47,4 @@ BOOL ResetEvent(HANDLE); // Communications BOOL ClearCommError(HANDLE, LPDWORD, LPCOMSTAT); int WSAEventSelect(int, HANDLE, long); +int WSAGetLastError(void); diff --git a/pywincffi/core/cdefs/sources/main.c b/pywincffi/core/cdefs/sources/main.c index 75dee99..3e4afc0 100644 --- a/pywincffi/core/cdefs/sources/main.c +++ b/pywincffi/core/cdefs/sources/main.c @@ -1,5 +1,6 @@ #include #include +#include #include // Extra constants which are not defined in all versions of Windows or From 65d3a0ef55fbd25a884f50a24c9fc26aa8ae9073 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Thu, 5 May 2016 00:13:13 -0400 Subject: [PATCH 04/48] initial commit of WSAEventSelect() --- pywincffi/ws3_32/__init__.py | 9 ++++++ pywincffi/ws3_32/events.py | 53 +++++++++++++++++++++++++++++++++++ tests/test_ws2_32/__init__.py | 0 3 files changed, 62 insertions(+) create mode 100644 pywincffi/ws3_32/__init__.py create mode 100644 pywincffi/ws3_32/events.py create mode 100644 tests/test_ws2_32/__init__.py diff --git a/pywincffi/ws3_32/__init__.py b/pywincffi/ws3_32/__init__.py new file mode 100644 index 0000000..8776455 --- /dev/null +++ b/pywincffi/ws3_32/__init__.py @@ -0,0 +1,9 @@ +""" +Ws2_32 Sub-Package +================== + +Provides functions, constants and utilities that wrap functions provided by +``ws3_32.dll``. +""" + +from pywincffi.ws3_32.events import WSAEventSelect diff --git a/pywincffi/ws3_32/events.py b/pywincffi/ws3_32/events.py new file mode 100644 index 0000000..167f662 --- /dev/null +++ b/pywincffi/ws3_32/events.py @@ -0,0 +1,53 @@ +""" +Events +------ + +A module containing Windows functions for working with events. +""" + +from six import integer_types + +from pywincffi.core import dist +from pywincffi.core.checks import Enums, input_check, error_check +from pywincffi.exceptions import WindowsAPIError + + +def WSAEventSelect(sock, hEventObject, lNetworkEvents): + """ + Specifies an event object to be associated with the specified set of + FD_XXX network events. + + .. seealso:: + + https://msdn.microsoft.com/en-us/library/ms741576 + + :param int sock: + A descriptor identify the socket. + + :param handle hEventObject: + A handle which identifies the event object to be associated + with the network events. + + :param int lNetworkEvents: + A bitmask which specifies the combination of ``FD_XXX`` network + events which the application has interest in. + """ + input_check("sock", sock, integer_types) + input_check("hEventObject", hEventObject, Enums.HANDLE) + input_check("lNetworkEvents", lNetworkEvents, integer_types) + + ffi, library = dist.load() + + # TODO: `sock` needs conversion + code = library.WSAEventSelect( + sock, + ffi.cast("WSAEVENT", hEventObject), + ffi.cast("long", lNetworkEvents) + ) + + if code == library.SOCKET_ERROR: + errno = library.WSAGetLastError() + raise WindowsAPIError( + "WSAEventSelect", "Socket error %d" % errno, errno) + + error_check("WSAEventSelect", code, expected=0) diff --git a/tests/test_ws2_32/__init__.py b/tests/test_ws2_32/__init__.py new file mode 100644 index 0000000..e69de29 From 8e9b6d9ad6f726ef50e661673c46b6edb35c030c Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 5 Jun 2016 22:51:31 -0400 Subject: [PATCH 05/48] adding WSA_INVALID_EVENT --- pywincffi/core/cdefs/headers/constants.h | 1 + 1 file changed, 1 insertion(+) diff --git a/pywincffi/core/cdefs/headers/constants.h b/pywincffi/core/cdefs/headers/constants.h index 839871f..a6f4ec0 100644 --- a/pywincffi/core/cdefs/headers/constants.h +++ b/pywincffi/core/cdefs/headers/constants.h @@ -327,6 +327,7 @@ #define WSA_QOS_ESDMODEOBJ ... #define WSA_QOS_ESHAPERATEOBJ ... #define WSA_QOS_RESERVED_PETYPE ... +#define WSA_INVALID_EVENT ... // For the moment, we can't define this here. When cffi // parses the header this returns -1 and cffi seems to From 6dee8cb444900fff3c5c7f28b02bc1c7cb2d2334 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 5 Jun 2016 22:51:52 -0400 Subject: [PATCH 06/48] adding WSACreateEvent (will mostly be used for testing) --- pywincffi/core/cdefs/headers/functions.h | 1 + 1 file changed, 1 insertion(+) diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 0651566..2dd0ebb 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -48,3 +48,4 @@ BOOL ResetEvent(HANDLE); BOOL ClearCommError(HANDLE, LPDWORD, LPCOMSTAT); int WSAEventSelect(int, HANDLE, long); int WSAGetLastError(void); +WSAEVENT WSACreateEvent(void); From 753a9f1c6cf220cf6fc66459575c107766c12504 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 5 Jun 2016 22:52:28 -0400 Subject: [PATCH 07/48] adding WSAGetLastError --- pywincffi/ws3_32/events.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pywincffi/ws3_32/events.py b/pywincffi/ws3_32/events.py index 167f662..7e152a4 100644 --- a/pywincffi/ws3_32/events.py +++ b/pywincffi/ws3_32/events.py @@ -46,8 +46,20 @@ def WSAEventSelect(sock, hEventObject, lNetworkEvents): ) if code == library.SOCKET_ERROR: - errno = library.WSAGetLastError() + errno = WSAGetLastError() raise WindowsAPIError( "WSAEventSelect", "Socket error %d" % errno, errno) error_check("WSAEventSelect", code, expected=0) + + +def WSAGetLastError(): + """ + Returns the last error status for a windows socket operation. + + .. seealso:: + + https://msdn.microsoft.com/en-us/library/ms741580 + """ + _, library = dist.load() + return library.WSAGetLastError() From daa6f23bd50a35a9b03c7305fd92d21d3dee85b3 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 5 Jun 2016 22:52:58 -0400 Subject: [PATCH 08/48] adding WSACreateEvent --- pywincffi/ws3_32/events.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pywincffi/ws3_32/events.py b/pywincffi/ws3_32/events.py index 7e152a4..29e3a91 100644 --- a/pywincffi/ws3_32/events.py +++ b/pywincffi/ws3_32/events.py @@ -53,6 +53,28 @@ def WSAEventSelect(sock, hEventObject, lNetworkEvents): error_check("WSAEventSelect", code, expected=0) +def WSACreateEvent(): + """ + Creates a new event object. + + .. seealso:: + + https://msdn.microsoft.com/en-us/library/ms741561 + + :returns: + Returns a handle to a new event object. + """ + _, library = dist.load() + result = library.WSACreateEvent() + + if result == library.WSA_INVALID_EVENT: + errno = WSAGetLastError() + raise WindowsAPIError( + "WSACreateEvent", "Socket error %d" % errno, errno) + + return result + + def WSAGetLastError(): """ Returns the last error status for a windows socket operation. From 2eb37e1ca72c29797f08596c2407ad3db483e940 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 5 Jun 2016 22:53:08 -0400 Subject: [PATCH 09/48] adding missing imports --- pywincffi/ws3_32/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pywincffi/ws3_32/__init__.py b/pywincffi/ws3_32/__init__.py index 8776455..7459fc4 100644 --- a/pywincffi/ws3_32/__init__.py +++ b/pywincffi/ws3_32/__init__.py @@ -6,4 +6,5 @@ ``ws3_32.dll``. """ -from pywincffi.ws3_32.events import WSAEventSelect +from pywincffi.ws3_32.events import ( + WSAEventSelect, WSACreateEvent, WSAGetLastError) From 7c1de264c963b16abc55376da17c38bd0ec01d19 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Thu, 9 Jun 2016 22:59:48 -0400 Subject: [PATCH 10/48] fixing build --- pywincffi/core/cdefs/headers/constants.h | 1 - pywincffi/core/cdefs/headers/functions.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pywincffi/core/cdefs/headers/constants.h b/pywincffi/core/cdefs/headers/constants.h index a6f4ec0..839871f 100644 --- a/pywincffi/core/cdefs/headers/constants.h +++ b/pywincffi/core/cdefs/headers/constants.h @@ -327,7 +327,6 @@ #define WSA_QOS_ESDMODEOBJ ... #define WSA_QOS_ESHAPERATEOBJ ... #define WSA_QOS_RESERVED_PETYPE ... -#define WSA_INVALID_EVENT ... // For the moment, we can't define this here. When cffi // parses the header this returns -1 and cffi seems to diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 2dd0ebb..a19c7c9 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -48,4 +48,4 @@ BOOL ResetEvent(HANDLE); BOOL ClearCommError(HANDLE, LPDWORD, LPCOMSTAT); int WSAEventSelect(int, HANDLE, long); int WSAGetLastError(void); -WSAEVENT WSACreateEvent(void); +HANDLE WSACreateEvent(void); From cfc66bbaa84adbf28e2f1f452fb62a545ef05f5f Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 12:58:11 -0400 Subject: [PATCH 11/48] adding typedefs for SOCKET, WSAEVENT --- pywincffi/core/cdefs/headers/typedefs.h | 13 +++++++++++++ pywincffi/core/dist.py | 2 ++ 2 files changed, 15 insertions(+) create mode 100644 pywincffi/core/cdefs/headers/typedefs.h diff --git a/pywincffi/core/cdefs/headers/typedefs.h b/pywincffi/core/cdefs/headers/typedefs.h new file mode 100644 index 0000000..85548fd --- /dev/null +++ b/pywincffi/core/cdefs/headers/typedefs.h @@ -0,0 +1,13 @@ +// +// This file contains type definitions that are required by other +// headers. In a normal C environment these would come directly +// from the system headers. With cffi however it has a set defined +// types: +// https://bitbucket.org/cffi/cffi/raw/default/c/commontypes.c +// +// Any additional types we need must be defined here. This file must +// loaded before any other headers are in dist.py. +// + +typedef int... SOCKET; +typedef HANDLE WSAEVENT; /* according to winsock2.h */ diff --git a/pywincffi/core/dist.py b/pywincffi/core/dist.py index c08e4b7..3138915 100644 --- a/pywincffi/core/dist.py +++ b/pywincffi/core/dist.py @@ -49,6 +49,8 @@ MODULE_NAME = "_pywincffi" HEADER_FILES = ( + resource_filename( + "pywincffi", join("core", "cdefs", "headers", "typedefs.h")), resource_filename( "pywincffi", join("core", "cdefs", "headers", "constants.h")), resource_filename( From 2e79ea314a57fb0127bf7491d09c7b1f0def5813 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 13:04:10 -0400 Subject: [PATCH 12/48] adding WSAEnumNetworkEvents() to headers --- pywincffi/core/cdefs/headers/constants.h | 1 + pywincffi/core/cdefs/headers/functions.h | 7 +++++++ pywincffi/core/cdefs/headers/structs.h | 6 ++++++ 3 files changed, 14 insertions(+) diff --git a/pywincffi/core/cdefs/headers/constants.h b/pywincffi/core/cdefs/headers/constants.h index e1ce9c9..b1b1ef1 100644 --- a/pywincffi/core/cdefs/headers/constants.h +++ b/pywincffi/core/cdefs/headers/constants.h @@ -229,6 +229,7 @@ #define FD_GROUP_QOS ... #define FD_ROUTING_INTERFACE_CHANGE ... #define FD_ADDRESS_LIST_CHANGE ... +#define FD_MAX_EVENTS ... // Windows socket error codes // https://msdn.microsoft.com/en-us/library/ms740668 diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 5401ce7..9ac1b70 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -237,3 +237,10 @@ int WSAGetLastError(void); // https://msdn.microsoft.com/en-us/ms741561 WSAEVENT WSACreateEvent(void); + +// https://msdn.microsoft.com/en-us/ms741572 +int WSAEnumNetworkEvents( + _In_ SOCKET s, + _In_ WSAEVENT hEventObject, + _Out_ LPWSANETWORKEVENTS lpNetworkEvents +); diff --git a/pywincffi/core/cdefs/headers/structs.h b/pywincffi/core/cdefs/headers/structs.h index 090a5ff..4dde384 100644 --- a/pywincffi/core/cdefs/headers/structs.h +++ b/pywincffi/core/cdefs/headers/structs.h @@ -67,3 +67,9 @@ typedef struct _COMSTAT { DWORD cbInQue; DWORD cbOutQue; } COMSTAT, *LPCOMSTAT; + +// https://msdn.microsoft.com/en-us/ms741653 +typedef struct _WSANETWORKEVENTS { + long lNetworkEvents; + int iErrorCode[...]; +} WSANETWORKEVENTS, *LPWSANETWORKEVENTS; From de4f69cafb5eaa459e0868884026f239e4415f7d Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 13:40:03 -0400 Subject: [PATCH 13/48] reworking setup of SetLastError/WSASetLastError a bit --- pywincffi/dev/testutil.py | 64 +++++++++++++++------------------------ 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/pywincffi/dev/testutil.py b/pywincffi/dev/testutil.py index 4d78eef..421aa4d 100644 --- a/pywincffi/dev/testutil.py +++ b/pywincffi/dev/testutil.py @@ -11,17 +11,17 @@ import sys from random import choice from string import ascii_lowercase, ascii_uppercase +from textwrap import dedent -from cffi import FFI, CDefError -from six import PY2, PY3 +from cffi import FFI, CDefError, FFIError try: # The setup.py file installs unittest2 for Python 2 # which backports newer test framework features. - from unittest2 import TestCase as _TestCase, skipUnless + from unittest2 import TestCase as _TestCase except ImportError: # pragma: no cover # pylint: disable=wrong-import-order - from unittest import TestCase as _TestCase, skipUnless + from unittest import TestCase as _TestCase from pywincffi.core.config import config from pywincffi.core.logger import get_logger @@ -34,22 +34,6 @@ except NameError: # pragma: no cover WindowsError = OSError # pylint: disable=redefined-builtin -# Load in our own kernel32 with the function(s) we need -# so we don't have to rely on pywincffi.core -libtest = None # pylint: disable=invalid-name -ffi = FFI() - -# pylint: disable=invalid-name -skip_unless_python2 = skipUnless(PY2, "Not Python 2") -skip_unless_python3 = skipUnless(PY3, "Not Python 3") - -try: - ffi.cdef("void SetLastError(DWORD);") - libtest = ffi.dlopen("kernel32") # pylint: disable=invalid-name -except (AttributeError, OSError, CDefError): # pragma: no cover - if os.name == "nt": - logger.warning("Failed to build SetLastError()") - class TestCase(_TestCase): """ @@ -58,6 +42,9 @@ class TestCase(_TestCase): """ REQUIRES_INTERNET = False _HAS_INTERNET = None + _ffi = None + _kernel32 = None + _ws2_32 = None def setUp(self): # pragma: no cover if self.REQUIRES_INTERNET and not self.internet_connected(): @@ -68,11 +55,27 @@ def setUp(self): # pragma: no cover self.skipTest("Internet unavailable") - if os.name == "nt": # pragma: no cover + # Build the small FFI module we need for use in the tests + if os.name == "nt": + if self._ffi is None: # pragma: no cover + self._ffi = FFI() + self._ffi.set_unicode(True) + self._ffi.cdef(dedent(""" + void SetLastError(DWORD); + void WSASetLastError(int); + """)) + + try: + self._kernel32 = self._ffi.dlopen("kernel32") + self._ws2_32 = self._ffi.dlopen("ws2_32") + except (AttributeError, OSError, CDefError, FFIError): + self.fail("Failed to build internal _ffi module") + # Always reset the last error to 0 between tests. This # ensures that any error we intentionally throw in one # test does not causes an error to be raised in another. - self.SetLastError(0) + self._kernel32.SetLastError(0) + self._ws2_32.WSASetLastError(0) config.load() @@ -109,23 +112,6 @@ def internet_connected(cls): socket.setdefaulttimeout(original_timeout) return TestCase._HAS_INTERNET - # pylint: disable=invalid-name - def SetLastError(self, value=0, lib=None): # pragma: no cover - """Calls the Windows API function SetLastError()""" - if os.name != "nt": - self.fail("Only an NT system should call this method") - - if lib is None: - lib = libtest - - if lib is None: - self.fail("`lib` was not defined") - - if not isinstance(value, int): - self.fail("Expected int for `value`") - - return lib.SetLastError(ffi.cast("DWORD", value)) - def _terminate_process(self, process): # pylint: disable=no-self-use """ Calls terminnate() on ``process`` and ignores any errors produced. From 79076e1c1e2dc473bf22b66578eba5e0864a93b9 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 13:40:55 -0400 Subject: [PATCH 14/48] adding WSASetLastError for testing --- pywincffi/core/cdefs/headers/functions.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 9ac1b70..fafa611 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -235,6 +235,11 @@ int WSAEventSelect( // https://msdn.microsoft.com/en-us/ms741580 int WSAGetLastError(void); +// https://msdn.microsoft.com/en-us/ms742209 +void WSASetLastError( + _In_ int iError +); + // https://msdn.microsoft.com/en-us/ms741561 WSAEVENT WSACreateEvent(void); From 06566560848d26c45ef71823f9076c34ffe59d7e Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 13:41:13 -0400 Subject: [PATCH 15/48] fixing module name --- pywincffi/{ws3_32 => ws2_32}/__init__.py | 2 +- pywincffi/{ws3_32 => ws2_32}/events.py | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename pywincffi/{ws3_32 => ws2_32}/__init__.py (83%) rename pywincffi/{ws3_32 => ws2_32}/events.py (100%) diff --git a/pywincffi/ws3_32/__init__.py b/pywincffi/ws2_32/__init__.py similarity index 83% rename from pywincffi/ws3_32/__init__.py rename to pywincffi/ws2_32/__init__.py index 7459fc4..18c94d0 100644 --- a/pywincffi/ws3_32/__init__.py +++ b/pywincffi/ws2_32/__init__.py @@ -6,5 +6,5 @@ ``ws3_32.dll``. """ -from pywincffi.ws3_32.events import ( +from pywincffi.ws2_32.events import ( WSAEventSelect, WSACreateEvent, WSAGetLastError) diff --git a/pywincffi/ws3_32/events.py b/pywincffi/ws2_32/events.py similarity index 100% rename from pywincffi/ws3_32/events.py rename to pywincffi/ws2_32/events.py From dada8d076a2af34efa1165a90ba2ea88d055b147 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 13:43:50 -0400 Subject: [PATCH 16/48] only tests need these functions --- pywincffi/core/cdefs/headers/functions.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index fafa611..8aa930b 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -1,12 +1,3 @@ -/////////////////////// -// Misc functions -/////////////////////// - -// https://msdn.microsoft.com/en-us/ms680627 -void WINAPI SetLastError( - _In_ DWORD dwErrCode -); - /////////////////////// // Processes /////////////////////// @@ -235,11 +226,6 @@ int WSAEventSelect( // https://msdn.microsoft.com/en-us/ms741580 int WSAGetLastError(void); -// https://msdn.microsoft.com/en-us/ms742209 -void WSASetLastError( - _In_ int iError -); - // https://msdn.microsoft.com/en-us/ms741561 WSAEVENT WSACreateEvent(void); From dd5bf61b796f53278e578fcecef0c44032fc7185 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 14:31:58 -0400 Subject: [PATCH 17/48] ignore duplicate-code --- pylintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pylintrc b/pylintrc index b2975d2..1b611c7 100644 --- a/pylintrc +++ b/pylintrc @@ -63,7 +63,8 @@ disable=W1609,W1628,W1606,I0020,E1608,W1636,W1608,W1618,W1616,W1620,W1607, W1611,W1633,I0021,W1629,W1635,W1626,W1615,W1638,W1640,W1613,W0704, W1622,W1610,W1627,W1602,W1630,E1602,W1619,W1632,E1606,W1605,W1624, W1625,W1614,W1634,E1601,W1604,W1603,W1637,W1621,W1623,W1617,W1601, - E1607,E1604,W1639,W1612,E1603,E1605,locally-disabled,too-many-ancestors,ungrouped-imports + E1607,E1604,W1639,W1612,E1603,E1605,locally-disabled,too-many-ancestors, + ungrouped-imports,duplicate-code [REPORTS] From 42a5d2a7e2116cfa25856b92c4ab5902daef8f0d Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 14:40:11 -0400 Subject: [PATCH 18/48] adding test for WSAGetlastError --- tests/test_ws2_32/test_events.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/test_ws2_32/test_events.py diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py new file mode 100644 index 0000000..7fc7f95 --- /dev/null +++ b/tests/test_ws2_32/test_events.py @@ -0,0 +1,11 @@ +from pywincffi.dev.testutil import TestCase +from pywincffi.ws2_32 import WSAGetLastError + + +class TestWSAGetLastError(TestCase): + """ + Tests for ``pywincffi.ws2_32.events.WSAGetLastError`` + """ + def test_get_last_error(self): + self._ws2_32.WSASetLastError(4242) + self.assertEqual(WSAGetLastError(), 4242) From 4f45ce5ad7e57035a7dcd2794df183a30d291a5e Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 14:40:31 -0400 Subject: [PATCH 19/48] setting up WSAEventSelect to use new types --- pywincffi/wintypes/__init__.py | 30 ++++++++++++++++++++++++++++++ pywincffi/ws2_32/events.py | 23 ++++++++++++++--------- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/pywincffi/wintypes/__init__.py b/pywincffi/wintypes/__init__.py index 98a5bb9..f85c7c2 100644 --- a/pywincffi/wintypes/__init__.py +++ b/pywincffi/wintypes/__init__.py @@ -72,6 +72,36 @@ def __eq__(self, other): return self._cdata[0] == other._cdata[0] +class SOCKET(typesbase.CFFICDataWrapper): + """ + Wraps the ``SOCKET`` C data type. + + .. seealso:: + + https://msdn.microsoft.com/en-us/library/ms740516 + """ + def __init__(self, data=None): + ffi, _ = dist.load() + super(SOCKET, self).__init__("SOCKET[1]", ffi) + # Initialize from a object as returned by some + # Windows API library calls: Python AND FFI types must be equal. + if isinstance(data, type(self._cdata[0])): + if ffi.typeof(data) == ffi.typeof(self._cdata[0]): + self._cdata[0] = data + + def __repr__(self): + ffi, _ = dist.load() + return "" % ( + int(ffi.cast("intptr_t", self._cdata[0])), + id(self) + ) + + def __eq__(self, other): + if not isinstance(other, SOCKET): + raise TypeError("%r must be a SOCKET" % other) + return self._cdata[0] == other._cdata[0] + + # pylint: disable=invalid-name class SECURITY_ATTRIBUTES(typesbase.CFFICDataWrapper): """ diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index 29e3a91..d5c151e 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -8,11 +8,12 @@ from six import integer_types from pywincffi.core import dist -from pywincffi.core.checks import Enums, input_check, error_check +from pywincffi.core.checks import input_check, error_check from pywincffi.exceptions import WindowsAPIError +from pywincffi.wintypes import HANDLE, SOCKET, wintype_to_cdata -def WSAEventSelect(sock, hEventObject, lNetworkEvents): +def WSAEventSelect(socket, hEventObject, lNetworkEvents): """ Specifies an event object to be associated with the specified set of FD_XXX network events. @@ -21,10 +22,10 @@ def WSAEventSelect(sock, hEventObject, lNetworkEvents): https://msdn.microsoft.com/en-us/library/ms741576 - :param int sock: + :param int socket: A descriptor identify the socket. - :param handle hEventObject: + :param :class:`pywincffi.wintypes.WSAEVENT` hEventObject: A handle which identifies the event object to be associated with the network events. @@ -32,16 +33,20 @@ def WSAEventSelect(sock, hEventObject, lNetworkEvents): A bitmask which specifies the combination of ``FD_XXX`` network events which the application has interest in. """ - input_check("sock", sock, integer_types) - input_check("hEventObject", hEventObject, Enums.HANDLE) + input_check( + "socket", socket, allowed_types=(SOCKET, )) + input_check( + "hEventObject", hEventObject, + allowed_types=(HANDLE, ) + ) input_check("lNetworkEvents", lNetworkEvents, integer_types) ffi, library = dist.load() - # TODO: `sock` needs conversion + # TODO: `socket` needs conversion code = library.WSAEventSelect( - sock, - ffi.cast("WSAEVENT", hEventObject), + wintype_to_cdata(socket), + wintype_to_cdata(hEventObject), ffi.cast("long", lNetworkEvents) ) From 38a166d98905d4fb048e1362354ea280e5a73d4a Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sat, 18 Jun 2016 14:41:50 -0400 Subject: [PATCH 20/48] import fix --- pywincffi/wintypes/__init__.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pywincffi/wintypes/__init__.py b/pywincffi/wintypes/__init__.py index f85c7c2..8ea0537 100644 --- a/pywincffi/wintypes/__init__.py +++ b/pywincffi/wintypes/__init__.py @@ -6,9 +6,8 @@ used across the exposed APIs. """ - -from pywincffi.core import typesbase from pywincffi.core import dist +from pywincffi.core.typesbase import CFFICDataWrapper # pylint: disable=protected-access @@ -29,7 +28,7 @@ def wintype_to_cdata(wintype): >>> result = lib.ResetEvent(hEvent_cdata) :param wintype: - A type derived from :class:`pywincffi.core.typesbase.CFFICDataWrapper` + A type derived from :class:`pywincffi.core.CFFICDataWrapper` :return: The underlying CFFI object, or ffi.NULL if wintype is None. @@ -44,7 +43,7 @@ def wintype_to_cdata(wintype): # pylint: disable=too-few-public-methods -class HANDLE(typesbase.CFFICDataWrapper): +class HANDLE(CFFICDataWrapper): """ .. seealso:: @@ -72,7 +71,7 @@ def __eq__(self, other): return self._cdata[0] == other._cdata[0] -class SOCKET(typesbase.CFFICDataWrapper): +class SOCKET(CFFICDataWrapper): """ Wraps the ``SOCKET`` C data type. @@ -103,7 +102,7 @@ def __eq__(self, other): # pylint: disable=invalid-name -class SECURITY_ATTRIBUTES(typesbase.CFFICDataWrapper): +class SECURITY_ATTRIBUTES(CFFICDataWrapper): """ .. seealso:: @@ -132,7 +131,7 @@ def nLength(self, _): # pylint: disable=too-few-public-methods -class OVERLAPPED(typesbase.CFFICDataWrapper): +class OVERLAPPED(CFFICDataWrapper): """ .. seealso:: @@ -156,7 +155,7 @@ def hEvent(self, handle): # pylint: disable=too-few-public-methods -class FILETIME(typesbase.CFFICDataWrapper): +class FILETIME(CFFICDataWrapper): """ .. seealso:: From c9b214fef1954070861098c0145ad29fe7db4820 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 12:32:58 -0400 Subject: [PATCH 21/48] adding wsa_invalid_event --- pywincffi/core/cdefs/headers/functions.h | 2 ++ pywincffi/core/cdefs/sources/main.c | 8 ++++++++ pywincffi/ws2_32/events.py | 8 ++++---- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 8aa930b..726bb48 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -209,6 +209,8 @@ BOOL WINAPI ResetEvent( /////////////////////// // Communications /////////////////////// +BOOL wsa_invalid_event(WSAEVENT); + // https://msdn.microsoft.com/en-us/aa363180 BOOL WINAPI ClearCommError( _In_ HANDLE hFile, diff --git a/pywincffi/core/cdefs/sources/main.c b/pywincffi/core/cdefs/sources/main.c index e328be8..ffb01f3 100644 --- a/pywincffi/core/cdefs/sources/main.c +++ b/pywincffi/core/cdefs/sources/main.c @@ -29,3 +29,11 @@ HANDLE handle_from_fd(int fd) { return (HANDLE)_get_osfhandle(fd); } + + +// Checks to see if a given event is considered invalid. We perform this +// check in C because cffi itself has trouble creating a usable value for +// WSA_INVALID_EVENT. +BOOL wsa_invalid_event(WSAEVENT event) { + return event == WSA_INVALID_EVENT; +} diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index d5c151e..014c65d 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -69,15 +69,15 @@ def WSACreateEvent(): :returns: Returns a handle to a new event object. """ - _, library = dist.load() - result = library.WSACreateEvent() + ffi, library = dist.load() + event = library.WSACreateEvent() - if result == library.WSA_INVALID_EVENT: + if library.wsa_invalid_event(event): errno = WSAGetLastError() raise WindowsAPIError( "WSACreateEvent", "Socket error %d" % errno, errno) - return result + return HANDLE(event) def WSAGetLastError(): From 123f826d2a8ce113a5e3128ac543eee97ffec9ce Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 12:59:33 -0400 Subject: [PATCH 22/48] adding mock_library() so we can mock library functions --- pywincffi/dev/testutil.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/pywincffi/dev/testutil.py b/pywincffi/dev/testutil.py index 421aa4d..9b34988 100644 --- a/pywincffi/dev/testutil.py +++ b/pywincffi/dev/testutil.py @@ -14,6 +14,7 @@ from textwrap import dedent from cffi import FFI, CDefError, FFIError +from mock import patch try: # The setup.py file installs unittest2 for Python 2 @@ -23,6 +24,7 @@ # pylint: disable=wrong-import-order from unittest import TestCase as _TestCase +from pywincffi.core import dist from pywincffi.core.config import config from pywincffi.core.logger import get_logger @@ -35,6 +37,25 @@ WindowsError = OSError # pylint: disable=redefined-builtin +class LibraryWrapper(object): + def __init__(self, library, attributes): + self.library = library + self.attributes = {} + + for attribute, value in attributes.items(): + if not hasattr(library, attribute): + raise AttributeError( + "No such attribute %r on library" % attribute) + + self.attributes[attribute] = value + + def __getattr__(self, item): + if item in self.attributes: + return self.attributes[item] + + return getattr(self.library, item) + + class TestCase(_TestCase): """ A base class for all test cases. By default the @@ -148,3 +169,13 @@ def random_string(self, length): output += choice(ascii_lowercase + ascii_uppercase + "0123456789") return output + + def mock_library(self, **attributes): + """ + Used to replace an attribute the library that :func:`dist.load` + returns. Useful for replacing part of the compiled library as part + of the test. + """ + ffi, library = dist.load() + return patch.object( + dist, "load", lambda: [ffi, LibraryWrapper(library, attributes)]) From c3ea3dcedd6c2fe061a61680ec62bea15968b294 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 12:59:45 -0400 Subject: [PATCH 23/48] adding tests for WSACreateEvent --- tests/test_ws2_32/test_events.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index 7fc7f95..4258d69 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -1,5 +1,7 @@ from pywincffi.dev.testutil import TestCase -from pywincffi.ws2_32 import WSAGetLastError +from pywincffi.exceptions import WindowsAPIError +from pywincffi.kernel32 import CloseHandle +from pywincffi.ws2_32 import WSAGetLastError, WSACreateEvent class TestWSAGetLastError(TestCase): @@ -9,3 +11,17 @@ class TestWSAGetLastError(TestCase): def test_get_last_error(self): self._ws2_32.WSASetLastError(4242) self.assertEqual(WSAGetLastError(), 4242) + + +class TestWSACreateEvent(TestCase): + """ + Tests for ``pywincffi.ws2_32.events.WSACreateEvent`` + """ + def test_create_event_call(self): + event = WSACreateEvent() + CloseHandle(event) + + def test_invalid_event(self): + with self.mock_library(wsa_invalid_event=lambda _: True): + with self.assertRaises(WindowsAPIError): + WSACreateEvent() From 41eeea9a854747aa7e9715aa8186218d7d66fb46 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 13:02:56 -0400 Subject: [PATCH 24/48] rename unused var to _ --- pywincffi/ws2_32/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index 014c65d..13dbe56 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -69,7 +69,7 @@ def WSACreateEvent(): :returns: Returns a handle to a new event object. """ - ffi, library = dist.load() + _, library = dist.load() event = library.WSACreateEvent() if library.wsa_invalid_event(event): From 2ab19425fc402befb7af0d60e152350c6c0e2632 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 13:03:22 -0400 Subject: [PATCH 25/48] mock_library should be a function, not a method --- pywincffi/dev/testutil.py | 27 ++++++++++++++++----------- tests/test_ws2_32/test_events.py | 4 ++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/pywincffi/dev/testutil.py b/pywincffi/dev/testutil.py index 9b34988..670252d 100644 --- a/pywincffi/dev/testutil.py +++ b/pywincffi/dev/testutil.py @@ -37,7 +37,11 @@ WindowsError = OSError # pylint: disable=redefined-builtin -class LibraryWrapper(object): +class LibraryWrapper(object): # pylint: disable=too-few-public-methods + """ + Used by :meth:`TestCase.mock_library` to replace specific + attributes on a compiled library. + """ def __init__(self, library, attributes): self.library = library self.attributes = {} @@ -56,6 +60,17 @@ def __getattr__(self, item): return getattr(self.library, item) +def mock_library(**attributes): + """ + Used to replace an attribute the library that :func:`dist.load` + returns. Useful for replacing part of the compiled library as part + of the test. + """ + ffi, library = dist.load() + return patch.object( + dist, "load", lambda: [ffi, LibraryWrapper(library, attributes)]) + + class TestCase(_TestCase): """ A base class for all test cases. By default the @@ -169,13 +184,3 @@ def random_string(self, length): output += choice(ascii_lowercase + ascii_uppercase + "0123456789") return output - - def mock_library(self, **attributes): - """ - Used to replace an attribute the library that :func:`dist.load` - returns. Useful for replacing part of the compiled library as part - of the test. - """ - ffi, library = dist.load() - return patch.object( - dist, "load", lambda: [ffi, LibraryWrapper(library, attributes)]) diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index 4258d69..5940c35 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -1,4 +1,4 @@ -from pywincffi.dev.testutil import TestCase +from pywincffi.dev.testutil import TestCase, mock_library from pywincffi.exceptions import WindowsAPIError from pywincffi.kernel32 import CloseHandle from pywincffi.ws2_32 import WSAGetLastError, WSACreateEvent @@ -22,6 +22,6 @@ def test_create_event_call(self): CloseHandle(event) def test_invalid_event(self): - with self.mock_library(wsa_invalid_event=lambda _: True): + with mock_library(wsa_invalid_event=lambda _: True): with self.assertRaises(WindowsAPIError): WSACreateEvent() From 5887f8c2f9d6835e8a0bd729cbf8f450f3089c80 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 14:11:29 -0400 Subject: [PATCH 26/48] updating changelog --- docs/source/changelog.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 5b16e31..54724d1 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -16,7 +16,7 @@ Notable enhancements and changes are: * Fixed a bug where :func:`pywincffi.checks.input_check` might raise ``ffi.error`` in :issue:`73` * Several enhancements bringing :issue:`69` closer to closure. - * Addition several functions or :issue:`69`: + * Addition several functions for :issue:`69`: * :issue:`70` - :func:`pywincffi.kernel32.events.CreateEvent` and :func:`pywincffi.kernel32.events.OpenEvent` * :issue:`75` - :func:`pywincffi.kernel32.events.ResetEvent` @@ -24,6 +24,8 @@ Notable enhancements and changes are: * :issue:`78` - :func:`pywincffi.kernel32.handle.DuplicateHandle` * :issue:`79` - :func:`pywincffi.kernel32.process.ClearCommError` * :issue:`80` - :func:`pywincffi.user32.synchronization.MsgWaitForMultipleObjects` + * :issue:`81` - :func:`pywincffi.user32.synchronization.WSAEventSelect` and + :func:`pywincffi.user32.synchronization.WSAEnumNetworkEvents` * Added Python 3.5 support to the build. No bug fixes or code changes where required, just a minor test modification. * All exposed APIs updated to use the new Windows equivalent Python types From d48e57e2e3b77c23c1778b7d4b8d549305d83e3b Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 16:44:46 -0400 Subject: [PATCH 27/48] need to accept HANDLE here too --- pywincffi/wintypes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywincffi/wintypes/__init__.py b/pywincffi/wintypes/__init__.py index 8ea0537..e9efb56 100644 --- a/pywincffi/wintypes/__init__.py +++ b/pywincffi/wintypes/__init__.py @@ -36,7 +36,7 @@ def wintype_to_cdata(wintype): ffi, _ = dist.load() if wintype is None: return ffi.NULL - elif isinstance(wintype, HANDLE): + elif isinstance(wintype, (HANDLE, SOCKET)): return wintype._cdata[0] else: return wintype._cdata From d9d9a44ebd5f2c8a971e7bbb6e1adfe4f365d33a Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 16:45:22 -0400 Subject: [PATCH 28/48] adding socket_from_fd() library function --- pywincffi/core/cdefs/headers/functions.h | 1 + pywincffi/core/cdefs/sources/main.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pywincffi/core/cdefs/headers/functions.h b/pywincffi/core/cdefs/headers/functions.h index 726bb48..f0598e4 100644 --- a/pywincffi/core/cdefs/headers/functions.h +++ b/pywincffi/core/cdefs/headers/functions.h @@ -210,6 +210,7 @@ BOOL WINAPI ResetEvent( // Communications /////////////////////// BOOL wsa_invalid_event(WSAEVENT); +SOCKET socket_from_fd(int...); // https://msdn.microsoft.com/en-us/aa363180 BOOL WINAPI ClearCommError( diff --git a/pywincffi/core/cdefs/sources/main.c b/pywincffi/core/cdefs/sources/main.c index ffb01f3..ea7879b 100644 --- a/pywincffi/core/cdefs/sources/main.c +++ b/pywincffi/core/cdefs/sources/main.c @@ -2,6 +2,24 @@ #include #include #include +#include + +// Copied from Python's socket module. These are used to determine +// how PyLong_FromSocket_t should be defined. +#ifdef MS_WIN64 +#define SIZEOF_SOCKET_T 8 +#else +#define SIZEOF_SOCKET_T 4 +#endif + +// Copied from Python's socket module. These are considered private so we +// wouldn't have been able to used them directly. The resulting function, +// PyLong_FromSocket_t, is used in socket_from_fd below. +#if SIZEOF_SOCKET_T <= SIZEOF_LONG +#define PyLong_FromSocket_t(fd) PyLong_FromLong((SOCKET)(fd)) +#else +#define PyLong_FromSocket_t(fd) PyLong_FromLongLong((SOCKET)(fd)) +#endif // Extra constants which are not defined in all versions of the Windows // SDK. If cffi fails to find the value, it ends up being picked up from @@ -37,3 +55,8 @@ HANDLE handle_from_fd(int fd) { BOOL wsa_invalid_event(WSAEVENT event) { return event == WSA_INVALID_EVENT; } + +// A function which converts +SOCKET socket_from_fd(int fd) { + return (SOCKET)PyLong_FromSocket_t(fd); +} From e5c4fbaa94c126b620f4e81c9ac9b3c7c70821b3 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 26 Jun 2016 17:06:37 -0400 Subject: [PATCH 29/48] wip --- pywincffi/ws2_32/events.py | 3 +-- tests/test_ws2_32/test_events.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index 13dbe56..5086d06 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -37,8 +37,7 @@ def WSAEventSelect(socket, hEventObject, lNetworkEvents): "socket", socket, allowed_types=(SOCKET, )) input_check( "hEventObject", hEventObject, - allowed_types=(HANDLE, ) - ) + allowed_types=(HANDLE, )) input_check("lNetworkEvents", lNetworkEvents, integer_types) ffi, library = dist.load() diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index 5940c35..c946279 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -25,3 +25,14 @@ def test_invalid_event(self): with mock_library(wsa_invalid_event=lambda _: True): with self.assertRaises(WindowsAPIError): WSACreateEvent() + + +class TestWSAEventSelect(TestCase): + """ + Tests for ``pywincffi.ws2_32.events.WSAEventSelect`` + """ + # def test_select_event_call(self): + # ffi, library = dist.load() + # event = CreateEvent( + # False, False, lpEventAttributes=None, lpName=None) + # self.addCleanup(CloseHandle, event) From 7f2260e20c614fa7e93f7aff8c4d5e57226d168c Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Fri, 1 Jul 2016 07:46:22 -0400 Subject: [PATCH 30/48] fixing changelog to point to 'latest' version --- docs/source/changelog.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 19328ee..7db0af1 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -11,12 +11,18 @@ Versions latest ~~~~~~ +Notable enhancements and changes are: + + * :issue:`81` - :func:`pywincffi.user32.synchronization.WSAEventSelect` and + :func:`pywincffi.user32.synchronization.WSAEnumNetworkEvents` + 0.3.0 ~~~~~ Notable enhancements and changes are: - * Added the :func:`pywincffi.kernel32.CreateToolhelp32Snapshot` function in :issue:`101`. + * Added the :func:`pywincffi.kernel32.CreateToolhelp32Snapshot` function + in :issue:`101`. * Fixed a bug where :func:`pywincffi.checks.input_check` might raise ``ffi.error`` in :issue:`73` * Several enhancements bringing :issue:`69` closer to closure. @@ -28,8 +34,6 @@ Notable enhancements and changes are: * :issue:`78` - :func:`pywincffi.kernel32.handle.DuplicateHandle` * :issue:`79` - :func:`pywincffi.kernel32.process.ClearCommError` * :issue:`80` - :func:`pywincffi.user32.synchronization.MsgWaitForMultipleObjects` - * :issue:`81` - :func:`pywincffi.user32.synchronization.WSAEventSelect` and - :func:`pywincffi.user32.synchronization.WSAEnumNetworkEvents` * Added Python 3.5 support to the build. No bug fixes or code changes where required, just a minor test modification. * All exposed APIs updated to use the new Windows equivalent Python types From 2d5e8d5d799e87fff4a68d7ce1bc425b7e9c6127 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Fri, 1 Jul 2016 08:26:38 -0400 Subject: [PATCH 31/48] fix doc strings --- pywincffi/ws2_32/events.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index 5086d06..de73ba9 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -22,10 +22,10 @@ def WSAEventSelect(socket, hEventObject, lNetworkEvents): https://msdn.microsoft.com/en-us/library/ms741576 - :param int socket: + :param pywincffi.wintypes.objects.SOCKET socket: A descriptor identify the socket. - :param :class:`pywincffi.wintypes.WSAEVENT` hEventObject: + :param pywincffi.wintypes.objects.WSAEVENT hEventObject: A handle which identifies the event object to be associated with the network events. @@ -42,7 +42,6 @@ def WSAEventSelect(socket, hEventObject, lNetworkEvents): ffi, library = dist.load() - # TODO: `socket` needs conversion code = library.WSAEventSelect( wintype_to_cdata(socket), wintype_to_cdata(hEventObject), From 830b94c1a55d6806d707756ba8ad126912dc4d3b Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Fri, 1 Jul 2016 08:27:34 -0400 Subject: [PATCH 32/48] continued work on tests --- tests/test_ws2_32/test_events.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index c946279..04eae64 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -1,7 +1,11 @@ +import socket + +from pywincffi.core import dist from pywincffi.dev.testutil import TestCase, mock_library from pywincffi.exceptions import WindowsAPIError from pywincffi.kernel32 import CloseHandle -from pywincffi.ws2_32 import WSAGetLastError, WSACreateEvent +from pywincffi.ws2_32 import WSAGetLastError, WSACreateEvent, WSAEventSelect +from pywincffi.wintypes import socket_from_object, wintype_to_cdata class TestWSAGetLastError(TestCase): @@ -31,8 +35,18 @@ class TestWSAEventSelect(TestCase): """ Tests for ``pywincffi.ws2_32.events.WSAEventSelect`` """ - # def test_select_event_call(self): - # ffi, library = dist.load() - # event = CreateEvent( - # False, False, lpEventAttributes=None, lpName=None) - # self.addCleanup(CloseHandle, event) + def create_socket(self): + _, library = dist.load() + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(sock.close) + return socket_from_object(sock) + + def test_select_event_call(self): + sock = self.create_socket() + ffi, library = dist.load() + event = WSACreateEvent() + self.addCleanup(CloseHandle, event) + WSAEventSelect( + sock, event, + library.FD_READ | library.FD_WRITE + ) From ea007ba51b9b65db8887e51f732ee4bb75c2c369 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 11:30:44 -0400 Subject: [PATCH 33/48] bugfix, should have SOCKET here too --- pywincffi/wintypes/functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywincffi/wintypes/functions.py b/pywincffi/wintypes/functions.py index 50a5e93..5b85454 100644 --- a/pywincffi/wintypes/functions.py +++ b/pywincffi/wintypes/functions.py @@ -39,7 +39,7 @@ def wintype_to_cdata(wintype): ffi, _ = dist.load() if wintype is None: return ffi.NULL - elif isinstance(wintype, HANDLE): + elif isinstance(wintype, (SOCKET, HANDLE)): return wintype._cdata[0] else: return wintype._cdata From 2632e70c53b13275afda536db6d351308177cd5d Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 11:35:22 -0400 Subject: [PATCH 34/48] lint fix --- tests/test_ws2_32/test_events.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index 04eae64..e8fa75b 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -5,7 +5,7 @@ from pywincffi.exceptions import WindowsAPIError from pywincffi.kernel32 import CloseHandle from pywincffi.ws2_32 import WSAGetLastError, WSACreateEvent, WSAEventSelect -from pywincffi.wintypes import socket_from_object, wintype_to_cdata +from pywincffi.wintypes import socket_from_object class TestWSAGetLastError(TestCase): @@ -36,14 +36,13 @@ class TestWSAEventSelect(TestCase): Tests for ``pywincffi.ws2_32.events.WSAEventSelect`` """ def create_socket(self): - _, library = dist.load() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.addCleanup(sock.close) return socket_from_object(sock) def test_select_event_call(self): sock = self.create_socket() - ffi, library = dist.load() + _, library = dist.load() event = WSACreateEvent() self.addCleanup(CloseHandle, event) WSAEventSelect( From 10a3be6cf8e4b75a517665e3986334df48ff97c1 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 12:28:04 -0400 Subject: [PATCH 35/48] adding missing url --- pywincffi/core/cdefs/headers/constants.h | 1 + 1 file changed, 1 insertion(+) diff --git a/pywincffi/core/cdefs/headers/constants.h b/pywincffi/core/cdefs/headers/constants.h index 2f3f4bf..3b0dc78 100644 --- a/pywincffi/core/cdefs/headers/constants.h +++ b/pywincffi/core/cdefs/headers/constants.h @@ -227,6 +227,7 @@ #define QS_TIMER ... // WSAEventSelect +// https://msdn.microsoft.com/en-us/library/ms741576 #define SOCKET_ERROR ... #define FD_READ ... #define FD_WRITE ... From 4f77cf6fc306f0cf9b6d3f148c3ac4c092b27043 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 12:28:26 -0400 Subject: [PATCH 36/48] fix header order --- pywincffi/core/cdefs/sources/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pywincffi/core/cdefs/sources/main.c b/pywincffi/core/cdefs/sources/main.c index be18470..8a475d8 100644 --- a/pywincffi/core/cdefs/sources/main.c +++ b/pywincffi/core/cdefs/sources/main.c @@ -1,9 +1,8 @@ #include #include #include -#include #include -#include +#include // Extra constants which are not defined in all versions of the Windows // SDK. If cffi fails to find the value, it ends up being picked up from From 37ed287ad293dc30cd6b6226fbea9cc5edafc1e5 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 12:28:55 -0400 Subject: [PATCH 37/48] create function to return reader and writer sockets for testing --- pywincffi/dev/testutil.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pywincffi/dev/testutil.py b/pywincffi/dev/testutil.py index db22e25..82cf474 100644 --- a/pywincffi/dev/testutil.py +++ b/pywincffi/dev/testutil.py @@ -183,3 +183,23 @@ def random_string(self, length): output += choice(ascii_lowercase + ascii_uppercase + "0123456789") return output + + def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM): + """ + Creates a local socket listening on a random port. + """ + # Establish the server's socket + server = socket.socket(family=family, type=type) + server.bind(("127.0.0.1", 0)) + server.setblocking(0) + _, port = server.getsockname() + server.listen(0) + + # Connect to the server's socket. + client = socket.socket(family=family, type=type) + client.connect(("127.0.0.1", port)) + + self.addCleanup(client.close) + self.addCleanup(server.close) + + return server, client From 702017a8eb7888c3f9773f4288b07126e841ca11 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 12:29:40 -0400 Subject: [PATCH 38/48] adding simple call test for WSAEventSelect --- tests/test_ws2_32/test_events.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index e8fa75b..2ef8404 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -1,5 +1,3 @@ -import socket - from pywincffi.core import dist from pywincffi.dev.testutil import TestCase, mock_library from pywincffi.exceptions import WindowsAPIError @@ -35,17 +33,16 @@ class TestWSAEventSelect(TestCase): """ Tests for ``pywincffi.ws2_32.events.WSAEventSelect`` """ - def create_socket(self): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.addCleanup(sock.close) - return socket_from_object(sock) - - def test_select_event_call(self): - sock = self.create_socket() + def test_event_select_basic_call(self): + # Establish a simple socket server and client _, library = dist.load() + server, client = self.create_socket() + + # Setup the event event = WSACreateEvent() self.addCleanup(CloseHandle, event) WSAEventSelect( - sock, event, - library.FD_READ | library.FD_WRITE + socket_from_object(server), + event, + library.FD_WRITE | library.FD_ACCEPT | library.FD_CONNECT ) From a24d7b1e56696fb626144be5bf9e8db4c1c22e30 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 12:31:27 -0400 Subject: [PATCH 39/48] lint fixes --- pywincffi/dev/testutil.py | 6 +++--- tests/test_ws2_32/test_events.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pywincffi/dev/testutil.py b/pywincffi/dev/testutil.py index 82cf474..52f44be 100644 --- a/pywincffi/dev/testutil.py +++ b/pywincffi/dev/testutil.py @@ -184,19 +184,19 @@ def random_string(self, length): return output - def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM): + def create_socket(self, family=socket.AF_INET, type_=socket.SOCK_STREAM): """ Creates a local socket listening on a random port. """ # Establish the server's socket - server = socket.socket(family=family, type=type) + server = socket.socket(family=family, type=type_) server.bind(("127.0.0.1", 0)) server.setblocking(0) _, port = server.getsockname() server.listen(0) # Connect to the server's socket. - client = socket.socket(family=family, type=type) + client = socket.socket(family=family, type=type_) client.connect(("127.0.0.1", port)) self.addCleanup(client.close) diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index 2ef8404..ab5dfde 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -36,7 +36,7 @@ class TestWSAEventSelect(TestCase): def test_event_select_basic_call(self): # Establish a simple socket server and client _, library = dist.load() - server, client = self.create_socket() + server, _ = self.create_socket() # Setup the event event = WSACreateEvent() From 5cc5c215f47afec2eb9967d1bd6d1680569622e3 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 12:41:32 -0400 Subject: [PATCH 40/48] doc string fix --- pywincffi/ws2_32/events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index de73ba9..b9fc1b6 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -23,7 +23,7 @@ def WSAEventSelect(socket, hEventObject, lNetworkEvents): https://msdn.microsoft.com/en-us/library/ms741576 :param pywincffi.wintypes.objects.SOCKET socket: - A descriptor identify the socket. + The socket object to associate the selected network events with. :param pywincffi.wintypes.objects.WSAEVENT hEventObject: A handle which identifies the event object to be associated From 02c63e2cf7977dba8e3f2966ffa1ccf2c4805acd Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 12:46:42 -0400 Subject: [PATCH 41/48] adding WSAEVENT --- pywincffi/wintypes/__init__.py | 2 +- pywincffi/wintypes/functions.py | 4 ++-- pywincffi/wintypes/objects.py | 11 +++++++++++ tests/test_wintypes/test_objects.py | 15 ++++++++++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/pywincffi/wintypes/__init__.py b/pywincffi/wintypes/__init__.py index 050f7ad..fdabc29 100644 --- a/pywincffi/wintypes/__init__.py +++ b/pywincffi/wintypes/__init__.py @@ -7,6 +7,6 @@ from pywincffi.wintypes.functions import ( wintype_to_cdata, handle_from_file, socket_from_object) -from pywincffi.wintypes.objects import WrappedObject, HANDLE, SOCKET +from pywincffi.wintypes.objects import WrappedObject, HANDLE, WSAEVENT, SOCKET from pywincffi.wintypes.structures import ( SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME) diff --git a/pywincffi/wintypes/functions.py b/pywincffi/wintypes/functions.py index 5b85454..a77076c 100644 --- a/pywincffi/wintypes/functions.py +++ b/pywincffi/wintypes/functions.py @@ -10,7 +10,7 @@ from pywincffi.core import dist from pywincffi.exceptions import InputError -from pywincffi.wintypes.objects import HANDLE, SOCKET +from pywincffi.wintypes.objects import HANDLE, SOCKET, WSAEVENT # pylint: disable=protected-access @@ -39,7 +39,7 @@ def wintype_to_cdata(wintype): ffi, _ = dist.load() if wintype is None: return ffi.NULL - elif isinstance(wintype, (SOCKET, HANDLE)): + elif isinstance(wintype, (SOCKET, HANDLE, WSAEVENT)): return wintype._cdata[0] else: return wintype._cdata diff --git a/pywincffi/wintypes/objects.py b/pywincffi/wintypes/objects.py index d99705a..5ab55c2 100644 --- a/pywincffi/wintypes/objects.py +++ b/pywincffi/wintypes/objects.py @@ -60,6 +60,17 @@ class HANDLE(WrappedObject): C_TYPE = "HANDLE[1]" +class WSAEVENT(HANDLE): + """ + Handles interaction with a WSAEVENT object via its cdata. + + .. note:: + + This is functionally equivalent to a :class:`HANDLE` object. + """ + C_TYPE = "WSAEVENT[1]" + + class SOCKET(WrappedObject): """Handles interaction with a SOCKET object via its cdata""" C_TYPE = "SOCKET[1]" diff --git a/tests/test_wintypes/test_objects.py b/tests/test_wintypes/test_objects.py index 24ba8c6..60878cb 100644 --- a/tests/test_wintypes/test_objects.py +++ b/tests/test_wintypes/test_objects.py @@ -1,6 +1,6 @@ from pywincffi.core import dist from pywincffi.dev.testutil import TestCase -from pywincffi.wintypes import WrappedObject, HANDLE, SOCKET +from pywincffi.wintypes import WrappedObject, HANDLE, SOCKET, WSAEVENT class TestWrappedObject(TestCase): @@ -92,6 +92,19 @@ def cast_from_value(self, int_data): return self.OBJECT_CLASS(cdata[0]) +class TestWSAEVENT(ObjectBaseTestCase): + """ + Tests for :class:`pywincffi.wintypes.WSAEVENT` + """ + OBJECT_CLASS = WSAEVENT + + def cast_from_value(self, int_data): + ffi, _ = dist.load() + cdata = ffi.new(self.OBJECT_CLASS.C_TYPE) + cdata[0] = ffi.cast(self.OBJECT_CLASS.__name__, int_data) + return self.OBJECT_CLASS(cdata[0]) + + class TestSOCKET(ObjectBaseTestCase): """ Tests for :class:`pywincffi.wintypes.SOCKET` From bbf196df63ae8665e91112f01af750ce9c9b8561 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 13:00:08 -0400 Subject: [PATCH 42/48] initial definition of WSANETWORKEVENTS --- pywincffi/wintypes/__init__.py | 2 +- pywincffi/wintypes/structures.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pywincffi/wintypes/__init__.py b/pywincffi/wintypes/__init__.py index fdabc29..d40a229 100644 --- a/pywincffi/wintypes/__init__.py +++ b/pywincffi/wintypes/__init__.py @@ -9,4 +9,4 @@ wintype_to_cdata, handle_from_file, socket_from_object) from pywincffi.wintypes.objects import WrappedObject, HANDLE, WSAEVENT, SOCKET from pywincffi.wintypes.structures import ( - SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME) + SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME, WSANETWORKEVENTS) diff --git a/pywincffi/wintypes/structures.py b/pywincffi/wintypes/structures.py index e476836..3702c58 100644 --- a/pywincffi/wintypes/structures.py +++ b/pywincffi/wintypes/structures.py @@ -74,3 +74,14 @@ class FILETIME(CFFICDataWrapper): def __init__(self): ffi, _ = dist.load() super(FILETIME, self).__init__("FILETIME*", ffi) + + +class WSANETWORKEVENTS(CFFICDataWrapper): + """ + .. seealso:: + + https://msdn.microsoft.com/en-us/ms741653 + """ + def __init__(self): + ffi, _ = dist.load() + super(WSANETWORKEVENTS, self).__init__("WSANETWORKEVENTS*", ffi) From 2a532beddacaf828bbf1241c50b21efcc6fddcfc Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 13:08:47 -0400 Subject: [PATCH 43/48] initial definition of WSAEnumNetworkEvents --- pywincffi/ws2_32/__init__.py | 2 +- pywincffi/ws2_32/events.py | 52 +++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/pywincffi/ws2_32/__init__.py b/pywincffi/ws2_32/__init__.py index 18c94d0..2b3b75a 100644 --- a/pywincffi/ws2_32/__init__.py +++ b/pywincffi/ws2_32/__init__.py @@ -7,4 +7,4 @@ """ from pywincffi.ws2_32.events import ( - WSAEventSelect, WSACreateEvent, WSAGetLastError) + WSAEventSelect, WSACreateEvent, WSAGetLastError, WSAEnumNetworkEvents) diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index b9fc1b6..54a9b8f 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -10,7 +10,8 @@ from pywincffi.core import dist from pywincffi.core.checks import input_check, error_check from pywincffi.exceptions import WindowsAPIError -from pywincffi.wintypes import HANDLE, SOCKET, wintype_to_cdata +from pywincffi.wintypes import ( + HANDLE, SOCKET, WSAEVENT, WSANETWORKEVENTS, wintype_to_cdata) def WSAEventSelect(socket, hEventObject, lNetworkEvents): @@ -33,11 +34,8 @@ def WSAEventSelect(socket, hEventObject, lNetworkEvents): A bitmask which specifies the combination of ``FD_XXX`` network events which the application has interest in. """ - input_check( - "socket", socket, allowed_types=(SOCKET, )) - input_check( - "hEventObject", hEventObject, - allowed_types=(HANDLE, )) + input_check("socket", socket, allowed_types=(SOCKET, )) + input_check("hEventObject", hEventObject, allowed_types=(HANDLE, )) input_check("lNetworkEvents", lNetworkEvents, integer_types) ffi, library = dist.load() @@ -88,3 +86,45 @@ def WSAGetLastError(): """ _, library = dist.load() return library.WSAGetLastError() + + +def WSAEnumNetworkEvents(socket, hEventObject=None): + """ + Discovers occurrences of network events on the indicated ``socket``, clears + internal events and optionally resets event objects. + + .. seealso:: + https://msdn.microsoft.com/en-us/ms741572 + + :param pywincffi.wintypes.objects.SOCKET socket: + The socket object to enumerate events for. + + :keyword pywincffi.wintypes.objects.WSAEVENT hEventObject: + An optional handle identify an associated event object + to be reset. + + :rtype: :class:`pywincffi.wintypes.structures.WSANETWORKEVENTS` + :return: + """ + input_check("socket", socket, allowed_types=(SOCKET, )) + + ffi, library = dist.load() + if hEventObject is not None: + input_check("hEventObject", hEventObject, allowed_types=(WSAEVENT, )) + hEventObject = wintype_to_cdata(hEventObject) + else: + hEventObject = ffi.NULL + + lpNetworkEvents = ffi.new("LPWSANETWORKEVENTS") + code = library.WSAEnumNetworkEvents( + wintype_to_cdata(socket), + hEventObject, + lpNetworkEvents + ) + error_check("WSAEnumNetworkEvents", code=code, expected=0) + + # TODO use something like WSANETWORKEVENTS.from_cdata here + # pylint: disable=protected-access + result = WSANETWORKEVENTS() + result._cdata[0] = lpNetworkEvents + return result From 4ca0679840956df4906cdb57f84d7cd8c7e88a00 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 15:10:12 -0400 Subject: [PATCH 44/48] add test to cover WSAEventSelect returning SOCKET_ERROR --- tests/test_ws2_32/test_events.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index ab5dfde..59901c2 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -46,3 +46,24 @@ def test_event_select_basic_call(self): event, library.FD_WRITE | library.FD_ACCEPT | library.FD_CONNECT ) + + def test_socket_error(self): + def wrapped(*args): + _, library = dist.load() + return library.SOCKET_ERROR + + with mock_library(WSAEventSelect=wrapped): + # Establish a simple socket server and client + _, library = dist.load() + server, _ = self.create_socket() + + # Setup the event + event = WSACreateEvent() + self.addCleanup(CloseHandle, event) + + with self.assertRaises(WindowsAPIError): + WSAEventSelect( + socket_from_object(server), + event, + library.FD_WRITE | library.FD_ACCEPT | library.FD_CONNECT + ) From ffee5dbcc4f4934fabb74ee8b3e0ebfecf3bf752 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 15:38:19 -0400 Subject: [PATCH 45/48] fix type name, adding iErrorCode property --- pywincffi/wintypes/__init__.py | 2 +- pywincffi/wintypes/structures.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pywincffi/wintypes/__init__.py b/pywincffi/wintypes/__init__.py index d40a229..815aca4 100644 --- a/pywincffi/wintypes/__init__.py +++ b/pywincffi/wintypes/__init__.py @@ -9,4 +9,4 @@ wintype_to_cdata, handle_from_file, socket_from_object) from pywincffi.wintypes.objects import WrappedObject, HANDLE, WSAEVENT, SOCKET from pywincffi.wintypes.structures import ( - SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME, WSANETWORKEVENTS) + SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME, LPWSANETWORKEVENTS) diff --git a/pywincffi/wintypes/structures.py b/pywincffi/wintypes/structures.py index 3702c58..6522334 100644 --- a/pywincffi/wintypes/structures.py +++ b/pywincffi/wintypes/structures.py @@ -76,7 +76,7 @@ def __init__(self): super(FILETIME, self).__init__("FILETIME*", ffi) -class WSANETWORKEVENTS(CFFICDataWrapper): +class LPWSANETWORKEVENTS(CFFICDataWrapper): """ .. seealso:: @@ -84,4 +84,9 @@ class WSANETWORKEVENTS(CFFICDataWrapper): """ def __init__(self): ffi, _ = dist.load() - super(WSANETWORKEVENTS, self).__init__("WSANETWORKEVENTS*", ffi) + super(LPWSANETWORKEVENTS, self).__init__("LPWSANETWORKEVENTS", ffi) + + @property + def iErrorCode(self): + """An array of integers containing any associated error codes""" + return tuple(self._cdata.iErrorCode) From b115b80f687d0a6a976f13493fce997d8aea0a67 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 15:38:33 -0400 Subject: [PATCH 46/48] adding test for iErrorCode property --- tests/test_wintypes/test_structures.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/test_wintypes/test_structures.py b/tests/test_wintypes/test_structures.py index 24a46a5..0085b24 100644 --- a/tests/test_wintypes/test_structures.py +++ b/tests/test_wintypes/test_structures.py @@ -1,6 +1,7 @@ +from pywincffi.core import dist from pywincffi.dev.testutil import TestCase from pywincffi.wintypes import ( - HANDLE, SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME) + HANDLE, SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME, LPWSANETWORKEVENTS) class TestSECURITY_ATTRIBUTES(TestCase): @@ -82,3 +83,13 @@ def test_missing_attr(self): ft = FILETIME() with self.assertRaises(AttributeError): ft.no_such_attr = None + + +class TestLPWSANETWORKEVENTS(TestCase): + """ + Tests for :class:`pywincffi.wintypes.LPWSANETWORKEVENTS` + """ + def test_iErrorCode(self): + _, library = dist.load() + events = LPWSANETWORKEVENTS() + self.assertEqual(events.iErrorCode, tuple([0] * library.FD_MAX_EVENTS)) From 0b102b456f037458695d64310a9820d357fe34f1 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 15:39:00 -0400 Subject: [PATCH 47/48] should not be calling ffi.new() internally --- pywincffi/ws2_32/events.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pywincffi/ws2_32/events.py b/pywincffi/ws2_32/events.py index 54a9b8f..f5fd29a 100644 --- a/pywincffi/ws2_32/events.py +++ b/pywincffi/ws2_32/events.py @@ -11,7 +11,7 @@ from pywincffi.core.checks import input_check, error_check from pywincffi.exceptions import WindowsAPIError from pywincffi.wintypes import ( - HANDLE, SOCKET, WSAEVENT, WSANETWORKEVENTS, wintype_to_cdata) + HANDLE, SOCKET, WSAEVENT, LPWSANETWORKEVENTS, wintype_to_cdata) def WSAEventSelect(socket, hEventObject, lNetworkEvents): @@ -103,7 +103,7 @@ def WSAEnumNetworkEvents(socket, hEventObject=None): An optional handle identify an associated event object to be reset. - :rtype: :class:`pywincffi.wintypes.structures.WSANETWORKEVENTS` + :rtype: :class:`pywincffi.wintypes.structures.LPWSANETWORKEVENTS` :return: """ input_check("socket", socket, allowed_types=(SOCKET, )) @@ -115,16 +115,12 @@ def WSAEnumNetworkEvents(socket, hEventObject=None): else: hEventObject = ffi.NULL - lpNetworkEvents = ffi.new("LPWSANETWORKEVENTS") + lpNetworkEvents = LPWSANETWORKEVENTS() code = library.WSAEnumNetworkEvents( wintype_to_cdata(socket), hEventObject, - lpNetworkEvents + wintype_to_cdata(lpNetworkEvents) ) error_check("WSAEnumNetworkEvents", code=code, expected=0) - # TODO use something like WSANETWORKEVENTS.from_cdata here - # pylint: disable=protected-access - result = WSANETWORKEVENTS() - result._cdata[0] = lpNetworkEvents - return result + return lpNetworkEvents From 711bdcd9531703ca3640b914ec68096801852641 Mon Sep 17 00:00:00 2001 From: Oliver Palmer Date: Sun, 3 Jul 2016 16:29:12 -0400 Subject: [PATCH 48/48] added tests for WSAEnumNetworkEvents --- pywincffi/dev/testutil.py | 20 ------ tests/test_ws2_32/test_events.py | 104 ++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 37 deletions(-) diff --git a/pywincffi/dev/testutil.py b/pywincffi/dev/testutil.py index 52f44be..db22e25 100644 --- a/pywincffi/dev/testutil.py +++ b/pywincffi/dev/testutil.py @@ -183,23 +183,3 @@ def random_string(self, length): output += choice(ascii_lowercase + ascii_uppercase + "0123456789") return output - - def create_socket(self, family=socket.AF_INET, type_=socket.SOCK_STREAM): - """ - Creates a local socket listening on a random port. - """ - # Establish the server's socket - server = socket.socket(family=family, type=type_) - server.bind(("127.0.0.1", 0)) - server.setblocking(0) - _, port = server.getsockname() - server.listen(0) - - # Connect to the server's socket. - client = socket.socket(family=family, type=type_) - client.connect(("127.0.0.1", port)) - - self.addCleanup(client.close) - self.addCleanup(server.close) - - return server, client diff --git a/tests/test_ws2_32/test_events.py b/tests/test_ws2_32/test_events.py index 59901c2..bbf30a3 100644 --- a/tests/test_ws2_32/test_events.py +++ b/tests/test_ws2_32/test_events.py @@ -1,9 +1,37 @@ +import socket + from pywincffi.core import dist from pywincffi.dev.testutil import TestCase, mock_library from pywincffi.exceptions import WindowsAPIError from pywincffi.kernel32 import CloseHandle -from pywincffi.ws2_32 import WSAGetLastError, WSACreateEvent, WSAEventSelect -from pywincffi.wintypes import socket_from_object +from pywincffi.wintypes import LPWSANETWORKEVENTS, socket_from_object +from pywincffi.ws2_32 import ( + WSAGetLastError, WSACreateEvent, WSAEventSelect, WSAEnumNetworkEvents) + + +class EventsCase(TestCase): + """ + Has some common methods used by tests in this module + """ + def tearDown(self): + super(EventsCase, self).tearDown() + self.assertEqual(WSAGetLastError(), 0) + + def create_wsaevent(self): + event = WSACreateEvent() + self.addCleanup(CloseHandle, event) + return event + + def create_socket_pair(self): + """ + Creates a local socket listening on a random port. + """ + # Establish the server's socket + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(server.close) + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addCleanup(client.close) + return server, client class TestWSAGetLastError(TestCase): @@ -12,6 +40,7 @@ class TestWSAGetLastError(TestCase): """ def test_get_last_error(self): self._ws2_32.WSASetLastError(4242) + self.addCleanup(self._ws2_32.WSASetLastError, 0) self.assertEqual(WSAGetLastError(), 4242) @@ -19,51 +48,92 @@ class TestWSACreateEvent(TestCase): """ Tests for ``pywincffi.ws2_32.events.WSACreateEvent`` """ - def test_create_event_call(self): - event = WSACreateEvent() - CloseHandle(event) - def test_invalid_event(self): with mock_library(wsa_invalid_event=lambda _: True): with self.assertRaises(WindowsAPIError): WSACreateEvent() -class TestWSAEventSelect(TestCase): +class TestWSAEventSelect(EventsCase): """ Tests for ``pywincffi.ws2_32.events.WSAEventSelect`` """ - def test_event_select_basic_call(self): + def test_basic_call(self): # Establish a simple socket server and client _, library = dist.load() - server, _ = self.create_socket() + sock, _, = self.create_socket_pair() # Setup the event - event = WSACreateEvent() - self.addCleanup(CloseHandle, event) + event = self.create_wsaevent() WSAEventSelect( - socket_from_object(server), + socket_from_object(sock), event, library.FD_WRITE | library.FD_ACCEPT | library.FD_CONNECT ) def test_socket_error(self): - def wrapped(*args): + def wrapped(*_): _, library = dist.load() return library.SOCKET_ERROR with mock_library(WSAEventSelect=wrapped): # Establish a simple socket server and client _, library = dist.load() - server, _ = self.create_socket() + sock, _ = self.create_socket_pair() # Setup the event - event = WSACreateEvent() - self.addCleanup(CloseHandle, event) + event = self.create_wsaevent() with self.assertRaises(WindowsAPIError): WSAEventSelect( - socket_from_object(server), + socket_from_object(sock), event, library.FD_WRITE | library.FD_ACCEPT | library.FD_CONNECT ) + + +class TestWSAEnumNetworkEvents(EventsCase): + """ + Tests for ``pywincffi.ws2_32.events.WSAEnumNetworkEvents`` + """ + def test_basic_call(self): + _, library = dist.load() + sock, _ = self.create_socket_pair() + events = WSAEnumNetworkEvents(socket_from_object(sock)) + self.assertIsInstance(events, LPWSANETWORKEVENTS) + self.assertEqual(events.iErrorCode, tuple([0] * library.FD_MAX_EVENTS)) + + def test_triggers_accept_event(self): + _, library = dist.load() + sock_server, sock_client = self.create_socket_pair() + sock_server_wintype = socket_from_object(sock_server) + + # Listen on one socket and then connect with another. This should + # cause an FD_ACCEPT network event to occur. + sock_server.bind(("127.0.0.1", 0)) + sock_server.listen(0) + _, port = sock_server.getsockname() + sock_client.connect(("127.0.0.1", port)) + + event = self.create_wsaevent() + WSAEventSelect(sock_server_wintype, event, library.FD_ACCEPT) + events = WSAEnumNetworkEvents(sock_server_wintype) + self.assertEqual(events.lNetworkEvents, library.FD_ACCEPT) + + def test_triggers_write_event(self): + _, library = dist.load() + sock_server, sock_client = self.create_socket_pair() + sock_client_wintype = socket_from_object(sock_client) + + # Listen on one socket and then connect with another. This should + # cause an FD_ACCEPT network event to occur. + sock_server.bind(("127.0.0.1", 0)) + sock_server.listen(0) + _, port = sock_server.getsockname() + sock_client.connect(("127.0.0.1", port)) + sock_client.send(b"Hello world") + + event = self.create_wsaevent() + WSAEventSelect(sock_client_wintype, event, library.FD_WRITE) + events = WSAEnumNetworkEvents(sock_client_wintype) + self.assertEqual(events.lNetworkEvents, library.FD_WRITE)