예제 #1
0
        /// <summary>
        /// Contructs a msg from the SSH stream
        /// </summary>
        /// <param name="msg">RSProtoBuffSSHMsg (ref)</param>
        /// <param name="timeOut">timeout in ms ( 0 = default)</param>
        /// <param name="GetHeader">read header or skip to ProtoBufMsg</param>
        /// <returns>success?</returns>
        private bool ReadMsgFromStream(ref RSProtoBuffSSHMsg msg, uint timeOut = 0, bool GetHeader = true)
        {
            if (timeOut == 0)
            {
                timeOut = _timeOut;
            }

            byte[] input = new byte[16], buffer;
            uint   magicCode;

            if (GetHeader)
            {
                // get Header
                if (!ReadFromStream(timeOut, 16, out buffer))
                {
                    return(false);
                }
                buffer.CopyTo(input, 0);

                // read header
                Array.Reverse(input);
                msg.BodySize = BitConverter.ToUInt32(input, 0);
                msg.ReqID    = BitConverter.ToUInt32(input, 4);
                msg.MsgID    = BitConverter.ToUInt32(input, 8);
                magicCode    = BitConverter.ToUInt32(input, 12);

                System.Diagnostics.Debug.WriteLineIf(DEBUG, "rec: ReqID: " + msg.ReqID + " - MsgID: " + msg.MsgID + " - body size: " + msg.BodySize + " byte");

                if (magicCode != msg.MagicCode)
                {
                    System.Diagnostics.Debug.WriteLineIf(DEBUG, "rec: MagicCode mismatch");
                    _findMagicCode = true;
                    _lastSize      = msg.BodySize;
                    _parent.Error(new Exception("MagicCode mismatch"), RSRPC.ErrorFrom.ProtoBuf);
                    return(false);
                }

                if (!IsRpcMsgIdResponse(msg.MsgID))
                {
                    System.Diagnostics.Debug.WriteLineIf(DEBUG, "rec: msg is no response");
                }
            }
            else
            {
                System.Diagnostics.Debug.WriteLineIf(DEBUG, "rec: ReqID: " + msg.ReqID + " - MsgID: " + msg.MsgID + " - body size: " + msg.BodySize + " byte");
            }

            // get ProtoBufMsg
            byte[] PbMsg = new byte[msg.BodySize];
            if (!ReadFromStream(timeOut, msg.BodySize, out buffer))
            {
                return(false);
            }
            buffer.CopyTo(PbMsg, 0);

            msg.ProtoBuffMsg = new MemoryStream();
            msg.ProtoBuffMsg.Write(PbMsg, 0, (int)msg.BodySize);
            msg.ProtoBuffMsg.Position = 0;
            return(true);
        }
예제 #2
0
        /// <summary>
        /// wrapper for ReadMsgFromStream(..)
        /// </summary>
        /// <param name="msg">RSProtoBuffSSHMsg (out)</param>
        /// <param name="timeOut">timeout in ms ( 0 = default)</param>
        /// <returns>success?</returns>
        public bool Receive(out RSProtoBuffSSHMsg msg, uint timeOut = 0)
        {
            msg = new RSProtoBuffSSHMsg();
            if (!_stream.CanRead)
            {
                System.Diagnostics.Debug.WriteLine("rec: cannot read stream!");
                _parent.Error(new IOException("send: can't read stream"), RSRPC.ErrorFrom.ProtoBuf);
                return(false);
            }
            if (!ReadMsgFromStream(ref msg, timeOut))
            {
                System.Diagnostics.Debug.WriteLine("rec: Error receiving data from stream");
                return(false);
            }

            System.Diagnostics.Debug.WriteLineIf(DEBUG, "rec: " + msg.ReqID + " body Length: " + msg.ProtoBuffMsg.Length);
            return(true);
        }
