コード例 #1
0
    def _on_entering(self):
        """Acquire network resources and try to connect.

        The connection is authenticated by the mean of the server
        certificate, so it is trusted.
        """
        self.logger.info(u"Connecting to server...")
        self._context._internal_facade.set_global_status(
            GStatuses.NC_CONNECTING)
        if self._context.acquire_network_resources():
            self.logger.info(u"Server has successfully authenticated itself")
            self._context.num_connection_attempts = 0
            self._context._internal_facade.reset_pause_timer()
            self._set_next_state(StateRegister.get('ConnectedState'))
            self._context._input_queue.put(Command('HANDSHAKE'),
                                           'sessioncommand')
        else:
            self._context._internal_facade.set_global_status(
                GStatuses.NC_NOSERVER)
            if self._context.num_connection_attempts > self._context.max_connection_attempts:
                self.logger.error(
                    u'Server has been unreachable for too long, giving up.')
                return self._context._internal_facade.pause_and_restart()
            self._set_next_state(StateRegister.get('DisconnectedState'))
            self._context._input_queue.put(Command('CONNECT'),
                                           'sessioncommand')
コード例 #2
0
ファイル: sync.py プロジェクト: adamnemecek/FileRock-Client
 def _handle_command_OPERATIONSFINISHED(self, command):
     """Receiving this command means that all the internal operations
     have been served. Wait until all of them are complete.
     """
     self._set_next_state(StateRegister.get('SyncWaitingForCompletionState'))
     cmd = Command('GOTOONCOMPLETION')
     cmd.next_state = 'SyncDoneState'
     self._context._input_queue.put(cmd, 'sessioncommand')
コード例 #3
0
    def _set_next_state(self, next_state):
        """Change ServerSession's state.

        @param next_state:
                    Instance of a subclass of ServerSessionState.
        """
        command = Command('CHANGESTATE')
        command.next_state = next_state
        self._context._input_queue.put(command, 'sessioncommand')
コード例 #4
0
    def _set_next_state(self, next_state):
        """Change ServerSession's state.

        @param next_state:
                    Instance of a subclass of ServerSessionState.
        """
        command = Command('CHANGESTATE')
        command.next_state = next_state
        self._context._input_queue.put(command, 'sessioncommand')
コード例 #5
0
    def signal_download_integrity_error(self, operation, reason, expected_etag,
                                        expected_basis, actual_etag,
                                        computed_basis):
        """Tell ServerSession that the integrity check of a downloaded
        file has failed.

        This method is meant to be called by Workers.

        @param operation:
                    Instance of PathnameOperation. Remember that it
                    contains also its Proof object.
        @param reason:
                    String shortly describing the error.
        @param expected_etag:
                    The etag the file was expected to have. It's the one
                    communicated by the server in its file list.
        @param expected_basis:
                    The trusted basis. It's the one the user had
                    accepted when the sync started.
        @param actual_etag:
                    The etag the file has turned to have after being
                    downloaded.
        @param computed_basis:
                    The basis returned by the IntegrityManager when
                    computing the given proof object. Possibly None.
        """
        cmd = Command('INTEGRITYERRORONDOWNLOAD')
        cmd.operation = operation
        cmd.proof = operation.download_info['proof']
        cmd.reason = reason
        cmd.expected_etag = expected_etag
        cmd.expected_basis = expected_basis
        cmd.actual_etag = actual_etag
        cmd.computed_basis = computed_basis
        self._input_queue.put(cmd, 'systemcommand')
コード例 #6
0
 def _exchange_keepalive_message(self):
     #self.logger.debug(
     #    u"Sending KEEP_ALIVE id=%s to server" % self.keepalive_id)
     self.output_message_queue.put(
         KEEP_ALIVE('KEEP_ALIVE', {'id': self.keepalive_id}))
     self.keepalive_id += 1
     if self.keepalive_id > 99999:
         self.keepalive_id = 1
     try:
         while True:
             message = self.input_message_queue.get(
                 block=True, timeout=self.timeout_time)
             if message is POISON_PILL:
                 break
             if message.getParameter('id') == self.keepalive_id - 1:
                 break
     except Queue.Empty:
         self.logger.warning(
             u"Server hasn't replied to KEEP_ALIVE in %s seconds,"
             " assuming crash." % self.timeout_time)
         self._session_queue.put(
             Command('KEEPALIVETIMEDOUT'), 'sessioncommand')
         return
     # Have we been woken up due to suspension?
     if not self._check_suspension():
         # No, it was a normal KEEP_ALIVE reply from the server
         ##self.logger.debug(
         ##    u"Received KEEP_ALIVE reply id=%s from server"
         ##    % (message.getParameter('id')))
         pass
