On Wed, Jun 30, 2021 at 08:22:19PM +0100, Richard W.M. Jones wrote:
This call previously just called abort(). Implement it for Unix domain sockets (the easy case). Implementing it for AF_INET and AF_INET6 is more complicated so that is left as a to-do.
Still, fixing it to return an error instead of abort()ing is nice.
Note also that implementing this fully for Python is a bit pointless. It would be easier for a Python program to call nbd.aio_connect_tcp(host, port) instead of calling nbd.aio_connect((host, port)). Both cases would do hostname lookups but the former is already implemented. ---
@@ -92,3 +94,64 @@ nbd_internal_py_free_string_list (char **argv) free (argv[i]); free (argv); } + +/* Convert a Python object into a struct sockaddr, according to the + * general rules described here: + * https://docs.python.org/3/library/socket.html
Python's representation is complex!
+ * + * There is a function in cpython called getsockaddrarg which roughly + * does the same thing, but in cpython they know the socket family + * already (which we do not). In any case that function cannot be + * called directly. + */ +int +nbd_internal_py_get_sockaddr (PyObject *addr, + struct sockaddr_storage *ss, socklen_t *len) +{ + memset (ss, 0, sizeof *ss); + + if (PyUnicode_Check (addr)) { /* AF_UNIX */ + struct sockaddr_un *sun = (struct sockaddr_un *)ss; + const char *unixsocket; + size_t namelen; + + sun->sun_family = AF_UNIX; + unixsocket = PyUnicode_AsUTF8 (addr); + if (!unixsocket) + goto err;
Given the PyUnicode_Check() call above, this is unlikely to fail; but checking for failure anyway is good practice.
+ namelen = strlen (unixsocket); + if (namelen > sizeof sun->sun_path) { + PyErr_SetString (PyExc_RuntimeError, + "get_sockaddr: Unix domain socket name too long"); + return -1; + } + memcpy (sun->sun_path, unixsocket, namelen); + *len = sizeof *sun; + return 0; + } + +#if 0 + else if (PyTuple_Check (addr)) { + Py_ssize_t n = PyTuple_Size (addr); + + switch (n) { + case 2: /* AF_INET */ + /* XXX TODO */ + break; + + case 4: /* AF_INET6 */ + /* XXX TODO */ + break;
The python docs implied that the last two fields were optional for AF_INET6, which makes this even more complicated. But this is all #if 0 until someone needs and implements it anyway. Patch looks good to me. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org