author | Alberto Bertogli
<abertogli@integratech.com.ar> 2007-12-14 15:40:06 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-12-14 15:40:40 UTC |
.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); +} + +