예제 #3
0
        /// <summary>
        /// Converts a msg into a a byte array in network order (ready to send)
        /// </summary>
        /// <param name="msg">input RSProtoBuffSSHMsg to convert</param>
        /// <returns>msg as a byte array</returns>
        private byte[] CreatePacketFromMsg(RSProtoBuffSSHMsg msg)
        {
            byte[] a      = new byte[4];
            byte[] pbMsg  = new byte[msg.BodySize];
            byte[] output = new byte[16 + msg.BodySize];

            a = UintToByteNetwortOrder(msg.MagicCode);
            Array.Copy(a, 0, output, 0, 4);
            a = UintToByteNetwortOrder(msg.MsgID);
            Array.Copy(a, 0, output, 4, 4);
            a = UintToByteNetwortOrder(msg.ReqID);
            Array.Copy(a, 0, output, 8, 4);
            a = UintToByteNetwortOrder(msg.BodySize);
            Array.Copy(a, 0, output, 12, 4);

            msg.ProtoBuffMsg.Read(pbMsg, 0, (int)msg.BodySize);
            msg.ProtoBuffMsg.Position = 0;
            Array.Copy(pbMsg, 0, output, 16, (int)msg.BodySize);

            return(output);
        }
예제 #4
0
파일: RSRPC.cs 프로젝트: nolith/RSSSHClient
        // ---------- send ----------
        // ---------- generic send<T> ----------
        public uint Send <T>(T pbMsg, uint inMsgID)
        {
            if (!_connected)
            {
                Error(new Exception("not connected"), ErrorFrom.RPC);
                return(0);
            }

            RSProtoBuffSSHMsg msg = new RSProtoBuffSSHMsg();

            msg.MsgID        = inMsgID;
            msg.ReqID        = _rsProtoBuf.GetReqID();
            msg.ProtoBuffMsg = new MemoryStream();
            Serializer.Serialize <T>(msg.ProtoBuffMsg, pbMsg);
            msg.ProtoBuffMsg.Position = 0;
            msg.BodySize = (uint)msg.ProtoBuffMsg.Length;

            lock (_sendQueue)
                _sendQueue.Enqueue(msg);

            return(msg.ReqID);
        }
예제 #5
0
        /// <summary>
        /// Wrtites a msg to the SSH stream
        /// </summary>
        /// <param name="msg">msg to send</param>
        /// <returns></returns>
        public uint Send(RSProtoBuffSSHMsg msg)
        {
            System.Diagnostics.Debug.WriteLineIf(DEBUG, "send: sending packet " + msg.ReqID + " MsgID: " + msg.MsgID + " body size: " + msg.BodySize);
            if (_stream.CanWrite)
            {
                try
                {
                    _stream.Write(CreatePacketFromMsg(msg), 0, 16 + (int)msg.BodySize);
                    _stream.Flush();
                }
                catch (Exception e)
                {
                    _parent.Error(e, RSRPC.ErrorFrom.ProtoBuf);
                }
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("send: can't write stream");
                _parent.Error(new IOException("send: can't write stream"), RSRPC.ErrorFrom.ProtoBuf);
            }

            return(msg.ReqID);
        }
