예제 #1
0
        protected void OnMessage(PlainEventMsg msg)
        {
            NameValueCollection parameters = msg.ParseBody(true);
            string eventName = parameters["event-name"];

            if (eventName == null)
            {
                return;
            }

            eventName = string.Compare(parameters["event-name"], "custom", true) == 0
                            ? parameters["event-subclass"]
                            : parameters["event-name"];

            //Quickhack for Sofia::Register (convert to sofia_register)
            eventName = eventName.Replace("::", "_");
            eventName = StringHelper.UpperCaseToCamelCase(eventName);

            // Try to load the event (check if we've created an event class for the registered event)
            EventBase eb = EventBase.CreateEvent(eventName);

            // Yep, we got an event class. Let it parse the event information
            if (eb != null)
            {
                eb.SetParameters(parameters);
                eb.Parse(parameters);
                EventReceived(eb);
            }
            else if (DisplayMissingEventTypes)
            {
                _logWriter(LogPrio.Warning, "Failed to load '" + eventName + "'.");
            }
        }
예제 #2
0
        internal static void ParseHeaders(PlainEventMsg msg, string header)
        {
            StringParser parser = new StringParser(header);
            string       name   = parser.Read(':', true);

            while (name != string.Empty)
            {
                switch (name)
                {
                case "Content-Length":
                    msg.ContentLength = int.Parse(parser.ReadLine(true));
                    break;

                case "Content-Type":
                    msg.ContentType = parser.ReadLine(true);
                    break;

                case "Reply-Text":
                    msg.Body = parser.ReadLine(true);
                    break;
                }

                // empty line == end of header
                if (parser.EOL)
                {
                    break;
                }

                name = parser.Read(':', true);
            }
        }
예제 #3
0
        private PlainEventMsg FindHeaders(ref int index)
        {
            IgnoreEmptyLines(ref index);

            int start = index;

            FindEmptyLine(ref index);
            if (start == index)
            {
                return(null);                //got no header.
            }
            char[] headerBuffer = new char[index - start];
            _text.CopyTo(start, headerBuffer, 0, index - start);

            PlainEventMsg eventMsg = new PlainEventMsg();

            ParseHeaders(eventMsg, new string(headerBuffer));
            return(eventMsg);
        }
예제 #4
0
        // Should ONLY be called from the parsing thread.
        private void ParseMessages()
        {
            PlainEventMsg msg = _parser.ParseOne();

            while (msg != null)
            {
                LogWriter(LogPrio.Trace, "MessageType: " + msg.ContentType);
                switch (msg.ContentType)
                {
                case "auth/request":
                {
                    var cmd = new AuthCommand(_password);
                    cmd.ReplyReceived += OnAuthed;
                    _commands.Enqueue(cmd);
                    Write(cmd + "\n\n");
                }
                break;

                case "api/response":
                case "command/reply":
                    if (_commands.Count > 0)
                    {
                        CmdBase cmd = _commands.Dequeue();
                        cmd.HandleReply(cmd.CreateReply(msg.Body.Trim()));
                    }
                    else
                    {
                        LogWriter(LogPrio.Debug, "Got command reply or api response, but no actual command/api: " + msg.Body);
                    }
                    break;

                default:
                    MessageReceived(msg);
                    break;
                }
                msg = _parser.ParseOne();
            }
        }
예제 #5
0
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        /// <exception cref="InvalidDataException">If parsing failed due to invalid format.</exception>
        public PlainEventMsg ParseOne()
        {
            // Move queue to text
            lock (_piecesToAppend)
            {
                while (_piecesToAppend.Count > 0)
                {
                    _text.Append(_piecesToAppend.Dequeue());
                }
            }

            if (_text.Length == 0)
            {
                return(null);
            }

            PlainEventMsg plainEvent;

            lock (_text)
            {
                int i = 0;
                IgnoreLineBreaks(ref i);
                _text.Remove(0, i);

                i = FindEmptyLine(i);
                if (i == -1)
                {
                    return(null);
                }

                // extract header
                char[] chars = new char[i];
                _text.CopyTo(0, chars, 0, i);
                string headers = new string(chars);
                IgnoreLineBreaks(ref i);

                plainEvent = new PlainEventMsg();
                ParseHeaders(plainEvent, headers);

                // we got a body?
                if (plainEvent.ContentLength > 0)
                {
                    // Start of Empty header bugfix
                    // FS seems to send a header with content-length without sending an actual body
                    // this will eat that kind of header.
                    if (_text.Length >= BugWorkaround.Length + i)
                    {
                        bool found = true;
                        for (int index = 0; index < BugWorkaround.Length; ++index)
                        {
                            if (_text[index + i] != BugWorkaround[index])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            _text.Remove(0, i);
                            Console.WriteLine("Removing empty content header.");
                            return(null);
                        }
                    }
                    // end of bugfix.

                    // not enough data for body.
                    if (plainEvent.ContentLength + i > _text.Length)
                    {
                        return(null);
                    }

                    // extract body

                    // since Freeswitch report false sizes sometimes,
                    // we need to go through all lines to find contents.
                    //
                    // If FreeSWITCH is actually doing something wrong and you can prove it, you should report it as a bug.
                    // More likely you are misunderstanding the protocol and confusing the events with more encapsulated events
                    // as a mistake. Dozens of other people have had that same mistake making an ESL client.
                    // You should look in libs/esl and try to get the swig wrapper on the esl lib working instead.

                    int endOfBody = FindEmptyLine(i) + 2;     // include the first and last \n
                    if (endOfBody - i != plainEvent.ContentLength)
                    {
                        Console.WriteLine("Invalid content length, actual length: " + (endOfBody - i) + ", reported length: " +
                                          plainEvent.ContentLength);
                        plainEvent.ContentLength = endOfBody - i;
                    }
                    chars = new char[plainEvent.ContentLength];
                    _text.CopyTo(i, chars, 0, plainEvent.ContentLength);
                    plainEvent.Body = new string(chars);

                    // api/response is buggy for originate, no \n\n are appended at the end.
                    if (plainEvent.ContentType != "api/response")
                    {
                        // check for errors.
                        int pos = plainEvent.Body.IndexOf("\n\n");
                        if (pos < plainEvent.Body.Length - 2)
                        {
                            Console.WriteLine("Invalid event");
                            Console.WriteLine("Header");
                            Console.WriteLine(headers);
                            Console.WriteLine("Body");
                            Console.WriteLine(plainEvent.Body);
                            Console.WriteLine("=========================== EVERYTHING unparsed ==============================");
                            Console.WriteLine(_text);
                            throw new InvalidDataException("Invalid event: " + _text);
                        }
                    }

                    if (plainEvent.Body.Length < plainEvent.ContentLength)
                    {
                        throw new InvalidDataException("Body contents are too small!");
                    }

                    // Move forward to next header
                    i += plainEvent.ContentLength;
                    IgnoreLineBreaks(ref i);
                }


                // remove header( + body) from buffer
                _text.Remove(0, i);
            }

            return(plainEvent);
        }
예제 #6
0
        public PlainEventMsg ParseOne()
        {
            AppendPieces();

            int           index = 0;
            PlainEventMsg msg   = FindHeaders(ref index);

            if (msg == null)
            {
                return(null);
            }

            // no body
            if (msg.ContentLength <= 0)
            {
                _text.Remove(0, index);
                return(msg);
            }

            // too few bytes.
            if (_text.Length - index < msg.ContentLength)
            {
                return(null);
            }

            // ignore empty line between header and body.
            IgnoreEmptyLines(ref index);

            int start = index;

            FindEmptyLine(ref index);

            int size = index - start + 2;             // include \n\n

            // Validate size.
            //
            // Someone suggested that the sizes are correct and that
            // the events was wrapped. Well. I've checked if the
            // specified position is a \n\n, and it's not.
            //
            // Don't force me to check source code of another implementation
            //
            if (size != msg.ContentLength)
            {
                // Check if the buffer contains header + body only,
                // then use the reported size, despite that our check failed.
                if (_text.Length == msg.ContentLength + start)
                {
                    size = msg.ContentLength;
                }
                // buffer contains more than one message.
                else if (_text.Length > msg.ContentLength + start)
                {
                    // Check if the reported size ends with a \n,
                    // in that case we have a container event.
                    if (_text[msg.ContentLength + start - 1] == '\n')
                    {
                        size = msg.ContentLength;
                    }
                }
            }

            char[] body = new char[size];
            _text.CopyTo(start, body, 0, size);
            msg.Body = new string(body);
            _text.Remove(0, index);
            return(msg);
        }