def Server(cmdch, brdch): try: ipr = IPRoute() lock = ipr._sproxy.lock ipr._s_channel = brdch poll = select.poll() poll.register(ipr, select.POLLIN | select.POLLPRI) poll.register(cmdch, select.POLLIN | select.POLLPRI) except Exception as e: cmdch.send({'stage': 'init', 'error': e}) return 255 # all is OK so far cmdch.send({'stage': 'init', 'error': None}) # 8<------------------------------------------------------------- while True: events = poll.poll() for (fd, event) in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with lock: brdch.send({ 'stage': 'broadcast', 'data': ipr.recv(bufsize) }) elif fd == cmdch.fileno(): cmd = cmdch.recv() if cmd['stage'] == 'shutdown': poll.unregister(ipr) poll.unregister(cmdch) ipr.close() return elif cmd['stage'] == 'command': error = None try: ret = getattr(ipr, cmd['name'])(*cmd['argv'], **cmd['kwarg']) except Exception as e: error = e error.tb = traceback.format_exc() cmdch.send({ 'stage': 'command', 'error': error, 'return': ret, 'cookie': cmd['cookie'] })
def Server(cmdch, brdch): try: ipr = IPRoute() lock = ipr._sproxy.lock ipr._s_channel = brdch poll = select.poll() poll.register(ipr, select.POLLIN | select.POLLPRI) poll.register(cmdch, select.POLLIN | select.POLLPRI) except Exception as e: cmdch.send({'stage': 'init', 'error': e}) return 255 # all is OK so far cmdch.send({'stage': 'init', 'error': None}) # 8<------------------------------------------------------------- while True: events = poll.poll() for (fd, event) in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with lock: brdch.send({'stage': 'broadcast', 'data': ipr.recv(bufsize)}) elif fd == cmdch.fileno(): cmd = cmdch.recv() if cmd['stage'] == 'shutdown': poll.unregister(ipr) poll.unregister(cmdch) ipr.close() return elif cmd['stage'] == 'command': error = None try: ret = getattr(ipr, cmd['name'])(*cmd['argv'], **cmd['kwarg']) except Exception as e: error = e error.tb = traceback.format_exc() cmdch.send({'stage': 'command', 'error': error, 'return': ret, 'cookie': cmd['cookie']})
def Server(cmdch, brdch): ''' A server routine to run an IPRoute object and expose it via custom RPC. many TODOs: * document the protocol * provide not only IPRoute RPC Messages sent via channels are dictionaries with predefined structure. There are 4 s.c. stages:: init (server <-----> client) command (server <-----> client) broadcast (server ------> client) shutdown (server <------ client) Stage 'init' is used during initialization. The client establishes connections to the server and announces them by sending a single message via each channel:: {'stage': 'init', 'domain': ch_domain, 'client': client.uuid} Here, the client uuid is used to group all the connections of the same client and `ch_domain` is either 'command', or 'broadcast'. The latter will become a unidirectional channel from the server to the client, all data that arrives on the server side via netlink socket will be forwarded to the broadcast channel. The command channel will be used to make RPC calls and to shut the worker thread down before the client disconnects from the server. When all the registration is done, the server sends a single message via the command channel:: {'stage': 'init', 'error': exception or None} If the `error` field is None, everything is ok. If it is an exception, the init is failed and the exception should be thrown on the client side. In the runtime, all the data that arrives on the netlink socket fd, is to be forwarded directly via the broadcast channel. Commands are handled with the `command` stage:: # request {'stage': 'command', 'name': str, 'cookie': cookie, 'argv': [...], 'kwarg': {...}} # response {'stage': 'command', 'error': exception or None, 'return': retval, 'cookie': cookie} Right now the protocol is synchronous, so there is not need in cookie yet. But in some future it can turn into async, and then cookies will be used to match messages. The final stage is 'shutdown'. It terminates the worker thread, has no response and no messages can passed after. ''' def close(s, frame): # just leave everything else as is brdch.send({'stage': 'signal', 'data': s}) try: ipr = IPRoute() lock = ipr._sproxy.lock ipr._s_channel = ProxyChannel(brdch, 'broadcast') poll = select.poll() poll.register(ipr, select.POLLIN | select.POLLPRI) poll.register(cmdch, select.POLLIN | select.POLLPRI) except Exception as e: cmdch.send({'stage': 'init', 'error': e}) return 255 # all is OK so far cmdch.send({'stage': 'init', 'error': None}) signal.signal(signal.SIGHUP, close) signal.signal(signal.SIGINT, close) signal.signal(signal.SIGTERM, close) # 8<------------------------------------------------------------- while True: try: events = poll.poll() except: continue for (fd, event) in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with lock: error = None data = None try: data = ipr.recv(bufsize) except Exception as e: error = e error.tb = traceback.format_exc() brdch.send({'stage': 'broadcast', 'data': data, 'error': error}) elif fd == cmdch.fileno(): cmd = cmdch.recv() if cmd['stage'] == 'shutdown': poll.unregister(ipr) poll.unregister(cmdch) ipr.close() return elif cmd['stage'] == 'reconstruct': error = None try: msg = cmd['argv'][0]() msg.load(pickle.loads(cmd['argv'][1])) msg.encode() ipr.sendto_gate(msg, cmd['argv'][2]) except Exception as e: error = e error.tb = traceback.format_exc() cmdch.send({'stage': 'reconstruct', 'error': error, 'return': None, 'cookie': cmd['cookie']}) elif cmd['stage'] == 'command': error = None try: ret = getattr(ipr, cmd['name'])(*cmd['argv'], **cmd['kwarg']) except Exception as e: error = e error.tb = traceback.format_exc() cmdch.send({'stage': 'command', 'error': error, 'return': ret, 'cookie': cmd['cookie']})
def Server(trnsp_in, trnsp_out): try: ipr = IPRoute() lock = ipr._sproxy.lock ipr._s_channel = ProxyChannel(trnsp_out, 'broadcast') except Exception as e: trnsp_out.send({'stage': 'init', 'error': e}) return 255 inputs = [ipr.fileno(), trnsp_in.fileno()] outputs = [] # all is OK so far trnsp_out.send({'stage': 'init', 'error': None}) # 8<------------------------------------------------------------- while True: try: events, _, _ = select.select(inputs, outputs, inputs) except: continue for fd in events: if fd == ipr.fileno(): bufsize = ipr.getsockopt(SOL_SOCKET, SO_RCVBUF) // 2 with lock: error = None data = None try: data = ipr.recv(bufsize) except Exception as e: error = e error.tb = traceback.format_exc() trnsp_out.send({ 'stage': 'broadcast', 'data': data, 'error': error }) elif fd == trnsp_in.fileno(): cmd = trnsp_in.recv_cmd() if cmd['stage'] == 'shutdown': ipr.close() return elif cmd['stage'] == 'reconstruct': error = None try: msg = cmd['argv'][0]() msg.load(pickle.loads(cmd['argv'][1])) msg.encode() ipr.sendto_gate(msg, cmd['argv'][2]) except Exception as e: error = e error.tb = traceback.format_exc() trnsp_out.send({ 'stage': 'reconstruct', 'error': error, 'return': None, 'cookie': cmd['cookie'] }) elif cmd['stage'] == 'command': error = None try: ret = getattr(ipr, cmd['name'])(*cmd['argv'], **cmd['kwarg']) except Exception as e: ret = None error = e error.tb = traceback.format_exc() trnsp_out.send({ 'stage': 'command', 'error': error, 'return': ret, 'cookie': cmd['cookie'] })
from socket import socket from socket import AF_INET from socket import SOCK_STREAM from socket import SOL_SOCKET from socket import SO_REUSEADDR ip = IPRoute() ## # pr = socket(AF_INET, SOCK_STREAM) pr.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) pr.bind(('127.0.0.1', 4011)) pr.listen(1) (client, addr) = pr.accept() ip._s_channel = client ## # poll = select.poll() poll.register(client, select.POLLIN | select.POLLPRI) poll.register(ip, select.POLLIN | select.POLLPRI) while True: events = poll.poll() for (fd, event) in events: if fd == client.fileno(): try: ip.sendto(client.recv(16384), (0, 0)) except: sys.exit(0)