Beispiel #1
0
        protected bool encryptMessage(FunapiMessage message, EncryptionType type, ref string header)
        {
            if (!encryptors_.ContainsKey(type))
            {
                Log("Unknown encryption: {0}", type);
                return(false);
            }

            Encryptor encryptor = encryptors_[type];

            if (encryptor == null || encryptor.state != Encryptor.State.kEstablished)
            {
                Log("Invalid encryption: {0}", type);
                return(false);
            }

            if (message.buffer.Count > 0)
            {
                Int64 nSize = encryptor.Encrypt(message.buffer, message.buffer, ref header);
                if (nSize <= 0)
                {
                    Log("Failed to encrypt.");
                    return(false);
                }

                FunDebug.Assert(nSize == message.buffer.Count);
            }

            return(true);
        }
Beispiel #2
0
        void onReceived(string channel_id, string sender, object data)
        {
            if (encoding_ == FunEncoding.kJson)
            {
                string text = json_helper_.GetStringField(data, kMessage);

                lock (chat_channel_lock_)
                {
                    if (chat_channels_.ContainsKey(channel_id))
                    {
                        chat_channels_[channel_id](channel_id, sender, text);
                    }
                }
            }
            else
            {
                FunDebug.Assert(data is FunMulticastMessage);
                FunMulticastMessage mcast_msg = data as FunMulticastMessage;

                object         obj      = FunapiMessage.GetMessage(mcast_msg, MulticastMessageType.chat);
                FunChatMessage chat_msg = obj as FunChatMessage;

                lock (chat_channel_lock_)
                {
                    if (chat_channels_.ContainsKey(channel_id))
                    {
                        chat_channels_[channel_id](channel_id, sender, chat_msg.text);
                    }
                }
            }
        }
Beispiel #3
0
        public bool SendText(string channel_id, string text)
        {
            if (!Connected)
            {
                return(false);
            }

            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast_msg = new Dictionary <string, object>();
                mcast_msg[kChannelId] = channel_id;
                mcast_msg[kBounce]    = true;
                mcast_msg[kMessage]   = text;

                SendToChannel(mcast_msg);
            }
            else
            {
                FunChatMessage chat_msg = new FunChatMessage();
                chat_msg.text = text;

                FunMulticastMessage mcast_msg = FunapiMessage.CreateFunMessage(chat_msg, MulticastMessageType.chat);
                mcast_msg.channel = channel_id;
                mcast_msg.bounce  = true;

                SendToChannel(mcast_msg);
            }

            return(true);
        }
Beispiel #4
0
        protected bool encryptMessage(FunapiMessage message, EncryptionType type, ref string header)
        {
            if (!encryptors_.ContainsKey(type))
            {
                LogWarning("Encryptor.encryptMessage - Unavailable type: {0}", type);
                return(false);
            }

            Encryptor encryptor = encryptors_[type];

            if (encryptor.state != Encryptor.State.kEstablished)
            {
                LogWarning("Encryptor.encryptMessage - Can't encrypt '{0}' message. " +
                           "Encryptor state is not established. state: {1}",
                           message.msg_type, encryptor.state);
                return(false);
            }

            if (message.buffer.Count > 0)
            {
                Int64 nSize = encryptor.Encrypt(message.buffer, message.buffer, ref header);
                if (nSize <= 0)
                {
                    LogWarning("Encryptor.encryptMessage - Failed to encrypt.");
                    return(false);
                }

                FunDebug.Assert(nSize == message.buffer.Count);
            }

            return(true);
        }
Beispiel #5
0
        protected EncryptionType getEncryption(FunapiMessage message)
        {
            if (message.enc_type != EncryptionType.kDefaultEncryption)
            {
                return(message.enc_type);
            }

            return(default_encryptor_);
        }
        public bool JoinChannel(string channel_id, string token, ChannelMessage handler)
        {
            if (!Connected)
            {
                FunDebug.LogWarning("Multicast.JoinChannel - Multicast is not connected.\n" +
                                    "Please connect first before join a multicast channel.");
                return(false);
            }

            lock (channel_lock_)
            {
                if (channels_.ContainsKey(channel_id))
                {
                    FunDebug.LogWarning("Multicast.JoinChannel - Already joined the '{0} channel.", channel_id);
                    return(false);
                }

                channels_.Add(channel_id, handler);
            }

            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast_msg = new Dictionary <string, object>();
                mcast_msg[kChannelId] = channel_id;
                mcast_msg[kSender]    = sender_;
                mcast_msg[kJoin]      = true;

                if (token != null && token.Length > 0)
                {
                    mcast_msg[kToken] = token;
                }

                session_.SendMessage(kMulticastMsgType, mcast_msg);
            }
            else
            {
                FunMulticastMessage mcast_msg = new FunMulticastMessage();
                mcast_msg.channel = channel_id;
                mcast_msg.sender  = sender_;
                mcast_msg.join    = true;

                if (token != null && token.Length > 0)
                {
                    mcast_msg.token = token;
                }

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast_msg, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg);
            }

            FunDebug.Log("Multicast - Request to join '{0}' channel", channel_id);

            return(true);
        }
 void onReceivedMessage(string msg_type, object body)
 {
     if (encoding_ == FunEncoding.kJson)
     {
         onReceivedMessage(body);
     }
     else
     {
         FunMessage          msg   = body as FunMessage;
         FunMulticastMessage mcast = FunapiMessage.GetMessage <FunMulticastMessage>(msg, MessageType.multicast);
         if (mcast != null)
         {
             onReceivedMessage(mcast);
         }
     }
 }
Beispiel #8
0
        public bool JoinChannel(string channel_id, ChannelMessage handler)
        {
            if (!Connected)
            {
                FunDebug.Log("Not connected. First connect before join a multicast channel.");
                return(false);
            }

            lock (channel_lock_)
            {
                if (channels_.ContainsKey(channel_id))
                {
                    FunDebug.Log("Already joined the channel: {0}", channel_id);
                    return(false);
                }

                channels_.Add(channel_id, handler);
            }

            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast_msg = new Dictionary <string, object>();
                mcast_msg[kChannelId] = channel_id;
                mcast_msg[kSender]    = sender_;
                mcast_msg[kJoin]      = true;

                session_.SendMessage(kMulticastMsgType, mcast_msg);
            }
            else
            {
                FunMulticastMessage mcast_msg = new FunMulticastMessage();
                mcast_msg.channel = channel_id;
                mcast_msg.sender  = sender_;
                mcast_msg.join    = true;

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast_msg, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg);
            }

            FunDebug.Log("Request to join '{0}' channel", channel_id);

            return(true);
        }
        bool sendToChannel(string channel_id, object message)
        {
            if (message == null)
            {
                return(false);
            }

            if (string.IsNullOrEmpty(channel_id))
            {
                FunDebug.LogWarning("[Multicast] can't send a message. invalid channel id.");
                return(false);
            }

            if (!Connected)
            {
                FunDebug.LogWarning("[Multicast] can't send a message. session is not connected.");
                return(false);
            }

            if (!InChannel(channel_id))
            {
                FunDebug.LogWarning("[Multicast] can't send a message. you aren't in '{0}' channel.", channel_id);
                return(false);
            }

            if (encoding_ == FunEncoding.kJson)
            {
                json_helper_.SetStringField(message, kSender, sender_);

                session_.SendMessage(kMulticastMsgType, message, protocol_);
            }
            else
            {
                FunMulticastMessage mcast = message as FunMulticastMessage;
                mcast.sender = sender_;

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg, protocol_);
            }

            return(true);
        }
        void requestToJoin(string channel_id, string token)
        {
            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast = new Dictionary <string, object>();
                mcast[kChannelId] = channel_id;
                mcast[kSender]    = sender_;
                mcast[kJoin]      = true;

                if (!string.IsNullOrEmpty(token))
                {
                    mcast[kToken] = token;
                }

                session_.SendMessage(kMulticastMsgType, mcast, protocol_);
            }
            else
            {
                FunMulticastMessage mcast = new FunMulticastMessage();
                mcast.channel = channel_id;
                mcast.sender  = sender_;
                mcast.join    = true;

                if (!string.IsNullOrEmpty(token))
                {
                    mcast.token = token;
                }

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg, protocol_);
            }

            if (!string.IsNullOrEmpty(token))
            {
                lock (token_lock_)
                {
                    tokens_[channel_id] = token;
                }
            }

            FunDebug.Log("[Multicast] requested to join '{0}' channel.", channel_id);
        }
        protected override void onMessageCallback(string channel_id, string user_id, object message)
        {
            if (encoding_ == FunEncoding.kJson)
            {
                string text = json_helper_.GetStringField(message, kMessage);

                base.onMessageCallback(channel_id, user_id, text);
            }
            else
            {
                FunMulticastMessage mcast = message as FunMulticastMessage;
                FunChatMessage      chat  = FunapiMessage.GetMulticastMessage <FunChatMessage>(mcast, MulticastMessageType.chat);
                if (chat == null)
                {
                    return;
                }

                base.onMessageCallback(channel_id, user_id, chat.text);
            }
        }
        /// The 'channel_id' field is mandatory.
        /// The 'sender' must fill in the message.
        /// The message shouldn't include join and leave flags.
        public bool SendToChannel(FunMulticastMessage mcast_msg)
        {
            if (mcast_msg == null)
            {
                return(false);
            }

            FunDebug.Assert(!mcast_msg.join);
            FunDebug.Assert(!mcast_msg.leave);

            string channel_id = mcast_msg.channel;

            if (channel_id == "")
            {
                FunDebug.LogWarning("Multicast.SendToChannel - You should set a vaild channel id.");
                return(false);
            }

            lock (channel_lock_)
            {
                if (!Connected)
                {
                    FunDebug.LogWarning("Multicast.SendToChannel - Multicast is not connected.\n" +
                                        "If you are trying to send a message in which you were, " +
                                        "connect first while preserving the session id you used for join.");
                    return(false);
                }
                if (!channels_.ContainsKey(channel_id))
                {
                    FunDebug.LogWarning("Multicast.SendToChannel - You are not in the '{0} channel.", channel_id);
                    return(false);
                }
            }

            mcast_msg.sender = sender_;

            FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast_msg, MessageType.multicast);

            session_.SendMessage(kMulticastMsgType, fun_msg);
            return(true);
        }
        void sendLeaveMessage(string channel_id)
        {
            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast_msg = new Dictionary <string, object>();
                mcast_msg[kChannelId] = channel_id;
                mcast_msg[kSender]    = sender_;
                mcast_msg[kLeave]     = true;

                session_.SendMessage(kMulticastMsgType, mcast_msg);
            }
            else
            {
                FunMulticastMessage mcast_msg = new FunMulticastMessage();
                mcast_msg.channel = channel_id;
                mcast_msg.sender  = sender_;
                mcast_msg.leave   = true;

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast_msg, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg);
            }
        }
        public void RequestChannelList()
        {
            if (!Connected)
            {
                FunDebug.LogWarning("[Multicast] request a channel list but the session is not connected.");
                return;
            }

            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast = new Dictionary <string, object>();
                mcast[kSender] = sender_;
                session_.SendMessage(kMulticastMsgType, mcast, protocol_);
            }
            else
            {
                FunMulticastMessage mcast = new FunMulticastMessage();
                mcast.sender = sender_;

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg, protocol_);
            }
        }
