Hi

I'm attempting to code a proxy in C++ using Winsock2. At the moment it only works on simple HTML pages and locks up a lot when downloading certain pages. After a lot of fiddling, I'm not sure what the problem is. A big thank you to anybody who can help.

#include <stdio.h>
#include <tchar.h>

#include <iostream>
#include <WinSock2.h>
#pragma comment( lib, "ws2_32.lib" ) 
#include <Windows.h>

using namespace std;

int port = 5522;

SOCKET listen_sock;
SOCKET client_sock;
char FR_recv_buf [1048576] = "";
char recv_buf [10240] = "";

int Receive();
int Listen();

//function to initialize winsock
bool InitializeWinsock()
{
	WSADATA wsaData;
	int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if(iResult != 0)
	{
		cout << "WSAStartup failed with error: " << iResult << endl;		
		return false;
	}
	else
	{
		cout << "WSAStartup successfully initialized." << endl;	
		return true;
	}
}

int ForwardResponse()
{

	if (send(client_sock, FR_recv_buf, sizeof(FR_recv_buf), 0) == SOCKET_ERROR)
	{
		cout << "Forward Response: send() failed with error: " << WSAGetLastError() << endl;
		closesocket(client_sock);
		//WSACleanup();
		return 0;
	}
	else
	{
		cout << "Forward Response: send() success.\n";
		//go back to begginning again?
		Receive();
		//CreateThread(0,0,(LPTHREAD_START_ROUTINE)Receive, 0, 0 ,0);
	}	
}

//Function to parse hostname from http request
string ParseHostname(char * buf)
{
	size_t pos;

	//string to hold hostname substring
	string hostname_t;	
	//copy request to string for easier parsing
	string httpheader = buf;

	pos = httpheader.find("Host: ");//find "Host: " line
	hostname_t = httpheader.substr(pos + 6);//copy to substring, not including "Host: ", just the hostname
	pos = hostname_t.find("\r\n");// find end of line
	hostname_t.erase(pos);//erase the rest of the string which is unwanted

	return hostname_t;
}

//Function to forward HTTP request from browser to webserver
int ForwardRequest()
{
	int bytes_received;
	SOCKADDR_IN Dest;
	SOCKET frecv_sock;
	hostent *Host;
		
	//parse hostname from http request
	string hostname = ParseHostname(recv_buf);
	
	if((Host=gethostbyname(hostname.c_str()))==NULL)
	{
		DWORD dwError = WSAGetLastError();
		if (dwError != 0)
		{
			if(dwError == WSAHOST_NOT_FOUND) 
			{
				cout << "Host " << hostname.c_str()  << " not found.\n";
				WSACleanup();
				return FALSE;
			}
			else if (dwError == WSANO_DATA) 
			{
				cout << "No data record found.\n";;
				WSACleanup();
				return FALSE;
			}
			else
			{
			    cout << "Function failed with error: " << dwError << endl;
				WSACleanup();
				return FALSE;
			}
		}
	}
	else
	{
		cout << "Successfully connected to host: " <<  hostname.c_str() << endl;
		//privmsg(wsockdl.sock,sendbuf,curchan);
	}

	Dest.sin_family=AF_INET;
	Dest.sin_port=htons(80);
	memcpy(&Dest.sin_addr,Host->h_addr,Host->h_length);

	// Create a SOCKET for connecting to server
	if((frecv_sock = socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
	{
		cout << "Forward Request: Error at socket(), error code: " << WSAGetLastError() << endl;
		
		closesocket(frecv_sock);
		//WSACleanup();
		return FALSE;
	}

	// Connect to server
	if(connect( frecv_sock,(SOCKADDR*)&Dest,sizeof(Dest))==SOCKET_ERROR)
	{
		cout << "Forward Request: connect() failed, error code: " << WSAGetLastError() << endl;
		closesocket( frecv_sock);
		//WSACleanup();
		return FALSE;
	}
	//send intercepted request to server
	if (send(frecv_sock, recv_buf, strlen(recv_buf), 0) == SOCKET_ERROR)
	{
		cout << "Forward Request: send() failed with error: " << WSAGetLastError() << endl;
		closesocket(frecv_sock);
		//WSACleanup();
		return 0;
	}
	else
	{
		cout << "Forward Request: send() success.\n";		
	}	

	//receive request from server
	do{
		bytes_received = recv(frecv_sock,FR_recv_buf,sizeof(FR_recv_buf),0);
		if (bytes_received > 0){
			strcat (FR_recv_buf, "\0");
			cout << "Forward Request: recv() success. Bytes received: " << bytes_received << endl;
			CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ForwardResponse, 0 ,0 ,0);
			//ForwardResponse();
		}
		else if ( bytes_received == 0 ){
			cout << "Forward Request: Connection closed\n";
			closesocket(frecv_sock);
		}
		else if ( bytes_received == SOCKET_ERROR){
			cout << "Forward Request: recv() failed with error: " << WSAGetLastError() << endl;
			closesocket(frecv_sock);
			//WSACleanup();
			return 0;
		}
	}while (bytes_received > 0);
	
}

//Function to accept connection and receive data from browser
int Receive()
{
	SOCKADDR_IN csin;
	int csin_len = sizeof(csin);
	int iResult;
	
	//accept client connection
	client_sock = accept(listen_sock , (LPSOCKADDR)&csin, &csin_len);//pauses here to wait for connection from client
	if (client_sock == INVALID_SOCKET) {
		cout << "accept failed with error: "<< WSAGetLastError() << endl;
		closesocket(client_sock);
		//WSACleanup();
		return 1;
	}
	else{
		cout << "Client connection from IP: " << inet_ntoa(csin.sin_addr) << ":" << csin.sin_port << endl;		
	}
	CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0); //Start another thread to accept.
	
	do {
	iResult = recv(client_sock, recv_buf, sizeof(recv_buf), 0);
		if (iResult == SOCKET_ERROR) {
			closesocket(client_sock);
			cout << "Receive: recv() failed with error: "<< WSAGetLastError() << endl;		
		}
		else if (iResult > 0){
			//null terminate receive buffer
			///recv_buf[iResult] = '\0';
			strcat(recv_buf, "\0");
			cout <<"Receive: Bytes received: " << iResult << endl;
			//forward HTTP request from browser to web server
			cout << recv_buf << endl;
			HANDLE pChildThread = CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)ForwardRequest, 0 , 0 ,0);
			WaitForSingleObject(pChildThread,60000);  //Wait for connection between proxy and remote server
			CloseHandle(pChildThread);		
		}
		else if ( iResult == 0 ){
			cout << "Receive: Connection closed\n";
		}
	}while ( iResult > 0 );

	return 0;
}

