/*
* Python bindings for TIPC
* Alberto Bertogli (albertito@gmail.com)
*
* This is the low-level module, used by the python one to construct
* friendlier objects.
*/
#include <Python.h>
#include <sys/types.h> /* socket defines */
#include <sys/socket.h> /* socket functions */
#include <stdlib.h> /* malloc() */
#include <stdint.h> /* uint32_t and friends */
#include <arpa/inet.h> /* htonls() and friends */
#include <string.h> /* memcpy() */
#include <linux/tipc.h> /* TIPC stuff */
/*
* Internal useful functions
*/
static int fill_sockaddr(struct sockaddr_tipc *sa, PyObject *addr)
{
unsigned int atype, v1, v2, v3;
unsigned int scope = TIPC_CLUSTER_SCOPE;
if (!PyArg_ParseTuple(addr, "IIII|I;Invalid TIPC address format",
&atype, &v1, &v2, &v3, &scope))
return 0;
memset(sa, 0, sizeof(struct sockaddr_tipc));
sa->family = AF_TIPC;
sa->scope = scope;
sa->addrtype = atype;
if (atype == TIPC_ADDR_NAMESEQ) {
sa->addr.nameseq.type = v1;
sa->addr.nameseq.lower = v2;
sa->addr.nameseq.upper = v3;
} else if (atype == TIPC_ADDR_NAME) {
sa->addr.name.name.type = v1;
sa->addr.name.name.instance = v2;
} else if (atype == TIPC_ADDR_ID) {
sa->addr.id.node = v1;
sa->addr.id.ref = v2;
} else {
/* Shouldn't happen */
PyErr_SetString(PyExc_TypeError, "Invalid address type");
return 0;
}
return 1;
}
static PyObject *sa_to_tuple(const struct sockaddr_tipc *sa)
{
if (sa->addrtype == TIPC_ADDR_NAMESEQ) {
return Py_BuildValue("IIIII",
sa->addrtype,
sa->addr.nameseq.type,
sa->addr.nameseq.lower,
sa->addr.nameseq.upper,
sa->scope);
} else if (sa->addrtype == TIPC_ADDR_NAME) {
return Py_BuildValue("IIIII",
sa->addrtype,
sa->addr.name.name.type,
sa->addr.name.name.instance,
sa->addr.name.name.instance,
sa->scope);
} else if (sa->addrtype == TIPC_ADDR_ID) {
return Py_BuildValue("IIIII",
sa->addrtype,
sa->addr.id.node,
sa->addr.id.ref,
0,
sa->scope);
} else {
/* Shouldn't happen */
PyErr_SetString(PyExc_TypeError, "Invalid address type");
return NULL;
}
}
/*
* Exported functions
*/
static PyObject *tipc_socket(PyObject *self, PyObject *args)
{
int fd, stype;
if (!PyArg_ParseTuple(args, "i:tipc_socket", &stype)) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS
fd = socket(AF_TIPC, stype, 0);
Py_END_ALLOW_THREADS
if (fd < 0)
return PyErr_SetFromErrno(PyExc_IOError);
return PyLong_FromLong(fd);
}
static PyObject *tipc_bind(PyObject *self, PyObject *args)
{
int fd, rv;
struct sockaddr_tipc sa;
PyObject *addr;
if (!PyArg_ParseTuple(args, "iO:tipc_bind", &fd, &addr))
return NULL;
if (!fill_sockaddr(&sa, addr))
return NULL;
Py_BEGIN_ALLOW_THREADS
rv = bind(fd, (struct sockaddr *) &sa, sizeof(sa));
Py_END_ALLOW_THREADS
if (rv < 0)
return PyErr_SetFromErrno(PyExc_IOError);
return PyLong_FromLong(rv);
}
static PyObject *tipc_connect(PyObject *self, PyObject *args)
{
int fd, rv;
struct sockaddr_tipc sa;
PyObject *addr;
if (!PyArg_ParseTuple(args, "iO:tipc_connect", &fd, &addr))
return NULL;
if (!fill_sockaddr(&sa, addr))
return NULL;
Py_BEGIN_ALLOW_THREADS
rv = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
Py_END_ALLOW_THREADS
if (rv < 0)
return PyErr_SetFromErrno(PyExc_IOError);
return PyLong_FromLong(rv);
}
static PyObject *tipc_accept(PyObject *self, PyObject *args)
{
int fd, newfd;
struct sockaddr_tipc sa;
socklen_t salen = sizeof(sa);
if (!PyArg_ParseTuple(args, "i:tipc_accept", &fd)) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS
newfd = accept(fd, (struct sockaddr *) &sa, &salen);
Py_END_ALLOW_THREADS
if (newfd < 0)
return PyErr_SetFromErrno(PyExc_IOError);
return Py_BuildValue("iN", newfd, sa_to_tuple(&sa));
}
static PyObject *tipc_sendto(PyObject *self, PyObject *args)
{
int fd, rv;
char *buf;
ssize_t len = 0;
struct sockaddr_tipc sa;
PyObject *addr;
if (!PyArg_ParseTuple(args, "is#O:tipc_sendto", &fd, &buf, &len, &addr))
return NULL;
if (!fill_sockaddr(&sa, addr))
return NULL;
Py_BEGIN_ALLOW_THREADS
rv = sendto(fd, buf, len, 0, (struct sockaddr *) &sa, sizeof(sa));
Py_END_ALLOW_THREADS
if (rv < 0)
return PyErr_SetFromErrno(PyExc_IOError);
return PyLong_FromLong(rv);
}
static PyObject *tipc_recvfrom(PyObject *self, PyObject *args)
{
int fd;
char *buf;
size_t maxlen = 0;
struct sockaddr_tipc sa;
socklen_t salen = sizeof(sa);
int rv;
PyObject *str;
if (!PyArg_ParseTuple(args, "iI:tipc_recvfrom", &fd, &maxlen)) {
return NULL;
}
buf = malloc(maxlen);
if (buf == NULL)
return PyErr_NoMemory();
Py_BEGIN_ALLOW_THREADS
rv = recvfrom(fd, buf, maxlen, 0,
(struct sockaddr *) &sa, &salen);
Py_END_ALLOW_THREADS
if (rv < 0) {
free(buf);
return PyErr_SetFromErrno(PyExc_IOError);
}
str = PyString_FromStringAndSize(buf, rv);
free(buf);
return Py_BuildValue("NN", str, sa_to_tuple(&sa));
}
static PyObject *tipc_getsockname(PyObject *self, PyObject *args)
{
int fd, rv;
struct sockaddr_tipc sa;
socklen_t salen = sizeof(sa);
if (!PyArg_ParseTuple(args, "i:tipc_getsockname", &fd))
return NULL;
rv = getsockname(fd, (struct sockaddr *) &sa, &salen);
return Py_BuildValue("N", sa_to_tuple(&sa));
}
static PyObject *tipc_build_subscr(PyObject *self, PyObject *args)
{
int stype, lower, upper;
uint32_t timeout, filter;
struct tipc_subscr subs;
if (!PyArg_ParseTuple(args, "IIIII:tipc_build_subscr",
&stype, &lower, &upper, &timeout, &filter)) {
return NULL;
}
subs.seq.type = stype;
subs.seq.lower = lower;
subs.seq.upper = upper;
subs.timeout = timeout;
subs.filter = filter;
return PyString_FromStringAndSize((char *) &subs,
sizeof(subs));
}
static PyObject *tipc_parse_event(PyObject *self, PyObject *args)
{
unsigned char *buf;
ssize_t len = 0;
struct tipc_event *event;
if (!PyArg_ParseTuple(args, "s#:tipc_parse_event",
&buf, &len)) {
return NULL;
}
/* Return None if the buffer looks strange */
if (len < sizeof(event))
return Py_BuildValue("");
event = (struct tipc_event *) buf;
return Py_BuildValue("III(IIIII)",
event->event,
event->found_lower,
event->found_upper,
event->s.seq.type,
event->s.seq.lower,
event->s.seq.upper,
event->s.timeout,
event->s.filter);
}
static PyMethodDef pytipc_functions[] = {
{ "socket", (PyCFunction) tipc_socket, METH_VARARGS, NULL },
{ "bind", (PyCFunction) tipc_bind, METH_VARARGS, NULL },
{ "connect", (PyCFunction) tipc_connect, METH_VARARGS, NULL },
{ "accept", (PyCFunction) tipc_accept, METH_VARARGS, NULL },
{ "sendto", (PyCFunction) tipc_sendto, METH_VARARGS, NULL },
{ "recvfrom", (PyCFunction) tipc_recvfrom, METH_VARARGS, NULL },
{ "build_subscr", (PyCFunction) tipc_build_subscr, METH_VARARGS, NULL },
{ "parse_event", (PyCFunction) tipc_parse_event, METH_VARARGS, NULL },
{ "getsockname", (PyCFunction) tipc_getsockname, METH_VARARGS, NULL },
{ NULL }
};
PyMODINIT_FUNC inittipc_ll(void)
{
PyObject *m;
m = Py_InitModule("tipc_ll", pytipc_functions);
PyModule_AddIntConstant(m, "AF_TIPC", AF_TIPC);
/* for addresses */
PyModule_AddIntConstant(m, "TIPC_ADDR_NAMESEQ", TIPC_ADDR_NAMESEQ);
PyModule_AddIntConstant(m, "TIPC_ADDR_NAME", TIPC_ADDR_NAME);
PyModule_AddIntConstant(m, "TIPC_ADDR_ID", TIPC_ADDR_ID);
PyModule_AddIntConstant(m, "TIPC_ZONE_SCOPE", TIPC_ZONE_SCOPE);
PyModule_AddIntConstant(m, "TIPC_CLUSTER_SCOPE", TIPC_CLUSTER_SCOPE);
PyModule_AddIntConstant(m, "TIPC_NODE_SCOPE", TIPC_NODE_SCOPE);
/* for setsockopt() */
PyModule_AddIntConstant(m, "SOL_TIPC", SOL_TIPC);
PyModule_AddIntConstant(m, "TIPC_IMPORTANCE", TIPC_IMPORTANCE);
PyModule_AddIntConstant(m, "TIPC_SRC_DROPPABLE", TIPC_SRC_DROPPABLE);
PyModule_AddIntConstant(m, "TIPC_DEST_DROPPABLE",
TIPC_DEST_DROPPABLE);
PyModule_AddIntConstant(m, "TIPC_CONN_TIMEOUT", TIPC_CONN_TIMEOUT);
PyModule_AddIntConstant(m, "TIPC_LOW_IMPORTANCE",
TIPC_LOW_IMPORTANCE);
PyModule_AddIntConstant(m, "TIPC_MEDIUM_IMPORTANCE",
TIPC_MEDIUM_IMPORTANCE);
PyModule_AddIntConstant(m, "TIPC_HIGH_IMPORTANCE",
TIPC_HIGH_IMPORTANCE);
PyModule_AddIntConstant(m, "TIPC_CRITICAL_IMPORTANCE",
TIPC_CRITICAL_IMPORTANCE);
/* for subscriptions */
PyModule_AddIntConstant(m, "TIPC_SUB_PORTS", TIPC_SUB_PORTS);
PyModule_AddIntConstant(m, "TIPC_SUB_SERVICE", TIPC_SUB_SERVICE);
PyModule_AddIntConstant(m, "TIPC_SUB_CANCEL", TIPC_SUB_CANCEL);
PyModule_AddIntConstant(m, "TIPC_WAIT_FOREVER", TIPC_WAIT_FOREVER);
PyModule_AddIntConstant(m, "TIPC_PUBLISHED", TIPC_PUBLISHED);
PyModule_AddIntConstant(m, "TIPC_WITHDRAWN", TIPC_WITHDRAWN);
PyModule_AddIntConstant(m, "TIPC_SUBSCR_TIMEOUT", TIPC_SUBSCR_TIMEOUT);
PyModule_AddIntConstant(m, "TIPC_CFG_SRV", TIPC_CFG_SRV);
PyModule_AddIntConstant(m, "TIPC_TOP_SRV", TIPC_TOP_SRV);
}