コード例 #1
0
ファイル: TelnetServer.cs プロジェクト: HarryCordewener/MUA
        private void ClientListener()
        {
            try
            {
                Start(); // Start listening.
                while (true)
                {
                    // Buffer for reading data
                    Console.WriteLine("Waiting for a connection... ");
                    // Perform a blocking call to accept requests.
                    // You could also user server.AcceptSocket() here.

                    var client = new TCPInitializer.Client(AcceptTcpClient(), Metadata);
                    AllClients.Add(client);

                    Thread clientThread = new Thread(StreamHandler);
                    clientThread.Start(client);


                    // Shutdown and end connection
                    // AllClients.Disconnect(client);
                }
            }
            catch (SocketException e)
            {
                Console.WriteLine("SocketException: {0}", e);
            }
            finally
            {
                // Stop listening for new clients.
                Stop();
                AllClients.Disconnect(Metadata);
            }
        }
コード例 #2
0
ファイル: TelnetServer.cs プロジェクト: HarryCordewener/MUA
        /// <summary>
        ///     This code is here to handle Negotiation, and storing the Negotiation information
        ///     on the client object using its KeyValuePair storage.
        ///     WARNING! This code assumes that Negotiation is clean, and does not fail.
        ///     This really should be written in the form of a state-machine.
        ///     But as this is just a proof of concept, this will do for now.
        ///     <todo>
        ///         Secondary Warning, we seem to have OFF-BY-ONE issues with TTYPE negocation.
        ///         That should not be happening! I need to look into how to fix this!
        ///     </todo>
        /// </summary>
        /// <param name="client">A TCP Client reference.</param>
        /// <param name="bytes">The bytes of data that have come through.</param>
        /// <param name="length">How long we can scan through this array.</param>
        /// <returns></returns>
        private int Negociate(ref TCPInitializer.Client client, ref Byte[] bytes, int length)
        {
            int i;

            Console.WriteLine("Negotiation!");
            var notes  = new List <string>();
            var stream = client.client.GetStream();

            for (i = 0; i < length; i++)
            {
                /*
                 *  WILL Negotiation
                 */
                if (bytes[i] == (byte)NegotiationOptions.WILL)
                {
                    if (length > i + 1)
                    {
                        if (bytes[i + 1] == (byte)NegotiationOptions.NAWS)
                        {
                            // Do nothing. They will send us stuff.
                        }
                        else if (bytes[i + 1] == (byte)NegotiationOptions.NEWENVIRON)
                        {
                            Console.WriteLine("They have indicated WILL NEWENVIRON. Sending Negotiation string.");

                            // We Send: IAC SB NEW-ENVIRON SEND IAC SE
                            foreach (var tosend in new List <NegotiationOptions>
                            {
                                NegotiationOptions.IAC,
                                NegotiationOptions.SB,
                                NegotiationOptions.NEWENVIRON,
                                NegotiationOptions.SEND,
                                NegotiationOptions.IAC,
                                NegotiationOptions.SE
                            })
                            {
                                stream.WriteByte((byte)tosend);
                            }
                        }
                        else if (bytes[i + 1] == (byte)NegotiationOptions.TTYPE)
                        {
                            Console.WriteLine("They have indicated WILL TTYPE. Sending Negotiation string.");
                            // We Send: IAC SB TERMINAL-TYPE SEND IAC SE
                            foreach (var tosend in new List <NegotiationOptions>
                            {
                                NegotiationOptions.IAC,
                                NegotiationOptions.SB,
                                NegotiationOptions.TTYPE,
                                NegotiationOptions.SEND,
                                NegotiationOptions.IAC,
                                NegotiationOptions.SE
                            })
                            {
                                stream.WriteByte((byte)tosend);
                            }
                        }
                        else if (bytes[i + 1] == (byte)NegotiationOptions.CHARSET)
                        {
                            Console.WriteLine("CHARSET NEG? (WILL). Let's try sending SB SEND");
                            var charsetsupport = Encoding.ASCII.GetBytes(";UTF-7;UTF-8;US-ASCII");
                            stream.WriteByte((byte)NegotiationOptions.IAC);
                            stream.WriteByte((byte)NegotiationOptions.SB);
                            stream.WriteByte((byte)NegotiationOptions.CHARSET);
                            stream.WriteByte((byte)NegotiationOptions.REQUEST);
                            stream.Write(charsetsupport, 0, charsetsupport.Length);
                            stream.WriteByte((byte)NegotiationOptions.IAC);
                            stream.WriteByte((byte)NegotiationOptions.SE);
                        }
                        else
                        {
                            Console.WriteLine("ERROR! The client WILL do something we don't recognize!");
                            return(i); // Bail!
                        }
                    }
                }

                /*
                 *  SUB Negotiation - THIS LARGELY IS US INTERPRETING INCOMING Negotiation
                 */
                else if (bytes[i] == (byte)NegotiationOptions.SB)
                {
                    // Begin SubNegotiation - this comes after an IAC
                    // After this, everything is Negotiation!

                    if (length > i + 1)
                    {
                        /*
                         *  NAWS Negotiation
                         */
                        if (bytes[i + 1] == (byte)NegotiationOptions.NAWS && length > i + 7)
                        {
                            // We really should move this code to the Client creation.
                            // A client should always have these two.
                            if (!client.KeyValuePairs.ContainsKey("WIDTH"))
                            {
                                client.KeyValuePairs.Add("WIDTH", "78");
                            }
                            if (!client.KeyValuePairs.ContainsKey("HEIGHT"))
                            {
                                client.KeyValuePairs.Add("HEIGHT", "24");
                            }

                            // We are expecting:
                            // IS <INT as Width> IS <INT as Height>
                            // Then IAC SE
                            if (bytes[i + 2] != (byte)NegotiationOptions.IS)
                            {
                                break;
                            }
                            client.KeyValuePairs["WIDTH"] = bytes[i + 3].ToString();
                            if (bytes[i + 4] != (byte)NegotiationOptions.IS)
                            {
                                break;
                            }
                            client.KeyValuePairs["HEIGHT"] = bytes[i + 5].ToString();
                            if (bytes[i + 6] != (byte)NegotiationOptions.IAC)
                            {
                                break;
                            }
                            if (bytes[i + 7] != (byte)NegotiationOptions.SE)
                            {
                                break;
                            }
                            i = i + 7;
                            Console.WriteLine("The client has indicated WIDTH = " + client.KeyValuePairs["WIDTH"]
                                              + " HEIGHT = " + client.KeyValuePairs["HEIGHT"]);
                        }

                        /*
                         *  ENVIRONMENT Negotiation
                         */
                        else if (bytes[i + 1] == (byte)NegotiationOptions.NEWENVIRON)
                        {
                            // We don't know yet, just how to do this.
                        }

                        /*
                         *  TERMINAL TYPE Negotiation
                         */
                        else if (bytes[i + 1] == (byte)NegotiationOptions.TTYPE)
                        {
                            // We are expecting:
                            // IS < other things > IAC SE
                            // We CAN then send another request for a TTYPE, to enumerate, until we get a duplicate.
                            // At which point we stop!
                            if (bytes[i + 2] != (byte)NegotiationOptions.IS)
                            {
                                break;
                            }
                            var termType  = new StringBuilder();
                            var completed = false;
                            for (i = i + 3; i < length; i++)
                            {
                                if (bytes[i] == (byte)NegotiationOptions.IAC &&
                                    length > i + 1 &&
                                    bytes[i + 1] == (byte)NegotiationOptions.SE)
                                {
                                    if (!client.KeyValuePairs.ContainsKey("TERMTYPE"))
                                    {
                                        client.KeyValuePairs.Add("TERMTYPE", termType.ToString());
                                    }
                                    else
                                    {
                                        if (!client.KeyValuePairs["TERMTYPE"].Contains(termType.ToString()))
                                        {
                                            client.KeyValuePairs["TERMTYPE"] = " " + termType;
                                        }
                                    }
                                    completed = true;
                                }
                                else
                                {
                                    termType.Append((char)bytes[i]);
                                }
                            }
                            if (!completed)
                            {
                                Console.WriteLine("INCOMPLETE TERMTYPE! HOW DO WE RECOVER?!");
                                return(0); // Bail
                            }
                            Console.WriteLine("TERMTYPE: " + client.KeyValuePairs["TERMTYPE"] + " ");
                            return(i);
                        }

                        /*
                         *  CHARACTER SET Negotiation
                         */
                        else if (bytes[i + 1] == (byte)NegotiationOptions.CHARSET)
                        {
                            var charsetNegotiation = new StringBuilder();
                            for (i = i + 1; i < length; i++)
                            {
                                if (bytes[i] == (byte)NegotiationOptions.IAC &&
                                    length > i + 1 &&
                                    bytes[i + 1] == (byte)NegotiationOptions.SE)
                                {
                                    Console.WriteLine(charsetNegotiation);
                                    i++;
                                    break;
                                }
                                switch (bytes[i])
                                {
                                case (byte)NegotiationOptions.ACCEPTED:
                                    charsetNegotiation.Append(NegotiationOptions.ACCEPTED + " ");
                                    break;

                                case (byte)NegotiationOptions.REQUEST:
                                    charsetNegotiation.Append(NegotiationOptions.REQUEST + " ");
                                    break;

                                case (byte)NegotiationOptions.CHARSET:
                                    charsetNegotiation.Append(NegotiationOptions.CHARSET + " ");
                                    break;

                                case (byte)NegotiationOptions.REJECTED:
                                    charsetNegotiation.Append(NegotiationOptions.REJECTED + " ");
                                    break;

                                case (byte)NegotiationOptions.TTABLE_ACK:
                                    charsetNegotiation.Append(NegotiationOptions.TTABLE_ACK + " ");
                                    break;

                                case (byte)NegotiationOptions.TTABLE_IS:
                                    charsetNegotiation.Append(NegotiationOptions.TTABLE_IS + " ");
                                    break;

                                case (byte)NegotiationOptions.TTABLE_NAK:
                                    charsetNegotiation.Append(NegotiationOptions.TTABLE_NAK + " ");
                                    break;

                                case (byte)NegotiationOptions.TTABLE_REJECTED:
                                    charsetNegotiation.Append(NegotiationOptions.TTABLE_REJECTED + " ");
                                    break;

                                default:
                                    charsetNegotiation.Append((char)bytes[i]);
                                    break;
                                }
                            }
                        }
                        else
                        {
                            Console.WriteLine("ERROR! The client WILL do something we don't recognize!");
                            return(i); // Bail!
                        }
                    }
                }
            }
            return(i);
        }
