Exemplo n.º 1
0
    def handshake(self, sock):
        data = sock.recv(4)
        if data == BOLT:
            log.info("C: <BOLT>")
        else:
            if data:
                log.error("C: <#?@!>")
            self.stop()
            return
        raw_data = sock.recv(16)
        suggested_version_1, = raw_unpack(INT_32, raw_data, 0)
        suggested_version_2, = raw_unpack(INT_32, raw_data, 4)
        suggested_version_3, = raw_unpack(INT_32, raw_data, 8)
        suggested_version_4, = raw_unpack(INT_32, raw_data, 12)
        client_requested_versions = [suggested_version_1, suggested_version_2, suggested_version_3, suggested_version_4]
        log.info("C: <VERSION> [0x%08x, 0x%08x, 0x%08x, 0x%08x]" % tuple(client_requested_versions))

        v = self.script.protocol_version
        if v not in client_requested_versions:
            raise RuntimeError("Script protocol version %r not offered by client" % v)

        # only single protocol version is currently supported
        response = raw_pack(INT_32, v)
        log.info("S: <VERSION> 0x%08x" % v)
        self.peers[sock].version = v
        sock.send(response)
Exemplo n.º 2
0
    def handshake(self, sock):
        data = sock.recv(4)
        if data == BOLT:
            log.info("C: <BOLT>")
        else:
            if data:
                log.error("C: <#?@!>")
            self.stop()
            return
        raw_data = sock.recv(16)
        suggested_version_1, = raw_unpack(INT_32, raw_data, 0)
        suggested_version_2, = raw_unpack(INT_32, raw_data, 4)
        suggested_version_3, = raw_unpack(INT_32, raw_data, 8)
        suggested_version_4, = raw_unpack(INT_32, raw_data, 12)
        client_requested_versions = [suggested_version_1, suggested_version_2, suggested_version_3, suggested_version_4]
        log.info("C: <VERSION> [0x%08x, 0x%08x, 0x%08x, 0x%08x]" % tuple(client_requested_versions))

        v = self.script.bolt_version
        if v not in client_requested_versions:
            raise RuntimeError("Script protocol version %r not offered by client" % v)

        # only single protocol version is currently supported
        response = raw_pack(INT_32, v)
        log.info("S: <VERSION> 0x%08x" % v)
        self.peers[sock].bolt_version = v
        sock.send(response)
Exemplo n.º 3
0
def connect(address):
    """ Connect and perform a handshake in order to return a valid
    Connection object, assuming a protocol version can be agreed.
    """

    # Establish a connection to the host and port specified
    log("~~ [CONNECT] %r", address)
    socket = create_connection(address)

    log("C: [MAGIC] %s", h(MAGIC))
    socket.sendall(MAGIC)

    # Send details of the protocol versions supported
    supported_versions = [1, 0, 0, 0]
    data = b"".join(raw_pack(UINT_32, version) for version in supported_versions)
    log("C: [HANDSHAKE] %s", h(data))
    socket.sendall(data)

    # Handle the handshake response
    data = socket.recv(4)
    log("S: [HANDSHAKE] %s", h(data))
    agreed_version, = raw_unpack(UINT_32, data)
    if agreed_version == 1:
        return Connection(socket)
    else:
        log("~~ [DISCONNECT] Could not negotiate protocol version")
        socket.close()
        raise RuntimeError("Could not negotiate protocol version")
Exemplo n.º 4
0
    def fetch(self):
        """ Receive exactly one message from an open socket
        """

        # Receive chunks of data until chunk_size == 0
        data = []
        chunk_size = -1
        while chunk_size != 0:
            chunk_size, = raw_unpack(UINT_16, self.socket.recv(2))
            if chunk_size > 0:
                data.append(self.socket.recv(chunk_size))
        message = unpack(b"".join(data))
        log("S: %s" % message_repr(*message))

        # Handle message
        request = self.incoming[0]
        try:
            request.on_message(*message)
        except Failure as failure:
            if isinstance(failure.request, QueryRequest):
                self.outgoing.append(Request(BOLT["ACK_FAILURE"]))
            else:
                self.close()
            raise
        finally:
            if request.complete:
                self.incoming.popleft()
        return not request.complete
