git » pytipc » commit 19270d1

Initial commit.

author Alberto Bertogli
2007-12-14 15:40:06 UTC
committer Alberto Bertogli
2007-12-14 15:40:40 UTC

Initial commit.

Signed-off-by: Alberto Bertogli <albertito@gmail.com>

.gitignore +4 -0
setup.py +16 -0
tipc.py +210 -0
tipc_ll.c +317 -0

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..898aef0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+build
+*.pyc
+*.pyo
+
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..a4e4f2a
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+from distutils.core import setup, Extension
+
+tipc_ll = Extension("tipc_ll", sources = ['tipc_ll.c'])
+
+setup(
+	name = 'tipc',
+	description = "TIPC bindings",
+	author = "Alberto Bertogli",
+	author_email = "albertito@gmail.com",
+	url = "http://auriga.wearlab.de/~alb/pytipc",
+	py_modules = ['tipc'],
+	ext_modules = [tipc_ll]
+)
+
diff --git a/tipc.py b/tipc.py
new file mode 100644
index 0000000..0924a1e
--- /dev/null
+++ b/tipc.py
@@ -0,0 +1,210 @@
+
+"""
+TIPC python wrapper
+Alberto Bertogli (albertito@gmail.com)
+
+
+Addresses are expressed as (addr_type, srv_type, lower, upper); where
+addr_type can be either TIPC_ADDR_NAME or TIPC_ADDR_NAMESEQ.
+
+If addr_type is TIPC_ADDR_NAME, then the "upper" parameter is not used (but
+should be set to an int anyway).
+"""
+
+import os
+import socket as socketmodule
+import tipc_ll
+
+# Exported constants
+from tipc_ll import AF_TIPC, SOL_TIPC, \
+	TIPC_ADDR_NAME, TIPC_ADDR_NAMESEQ, \
+	TIPC_IMPORTANCE, \
+	TIPC_SRC_DROPPABLE, TIPC_DEST_DROPPABLE, \
+	TIPC_CONN_TIMEOUT, \
+	TIPC_LOW_IMPORTANCE, TIPC_MEDIUM_IMPORTANCE, \
+	TIPC_HIGH_IMPORTANCE, TIPC_CRITICAL_IMPORTANCE, \
+	TIPC_SUB_PORTS, TIPC_SUB_SERVICE, TIPC_SUB_CANCEL, \
+	TIPC_WAIT_FOREVER, \
+	TIPC_PUBLISHED, TIPC_WITHDRAWN, TIPC_SUBSCR_TIMEOUT, \
+	TIPC_CFG_SRV, TIPC_TOP_SRV
+
+
+class TIPCSocket:
+	def __init__(self, stype, fd = None):
+		if not fd:
+			self.fd = tipc_ll.socket(stype)
+		else:
+			self.fd = fd
+
+		self.closed = 0
+		self.psock = socketmodule.fromfd(self.fd, AF_TIPC, stype)
+
+		self.family = AF_TIPC
+		self.type = stype
+		self.proto = 0
+
+	def __del__(self):
+		self.close()
+
+
+	# Friendly functions for the ones implemented in tipc_ll
+
+	def connect(self, addr):
+		"Connects to the given server."
+		return tipc_ll.connect(self.fd, addr)
+
+	def bind(self, addr):
+		"Binds to the given address."
+		return tipc_ll.bind(self.fd, addr)
+
+	def accept(self):
+		"Accepts a new connection, returns (conn, addr)."
+		newfd, addr = tipc_ll.accept(self.fd)
+		return (TIPCSocket(self.type, fd = newfd), addr)
+
+	def sendto(self, buf, addr):
+		"Sends a message/buffer to the given address."
+		return tipc_ll.sendto(self.fd, buf, addr)
+
+	def recvfrom(self, maxlen = 64 * 1024):
+		"Receives a message/buffer, returns (buffer, address)."
+		return tipc_ll.recvfrom(self.fd, maxlen)
+
+	def close(self):
+		"Closes the socket."
+		if not self.closed:
+			self.closed = 1
+			return os.close(self.fd)
+
+
+	# Other useful functions, some of them based on socketmodule
+
+	def fileno(self):
+		"Returns the file descriptor number."
+		return self.fd
+
+	def send(self, buf):
+		"Sends a message/buffer."
+		self.psock.send(buf)
+
+	def recv(self, bufsize):
+		"Receives a message/buffer."
+		b, a = self.recvfrom(bufsize)
+		return b
+
+	def listen(self, backlog):
+		"Listen for connections made to the socket."
+		return self.psock.listen(backlog)
+
+	def setblocking(self, flag):
+		"Set blocking or non-blocking mode for the socket."
+		return self.psock.setblocking(flag)
+
+	def getsockopt(self, level, optname, buflen = None):
+		"""Return the value of the given socket option (see the Unix
+		man page getsockopt(2))."""
+		if not buflen:
+			return self.psock.getsockopt(level, optname)
+		return self.psock.getsockopt(level, optname, buflen)
+
+	def setsockopt(self, level, optname, value):
+		"""Set the value of the given socket option (see the Unix
+		manual page setsockopt(2))"""
+		return self.psock.setsockopt(level, optname, value)
+
+	def shutdown(self, how):
+		"Shut down one or both halves of the connection."
+		return self.psock.shutdown(how)
+
+
+	# Subscription handling
+
+	def send_subscr(self, addr, timeout = None, filter = TIPC_SUB_SERVICE):
+		"""
+		Sends a subscription message to the server (the socket must
+		be connected to TIPC_ADDR_NAME, TIPC_TOP_SRV, TIPC_TOP_SRV, 0)
+		for this to work).
+		 - addr: specifies the address to wait for (can be a name or a
+		   nameseq).
+		 - timeout: timeout in milliseconds (use None to wait
+		   forever), defaults to None.
+		 - filter: Either TIPC_SUB_SERVICE or TIPC_SUB_PORTS, see TIPC
+		   documentation for details. Defaults to TIPC_SUB_SERVICE.
+		"""
+
+		if not timeout:
+			timeout = TIPC_WAIT_FOREVER
+
+		atype, stype, lower, upper = addr
+		subs = tipc_ll.build_subscr(stype, lower, upper,
+				timeout, filter)
+		self.send(subs)
+
+	def recv_subscr_event(self):
+		"""
+		Receives a subscription event from the socket.
+
+		It returns None if there was an error receiving the
+		subscription, or the tuple:
+		 ( event, found_lower, found_upper,
+		   (srv_type, lower, upper, timeout, filter) )
+
+		- event: one of TIPC_SUBSCR_TIMEOUT, TIPC_PUBLISHED or
+		  TIPC_WITHDRAWN.
+		- found_lower, found_upper: the lower and upper ports found.
+		- (srv_type, lower, upper, timeout, filter): information on
+		  the subscription that generated the event (see send_subscr()
+		  for details).
+		"""
+		buf = self.recv(4092)
+		return tipc_ll.parse_event(buf)
+
+
+def socket(stype):
+	"""
+	Creates and returns a socket object of the given type.
+
+	The type can be one of SOCK_RDM, SOCK_SEQPACKET, SOCK_STREAM and
+	SOCK_DGRAM, see TIPC documentation for more information.
+	"""
+	return TIPCSocket(stype)
+
+
+def wait_for(addr, timeout = None, filter = None):
+	"""
+	Waits for a server to appear on the given address.
+
+	If a timeout is specified and no server came up after that number of
+	milliseconds, returns None.
+	The optional filter parameter can be either TIPC_SUB_SERVICE or
+	TIPC_SUB_PORTS, see TIPC documentation for more details; it defaults
+	to TIPC_SUB_SERVICE.
+
+	If there are any errors, return None; otherwise return an event tuple
+	composed of:
+	 ( event, found_lower, found_upper,
+	   (srv_type, lower, upper, timeout, filter) )
+
+	- event: one of TIPC_SUBSCR_TIMEOUT, TIPC_PUBLISHED or
+	  TIPC_WITHDRAWN.
+	- found_lower, found_upper: the lower and upper ports found.
+	- (srv_type, lower, upper, timeout, filter): information on
+	  the subscription that generated the event (see send_subscr()
+	  for details).
+	"""
+
+	fd = socket(socketmodule.SOCK_SEQPACKET)
+
+	if not timeout:
+		timeout = TIPC_WAIT_FOREVER
+	if not filter:
+		filter = TIPC_SUB_SERVICE
+
+	topsrv_addr = (TIPC_ADDR_NAME, TIPC_TOP_SRV,
+			TIPC_TOP_SRV, TIPC_TOP_SRV)
+	fd.connect(topsrv_addr)
+
+	fd.send_subscr(addr, timeout, filter)
+	return fd.recv_subscr_event()
+
+
diff --git a/tipc_ll.c b/tipc_ll.c
new file mode 100644
index 0000000..f7dcff0
--- /dev/null
+++ b/tipc_ll.c
@@ -0,0 +1,317 @@
+
+/*
+ * 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 void fill_sockaddr(struct sockaddr_tipc *sa,
+		int atype, int stype, int lower, int upper)
+{
+	memset(sa, 0, sizeof(struct sockaddr_tipc));
+
+	sa->family = AF_TIPC;
+	sa->scope = TIPC_CLUSTER_SCOPE;
+
+	if (atype == TIPC_ADDR_NAME) {
+		sa->addrtype = TIPC_ADDR_NAME;
+		sa->addr.name.name.type = stype;
+		sa->addr.name.name.instance = lower;
+	} else {
+		sa->addrtype = TIPC_ADDR_NAMESEQ;
+		sa->addr.nameseq.type = stype;
+		sa->addr.nameseq.lower = lower;
+		sa->addr.nameseq.upper = upper;
+	}
+	return;
+}
+
+static PyObject *sa_to_tuple(const struct sockaddr_tipc *sa)
+{
+	if (sa->addrtype == TIPC_ADDR_NAMESEQ) {
+		return Py_BuildValue("iiii",
+				sa->addrtype,
+				sa->addr.nameseq.type,
+				sa->addr.nameseq.lower,
+				sa->addr.nameseq.upper);
+	} else {
+		return Py_BuildValue("iiii",
+				sa->addrtype,
+				sa->addr.name.name.type,
+				sa->addr.name.name.instance,
+				sa->addr.name.name.instance);
+	}
+}
+
+
+/*
+ * 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, atype, stype, lower, upper;
+	struct sockaddr_tipc sa;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "i(iiii):tipc_bind",
+				&fd, &atype, &stype, &lower, &upper)) {
+		return NULL;
+	}
+
+	fill_sockaddr(&sa, atype, stype, lower, upper);
+
+	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, atype, stype, lower, upper;
+	struct sockaddr_tipc sa;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "i(iiii):tipc_connect",
+				&fd, &atype, &stype, &lower, &upper)) {
+		return NULL;
+	}
+
+	fill_sockaddr(&sa, atype, stype, lower, upper);
+
+	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("iO", newfd, sa_to_tuple(&sa));
+}
+
+
+static PyObject *tipc_sendto(PyObject *self, PyObject *args)
+{
+	int fd, atype, stype, lower, upper;
+	char *buf;
+	size_t len;
+	struct sockaddr_tipc sa;
+	int rv;
+
+	if (!PyArg_ParseTuple(args, "is#(iiii):tipc_sendto",
+				&fd, &buf, &len,
+				&atype, &stype, &lower, &upper)) {
+		return NULL;
+	}
+
+	fill_sockaddr(&sa, atype, stype, lower, upper);
+
+	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;
+	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)
+		return PyErr_SetFromErrno(PyExc_IOError);
+
+	str = PyString_FromStringAndSize(buf, rv);
+	free(buf);
+
+	return Py_BuildValue("OO", str, 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;
+	size_t len;
+	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 },
+	{ 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_NAME", TIPC_ADDR_NAME);
+	PyModule_AddIntConstant(m, "TIPC_ADDR_NAMESEQ", TIPC_ADDR_NAMESEQ);
+
+	/* 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);
+}
+
+