예제 #1
0
    def connect(self, address):
        """
        Connect the socket to a remote address.  For IP sockets, the address
        is a pair (host, port).

        Please note: only support SOCK_RE mode,
        A socket may only connect if it's unbound (clean socket)

        :param address: YO remote address ('A.B')
        """
        with self.main_lock:
            if self.__protocol != SOCK_RE:
                raise YOREUnsupportedProtocolAction("Unexpected cmd for this socket. Use with SOCK_RE",
                                                    SOCK_RE, self.__protocol)
            if self.__state != STATE.NONE:
                raise YOREUnsupportedProtocolAction("Error, must be in STATE %d to connect" % STATE.NONE,
                                                    STATE.NONE, self.__state)
            host, port = address
            self.__yo_dest = host

            if type(host) is str:
                a, b = host.split(".")
                self.__yo_dest = struct.unpack(">H", struct.pack(">BB", int(a), int(b)))[0]
            self.re_port = port

            args = [self.__yo_dest, self.re_port]

            return self.__safe_send_and_recv_ipc(SERIALIZER_CMD.CONNECT, STATE.NONE, args,
                                             upgrade_state_if_successful=STATE.CONNECTION_ESTABLISHED)[0]
예제 #2
0
    def recvfrom(self, buffer_size):
        """
        Receive From command. This function is blocking until there's data to receive.
        Notice that like real sockets, stating buffer_size does not necessarily mean the whole
        buffer is going to get filled. When the ProtocolDaemon has data to send back, it will do so.
        The buffer_size indicates the maximum data size that the user is able to chew at the moment.
        NON-BLOCKING MODE: May return false if disconnected
        BLOCKING MODE: May raise YOREException if disconnected

        Please note: only support SOCK_RAW mode
        :param buffer_size: max buffer length to receive
        :return: (address, buffer)
        """
        with self.main_lock:
            if self.__protocol != SOCK_RAW:
                raise YOREUnsupportedProtocolAction("Unexpected cmd for this socket. Use with SOCK_RAW",
                                                    SOCK_RAW, self.__protocol)

            (res, data) = self.__safe_send_and_recv_ipc(SERIALIZER_CMD.RECVFROM, STATE.BOUND,
                                                        [buffer_size], return_command_types=(SERIALIZER_CMD.RECVFROM,
                                                                                             SERIALIZER_CMD.RECV_EMPTY,
                                                                                             SERIALIZER_CMD.CLOSE))

            if data[0] == SERIALIZER_CMD.RECV_EMPTY:
                if self.__blocking == BLOCKING:
                    raise YORETimeoutException
                else:
                    return False

            res = ((data[1], data[2]) if data[0] == SERIALIZER_CMD.RECVFROM else False) if res else False

            # addition - add exception
            if self.__blocking == BLOCKING and res == False:
                raise YOREException
            return res
예제 #3
0
    def __safe_send_and_recv_ipc(self, command_type, should_be_in_state, args, upgrade_state_if_successful=None,
                                 return_command_types=None):
        """
        send and recv ipc with many security checks according to the parameters.

        for example: to send ipc of "SEND" command we will send SERIALIZER_CMD.SEND and expect to get
        reply with the same enum. Also we demand that our state will be STATE.CONNECTION_ESTABLISHED

        can raise YOREUnsupportedProtocolAction, YOREDaemonToAPIValueError

        :param command_type: SERIALIZER_CMD enum - the cmd to send
        :param should_be_in_state: STATE enum - what self.state should be
        :param args: [data] - to send to the ipc
        :param upgrade_state_if_successful: STATE enum - if everything goes fine - change self.state to new one
        :param return_command_types: SERIALIZER_CMD enum list - what to expect to receive -
        - if None will use the command_type instead
        :return: (True, [data]) or (False,None)
        """
        if return_command_types is None:
            return_command_types = [command_type]

        # Failure check
        if should_be_in_state is not None and self.__state != should_be_in_state:
            raise YOREUnsupportedProtocolAction("Error, must be in STATE %d to connect" % should_be_in_state,
                                                should_be_in_state, self.__state)

        # The real job is in here - send the ipc to the daemon and receive an answer

        result, data = self.__send_and_recv_ipc(command_type, args)

        # Failure checks
        if result == self.__serializer.RESULT_ERROR:
            if self.__state != STATE.NONE:
                self.__state = STATE.NONE
                self.__ipc.close()
            if len(data) == 3:
                raise YOREProtocolError(data[1], data[2])
            elif len(data) == 2:
                raise YOREProtocolError(data[1])
            else:
                raise YOREProtocolError()
        elif result != self.__serializer.RESULT_SUCCESS:
            self.__state = STATE.NONE
            self.__ipc.close()
            raise YOREDaemonToAPIValueError(
                "Got an unexpected cmd result %d for cmd %d. closing socket!" % (result, command_type),
                result, command_type)
        if command_type not in return_command_types:
            self.__state = STATE.NONE
            self.__ipc.close()
            raise YOREDaemonToAPIValueError(
                "Got an unexpected cmd type %d for cmd %d. closing socket!" % (data[0], command_type),
                [0], command_type)

        # If we got to here - success!
        if upgrade_state_if_successful is not None:
            self.__state = upgrade_state_if_successful
        return True, data