Exemplo n.º 5
0
    def fetch_one(self):
        """ Receive exactly one response message from the server. This method blocks until either a
        message arrives or the connection is terminated.
        """

        # Receive chunks of data until chunk_size == 0
        data = []
        chunk_size = -1
        while chunk_size != 0:
            chunk_size, = raw_unpack(UINT_16, self.socket.recv(2))
            if chunk_size > 0:
                data.append(self.socket.recv(chunk_size))
        message = unpack(b"".join(data))

        # Handle message
        response = self.responses[0]
        try:
            response.on_message(message.tag, *message.fields)
        except Failure as failure:
            if isinstance(failure.response, QueryResponse):
                self.reset()
            else:
                self.close()
            raise
        finally:
            if response.complete():
                self.responses.pop(0)
Exemplo n.º 6
0
 def _open_to(cls, address, auth, user_agent, bolt_versions):
     """ Attempt to open a connection to a Bolt server, given a single
     socket address.
     """
     cx = None
     handshake_data = BOLT + b"".join(raw_pack(UINT_32, version)
                                      for version in bolt_versions)
     s = socket(family={2: AF_INET, 4: AF_INET6}[len(address)])
     try:
         s.connect(address)
         s.sendall(handshake_data)
         raw_bolt_version = s.recv(4)
         if raw_bolt_version:
             bolt_version, = raw_unpack(UINT_32, raw_bolt_version)
             if bolt_version > 0 and bolt_version in bolt_versions:
                 cx = cls(s, bolt_version, auth, user_agent)
             else:
                 log.error("Could not negotiate protocol version "
                           "(outcome=%d)", bolt_version)
         else:
             pass  # recv returned empty, peer closed connection
     finally:
         if not cx:
             s.close()
     return cx
Exemplo n.º 7
0
 def raw_unpack(self, type_code):
     value, = raw_unpack(type_code, self.data, self.offset)
     self.offset += {
         INT_8: 1, INT_16: 2, INT_32: 4, INT_64: 8,
         UINT_8: 1, UINT_16: 2, UINT_32: 4, FLOAT_64: 8,
     }[type_code]
     return value
Exemplo n.º 8
0
    def fetch(self):
        """ Receive exactly one response message from the server. This method blocks until either a
        message arrives or the connection is terminated.
        """

        # Receive chunks of data until chunk_size == 0
        data = []
        chunk_size = -1
        while chunk_size != 0:
            chunk_size, = raw_unpack(UINT_16, self.socket.recv(2))
            if chunk_size > 0:
                data.append(self.socket.recv(chunk_size))
        message = unpacked(b"".join(data))

        # Handle message
        response = self.responses[0]
        try:
            response.on_message(*message)
        except Failure as failure:
            if isinstance(failure.response, QueryResponse):
                self.requests.append(ACK_FAILURE_REQUEST)
                self.responses.append(Response())
            else:
                self.close()
            raise
        finally:
            if response.complete():
                self.responses.popleft()
Exemplo n.º 9
0
    def handle_request(self, sock):
        v = self.peers[sock].version

        chunked_data = b""
        message_data = b""
        chunk_size = -1
        debug = []
        while chunk_size != 0:
            chunk_header = sock.recv(2)
            if len(chunk_header) == 0:
                self.stop()
                return
            chunked_data += chunk_header
            chunk_size, = raw_unpack(UINT_16, chunk_header)
            if chunk_size > 0:
                chunk = sock.recv(chunk_size)
                chunked_data += chunk
                message_data += chunk
            else:
                chunk = b""
            debug.append("     [%s] %s" % (h(chunk_header), h(chunk)))
        request = unpacked(message_data)

        if self.script.match_request(request):
            # explicitly matched
            log.info("C: %s", message_repr(v, *request))
        elif self.script.match_auto_request(request):
            # auto matched
            log.info("C! %s", message_repr(v, *request))
        else:
            # not matched
            log.error("C: %s", message_repr(v, *request))

        responses = self.script.match_responses()
        if not responses and self.script.match_auto_request(request):
            # These are hard-coded and therefore not very future-proof.
            if request[0] in (CLIENT[v].get("HELLO"), CLIENT[v].get("INIT")):
                responses = [(SERVER[v]["SUCCESS"], {
                    u"server": u"Neo4j/9.99.999"
                })]
            elif request[0] == CLIENT[v].get("GOODBYE"):
                log.info("S: <EXIT>")
                exit(0)
            elif request[0] == CLIENT[v]["RUN"]:
                responses = [(SERVER[v]["SUCCESS"], {u"fields": []})]
            else:
                responses = [(SERVER[v]["SUCCESS"], {})]
        for response in responses:
            if isinstance(response, tuple):
                data = packed(response)
                self.send_chunk(sock, data)
                self.send_chunk(sock)
                log.info("S: %s", message_repr(v, *response))
            elif isinstance(response, ExitCommand):
                exit(0)
            else:
                raise RuntimeError("Unknown response type %r" % response)
