Пример #1
0
    def _send(self, frames, publisher):
        """
        Sends the message to the recipient. If the recipient is unreachable, it is dropped from list of peers (and
        associated subscriptions are removed. Any EAGAIN errors are reported back to the publisher.
        :param frames list of frames
        :type frames list
        :param publisher
        :type bytes
        :returns: List of dropped recipients, if any
        :rtype: list

        :Return Values:
        List of dropped recipients, if any
        """
        drop = []
        subscriber = frames[0]
        # Expecting outgoing frames:
        #   [RECIPIENT, SENDER, PROTO, USER_ID, MSG_ID, SUBSYS, ...]
        # _log.debug(f"pubsubservice _send {frames}")

        try:
            # Try sending the message to its recipient
            # Because we are sending directly on the socket we need
            # bytes
            serialized = serialize_frames(frames)
            self._vip_sock.send_multipart(serialized,
                                          flags=NOBLOCK,
                                          copy=False)
        except ZMQError as exc:
            try:
                errnum, errmsg = error = _ROUTE_ERRORS[exc.errno]
            except KeyError:
                error = None
            if exc.errno == EHOSTUNREACH:
                self._logger.debug("Host unreachable {}".format(subscriber))
                drop.append(subscriber)
            elif exc.errno == EAGAIN:
                self._logger.debug("EAGAIN error {}".format(subscriber))
                # Only send EAGAIN errors
                proto, user_id, msg_id, subsystem = frames[2:6]
                frames = [
                    publisher, '', proto, user_id, msg_id, 'error', errnum,
                    errmsg, subscriber, subsystem
                ]
                try:
                    frames = serialize_frames(frames)
                    self._vip_sock.send_multipart(frames,
                                                  flags=NOBLOCK,
                                                  copy=False)
                except ZMQError as exc:
                    # raise
                    pass
        return drop
Пример #2
0
    def _handle_subsystem(self, message):
        """
        Handle the channel subsystem sending multipart data through the socket.
        """
        _log.debug(f"Message received: {message}")
        frames = message.args
        try:
            name = frames[0]
        except IndexError:
            return
        channel = (message.peer, name)
        try:
            ident = self._channels[channel]
        except KeyError:
            # XXX: Handle channel not found
            _log.error(f"Channel {channel} not found!")
            return
        frames[0] = ident

        try:
            memoryview(frames)
            _log.debug("Serializing frames not necessary")
        except TypeError:
            _log.debug("Serializing frames necessary")
            frames = serialize_frames(frames)
        
        _log.debug(f"frames are before send_multipart: {frames}")

        self.socket.send_multipart(frames, copy=False)
Пример #3
0
 def _send_internal(self, frames):
     """
     Send message to internal/local peer
     :param frames: frames
     :return: peer to be dropped if not reachable
     """
     drop = []
     peer = frames[0]
     # Expecting outgoing frames:
     #   [RECIPIENT, SENDER, PROTO, USER_ID, MSG_ID, SUBSYS, ...]
     frames = serialize_frames(frames)
     try:
         # Try sending the message to its recipient
         self._vip_sock.send_multipart(frames, flags=NOBLOCK, copy=False)
     except ZMQError as exc:
         try:
             errnum, errmsg = error = _ROUTE_ERRORS[exc.errno]
         except KeyError:
             error = None
         if exc.errno == EHOSTUNREACH:
             _log.debug("Host unreachable {}".format(peer))
             drop.append(peer)
         elif exc.errno == EAGAIN:
             _log.debug("EAGAIN error {}".format(peer))
     return drop
Пример #4
0
def test_can_serialize_homogeneous_strings():
    original = ["alpha", "beta", "gamma"]
    frames = serialize_frames(original)

    for r in range(len(original)):
        assert original[r] == frames[r].bytes.decode(
            'utf-8'), f"Element {r} is not the same."
Пример #5
0
    def _send_to_socket(self, sock, frames):
        """
        Send specified frames through the passed zmq.Socket.  The frames do not
        have to be true frames.  This function will call `volttron.utils/.rame_serialization.serialize_frames``
        on the list of frames before sending the data.

        :param sock: zmq.Socket
        :param frames:
            A list of frames or data to be sent through a zmq socket.
        :return:
            bool - True if frames were successfully sent.
        """
        success = True

        try:
            frames = serialize_frames(frames)
            _log.debug(f"Frames sent to external {[x.bytes for x in frames]}")
            # Try sending the message to its recipient
            sock.send_multipart(frames, flags=NOBLOCK, copy=False)
        except ZMQError as exc:
            try:
                errnum, errmsg = error = _ROUTE_ERRORS[exc.errno]
            except KeyError:
                success = False
                error = None
            if exc.errno == EHOSTUNREACH or exc.errno == EAGAIN:
                success = False
                raise
        return success