Beispiel #15
0
        public void RequestChannelList()
        {
            if (!Connected)
            {
                FunDebug.Log("Not connected. First connect before join a multicast channel.");
                return;
            }

            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast_msg = new Dictionary <string, object>();
                mcast_msg[kSender] = sender_;
                session_.SendMessage(kMulticastMsgType, mcast_msg);
            }
            else
            {
                FunMulticastMessage mcast_msg = new FunMulticastMessage();
                mcast_msg.sender = sender_;

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast_msg, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg);
            }
        }
        void requestToLeave(string channel_id)
        {
            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast = new Dictionary <string, object>();
                mcast[kChannelId] = channel_id;
                mcast[kSender]    = sender_;
                mcast[kLeave]     = true;

                session_.SendMessage(kMulticastMsgType, mcast, protocol_);
            }
            else
            {
                FunMulticastMessage mcast = new FunMulticastMessage();
                mcast.channel = channel_id;
                mcast.sender  = sender_;
                mcast.leave   = true;

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg, protocol_);
            }

            FunDebug.Log("[Multicast] requested to leave '{0}' channel.", channel_id);
        }
        public void RequestChannelList()
        {
            if (!Connected)
            {
                FunDebug.LogWarning("Multicast.RequestChannelList - Multicast is not connected.\n" +
                                    "Please connect first before request a channel list.");
                return;
            }

            if (encoding_ == FunEncoding.kJson)
            {
                Dictionary <string, object> mcast_msg = new Dictionary <string, object>();
                mcast_msg[kSender] = sender_;
                session_.SendMessage(kMulticastMsgType, mcast_msg);
            }
            else
            {
                FunMulticastMessage mcast_msg = new FunMulticastMessage();
                mcast_msg.sender = sender_;

                FunMessage fun_msg = FunapiMessage.CreateFunMessage(mcast_msg, MessageType.multicast);
                session_.SendMessage(kMulticastMsgType, fun_msg);
            }
        }
 // Send a message
 internal abstract void SendMessage(FunapiMessage fun_msg);
        internal bool EncryptThenSendMessage()
        {
            DebugUtils.Assert((int)state_ >= (int)State.kConnected);
            DebugUtils.Assert(sending_.Count > 0);

            for (int i = 0; i < sending_.Count; i+=2)
            {
                FunapiMessage message = sending_[i];

                EncryptionType encryption = message.enc_type;
                if (encryption == EncryptionType.kDefaultEncryption)
                    encryption = (EncryptionType)default_encryptor_;

                Encryptor encryptor = null;
                string encryption_header = "";
                if ((int)encryption != kNoneEncryption)
                {
                    encryptor = encryptors_[encryption];
                    if (encryptor == null)
                    {
                        last_error_code_ = ErrorCode.kUnknownEncryption;
                        last_error_message_ = "Unknown encryption: " + encryption;
                        DebugUtils.Log(last_error_message_);
                        AddFailureCallback(message);
                        return false;
                    }

                    if (encryptor.state != Encryptor.State.kEstablished)
                    {
                        last_error_code_ = ErrorCode.kInvalidEncryption;
                        last_error_message_ = string.Format("'{0}' is invalid encryption type. Check out the encryption type of server.", encryptor.name);
                        DebugUtils.Log(last_error_message_);
                        AddFailureCallback(message);
                        return false;
                    }

                    if (message.buffer.Count > 0)
                    {
                        Int64 nSize = encryptor.Encrypt(message.buffer, message.buffer, ref encryption_header);
                        if (nSize <= 0)
                        {
                            last_error_code_ = ErrorCode.kEncryptionFailed;
                            last_error_message_ = "Encrypt failure: " + encryptor.name;
                            DebugUtils.Log(last_error_message_);
                            AddFailureCallback(message);
                            return false;
                        }

                        DebugUtils.Assert(nSize == message.buffer.Count);
                    }
                }

                StringBuilder header = new StringBuilder();
                header.AppendFormat("{0}{1}{2}{3}", kVersionHeaderField, kHeaderFieldDelimeter, FunapiVersion.kProtocolVersion, kHeaderDelimeter);
                if (first_sending_)
                {
                    header.AppendFormat("{0}{1}{2}{3}", kPluginVersionHeaderField, kHeaderFieldDelimeter, FunapiVersion.kPluginVersion, kHeaderDelimeter);
                    first_sending_ = false;
                }
                header.AppendFormat("{0}{1}{2}{3}", kLengthHeaderField, kHeaderFieldDelimeter, message.buffer.Count, kHeaderDelimeter);
                if ((int)encryption != kNoneEncryption)
                {
                    DebugUtils.Assert(encryptor != null);
                    DebugUtils.Assert(encryptor.encryption == encryption);
                    header.AppendFormat("{0}{1}{2}", kEncryptionHeaderField, kHeaderFieldDelimeter, Convert.ToInt32(encryption));
                    header.AppendFormat("-{0}{1}", encryption_header, kHeaderDelimeter);
                }
                header.Append(kHeaderDelimeter);

                FunapiMessage header_buffer = new FunapiMessage(protocol_, message.msg_type, header);
                header_buffer.buffer = new ArraySegment<byte>(System.Text.Encoding.ASCII.GetBytes(header.ToString()));
                sending_.Insert(i, header_buffer);

                DebugUtils.DebugLog("Header to send: {0} body length: {1}", header, message.buffer.Count);
            }

            WireSend();

            return true;
        }
        private void SendMessage(FunapiMessage fun_msg, byte[] body)
        {
            try
            {
                lock (sending_lock_)
                {
                    fun_msg.buffer = new ArraySegment<byte>(body);
                    pending_.Add(fun_msg);

                    if (Started && IsSendable)
                    {
                        List<FunapiMessage> tmp = sending_;
                        sending_ = pending_;
                        pending_ = tmp;

                        EncryptThenSendMessage();
                    }
                }
            }
            catch (Exception e)
            {
                last_error_code_ = ErrorCode.kSendFailed;
                last_error_message_ = "Failure in SendMessage: " + e.ToString();
                DebugUtils.Log(last_error_message_);
                AddFailureCallback(fun_msg);
            }
        }
        void onReceived(string msg_type, object body)
        {
            string channel_id = "";
            string sender     = "";
            bool   join       = false;
            bool   leave      = false;
            int    error_code = 0;

            if (encoding_ == FunEncoding.kJson)
            {
                if (json_helper_.HasField(body, kChannelId))
                {
                    channel_id = json_helper_.GetStringField(body, kChannelId);
                }

                if (json_helper_.HasField(body, kSender))
                {
                    sender = json_helper_.GetStringField(body, kSender);
                }

                if (json_helper_.HasField(body, kErrorCode))
                {
                    error_code = (int)json_helper_.GetIntegerField(body, kErrorCode);
                }

                if (json_helper_.HasField(body, kChannelList))
                {
                    if (ChannelListCallback != null)
                    {
                        object list = json_helper_.GetObject(body, kChannelList);
                        ChannelListCallback(list);
                    }
                    return;
                }
                else if (json_helper_.HasField(body, kJoin))
                {
                    join = json_helper_.GetBooleanField(body, kJoin);
                }
                else if (json_helper_.HasField(body, kLeave))
                {
                    leave = json_helper_.GetBooleanField(body, kLeave);
                }
            }
            else
            {
                FunMessage          msg       = body as FunMessage;
                FunMulticastMessage mcast_msg = FunapiMessage.GetMessage <FunMulticastMessage>(msg, MessageType.multicast);
                if (mcast_msg == null)
                {
                    return;
                }

                if (mcast_msg.channelSpecified)
                {
                    channel_id = mcast_msg.channel;
                }

                if (mcast_msg.senderSpecified)
                {
                    sender = mcast_msg.sender;
                }

                if (mcast_msg.error_codeSpecified)
                {
                    error_code = (int)mcast_msg.error_code;
                }

                if (mcast_msg.channels.Count > 0 || (channel_id == "" && sender == ""))
                {
                    if (ChannelListCallback != null)
                    {
                        ChannelListCallback(mcast_msg.channels);
                    }
                    return;
                }
                else if (mcast_msg.joinSpecified)
                {
                    join = mcast_msg.join;
                }
                else if (mcast_msg.leaveSpecified)
                {
                    leave = mcast_msg.leave;
                }

                body = mcast_msg;
            }

            if (error_code != 0)
            {
                FunMulticastMessage.ErrorCode code = (FunMulticastMessage.ErrorCode)error_code;
                FunDebug.LogWarning("Multicast.onReceived - channel: {0} error: {1}", channel_id, code);

                if (code != FunMulticastMessage.ErrorCode.EC_ALREADY_JOINED)
                {
                    lock (channel_lock_)
                    {
                        if (channels_.ContainsKey(channel_id))
                        {
                            channels_.Remove(channel_id);
                        }
                    }
                }

                if (ErrorCallback != null)
                {
                    ErrorCallback(channel_id, code);
                }

                return;
            }

            lock (channel_lock_)
            {
                if (!channels_.ContainsKey(channel_id))
                {
                    FunDebug.LogWarning("Multicast.onReceived - You are not in the '{0} channel.", channel_id);
                    return;
                }
            }

            if (join)
            {
                onUserJoined(channel_id, sender);
            }
            else if (leave)
            {
                onUserLeft(channel_id, sender);
            }
            else
            {
                lock (channel_lock_)
                {
                    if (channels_.ContainsKey(channel_id))
                    {
                        channels_[channel_id](channel_id, sender, body);
                    }
                }
            }
        }
 internal void AddFailureCallback(FunapiMessage fun_msg)
 {
     AddToEventQueue(
         delegate {
             OnMessageFailureCallback(fun_msg);
             OnFailureCallback();
         }
     );
 }
 internal void OnMessageFailureCallback(FunapiMessage fun_msg)
 {
     if (MessageFailureCallback != null)
     {
         MessageFailureCallback(protocol_, fun_msg);
     }
 }
        private void SendWWWRequest(Dictionary<string, string> headers, FunapiMessage body)
        {
            cancel_www_ = false;

            if (body.buffer.Count > 0)
            {
                FunapiManager.instance.StartCoroutine(
                    WWWPost(new WWW(host_url_, body.buffer.Array, headers)));
            }
            else
            {
                FunapiManager.instance.StartCoroutine(
                    WWWPost(new WWW(host_url_, null, headers)));
            }
        }
        private void SendHttpWebRequest(Dictionary<string, string> headers, FunapiMessage body)
        {
            // Request
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host_url_);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = body.buffer.Count;

            foreach (KeyValuePair<string, string> item in headers) {
                request.Headers[item.Key] = item.Value;
            }

            // Response
            WebState ws = new WebState();
            ws.request = request;
            ws.msg_type = body.msg_type;
            ws.sending = body.buffer;
            list_.Add(ws);

            cur_request_ = ws;
            request.BeginGetRequestStream(new AsyncCallback(RequestStreamCb), ws);
        }
        public void SendMessage(string msg_type, object message,
                                 EncryptionType encryption = EncryptionType.kDefaultEncryption,
                                 TransportProtocol protocol = TransportProtocol.kDefault,
                                 string expected_reply_type = null, float expected_reply_time = 0f,
                                 TimeoutEventHandler onReplyMissed = null)
        {
            if (protocol == TransportProtocol.kDefault)
                protocol = GetMessageProtocol(msg_type);

            bool transport_reliability = (protocol == TransportProtocol.kTcp && session_reliability_);

            // Invalidates session id if it is too stale.
            if (last_received_.AddSeconds(kFunapiSessionTimeout) < DateTime.Now)
            {
                DebugUtils.Log("Session is too stale. The server might have invalidated my session. Resetting.");
                session_id_ = "";
            }

            FunapiTransport transport = GetTransport(protocol);
            if (transport != null && transport.state == FunapiTransport.State.kEstablished &&
                (transport_reliability == false || unsent_queue_.Count <= 0))
            {
                FunapiMessage fun_msg = null;

                if (transport.Encoding == FunEncoding.kJson)
                {
                    fun_msg = new FunapiMessage(protocol, msg_type, transport.JsonHelper.Clone(message), encryption);

                    // Encodes a messsage type
                    transport.JsonHelper.SetStringField(fun_msg.message, kMsgTypeBodyField, msg_type);

                    // Encodes a session id, if any.
                    if (session_id_.Length > 0)
                    {
                        transport.JsonHelper.SetStringField(fun_msg.message, kSessionIdBodyField, session_id_);
                    }

                    if (transport_reliability)
                    {
                        transport.JsonHelper.SetIntegerField(fun_msg.message, kSeqNumberField, seq_);
                        ++seq_;

                        send_queue_.Enqueue(fun_msg);
                        DebugUtils.DebugLog("{0} send message - msgtype:{1} seq:{2}", protocol, msg_type, seq_ - 1);
                    }
                    else
                    {
                        DebugUtils.DebugLog("{0} send message - msgtype:{1}", protocol, msg_type);
                    }
                }
                else if (transport.Encoding == FunEncoding.kProtobuf)
                {
                    fun_msg = new FunapiMessage(protocol, msg_type, message, encryption);

                    FunMessage pbuf = fun_msg.message as FunMessage;
                    pbuf.msgtype = msg_type;

                    // Encodes a session id, if any.
                    if (session_id_.Length > 0)
                    {
                        pbuf.sid = session_id_;
                    }

                    if (transport_reliability)
                    {
                        pbuf.seq = seq_;
                        ++seq_;

                        send_queue_.Enqueue(fun_msg);
                        DebugUtils.DebugLog("{0} send message - msgtype:{1} seq:{2}", protocol, msg_type, pbuf.seq);
                    }
                    else
                    {
                        DebugUtils.DebugLog("{0} send message - msgtype:{1}", protocol, msg_type);
                    }
                }

                if (expected_reply_type != null && expected_reply_type.Length > 0)
                {
                    AddExpectedReply(fun_msg, expected_reply_type, expected_reply_time, onReplyMissed);
                }

                transport.SendMessage(fun_msg);
            }
            else if (transport != null &&
                     (transport_reliability || transport.state == FunapiTransport.State.kEstablished))
            {
                if (transport.Encoding == FunEncoding.kJson)
                {
                    if (transport == null)
                        unsent_queue_.Enqueue(new FunapiMessage(protocol, msg_type, message, encryption));
                    else
                        unsent_queue_.Enqueue(new FunapiMessage(protocol, msg_type, transport.JsonHelper.Clone(message), encryption));
                }
                else if (transport.Encoding == FunEncoding.kProtobuf)
                {
                    unsent_queue_.Enqueue(new FunapiMessage(protocol, msg_type, message, encryption));
                }

                DebugUtils.Log("SendMessage - '{0}' message queued.", msg_type);
            }
            else
            {
                StringBuilder strlog = new StringBuilder();
                strlog.AppendFormat("SendMessage - '{0}' message skipped.", msg_type);
                if (transport == null)
                    strlog.AppendFormat(" There's no '{0}' transport.", protocol);
                else if (transport.state != FunapiTransport.State.kEstablished)
                    strlog.AppendFormat(" Transport's state is '{0}'.", transport.state);

                DebugUtils.Log(strlog.ToString());
            }
        }
        private void OnTransportFailure(TransportProtocol protocol, FunapiMessage fun_msg)
        {
            if (fun_msg == null || fun_msg.reply_type.Length <= 0)
                return;

            DeleteExpectedReply(fun_msg.reply_type);
        }
        internal override void SendMessage(FunapiMessage fun_msg)
        {
            if (encoding_ == FunEncoding.kJson)
            {
                string str = this.JsonHelper.Serialize(fun_msg.message);
                byte[] body = System.Text.Encoding.UTF8.GetBytes(str);

                DebugUtils.Log(String.Format("JSON to send : {0}", str));

                SendMessage(fun_msg, body);
            }
            else if (encoding_ == FunEncoding.kProtobuf)
            {
                MemoryStream stream = new MemoryStream();
                this.ProtobufHelper.Serialize (stream, fun_msg.message);

                byte[] body = new byte[stream.Length];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(body, 0, body.Length);

                SendMessage(fun_msg, body);
            }
            else
            {
                Debug.Log("SendMessage - Invalid FunEncoding type: " + encoding_);
            }
        }
        private void AddExpectedReply(FunapiMessage fun_msg, string reply_type,
                                       float reply_time, TimeoutEventHandler onReplyMissed)
        {
            lock (expected_reply_lock)
            {
                if (!expected_replies_.ContainsKey(reply_type))
                {
                    expected_replies_[reply_type] = new List<FunapiMessage>();
                }

                fun_msg.SetReply(reply_type, reply_time, onReplyMissed);
                expected_replies_[reply_type].Add(fun_msg);
                DebugUtils.Log("Adds expected reply message - {0} > {1}", fun_msg.msg_type, reply_type);
            }
        }
        private void SendMessage(FunapiMessage msg_body, byte[] buffer)
        {
            try
            {
                lock (sending_lock_)
                {
                    StringBuilder header = new StringBuilder();
                    header.AppendFormat("{0}{1}{2}{3}", kVersionHeaderField, kHeaderFieldDelimeter, FunapiVersion.kProtocolVersion, kHeaderDelimeter);
                    if (first_sending_)
                    {
                        header.AppendFormat("{0}{1}{2}{3}", kPluginVersionHeaderField, kHeaderFieldDelimeter, FunapiVersion.kPluginVersion, kHeaderDelimeter);
                        first_sending_ = false;
                    }
                    header.AppendFormat("{0}{1}{2}{3}", kLengthHeaderField, kHeaderFieldDelimeter, buffer.Length, kHeaderDelimeter);
                    header.Append(kHeaderDelimeter);

                    FunapiMessage msg_header = new FunapiMessage(msg_body.protocol, msg_body.msg_type, header);
                    msg_header.buffer = new ArraySegment<byte>(System.Text.Encoding.ASCII.GetBytes(header.ToString()));
                    msg_body.buffer = new ArraySegment<byte>(buffer);

                    pending_.Add(msg_header);
                    pending_.Add(msg_body);

                    if (Started && IsSendable)
                    {
                        List<FunapiMessage> tmp = sending_;
                        sending_ = pending_;
                        pending_ = tmp;

                        WireSend();
                    }
                }
            }
            catch (Exception e)
            {
                last_error_code_ = ErrorCode.kSendFailed;
                last_error_message_ = "Failure in SendMessage: " + e.ToString();
                Debug.Log(last_error_message_);
                AddFailureCallback(msg_body);
            }
        }