Exemplo n.º 10
0
    def handle_request(self, sock):
        v = self.peers[sock].bolt_version

        chunked_data = b""
        message_data = b""
        chunk_size = -1
        debug = []
        while chunk_size != 0:
            chunk_header = sock.recv(2)
            if len(chunk_header) == 0:
                self.stop()
                return
            chunked_data += chunk_header
            chunk_size, = raw_unpack(UINT_16, chunk_header)
            if chunk_size > 0:
                chunk = sock.recv(chunk_size)
                chunked_data += chunk
                message_data += chunk
            else:
                chunk = b""
            debug.append("     [%s] %s" % (h(chunk_header), h(chunk)))
        request = unpacked(message_data)

        if self.script.match_request(request):
            # explicitly matched
            log.info("C: %s", message_repr(v, request))
        elif self.script.match_auto_request(request):
            # auto matched
            log.info("C! %s", message_repr(v, request))
        else:
            # not matched
            log.error("C: %s", message_repr(v, request))

        responses = self.script.match_responses()
        if not responses and self.script.match_auto_request(request):
            # These are hard-coded and therefore not very future-proof.
            if request.tag in (CLIENT[v].get("HELLO"), CLIENT[v].get("INIT")):
                responses = [Structure(SERVER[v]["SUCCESS"], {"server": server_agents.get(v, "Neo4j/9.99.999")})]
            elif request.tag == CLIENT[v].get("GOODBYE"):
                log.info("S: <EXIT>")
                exit(0)
            elif request.tag == CLIENT[v]["RUN"]:
                responses = [Structure(SERVER[v]["SUCCESS"], {"fields": []})]
            else:
                responses = [Structure(SERVER[v]["SUCCESS"], {})]
        for response in responses:
            if isinstance(response, Structure):
                data = packed(response)
                self.send_chunk(sock, data)
                self.send_chunk(sock)
                log.info("S: %s", message_repr(v, Structure(response.tag, *response.fields)))
            elif isinstance(response, ExitCommand):
                exit(0)
            else:
                raise RuntimeError("Unknown response type %r" % (response,))
Exemplo n.º 11
0
 def raw_unpack(self, type_code):
     value, = raw_unpack(type_code, self.data, self.offset)
     self.offset += {
         INT_8: 1,
         INT_16: 2,
         INT_32: 4,
         INT_64: 8,
         UINT_8: 1,
         UINT_16: 2,
         UINT_32: 4,
         FLOAT_64: 8,
     }[type_code]
     return value
Exemplo n.º 12
0
 def __init__(self, client, server):
     super(ProxyPair, self).__init__()
     self.client = client
     self.server = server
     print("C: <CONNECT> {} -> {}".format(self.client.address, self.server.address))
     print("C: <BOLT> {}".format(h(self.forward_bytes(client, server, 4))))
     print("C: <VERSION> {}".format(h(self.forward_bytes(client, server, 16))))
     raw_bolt_version = self.forward_bytes(server, client, 4)
     bolt_version, = raw_unpack(UINT_32, raw_bolt_version)
     self.client.bolt_version = self.server.bolt_version = bolt_version
     print("S: <VERSION> {}".format(h(raw_bolt_version)))
     self.client_messages = {v: k for k, v in CLIENT[self.client.bolt_version].items()}
     self.server_messages = {v: k for k, v in SERVER[self.server.bolt_version].items()}
Exemplo n.º 13
0
 def __init__(self, client, server):
     super(ProxyPair, self).__init__()
     self.client = client
     self.server = server
     log.debug("C: <CONNECT> {} -> {}".format(self.client.address, self.server.address))
     log.debug("C: <BOLT> {}".format(h(self.forward_bytes(client, server, 4))))
     log.debug("C: <VERSION> {}".format(h(self.forward_bytes(client, server, 16))))
     raw_bolt_version = self.forward_bytes(server, client, 4)
     bolt_version, = raw_unpack(UINT_32, raw_bolt_version)
     self.client.bolt_version = self.server.bolt_version = bolt_version
     log.debug("S: <VERSION> {}".format(h(raw_bolt_version)))
     self.client_messages = {v: k for k, v in CLIENT[self.client.bolt_version].items()}
     self.server_messages = {v: k for k, v in SERVER[self.server.bolt_version].items()}