コード例 #3
0
ファイル: TelnetServer.cs プロジェクト: HarryCordewener/MUA
        private void StreamHandler(object clientArg)
        {
            TCPInitializer.Client client = (TCPInitializer.Client)clientArg;
            Console.WriteLine("Accepted a connection.");

            // Get a stream object for reading and writing
            var stream = client.client.GetStream();


            int i;
            int concat = 0;
            var bytes  = new Byte[MUASettings.Default.client_buffer_len * 2];

            // Let's tell it what we're willing to do here!
            // We do NAWS, CHARSET, TTYPE and NEWENVIRON
            foreach (var option in new[]
            {
                NegotiationOptions.NAWS,
                NegotiationOptions.CHARSET,
                NegotiationOptions.TTYPE,
                NegotiationOptions.NEWENVIRON
            })
            {
                stream.WriteByte((byte)NegotiationOptions.IAC);
                stream.WriteByte((byte)NegotiationOptions.DO);
                stream.WriteByte((byte)option);
            }

            // Loop to receive all the data sent by the client.
            while ((i = stream.Read(bytes, concat, MUASettings.Default.client_buffer_len)) != 0)
            {
                int c = 0;
                int postNegotiationPtr = 0;

                // We refuse to believe IAC will appear anywhere BUT at the start of a sent.
                // We also refuse to believe a single negociation string will be longer than the default client
                // buffer length, which hopefully will be about 2 MB or more.
                // If the first character is telnet IAC, and it is not an escaped char 255...
                if (i > 1 && bytes[0] == 255 && bytes[1] != 255 && concat == 0)
                {
                    postNegotiationPtr = Negociate(ref client, ref bytes, i);
                    Console.WriteLine("Negotiation was {0} characters of {1} bytes.", postNegotiationPtr, i);
                    if (postNegotiationPtr > i)
                    {
                        for (int bte = 0; bte < i; bte++)
                        {
                            Console.Write(bytes[bte] + " ");
                        }
                        Console.WriteLine("\nWas received");
                    }
                    if (postNegotiationPtr >= i)
                    {
                        Console.WriteLine("This was pure Negotiation. Going to the next message.");
                        continue;
                    }
                }

                /*
                 * We need a way here to 'confirm' how many we received and actually copied over.
                 * But post-negociation, we can at least attempt to copy as much as we have.
                 * We then look through 'bytes' for a \n\r or \r\n, so we can treat it as a 'send'
                 * and clear our buffer? Or should we, upon reaching the max length, just assume that
                 * was a send and toss the rest we received to the wayside?
                 * The latter most certainly would be the easiest way to go about it!
                 */
                for (var b = client.BytePtr; (b < client.Bytes.Length && c < i); b++, c++)
                {
                    client.Bytes[b] = bytes[c + concat];
                }
                Console.WriteLine("Inserting at pointer position {0} of client {1}",
                                  client.BytePtr, client.client.Client.RemoteEndPoint);
                Console.WriteLine("We received {0} bytes, and recorded {1} of those.", i, c);


                var bytesReceived = new StringBuilder();

                for (var j = 0; (j < client.BytePtr + i && j < client.Bytes.Length); j++)
                {
                    bytesReceived.Append(client.Bytes[j]);
                    bytesReceived.Append(" ");
                }

                // Translate data bytes to a ASCII string.
                // Note! If we have negociated for UTF-8 etc, we should use that instead!
                var data = Encoding.ASCII.GetString(client.Bytes, postNegotiationPtr,
                                                    Math.Min(client.BytePtr + i - postNegotiationPtr, client.Bytes.Length));
                Console.WriteLine("Received: {0} AKA {1}", data, bytesReceived);

                var msg = Encoding.ASCII.GetBytes("Buffer cleared.\n\r");

                // Send back a response.
                // stream.Write(msg, 0, msg.Length);
                // Console.WriteLine("Sent: {0}", data);

                client.BytePtr = Math.Min(client.BytePtr + i, client.Bytes.Length);

                if (i + concat >= 2 &&
                    ((bytes[i - 1 + concat] == (byte)NegotiationOptions.NEWLINE &&
                      bytes[i - 1 - 1 + concat] == (byte)NegotiationOptions.CR) ||
                     (bytes[i - 1 + concat] == (byte)NegotiationOptions.CR &&
                      bytes[i - 1 - 1 + concat] == (byte)NegotiationOptions.NEWLINE)))
                {
                    // client.Bytes.Initialize();
                    client.BytePtr = 0;
                    Console.WriteLine("Buffer cleared.");
                    client.client.GetStream().Write(msg, 0, msg.Length);

                    /*
                     * THIS IS WHERE WE MUST SEND THE INFORMATION TO THE PARSER!
                     * WE QUEUE THE CLIENT BUFFER ONTO THE PARSE STACK.
                     */
                    concat = 0;
                }
                else
                {
                    // We are not re-using, to make the code more readable. Concat has a very specific meaning.
                    concat = client.Bytes.Length;
                    for (int block = client.Bytes.Length; block < 2 * client.Bytes.Length; block++)
                    {
                        bytes[block - client.Bytes.Length] = bytes[block];
                    }
                }
            }
        }