예제 #4
0
    def listen(self, backlog=1):
        """
        Socket listen command - listens for new connections.

        Please note: only support SOCK_RE mode,
        A socket may only listen if it's bound to an address

        :param backlog: At the moment, we don't care about listen "backlog" functionality, and
        we only maintain this parameter to keep the listen identical to a normal
        socket's listen.
        """
        with self.main_lock:
            if self.__protocol != SOCK_RE:
                raise YOREUnsupportedProtocolAction("Unexpected cmd for this socket. Use with SOCK_RE",
                                                    SOCK_RE, self.__protocol)
            return self.__safe_send_and_recv_ipc(SERIALIZER_CMD.LISTEN, STATE.BOUND, [backlog],
                                                 upgrade_state_if_successful=STATE.LISTEN)[0]
예제 #5
0
    def accept(self):
        """
        Accept command.
        On success, This command returns a new Resocket (initialized with the
        correct YO address, destination port and session id), and the YO

        Please note: only support SOCK_RE mode
        """
        with self.main_lock:
            if self.__protocol != SOCK_RE:
                raise YOREUnsupportedProtocolAction("Unexpected cmd for this socket. Use with SOCK_RE",
                                                    SOCK_RE, self.__protocol)

            (res, data) = self.__safe_send_and_recv_ipc(SERIALIZER_CMD.ACCEPT, STATE.LISTEN, [])

            if not res:
                return None
            yo_addr, self.__yo_dest, re_port, self.__sid, last_packet = data[1:6]
            accept_parameters = [self.__yo_dest, re_port, self.__sid, last_packet, self.__blocking, self.__timeout]
            return Resocket(SOCK_RE, accept_params=accept_parameters, daemon_port=self.daemon_port), self.__yo_dest
예제 #6
0
    def send(self, send_data):
        """
        Send data command.
        May raise YOREException if disconnected

        Please note: only support SOCK_RE mode
        :param send_data: buffer as string. if  is empty - ignores and return None
        """
        with self.main_lock:
            if send_data is None or send_data == '':
                return None

            if self.__protocol != SOCK_RE:
                raise YOREUnsupportedProtocolAction("Unexpected cmd for this socket. Use with SOCK_RE",
                                                    SOCK_RE, self.__protocol)

            res = self.__safe_send_and_recv_ipc(SERIALIZER_CMD.SEND, STATE.CONNECTION_ESTABLISHED, [send_data])[0]

            # addition - add exception
            if res == False or res is None:
                raise YOREException
            return res
예제 #7
0
    def sendto(self, address, send_data):
        """
        Sendto data command
        May raise YOREException if disconnected

        Please note: only support SOCK_RAW mode
        :param address: YO remote address ('A.B')
        :param send_data: buffer as string. if  is empty - ignores and return None
        """
        with self.main_lock:
            if send_data is None or send_data == '':
                return None

            if self.__protocol != SOCK_RAW:
                raise YOREUnsupportedProtocolAction("Unexpected cmd for this socket. Use with SOCK_RAW",
                                                    SOCK_RAW, self.__protocol)

            res = self.__safe_send_and_recv_ipc(SERIALIZER_CMD.SENDTO, None, [address, send_data])[0]

            # addition - add exception
            if res == False or res is None:
                raise YOREException
            return res