mirror of https://git.kore.io/kore.git
Python: Add kore.socket.recvmsg()
Returns the ancillary data to the caller as a list.
This commit is contained in:
parent
af99a4d9e2
commit
4313c0eab5
|
@ -315,6 +315,7 @@ static PyObject *pysocket_close(struct pysocket *, PyObject *);
|
||||||
static PyObject *pysocket_accept(struct pysocket *, PyObject *);
|
static PyObject *pysocket_accept(struct pysocket *, PyObject *);
|
||||||
static PyObject *pysocket_sendto(struct pysocket *, PyObject *);
|
static PyObject *pysocket_sendto(struct pysocket *, PyObject *);
|
||||||
static PyObject *pysocket_connect(struct pysocket *, PyObject *);
|
static PyObject *pysocket_connect(struct pysocket *, PyObject *);
|
||||||
|
static PyObject *pysocket_recvmsg(struct pysocket *, PyObject *);
|
||||||
static PyObject *pysocket_recvfrom(struct pysocket *, PyObject *);
|
static PyObject *pysocket_recvfrom(struct pysocket *, PyObject *);
|
||||||
|
|
||||||
static PyMethodDef pysocket_methods[] = {
|
static PyMethodDef pysocket_methods[] = {
|
||||||
|
@ -324,6 +325,7 @@ static PyMethodDef pysocket_methods[] = {
|
||||||
METHOD("accept", pysocket_accept, METH_NOARGS),
|
METHOD("accept", pysocket_accept, METH_NOARGS),
|
||||||
METHOD("sendto", pysocket_sendto, METH_VARARGS),
|
METHOD("sendto", pysocket_sendto, METH_VARARGS),
|
||||||
METHOD("connect", pysocket_connect, METH_VARARGS),
|
METHOD("connect", pysocket_connect, METH_VARARGS),
|
||||||
|
METHOD("recvmsg", pysocket_recvmsg, METH_VARARGS),
|
||||||
METHOD("recvfrom", pysocket_recvfrom, METH_VARARGS),
|
METHOD("recvfrom", pysocket_recvfrom, METH_VARARGS),
|
||||||
METHOD(NULL, NULL, -1),
|
METHOD(NULL, NULL, -1),
|
||||||
};
|
};
|
||||||
|
@ -346,6 +348,7 @@ static PyTypeObject pysocket_type = {
|
||||||
#define PYSOCKET_TYPE_SEND 4
|
#define PYSOCKET_TYPE_SEND 4
|
||||||
#define PYSOCKET_TYPE_RECVFROM 5
|
#define PYSOCKET_TYPE_RECVFROM 5
|
||||||
#define PYSOCKET_TYPE_SENDTO 6
|
#define PYSOCKET_TYPE_SENDTO 6
|
||||||
|
#define PYSOCKET_TYPE_RECVMSG 7
|
||||||
|
|
||||||
struct pysocket_op {
|
struct pysocket_op {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
|
|
142
src/python.c
142
src/python.c
|
@ -66,6 +66,7 @@ static PyObject *python_callable(PyObject *, const char *);
|
||||||
static void python_split_arguments(char *, char **, size_t);
|
static void python_split_arguments(char *, char **, size_t);
|
||||||
static void python_kore_recvobj(struct kore_msg *, const void *);
|
static void python_kore_recvobj(struct kore_msg *, const void *);
|
||||||
|
|
||||||
|
static PyObject *python_cmsg_to_list(struct msghdr *);
|
||||||
static const char *python_string_from_dict(PyObject *, const char *);
|
static const char *python_string_from_dict(PyObject *, const char *);
|
||||||
static int python_bool_from_dict(PyObject *, const char *, int *);
|
static int python_bool_from_dict(PyObject *, const char *, int *);
|
||||||
static int python_long_from_dict(PyObject *, const char *, long *);
|
static int python_long_from_dict(PyObject *, const char *, long *);
|
||||||
|
@ -846,6 +847,38 @@ python_string_from_dict(PyObject *dict, const char *key)
|
||||||
return (PyUnicode_AsUTF8AndSize(obj, NULL));
|
return (PyUnicode_AsUTF8AndSize(obj, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
python_cmsg_to_list(struct msghdr *msg)
|
||||||
|
{
|
||||||
|
struct cmsghdr *c;
|
||||||
|
Py_ssize_t idx;
|
||||||
|
PyObject *list, *tuple;
|
||||||
|
|
||||||
|
if ((list = PyList_New(0)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
idx = 0;
|
||||||
|
|
||||||
|
for (c = CMSG_FIRSTHDR(msg); c != NULL; c = CMSG_NXTHDR(msg, c)) {
|
||||||
|
tuple = Py_BuildValue("(Iiiy#)", c->cmsg_len,
|
||||||
|
c->cmsg_level, c->cmsg_type, CMSG_DATA(c), c->cmsg_len);
|
||||||
|
|
||||||
|
if (tuple == NULL) {
|
||||||
|
Py_DECREF(list);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Steals a reference to tuple. */
|
||||||
|
if (PyList_Insert(list, idx++, tuple) == -1) {
|
||||||
|
Py_DECREF(tuple);
|
||||||
|
Py_DECREF(list);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (list);
|
||||||
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
python_malloc(void *ctx, size_t len)
|
python_malloc(void *ctx, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -2903,6 +2936,17 @@ pysocket_recv(struct pysocket *sock, PyObject *args)
|
||||||
return (obj);
|
return (obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pysocket_recvmsg(struct pysocket *sock, PyObject *args)
|
||||||
|
{
|
||||||
|
Py_ssize_t len;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "n", &len))
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
return (pysocket_op_create(sock, PYSOCKET_TYPE_RECVMSG, NULL, len));
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
pysocket_recvfrom(struct pysocket *sock, PyObject *args)
|
pysocket_recvfrom(struct pysocket *sock, PyObject *args)
|
||||||
{
|
{
|
||||||
|
@ -2997,6 +3041,7 @@ static void
|
||||||
pysocket_op_dealloc(struct pysocket_op *op)
|
pysocket_op_dealloc(struct pysocket_op *op)
|
||||||
{
|
{
|
||||||
if (op->type == PYSOCKET_TYPE_RECV ||
|
if (op->type == PYSOCKET_TYPE_RECV ||
|
||||||
|
op->type == PYSOCKET_TYPE_RECVMSG ||
|
||||||
op->type == PYSOCKET_TYPE_RECVFROM ||
|
op->type == PYSOCKET_TYPE_RECVFROM ||
|
||||||
op->type == PYSOCKET_TYPE_SEND ||
|
op->type == PYSOCKET_TYPE_SEND ||
|
||||||
op->type == PYSOCKET_TYPE_SENDTO)
|
op->type == PYSOCKET_TYPE_SENDTO)
|
||||||
|
@ -3005,6 +3050,7 @@ pysocket_op_dealloc(struct pysocket_op *op)
|
||||||
switch (op->type) {
|
switch (op->type) {
|
||||||
case PYSOCKET_TYPE_RECV:
|
case PYSOCKET_TYPE_RECV:
|
||||||
case PYSOCKET_TYPE_ACCEPT:
|
case PYSOCKET_TYPE_ACCEPT:
|
||||||
|
case PYSOCKET_TYPE_RECVMSG:
|
||||||
case PYSOCKET_TYPE_RECVFROM:
|
case PYSOCKET_TYPE_RECVFROM:
|
||||||
if (op->socket->recvop != op)
|
if (op->socket->recvop != op)
|
||||||
fatal("recvop mismatch");
|
fatal("recvop mismatch");
|
||||||
|
@ -3041,6 +3087,7 @@ pysocket_op_create(struct pysocket *sock, int type, const void *ptr, size_t len)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PYSOCKET_TYPE_RECV:
|
case PYSOCKET_TYPE_RECV:
|
||||||
case PYSOCKET_TYPE_ACCEPT:
|
case PYSOCKET_TYPE_ACCEPT:
|
||||||
|
case PYSOCKET_TYPE_RECVMSG:
|
||||||
case PYSOCKET_TYPE_RECVFROM:
|
case PYSOCKET_TYPE_RECVFROM:
|
||||||
if (sock->recvop != NULL) {
|
if (sock->recvop != NULL) {
|
||||||
PyErr_SetString(PyExc_RuntimeError,
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
|
@ -3077,6 +3124,7 @@ pysocket_op_create(struct pysocket *sock, int type, const void *ptr, size_t len)
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PYSOCKET_TYPE_RECV:
|
case PYSOCKET_TYPE_RECV:
|
||||||
|
case PYSOCKET_TYPE_RECVMSG:
|
||||||
case PYSOCKET_TYPE_RECVFROM:
|
case PYSOCKET_TYPE_RECVFROM:
|
||||||
sock->recvop = op;
|
sock->recvop = op;
|
||||||
kore_buf_init(&op->buffer, len);
|
kore_buf_init(&op->buffer, len);
|
||||||
|
@ -3149,6 +3197,7 @@ pysocket_op_iternext(struct pysocket_op *op)
|
||||||
ret = pysocket_async_accept(op);
|
ret = pysocket_async_accept(op);
|
||||||
break;
|
break;
|
||||||
case PYSOCKET_TYPE_RECV:
|
case PYSOCKET_TYPE_RECV:
|
||||||
|
case PYSOCKET_TYPE_RECVMSG:
|
||||||
case PYSOCKET_TYPE_RECVFROM:
|
case PYSOCKET_TYPE_RECVFROM:
|
||||||
ret = pysocket_async_recv(op);
|
ret = pysocket_async_recv(op);
|
||||||
break;
|
break;
|
||||||
|
@ -3247,23 +3296,44 @@ pysocket_async_accept(struct pysocket_op *op)
|
||||||
static PyObject *
|
static PyObject *
|
||||||
pysocket_async_recv(struct pysocket_op *op)
|
pysocket_async_recv(struct pysocket_op *op)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
size_t len;
|
size_t len;
|
||||||
u_int16_t port;
|
u_int16_t port;
|
||||||
socklen_t socklen;
|
struct iovec iov;
|
||||||
struct sockaddr *sendaddr;
|
struct msghdr msg;
|
||||||
const char *ptr, *ip;
|
socklen_t socklen;
|
||||||
PyObject *bytes, *result, *tuple;
|
struct sockaddr *sendaddr;
|
||||||
|
const char *ptr, *ip;
|
||||||
|
u_int8_t ancdata[1024];
|
||||||
|
PyObject *bytes, *result, *tuple, *list;
|
||||||
|
|
||||||
if (!(op->socket->event.evt.flags & KORE_EVENT_READ)) {
|
if (!(op->socket->event.evt.flags & KORE_EVENT_READ)) {
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (op->type == PYSOCKET_TYPE_RECV) {
|
switch (op->type) {
|
||||||
|
case PYSOCKET_TYPE_RECV:
|
||||||
ret = read(op->socket->fd, op->buffer.data,
|
ret = read(op->socket->fd, op->buffer.data,
|
||||||
op->buffer.length);
|
op->buffer.length);
|
||||||
} else {
|
break;
|
||||||
|
case PYSOCKET_TYPE_RECVMSG:
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
|
||||||
|
iov.iov_base = op->buffer.data;
|
||||||
|
iov.iov_len = op->buffer.length;
|
||||||
|
|
||||||
|
msg.msg_iov = &iov;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
msg.msg_name = &op->sendaddr;
|
||||||
|
msg.msg_namelen = sizeof(op->sendaddr);
|
||||||
|
msg.msg_control = ancdata;
|
||||||
|
msg.msg_controllen = sizeof(ancdata);
|
||||||
|
|
||||||
|
memset(&op->sendaddr, 0, sizeof(op->sendaddr));
|
||||||
|
ret = recvmsg(op->socket->fd, &msg, 0);
|
||||||
|
break;
|
||||||
|
case PYSOCKET_TYPE_RECVFROM:
|
||||||
sendaddr = (struct sockaddr *)&op->sendaddr;
|
sendaddr = (struct sockaddr *)&op->sendaddr;
|
||||||
switch (op->socket->family) {
|
switch (op->socket->family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
|
@ -3273,12 +3343,15 @@ pysocket_async_recv(struct pysocket_op *op)
|
||||||
socklen = sizeof(op->sendaddr.sun);
|
socklen = sizeof(op->sendaddr.sun);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fatal("non AF_INET/AF_UNIX in %s", __func__);
|
fatal("%s: non AF_INET/AF_UNIX", __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(sendaddr, 0, socklen);
|
memset(sendaddr, 0, socklen);
|
||||||
ret = recvfrom(op->socket->fd, op->buffer.data,
|
ret = recvfrom(op->socket->fd, op->buffer.data,
|
||||||
op->buffer.length, 0, sendaddr, &socklen);
|
op->buffer.length, 0, sendaddr, &socklen);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fatal("%s: unknown type %d", __func__, op->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
|
@ -3312,10 +3385,22 @@ pysocket_async_recv(struct pysocket_op *op)
|
||||||
if ((bytes = PyBytes_FromStringAndSize(ptr, ret)) == NULL)
|
if ((bytes = PyBytes_FromStringAndSize(ptr, ret)) == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
if (op->type == PYSOCKET_TYPE_RECV) {
|
list = NULL;
|
||||||
|
|
||||||
|
switch (op->type) {
|
||||||
|
case PYSOCKET_TYPE_RECV:
|
||||||
PyErr_SetObject(PyExc_StopIteration, bytes);
|
PyErr_SetObject(PyExc_StopIteration, bytes);
|
||||||
Py_DECREF(bytes);
|
Py_DECREF(bytes);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
case PYSOCKET_TYPE_RECVMSG:
|
||||||
|
socklen = msg.msg_namelen;
|
||||||
|
if ((list = python_cmsg_to_list(&msg)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
break;
|
||||||
|
case PYSOCKET_TYPE_RECVFROM:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fatal("%s: unknown type %d", __func__, op->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(op->socket->family) {
|
switch(op->socket->family) {
|
||||||
|
@ -3323,8 +3408,10 @@ pysocket_async_recv(struct pysocket_op *op)
|
||||||
port = ntohs(op->sendaddr.ipv4.sin_port);
|
port = ntohs(op->sendaddr.ipv4.sin_port);
|
||||||
ip = inet_ntoa(op->sendaddr.ipv4.sin_addr);
|
ip = inet_ntoa(op->sendaddr.ipv4.sin_addr);
|
||||||
|
|
||||||
if ((tuple = Py_BuildValue("(sHN)", ip, port, bytes)) == NULL)
|
if (op->type == PYSOCKET_TYPE_RECV)
|
||||||
return (NULL);
|
tuple = Py_BuildValue("(sHN)", ip, port, bytes);
|
||||||
|
else
|
||||||
|
tuple = Py_BuildValue("(sHNN)", ip, port, bytes, list);
|
||||||
break;
|
break;
|
||||||
case AF_UNIX:
|
case AF_UNIX:
|
||||||
len = strlen(op->sendaddr.sun.sun_path);
|
len = strlen(op->sendaddr.sun.sun_path);
|
||||||
|
@ -3336,18 +3423,29 @@ pysocket_async_recv(struct pysocket_op *op)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
if ((tuple = Py_BuildValue("(ON)",
|
if (op->type == PYSOCKET_TYPE_RECVFROM) {
|
||||||
Py_None, bytes)) == NULL)
|
tuple = Py_BuildValue("(ON)", Py_None, bytes);
|
||||||
return (NULL);
|
} else {
|
||||||
break;
|
tuple = Py_BuildValue("(ONN)",
|
||||||
|
Py_None, bytes, list);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (op->type == PYSOCKET_TYPE_RECVFROM) {
|
||||||
|
tuple = Py_BuildValue("(sN)",
|
||||||
|
op->sendaddr.sun.sun_path, bytes);
|
||||||
|
} else {
|
||||||
|
tuple = Py_BuildValue("(sNN)",
|
||||||
|
op->sendaddr.sun.sun_path, bytes, list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((tuple = Py_BuildValue("(sN)",
|
|
||||||
op->sendaddr.sun.sun_path, bytes)) == NULL)
|
|
||||||
return (NULL);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PyErr_SetString(PyExc_RuntimeError, "Unsupported family");
|
fatal("%s: non AF_INET/AF_UNIX", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tuple == NULL) {
|
||||||
|
Py_XDECREF(list);
|
||||||
|
Py_DECREF(bytes);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue