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);
}