Esempio n. 1
0
    def start_connecting(self):
        print "Connecting to %s:%d" % self.address
        self._is_connecting = True
        
        self._socket_to_host = socketutils.new_udp_socket()

        for i in xrange(ATTEMPT_COUNT):
            # Send version to identify both our version and the local port of this connection
            self._socket_to_host.sendto(dumps((self.protocol_version,
                                               self.local_host.id,
                                               self.local_host.name)), self.address)
            # Receive hello as ack and to know the remote port of this particular connection
            try:
                socketutils.wait_for_read([self._socket_to_host], timeout=0.5)
            except socketutils.TimeoutError:
                pass
            else:
                request, remote_address = self._socket_to_host.recvfrom(MAX_PACKET_SIZE)
                request_type, request_data = loads(request)
                if request_type == 'NOTCONNECTING!':
                    raise ConnectionFailed("Other host has stopped connecting to us!")
                assert request_type == 'WELCOME!', "Expected WELCOME, received %r" % (request_type,)
                print "Received welcome response"
                self._publicized_data, host_ids = request_data

                # The welcome is sent from a different port (not the listening port)...
                self._socket_to_host.connect(remote_address)

                self._listener_socks = dict([(socketutils.udp_listener_on(0), (id, name))
                                             for id, name in host_ids])
                self._send_listening_on_ports()
                break
        else:
            raise ConnectionFailed("Cannot connect to given host")
        self.update = self._attempt_connecting
Esempio n. 2
0
    def _send_welcome(self):
        self._sync_actions()
        
        conn = self._awaiting_connection
        remote_hostname, remote_port = conn.remote_address
        # Flood him with WELCOME!'s until he responds...
        conn.sock.send(conn._welcome_to_send)
        try:
            socketutils.wait_for_read([conn.sock], timeout=0.5)
        except socketutils.TimeoutError:
            conn._welcome_count += 1
            if conn._welcome_count >= ATTEMPT_COUNT:
                self.update = self._attempt_listening
                self._awaiting_connection = None
            return

        data = conn.sock.recv(MAX_PACKET_SIZE)
        request_type, ports = loads(data)
        assert request_type == 'listening_on'
        
        self.notify("new_connector2", conn.remote_host_name, conn.remote_address)
        for host, port in zip(self.hosts, ports):
            self.run_action_on(host, 'INTERNAL_connect_to',
                               conn.remote_host_id,
                               conn.remote_host_name,
                               conn.remote_address,
                               (remote_hostname, port))
        self.update = self._attempt_listening
        self._awaiting_connection = None
Esempio n. 3
0
    def _attempt_listening(self):
        self._sync_actions()
        
        if self._awaiting_connection is not None:
            # Cannot handle multiple connection requests at the same time
            return
        try:
            socketutils.wait_for_read([self._listener_sock], timeout=0)
        except socketutils.TimeoutError:
            return
        
        conn = Bunch()
        data, conn.remote_address = self._listener_sock.recvfrom(MAX_PACKET_SIZE)
        remote_hostname, remote_port = conn.remote_address
        remote_version, conn.remote_host_id, conn.remote_host_name = loads(data)
        assert remote_version == self.protocol_version, "Attempt to connect with client of different version"
        if conn.remote_address in self._already_connected:
            # We may be receiving a retransmit of the connection
            # packet from before, anyhow, he is already connected, so
            # ignore it.
            return
        
        self.notify("new_connector1", conn.remote_host_name, conn.remote_address)
        conn.sock=socketutils.new_udp_socket()
        conn.sock.connect(conn.remote_address)
        
        host_ids = [(host.id, host.name) for host in self.hosts]
        welcome_to_send = dumps(('WELCOME!', (self._publicized_data, host_ids)))
        conn._welcome_to_send = welcome_to_send
        conn._welcome_count = 0

        self._awaiting_connection = conn
        self.update = self._send_welcome
Esempio n. 4
0
 def _recv(self, timeout=RECV_FRAME_TIMEOUT):
     # Note that UDP receive will only receive from the correct
     # port due to the connect call from before
     socketutils.wait_for_read([self.sock], timeout=timeout)
     try:
         data = self.sock.recv(MAX_PACKET_SIZE)
     except socket.error, s:
         self._handle_socket_error(s)
         # Convert the disconnected error to another error that may occur
         # when disconnection occurs to unify the error handling.
         raise socketutils.TimeoutError()
Esempio n. 5
0
    def _listen_to_all_create_remote_hosts(self):
        while self._listener_socks:
            read_available = socketutils.wait_for_read(list(self._listener_socks), timeout=60)
            for sock in read_available:
                remote_host_id, remote_host_name = self._listener_socks[sock]
                del self._listener_socks[sock]

                # Get the first Actions packet only to extract
                # iteration_count and the remote address
                
                data, address = sock.recvfrom(MAX_PACKET_SIZE)
                sock.connect(address)
                frame_type, (executed_iteration_count, iterations) = loads(data)
                assert frame_type == 'Actions'

                self.iteration_count = executed_iteration_count

                # Discard this Actions packet
                # It is okay because it is assumed to be losable and
                # because the next packet will contain all of its
                # actions again.

                # The first action set we receive MUST fix the random
                # seed (or we'll be out of sync)

                remote_host = RemoteHost(remote_host_id, remote_host_name, address, sock)
                self._add_remote_host(remote_host)
Esempio n. 6
0
 def _attempt_connecting(self):
     try:
         all_files = [self._socket_to_host] + list(self._listener_socks)
         read_available = socketutils.wait_for_read(all_files, timeout=0)
     except socketutils.TimeoutError:
         return
     
     if read_available == [self._socket_to_host]:
         request, remote_address = self._socket_to_host.recvfrom(MAX_PACKET_SIZE)
         request_type, request_data = loads(request)
         # This can only be WELCOME because UNWELCOME cannot follow WELCOME
         assert request_type == 'WELCOME!', "Expected WELCOME, received %r" % (request_type,)
         # Hmm.. we are Welcome'd again... so appearantly he did not see we sent him our port list..
         self._send_listening_on_ports()
     else:
         # Somebody connects to us! This means that the entire network is in sync, and knows we're in!
         self.notify('got_first_connection')
         self._listen_to_all_create_remote_hosts()
         self.notify('in_network')
         self.update = self._sync_actions