// File: /workspace/github_cpp_makefile_star2_O1/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x588, %rsp            # imm = 0x588
cmpl $0x4, %edi
jne 0x2c92
movq %rsi, %r15
xorps %xmm0, %xmm0
leaq -0x5b0(%rbp), %rdx
movaps %xmm0, (%rdx)
movaps %xmm0, 0x10(%rdx)
movaps %xmm0, 0x20(%rdx)
movabsq $0x100000002, %rax      # imm = 0x100000002
movq %rax, 0x4(%rdx)
movq 0x8(%rsi), %rdi
movq 0x10(%rsi), %rsi
leaq -0x60(%rbp), %rcx
callq 0x2180
testl %eax, %eax
jne 0x2ccc
movq -0x60(%rbp), %r12
testq %r12, %r12
sete %r14b
je 0x274f
movl 0x4(%r12), %edi
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
callq 0x2060
cmpl $-0x1, %eax
je 0x2714
movl %eax, %r13d
jmp 0x2755
leaq 0x94b(%rip), %rbx       # 0x3066
movq %rbx, %rdi
callq 0x2110
movq 0x28(%r12), %r12
testq %r12, %r12
sete %r14b
je 0x274f
movl 0x4(%r12), %edi
movl 0x8(%r12), %esi
movl 0xc(%r12), %edx
callq 0x2060
movl %eax, %r13d
cmpl $-0x1, %eax
je 0x271b
jmp 0x2755
movl $0xffffffff, %r13d      # imm = 0xFFFFFFFF
testb %r14b, %r14b
jne 0x2c9e
leaq -0x64(%rbp), %rcx
movl $0x1, (%rcx)
movl %r13d, %edi
movl $0x1, %esi
movl $0x2, %edx
movl $0x4, %r8d
callq 0x2270
cmpl $-0x1, %eax
je 0x2cd3
movl $0x801, %edi            # imm = 0x801
callq 0x21b0
movq %rax, %r14
movq 0x18(%r12), %rsi
movl 0x10(%r12), %edx
movl %r13d, -0x2c(%rbp)
movl %r13d, %edi
callq 0x2100
cmpl $-0x1, %eax
je 0x2caa
movq -0x60(%rbp), %rdi
callq 0x2190
movq 0x18(%r15), %rdi
callq 0x24ba
movq %rax, %r12
movq %rax, %rdi
callq 0x2090
movq %rax, -0x38(%rbp)
movq 0x27f3(%rip), %r13      # 0x4fd0
leaq 0x8cb(%rip), %rsi       # 0x30af
movl $0xc, %edx
movq %r13, %rdi
callq 0x2160
movq 0x18(%r15), %rbx
testq %rbx, %rbx
je 0x2816
movq %rbx, %rdi
callq 0x2090
movq 0x27c7(%rip), %rdi      # 0x4fd0
movq %rbx, %rsi
movq %rax, %rdx
callq 0x2160
jmp 0x282f
movq (%r13), %rax
movq -0x18(%rax), %rax
leaq (%rax,%r13), %rdi
movl 0x20(%r13,%rax), %esi
orl $0x1, %esi
callq 0x2230
movq (%r13), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %r13, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20c0
movzwl -0x38(%rbp), %edx
movl -0x2c(%rbp), %edi
movq %r12, %rsi
xorl %ecx, %ecx
callq 0x20b0
cmpl $-0x1, %eax
je 0x2cbb
leaq -0x3f0(%rbp), %rdi
callq 0x2240
movq 0x18(%r15), %rdi
callq 0x25da
movq %rax, %r15
leaq -0x578(%rbp), %rdi
callq 0x20d0
leaq -0x568(%rbp), %rbx
testq %r15, %r15
je 0x28b9
movq %r15, %rdi
callq 0x2090
movq %rbx, %rdi
movq %r15, %rsi
movq %rax, %rdx
callq 0x2160
jmp 0x28d9
movq -0x568(%rbp), %rax
movq -0x18(%rax), %rax
addq %rax, %rbx
movl -0x548(%rbp,%rax), %esi
orl $0x1, %esi
movq %rbx, %rdi
callq 0x2230
leaq -0x560(%rbp), %rsi
leaq -0x1f0(%rbp), %r12
movq %r12, %rdi
callq 0x2220
movq -0x1f0(%rbp), %rsi
leaq -0x3f0(%rbp), %rdi
movl $0x14, %edx
callq 0x2040
leaq -0x1e0(%rbp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x2926
movq -0x1e0(%rbp), %rsi
incq %rsi
callq 0x2150
movq %r15, -0x38(%rbp)
leaq -0x380(%rbp), %rdi
callq 0x2050
testb %al, %al
je 0x2cd8
movb $0x1, %r15b
movb $0x1, %bl
movl $0x7d0, %edx            # imm = 0x7D0
movl -0x2c(%rbp), %edi
movq %r14, %rsi
xorl %ecx, %ecx
callq 0x2070
movq %rax, %r13
testb $0x1, %bl
je 0x2ad8
movq %r12, %rdi
callq 0x20d0
testq %r14, %r14
je 0x298a
movq %r14, %rdi
callq 0x2090
leaq -0x1e0(%rbp), %rdi
movq %r14, %rsi
movq %rax, %rdx
callq 0x2160
jmp 0x29af
movq -0x1e0(%rbp), %rax
movq -0x18(%rax), %rax
leaq -0x1e0(%rbp), %rcx
leaq (%rcx,%rax), %rdi
movl -0x1c0(%rbp,%rax), %esi
orl $0x1, %esi
callq 0x2230
leaq -0x48(%rbp), %rax
movq %rax, -0x58(%rbp)
movq $0x0, -0x50(%rbp)
movb $0x0, -0x48(%rbp)
movq -0x1f0(%rbp), %rax
movq -0x18(%rax), %rdi
addq %r12, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %edx
movq %r12, %rdi
leaq -0x58(%rbp), %rsi
callq 0x2280
movl $0x3, %ecx
leaq -0x58(%rbp), %rdi
leaq 0x6f1(%rip), %rsi       # 0x30eb
xorl %edx, %edx
callq 0x2250
cmpq $-0x1, %rax
je 0x2a4c
movl $0x12, %edx
movq 0x25bd(%rip), %rdi      # 0x4fd0
leaq 0x6d5(%rip), %rsi       # 0x30ef
callq 0x2160
movq -0x58(%rbp), %rsi
movq -0x50(%rbp), %rdx
movq 0x25a2(%rip), %rdi      # 0x4fd0
callq 0x2160
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2140
jmp 0x2a8f
movl $0x8, %edx
movq 0x2578(%rip), %rdi      # 0x4fd0
leaq 0x6a3(%rip), %rsi       # 0x3102
callq 0x2160
movq -0x58(%rbp), %rsi
movq -0x50(%rbp), %rdx
movq 0x255d(%rip), %rdi      # 0x4fd0
callq 0x2160
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x20c0
movq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %rax
cmpq %rax, %rdi
je 0x2abb
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2150
movq %r12, %rdi
movq 0x24eb(%rip), %rsi      # 0x4fb0
callq 0x20e0
leaq -0x170(%rbp), %rdi
callq 0x2080
xorl %ebx, %ebx
xorl %eax, %eax
testb $0x1, %r15b
je 0x2b1e
cmpl $0x4, %r13d
jl 0x2b1e
movl %r13d, %ecx
andl $0x7fffffff, %ecx       # imm = 0x7FFFFFFF
movl $0x3, %eax
cmpb $0xa, (%r14,%rax)
jne 0x2b13
cmpb $0xd, -0x1(%r14,%rax)
jne 0x2b13
cmpb $0xa, -0x2(%r14,%rax)
jne 0x2b13
cmpb $0xd, -0x3(%r14,%rax)
je 0x2b68
incq %rax
cmpq %rax, %rcx
jne 0x2af4
movl %r13d, %eax
testb $0x1, %r15b
jne 0x2b3e
cltq
leaq (%r14,%rax), %rsi
movl %r13d, %ecx
subl %eax, %ecx
movslq %ecx, %rdx
leaq -0x3f0(%rbp), %rdi
callq 0x21a0
cmpl $-0x1, %r13d
je 0x2b5a
testl %r13d, %r13d
je 0x2b6f
leaq -0x3f0(%rbp), %rdi
callq 0x20c0
jmp 0x2943
leaq 0x5aa(%rip), %rdi       # 0x310b
callq 0x2110
jmp 0x2b49
incl %eax
xorl %r15d, %r15d
jmp 0x2b1e
movl -0x2c(%rbp), %edi
callq 0x22a0
movq 0x2452(%rip), %rbx      # 0x4fd0
leaq 0x593(%rip), %rsi       # 0x3118
movl $0x17, %edx
movq %rbx, %rdi
callq 0x2160
movq -0x38(%rbp), %r14
testq %r14, %r14
je 0x2bb7
movq %r14, %rdi
callq 0x2090
movq 0x2426(%rip), %rdi      # 0x4fd0
movq %r14, %rsi
movq %rax, %rdx
callq 0x2160
jmp 0x2bce
movq (%rbx), %rax
movq -0x18(%rax), %rax
leaq (%rbx,%rax), %rdi
movl 0x20(%rbx,%rax), %esi
orl $0x1, %esi
callq 0x2230
movq (%rbx), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x2140
movsbl %al, %esi
movq 0x23e4(%rip), %rdi      # 0x4fd0
callq 0x2030
movq %rax, %rdi
callq 0x20c0
leaq 0x530(%rip), %rdi       # 0x3130
callq 0x2210
leaq -0x3f0(%rbp), %rdi
callq 0x20c0
leaq -0x3f0(%rbp), %rdi
callq 0x21d0
leaq -0x3f0(%rbp), %rdi
callq 0x21d0
movq 0x2380(%rip), %rsi      # 0x4fb0
leaq -0x578(%rbp), %rdi
callq 0x20e0
leaq -0x4f8(%rbp), %rdi
callq 0x2080
movq 0x2379(%rip), %rax      # 0x4fc8
movq (%rax), %rcx
movq 0x18(%rax), %rax
leaq -0x3e8(%rbp), %rdi
movq %rcx, -0x8(%rdi)
movq -0x18(%rcx), %rcx
movq %rax, -0x3f0(%rbp,%rcx)
callq 0x2120
leaq -0x2f8(%rbp), %rdi
callq 0x2080
xorl %eax, %eax
addq $0x588, %rsp            # imm = 0x588
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x22c0
movl $0x1, %eax
jmp 0x2c80
callq 0x2338
movl $0x2, %eax
jmp 0x2c80
leaq 0x3ee(%rip), %rdi       # 0x309f
callq 0x2110
jmp 0x27b5
leaq 0x3fa(%rip), %rdi       # 0x30bc
callq 0x2110
jmp 0x2871
movl %eax, %edi
callq 0x22ef
callq 0x2320
movq 0x22f1(%rip), %rdi      # 0x4fd0
leaq 0x3e3(%rip), %rsi       # 0x30c9
movl $0x21, %edx
callq 0x2160
movq 0x22d9(%rip), %rdi      # 0x4fd0
callq 0x20a0
xorl %edi, %edi
callq 0x2170
jmp 0x2d3d
movq %rax, %rbx
leaq -0x1e0(%rbp), %rax
movq -0x10(%rax), %rdi
cmpq %rax, %rdi
je 0x2d7d
movq -0x1e0(%rbp), %rsi
incq %rsi
callq 0x2150
jmp 0x2d7d
jmp 0x2d3d
movq %rax, %rbx
jmp 0x2d9c
jmp 0x2d3d
jmp 0x2d3d
jmp 0x2d3d
movq %rax, %rbx
jmp 0x2d5e
jmp 0x2d3d
movq %rax, %rbx
jmp 0x2d7d
movq %rax, %rbx
movq -0x58(%rbp), %rdi
leaq -0x48(%rbp), %rax
cmpq %rax, %rdi
je 0x2d5e
movq -0x48(%rbp), %rsi
incq %rsi
callq 0x2150
movq 0x224b(%rip), %rsi      # 0x4fb0
leaq -0x1f0(%rbp), %rdi
callq 0x20e0
leaq -0x170(%rbp), %rdi
callq 0x2080
movq 0x222c(%rip), %rsi      # 0x4fb0
leaq -0x578(%rbp), %rdi
callq 0x20e0
leaq -0x4f8(%rbp), %rdi
callq 0x2080
leaq -0x3f0(%rbp), %rdi
callq 0x21f0
movq %rbx, %rdi
callq 0x2260