Exemplo n.º 14
0
    def handle_request(self, sock):
        chunked_data = b""
        message_data = b""
        chunk_size = -1
        debug = []
        while chunk_size != 0:
            chunk_header = sock.recv(2)
            if len(chunk_header) == 0:
                self.stop()
                return
            chunked_data += chunk_header
            chunk_size, = raw_unpack(UINT_16, chunk_header)
            if chunk_size > 0:
                chunk = sock.recv(chunk_size)
                chunked_data += chunk
                message_data += chunk
            else:
                chunk = b""
            debug.append("     [%s] %s" % (h(chunk_header), h(chunk)))
        request = unpacked(message_data)

        if self.script.match_request(request):
            # explicitly matched
            log.info("C: %s", message_repr(*request))
        elif self.script.match_auto_request(request):
            # auto matched
            log.info("C! %s", message_repr(*request))
        else:
            # not matched
            log.error("C: %s", message_repr(*request))

        responses = self.script.match_responses()
        if not responses and self.script.match_auto_request(request):
            responses = [(SERVER["SUCCESS"], {
                u"fields": []
            } if request[0] == CLIENT["RUN"] else {})]
        for response in responses:
            if isinstance(response, tuple):
                data = packed(response)
                self.send_chunk(sock, data)
                self.send_chunk(sock)
                log.info("S: %s", message_repr(*response))
            elif isinstance(response, ExitCommand):
                exit(0)
            else:
                raise RuntimeError("Unknown response type %r" % response)
Exemplo n.º 15
0
    def fetch_one(self):
        """ Receive exactly one response message from the server. This method
        blocks until either a message arrives or the connection is terminated.
        """

        # Receive chunks of data until chunk_size == 0
        data = []
        chunk_size = -1
        while chunk_size != 0:
            chunk_size, = raw_unpack(UINT_16, self.socket.recv(2))
            if chunk_size > 0:
                data.append(self.socket.recv(chunk_size))
        message = unpack(b"".join(data))

        # Handle message
        response = self.responses[0]
        response.on_message(message.tag, *message.fields)
        if response.complete:
            self.responses.pop(0)
Exemplo n.º 16
0
    def handle_request(self, sock):
        chunked_data = b""
        message_data = b""
        chunk_size = -1
        debug = []
        while chunk_size != 0:
            chunk_header = sock.recv(2)
            if len(chunk_header) == 0:
                self.stop()
                return
            chunked_data += chunk_header
            chunk_size, = raw_unpack(UINT_16, chunk_header)
            if chunk_size > 0:
                chunk = sock.recv(chunk_size)
                chunked_data += chunk
                message_data += chunk
            else:
                chunk = b""
            debug.append("     [%s] %s" % (h(chunk_header), h(chunk)))
        request = unpacked(message_data)

        if self.script.match_request(request):
            # explicitly matched
            log.info("C: %s", message_repr(*request))
        elif self.script.match_auto_request(request):
            # auto matched
            log.info("C! %s", message_repr(*request))
        else:
            # not matched
            log.error("C: %s", message_repr(*request))

        responses = self.script.match_responses()
        if not responses and self.script.match_auto_request(request):
            responses = [(SERVER["SUCCESS"], {u"fields": []}
                         if request[0] == CLIENT["RUN"] else {})]
        for response in responses:
            data = packed(response)
            self.send_chunk(sock, data)
            self.send_chunk(sock)
            log.info("S: %s", message_repr(*response))
Exemplo n.º 17
0
def connect(address, connection_settings):
    """ Establish a connection to a Bolt server. It is here that we create a low-level socket
    connection and carry out version negotiation. Following this (and assuming success) a
    Connection instance will be returned.  This Connection takes ownership of the underlying
    socket and is subsequently responsible for managing its lifecycle.

    Args:
        address: A tuple of host and port, such as ("127.0.0.1", 7687).
        connection_settings: Settings for initialising the connection once established.

    Returns:
        A connection to the Bolt server.

    Raises:
        ProtocolError: if the protocol version could not be negotiated.
    """

    # Establish a connection to the host and port specified
    log.info("~~ <CONNECT> \"%s\" %d", *address)
    socket = create_connection(address)
    socket.settimeout(SOCKET_TIMEOUT)

    log.info("C: <BOLT>")
    socket.sendall(BOLT)

    # Send details of the protocol versions supported
    log.info("C: <VERSION> %d", BOLT_VERSION)
    socket.sendall(RAW_BOLT_VERSIONS)

    # Handle the handshake response
    raw_version = socket.recv(4)
    version, = raw_unpack(UINT_32, raw_version)
    log.info("S: <VERSION> %d", version)

    if version == BOLT_VERSION:
        return Connection(socket, connection_settings)
    else:
        log.error("~~ <CLOSE> Could not negotiate protocol version")
        socket.close()
        raise ProtocolError("Could not negotiate protocol version")