コード例 #7
0
    def _handle_message_COMMIT_DONE(self, message):
        """Everything went well, the server has completed the commit.

        Check the resulting basis sent by the server against our
        candidate basis, if it's valid then finalize the commit by
        updating all internal data structures.
        Finally go into the sync phase, the session can begin at last.
        """
        self.logger.info(u'Commit done')
        server_basis = message.getParameter('new_basis')
        candidate_basis = self._load_candidate_basis()
        previous_basis = self._load_trusted_basis()
        self.logger.debug(u"Server basis: %s" % server_basis)
        self.logger.debug(u"Candidate basis: %s" % candidate_basis)
        self.logger.debug(u"Last trusted basis: %s" % previous_basis)

        # Check the server basis against the candidate basis
        self._context.integrity_manager.setCurrentBasis(candidate_basis)
        self._check_integrity(server_basis)

        # Everything OK, persist the new trusted basis and related metadata
        operations = self._context.transaction_cache.get_all_records()
        operations = [(op_id, op) for (op_id, op, _) in operations]
        self._persist_integrity_metadata(previous_basis, server_basis,
                                         operations)
        self._context.integrity_manager.setCurrentBasis(server_basis)

        self.logger.info(u"Pending commit successfully recovered.")
        self.logger.info(u"Updated basis: %s" % server_basis)
        self._update_user_interfaces(message)
        self._set_next_state(StateRegister.get('ReadyForServiceState'))
        self._context._input_queue.put(Command('STARTSYNCPHASE'),
                                       'sessioncommand')
コード例 #8
0
    def signal_free_worker(self):
        """
        Tell ServerSession that a worker is free to receive new tasks.

        This method is meant to be called by WorkerPool.
        """
        self._input_queue.put(Command('WORKERFREE'), 'systemcommand')
コード例 #9
0
 def _handle_message_REPLICATION_START(self, message):
     """The server is ready to leave the sync phase, too. Let's
     start the Replication & Transfer phase.
     """
     self._set_next_state(
         StateRegister.get('EnteringReplicationAndTransferState'))
     self._context._input_queue.put(
         Command('UPDATEBEFOREREPLICATION'), 'sessioncommand')
コード例 #10
0
    def signal_deletelocal_integrity_error(self, pathname, proof, reason,
                                           expected_basis, computed_basis):
        """Tell ServerSession that the integrity check of a
        pathname to delete locally has failed.

        This method is meant to be called by Workers.

        @param pathname:
                    String representing the pathname.
        @param reason:
                    String shortly describing the error.
        @param expected_basis:
                    The trusted basis. It's the one the user had
                    accepted when the sync started.
        @param computed_basis:
                    The basis returned by the IntegrityManager when
                    computing the given proof object. Possibly None.
        """
        cmd = Command('INTEGRITYERRORONDELETELOCAL')
        cmd.pathname = pathname
        cmd.proof = proof
        cmd.reason = reason
        cmd.expected_basis = expected_basis
        cmd.computed_basis = computed_basis
        self._input_queue.put(cmd, 'systemcommand')
コード例 #11
0
 def run(self):
     self.started = True
     try:
         while not self._termination_requested():
             ready, _, _ = select([self.sock], [], [], 1)
             if ready:
                 msg = self._receive_message()
                 if msg.name == 'KEEP_ALIVE':
                     self.input_keepalive_queue.put(msg)
                 else:
                     self.input_message_queue.put(msg, 'servermessage')
     except ConnectionException:
         self.logger.info(u"Server has closed the connection, aborting")
         self.input_message_queue.put(Command('BROKENCONNECTION'),
                                      'sessioncommand')
     except Exception as e:
         self.logger.warning(u"Detected a connection problem, aborting: %s",
                             e)
         self.input_message_queue.put(Command('BROKENCONNECTION'),
                                      'sessioncommand')
