Ask a questionAsk a question
 

AnswerTcp: responding to server-to-client acknowledgments

  • Thursday, October 22, 2009 12:40 PMdeostroll Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code
    We connect to a server via command prompt issuing a telnet. (telnet.exe). I am trying to simulate the same application via a program I am trying to build in c#. So on the telnet sessions (via command prompt) we are supposed to issue operation-specific commands, etc. Normally we'd have to navigate to those screens/menus to do it. (All of this is via the console window). The ultimate aim of the program I am trying to build is to avoid all the navigation, and automate certain operations.

    I've been doing a long research on this. If you are interested in the history please check the threads below:
    http://social.msdn.microsoft.com/Forums/en-US/ncl/thread/2c88cbed-95e3-41dc-b13f-cf2fe9e525da

    Lately I've used wireshark to understand what is the communication going on...wireshark also has helped me to understand what sort of instructions I am supposed to send to the server. I've used the TcpClient object to do all this. But I've noticed my program was not working right. I did a wireshark analysis on my program and on telnet.exe (command prompt tool) and found out nuances in the communication packets sent from my program.

    It is kind of hard for me to put it out all here...but I'll try my best. I observe certain responses are supposed to be sent after we receive some acknowledgment from the server. Observe 14th packet below:

    No.     Time        Source                Destination           Protocol Info
         12 1.221591    myTelnetServr         local-Client          TELNET   Telnet Data ...
         13 1.221681    local-Client          myTelnetServr         TELNET   Telnet Data ...
         14 1.529235    myTelnetServr         local-Client          TCP      telnet > ttnrepository [ACK] Seq=19 Ack=29 Win=32768 Len=0
         15 1.529302    local-Client          myTelnetServr         TELNET   Telnet Data ...
         16 1.774135    myTelnetServr         local-Client          TELNET   Telnet Data ...
    
    
    There is no way for my program to currently understand that an acknowledgment was received, (i.e., packet 14) was received. (I don't know what the 14th packet means either, but I'd like to know).

    Here is part of the code I've used. There are a lot of helper methods I've created; I am purposefully not including them because I think its unnecessary; but I am willing to post them if required.
    using System;
    using System.Net.Sockets;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading;
    using System.Diagnostics;
    
    namespace tcpClientDemo
    {
        class Program
        {
            //storing the sequence of bytes I've to 
            //send in a fifo queue
            static Queue<string> Commands;
    
            static void Main(string[] args)
            {
                
                Commands = new Queue<string>();
    
                //Creating the sequence of commands to send.
                //There are lots of commands to send, but I am 
                //purposefully stopping short.
    
                Commands.Enqueue("ff fc 24");
                Commands.Enqueue("ff fb 18 ff fb 1f");
                Commands.Enqueue("ff fa 18 00 41 4e 53 49 ff f0");
                Commands.Enqueue("ff fa 1f 00 50 00 19 ff f0 ff fc 20");
                Commands.Enqueue("ff fc 20");
                Commands.Enqueue("ff fd 01 ff fd 03 ff fc 21 ff fb 01");
                Commands.Enqueue("ff fc 21");
                Commands.Enqueue("ff fc 01");            
    
                Demo3();
            }
    
            private static void Demo3()
            {
                Console.WriteLine("Press key to start connection");
                Console.ReadKey();
                TcpClient tcp = new TcpClient("myTelnetServr", 23);
                
                if (tcp.Connected)
                    Console.WriteLine("Successfully connected");
                else
                {
                    Console.WriteLine("not connected");
                    return;
                }
    
                NegotiateStream(tcp.GetStream());
    
                Console.WriteLine("Press enter to quit");
                Console.ReadLine();
            }        
    
            static void Write(NetworkStream stream, byte[] data)
            {
                TelnetCommand.InterpretSequence(data, data.Length);
                Console.WriteLine("Sending [{0}]", BitConverter.ToString(data));
                stream.Write(data, 0, data.Length);
            }
    
            static byte[] InputBytes()
            {
                List<byte> inputBytes = new List<byte>();
                Console.Write("Enter values: ");
                string inpStr = Console.ReadLine();
                char[] sep = { char.Parse(" ") };
                string[] byteStr = inpStr.Split(sep);
                for (int i = 0; i < byteStr.Length; i++)
                    inputBytes.Add(byte.Parse(byteStr[i], System.Globalization.NumberStyles.HexNumber));
                return inputBytes.ToArray();
            }
    
            static byte[] InputBytes(string byteString)
            {
                List<byte> inputBytes = new List<byte>();
                Console.Write("Enter values: ");
                string inpStr = byteString;
                char[] sep = { char.Parse(" ") };
                string[] byteStr = inpStr.Split(sep);
                for (int i = 0; i < byteStr.Length; i++)
                    inputBytes.Add(byte.Parse(byteStr[i], System.Globalization.NumberStyles.HexNumber));
                return inputBytes.ToArray();
            }
    
            static void NegotiateStream(NetworkStream stream)
            {
                while (!stream.DataAvailable)
                {
                    List<byte> tcpdata = new List<byte>();
                    int val = stream.ReadByte();
                    if (val == -1)
                    {
                        Debug.Assert(val == -1, "val is negative");                                  
                    }
    
                    tcpdata.Add(Convert.ToByte(val));
    
                    while (stream.DataAvailable)
                    {
                        val = stream.ReadByte();
                        tcpdata.Add(Convert.ToByte(val));
                    }
                    
                    Console.WriteLine("Received [{0}]", BitConverter.ToString(tcpdata.ToArray()));
                    
                    TelnetDataParser.Parse(tcpdata.ToArray());
                    Console.WriteLine("{0} : Input required detected...", DateTime.Now.ToLongTimeString());
                    byte[] data = InputBytes(Commands.Dequeue());
                    if (data.Length > 1)
                        Write(stream, data);
                    else
                    {
                        Console.WriteLine("Quitting negotiation loop");
                        break;
                    }
                }
            }
    
        }
    }
    
    


    I am a bundle of mistakes intertwined together with good intentions
    • Edited bydeostroll Thursday, October 22, 2009 12:46 PMrepasted code...
    •  

Answers

  • Thursday, October 29, 2009 7:15 AMdeostroll Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hi,

    I did escalate this post over to public groups and found that the implementation of the protocol in the above code is incorrect. The correct means of implementing this can be found below:
    http://www.faqs.org/rfcs/rfc1143.html

    Plus, I also found an open source library in c# which implements the protocol as per the technique (q-method) mentioned in the above mentioned link (viz a standard specification RFC). That can be found below:
    http://sourceforge.net/projects/dotnettelnet/

    I got this part of the problem solved, but there are other problems I've landed into...
    I am a bundle of mistakes intertwined together with good intentions
    • Marked As Answer bydeostroll Thursday, October 29, 2009 7:15 AM
    •  

All Replies

  • Thursday, October 29, 2009 7:15 AMdeostroll Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hi,

    I did escalate this post over to public groups and found that the implementation of the protocol in the above code is incorrect. The correct means of implementing this can be found below:
    http://www.faqs.org/rfcs/rfc1143.html

    Plus, I also found an open source library in c# which implements the protocol as per the technique (q-method) mentioned in the above mentioned link (viz a standard specification RFC). That can be found below:
    http://sourceforge.net/projects/dotnettelnet/

    I got this part of the problem solved, but there are other problems I've landed into...
    I am a bundle of mistakes intertwined together with good intentions
    • Marked As Answer bydeostroll Thursday, October 29, 2009 7:15 AM
    •