Esempio n. 1
0
    def do_dispatch(self, session, request):
        """ dispatch request to the relevant processor """

        method = request['method']
        params = request.get('params', [])
        suffix = method.split('.')[-1]

        if session is not None:
            if suffix == 'subscribe':
                if not session.subscribe_to_service(method, params):
                    return

        prefix = request['method'].split('.')[0]
        try:
            p = self.processors[prefix]
        except:
            print_log("error: no processor for", prefix)
            return

        p.add_request(session, request)

        if method in ['server.version']:
            try:
                session.version = params[0]
                session.protocol_version = float(params[1])
            except:
                pass
Esempio n. 2
0
 def shutdown(self):
     try:
         self._connection.shutdown(socket.SHUT_RDWR)
     except Exception as err:
         print_log("problem shutting down", self.address)
         print_log(err)
     finally:
         self._connection.close()
Esempio n. 3
0
    def stop(self):
        print_log("Stop", self.address)
        with self.lock:
            if self._stopped:
                return
            self._stopped = True

        self.shutdown()
        self.dispatcher.remove_session(self)
        self.stop_subscriptions()
Esempio n. 4
0
    def subscribe_to_service(self, method, params):
        if self.stopped():
            return False

        if len(self.subscriptions) > self.max_subscriptions:
            print_log("max subscriptions reached", self.address)
            self.stop()
            return False

        # append to self.subscriptions only if this does not raise
        self.bp.do_subscribe(method, params, self)
        with self.lock:
            if (method, params) not in self.subscriptions:
                self.subscriptions.append((method, params))
        return True
Esempio n. 5
0
 def stop(self):
     print_log("Stopping Stratum")
     with self.lock:
         self._stopped = True
Esempio n. 6
0
 def info(self):
     if self.subscriptions:
         print_log("%4s" % self.name, "%21s" % self.address,
                   "%4d" % len(self.subscriptions), self.version)
