// File: jasmeet13n[P]HTTP-Proxy-Server-Client/client.cpp
// Function: main
int main(int argc, char *argv[]){
	int error;
	if(argc!=4){									// show error if number of command line arguments are not equal to 4
		fprintf(stderr,"Enter PROXY SERVER IP, PROXY SERVER PORT, URL\n");
		return 1;
	}
	struct addrinfo hints;
	struct addrinfo *servinfo, *p;
	//char ipstr[INET_ADDRSTRLEN];	//INET6_ADDRSTRLEN for IPv6

	memset(&hints,0,sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;

	if( (error = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0){	// get address info of server for given IP address and PORT number
		fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(error));
		exit(1);
	}

	int sockfd;
	for(p=servinfo; p!=NULL; p=p->ai_next){
		if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol))== -1){	// create client socket
			perror("client: socket");
			continue;
		}
		break;
	}
	if(p==NULL){
		fprintf(stderr, "my sock fd: failed to connect\n");
		return 2;
	}
	int yes=1;

	if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
    	perror("setsockopt");
    	exit(1);
	}

	int size = 2048, num_bytes;
	char *buf = (char *)malloc((size+1)*sizeof(char));
	unsigned short int len;
	if( (error = connect(sockfd,p->ai_addr,p->ai_addrlen)) == -1){			// connect to server IP Address and PORT number
		perror("client: connect");
	}
	freeaddrinfo(servinfo);
	
	char *query = get_http_request(argv[3]);
	/*char *query = "GET / HTTP/1.0\r\n"
        "Host: www.google.com\r\n"
        "\r\n";*/
	//cout << query << endl;
    len = strlen(query);
    cout << "CLIENT: GET " << argv[3] << endl;
	if( (error = send(sockfd,query,len,0)) == -1){			// send the message to the server
		perror("client: send");
	}
	ofstream myfile;
	char *filename = get_filename(argv[3]);
	stringstream ss;
	ss << filename;

	myfile.open(ss.str().c_str(),ios::out | ios::binary);
	if(!myfile.is_open()){
		cout << "Could not open file in filesystem" << endl;
		exit(0);
	}
	bool header = true;
	bool first=true;
	while(1){
		num_bytes = recv(sockfd,buf,2000,0);			// receive message from server
		//printf("%d\n",num_bytes);
		if(first){
			stringstream tmp;
			tmp << buf;
			string line;
			getline(tmp,line);
			if(line.find("404")!=string::npos)
				cout << "SERVER: **ERROR** " << line << endl;
			else
				cout << "SERVER: " << line << endl;
			first = false;
		}
		int i=0;
		if(header){
			if(num_bytes>=4){
				for(i=3; i<num_bytes; i++){
					if(buf[i]=='\n' && buf[i-1]=='\r'){
						if(buf[i-2]=='\n' && buf[i-3]=='\r'){
							header=false;				// Detect the end of header and start storing data
							i++;
							break;
						}
					}
				}	
			}
		}
		if(!header)
			myfile.write(buf+i,num_bytes-i);			// Store received data in file 
		if(num_bytes == -1){
			perror("client: recv");
		}
		else if(num_bytes == 0){						// if number of bytes received is zero, it means server has closed the connection
			close(sockfd);
			cout << "CLIENT: File Saved at: " << filename << endl;	// Close the connection when server closes the connection
			printf("CLIENT: Connection closed by server\n");
			myfile.flush();
			myfile.close();
			break;							
		}
		myfile.flush();				// Flush the output file buffers
	}
	myfile.close();					// Close the output file
	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x660, %rsp            # imm = 0x660
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x4, -0x8(%rbp)
je 0x2b03
movq 0x34f2(%rip), %rax      # 0x5fd8
movq (%rax), %rdi
leaq 0x1514(%rip), %rsi      # 0x4004
movb $0x0, %al
callq 0x2240
movl $0x1, -0x4(%rbp)
jmp 0x3212
leaq -0x48(%rbp), %rdi
xorl %esi, %esi
movl $0x30, %edx
callq 0x20c0
movl $0x2, -0x44(%rbp)
movl $0x1, -0x40(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
leaq -0x48(%rbp), %rdx
leaq -0x50(%rbp), %rcx
callq 0x21c0
movl %eax, -0x14(%rbp)
cmpl $0x0, %eax
je 0x2b81
movq 0x348b(%rip), %rax      # 0x5fd8
movq (%rax), %rax
movq %rax, -0x600(%rbp)
movl -0x14(%rbp), %edi
callq 0x2220
movq -0x600(%rbp), %rdi
movq %rax, %rdx
leaq 0x14c3(%rip), %rsi      # 0x4033
movb $0x0, %al
callq 0x2240
movl $0x1, %edi
callq 0x21b0
movq -0x50(%rbp), %rax
movq %rax, -0x58(%rbp)
cmpq $0x0, -0x58(%rbp)
je 0x2bd0
movq -0x58(%rbp), %rax
movl 0x4(%rax), %edi
movq -0x58(%rbp), %rax
movl 0x8(%rax), %esi
movq -0x58(%rbp), %rax
movl 0xc(%rax), %edx
callq 0x2070
movl %eax, -0x5c(%rbp)
cmpl $-0x1, %eax
jne 0x2bc0
leaq 0x1491(%rip), %rdi      # 0x404a
callq 0x2150
jmp 0x2bc2
jmp 0x2bd0
movq -0x58(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x58(%rbp)
jmp 0x2b89
cmpq $0x0, -0x58(%rbp)
jne 0x2bfb
movq 0x33fa(%rip), %rax      # 0x5fd8
movq (%rax), %rdi
leaq 0x1471(%rip), %rsi      # 0x4059
movb $0x0, %al
callq 0x2240
movl $0x2, -0x4(%rbp)
jmp 0x3212
movl $0x1, -0x60(%rbp)
movl -0x5c(%rbp), %edi
movl $0x1, %esi
movl $0x2, %edx
leaq -0x60(%rbp), %rcx
movl $0x4, %r8d
callq 0x2290
cmpl $-0x1, %eax
jne 0x2c39
leaq 0x144e(%rip), %rdi      # 0x4078
callq 0x2150
movl $0x1, %edi
callq 0x21b0
movl $0x800, -0x64(%rbp)     # imm = 0x800
movl -0x64(%rbp), %eax
addl $0x1, %eax
movslq %eax, %rdi
shlq $0x0, %rdi
callq 0x2200
movq %rax, -0x70(%rbp)
movl -0x5c(%rbp), %edi
movq -0x58(%rbp), %rax
movq 0x18(%rax), %rsi
movq -0x58(%rbp), %rax
movl 0x10(%rax), %edx
callq 0x2140
movl %eax, -0x14(%rbp)
cmpl $-0x1, %eax
jne 0x2c81
leaq 0x1407(%rip), %rdi      # 0x4083
callq 0x2150
movq -0x50(%rbp), %rdi
callq 0x21e0
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0x2530
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rdi
callq 0x20a0
movw %ax, -0x72(%rbp)
movq 0x3321(%rip), %rdi      # 0x5fd0
leaq 0x13dd(%rip), %rsi      # 0x4093
callq 0x2190
movq %rax, %rdi
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rsi
callq 0x2190
movq %rax, %rdi
movq 0x32eb(%rip), %rsi      # 0x5fc0
callq 0x21a0
movl -0x5c(%rbp), %edi
movq -0x80(%rbp), %rsi
movzwl -0x72(%rbp), %eax
movl %eax, %edx
xorl %ecx, %ecx
callq 0x20b0
movl %eax, -0x14(%rbp)
cmpl $-0x1, %eax
jne 0x2d02
leaq 0x13a3(%rip), %rdi      # 0x40a0
callq 0x2150
leaq -0x280(%rbp), %rdi
callq 0x2270
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rdi
callq 0x28c0
movq %rax, -0x288(%rbp)
leaq -0x410(%rbp), %rdi
callq 0x20f0
jmp 0x2d30
leaq -0x400(%rbp), %rdi
movq -0x288(%rbp), %rsi
callq 0x2190
jmp 0x2d45
leaq -0x440(%rbp), %rdi
leaq -0x410(%rbp), %rsi
callq 0x2180
jmp 0x2d5a
leaq -0x440(%rbp), %rdi
callq 0x2090
movq %rax, -0x610(%rbp)
movl $0x10, %edi
movl $0x4, %esi
callq 0x3230
movl %eax, -0x604(%rbp)
jmp 0x2d84
movl -0x604(%rbp), %edx
movq -0x610(%rbp), %rsi
leaq -0x280(%rbp), %rdi
callq 0x2040
jmp 0x2d9f
leaq -0x440(%rbp), %rdi
callq 0x20d0
leaq -0x280(%rbp), %rdi
callq 0x2120
movb %al, -0x611(%rbp)
jmp 0x2dbf
movb -0x611(%rbp), %al
testb $0x1, %al
jne 0x2e58
jmp 0x2dcf
movq 0x31fa(%rip), %rdi      # 0x5fd0
leaq 0x12d0(%rip), %rsi      # 0x40ad
callq 0x2190
movq %rax, -0x620(%rbp)
jmp 0x2deb
movq -0x620(%rbp), %rdi
movq 0x31c7(%rip), %rsi      # 0x5fc0
callq 0x21a0
jmp 0x2e00
xorl %edi, %edi
callq 0x21b0
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x418(%rbp)
movl %eax, -0x41c(%rbp)
jmp 0x3204
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x418(%rbp)
movl %eax, -0x41c(%rbp)
jmp 0x31f8
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x418(%rbp)
movl %eax, -0x41c(%rbp)
leaq -0x440(%rbp), %rdi
callq 0x20d0
jmp 0x31f8
movb $0x1, -0x441(%rbp)
movb $0x1, -0x442(%rbp)
jmp 0x2e68
movl -0x5c(%rbp), %edi
movq -0x70(%rbp), %rsi
movl $0x7d0, %edx            # imm = 0x7D0
xorl %ecx, %ecx
callq 0x2080
movq %rax, -0x628(%rbp)
jmp 0x2e84
movq -0x628(%rbp), %rax
movl %eax, -0x68(%rbp)
testb $0x1, -0x442(%rbp)
je 0x300e
leaq -0x5d0(%rbp), %rdi
callq 0x20f0
jmp 0x2ea9
leaq -0x5c0(%rbp), %rdi
movq -0x70(%rbp), %rsi
callq 0x2190
jmp 0x2ebb
leaq -0x5f0(%rbp), %rdi
movq %rdi, -0x630(%rbp)
callq 0x2210
movq -0x630(%rbp), %rsi
leaq -0x5d0(%rbp), %rdi
callq 0x2060
jmp 0x2ee3
leaq -0x5f0(%rbp), %rdi
leaq 0x11de(%rip), %rsi      # 0x40cf
xorl %eax, %eax
movl %eax, %edx
callq 0x22c0
cmpq $-0x1, %rax
je 0x2f8d
movq 0x30c5(%rip), %rdi      # 0x5fd0
leaq 0x11c1(%rip), %rsi      # 0x40d3
callq 0x2190
movq %rax, -0x638(%rbp)
jmp 0x2f20
movq -0x638(%rbp), %rdi
leaq -0x5f0(%rbp), %rsi
callq 0x2170
movq %rax, -0x640(%rbp)
jmp 0x2f3c
movq -0x640(%rbp), %rdi
movq 0x3076(%rip), %rsi      # 0x5fc0
callq 0x21a0
jmp 0x2f51
jmp 0x2fdc
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x418(%rbp)
movl %eax, -0x41c(%rbp)
jmp 0x2ffd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x418(%rbp)
movl %eax, -0x41c(%rbp)
leaq -0x5f0(%rbp), %rdi
callq 0x20d0
jmp 0x2ffd
movq 0x303c(%rip), %rdi      # 0x5fd0
leaq 0x114b(%rip), %rsi      # 0x40e6
callq 0x2190
movq %rax, -0x648(%rbp)
jmp 0x2fa9
movq -0x648(%rbp), %rdi
leaq -0x5f0(%rbp), %rsi
callq 0x2170
movq %rax, -0x650(%rbp)
jmp 0x2fc5
movq -0x650(%rbp), %rdi
movq 0x2fed(%rip), %rsi      # 0x5fc0
callq 0x21a0
jmp 0x2fda
jmp 0x2fdc
movb $0x0, -0x442(%rbp)
leaq -0x5f0(%rbp), %rdi
callq 0x20d0
leaq -0x5d0(%rbp), %rdi
callq 0x2100
jmp 0x300e
leaq -0x5d0(%rbp), %rdi
callq 0x2100
jmp 0x31f8
movl $0x0, -0x5f4(%rbp)
testb $0x1, -0x441(%rbp)
je 0x30db
cmpl $0x4, -0x68(%rbp)
jl 0x30d9
movl $0x3, -0x5f4(%rbp)
movl -0x5f4(%rbp), %eax
cmpl -0x68(%rbp), %eax
jge 0x30d7
movq -0x70(%rbp), %rax
movslq -0x5f4(%rbp), %rcx
movsbl (%rax,%rcx), %eax
cmpl $0xa, %eax
jne 0x30c1
movq -0x70(%rbp), %rax
movl -0x5f4(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0xd, %eax
jne 0x30c1
movq -0x70(%rbp), %rax
movl -0x5f4(%rbp), %ecx
subl $0x2, %ecx
movslq %ecx, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0xa, %eax
jne 0x30bf
movq -0x70(%rbp), %rax
movl -0x5f4(%rbp), %ecx
subl $0x3, %ecx
movslq %ecx, %rcx
movsbl (%rax,%rcx), %eax
cmpl $0xd, %eax
jne 0x30bf
movb $0x0, -0x441(%rbp)
movl -0x5f4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5f4(%rbp)
jmp 0x30d7
jmp 0x30c1
jmp 0x30c3
movl -0x5f4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5f4(%rbp)
jmp 0x3039
jmp 0x30d9
jmp 0x30db
testb $0x1, -0x441(%rbp)
jne 0x310c
movq -0x70(%rbp), %rsi
movslq -0x5f4(%rbp), %rax
movl %eax, %ecx
addq %rax, %rsi
movl -0x68(%rbp), %eax
subl %ecx, %eax
movslq %eax, %rdx
leaq -0x280(%rbp), %rdi
callq 0x21f0
jmp 0x310a
jmp 0x310c
cmpl $-0x1, -0x68(%rbp)
jne 0x3125
leaq 0xfd6(%rip), %rdi       # 0x40ef
callq 0x2150
jmp 0x3120
jmp 0x31b6
cmpl $0x0, -0x68(%rbp)
jne 0x31b4
movl -0x5c(%rbp), %edi
callq 0x22b0
jmp 0x3139
movq 0x2e90(%rip), %rdi      # 0x5fd0
leaq 0xfb5(%rip), %rsi       # 0x40fc
callq 0x2190
movq %rax, -0x658(%rbp)
jmp 0x3155
movq -0x658(%rbp), %rdi
movq -0x288(%rbp), %rsi
callq 0x2190
movq %rax, -0x660(%rbp)
jmp 0x3171
movq -0x660(%rbp), %rdi
movq 0x2e41(%rip), %rsi      # 0x5fc0
callq 0x21a0
jmp 0x3186
leaq 0xf87(%rip), %rdi       # 0x4114
xorl %eax, %eax
callq 0x2030
jmp 0x3196
leaq -0x280(%rbp), %rdi
callq 0x20e0
jmp 0x31a4
leaq -0x280(%rbp), %rdi
callq 0x2230
jmp 0x31b2
jmp 0x31c9
jmp 0x31b6
leaq -0x280(%rbp), %rdi
callq 0x20e0
jmp 0x31c4
jmp 0x2e66
leaq -0x280(%rbp), %rdi
callq 0x2230
jmp 0x31d7
movl $0x0, -0x4(%rbp)
leaq -0x410(%rbp), %rdi
callq 0x2100
leaq -0x280(%rbp), %rdi
callq 0x2250
jmp 0x3212
leaq -0x410(%rbp), %rdi
callq 0x2100
leaq -0x280(%rbp), %rdi
callq 0x2250
jmp 0x321e
movl -0x4(%rbp), %eax
addq $0x660, %rsp            # imm = 0x660
popq %rbp
retq
movq -0x418(%rbp), %rdi
callq 0x2280
nopw (%rax,%rax)