0
Answer

A simple proxy server in C#

Prahlad Yeri

Prahlad Yeri

12y
2.1k
1
I have written a simple and minimalist HTTP proxy server that runs on command line. In the Start() method, a TcpListener blocks until it gets a client request and creates a new thread (ThreadHandleClient method) that processes this client, fetches its url and relays data.
 
The trouble is in the relay logic that I want to refine. In the first inner loop, I receive all webserver data and send it to client until zero bytes are left. In second inner loop, I do vice-versa: receive all client data and send to web-server until zero bytes left. However, the code gets blocked in the beginning of second inner-loop at client.receive(). This is what I'm basically doing:
 
Any help will be truly appreciated. Thanks in advance.
 
public void Start(IPAddress ip, int port)
    {
    try
    {
    TcpListener listener = new TcpListener(ip, port);
    listener.Start(100);
    while (!stopFlag)
    {
    Socket client = listener.AcceptSocket();
    IPEndPoint rep = (IPEndPoint)client.RemoteEndPoint;
    Thread th = new Thread(ThreadHandleClient);
    th.Start(client);
    }
    listener.Stop();
    }
    catch (Exception ex)
    {
    Debug.Print("START: " + ex.Message);
    }
    }
    public void ThreadHandleClient(object o)
    {
    try
    {
    Socket client = (Socket)o;
    NetworkStream ns = new NetworkStream(client);
    //RECEIVE CLIENT DATA
    byte[] buffer = new byte[2048];
    int rec = 0, sent = 0, transferred = 0, rport = 0;
    string data = "";
    do
    {
    rec = ns.Read(buffer, 0, buffer.Length);
    data += Encoding.ASCII.GetString(buffer, 0, rec);
    } while (rec == buffer.Length);
    //PARSE DESTINATION AND SEND REQUEST
    string line = data.Replace("\r\n", "\n").Split(new string[] { "\n" }, StringSplitOptions.None)[0];
    Uri uri = new Uri(line.Split(new string[] { " " }, StringSplitOptions.None)[1]);
    Debug.Print("CLIENT REQUEST RECEIVED: " + uri.OriginalString);
    if (uri.Scheme == "https")
    {
    rport = 443;
    Debug.Print("HTTPS - 443");
    }
    else
    {
    rport = 80;
    Debug.Print("HTTP - 443");
    }
    IPHostEntry rh = Dns.GetHostEntry(uri.Host);
    Socket webserver = new Socket(rh.AddressList[0].AddressFamily, SocketType.Stream, ProtocolType.IP);
    webserver.Connect(new IPEndPoint(rh.AddressList[0], rport));
    byte[] databytes = Encoding.ASCII.GetBytes(data);
    webserver.Send(databytes, databytes.Length, SocketFlags.None);
    Debug.Print("SENT TO SERVER. WILL NOW RELAY: " + data);
    //START RELAY
    buffer = new byte[2048];
    rec = 0;
    data = "";
    do
    {
    transferred = 0;
    do
    {
    rec = webserver.Receive(buffer, buffer.Length, SocketFlags.None);
    Debug.Print("RECEIVED FROM WEBSERVER[" + rec.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec));
    sent = client.Send(buffer, rec, SocketFlags.None);
    Debug.Print("SENT TO CLIENT[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec));
    transferred += rec;
    //data += Encoding.ASCII.GetString(serverbytes, 0, rec);
    } while (rec == buffer.Length);
    Debug.Print("loop-1 finished");
    if (transferred == 0)
    break;
    transferred = 0;
    do
    {
    rec = client.Receive(buffer, buffer.Length, SocketFlags.None);
    Debug.Print("RECEIVED FROM CLIENT: " + Encoding.ASCII.GetString(buffer, 0, rec));
    sent = webserver.Send(buffer, rec, SocketFlags.None);
    Debug.Print("SENT TO WEBSERVER[" + sent.ToString() + "]: " + Encoding.ASCII.GetString(buffer, 0, rec));
    transferred += rec;
    } while (rec == buffer.Length);
    Debug.Print("loop-2 finished");
    } while (transferred > 0);
    Debug.Print("LOOP ENDS. EXITING THREAD");
    }
    catch (Exception ex)
    {
    Debug.Print("Error occured: " + ex.Message);
    }