git » pytipc » master » tree

[master] / tipc_ll.c

/*
 * 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);
}