def testMsgWaitallProblems2(self): class ReceiveThread(threadutil.Thread): def __init__(self, sock, sizes): super(ReceiveThread, self).__init__() self.sock = sock self.sizes = sizes def run(self): cs, _ = self.sock.accept() for size in self.sizes: data = SU.receiveData(cs, size) SU.sendData(cs, data) cs.close() ss = SU.createSocket(bind=("localhost", 0)) SIZES = [ 1000, 10000, 32000, 32768, 32780, 41950, 41952, 42000, 65000, 65535, 65600, 80000, 999999 ] serverthread = ReceiveThread(ss, SIZES) serverthread.setDaemon(True) serverthread.start() port = ss.getsockname()[1] cs = SU.createSocket(connect=("localhost", port), timeout=2) # test some sizes that might be problematic with MSG_WAITALL and check that they work fine for size in SIZES: SU.sendData(cs, tobytes("x") * size) data = SU.receiveData(cs, size) self.assertEqual(size, len(data)) serverthread.join() ss.close() cs.close()
def testConnectCrash(self): serv_thread = TestServerDOS_multiplex.ServerThread( self.socket_server, ServerCallback_BrokenHandshake) serv_thread.start() time.sleep(0.2) self.assertTrue(serv_thread.is_alive(), "server thread failed to start") try: host, port = serv_thread.locationStr.split(':') port = int(port) try: # first connection attempt (will fail because server daemon _handshake crashes) csock = SU.createSocket(connect=(host, port)) conn = SU.SocketConnection(csock, "uri") Pyro4.message.Message.recv(conn, [Pyro4.message.MSG_CONNECTOK]) except errors.ConnectionClosedError: pass conn.close() try: # second connection attempt, should still work (i.e. server should still be running) csock = SU.createSocket(connect=(host, port)) conn = SU.SocketConnection(csock, "uri") Pyro4.message.Message.recv(conn, [Pyro4.message.MSG_CONNECTOK]) except errors.ConnectionClosedError: pass finally: conn.close() serv_thread.stop_loop.set() serv_thread.join()
def testSend(self): ss = SU.createSocket(bind=("localhost", 0)) port = ss.getsockname()[1] cs = SU.createSocket(connect=("localhost", port)) SU.sendData(cs, tobytes("foobar!") * 10) cs.shutdown(socket.SHUT_WR) a = ss.accept() data = SU.receiveData(a[0], 5) self.assertEqual(tobytes("fooba"), data) data = SU.receiveData(a[0], 5) self.assertEqual(tobytes("r!foo"), data) a[0].close() ss.close() cs.close()
def testMsgWaitallProblems(self): ss = SU.createSocket(bind=("localhost", 0), timeout=2) port = ss.getsockname()[1] cs = SU.createSocket(connect=("localhost", port), timeout=2) a = ss.accept() # test some sizes that might be problematic with MSG_WAITALL and check that they work fine for size in [1000, 10000, 32000, 32768, 32780, 41950, 41952, 42000, 65000, 65535, 65600, 80000]: SU.sendData(cs, tobytes("x") * size) data = SU.receiveData(a[0], size) SU.sendData(a[0], data) data = SU.receiveData(cs, size) self.assertEqual(size, len(data)) a[0].close() ss.close() cs.close()
def testSendUnix(self): SOCKNAME = "test_unixsocket" ss = SU.createSocket(bind=SOCKNAME) cs = SU.createSocket(connect=SOCKNAME) SU.sendData(cs, tobytes("foobar!") * 10) cs.shutdown(socket.SHUT_WR) a = ss.accept() data = SU.receiveData(a[0], 5) self.assertEqual(tobytes("fooba"), data) data = SU.receiveData(a[0], 5) self.assertEqual(tobytes("r!foo"), data) a[0].close() ss.close() cs.close() if os.path.exists(SOCKNAME): os.remove(SOCKNAME)
def connect(host, port): # connect to the server csock = SU.createSocket(connect=(host, port)) conn = SU.SocketConnection(csock, "uri") # get the handshake/connect response Pyro4.message.Message.recv(conn, [Pyro4.message.MSG_CONNECTOK]) return conn
def init(self, daemon, host, port, unixsocket=None): log.info("starting multiplexed socketserver") log.debug("selector implementation: " + self.selector.__class__.__name__) self.sock = None bind_location = unixsocket if unixsocket else (host, port) self.sock = socketutil.createSocket(bind=bind_location, reuseaddr=Pyro4.config.SOCK_REUSE, timeout=Pyro4.config.COMMTIMEOUT, noinherit=True, nodelay=Pyro4.config.SOCK_NODELAY) self.daemon = daemon self._socketaddr = sockaddr = self.sock.getsockname() if not unixsocket and sockaddr[0].startswith("127."): if host is None or host.lower( ) != "localhost" and not host.startswith("127."): log.warning( "weird DNS setup: %s resolves to localhost (127.x.x.x)", host) if unixsocket: self.locationStr = "./u:" + unixsocket else: host = host or sockaddr[0] port = port or sockaddr[1] if ":" in host: # ipv6 self.locationStr = "[%s]:%d" % (host, port) else: self.locationStr = "%s:%d" % (host, port) self.selector.register(self.sock, selectors.EVENT_READ, self)
def run(self): while not self.stop: time.sleep(self.loop_delay) time_since_last_autoclean = time.time() - self.last_cleaned if time_since_last_autoclean < config.NS_AUTOCLEAN: continue for name, uri in self.nameserver.list().items(): if name in (constants.DAEMON_NAME, constants.NAMESERVER_NAME): continue try: uri_obj = core.URI(uri) timeout = config.COMMTIMEOUT or 5 sock = socketutil.createSocket(connect=(uri_obj.host, uri_obj.port), timeout=timeout) sock.close() # if we get here, the listed server is still answering on its port if name in self.unreachable: del self.unreachable[name] except socket.error: if name not in self.unreachable: self.unreachable[name] = time.time() if time.time() - self.unreachable[name] >= self.max_unreachable_time: log.info("autoclean: unregistering %s; cannot connect uri %s for %d sec", name, uri, self.max_unreachable_time) self.nameserver.remove(name) del self.unreachable[name] continue self.last_cleaned = time.time() if self.unreachable: log.debug("autoclean: %d/%d names currently unreachable", len(self.unreachable), self.nameserver.count())
def testContextAndSock(self): cert_dir = "../../certs" if not os.path.isdir(cert_dir): cert_dir = "../certs" if not os.path.isdir(cert_dir): cert_dir = "./certs" if not os.path.isdir(cert_dir): self.fail("cannot locate test certs directory") try: config.SSL = True config.SSL_REQUIRECLIENTCERT = True server_ctx = SU.getSSLcontext(cert_dir + "/server_cert.pem", cert_dir + "/server_key.pem") client_ctx = SU.getSSLcontext( clientcert=cert_dir + "/client_cert.pem", clientkey=cert_dir + "/client_key.pem") self.assertEqual(ssl.CERT_REQUIRED, server_ctx.verify_mode) self.assertEqual(ssl.CERT_REQUIRED, client_ctx.verify_mode) self.assertTrue(client_ctx.check_hostname) sock = SU.createSocket(sslContext=server_ctx) try: self.assertTrue(hasattr(sock, "getpeercert")) finally: sock.close() finally: config.SSL = False
def init(self, daemon, host, port, unixsocket=None): log.info("starting multiplexed socketserver") log.debug("selector implementation: %s.%s", self.selector.__class__.__module__, self.selector.__class__.__name__) self.sock = None bind_location = unixsocket if unixsocket else (host, port) if config.SSL: sslContext = socketutil.getSSLcontext(servercert=config.SSL_SERVERCERT, serverkey=config.SSL_SERVERKEY, keypassword=config.SSL_SERVERKEYPASSWD, cacerts=config.SSL_CACERTS) log.info("using SSL, cert=%s key=%s cacerts=%s", config.SSL_SERVERCERT, config.SSL_SERVERKEY, config.SSL_CACERTS) else: sslContext = None log.info("not using SSL") self.sock = socketutil.createSocket(bind=bind_location, reuseaddr=config.SOCK_REUSE, timeout=config.COMMTIMEOUT, noinherit=True, nodelay=config.SOCK_NODELAY, sslContext=sslContext) self.daemon = daemon self._socketaddr = sockaddr = self.sock.getsockname() if not unixsocket and sockaddr[0].startswith("127."): if host is None or host.lower() != "localhost" and not host.startswith("127."): log.warning("weird DNS setup: %s resolves to localhost (127.x.x.x)", host) if unixsocket: self.locationStr = "./u:" + unixsocket else: host = host or sockaddr[0] port = port or sockaddr[1] if ":" in host: # ipv6 self.locationStr = "[%s]:%d" % (host, port) else: self.locationStr = "%s:%d" % (host, port) self.selector.register(self.sock, selectors.EVENT_READ, self)
def init(self, daemon, host, port, unixsocket=None): log.info("starting thread pool socketserver") self.daemon = daemon self.sock = None bind_location = unixsocket if unixsocket else (host, port) self.sock = socketutil.createSocket(bind=bind_location, reuseaddr=Pyro4.config.SOCK_REUSE, timeout=Pyro4.config.COMMTIMEOUT, noinherit=True) self._socketaddr = self.sock.getsockname() if not unixsocket and self._socketaddr[0].startswith("127."): if host is None or host.lower( ) != "localhost" and not host.startswith("127."): log.warning( "weird DNS setup: %s resolves to localhost (127.x.x.x)", host) if unixsocket: self.locationStr = "./u:" + unixsocket else: host = host or self._socketaddr[0] port = port or self._socketaddr[1] if ":" in host: # ipv6 self.locationStr = "[%s]:%d" % (host, port) else: self.locationStr = "%s:%d" % (host, port) self.pool = Pool()
def testCreateBoundSockets6(self): s = SU.createSocket(bind=('::1', 0)) self.assertEqual(socket.AF_INET6, s.family) bs = SU.createBroadcastSocket(bind=('::1', 0)) self.assertIn(':', s.getsockname()[0]) self.assertIn(':', bs.getsockname()[0]) s.close() bs.close() self.assertRaises(ValueError, SU.createSocket, bind=('::1', 12345), connect=('::1', 1234))
def __pyroCreateConnection(self, replaceUri=False): """ Connects this proxy to the remote Pyro daemon. Does connection handshake. Returns true if a new connection was made, false if an existing one was already present. """ with self.__pyroConnLock: if self._pyroConnection is not None: return False # already connected from Pyro4.naming import resolve # don't import this globally because of cyclic dependancy uri=resolve(self._pyroUri) # socket connection (normal or Unix domain socket) conn=None log.debug("connecting to %s", uri) connect_location=uri.sockname if uri.sockname else (uri.host, uri.port) with self.__pyroLock: try: if self._pyroConnection is not None: return False # already connected sock=socketutil.createSocket(connect=connect_location, reuseaddr=Pyro4.config.SOCK_REUSE, timeout=self.__pyroTimeout) conn=socketutil.SocketConnection(sock, uri.object) # Do handshake. For now, no need to send anything. (message type CONNECT is not yet used) msg = Message.recv(conn, None) # any trailing data (dataLen>0) is an error message, if any except Exception: x=sys.exc_info()[1] if conn: conn.close() err="cannot connect: %s" % x log.error(err) if isinstance(x, errors.CommunicationError): raise else: ce = errors.CommunicationError(err) ce.__cause__ = x raise ce else: if msg.type==Pyro4.message.MSG_CONNECTFAIL: error="connection rejected" if msg.data: serializer = util.get_serializer_by_id(msg.serializer_id) data = serializer.deserializeData(msg.data, compressed=msg.flags & Pyro4.message.FLAGS_COMPRESSED) error += ", reason: " + data conn.close() log.error(error) raise errors.CommunicationError(error) elif msg.type==Pyro4.message.MSG_CONNECTOK: self._pyroConnection=conn if replaceUri: self._pyroUri=uri log.debug("connected to %s", self._pyroUri) return True else: conn.close() err="connect: invalid msg type %d received" % msg.type log.error(err) raise errors.ProtocolError(err)
def testCreateBoundUnixSockets(self): SOCKNAME = "test_unixsocket" if os.path.exists(SOCKNAME): os.remove(SOCKNAME) s = SU.createSocket(bind=SOCKNAME) self.assertEqual(socket.AF_UNIX, s.family) self.assertEqual(SOCKNAME, s.getsockname()) s.close() if os.path.exists(SOCKNAME): os.remove(SOCKNAME) # unicode arg SOCKNAME = unicode(SOCKNAME) s = SU.createSocket(bind=SOCKNAME) self.assertEqual(socket.AF_UNIX, s.family) self.assertEqual(SOCKNAME, s.getsockname()) s.close() if os.path.exists(SOCKNAME): os.remove(SOCKNAME) self.assertRaises(ValueError, SU.createSocket, bind=SOCKNAME, connect=SOCKNAME)
def __pyroCreateConnection(self, replaceUri=False): """ Connects this proxy to the remote Pyro daemon. Does connection handshake. Returns true if a new connection was made, false if an existing one was already present. """ with self.__pyroConnLock: if self._pyroConnection is not None: return False # already connected from Pyro4.naming import resolve # don't import this globally because of cyclic dependancy uri=resolve(self._pyroUri) # socket connection (normal or Unix domain socket) conn=None log.debug("connecting to %s", uri) connect_location=uri.sockname if uri.sockname else (uri.host, uri.port) with self.__pyroLock: try: if self._pyroConnection is not None: return False # already connected sock=socketutil.createSocket(connect=connect_location, reuseaddr=Pyro4.config.SOCK_REUSE, timeout=self.__pyroTimeout) conn=socketutil.SocketConnection(sock, uri.object) # Do handshake. For now, no need to send anything. msgType, flags, seq, data = MessageFactory.getMessage(conn, None) # any trailing data (dataLen>0) is an error message, if any except Exception: x=sys.exc_info()[1] if conn: conn.close() err="cannot connect: %s" % x log.error(err) if isinstance(x, errors.CommunicationError): raise else: raise errors.CommunicationError(err) else: if msgType==MessageFactory.MSG_CONNECTFAIL: error="connection rejected" if data: if sys.version_info>=(3,0): data=str(data,"utf-8") error+=", reason: "+data conn.close() log.error(error) raise errors.CommunicationError(error) elif msgType==MessageFactory.MSG_CONNECTOK: self._pyroConnection=conn if replaceUri: log.debug("replacing uri with bound one") self._pyroUri=uri log.debug("connected to %s", self._pyroUri) return True else: conn.close() err="connect: invalid msg type %d received" % msgType log.error(err) raise errors.ProtocolError(err)
def testServerPoolFull(self): port = socketutil.findProbablyUnusedPort() serv = SocketServer_Threadpool() daemon = ServerCallback() serv.init(daemon, "localhost", port) serversock = serv.sock.getsockname() csock1 = socketutil.createSocket(connect=serversock) csock2 = socketutil.createSocket(connect=serversock) try: serv.events([serv.sock]) time.sleep(0.2) self.assertEqual([None], daemon.received_denied_reasons) serv.events([serv.sock]) time.sleep(0.2) self.assertEqual(2, len(daemon.received_denied_reasons)) self.assertIn("no free workers, increase server threadpool size", daemon.received_denied_reasons) finally: csock1.close() csock2.close() serv.shutdown()
def connect(host, port): # connect to the server csock = SU.createSocket(connect=(host, port)) conn = SU.SocketConnection(csock, "uri") # send the handshake/connect data ser = Pyro4.util.get_serializer_by_id(Pyro4.util.MarshalSerializer.serializer_id) data, _ = ser.serializeData({"handshake": "hello", "object": Pyro4.constants.DAEMON_NAME}, False) msg = Pyro4.message.Message(Pyro4.message.MSG_CONNECT, data, Pyro4.util.MarshalSerializer.serializer_id, 0, 0) conn.send(msg.to_bytes()) # get the handshake/connect response Pyro4.message.Message.recv(conn, [Pyro4.message.MSG_CONNECTOK]) return conn
def interruptSocket(address): """bit of a hack to trigger a blocking server to get out of the loop, useful at clean shutdowns""" try: sock=socketutil.createSocket(connect=address, keepalive=False, timeout=None) socketutil.triggerSocket(sock) try: sock.shutdown(socket.SHUT_RDWR) except (OSError, socket.error): pass sock.close() except socket.error: pass
def interruptSocket(address): """bit of a hack to trigger a blocking server to get out of the loop, useful at clean shutdowns""" try: sock = socketutil.createSocket(connect=address, keepalive=False, timeout=None) if sys.version_info < (3, 0): sock.send("!" * 16) else: sock.send(bytes([1] * 16)) sock.close() except socket.error: pass
def testCreateUnboundSockets6(self): s = SU.createSocket(ipv6=True) self.assertEqual(socket.AF_INET6, s.family) bs = SU.createBroadcastSocket(ipv6=True) self.assertEqual(socket.AF_INET6, bs.family) try: host, port, _, _ = s.getsockname() # can either fail with socket.error or return (host,0) self.assertEqual(0, port) except socket.error: pass try: host, port, _, _ = bs.getsockname() # can either fail with socket.error or return (host,0) self.assertEqual(0, port) except socket.error: pass s.close() bs.close()
def init(self, daemon, host, port, unixsocket=None): log.info("starting thread pool socketserver") self.daemon = daemon self.sock = None bind_location = unixsocket if unixsocket else (host, port) if config.SSL: sslContext = socketutil.getSSLcontext( servercert=config.SSL_SERVERCERT, serverkey=config.SSL_SERVERKEY, keypassword=config.SSL_SERVERKEYPASSWD, cacerts=config.SSL_CACERTS) log.info("using SSL, cert=%s key=%s cacerts=%s", config.SSL_SERVERCERT, config.SSL_SERVERKEY, config.SSL_CACERTS) else: sslContext = None log.info("not using SSL") self.sock = socketutil.createSocket(bind=bind_location, reuseaddr=config.SOCK_REUSE, timeout=config.COMMTIMEOUT, noinherit=True, nodelay=config.SOCK_NODELAY, sslContext=sslContext) self._socketaddr = self.sock.getsockname() if not unixsocket and self._socketaddr[0].startswith("127."): if host is None or host.lower( ) != "localhost" and not host.startswith("127."): log.warning( "weird DNS setup: %s resolves to localhost (127.x.x.x)", host) if unixsocket: self.locationStr = "./u:" + unixsocket else: host = host or self._socketaddr[0] port = port or self._socketaddr[1] if ":" in host: # ipv6 self.locationStr = "[%s]:%d" % (host, port) else: self.locationStr = "%s:%d" % (host, port) self.pool = Pool() self.housekeeper = Housekeeper(daemon) self.housekeeper.start()
def create_ssl_socket(*args, **kwargs): """Override the Pyro createSocket method and wrap with SSL""" socket = socketutil.createSocket(*args, **kwargs) ssl_socket = SSLSocket.wrap_socket(socket, *args, **kwargs) return ssl_socket
def testAbstractNamespace(self): SOCKNAME = "\0test_unixsocket_abstract_ns" # mind the \0 at the start s = SU.createSocket(bind=SOCKNAME) sn_bytes = tobytes(SOCKNAME) self.assertEqual(sn_bytes, s.getsockname()) s.close()