summaryrefslogtreecommitdiffstats
path: root/Modules/overlapped.c
diff options
context:
space:
mode:
authorAlex Grönholm <alex.gronholm@nextday.fi>2022-03-13 16:42:29 (GMT)
committerGitHub <noreply@github.com>2022-03-13 16:42:29 (GMT)
commit9f04ee569cebb8b4c6f04bea95d91a19c5403806 (patch)
treeabd4626ee19d394f35109b4cd2830d50a4a4f9d9 /Modules/overlapped.c
parent7e473e94a52024ac821dd2f206290423e4987ead (diff)
downloadcpython-9f04ee569cebb8b4c6f04bea95d91a19c5403806.zip
cpython-9f04ee569cebb8b4c6f04bea95d91a19c5403806.tar.gz
cpython-9f04ee569cebb8b4c6f04bea95d91a19c5403806.tar.bz2
bpo-46805: Add low level UDP socket functions to asyncio (GH-31455)
Diffstat (limited to 'Modules/overlapped.c')
-rw-r--r--Modules/overlapped.c132
1 files changed, 128 insertions, 4 deletions
diff --git a/Modules/overlapped.c b/Modules/overlapped.c
index 2ba48c8..ab9a2f0 100644
--- a/Modules/overlapped.c
+++ b/Modules/overlapped.c
@@ -64,7 +64,7 @@ class _overlapped.Overlapped "OverlappedObject *" "&OverlappedType"
enum {TYPE_NONE, TYPE_NOT_STARTED, TYPE_READ, TYPE_READINTO, TYPE_WRITE,
TYPE_ACCEPT, TYPE_CONNECT, TYPE_DISCONNECT, TYPE_CONNECT_NAMED_PIPE,
TYPE_WAIT_NAMED_PIPE_AND_CONNECT, TYPE_TRANSMIT_FILE, TYPE_READ_FROM,
- TYPE_WRITE_TO};
+ TYPE_WRITE_TO, TYPE_READ_FROM_INTO};
typedef struct {
PyObject_HEAD
@@ -91,6 +91,17 @@ typedef struct {
struct sockaddr_in6 address;
int address_length;
} read_from;
+
+ /* Data used for reading from a connectionless socket:
+ TYPE_READ_FROM_INTO */
+ struct {
+ // A (number of bytes read, (host, port)) tuple
+ PyObject* result;
+ /* Buffer passed by the user */
+ Py_buffer *user_buffer;
+ struct sockaddr_in6 address;
+ int address_length;
+ } read_from_into;
};
} OverlappedObject;
@@ -662,6 +673,13 @@ Overlapped_clear(OverlappedObject *self)
}
break;
}
+ case TYPE_READ_FROM_INTO: {
+ if (self->read_from_into.result) {
+ // We've received a message, free the result tuple.
+ Py_CLEAR(self->read_from_into.result);
+ }
+ break;
+ }
case TYPE_WRITE:
case TYPE_WRITE_TO:
case TYPE_READINTO: {
@@ -866,6 +884,11 @@ _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
{
break;
}
+ else if (self->type == TYPE_READ_FROM_INTO &&
+ self->read_from_into.result != NULL)
+ {
+ break;
+ }
/* fall through */
default:
return SetFromWindowsErr(err);
@@ -914,6 +937,30 @@ _overlapped_Overlapped_getresult_impl(OverlappedObject *self, BOOL wait)
Py_INCREF(self->read_from.result);
return self->read_from.result;
+ case TYPE_READ_FROM_INTO:
+ // unparse the address
+ addr = unparse_address((SOCKADDR*)&self->read_from_into.address,
+ self->read_from_into.address_length);
+
+ if (addr == NULL) {
+ return NULL;
+ }
+
+ // The result is a two item tuple: (number of bytes read, address)
+ self->read_from_into.result = PyTuple_New(2);
+ if (self->read_from_into.result == NULL) {
+ Py_CLEAR(addr);
+ return NULL;
+ }
+
+ // first item: number of bytes read
+ PyTuple_SET_ITEM(self->read_from_into.result, 0,
+ PyLong_FromUnsignedLong((unsigned long)transferred));
+ // second item: address
+ PyTuple_SET_ITEM(self->read_from_into.result, 1, addr);
+
+ Py_INCREF(self->read_from_into.result);
+ return self->read_from_into.result;
default:
return PyLong_FromUnsignedLong((unsigned long) transferred);
}
@@ -1053,6 +1100,7 @@ do_WSARecv(OverlappedObject *self, HANDLE handle,
}
}
+
/*[clinic input]
_overlapped.Overlapped.WSARecv
@@ -1617,6 +1665,13 @@ Overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
case TYPE_READ_FROM:
Py_VISIT(self->read_from.result);
Py_VISIT(self->read_from.allocated_buffer);
+ break;
+ case TYPE_READ_FROM_INTO:
+ Py_VISIT(self->read_from_into.result);
+ if (self->read_from_into.user_buffer->obj) {
+ Py_VISIT(&self->read_from_into.user_buffer->obj);
+ }
+ break;
}
return 0;
}
@@ -1766,8 +1821,8 @@ _overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
DWORD flags)
/*[clinic end generated code: output=13832a2025b86860 input=1b2663fa130e0286]*/
{
- DWORD nread;
PyObject *buf;
+ DWORD nread;
WSABUF wsabuf;
int ret;
DWORD err;
@@ -1785,8 +1840,8 @@ _overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
return NULL;
}
- wsabuf.len = size;
wsabuf.buf = PyBytes_AS_STRING(buf);
+ wsabuf.len = size;
self->type = TYPE_READ_FROM;
self->handle = handle;
@@ -1802,8 +1857,74 @@ _overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
Py_END_ALLOW_THREADS
self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
+ switch (err) {
+ case ERROR_BROKEN_PIPE:
+ mark_as_completed(&self->overlapped);
+ return SetFromWindowsErr(err);
+ case ERROR_SUCCESS:
+ case ERROR_MORE_DATA:
+ case ERROR_IO_PENDING:
+ Py_RETURN_NONE;
+ default:
+ self->type = TYPE_NOT_STARTED;
+ return SetFromWindowsErr(err);
+ }
+}
- switch(err) {
+
+/*[clinic input]
+_overlapped.Overlapped.WSARecvFromInto
+
+ handle: HANDLE
+ buf as bufobj: Py_buffer
+ size: DWORD
+ flags: DWORD = 0
+ /
+
+Start overlapped receive.
+[clinic start generated code]*/
+
+static PyObject *
+_overlapped_Overlapped_WSARecvFromInto_impl(OverlappedObject *self,
+ HANDLE handle, Py_buffer *bufobj,
+ DWORD size, DWORD flags)
+/*[clinic end generated code: output=30c7ea171a691757 input=4be4b08d03531e76]*/
+{
+ DWORD nread;
+ WSABUF wsabuf;
+ int ret;
+ DWORD err;
+
+ if (self->type != TYPE_NONE) {
+ PyErr_SetString(PyExc_ValueError, "operation already attempted");
+ return NULL;
+ }
+
+#if SIZEOF_SIZE_T > SIZEOF_LONG
+ if (bufobj->len > (Py_ssize_t)ULONG_MAX) {
+ PyErr_SetString(PyExc_ValueError, "buffer too large");
+ return NULL;
+ }
+#endif
+
+ wsabuf.buf = bufobj->buf;
+ wsabuf.len = size;
+
+ self->type = TYPE_READ_FROM_INTO;
+ self->handle = handle;
+ self->read_from_into.user_buffer = bufobj;
+ memset(&self->read_from_into.address, 0, sizeof(self->read_from_into.address));
+ self->read_from_into.address_length = sizeof(self->read_from_into.address);
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = WSARecvFrom((SOCKET)handle, &wsabuf, 1, &nread, &flags,
+ (SOCKADDR*)&self->read_from_into.address,
+ &self->read_from_into.address_length,
+ &self->overlapped, NULL);
+ Py_END_ALLOW_THREADS
+
+ self->error = err = (ret < 0 ? WSAGetLastError() : ERROR_SUCCESS);
+ switch (err) {
case ERROR_BROKEN_PIPE:
mark_as_completed(&self->overlapped);
return SetFromWindowsErr(err);
@@ -1817,6 +1938,7 @@ _overlapped_Overlapped_WSARecvFrom_impl(OverlappedObject *self,
}
}
+
#include "clinic/overlapped.c.h"
static PyMethodDef Overlapped_methods[] = {
@@ -1826,6 +1948,8 @@ static PyMethodDef Overlapped_methods[] = {
_OVERLAPPED_OVERLAPPED_READFILEINTO_METHODDEF
_OVERLAPPED_OVERLAPPED_WSARECV_METHODDEF
_OVERLAPPED_OVERLAPPED_WSARECVINTO_METHODDEF
+ _OVERLAPPED_OVERLAPPED_WSARECVFROM_METHODDEF
+ _OVERLAPPED_OVERLAPPED_WSARECVFROMINTO_METHODDEF
_OVERLAPPED_OVERLAPPED_WRITEFILE_METHODDEF
_OVERLAPPED_OVERLAPPED_WSASEND_METHODDEF
_OVERLAPPED_OVERLAPPED_ACCEPTEX_METHODDEF