Esempio n. 1
0
    def connection_request(self, payload):
        """ A request from a peer to connect a port"""
        if not ('peer_port_id' in payload or
                ('peer_actor_id' in payload and
                'peer_port_name' in payload and
                'peer_port_dir' in payload)):
            # Not enough info to find port
            _log.debug("CONNECTION REQUEST failed not enough data")
            return {'reply':"NACK"}
        try:
            port = self._get_local_port(payload['peer_actor_id'], 
                                        payload['peer_port_name'], 
                                        payload['peer_port_dir'], 
                                        payload['peer_port_id'])
        except:
            # We don't have the port
            _log.debug("CONNECTION REQUEST failed not found local")
            return {'reply':"NACK"}
        else:
            if not 'tunnel_id' in payload:
                # TODO implement connection requests not via tunnel
                raise NotImplementedError()
            tunnel = self.tunnels[payload['from_rt_uuid']]
            if tunnel.id != payload['tunnel_id']:
                # For some reason does the tunnel id not match the one we have to connect to the peer
                _log.debug("CONNECTION REQUEST failed not correct tunnel")
                return {'reply':"NACK"}

            if isinstance(port, InPort):
                endp = endpoint.TunnelInEndpoint(port, 
                                                 tunnel, 
                                                 payload['from_rt_uuid'], 
                                                 payload['port_id'], 
                                                 self.node.sched.trigger_loop)
            else:
                endp = endpoint.TunnelOutEndpoint(port, 
                                                  tunnel, 
                                                  payload['from_rt_uuid'], 
                                                  payload['port_id'], 
                                                  self.node.sched.trigger_loop)
                self.monitor.register_out_endpoint(endp)

            invalid_endpoint = port.attach_endpoint(endp)
            # Remove previous endpoint
            if invalid_endpoint:
                if isinstance(invalid_endpoint, endpoint.TunnelOutEndpoint):
                    self.monitor.unregister_out_endpoint(invalid_endpoint)
                invalid_endpoint.destroy()

            # Update storage
            if isinstance(port, InPort):
                self.node.storage.add_port(port, self.node.id, port.owner.id, "in")
            else:
                self.node.storage.add_port(port, self.node.id, port.owner.id, "out")

            return {'reply':"ACK", 'port_id': port.id}
Esempio n. 2
0
    def _connected_via_tunnel(self, reply, **state):
        """ Gets called when remote responds to our request for port connection """
        if reply['reply']=="NACK":
            # Other end did not accept our port connection request
            if state['callback']:
                state['callback'](status="NACK", **state)
                return None

        # Set up the port's endpoint
        tunnel = self.tunnels[state['peer_node_id']]
        port = self.ports[state['port_id']]
        if isinstance(port, InPort):
            endp = endpoint.TunnelInEndpoint(port, 
                                             tunnel, 
                                             state['peer_node_id'], 
                                             reply['port_id'], 
                                             self.node.sched.trigger_loop)
        else:
            endp = endpoint.TunnelOutEndpoint(port, 
                                              tunnel, 
                                              state['peer_node_id'], 
                                              reply['port_id'], 
                                              self.node.sched.trigger_loop)
            # register into main loop
            self.monitor.register_out_endpoint(endp)
        invalid_endpoint = port.attach_endpoint(endp)
        # remove previous endpoint
        if invalid_endpoint:
            if isinstance(invalid_endpoint, endpoint.TunnelOutEndpoint):
                self.monitor.unregister_out_endpoint(invalid_endpoint)
            invalid_endpoint.destroy()

        # Done connecting the port
        if state['callback']:
            state['callback'](status="ACK", **state)

        # Update storage
        if isinstance(port, InPort):
            self.node.storage.add_port(port, self.node.id, port.owner.id, "in")
        else:
            self.node.storage.add_port(port, self.node.id, port.owner.id, "out")
