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