// File: /workspace/github_cpp_makefile_star2_O2/akw0088[P]openssl/rsync_upload.c
// Function: rsync_file_download
int rsync_file_download(char *ip_str, unsigned short int port, char *response, int size, unsigned int *final_size, char *file_name, unsigned int block_size)
{
	struct sockaddr_in	servaddr;
	SOCKET sock;
	int ret;

	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	memset(&servaddr, 0, sizeof(struct sockaddr_in));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = inet_addr(ip_str);
	servaddr.sin_port = htons(port);

	// 3 way handshake
	printf("Attempting to connect to %s\n", ip_str);
	ret = connect(sock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));
	if (ret == SOCKET_ERROR)
	{
#ifdef _WIN32
		ret = WSAGetLastError();

		switch (ret)
		{
		case WSAETIMEDOUT:
			printf("Fatal Error: Connection timed out.\n");
			break;
		case WSAECONNREFUSED:
			printf("Fatal Error: Connection refused\n");
			break;
		case WSAEHOSTUNREACH:
			printf("Fatal Error: Router sent ICMP packet (destination unreachable)\n");
			break;
		default:
			printf("Fatal Error: %d\n", ret);
			break;
		}
#else
		ret = errno;

	        switch(ret)
	        {
		case ENETUNREACH:
			printf("Fatal Error: The network is unreachable from this host at this time.\n(Bad IP address)\n");
			break;
	        case ETIMEDOUT:
	                printf("Fatal Error: Connecting timed out.\n");
	                break;
	        case ECONNREFUSED:
	                printf("Fatal Error: Connection refused\n");
	                break;
	        case EHOSTUNREACH:
	                printf("Fatal Error: router sent ICMP packet (destination unreachable)\n");
	                break;
	        default:
	                printf("Fatal Error: %d\n", ret);
	                break;
	        }
#endif
		return -1;
	}
	printf("TCP handshake completed\n");

	memset(response, 0, size);

	unsigned int rnum_block = 0;
	unsigned int rfile_size = 0;
	if (Recv(sock, (char *)&rfile_size, sizeof(unsigned int), 0) == -1)
	{
		printf("recv failed\r\n");
		return -1;
	}

	if ( Recv(sock, (char *)file_name, PATH_SIZE, 0) == -1)
	{
		printf("recv failed\r\n");
		return -1;
	}

	char temp[PATH_SIZE] = {0};
	StripChars(file_name, temp, ".\\/;:*?\"<>|");
	strcpy(file_name, temp);

	unsigned char rfile_hash[MD5_SIZE + 1] = {0};
	if ( Recv(sock, (char *)rfile_hash, MD5_SIZE, 0) == -1)
	{
		printf("recv failed\r\n");
		return -1;
	}


	printf("Opening local %s file for compare\r\n", file_name);
	unsigned int file_size = 0;
	char *data = get_file(file_name, &file_size);
	if (data == NULL)
	{
		printf("Unable to open %s\r\n", file_name);
	}

	unsigned char file_hash[MD5_SIZE + 1] = {0};
	if (data != NULL)
	{
		md5sum((char *)&data[0], file_size, (char *)file_hash);
	}

	if ( Send(sock, (char *)file_hash, MD5_SIZE, 0) == -1)
	{
		printf("recv failed\r\n");
		return -1;
	}

	if (rfile_size == file_size)
	{
		printf("Our file is same size\r\n");
		if (strcmp((char *)file_hash, (char *)rfile_hash) == 0)
		{
			printf("Files have the same hash\r\n");
			*final_size = 0;
			return 0;
		}

	}
	else if (rfile_size > file_size)
	{
		printf("Our file is smaller by %d bytes\r\n", rfile_size - file_size);
	}
	else
	{
		printf("Our file is larger by %d bytes\r\n", file_size - rfile_size);
	}

	if (data == NULL)
	{
		file_size = rfile_size;
	}

	// Calculate block size first
	unsigned int num_block = file_size / block_size;
	int remainder = file_size - num_block * block_size;
	if (remainder > 0)
	{
		num_block++;
	}


	printf("File has %d blocks %d bytes remainder %d\r\n", num_block, file_size, remainder);

	char **md5_array = (char **)malloc(num_block * sizeof(char *));
	if (md5_array == NULL)
	{
		perror("malloc failed");
		return -1;
	}

	unsigned int *checksum_adler32 = (unsigned int *)malloc(num_block * sizeof(unsigned int));
	if (checksum_adler32 == NULL)
	{
		perror("malloc failed");
		return -1;
	}

	for (unsigned int i = 0; i < num_block; i++)
	{
		checksum_adler32[i] = -1;
		md5_array[i] = md5_array[i] = malloc(MD5_SIZE + 1);
		if (md5_array[i] == NULL)
		{
			perror("malloc failed");
			return -1;
		}

		memset(md5_array[i], 0, MD5_SIZE + 1);
	}

	if (data)
	{
		printf("Calculating adler32 and md5 hashes for each block\r\n");
		for (unsigned int i = 0; i < num_block; i++)
		{
			unsigned int rsize = block_size;

			if (i == num_block - 1)
			{
				rsize = file_size - block_size * i;
			}
			checksum_adler32[i] = adler32((unsigned char *)&data[block_size * i], rsize);
			md5sum((char *)&data[block_size * i], rsize, md5_array[i]);
		}
	}
	
	printf("Sending hashes to server\r\n");	
	block_t *block = (block_t *)malloc(num_block * sizeof(block_t));
	if (block == NULL)
	{
		perror("malloc failed");
		return -1;
	}

	Send(sock, (char *)&num_block, sizeof(int), 0);
	Send(sock, (char *)&block_size, sizeof(int), 0);
	Send(sock, (char *)checksum_adler32, num_block * sizeof(int), 0);
	for (unsigned int i = 0; i < num_block; i++)
	{
		Send(sock, (char *)md5_array[i], MD5_SIZE, 0);
	}

	if ( Recv(sock, (char *)&block[0], sizeof(block_t) * num_block, 0) == -1)
	{
		printf("recv failed\r\n");
		return -1;
	}

	printf("Got offsets for each block\r\n");
	for (unsigned int i = 0; i < num_block; i++)
	{
		int rsize = block_size;

		if (i == num_block - 1)
		{
			rsize = rfile_size - (num_block - 1) * block_size;
		}

		if (block[i].offset == -1)
		{
			printf("\tmissing block %d [%d bytes]\r\n", i, rsize);
		}
	}

	unsigned int diff_size = 0;
	if ( Recv(sock, (char *)&diff_size, sizeof(unsigned int), 0) == -1)
	{
		printf("recv failed\r\n");
		return -1;
	}

	printf("Delta size is %d bytes\r\n", diff_size);

	unsigned char *diff = (unsigned char *)malloc(diff_size + block_size);
	if (diff == NULL)
	{
		perror("malloc failed");
	}

	unsigned int download_size = 0;
	download_size = Recv(sock, (char *)diff, diff_size, 0);
	if (download_size == -1)
	{
		printf("recv failed\r\n");
		return -1;
	}

	printf("Downloaded delta\r\n");
	closesocket(sock);

	assemble_download(response, rfile_size, data, file_size, block, num_block, block_size, (char *)diff, diff_size);
	*final_size = rfile_size;

	// Calculate final hash to be sure it matches
	memset(file_hash, 0, MD5_SIZE + 1);
	md5sum(response, *final_size, (char *)file_hash);


	if (strcmp((char *)file_hash, (char *)rfile_hash) != 0)
	{
		printf("Rsync failed\r\n");
		printf("hashes dont match\r\n\tremote: %s\r\n\tlocal : %s\r\n", file_hash, rfile_hash);
		printf("file size\r\n\tremote: %d\r\n\tlocal : %d\r\n", *final_size, rfile_size);
		printf("First 8 bytes\r\n");
		for (int i = 0; i < 8; i++)
		{
			printf("%02X ", response[i]);
		}

		printf("\r\nLast 8 bytes\r\n");
		for (int i = 0; i < 8; i++)
		{
			printf("%02X ", response[i + *final_size - 8]);
		}
		return -1;
	}

	printf("Rsync successful\r\n");
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x158, %rsp            # imm = 0x158
movq %r9, 0x18(%rsp)
movq %r8, 0x28(%rsp)
movl %ecx, %ebx
movq %rdx, %rbp
movl %esi, %r14d
movq %rdi, %r15
movl 0x190(%rsp), %eax
movl %eax, 0x24(%rsp)
pushq $0x2
popq %rdi
pushq $0x1
popq %rsi
pushq $0x6
popq %rdx
callq 0x1240
movl %eax, %r12d
leaq 0xc0(%rsp), %r13
andq $0x0, 0x8(%r13)
movw $0x2, (%r13)
movq %r15, %rdi
callq 0x1130
movl %eax, 0x4(%r13)
rolw $0x8, %r14w
movw %r14w, 0x2(%r13)
movl %r12d, %r14d
leaq 0x2722(%rip), %rdi      # 0x4064
movq %r15, %rsi
xorl %eax, %eax
callq 0x10e0
pushq $0x10
popq %rdx
movl %r12d, %edi
movq %r13, %rsi
callq 0x1210
cmpl $-0x1, %eax
je 0x1a7e
leaq 0x29c8(%rip), %rdi      # 0x4332
callq 0x1070
movslq %ebx, %rdx
movq %rbp, %rdi
xorl %esi, %esi
callq 0x1100
leaq 0xc(%rsp), %rsi
andl $0x0, (%rsi)
pushq $0x4
popq %rdx
movl %r14d, %edi
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
je 0x1dd3
movl %r14d, %edi
movq 0x18(%rsp), %r15
movq %r15, %rsi
movl $0x80, %edx
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
je 0x1dd3
xorps %xmm0, %xmm0
leaq 0xd0(%rsp), %rbx
movaps %xmm0, 0x70(%rbx)
movaps %xmm0, 0x60(%rbx)
movaps %xmm0, 0x50(%rbx)
movaps %xmm0, 0x40(%rbx)
movaps %xmm0, 0x30(%rbx)
movaps %xmm0, 0x20(%rbx)
movaps %xmm0, 0x10(%rbx)
movaps %xmm0, (%rbx)
leaq 0x26a7(%rip), %rdx      # 0x4092
movq %r15, %rdi
movq %rbx, %rsi
callq 0x1fda
movq %r15, %rdi
movq %rbx, %rsi
callq 0x1060
leaq 0x90(%rsp), %rsi
xorps %xmm0, %xmm0
movaps %xmm0, 0x10(%rsi)
movaps %xmm0, (%rsi)
movb $0x0, 0x20(%rsi)
pushq $0x20
popq %rdx
movl %r14d, %edi
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
je 0x1dd3
leaq 0x266a(%rip), %rdi      # 0x409e
movq %r15, %rsi
xorl %eax, %eax
callq 0x10e0
leaq 0x8(%rsp), %rsi
andl $0x0, (%rsi)
movq %r15, %rdi
callq 0x1709
movq %rax, %r12
testq %rax, %rax
je 0x1adc
xorps %xmm0, %xmm0
leaq 0x60(%rsp), %rdx
movaps %xmm0, 0x10(%rdx)
movaps %xmm0, (%rdx)
movb $0x0, 0x20(%rdx)
movl 0x8(%rsp), %esi
movq %r12, %rdi
callq 0x26a0
jmp 0x1b02
callq 0x1050
movl (%rax), %esi
cmpl $0x71, %esi
je 0x1abd
cmpl $0x6e, %esi
je 0x1aa5
cmpl $0x6f, %esi
je 0x1ab1
cmpl $0x65, %esi
jne 0x1ac9
leaq 0x2a17(%rip), %rdi      # 0x44b7
jmp 0x1dda
leaq 0x29e8(%rip), %rdi      # 0x4494
jmp 0x1dda
leaq 0x29bc(%rip), %rdi      # 0x4474
jmp 0x1dda
leaq 0x2971(%rip), %rdi      # 0x4435
jmp 0x1dda
leaq 0x25b1(%rip), %rdi      # 0x4081
xorl %eax, %eax
callq 0x10e0
jmp 0x1ddf
leaq 0x25df(%rip), %rdi      # 0x40c2
movq %r15, %rsi
xorl %eax, %eax
callq 0x10e0
xorps %xmm0, %xmm0
movaps %xmm0, 0x70(%rsp)
movaps %xmm0, 0x60(%rsp)
movb $0x0, 0x80(%rsp)
leaq 0x60(%rsp), %rsi
pushq $0x20
popq %rdx
movl %r14d, %edi
xorl %ecx, %ecx
callq 0x168a
cmpl $-0x1, %eax
je 0x1dd3
movl 0xc(%rsp), %ecx
movl 0x8(%rsp), %esi
movl %ecx, %eax
subl %esi, %eax
jne 0x1b69
leaq 0x2818(%rip), %rdi      # 0x434a
callq 0x1070
leaq 0x60(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x1140
testl %eax, %eax
jne 0x1b86
leaq 0x28c7(%rip), %rdi      # 0x441b
callq 0x1070
movq 0x28(%rsp), %rax
andl $0x0, (%rax)
xorl %r13d, %r13d
jmp 0x1de3
jbe 0x1b76
leaq 0x2564(%rip), %rdi      # 0x40d6
movl %eax, %esi
jmp 0x1b7f
subl %ecx, %esi
leaq 0x2579(%rip), %rdi      # 0x40f8
xorl %eax, %eax
callq 0x10e0
testq %r12, %r12
je 0x1b92
movl 0x8(%rsp), %r8d
jmp 0x1b9c
movl 0xc(%rsp), %r8d
movl %r8d, 0x8(%rsp)
movl %r8d, %eax
xorl %edx, %edx
divl 0x24(%rsp)
movl %edx, %ecx
xorl %ebx, %ebx
testl %edx, %edx
setg %bl
addl %eax, %ebx
movl %ebx, 0x10(%rsp)
leaq 0x255e(%rip), %rdi      # 0x4119
movl %ebx, %esi
movl %r8d, %edx
xorl %eax, %eax
callq 0x10e0
leaq (,%rbx,8), %r15
movq %r15, %rdi
callq 0x1180
testq %rax, %rax
je 0x1f61
movq %rax, %r13
leaq (,%rbx,4), %rdi
callq 0x1180
movq %rax, 0x30(%rsp)
testq %rax, %rax
je 0x1f61
movq %r15, 0x50(%rsp)
movq %rbx, 0x18(%rsp)
movl %r14d, 0x20(%rsp)
movq %rbp, 0x48(%rsp)
xorl %ebx, %ebx
pushq $0x1
popq %r14
pushq $0x21
popq %r15
movq 0x30(%rsp), %rbp
cmpq %rbx, 0x18(%rsp)
je 0x1c4a
orl $-0x1, (%rbp,%rbx,4)
movq %r14, %rdi
movq %r15, %rsi
callq 0x1120
movq %rax, (%r13,%rbx,8)
incq %rbx
testq %rax, %rax
jne 0x1c21
jmp 0x1f61
movq %r13, 0x40(%rsp)
movq %r12, 0x38(%rsp)
testq %r12, %r12
movq 0x18(%rsp), %r15
je 0x1cd5
leaq 0x26fc(%rip), %rdi      # 0x4361
callq 0x1070
leal -0x1(%r15), %eax
movq %rax, 0x58(%rsp)
xorl %ebp, %ebp
xorl %ebx, %ebx
xorl %r12d, %r12d
movl 0x24(%rsp), %r13d
cmpq %r15, %r12
jae 0x1cd5
movl 0x8(%rsp), %r14d
addl %ebp, %r14d
cmpq %r12, 0x58(%rsp)
cmovnel %r13d, %r14d
movl %ebx, %r15d
addq 0x38(%rsp), %r15
movq %r15, %rdi
movl %r14d, %esi
callq 0x134c
movq 0x30(%rsp), %rcx
movl %eax, (%rcx,%r12,4)
movq 0x40(%rsp), %rax
movq (%rax,%r12,8), %rdx
movq %r15, %rdi
movq 0x18(%rsp), %r15
movl %r14d, %esi
callq 0x26a0
incq %r12
addl %r13d, %ebx
subl %r13d, %ebp
jmp 0x1c7f
leaq 0x26b8(%rip), %rdi      # 0x4394
callq 0x1070
movq 0x50(%rsp), %rdi
callq 0x1180
testq %rax, %rax
je 0x1f61
movq %rax, %r12
leaq 0x10(%rsp), %r14
pushq $0x4
popq %r15
xorl %ebp, %ebp
movl 0x20(%rsp), %ebx
movl %ebx, %edi
movq %r14, %rsi
movl %r15d, %edx
xorl %ecx, %ecx
callq 0x168a
leaq 0x190(%rsp), %rsi
movl %ebx, %edi
movl %r15d, %edx
xorl %ecx, %ecx
callq 0x168a
movl (%r14), %edx
movl %ebx, %r14d
shll $0x2, %edx
movl %ebx, %edi
movq 0x30(%rsp), %rsi
xorl %ecx, %ecx
callq 0x168a
pushq $0x20
popq %rbx
movq 0x48(%rsp), %r15
movq 0x40(%rsp), %r13
movl 0x10(%rsp), %edx
cmpq %rdx, %rbp
jae 0x1d6c
movq (%r13,%rbp,8), %rsi
movl %r14d, %edi
movl %ebx, %edx
xorl %ecx, %ecx
callq 0x168a
incq %rbp
jmp 0x1d4d
shll $0x3, %edx
movl %r14d, %edi
movq %r12, %rsi
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
je 0x1dd3
leaq 0x2626(%rip), %rdi      # 0x43ae
callq 0x1070
leaq 0x23be(%rip), %rbx      # 0x4152
xorl %r13d, %r13d
movl 0x10(%rsp), %eax
cmpq %rax, %r13
jae 0x1df8
cmpl $-0x1, (%r12,%r13,8)
jne 0x1dce
decl %eax
movl 0xc(%rsp), %edx
movl 0x190(%rsp), %ecx
movl %eax, %esi
imull %ecx, %esi
subl %esi, %edx
cmpq %rax, %r13
cmovnel %ecx, %edx
movq %rbx, %rdi
movl %r13d, %esi
xorl %eax, %eax
callq 0x10e0
incq %r13
jmp 0x1d97
leaq 0x27d3(%rip), %rdi      # 0x45ad
callq 0x1070
pushq $-0x1
popq %r13
movl %r13d, %eax
addq $0x158, %rsp            # imm = 0x158
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x14(%rsp), %rsi
andl $0x0, (%rsi)
pushq $0x4
popq %rdx
movl %r14d, %edi
xorl %ecx, %ecx
callq 0x160e
pushq $-0x1
popq %r13
leaq 0x2795(%rip), %rdi      # 0x45ad
cmpl $-0x1, %eax
je 0x1fba
movl 0x14(%rsp), %esi
leaq 0x2345(%rip), %rdi      # 0x4171
xorl %eax, %eax
callq 0x10e0
movl 0x14(%rsp), %r14d
movl 0x190(%rsp), %edi
addl %r14d, %edi
callq 0x1180
movq %rax, %rbx
testq %rax, %rax
je 0x1fc4
movl 0x20(%rsp), %ebp
movl %ebp, %edi
movq %rbx, %rsi
movl %r14d, %edx
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
leaq 0x273d(%rip), %rdi      # 0x45ad
je 0x1fba
leaq 0x254d(%rip), %rdi      # 0x43ca
callq 0x1070
movl %ebp, %edi
callq 0x1110
movl 0xc(%rsp), %ebp
movl 0x10(%rsp), %r9d
movl 0x190(%rsp), %eax
subq $0x10, %rsp
movq %r15, %rdi
movl %ebp, %esi
movq 0x48(%rsp), %rdx
movq %r12, %r8
pushq %rbx
pushq %rax
callq 0x1822
addq $0x20, %rsp
movq 0x28(%rsp), %r14
movl %ebp, (%r14)
xorps %xmm0, %xmm0
leaq 0x60(%rsp), %rbx
movaps %xmm0, (%rbx)
movaps %xmm0, 0x10(%rbx)
movb $0x0, 0x20(%rbx)
movq %r15, %rdi
movl %ebp, %esi
movq %rbx, %rdx
callq 0x26a0
leaq 0x90(%rsp), %rsi
movq %rbx, %rdi
callq 0x1140
testl %eax, %eax
je 0x1fb0
leaq 0x24f2(%rip), %rdi      # 0x43ee
callq 0x1070
leaq 0x2282(%rip), %rdi      # 0x418a
leaq 0x60(%rsp), %rsi
leaq 0x90(%rsp), %rdx
xorl %eax, %eax
callq 0x10e0
movl (%r14), %esi
movl 0xc(%rsp), %edx
leaq 0x228e(%rip), %rdi      # 0x41b8
xorl %eax, %eax
callq 0x10e0
leaq 0x24c4(%rip), %rdi      # 0x43fc
callq 0x1070
leaq 0x229a(%rip), %rbx      # 0x41de
xorl %r14d, %r14d
cmpq $0x8, %r14
je 0x1f72
movsbl (%r15,%r14), %esi
movq %rbx, %rdi
xorl %eax, %eax
callq 0x10e0
incq %r14
jmp 0x1f47
leaq 0x21dc(%rip), %rdi      # 0x4144
callq 0x11d0
jmp 0x1ddf
leaq 0x2492(%rip), %rdi      # 0x440b
callq 0x1070
pushq $-0x8
popq %rbp
pushq $-0x1
popq %r13
leaq 0x2252(%rip), %rbx      # 0x41de
testl %ebp, %ebp
je 0x1de3
movq 0x28(%rsp), %rax
movl (%rax), %eax
addl %ebp, %eax
movsbl (%r15,%rax), %esi
movq %rbx, %rdi
xorl %eax, %eax
callq 0x10e0
incl %ebp
jmp 0x1f8c
leaq 0x2425(%rip), %rdi      # 0x43dc
xorl %r13d, %r13d
callq 0x1070
jmp 0x1de3
leaq 0x2179(%rip), %rdi      # 0x4144
callq 0x11d0
movl 0x14(%rsp), %r14d
jmp 0x1e53