Пример #6
0
 def _send(self, frames):
     issue = self.issue
     socket = self.socket
     drop = []
     recipient, sender = frames[:2]
     # Expecting outgoing frames:
     #   [RECIPIENT, SENDER, PROTO, USER_ID, MSG_ID, SUBSYS, ...]
     try:
         # Try sending the message to its recipient
         # This is a zmq socket so we need to serialize it before sending
         serialized_frames = serialize_frames(frames)
         socket.send_multipart(serialized_frames, flags=NOBLOCK, copy=False)
         issue(OUTGOING, serialized_frames)
     except ZMQError as exc:
         try:
             errnum, errmsg = error = _ROUTE_ERRORS[exc.errno]
         except KeyError:
             error = None
         if error is None:
             raise
         issue(ERROR, frames, error)
         if exc.errno == EHOSTUNREACH:
             drop.append(recipient)
         if exc.errno != EHOSTUNREACH or sender is not frames[0]:
             # Only send errors if the sender and recipient differ
             proto, user_id, msg_id, subsystem = frames[2:6]
             frames = [
                 sender, '', proto, user_id, msg_id, 'error', errnum,
                 errmsg, recipient, subsystem
             ]
             serialized_frames = serialize_frames(frames)
             try:
                 socket.send_multipart(serialized_frames,
                                       flags=NOBLOCK,
                                       copy=False)
                 issue(OUTGOING, serialized_frames)
             except ZMQError as exc:
                 try:
                     errnum, errmsg = error = _ROUTE_ERRORS[exc.errno]
                 except KeyError:
                     error = None
                 if error is None:
                     raise
                 issue(ERROR, serialized_frames, error)
                 if exc.errno == EHOSTUNREACH:
                     drop.append(sender)
     return drop
Пример #7
0
 def send_multipart(self, msg_parts, flags=0, copy=True, track=False):
     parts = serialize_frames(msg_parts)
     # _log.debug("Sending parts on multiparts: {}".format(parts))
     with self._sending(flags) as flags:
         super(_Socket, self).send_multipart(parts,
                                             flags=flags,
                                             copy=copy,
                                             track=track)
Пример #8
0
    def _distribute_external(self, frames):
        """
        Distribute the publish message to external subscribers (platforms)
        :param frames: list of frames
        :return: Number of external subscribers
        """
        publisher, receiver, proto, user_id, msg_id, subsystem, op, topic, data = frames[
            0:9]

        success = False
        external_subscribers = set()
        topic = topic
        for platform_id, subscriptions in self._ext_subscriptions.items():
            for prefix in subscriptions:
                if topic.startswith(prefix):
                    external_subscribers.add(platform_id)
        # self._logger.debug("PUBSUBSERVICE External subscriptions {0}, {1}".format(topic, external_subscribers))
        if external_subscribers:
            frames[:] = []
            frames[
                0:
                7] = '', proto, user_id, msg_id, subsystem, 'external_publish', topic, data
            for platform_id in external_subscribers:
                try:
                    if self._ext_router is not None:
                        self._logger.debug(
                            "Sending to: {}".format(platform_id))
                        # Send the message to the external platform
                        success = self._ext_router.send_external(
                            platform_id, frames)
                except ZMQError as exc:
                    try:
                        errnum, errmsg = error = _ROUTE_ERRORS[exc.errno]
                    except KeyError:
                        error = None
                    if exc.errno == EAGAIN:
                        # Only send EAGAIN errors, so that publisher can try sending again later
                        frames = [
                            publisher, '', proto, user_id, msg_id, 'error',
                            errnum, errmsg, platform_id, subsystem
                        ]
                        try:
                            frames = serialize_frames(frames)
                            self._vip_sock.send_multipart(frames,
                                                          flags=NOBLOCK,
                                                          copy=False)
                        except ZMQError as exc:
                            # raise
                            pass
                    # If external platform is unreachable, drop the all subscriptions
                    if exc.errno == EHOSTUNREACH:
                        self._logger.debug(
                            "Host not reachable: {}".format(platform_id))
                        # self.external_platform_drop(platform_id)
                    else:
                        raise
        return len(external_subscribers)
Пример #9
0
def test_mixed_array():
    original = [
        "alpha",
        dict(alpha=5, gamma="5.0", theta=5.0), "gamma",
        ["from", "to", 'VIP1', ['third', 'level', 'here', 50]]
    ]
    frames = serialize_frames(original)
    for x in frames:
        assert isinstance(x, Frame)

    after_deserialize = deserialize_frames(frames)

    for r in range(len(original)):
        assert original[r] == after_deserialize[
            r], f"Element {r} is not the same."