//Function which listens for incoming connections to the proxy
int Listen()
{
	SOCKADDR_IN local;
	
	memset(&local,0,sizeof(local));

	local.sin_family = AF_INET;
	local.sin_port = htons(port);
	local.sin_addr.s_addr = INADDR_ANY;

	//create socket for listening to
	listen_sock = socket(AF_INET, SOCK_STREAM, 0);

	//bind function associates a local address with a socket.
	if (bind(listen_sock, (LPSOCKADDR)&local, sizeof(local)) == 0) 
	{	
		if (listen(listen_sock, 10) == 0) 
		{
			cout << "Listenining on: " << port << endl; 
		}
		else
		{
			cout << "Error listening on socket.\n";
		}
	}
	else{
		cout << "bind() failed with error: "<< WSAGetLastError() << endl;
	}	

	//accept and start receiving data from broswer
	CreateThread(0, 0 , (LPTHREAD_START_ROUTINE)Receive, 0 , 0 ,0);
	
	return 0;
}

int CloseServer()
{
	closesocket(client_sock);
	WSACleanup();
	return 1;
}

int _tmain(int argc, _TCHAR* argv[])
{
	InitializeWinsock();
	Listen();
	cin.get();
	return 0;
}

"locks up a lot when downloading certain pages"

That's not a very good description of your problem... can you be more specific?
Does it freeze completely? If so, does it every time if you try page X? Did you run under a debugger to see where it is freezing? etc.

"locks up a lot when downloading certain pages"

That's not a very good description of your problem... can you be more specific?
Does it freeze completely? If so, does it every time if you try page X? Did you run under a debugger to see where it is freezing? etc.

It loads only half a page for example and then will not receive any more data from the webserver. tbh I think there's a problem with the structure of the program.

With very large data (a website) you can't really assume that recv is able to 'fetch' all of the data in one call. Try setting the socket to non blocking, and call recv in a loop until it returns 0 (socked is gracefully closed).

something like (without error handling):

iResult = 0;
do {
iResult = recv(client_sock, recv_buf + iResult, sizeof(recv_buf) - iResult, 0);
} while( iResult != 0 );

Also, are you sure the page you're trying to load is less than 10240?

Note that if you set the socket to non blocking, SOCKET_ERROR doesn't always mean a fatal error, you will have to check if WSAGetLastError wass WSAEWOULDBLOCK, in that case it just means there is no data ready to be received.

Edit:
You'll need to do some more things to make non blocking sockets work nicely, like using select or something simmilar - but let's focus on this problem first.

Edited 5 Years Ago by thelamb: n/a

I've changed the do-while loop to what you suggested and called ioctlsocket() to make the socket non-blocking. However, testing on the local host with Internet Explorer and Mozilla Firefox it ends up infinitely looping "Receive: recv() failed with error: 10053".

This article has been dead for over six months. Start a new discussion instead.