Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Doc/library/socket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,33 @@ created. Socket addresses are represented as follows:

.. versionadded:: 3.9

- :const:`AF_HYPERV` is a Windows-only socket based interface for communicating
Comment thread
erlend-aasland marked this conversation as resolved.
with Hyper-V hosts and guests. The address family is represented as a
``(vm_id, service_id)`` tuple where the ``vm_id`` and ``service_id`` are the
little endian byte representation of a ``uuid.UUID`` object.
Comment thread
jborean93 marked this conversation as resolved.
Outdated

The ``vm_id`` is the virtual machine identifier or a set of known VMID values
if the target is not a specific virtual machine. Known VMID values are:

- ``HV_GUID_ZERO 00000000-0000-0000-0000-000000000000`` - Used to bind on
itself and accept connections from all partitions.
- ``HV_GUID_BROADCAST FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF``
- ``HV_GUID_CHILDREN 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd`` - Used to bind on
itself and accept connection from child partitions.
- ``HV_GUID_LOOPBACK e0e16197-dd56-4a10-9195-5ee7a155a838`` - Used as a
target to itself.
- ``HV_GUID_PARENT a42e7cda-d03f-480c-9cc2-a4de20abb878`` - When used as a
bind accepts connection from the parent partition. When used as an address
target it will connect to the parent parition.

The ``service_id`` is the registered service identifier of the registered
service.

The easily get the byte value do
``uuid.UUID("eee5f691-5210-47e8-bbc9-7198bed79b77").bytes_le``.

.. versionadded:: 3.12

If you use a hostname in the *host* portion of IPv4/v6 socket address, the
program may show a nondeterministic behavior, as Python uses the first address
returned from the DNS resolution. The socket address will be resolved
Expand Down Expand Up @@ -589,6 +616,16 @@ Constants

.. availability:: Linux >= 3.9

.. data:: AF_HYPERV
HV_PROTOCOL_RAW
HVSOCKET_*

Constants for Windows Hyper-V sockets for host/guest communications.

.. availability:: Windows.

.. versionadded:: 3.12

Functions
^^^^^^^^^

Expand Down
48 changes: 48 additions & 0 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,17 @@ def _have_socket_bluetooth():
return True


def _have_socket_hyperv():
"""Check whether AF_HYPERV sockets are supported on this host."""
try:
s = socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM, socket.HV_PROTOCOL_RAW)
except (AttributeError, OSError):
return False
else:
s.close()
return True


@contextlib.contextmanager
def socket_setdefaulttimeout(timeout):
old_timeout = socket.getdefaulttimeout()
Expand Down Expand Up @@ -171,6 +182,8 @@ def socket_setdefaulttimeout(timeout):

HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth()

HAVE_SOCKET_HYPERV = _have_socket_hyperv()

# Size in bytes of the int type
SIZEOF_INT = array.array("i").itemsize

Expand Down Expand Up @@ -2459,6 +2472,41 @@ def testCreateScoSocket(self):
pass


@unittest.skipUnless(HAVE_SOCKET_HYPERV,
'Hyper-V sockets required for this test.')
class BasicHyperVTest(unittest.TestCase):
Comment thread
jborean93 marked this conversation as resolved.

def testHyperVConstants(self):
socket.HVSOCKET_CONNECT_TIMEOUT
socket.HVSOCKET_CONNECT_TIMEOUT_MAX
socket.HVSOCKET_CONTAINER_PASSTHRU
socket.HVSOCKET_CONNECTED_SUSPEND
socket.HVSOCKET_ADDRESS_FLAG_PASSTHRU

def testCreateHyperVSocketWithUnknownProtoFailure(self):
self.assertRaises(OSError, socket.socket, socket.AF_HYPERV, socket.SOCK_STREAM)
Comment thread
jborean93 marked this conversation as resolved.
Outdated

def testCreateHyperVSocketAddrNotTupleFailure(self):
with socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM, socket.HV_PROTOCOL_RAW) as s:
self.assertRaises(TypeError, s.connect, b"\x00" * 16)

def testCreateHyperVSocketAddrNotTupleOf2BytesFailure(self):
with socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM, socket.HV_PROTOCOL_RAW) as s:
self.assertRaises(TypeError, s.connect, (b"\x00" * 16,))

def testCreateHyperVSocketAddrNotTupleOfBytesFailure(self):
with socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM, socket.HV_PROTOCOL_RAW) as s:
self.assertRaises(TypeError, s.connect, (1, 2))

def testCreateHyperVSocketAddrVmIdNotCorrectLengthFailure(self):
with socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM, socket.HV_PROTOCOL_RAW) as s:
self.assertRaises(TypeError, s.connect, (b"\x00", b"\x00" * 16))

def testCreateHyperVSocketAddrServiceIdNotCorrectLengthFailure(self):
with socket.socket(socket.AF_HYPERV, socket.SOCK_STREAM, socket.HV_PROTOCOL_RAW) as s:
self.assertRaises(TypeError, s.connect, (b"\x00" * 16, b"\x00"))


