Esempio n. 1
0
    def _start_deamon(self):
        if not self._debug and (os.name == 'nt' or not hasattr(os, 'fork')):
            raise exceptions.DeamonError('Windows does not support fork')
        # double fork create a deamon
        try:
            pid = os.fork()  # fork #1
            if pid > 0:  # parent exit
                exit()
        except OSError as e:
            raise exceptions.FatalError(
                'Fork #1 error occurs, reason({})'.format(e))

        os.chdir('/')
        os.setsid()
        os.umask(0)

        try:
            pid = os.fork()  # fork #2
            if pid > 0:  # parent exit
                exit()
        except OSError as e:
            raise exceptions.FatalError(
                'Fork #2 error occurs, reason({})'.format(e))

        # redirect all std file descriptor
        sys.stdout.flush()
        sys.stderr.flush()
        _stdin = open(self._stdin, 'r')
        _stdout = open(self._stdout, 'a')
        # if require non-buffer, open mode muse be `b`
        _stderr = open(self._stderr, 'wb+', buffering=0)
        os.dup2(_stdin.fileno(), sys.stdin.fileno())
        os.dup2(_stdout.fileno(), sys.stdout.fileno())
        os.dup2(_stderr.fileno(), sys.stderr.fileno())

        # terminal signal
        signal.signal(signal.SIGTERM, self._signal_handler)
        # kill signal
        signal.signal(signal.SIGILL, self._signal_handler)
        # system interrupt
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        # register function at exit
        atexit.register(self._remove_pid_file)
        # write pid file
        with open(self._pid_file, 'w') as fd:
            fd.write('{pid}\n'.format(pid=os.getpid()))
        logger.info('Daemon has been started')
Esempio n. 2
0
    def verify_host(self):
        if 'Host' not in self._request.header:
            self._raise_error_message(
                '{} loss `Host` option'.format(self._client_name))
        if not _server_name:
            raise exceptions.FatalError('Server Internal Error, Please report')
        if _server_name[0] is True:
            return True

        _host = self._request.header.get_value('Host', value_type=str)
        if _server_name[1] is 80:
            return _host == _server_name[0]
        return _host == ':'.join(
            map(lambda x: generic.to_string(x), _server_name))
Esempio n. 3
0
def parse_frame_length(frame_header):
    if not isinstance(frame_header, (str, bytes)):
        raise KeyError('frame_header must be str or bytes type')
    header = packet.ByteArray(frame_header)
    if len(header) < 2:
        logger.warning('receive less than 2-bytes')
        raise RuntimeError('frame header less than 2-bytes')
    # first bit is MASK flag
    payload_length = packet.bits_to_integer(header.get_bits(1)[1:])
    # if 0-125, that is the payload length
    if payload_length <= 125:
        # if frame is client-to-server, payload length does not include mask-key
        if header.get_bits(1)[0] is 1:
            return payload_length + 6
        return payload_length + 2
    # If 126, the following 2 bytes interpreted as a
    # 16-bit unsigned integer are the payload length
    elif payload_length == 126:
        # Payload length field is in [2-4)bytes
        if len(header) < 4:
            raise exceptions.FrameHeaderParseError(
                'payload length flag is 126, but header length is {}'.format(
                    len(header)))
        if header.get_bits(1)[0] is 1:
            return packet.bits_to_integer(
                generic.flatten_list(header.get_bits(2, 2))) + 8
        return packet.bits_to_integer(
            generic.flatten_list(header.get_bits(2, 2))) + 4
    # If 127, the following 8 bytes interpreted as a
    # 64-bit unsigned integer (the most significant bit
    # MUST be 0) are the payload length.
    elif payload_length == 127:
        # Payload length field is in [2-10)bytes
        if len(header) < 10:
            raise exceptions.FrameHeaderParseError(
                'payload length flag is 127, but header length is {}'.format(
                    len(header)))
        if header.get_bits(1)[0] is 1:
            return packet.bits_to_integer(
                generic.flatten_list(header.get_bits(2, 2))) + 14
        return packet.bits_to_integer(
            generic.flatten_list(header.get_bits(2, 2))) + 10
    raise exceptions.FatalError('internal error')
