// C Socket.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "C Socket.h"
#include "afxsock.h"
#include "string"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define MSIZE 10240
#define HTTP "http://"

// The one and only application object

CWinApp theApp;

using namespace std;

DWORD WINAPI ClientToProxy(LPVOID arg)
{
	SOCKET* hConnected = (SOCKET*)arg;
	CSocket chrome;
	//Chuyen ve lai CSocket
	chrome.Attach(*hConnected);
	char *IP, *url;
	int port;
	char buffer[MSIZE], buffer1[MSIZE];
	int b_length;

	b_length = chrome.Receive(&buffer, MSIZE, 0); // nhận gói tin từ web browser
													  //cắt thông tin bị dư từ gói tin
	if (b_length >= MSIZE) buffer[b_length - 1] = 0;
	else
	{
		if (b_length > 0) buffer[b_length] = 0;
		else buffer[0] = 0;
	}

	cout << "Recevie " << b_length << " Data: " << endl << buffer << endl << endl;

	Get_URL_Port(buffer, url, port);
	IP = Get_ip(url);
	cout << "URL: " << url << endl;
	cout << "Connecting to: " << IP << endl;

	CSocket proxy_server;
	proxy_server.Create();

	if (proxy_server.Connect(convertCharArrayToLPCWSTR(IP), port) == true)
	{
		cout << "Ket noi toi Server thanh cong !!!" << endl << endl;
		int check;
		check = proxy_server.Send(buffer, strlen(buffer), 0);
		if (check == SOCKET_ERROR)
		{
			cout << "Khong the gui goi tin len sever" << endl;
			proxy_server.Close();
			return 0;
		}
		else
		{
			b_length = proxy_server.Receive(&buffer1, MSIZE, 0);
			chrome.Send(buffer1, b_length, 0);

			if (b_length >= MSIZE) buffer1[b_length - 1] = 0;
			else
			{
				if (b_length > 0) buffer1[b_length] = 0;
				else buffer1[0] = 0;
			}
			cout << "Web Sever Send Header " << b_length << " Data: " << endl << buffer1 << endl << endl;

			int cont_length = Get_Content_Length(buffer1);
			cout << "Content - Length: " << cont_length << endl;
			int s_bytes = 0;
			s_bytes += b_length;
			while (cont_length > s_bytes)
			{
				b_length = proxy_server.Receive(&buffer1, MSIZE, 0);
				chrome.Send(buffer1, b_length, 0);
				//cout << buffer1 << endl;
				ZeroMemory(buffer1, b_length);
				s_bytes += b_length;
			};
			proxy_server.Close();
		}
	}
}


int main()
{
	int nRetCode = 0;

	HMODULE hModule = ::GetModuleHandle(nullptr);

	if (hModule != nullptr)
	{
		// initialize MFC and print and error on failure
		if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
		{
			// TODO: change error code to suit your needs
			wprintf(L"Fatal Error: MFC initialization failed\n");
			nRetCode = 1;
		}
		else
		{
			AfxSocketInit(NULL);
			// TODO: code your application's behavior here.
			if (AfxSocketInit() == FALSE)
			{
				cout << "Khong the khoi tao Socket Libraray";
				return FALSE;
			}
			CSocket chrome_proxy;
			CSocket chrome;
			DWORD threadID;
			HANDLE threadStatus;

			if (chrome_proxy.Create(8888, SOCK_STREAM, NULL) != 0)
			{
				cout << "Server khoi tao thanh cong !!!" << endl;
			}
			else
			{
				cout << "Khong the tao server!!!";
				chrome_proxy.Close();
				return FALSE;
			}
			do
			{
				if (chrome_proxy.Listen(5) == FALSE)
				{
					cout << "Khong the lang nghe tren port nay !!!" << endl;
					chrome_proxy.Close();
					return FALSE;
				}
				else
				{
					cout << "Lang nghe thanh cong !!!" << endl;
				}
				if (chrome_proxy.Accept(chrome) == true)
				{
					cout << "Da co client ket noi" << endl;
					SOCKET* hConnected = new SOCKET();
					//Chuyển đỏi CSocket thanh Socket
					*hConnected = chrome.Detach();
					threadStatus = CreateThread(NULL, 0, ClientToProxy, hConnected, 0, &threadID);
				}
			} while (true);
		}
	}
    else
    {
        // TODO: change error code to suit your needs
        wprintf(L"Fatal Error: GetModuleHandle failed\n");
        nRetCode = 1;
    }

    return nRetCode;
}


wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
{
	wchar_t* wString = new wchar_t[4096];
	MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
	return wString;
}

char *Get_ip(char *host)
{
	struct hostent *hstnm;
	hstnm = gethostbyname(host);
	if (hstnm == NULL) {
		cout << "Can't get IP address" << endl;
	}
	else
	{
		char *IP = new char[15];
		if (inet_ntop(AF_INET, (void *)hstnm->h_addr_list[0], IP, 15) == NULL)
			cout << "Can't resolve host" << endl;
		return IP;
	}
}

void Get_URL_Port(char* pac, char* &url, int &port)
{
	string arr(pac), result, temp;
	int pos1, pos2, dot_pos;
	pos1 = arr.find_first_of(HTTP) + 7; // 7 là độ dài chuỗi http://
	temp = arr.substr(pos1);
	pos2 = temp.find_first_of("/");
	result = temp.substr(0, pos2);
	dot_pos = result.find_first_of(":");
	if (dot_pos != -1)
	{
		string host, p;
		host = result.substr(0, dot_pos);
		p = result.substr(dot_pos + 1, result.length() - dot_pos);

		url = new char[host.length()];
		for (int i = 0;i < host.length();i++)
		{
			url[i] = host[i];
		}
		url[host.length()] = '\0';
		port = stoi(p);
	}
	else
	{
		url = new char[result.length()];
		for (int i = 0;i < result.length();i++)
		{
			url[i] = result[i];
		}
		url[result.length()] = '\0';
		port = 80; // port mặc định của http
	}
}

bool Check_HTTP(char * pac)
{
	if ((pac[0]=='G' && pac[1]=='E' && pac[2] == 'T')|| pac[0]=='P' && pac[1]=='O' && pac[2]=='S' && pac[3]=='T')
		return true;
	return false;
}

int Get_Content_Length(char * pac)
{
	string arr(pac);
	string ct = "Content-Length: ";
	string temp;
	int pos = arr.find(ct);
	if (pos == -1) return 0;
	else
	{
		pos += ct.length();
		while (arr[pos] >= '0' && arr[pos] <= '9')
		{
			temp.push_back(arr[pos]);
			pos += 1;
		}
	}
	return stoi(temp);
}