/**
         * Receive a message from the connection. If you set requiredMsgType to the required
         * message type id instead of zero, it will check the incoming message type and
         * raise a PyroException if they don't match.
         */
        public static Message getMessage(Stream connection, int requiredMsgType)
        {
            byte[]        headerdata = IOUtil.recv(connection, HEADER_SIZE);
            MessageHeader header     = parseMessageHeader(headerdata);

            if (requiredMsgType != 0 && header.type != requiredMsgType)
            {
                throw new PyroException("invalid msg type received: " + header.type);
            }
            byte[] data = IOUtil.recv(connection, header.datasize);
            if (Config.MSG_TRACE_DIR != null)
            {
                TraceMessageRecv(header.sequence, headerdata, data);
            }
            if (((header.flags & FLAGS_HMAC) != 0) && (Config.HMAC_KEY != null))
            {
                if (header.hmac != makeHMAC(data))
                {
                    throw new PyroException("message hmac mismatch");
                }
            }
            else if (((header.flags & FLAGS_HMAC) != 0) != (Config.HMAC_KEY != null))
            {
                throw new PyroException("hmac key config not symmetric");
            }

            Message msg = new Message();

            msg.type     = header.type;
            msg.flags    = header.flags;
            msg.sequence = header.sequence;
            msg.data     = data;
            return(msg);
        }
Exemple #2
0
        // Note: this 'chunked' way of sending is not used because it triggers Nagle's algorithm
        // on some systems (linux). This causes massive delays, unless you change the socket option
        // TCP_NODELAY to disable the algorithm. What also works, is sending all the message bytes
        // in one go: connection.send(message.to_bytes())
//    public void send(Stream connection)
//    {
//      // send the message as bytes over the connection
//      IOUtil.send(connection, get_header_bytes());
//      if(annotations_size>0)
//          IOUtil.send(connection, get_annotations_bytes());
//      IOUtil.send(connection, data);
//	}


        /// <summary>
        /// Receives a pyro message from a given connection.
        /// Accepts the given message types (None=any, or pass a sequence).
        /// Also reads annotation chunks and the actual payload data.
        /// Validates a HMAC chunk if present.
        /// </summary>
        public static Message recv(Stream connection, ushort[] requiredMsgTypes, byte[] hmac)
        {
            byte[] header_data = IOUtil.recv(connection, HEADER_SIZE);
            var    msg         = from_header(header_data);

            if (requiredMsgTypes != null && !requiredMsgTypes.Contains(msg.type))
            {
                throw new PyroException(string.Format("invalid msg type {0} received", msg.type));
            }

            byte[] annotations_data = null;
            msg.annotations = new Dictionary <string, byte[]>();
            if (msg.annotations_size > 0)
            {
                // read annotation chunks
                annotations_data = IOUtil.recv(connection, msg.annotations_size);
                int i = 0;
                while (i < msg.annotations_size)
                {
                    string anno              = Encoding.ASCII.GetString(annotations_data, i, 4);
                    int    length            = (annotations_data[i + 4] << 8) | annotations_data[i + 5];
                    byte[] annotations_bytes = new byte[length];
                    Array.Copy(annotations_data, i + 6, annotations_bytes, 0, length);
                    msg.annotations[anno] = annotations_bytes;
                    i += 6 + length;
                }
            }

            // read data
            msg.data = IOUtil.recv(connection, msg.data_size);

            if (Config.MSG_TRACE_DIR != null)
            {
                TraceMessageRecv(msg.seq, header_data, annotations_data, msg.data);
            }

            if (msg.annotations.ContainsKey("HMAC") && hmac != null)
            {
                if (!msg.annotations["HMAC"].SequenceEqual <byte>(msg.hmac(hmac)))
                {
                    throw new PyroException("message hmac mismatch");
                }
            }
            else if (msg.annotations.ContainsKey("HMAC") != (hmac != null))
            {
                // Message contains hmac and local HMAC_KEY not set, or vice versa. This is not allowed.
                throw new PyroException("hmac key config not symmetric");
            }
            return(msg);
        }
Exemple #3
0
        // Note: this 'chunked' way of sending is not used because it triggers Nagle's algorithm
        // on some systems (linux). This causes massive delays, unless you change the socket option
        // TCP_NODELAY to disable the algorithm. What also works, is sending all the message bytes
        // in one go: connection.send(message.to_bytes())
//    public void send(Stream connection)
//    {
//      // send the message as bytes over the connection
//      IOUtil.send(connection, get_header_bytes());
//      if(annotations_size>0)
//          IOUtil.send(connection, get_annotations_bytes());
//      IOUtil.send(connection, data);
//	}


        /// <summary>
        /// Receives a pyro message from a given connection.
        /// Accepts the given message types (None=any, or pass a sequence).
        /// Also reads annotation chunks and the actual payload data.
        /// </summary>
        // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global
        public static Message recv(Stream connection, byte[] requiredMsgTypes)
        {
            var header_data = IOUtil.recv(connection, HEADER_SIZE);
            var msg         = from_header(header_data);

            if (requiredMsgTypes != null && !requiredMsgTypes.Contains(msg.type))
            {
                throw new PyroException($"invalid msg type {msg.type} received");
            }

            byte[] annotations_data = null;
            msg.annotations = new Dictionary <string, byte[]>();
            if (msg.annotations_size > 0)
            {
                // read annotation chunks
                annotations_data = IOUtil.recv(connection, msg.annotations_size);
                int i = 0;
                while (i < msg.annotations_size)
                {
                    string anno              = Encoding.ASCII.GetString(annotations_data, i, 4);
                    int    length            = (annotations_data[i + 4] << 24) | (annotations_data[i + 5] << 16) | (annotations_data[i + 6] << 8) | annotations_data[i + 7];
                    var    annotations_bytes = new byte[length];
                    Array.Copy(annotations_data, i + 8, annotations_bytes, 0, length);
                    msg.annotations[anno] = annotations_bytes;
                    i += 8 + length;
                }
            }

            // read data
            msg.data = IOUtil.recv(connection, msg.data_size);

            if (Config.MSG_TRACE_DIR != null)
            {
                TraceMessageRecv(msg.seq, header_data, annotations_data, msg.data);
            }

            return(msg);
        }