Esempio n. 3
0
    def _connected_via_tunnel(self, reply, **state):
        """ Gets called when remote responds to our request for port connection """
        _log.analyze(self.node.id,
                     "+ " + str(reply),
                     {k: state[k]
                      for k in state.keys() if k != 'callback'},
                     peer_node_id=state['peer_node_id'])
        if reply in [response.BAD_REQUEST, response.NOT_FOUND]:
            # Other end did not accept our port connection request
            if state['retries'] == 0 and state['peer_node_id']:
                # Maybe it is on another node now lets retry and lookup the port
                state['peer_node_id'] = None
                state['retries'] += 1
                self.node.storage.get_port(
                    state['peer_port_id'],
                    CalvinCB(self._connect_by_peer_port_id, **state))
                return None
            if state['callback']:
                state['callback'](status=response.CalvinResponse(
                    response.NOT_FOUND),
                                  **state)
                return None

        if reply == response.GONE:
            # Other end did not accept our port connection request, likely due to they have not got the message
            # about the tunnel in time
            _log.analyze(
                self.node.id,
                "+ RETRY",
                {k: state[k]
                 for k in state.keys() if k != 'callback'},
                peer_node_id=state['peer_node_id'])
            if state['retries'] < 2:
                state['retries'] += 1
                self._connect_via_tunnel(**state)
                return None

        # Set up the port's endpoint
        tunnel = self.tunnels[state['peer_node_id']]
        port = self.ports[state['port_id']]
        if isinstance(port, InPort):
            endp = endpoint.TunnelInEndpoint(port, tunnel,
                                             state['peer_node_id'],
                                             reply.data['port_id'],
                                             self.node.sched.trigger_loop)
        else:
            endp = endpoint.TunnelOutEndpoint(port, tunnel,
                                              state['peer_node_id'],
                                              reply.data['port_id'],
                                              self.node.sched.trigger_loop)
            # register into main loop
            self.monitor.register_out_endpoint(endp)
        invalid_endpoint = port.attach_endpoint(endp)
        # remove previous endpoint
        if invalid_endpoint:
            if isinstance(invalid_endpoint, endpoint.TunnelOutEndpoint):
                self.monitor.unregister_out_endpoint(invalid_endpoint)
            invalid_endpoint.destroy()

        # Done connecting the port
        if state['callback']:
            state['callback'](status=response.CalvinResponse(True), **state)

        # Update storage
        if isinstance(port, InPort):
            self.node.storage.add_port(port, self.node.id, port.owner.id, "in")
        else:
            self.node.storage.add_port(port, self.node.id, port.owner.id,
                                       "out")
Esempio n. 4
0
    def connection_request(self, payload):
        """ A request from a peer to connect a port"""
        _log.analyze(self.node.id,
                     "+",
                     payload,
                     peer_node_id=payload['from_rt_uuid'])
        if not ('peer_port_id' in payload or
                ('peer_actor_id' in payload and 'peer_port_name' in payload
                 and 'peer_port_dir' in payload)):
            # Not enough info to find port
            _log.analyze(self.node.id,
                         "+ NOT ENOUGH DATA",
                         payload,
                         peer_node_id=payload['from_rt_uuid'])
            return response.CalvinResponse(response.BAD_REQUEST)
        try:
            port = self._get_local_port(payload['peer_actor_id'],
                                        payload['peer_port_name'],
                                        payload['peer_port_dir'],
                                        payload['peer_port_id'])
        except:
            # We don't have the port
            _log.analyze(self.node.id,
                         "+ PORT NOT FOUND",
                         payload,
                         peer_node_id=payload['from_rt_uuid'])
            return response.CalvinResponse(response.NOT_FOUND)
        else:
            if not 'tunnel_id' in payload:
                # TODO implement connection requests not via tunnel
                raise NotImplementedError()
            tunnel = self.tunnels[payload['from_rt_uuid']]
            if tunnel.id != payload['tunnel_id']:
                # For some reason does the tunnel id not match the one we have to connect to the peer
                # Likely due to that we have not yet received a tunnel request from the peer that replace our tunnel id
                # Can happen when race of simultaneous link setup and commands can be received out of order
                _log.analyze(self.node.id,
                             "+ WRONG TUNNEL",
                             payload,
                             peer_node_id=payload['from_rt_uuid'])
                return response.CalvinResponse(response.GONE)

            if isinstance(port, InPort):
                endp = endpoint.TunnelInEndpoint(port, tunnel,
                                                 payload['from_rt_uuid'],
                                                 payload['port_id'],
                                                 self.node.sched.trigger_loop)
            else:
                endp = endpoint.TunnelOutEndpoint(port, tunnel,
                                                  payload['from_rt_uuid'],
                                                  payload['port_id'],
                                                  self.node.sched.trigger_loop)
                self.monitor.register_out_endpoint(endp)

            invalid_endpoint = port.attach_endpoint(endp)
            # Remove previous endpoint
            if invalid_endpoint:
                if isinstance(invalid_endpoint, endpoint.TunnelOutEndpoint):
                    self.monitor.unregister_out_endpoint(invalid_endpoint)
                invalid_endpoint.destroy()

            # Update storage
            if isinstance(port, InPort):
                self.node.storage.add_port(port, self.node.id, port.owner.id,
                                           "in")
            else:
                self.node.storage.add_port(port, self.node.id, port.owner.id,
                                           "out")

            _log.analyze(self.node.id,
                         "+ OK",
                         payload,
                         peer_node_id=payload['from_rt_uuid'])
            return response.CalvinResponse(response.OK, {'port_id': port.id})