Пример #10
0
    def rpc_message_handler(self, ch, method, props, body):
        """

        :param ch:
        :param method:
        :param props:
        :param body:
        :return:
        """
        zmq_frames = []
        frames = serialize_frames(jsonapi.loads(body))

        try:
            self.zmq_router.socket.send_multipart(frames, copy=False)
        except ZMQError as ex:
            _log.error("ZMQ Error {}".format(ex))
Пример #11
0
    def outbound_response_handler(self, ch, method, props, body):
        """
        Message received from internal agent to send to remote agent in ZMQ VIP message format.
        :param ch: channel
        :param method: contains routing key
        :param props: message properties like VIP header information
        :param body: message
        :return:
        """
        # Strip sender's identity from binding key
        routing_key = str(method.routing_key)
        platform, to_identity = routing_key.split(".", 1)
        platform, from_identity = props.app_id.split(".", 1)
        userid = props.headers.get('user', '')
        # Reformat message into ZMQ VIP format
        frames = [
            to_identity, from_identity, 'VIP1', userid, props.message_id,
            props.type
        ]

        try:
            args = jsonapi.loads(body)
            try:
                # This is necessary because jsonrpc request/response is inside a list which the
                # ZMQ agent subsystem does not like
                args = jsonapi.loads(args[0])
                frames.append(jsonapi.dumps(args))
            except ValueError as e:
                if isinstance(args, list):
                    for m in args:
                        frames.append(m)
                else:
                    frames.append(jsonapi.dumps(args))
        except TypeError as e:
            _log.error("Invalid json format {}".format(e))
            return

        _log.debug("Proxy ZMQ Router Outbound handler {0}, {1}".format(
            to_identity, args))
        frames = serialize_frames(frames)
        try:
            self.zmq_router.socket.send_multipart(frames, copy=True)
        except ZMQError as ex:
            _log.error("ZMQ Error {}".format(ex))
Пример #12
0
    def _build_connection(self, instance_info):
        """
        Build connection with remote instance and send initial "hello" message.
        :param instance_name: name of remote instance
        :param serverkey: serverkey for establishing connection with remote instance
        :return:
        """
        _log.debug("instance_info {}".format(instance_info))
        try:
            instance_name = instance_info['instance-name']
            serverkey = instance_info['serverkey']
            address = instance_info['vip-address']
        except KeyError as exc:
            _log.error(
                "Missing parameter in instance info message {}".format(exc))
            return

        # Return immediately if vip_address of external instance is same as self address
        if address in self._my_addr:
            _log.debug("Same instance: {}".format(address))
            return
        sock = zmq.Socket(zmq.Context(), zmq.DEALER)
        sock.sndtimeo = 0
        sock.tcp_keepalive = True
        sock.tcp_keepalive_idle = 180
        sock.tcp_keepalive_intvl = 20
        sock.tcp_keepalive_cnt = 6

        num = random.random()
        sock.identity = f"instance.{instance_name}.{num}".encode('utf-8')
        sock.zap_domain = b'vip'
        mon_sock = sock.get_monitor_socket(zmq.EVENT_CONNECTED
                                           | zmq.EVENT_DISCONNECTED
                                           | zmq.EVENT_CONNECT_DELAYED)

        self._poller.register(mon_sock, zmq.POLLIN)
        self._monitor_sockets.add(mon_sock)

        self._instances[instance_name] = dict(platform_identity=sock.identity,
                                              status=STATUS_CONNECTING,
                                              socket=sock,
                                              monitor_socket=mon_sock)

        self._socket_identities[sock.identity] = instance_name
        self._vip_sockets.add(sock)

        self._poller.register(sock, zmq.POLLIN)

        self._routing_table[instance_name] = [instance_name]

        keystore = KeyStore()
        sock = self._instances[instance_name]['socket']

        vip_address = f"{address}?serverkey={serverkey}&publickey={keystore.public}&secretkey={keystore.secret}"

        ext_platform_address = Address(vip_address)
        ext_platform_address.identity = sock.identity
        try:
            ext_platform_address.connect(sock)
            # Form VIP message to send to remote instance
            frames = serialize_frames([
                '', 'VIP1', '', '', 'routing_table', 'hello', 'hello',
                self._my_instance_name
            ])
            _log.debug(f"HELLO Sending hello to: {instance_name}")
            self.send_external(instance_name, frames)
        except zmq.error.ZMQError as ex:
            _log.error("ZMQ error on external connection {}".format(ex))