Beispiel #1
0
    def __disconnect(session_id: int, address: tuple) -> bytes:
        """
        Closes session

        :param session_id: id of session to close
        :param address: address of the client
        :return: answer for the client
        """
        answer = Datagram(Status.OK, Mode.DISCONNECT, session_id)
        utils.log('removed session: ' + str(session_id) + ' : ' + str(address))
        return answer.get_bytes()
Beispiel #2
0
    def __operation(self, session_id: int, operation: int, num_a: float,
                    num_b: float) -> bytes:
        """
        Makes requested calculations

        :param session_id:
        :param operation: id of rewuested operation
        :param num_a: number a
        :param num_b: number b
        :return: answer for the client
        """

        utils.log('received call for ' + Operation.name_from_code(operation) +
                  ' from session: ' + str(session_id))

        answer = Datagram(Status.OK, Mode.OPERATION, session_id, operation,
                          num_a, num_b)
        answer.result_id = self.next_result_id
        result: float

        try:
            if operation == Operation.POWER:
                result = num_a**num_b
            elif operation == Operation.LOG:
                result = log(num_b) / log(num_a)
            elif operation == Operation.GEO_MEAN:
                if num_a * num_b < 0:
                    return self.__error(5, Mode.OPERATION, session_id,
                                        operation)
                result = sqrt(num_a * num_b)
            elif operation == Operation.BIN_COE:
                if num_b > num_a or num_a < 0 or num_b < 0:
                    return self.__error(5, Mode.OPERATION, session_id,
                                        operation)
                result = factorial(num_a) / (factorial(num_a - num_b) *
                                             factorial(num_b))
        except OverflowError:
            return self.__error(Error.MAX_VALUE_EXCEEDED, Mode.OPERATION,
                                session_id, operation)

        if result == float('inf'):
            return self.__error(Error.MAX_VALUE_EXCEEDED, Mode.OPERATION,
                                session_id, operation)

        self.results_storage[session_id][self.next_result_id] = \
            (operation, num_a, num_b, session_id, result, self.next_result_id)

        self.next_result_id += 1

        answer.result = result
        return answer.get_bytes()
Beispiel #3
0
    def __is_alive(self, session_id: int, handler: Thread) -> bytes:
        """
        Handles is alive request

        If session was closed on server, sends information about it to the client

        :param session_id: id of session to close
        :param handler: session handler
        :return: answer for the client
        """

        if self.sessions[handler]:
            answer = Datagram(Status.OK, Mode.IS_ALIVE, session_id)
        else:
            answer = Datagram(Status.REFUSED, Mode.IS_ALIVE, session_id)
        return answer.get_bytes()
Beispiel #4
0
    def __connect(self, address: tuple) -> (bytes, int):
        """
        Establish new session

        :param address: client address
        :return: (answer to the client , given session_id)
        """

        # get id
        self.next_id_lock.acquire()
        given_id = self.next_id
        self.next_id += 1
        self.next_id_lock.release()
        # prepare answer
        answer = Datagram(Status.OK, Mode.CONNECT, given_id)
        utils.log('new session: ' + str(given_id) + ' : ' + str(address[0]))
        return answer.get_bytes(), given_id
Beispiel #5
0
    def __error(code: int,
                mode: int = Mode.ERROR,
                session_id: int = 0,
                operation: int = 0) -> bytes:
        """
        Returns error answer

        :param code: error code
        :param mode: mode in which error occurred
        :param session_id: session id in which error occurred
        :param operation: operation in which error occurred
        :return: error answer for the client
        """
        utils.log(
            Error.name_from_code(code) + ' on session: ' + str(session_id) +
            ' mode: ' + Mode.name_from_code(mode), True)
        error = Datagram(Status.ERROR, mode, session_id, operation, a=code)
        return error.get_bytes()
Beispiel #6
0
    def __send_datagram(self, datagram: Datagram) -> List[Datagram]:
        """
        Sends data to the server

        :param datagram: data to send
        :return: list of answers
        """
        self.socket.sendall(datagram.get_bytes())
        answer = list()
        last = False

        # receive data until last flag is send to true
        while last is False:
            # get data
            answer_bin = self.socket.recv(DATAGRAM_SIZE)
            try:
                # decode data
                answer_data = Datagram.from_bytes(answer_bin)
            except (bitstring.ReadError, ValueError, TypeError) as e:
                # if data was unreadable
                utils.log('error reading datagram: ' + str(e), True)
                print('error reading datagram')
            else:
                # check last flag
                if answer_data.last:
                    last = True

                # proceed received errors
                if answer_data.status == Status.ERROR:
                    print('error on server: ' +
                          Mode.name_from_code(answer_data.mode) + ' - ' +
                          Error.name_from_code(answer_data.a))
                elif answer_data.status == Status.REFUSED:
                    print('server refused to ' +
                          Mode.name_from_code(answer_data.mode) + ' reason: ' +
                          Error.name_from_code(answer_data.a))

                # add received data to answers
                answer.append(answer_data)

        return answer