コード例 #12
0
    def signal_deletelocal_integrity_error(
            self, pathname, proof, reason, expected_basis, computed_basis):
        """Tell ServerSession that the integrity check of a
        pathname to delete locally has failed.

        This method is meant to be called by Workers.

        @param pathname:
                    String representing the pathname.
        @param reason:
                    String shortly describing the error.
        @param expected_basis:
                    The trusted basis. It's the one the user had
                    accepted when the sync started.
        @param computed_basis:
                    The basis returned by the IntegrityManager when
                    computing the given proof object. Possibly None.
        """
        cmd = Command('INTEGRITYERRORONDELETELOCAL')
        cmd.pathname = pathname
        cmd.proof = proof
        cmd.reason = reason
        cmd.expected_basis = expected_basis
        cmd.computed_basis = computed_basis
        self._input_queue.put(cmd, 'systemcommand')
コード例 #13
0
    def run(self):
        """Implementation of the threading.Thread.run() method."""
        self._started = True
        try:
            self.worker_pool.start_workers()
            self.keepalive_timer.start()
            self.current_state = StateRegister.get('DisconnectedState')
            curr_basis = self.current_state._load_trusted_basis()
            self.integrity_manager.setCurrentBasis(curr_basis)
            self.logger.info(u'Current basis is: %s' % curr_basis)
            self.current_state._on_entering()
            self._internal_facade.set_global_status(GStatuses.NC_STOPPED)
            if self.auto_start:
                self._input_queue.put(Command('CONNECT'), 'sessioncommand')
            self.cryptoAdapter.start()
            self._scheduler.schedule_action(self.check_encrypted_folder,
                                            name='check_encrypted_folder',
                                            seconds=5,
                                            repeating=True)

            # The event loop
            self._main_loop()

        except UnexpectedMessageException as e:
            self.logger.critical(
                u"Received an unexpected message from the Server while in "
                u"state '%s': %s. Forcing termination." %
                (self.current_state.__class__, str(e)))
            raise

        except ProtocolException as e:
            self.logger.critical(
                u"Detected an unrecoverable error, forcing termination: %s" %
                str(e))
            # Pre-emptive release, just stop before messing up the server
            self.release_network_resources()
            raise

        except Exception as e:
            self.logger.critical(
                u"Forcing termination due to uncaught exception '%s': %s" %
                (e.__class__, e))
            self.logger.debug(u"Last error stacktrace:\n%s" %
                              traceback.format_exc())
            # Pre-emptive release, just stop before messing up the server
            self.release_network_resources()
            raise
コード例 #14
0
    def terminate(self):
        """
        Termination routine for this component.

        Stops the running thread and releases any acquired resource.
        """
        self.logger.debug(u"Terminating Server Session...")
        if self._started:
            self.must_die.set()
            self.worker_pool.terminate()
            self._input_queue.put(Command('TERMINATE'), 'usercommand')
            self.transaction.can_be_committed.set()
            self.join() if self is not threading.current_thread() else None
            self.keepalive_timer.terminate()
            self.release_network_resources()
            self.cryptoAdapter.terminate()
        self.logger.debug(u"Server Session terminanted.")
コード例 #15
0
 def run(self):
     self.started = True
     try:
         msg = None
         while not self._termination_requested():
             if msg == None:
                 msg = self.output_message_queue.get()
             if msg == POISON_PILL:
                 continue
             _, ready, _ = select([], [self.sock], [], 1)
             if ready:
                 self._send_message(msg)
                 msg = None
     except Exception as exception:
         self.logger.warning(u"Detected a connection problem, aborting: %s",
                             exception)
         self._session_queue.put(Command('BROKENCONNECTION'),
                                 'sessioncommand')
