1#!/usr/bin/env python2.7
2
3import ctypes
4import collections
5
6from ctypes import CDLL, CFUNCTYPE, POINTER, cast, py_object
7from ctypes import c_char_p, c_void_p, c_int, pointer
8
9_qrtr = CDLL("./libqrtr.so")
10
11class qrtr:
12    Result = collections.namedtuple('Result', ['service', 'instance', 'addr'])
13    _cbtype = CFUNCTYPE(None, c_void_p, c_int, c_int, c_int, c_int)
14    def __init__(self, port=0):
15        self.sock = _qrtr.qrtr_open(port)
16        if self.sock < 0:
17            raise RuntimeError("unable to open qrtr socket")
18        self.service = None
19        self._qrtr = _qrtr
20
21    def __del__(self):
22        self._qrtr.qrtr_close(self.sock)
23
24    def _lookup_list_add(self, ptr, srv, instance, node, port):
25        res = qrtr.Result(srv, instance, (node, port))
26        cast(ptr, POINTER(py_object)).contents.value.append(res)
27
28    def lookup(self, srv, instance=0, ifilter=0):
29        results = []
30        err = _qrtr.qrtr_lookup(self.sock, srv, instance, ifilter,
31                qrtr._cbtype(self._lookup_list_add), cast(pointer(py_object(results)), c_void_p))
32        if err:
33            raise RuntimeError("query failed")
34        return results
35
36    def publish(self, service, version, instance):
37        err = _qrtr.qrtr_publish(self.sock, service, version, instance)
38        if err:
39            raise RuntimeError("publish failed")
40        self.service = (service, version, instance)
41
42    def new_server(self, service, version, instance):
43        err = _qrtr.qrtr_new_server(self.sock, service, version, instance)
44        if err:
45            raise RuntimeError("new_server failed")
46        self.service = (service, version, instance)
47
48        return self.service
49
50    def remove_server(self, service):
51        err = _qrtr.qrtr_remove_server(self.sock, *service)
52        if err:
53            raise RuntimeError("remove_server failed")
54        self.service = None
55
56    def new_lookup(self, service, version, instance):
57        err = _qrtr.qrtr_new_lookup(self.sock, service, version, instance)
58        if err:
59            raise RuntimeError("new_lookup failed")
60        return (service, version, instance)
61
62    def remove_lookup(self, lookup):
63        err = _qrtr.qrtr_remove_lookup(self.sock, *lookup)
64        if err:
65            raise RuntimeError("remove_lookup failed")
66
67    def send(self, addr, data):
68        node, port = addr
69        n = _qrtr.qrtr_sendto(self.sock, node, port, c_char_p(data), len(data))
70        if n:
71            raise RuntimeError("sendto failed")
72
73    def recv(self, sz=65536):
74        buf = ctypes.create_string_buffer(sz)
75        n = _qrtr.qrtr_recv(self.sock, c_char_p(ctypes.addressof(buf)), sz)
76        if n <= 0:
77            raise RuntimeError("recv failed")
78        return buf[0:n]
79
80    def recvfrom(self, sz=65536):
81        node = ctypes.c_int()
82        port = ctypes.c_int()
83        buf = ctypes.create_string_buffer(sz)
84        n = _qrtr.qrtr_recvfrom(self.sock, c_char_p(ctypes.addressof(buf)),
85                ctypes.byref(node), ctypes.byref(port))
86        if n <= 0:
87            raise RuntimeError("recvfrom failed")
88        return (buf[0:n], (node.value, port.value))
89
90    def poll(self, tout=0):
91        return _qrtr.qrtr_poll(self.sock, tout)
92
93if __name__ == "__main__":
94    svcs = qrtr().lookup(15) # 15 is the test service
95    print " service  instance  addr"
96    for svc in svcs:
97        print "% 8d  % 8d  %s" % (svc.service, svc.instance, svc.addr)
98