Beispiel #7
0
 def __query_by_session_id(self):
     datagram = Datagram(Status.NEW, Mode.QUERY_BY_SESSION_ID,
                         self.session_id)
     answer = self.__send_datagram(datagram)
     if answer[0].status == Status.OK:
         for result in answer:
             print('session_id = ' + str(result.session_id) + "\t" +
                   ' result id = ' + str(result.result_id) + "\t" +
                   ' operation: ' +
                   str(Operation.name_from_code(result.operation)) + "\t" +
                   ' a = ' + str(result.a) + "\t" + ' b = ' +
                   str(result.b) + "\t" + ' result = ' + str(result.result))
Beispiel #8
0
    def __query_by_result_id(self, session_id: int, given_session_id: int,
                             result_id: int) -> bytes:
        """
        Gets one result

        :param session_id: id of session to look for
        :param given_session_id: id of session requesting query
        :param result_id: id of result to look for
        :return: answer for the client
        """
        utils.log('querying by result id: ' + str(result_id) + 'for ' +
                  str(given_session_id))

        if session_id != given_session_id:
            return self.__error(Error.UNAUTHORISED, Mode.QUERY_BY_SESSION_ID,
                                session_id)

        if session_id not in self.results_storage:
            return self.__error(Error.NOT_EXISTING_DATA,
                                Mode.QUERY_BY_SESSION_ID_CMD)

        session_results = self.results_storage[session_id]

        if result_id not in session_results:
            return self.__error(Error.UNAUTHORISED, Mode.QUERY_BY_RESULT_ID,
                                session_id)

        answer = Datagram(
            Status.OK,
            Mode.QUERY_BY_RESULT_ID,
            session_id,
            operation=self.results_storage[session_id][result_id][0],
            a=self.results_storage[session_id][result_id][1],
            b=self.results_storage[session_id][result_id][2],
            result=self.results_storage[session_id][result_id][4],
            result_id=result_id,
        )

        return answer.get_bytes()
Beispiel #9
0
 def __query_by_result_id(self, result_id: int):
     datagram = Datagram(Status.NEW,
                         Mode.QUERY_BY_RESULT_ID,
                         self.session_id,
                         result_id=result_id)
     answer = self.__send_datagram(datagram)[0]
     if answer.status == Status.OK:
         # TODO: [Artur] improve presentation of result
         print('session_id = ' + str(answer.session_id) + "\t" +
               ' result id = ' + str(answer.result_id) + "\t" +
               ' operation: ' +
               str(Operation.name_from_code(answer.operation)) + "\t" +
               ' a = ' + str(answer.a) + "\t" + ' b = ' + str(answer.b) +
               "\t" + ' result = ' + str(answer.result))
Beispiel #10
0
    def __query_by_session_id(self, session_id: int, given_session_id: int,
                              connection: socket) -> bytes:
        """
        Gets all results of session

        :param session_id: id of session to look for
        :param given_session_id: id of session requesting query
        :param connection: connection socket
        :return: answer for the client
        """
        utils.log('querying by session_id: ' + str(session_id) + ' for ' +
                  str(given_session_id))

        if session_id != given_session_id:
            return self.__error(Error.UNAUTHORISED, Mode.QUERY_BY_SESSION_ID,
                                session_id)

        if session_id not in self.results_storage:
            return self.__error(Error.NOT_EXISTING_DATA,
                                Mode.QUERY_BY_SESSION_ID)

        if not self.results_storage[session_id]:
            return self.__error(Error.NOT_EXISTING_DATA,
                                Mode.QUERY_BY_SESSION_ID)

        results = self.results_storage[session_id]
        answer: List[Datagram] = list()
        for result_id, result in results.items():
            answer.append(
                Datagram(Status.OK,
                         Mode.QUERY_BY_SESSION_ID,
                         session_id,
                         operation=result[0],
                         a=result[1],
                         b=result[2],
                         result=result[4],
                         result_id=result_id,
                         last=False))

        # send all except last results to the client
        for i in range(0, len(answer) - 1):
            connection.sendall(answer[i].get_bytes())

        # return last result to send
        answer[len(answer) - 1].last = True
        return answer[len(answer) - 1].get_bytes()