コード例 #16
0
 def _handle_message_CHALLENGE_VERIFY_RESPONSE(self, message):
     """Received a reply to our challenge. Did the server authenticate
     us? If not, maybe another client is already connected to this
     account.
     """
     auth_result = message.getParameter('result')
     if auth_result:
         self.logger.info(u"Client has successfully authenticated itself.")
         self._context.output_message_queue.put(
             READY_FOR_SERVICE('READY_FOR_SERVICE'))
         self._context.session_id = message.get_session_id()
         self.logger.debug(u"Received Session id %s from server" %
                           self._context.session_id)
         self._context.keepalive_timer.resume_execution()
         self._set_next_state(StateRegister.get('ReadyForServiceState'))
     else:
         self.logger.error(u"Server rejected client authentication.")
         self._context._internal_facade.set_global_status(
             GStatuses.NC_NOTAUTHORIZED)
         if message.is_other_client_connected():
             client = message.get_other_connected_client()
             if client["client_id"] == 0:
                 other_client_message = u"Your web client is already connected"
             else:
                 other_client_message = \
                     u"Client number %s from computer %s already connected" \
                     % (client["client_id"], client["hostname"])
             self.logger.warning(other_client_message)
             self._context.disconnect_other_client = True
             force_disconnection = self._context._ui_controller.ask_for_user_input(
                 "other_client_connected", client["client_id"],
                 client["hostname"])
             if not force_disconnection == 'ok':
                 self._context._internal_facade.pause()
                 return
             else:
                 self._context.current_state._set_next_state(
                     StateRegister.get('DisconnectedState'))
                 self._context._input_queue.put(Command('CONNECT'),
                                                'sessioncommand')
                 return
         else:
             relink_user(self)
コード例 #17
0
    def signal_download_integrity_error(
            self, operation, reason,
            expected_etag, expected_basis,
            actual_etag, computed_basis):
        """Tell ServerSession that the integrity check of a downloaded
        file has failed.

        This method is meant to be called by Workers.

        @param operation:
                    Instance of PathnameOperation. Remember that it
                    contains also its Proof object.
        @param reason:
                    String shortly describing the error.
        @param expected_etag:
                    The etag the file was expected to have. It's the one
                    communicated by the server in its file list.
        @param expected_basis:
                    The trusted basis. It's the one the user had
                    accepted when the sync started.
        @param actual_etag:
                    The etag the file has turned to have after being
                    downloaded.
        @param computed_basis:
                    The basis returned by the IntegrityManager when
                    computing the given proof object. Possibly None.
        """
        cmd = Command('INTEGRITYERRORONDOWNLOAD')
        cmd.operation = operation
        cmd.proof = operation.download_info['proof']
        cmd.reason = reason
        cmd.expected_etag = expected_etag
        cmd.expected_basis = expected_basis
        cmd.actual_etag = actual_etag
        cmd.computed_basis = computed_basis
        self._input_queue.put(cmd, 'systemcommand')
コード例 #18
0
 def disconnect(self):
     """Make the client disconnect from the client, if connected."""
     # TODO: this method has been temporarly replaced by PAUSE
     self._input_queue.put(Command('DISCONNECT'), 'usercommand')
コード例 #19
0
 def commit(self):
     """Make the client commit the current transaction."""
     self._input_queue.put(Command('USERCOMMIT'), 'usercommand')
コード例 #20
0
 def _handle_command_BROKENCONNECTION(self, command):
     """The connection to the server is broken.
     """
     self.logger.info(u"Detected disconnection from the server")
     self._set_next_state(StateRegister.get('DisconnectedState'))
     self._context._input_queue.put(Command('CONNECT'), 'sessioncommand')
コード例 #21
0
 def _handle_command_USERCOMMIT(self, message):
     """The user has asked to commit, the operation will be recovered on
     next R&T loop.
     """
     self._set_next_state(StateRegister.get('ReplicationAndTransferState'))
     self._context._input_queue.put(Command('USERCOMMIT'), 'sessioncommand')
コード例 #22
0
 def _wake_me_up(self):
     """Callback for the scheduler.
     """
     self._context._input_queue.put(Command('REDECLAREOPERATION'), 'sessioncommand')
コード例 #23
0
 def _check_time_to_commit(self):
     """If it's time to commit, so be it.
     """
     if self._is_time_to_commit():
         self._context._input_queue.put(Command('COMMIT'), 'sessioncommand')
コード例 #24
0
 def connect(self):
     """Make the client connect to the server."""
     self._input_queue.put(Command('CONNECT'), 'usercommand')