Esempio n. 7
0
    def run(self):

        for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC,
                                      socket.SOCK_STREAM):
            af, socktype, proto, cannonname, sa = res
            try:
                sock = socket.socket(af, socktype, proto)
                sock.setblocking(0)
                sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            except socket.error:
                sock = None
                continue
            try:
                sock.bind(sa)
                sock.listen(5)
            except socket.error:
                sock.close()
                sock = None
                continue
            break
        host = sa[0]
        if af == socket.AF_INET6:
            host = "[%s]" % host
        if sock is None:
            print_log("could not open " + ("SSL" if self.use_ssl else "TCP") +
                      " socket on %s:%d" % (host, self.port))
            return
        print_log(("SSL" if self.use_ssl else "TCP") +
                  " server started on %s:%d" % (host, self.port))

        sock_fd = sock.fileno()
        poller = select.poll()
        poller.register(sock)

        def stop_session(fd):
            try:
                # unregister before we close s
                poller.unregister(fd)
            except BaseException as e:
                logger.error('unregister error:' + str(e))
            session = self.fd_to_session.pop(fd)
            # this will close the socket
            session.stop()

        def check_do_handshake(session):
            if session.handshake:
                return
            try:
                session._connection.do_handshake()
            except ssl.SSLError as err:
                if err.args[0] == ssl.SSL_ERROR_WANT_READ:
                    return
                elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
                    poller.modify(session.raw_connection, READ_WRITE)
                    return
                else:
                    raise BaseException(str(err))
            poller.modify(session.raw_connection, READ_ONLY)
            session.handshake = True

        redo = []

        while not self.shared.stopped():

            if self.shared.paused():
                sessions = self.fd_to_session.keys()
                if sessions:
                    logger.info("closing %d sessions" % len(sessions))
                for fd in sessions:
                    stop_session(fd)
                time.sleep(1)
                continue

            if redo:
                events = redo
                redo = []
            else:
                now = time.time()
                for fd, session in self.fd_to_session.items():
                    # Anti-DOS: wait 0.01 second between requests
                    if now - session.time > 0.01 and session.message:
                        cmd = session.parse_message()
                        if not cmd:
                            break
                        if cmd == 'quit':
                            data = False
                            break
                        session.time = now
                        self.handle_command(cmd, session)

                    # Anti-DOS: Stop reading if the session does not read responses
                    if session.response_queue.empty():
                        mode = READ_ONLY
                    elif session.response_queue.qsize() < 200:
                        mode = READ_WRITE
                    else:
                        mode = WRITE_ONLY
                    if mode != session.mode:
                        poller.modify(session.raw_connection, mode)
                        session.mode = mode

                    # Collect garbage
                    if now - session.time > session.timeout:
                        stop_session(fd)

                events = poller.poll(TIMEOUT)

            for fd, flag in events:
                # open new session
                if fd == sock_fd:
                    if flag & (select.POLLIN | select.POLLPRI):
                        try:
                            connection, address = sock.accept()
                            session = TcpSession(
                                self.dispatcher,
                                connection,
                                address,
                                use_ssl=self.use_ssl,
                                ssl_certfile=self.ssl_certfile,
                                ssl_keyfile=self.ssl_keyfile)
                        except BaseException as e:
                            logger.error("cannot start TCP session" + str(e) +
                                         ' ' + repr(address))
                            connection.close()
                            continue
                        connection = session._connection
                        connection.setblocking(False)
                        self.fd_to_session[connection.fileno()] = session
                        poller.register(connection, READ_ONLY)
                    continue
                # existing session
                session = self.fd_to_session[fd]
                s = session._connection
                # non-blocking handshake
                try:
                    check_do_handshake(session)
                except BaseException as e:
                    # logger.error('handshake failure:' + str(e) + ' ' + repr(session.address))
                    stop_session(fd)
                    continue
                # anti DOS
                now = time.time()
                if now - session.time < 0.01:
                    continue
                # Read input messages.
                if flag & (select.POLLIN | select.POLLPRI):
                    try:
                        data = s.recv(self.buffer_size)
                    except ssl.SSLError as x:
                        if x.args[0] == ssl.SSL_ERROR_WANT_READ:
                            pass
                        elif x.args[0] == ssl.SSL_ERROR_SSL:
                            pass
                        else:
                            logger.error('SSL recv error:' + repr(x))
                        continue
                    except socket.error as x:
                        if x.args[0] != 104:
                            logger.error('recv error: ' + repr(x) + ' %d' % fd)
                        stop_session(fd)
                        continue
                    except ValueError as e:
                        logger.error('recv error: ' + str(e) + ' %d' % fd)
                        stop_session(fd)
                        continue
                    if data:
                        session.message += data
                        if len(data) == self.buffer_size:
                            redo.append((fd, flag))

                    if not data:
                        stop_session(fd)
                        continue

                elif flag & select.POLLHUP:
                    print_log('client hung up', session.address)
                    stop_session(fd)

                elif flag & select.POLLOUT:
                    # Socket is ready to send data, if there is any to send.
                    if session.retry_msg:
                        next_msg = session.retry_msg
                    else:
                        try:
                            next_msg = session.response_queue.get_nowait()
                        except queue.Empty:
                            continue
                    try:
                        sent = s.send(next_msg)
                    except socket.error as x:
                        logger.error("send error:" + str(x))
                        stop_session(fd)
                        continue
                    session.retry_msg = next_msg[sent:]

                elif flag & select.POLLERR:
                    print_log('handling exceptional condition for',
                              session.address)
                    stop_session(fd)

                elif flag & select.POLLNVAL:
                    print_log('invalid request', session.address)
                    stop_session(fd)

        print_log('TCP thread terminating', self.shared.stopped())
Esempio n. 8
0
 def get_undo_claim_info(self, height):
     s = self.db_undo_claim.get("undo_info_%d" % height)
     if s is None:
         print_log('claim no undo info for {}'.format(height))
         return None
     return pickle.loads(s)