Beispiel #11
0
    def __connect(self) -> None:
        """ Connects to the server """

        self.connected_lock.acquire()
        utils.log('connecting to : ' + self.host + ':' + str(self.port))
        # connect to the server
        self.socket.connect((self.host, self.port))
        # get session id
        datagram = Datagram(Status.NEW, Mode.CONNECT)
        answer = self.__send_datagram(datagram)[0]
        self.session_id = answer.session_id
        if answer.status == Status.OK:
            utils.log('connected to : ' + self.host + ':' + str(self.port))
            self.connected = True
        else:
            utils.log(self.host + ':' + str(self.port) + ' refused to connect')
            self.connected = False
        self.connected_lock.release()
Beispiel #12
0
    def __disconnect(self) -> None:
        """ Disconnects from the server """

        self.connected_lock.acquire()
        utils.log('disconnecting from : ' + self.host + ':' + str(self.port))
        # send disconnect request
        datagram = Datagram(Status.NEW, Mode.DISCONNECT, self.session_id)
        answer = self.__send_datagram(datagram)[0]
        if answer.status == Status.OK:
            utils.log('disconnected from : ' + self.host + ':' +
                      str(self.port))
            # close connection
            self.socket.close()
            self.connected = False
        else:
            utils.log(
                'cannot disconnect from : ' + self.host + ':' +
                str(self.port) + ' error code: ' + str(answer.a), True)
        self.connected_lock.release()
Beispiel #13
0
    def __is_alive(self) -> None:
        """ Checks if server is still available"""

        while self.connected:
            self.connected_lock.acquire()
            datagram = Datagram(Status.NEW, Mode.IS_ALIVE, self.session_id)
            answer: List[Datagram]

            try:
                answer = self.__send_datagram(datagram)[0]
            except (ConnectionAbortedError, ConnectionResetError):
                utils.log('server went down')
                self.connected = False

            if answer.status != Status.OK:
                utils.log('server rejected session')
                self.connected = False
            if not self.connected:
                print('press ENTER to exit')
            self.connected_lock.release()
            time.sleep(1)
Beispiel #14
0
    def handle_incoming_connection(self, connection: socket, address: tuple,
                                   handler: Thread) -> None:
        """
        Handles session

        :param connection: socket with established cconnection
        :param address: address of client
        :param handler: handler object
        """

        # create variable for storing id
        session_id = 0

        # handle requests
        while self.sessions[handler]:
            try:
                # receive data
                data = connection.recv(DATAGRAM_SIZE)
                answer: Datagram = None
                # noinspection PyBroadException
                try:
                    # decode data
                    datagram = Datagram.from_bytes(data)
                    # utils.log('received: ' + str(datagram))
                    answer: bytes
                    if datagram.mode == Mode.CONNECT:
                        answer, session_id = self.__connect(address)
                        self.results_storage[session_id] = {}
                    elif datagram.session_id == session_id:
                        if datagram.mode == Mode.IS_ALIVE:
                            answer = self.__is_alive(datagram.session_id,
                                                     handler)
                        elif datagram.mode == Mode.DISCONNECT:
                            answer = self.__disconnect(datagram.session_id,
                                                       address)
                            self.sessions[handler] = False
                        elif datagram.mode == Mode.OPERATION:
                            answer = self.__operation(datagram.session_id,
                                                      datagram.operation,
                                                      datagram.a, datagram.b)
                        elif datagram.mode == Mode.QUERY_BY_SESSION_ID:
                            answer = self.__query_by_session_id(
                                session_id, datagram.session_id, connection)
                        elif datagram.mode == Mode.QUERY_BY_RESULT_ID:
                            answer = self.__query_by_result_id(
                                session_id, datagram.session_id,
                                datagram.result_id)
                    else:
                        # if authorization didn't succeed
                        answer = self.__error(Error.UNAUTHORISED)
                except (bitstring.ReadError, ValueError, TypeError) as e:
                    # if data was unreadable
                    utils.log("datagram exception: " + str(e), True)
                    answer = self.__error(Error.CANNOT_READ_DATAGRAM,
                                          Mode.ERROR, session_id)
                except Exception as e:
                    # if any other exception occurred
                    utils.log("exception: " + str(e), True)
                    answer = self.__error(Error.INTERNAL_SERVER_ERROR,
                                          Mode.ERROR, session_id)
                finally:
                    # send answer to the client
                    connection.sendall(answer)
            except (ConnectionAbortedError, ConnectionResetError):
                # if session was closed unsafely
                utils.log('breaking listening for session: ' + str(session_id))
                self.sessions[handler] = False

        # after closing session safely close connection
        connection.close()
        utils.log('session closed: ' + str(session_id))
Beispiel #15
0
 def __operation(self, operation: int, a: float, b: float):
     datagram = Datagram(Status.NEW, Mode.OPERATION, self.session_id,
                         operation, a, b)
     answer = self.__send_datagram(datagram)[0]
     if answer.status == Status.OK:
         print(str(answer.result) + '\t:' + str(answer.result_id))