Exemplo n.º 18
0
def connect(address, connection_settings):
    """ Establish a connection to a Bolt server. It is here that we create a low-level socket
    connection and carry out version negotiation. Following this (and assuming success) a
    Connection instance will be returned.  This Connection takes ownership of the underlying
    socket and is subsequently responsible for managing its lifecycle.

    Args:
        address: A tuple of host and port, such as ("127.0.0.1", 7687).
        connection_settings: Settings for initialising the connection once established.

    Returns:
        A connection to the Bolt server.

    Raises:
        ProtocolError: if the protocol version could not be negotiated.
    """

    # Establish a connection to the host and port specified
    log.info("~~ <CONNECT> \"%s\" %d", *address)
    socket = create_connection(address)

    log.info("C: <BOLT>")
    socket.sendall(BOLT)

    # Send details of the protocol versions supported
    log.info("C: <VERSION> %d", BOLT_VERSION)
    socket.sendall(RAW_BOLT_VERSIONS)

    # Handle the handshake response
    raw_version = socket.recv(4)
    version, = raw_unpack(UINT_32, raw_version)
    log.info("S: <VERSION> %d", version)

    if version == BOLT_VERSION:
        return Connection(socket, connection_settings)
    else:
        log.error("~~ <CLOSE> Could not negotiate protocol version")
        socket.close()
        raise ProtocolError("Could not negotiate protocol version")
Exemplo n.º 19
0
    def handle_request(self, sock):
        v = self.peers[sock].bolt_version

        chunked_data = b""
        message_data = b""
        chunk_size = -1
        debug = []
        while chunk_size != 0:
            chunk_header = sock.recv(2)
            if len(chunk_header) == 0:
                self.stop()
                return
            chunked_data += chunk_header
            chunk_size, = raw_unpack(UINT_16, chunk_header)
            if chunk_size > 0:
                chunk = sock.recv(chunk_size)
                chunked_data += chunk
                message_data += chunk
            else:
                chunk = b""
            debug.append("     [%s] %s" % (h(chunk_header), h(chunk)))
        request = unpack(message_data)

        if self.script.match_request(request):
            # explicitly matched
            log.debug("C: %s", message_repr(v, request))
        elif self.script.match_auto_request(request):
            # auto matched
            log.debug("C! %s", message_repr(v, request))
        else:
            # not matched
            if self.script.lines:
                expected = message_repr(v, self.script.lines[0].message)
            else:
                expected = "END OF SCRIPT"
            log.debug("C: %s", message_repr(v, request))
            log.error("Message mismatch (expected <%s>, "
                      "received <%s>)", expected, message_repr(v, request))
            self.stop()
            raise SystemExit(EXIT_OFF_SCRIPT)

        responses = self.script.match_responses()
        if not responses and self.script.match_auto_request(request):
            # These are hard-coded and therefore not very future-proof.
            if request.tag in (CLIENT[v].get("HELLO"), CLIENT[v].get("INIT")):
                responses = [
                    Structure(
                        SERVER[v]["SUCCESS"],
                        {"server": server_agents.get(v, "Neo4j/9.99.999")})
                ]
            elif request.tag == CLIENT[v].get("GOODBYE"):
                log.debug("S: <EXIT>")
                self.stop()
                raise SystemExit(EXIT_OK)
            elif request.tag == CLIENT[v]["RUN"]:
                responses = [Structure(SERVER[v]["SUCCESS"], {"fields": []})]
            else:
                responses = [Structure(SERVER[v]["SUCCESS"], {})]
        for response in responses:
            if isinstance(response, Structure):
                data = pack(response)
                self.send_chunk(sock, data)
                self.send_chunk(sock)
                log.debug(
                    "S: %s",
                    message_repr(v, Structure(response.tag, *response.fields)))
            elif isinstance(response, ExitCommand):
                self.stop()
                raise SystemExit(EXIT_OK)
            else:
                raise RuntimeError("Unknown response type %r" % (response, ))
Exemplo n.º 20
0
 def raw_unpack(self, type_code):
     value, = raw_unpack(type_code, self.data, self.offset)
     self.offset += type_sizes[type_code]
     return value