#!/usr/bin/env python #coding=utf8 import ssl import time import socket import select from sjrpc.core import RpcConnection, ConnectionManager class SimpleRpcServer(ConnectionManager): ''' A simple RPC Server that wait for new connections and dispatch messages from thoses are already established. :param sock: the :class:`socket` object to bind to the server connection :param default_handler: the default handler to bind to the new client connections ''' def __init__(self, sock, default_handler=None, on_disconnect=None): super(SimpleRpcServer, self).__init__() sock.setblocking(False) self._listening_sock = sock self._poll.register(sock) self._clients = {} self._default_handler = default_handler self._on_disconnect = on_disconnect def _accept_connection(self): return self._listening_sock.accept() def register(self, connection): super(SimpleRpcServer, self).register(connection) self._clients[connection.get_fd()] = connection def shutdown(self): super(SimpleRpcServer, self).shutdown() time.sleep(ConnectionManager.POLL_TIMEOUT) for connection in self._clients.values(): connection.shutdown(self._on_disconnect) self._listening_sock.close() def all_connections(self): return set(self._clients.values()) def handle_event(self, fd, event): if fd == self._listening_sock.fileno(): # Event concerns the listening socket: if event & select.EPOLLIN: sock, address = self._accept_connection() sock.setblocking(False) connection = RpcConnection(sock, self, handler=self._default_handler) self.register(connection) else: # Event concerns a client socket: connection = self._clients[fd] if event & select.EPOLLIN: # Data are ready to be readed on socket try: connection.receive() except socket.error as err: connection.shutdown(self._on_disconnect) del self._clients[fd] if event & select.EPOLLOUT: # Data are ready to be written on socket try: connection.send() except socket.error as err: connection.shutdown(self._on_disconnect) del self._clients[fd] if event & select.EPOLLHUP: connection.shutdown(self._on_disconnect) del self._clients[fd] class SimpleSslRpcServer(SimpleRpcServer): ''' A simple RPC Server that wait for new connections and dispatch messages from thoses are already established. This server version enable SSL on client sockets. :param sock: the :class:`socket` object to bind to the server connection :param default_handler: the default handler to bind to the new client connections ''' def __init__(self, sock, certfile=None, keyfile=None, **kwargs): self._certfile = certfile self._keyfile = keyfile super(SimpleSslRpcServer, self).__init__(sock, **kwargs) def _accept_connection(self): sock, address = self._listening_sock.accept() sslsock = ssl.wrap_socket(sock, server_side=True, keyfile=self._keyfile, certfile=self._certfile, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=True) return sslsock, address