Skip to content

Commit

Permalink
Merge pull request #81 from opalmer/wsa_event
Browse files Browse the repository at this point in the history
Implement WSAEventSelect and WSAEnumNetworkEvents
  • Loading branch information
opalmer authored Jul 3, 2016
2 parents 3de40a1 + 711bdcd commit dddde47
Show file tree
Hide file tree
Showing 18 changed files with 520 additions and 62 deletions.
10 changes: 8 additions & 2 deletions docs/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,22 @@ 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.
* 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`
Expand Down
3 changes: 2 additions & 1 deletion pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
113 changes: 113 additions & 0 deletions pywincffi/core/cdefs/headers/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,119 @@
#define QS_SENDMESSAGE ...
#define QS_TIMER ...

// WSAEventSelect
// https://msdn.microsoft.com/en-us/library/ms741576
#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 ...
#define FD_MAX_EVENTS ...

// 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 ...

// Other
#define FOREGROUND_RED ...
#define FOREGROUND_GREEN ...
Expand Down
32 changes: 22 additions & 10 deletions pywincffi/core/cdefs/headers/functions.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
///////////////////////
// Misc functions
///////////////////////

// https://msdn.microsoft.com/en-us/ms680627
void WINAPI SetLastError(
_In_ DWORD dwErrCode
);

///////////////////////
// Processes
///////////////////////
Expand Down Expand Up @@ -236,7 +227,28 @@ BOOL WINAPI ClearCommError(
_Out_opt_ LPCOMSTAT lpStat
);

// https://msdn.microsoft.com/en-us/ms741576
int WSAEventSelect(
_In_ SOCKET s,
_In_ WSAEVENT hEventObject,
_In_ long lNetworkEvents
);

// https://msdn.microsoft.com/en-us/ms741580
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
);

///////////////////////
// Conversion Functions
// Utility Functions
///////////////////////
HANDLE handle_from_fd(int);
BOOL wsa_invalid_event(WSAEVENT);
6 changes: 6 additions & 0 deletions pywincffi/core/cdefs/headers/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
1 change: 1 addition & 0 deletions pywincffi/core/cdefs/headers/typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
//

typedef int... SOCKET;
typedef HANDLE WSAEVENT; // according to winsock2.h
10 changes: 9 additions & 1 deletion pywincffi/core/cdefs/sources/main.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#include <io.h>
#include <winsock2.h>
#include <windows.h>
#include <winerror.h>
#include <TlHelp32.h>
#include <windows.h>

// 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
Expand Down Expand Up @@ -29,3 +30,10 @@
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;
}
68 changes: 27 additions & 41 deletions pywincffi/dev/testutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
import sys
from random import choice
from string import ascii_lowercase, ascii_uppercase
from textwrap import dedent

from cffi import FFI, CDefError
from cffi import FFI, CDefError, FFIError
from mock import patch
from six import PY2, PY3

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 import dist
from pywincffi.core.logger import get_logger
Expand All @@ -35,22 +35,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 LibraryWrapper(object): # pylint: disable=too-few-public-methods
"""
Expand Down Expand Up @@ -81,9 +65,9 @@ def mock_library(**attributes):
returns. Useful for replacing part of the compiled library as part
of the test.
"""
ffi_, library = dist.load()
ffi, library = dist.load()
return patch.object(
dist, "load", return_value=[ffi_, LibraryWrapper(library, attributes)])
dist, "load", lambda: [ffi, LibraryWrapper(library, attributes)])


class TestCase(_TestCase):
Expand All @@ -93,6 +77,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():
Expand All @@ -103,11 +90,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)

@classmethod
def internet_connected(cls):
Expand Down Expand Up @@ -142,23 +145,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.
Expand Down
5 changes: 2 additions & 3 deletions pywincffi/wintypes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
"""
Windows Types Package
=====================
Provides user accessible types corresponding to the respective Windows types
used across the exposed APIs.
"""

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)
SECURITY_ATTRIBUTES, OVERLAPPED, FILETIME, LPWSANETWORKEVENTS)
4 changes: 2 additions & 2 deletions pywincffi/wintypes/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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, WSAEVENT)):
return wintype._cdata[0]
else:
return wintype._cdata
Expand Down
Loading

0 comments on commit dddde47

Please sign in to comment.