Esempio n. 4
0
    def broadcast(self, message, include_self: bool=False):
        _self_class = self._get_handler_self()

        if not hasattr(_self_class, '__namespace__'):
            raise exceptions.BroadcastError('broadcast context invalid')

        namespace = _self_class.__namespace__
        if namespace not in self._client_list:
            raise exceptions.FatalError(
                'handler context invalid for namespace not found')

        if hasattr(message, 'pack'):
            pass
        elif hasattr(message, 'generate_frame'):
            message = message.generate_frame
        else:
            raise exceptions.BroadcastError('broadcast message invalid')

        _context_socket_fd = _self_class.socket_fd
        for socket_fd in self._client_list[namespace]:
            if socket_fd == _context_socket_fd and not include_self:
                continue
            self._write_queue[socket_fd].append(message)
        return True
Esempio n. 5
0
 def _get_handler_self():
     prev_locals = inspect.stack()[2][0].f_locals
     if 'self' in prev_locals:
         _self_class = prev_locals['self']
         return _self_class
     raise exceptions.FatalError('cannot find handler class')
Esempio n. 6
0
    def _accept_http_handshake(self, socket_fd):
        _tcp_stream = \
            self._client_list['default'][socket_fd]  # type:tcp_stream.TCPStream
        # receive data from kernel tcp buffer
        pos = _tcp_stream.find_buffer(b'\r\n\r\n')
        if pos is -1:
            return
        http_request = http_message.factory_http_message(
            _tcp_stream.feed_buffer(pos))
        # Verify http request is correct
        support_extension = tuple()
        try:
            support_extension_list = \
                http_verifier.verify_request(
                    socket_fd.getpeername(), http_request)
            support_extension = (
                b'Sec-WebSocket-Extensions',
                b','.join(map(
                    lambda x: generic.to_bytes(x), support_extension_list)))
            if not support_extension[1]:
                support_extension = None
        except exceptions.HttpVerifierError:
            # verify error occurs, return 403 Forbidden
            http_response = http_message.HttpResponse(
                403, (b'X-Forbidden-Reason', b'http-options-invalid'))
            # write directly to the data, and then close the connection
            self._socket_ready_write(
                socket_fd, http_response, http_request.url_path)
            # close connection
            self._close_client(socket_fd, 'default')
        logger.debug('Request: {}'.format(repr(http_request)))
        # TODO. chunk header-field
        if 'Content-Length' in http_request.header:
            logger.info('Request has payload, length = {}'.format(
                http_request.header.get_value('Content-Length')))
            # buffer length is too short
            if _tcp_stream.get_buffer_length() < \
                    http_request.header.get_value('Content-Length'):
                return
            # drop payload data
            _tcp_stream.feed_buffer(http_request['Content-Length'].value)

        ws_key = http_request.header.get_value('Sec-WebSocket-Key')
        # Optionally, other header fields, such as those used to send
        # cookies or request authentication to a server.
        http_response = http_message.HttpResponse(
            101, *(
                (b'Upgrade', b'websocket'),
                (b'Connection', b'Upgrade'),
                (b'Sec-WebSocket-Accept', ws_utils.ws_accept_key(ws_key)),
                support_extension
            )
        )
        try:
            namespace = generic.to_string(http_request.url_path)
            # get handler or default handler
            _handler = self._router.solution(namespace, 'handler')(socket_fd)
            # get controller or default controller
            controller_name = self._router.solution(namespace, 'controller')
            # initial controller
            if namespace not in self._client_list:
                self._client_list[namespace] = dict()
            self._client_list[namespace][socket_fd] = controller_name(
                self._client_list['default'].pop(socket_fd),
                self._write_queue[socket_fd].append,
                _handler)
            # send http-handshake-response
            self._write_queue[socket_fd].append(http_response)
            # notification handler connect event
            response = _handler.on_connect()
            # send connect message
            if hasattr(response, 'pack'):
                self._write_queue[socket_fd].append(response)
            elif hasattr(response, 'generate_frame'):
                self._write_queue[socket_fd].append(response.generate_frame)
            # modify selector data
            self._selector.modify(socket_fd,
                                  selectors.EVENT_READ,
                                  (self._socket_ready_receive, namespace))
        except exceptions.ParameterError:
            raise exceptions.FatalError('handler not found')