예제 #6
0
        /// <summary>
        /// Main loop to send and receive data from the SSH stream.
        ///
        /// Takes msgs from _sendQueue and sends them.
        /// Reads msgs and put them in _receiveQueue for further processing.
        /// Also reconnects when "MagicCode missmatch" occurs.
        ///
        /// Is designed to run in an own thread.
        /// Use _run = false to stop the loop.
        /// Use _finishQueue to send al pending msgs ( won't receive data anymore )
        /// </summary>
        private void mainLoop()
        {
            bool foundWork;
            //byte[] header1 = new byte[4], header234 = new byte[12], buffer = new byte[1024 * 25];
            RSProtoBuffSSHMsg msg = new RSProtoBuffSSHMsg(), newMsg = new RSProtoBuffSSHMsg();

            while (_run)
            {
                foundWork = false;
                if (_stream.DataAvailable && _run && !_finishQueue && !_findMagicCode)
                {
                    System.Diagnostics.Debug.WriteLineIf(DEBUG, "#######################################");
                    System.Diagnostics.Debug.WriteLineIf(DEBUG, "loop: receiving");
                    if (Receive(out newMsg))
                    {
                        lock (_receiveQueue)
                            _receiveQueue.Enqueue(newMsg);
                    }
                    foundWork = true;
                }

                if (_stream.DataAvailable && _findMagicCode)
                {
                    if (!_parent.Reconnect(out _stream))
                    {
                        _parent.Error(new Exception("Error while reconnecting"), RSRPC.ErrorFrom.ProtoBuf);
                        _run = false;
                    }
                    else
                    {
                        _findMagicCode = false;
                    }

                    /*
                     * this doesn't work yet
                     * the idea is to search for the next MagicCode assuming it's the begin of a new msg
                     * but this produce some strange behavior, is very slow and unreliable
                     */

                    //System.Diagnostics.Debug.WriteLineIf(DEBUG, "#######################################");
                    //System.Diagnostics.Debug.WriteLineIf(DEBUG, "loop: trying to find Magic Code ...");

                    //for (short i = 0; i < 1024 * 25 / 4; i++) // 25k too much?
                    //{
                    //    if (!_stream.DataAvailable)
                    //        break;
                    //    if (!ReadFromStream(_timeOut, 4, out header1))
                    //        break;
                    //    //buffer.CopyTo(header1, 0);
                    //    Array.Reverse(header1);
                    //    if (BitConverter.ToUInt32(header1, 0) == msg.MagicCode)
                    //    {
                    //        System.Diagnostics.Debug.WriteLineIf(DEBUG, "loop: found Magic Code");

                    //        // found magic code -> try to receive whole msg
                    //        if (!ReadFromStream(_timeOut, 12, out header234))
                    //            break;
                    //        //buffer.CopyTo(header234, 0);
                    //        Array.Reverse(header234);
                    //        newMsg.BodySize = BitConverter.ToUInt32(header234, 0);
                    //        newMsg.ReqID = BitConverter.ToUInt32(header234, 4);
                    //        newMsg.MsgID = BitConverter.ToUInt32(header234, 8);

                    //        System.Diagnostics.Debug.WriteLineIf(DEBUG, "rec: ReqID: " + msg.ReqID + " - MsgID: " + msg.MsgID + " - body size: " + msg.BodySize + " byte");

                    //        if (!IsRpcMsgIdResponse(msg.MsgID))
                    //        {
                    //            // is no response ( the magic code was a wrong one - or the response was somehow broken )
                    //            System.Diagnostics.Debug.WriteLineIf(DEBUG, "loop: no response");
                    //            continue;
                    //        }

                    //        if (ReadMsgFromStream(msg: ref newMsg, GetHeader: false))
                    //        {
                    //            // there is nothing more we can do here ... just put the msg in the queue and hope the best :D
                    //            System.Diagnostics.Debug.WriteLineIf(DEBUG, "loop: received msg");
                    //            lock (_receiveQueue)
                    //                _receiveQueue.Enqueue(newMsg);
                    //            _findMagicCode = false;
                    //            break;
                    //        }
                    //        else
                    //            System.Diagnostics.Debug.WriteLineIf(DEBUG, "loop: couldn't get msg");
                    //    }
                    //} // for
                    //foundWork = true;
                }

                if (_sendQueue.Count > 0)
                {
                    System.Diagnostics.Debug.WriteLineIf(DEBUG, "#######################################");
                    System.Diagnostics.Debug.WriteLineIf(DEBUG, "loop: sending req");
                    lock (_sendQueue)
                        msg = _sendQueue.Dequeue();
                    Send(msg);
                    foundWork = true;
                }

                if (!foundWork && _run && !_finishQueue)
                {
                    System.Threading.Thread.Sleep(250);
                }

                if (_finishQueue && _sendQueue.Count == 0)
                {
                    _run = false;
                }
            }
        }