class BasicTCPTest(SocketConnectedTest):

def __init__(self, methodName='runTest'):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for connecting and binding to Hyper-V sockets on Windows Hyper-V hosts and guests.
93 changes: 93 additions & 0 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,18 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
}
#endif /* HAVE_SOCKADDR_ALG */

#ifdef AF_HYPERV
case AF_HYPERV:
{
SOCKADDR_HV *a = (SOCKADDR_HV *) addr;
return Py_BuildValue("y#y#",
a->VmId,
sizeof(GUID),
a->ServiceId,
sizeof(GUID));
}
#endif /* AF_HYPERV */

/* More cases here... */

default:
Expand Down Expand Up @@ -2375,6 +2387,66 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 1;
}
#endif /* HAVE_SOCKADDR_ALG */
#ifdef AF_HYPERV
case AF_HYPERV:
{
switch (s->sock_proto) {
case HV_PROTOCOL_RAW:
{
GUID *vm_id;
Py_ssize_t vm_id_len = 0;

GUID *service_id;
Py_ssize_t service_id_len = 0;

SOCKADDR_HV *addr = &addrbuf->hv;

memset(addr, 0, sizeof(*addr));
addr->Family = AF_HYPERV;

if (!PyTuple_Check(args)) {
Comment thread
jborean93 marked this conversation as resolved.
PyErr_Format(PyExc_TypeError,
"%s(): AF_HYPERV address must be tuple, "
"not %.500s",
Comment thread
jborean93 marked this conversation as resolved.
Outdated
caller, Py_TYPE(args)->tp_name);
return 0;
}
if (!PyArg_ParseTuple(args,
"y#y#;AF_HYPERV address must be a tuple "
"(vm_id, service_id)",
&vm_id, &vm_id_len, &service_id,
&service_id_len))
{
return 0;
}
if (vm_id_len != sizeof(GUID)) {
PyErr_Format(PyExc_TypeError,
"%s(): AF_HYPERV address vm_id must have a "
"length of %d",
caller, sizeof(GUID));
return 0;
}
if (service_id_len != sizeof(GUID)) {
PyErr_Format(PyExc_TypeError,
"%s(): AF_HYPERV address service_id must have a "
"length of %d",
caller, sizeof(GUID));
return 0;
}

addr->VmId = *vm_id;
addr->ServiceId = *service_id;

*len_ret = sizeof(*addr);
return 1;
}
default:
PyErr_Format(PyExc_OSError,
"%s(): unsupported AF_HYPERV protocol", caller);
return 0;
}
}
#endif /* AF_HYPERV */

/* More cases here... */

Expand Down Expand Up @@ -2524,6 +2596,13 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
return 1;
}
#endif /* HAVE_SOCKADDR_ALG */
#ifdef AF_HYPERV
case AF_HYPERV:
{
*len_ret = sizeof (SOCKADDR_HV);
return 1;
}
#endif /* AF_HYPERV
Comment thread
jborean93 marked this conversation as resolved.
Outdated

/* More cases here... */

Expand Down Expand Up @@ -7351,6 +7430,20 @@ PyInit__socket(void)
/* Linux LLC */
PyModule_AddIntMacro(m, AF_LLC);
#endif
#ifdef AF_HYPERV
/* Hyper-V sockets */
PyModule_AddIntMacro(m, AF_HYPERV);

/* for proto */
PyModule_AddIntMacro(m, HV_PROTOCOL_RAW);

/* for setsockopt() */
PyModule_AddIntMacro(m, HVSOCKET_CONNECT_TIMEOUT);
PyModule_AddIntMacro(m, HVSOCKET_CONNECT_TIMEOUT_MAX);
PyModule_AddIntMacro(m, HVSOCKET_CONTAINER_PASSTHRU);
PyModule_AddIntMacro(m, HVSOCKET_CONNECTED_SUSPEND);
PyModule_AddIntMacro(m, HVSOCKET_ADDRESS_FLAG_PASSTHRU);
#endif /* AF_HYPERV */

#ifdef USE_BLUETOOTH
PyModule_AddIntMacro(m, AF_BLUETOOTH);
Expand Down
11 changes: 11 additions & 0 deletions Modules/socketmodule.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ struct SOCKADDR_BTH_REDEF {
# else
typedef int socklen_t;
# endif /* IPPROTO_IPV6 */

/* Future remove once Py_WINVER has been bumped to >=0x0604 */
Comment thread
jborean93 marked this conversation as resolved.
Outdated
# ifndef AF_HYPERV
# define AF_HYPERV 34
# endif

/* FIXME: Should this have some sort of safe guard? */
# include <hvsocket.h>
#endif /* MS_WINDOWS */

#ifdef HAVE_SYS_UN_H
Expand Down Expand Up @@ -288,6 +296,9 @@ typedef union sock_addr {
#ifdef HAVE_LINUX_TIPC_H
struct sockaddr_tipc tipc;
#endif
#ifdef AF_HYPERV
SOCKADDR_HV hv;
#endif
} sock_addr_t;

/* The object holding a socket. It holds some extra information,
Expand Down