// File: /workspace/github_cpp_makefile_star2_O2/akw0088[P]openssl/rsync_upload.c
// Function: rsync_file_upload
int rsync_file_upload(char *file, unsigned short port)
{
	int			connfd;
	unsigned int		size = sizeof(struct sockaddr_in);
	struct sockaddr_in	servaddr, client;
	time_t			ticks;
	int listenfd;


	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	if (listenfd == -1)
	{
		perror("socket error");
		return -1;
	}

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(port);

	int ret = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	while (ret == -1)
	{
		perror("bind error");
		printf("Retrying in 5 seconds\r\n");
#ifdef WIN32
		Sleep(5000);
#else
		sleep(5);
#endif
		ret = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	}

	printf("Server listening on: %s:%d\n", inet_ntoa(servaddr.sin_addr), htons(servaddr.sin_port));

	if (listen(listenfd, 3) == -1)
	{
		perror("listen error");
		return -1;
	}

	for (;;)
	{
		char response[1024] = { 0 };

		printf("listening for connections...\n");
		connfd = accept(listenfd, (struct sockaddr *)&client, (socklen_t *)&size);
		if (connfd == INVALID_SOCKET)
			continue;

		ticks = time(NULL);
		snprintf(response, sizeof(response), "%.24s\r\n", ctime(&ticks));
		printf("Client: %s - %s", inet_ntoa(client.sin_addr), response);

		unsigned int file_size = 0;
		char *data = get_file(file, &file_size);
		if (data == NULL)
		{
			printf("Unable to open %s\r\n", file);
			closesocket(connfd);
			continue;
		}

		char file_name[PATH_SIZE] = { 0 };
		unsigned char file_hash[MD5_SIZE + 1] = {0};
		unsigned char rfile_hash[MD5_SIZE + 1] = {0};

		md5sum((char *)&data[0], file_size, (char *)file_hash);

		unsigned int rnum_block = 0;
		memcpy(file_name, file, MIN(PATH_SIZE - 1, strlen(file)));
		Send(connfd, (char *)&file_size, sizeof(int), 0);
		Send(connfd, (char *)&file_name, PATH_SIZE, 0);
		Send(connfd, (char *)&file_hash, MD5_SIZE, 0);
		if ( Recv(connfd, (char *)&rfile_hash, MD5_SIZE, 0) == -1)
		{
			printf("recv failed\r\n");
			closesocket(connfd);
			continue;
		}

		if (strcmp((char *)rfile_hash, (char *)file_hash) == 0)
		{
			printf("Files already match\r\n");
			closesocket(connfd);
			continue;
		}

		if ( Recv(connfd, (char *)&rnum_block, sizeof(int), 0) == -1)
		{
			printf("recv failed\r\n");
			closesocket(connfd);
			continue;
		}

		unsigned int rblock_size = 0;
		if ( Recv(connfd, (char *)&rblock_size, sizeof(int), 0) == -1)
		{
			printf("recv failed\r\n");
			closesocket(connfd);
			continue;
		}


		unsigned int *rchecksum_array = (unsigned int *)malloc(rnum_block * sizeof(int));
		if (rchecksum_array == NULL)
		{
			perror("malloc failed");
			closesocket(connfd);
			continue;
		}

		for (unsigned int i = 0; i < rnum_block; i++)
		{
			rchecksum_array[i] = -1;
		}

		printf("Received %d checksum array from client\r\n", rnum_block);
		if (rnum_block == 0)
		{
			printf("Dropping client as we got no blocks\r\n");
			closesocket(connfd);
			continue;
		}

		if ( Recv(connfd, (char *)rchecksum_array, rnum_block * sizeof(int), 0) == -1)
		{
			printf("recv failed\r\n");
			closesocket(connfd);
			continue;
		}

		char **rmd5_array = (char **)malloc(rnum_block * sizeof(char *));
		if (rmd5_array == NULL)
		{
			perror("malloc failed");
			closesocket(connfd);
			continue;
		}

		for (unsigned int i = 0; i < rnum_block; i++)
		{
			rmd5_array[i] = (char *)malloc(MD5_SIZE + 1 * sizeof(char));
			memset(rmd5_array[i], 0, MD5_SIZE + 1);

			if ( Recv(connfd, (char *)rmd5_array[i], MD5_SIZE, 0) == -1)
			{
				printf("recv failed\r\n");
				closesocket(connfd);
				continue;
			}

		}

		block_t *block = (block_t *)malloc(sizeof(block_t) * rnum_block);
		if (block == NULL)
		{
			perror("malloc failed");
			closesocket(connfd);
			continue;
		}
		printf("Searching for matches in %d blocks\r\n", rnum_block);
		
		unsigned int null_count = 0;
		for (unsigned int i = 0; i < rnum_block; i++)
		{
			block[i].offset = -1;
			block[i].length = 0;

			if (strcmp((char *)rmd5_array, "") == 0)
			{
				null_count++;
			}
		}

		int ret = 0;
		if (null_count != rnum_block)
		{
			// we dont send the last partial block as we can only scan blocks of a single length at a time
			ret = adler32_scan((unsigned char *)&data[0], file_size, rblock_size, rchecksum_array, rnum_block - 1, block, rmd5_array);
		}

		// set length of last block which is always transferred
		block[rnum_block - 1].offset = -1;
		block[rnum_block - 1].length = file_size - (rnum_block - 1) * rblock_size;


		printf("Sending block offsets\r\n");
		Send(connfd, (char *)block, rnum_block * sizeof(block_t), 0);

		// Remote side now knows where it's blocks go in new file
		// going to send all bytes in order of whats left starting from 0 and skipping whats in the block report
		
		printf("Determining data client is missing\r\n");
		for (unsigned int i = 0; i < rnum_block; i++)
		{
			if (block[i].offset == -1)
			{
				printf("\tClient missing block %d [%d bytes]\r\n", i, block[i].length);
			}
		}

		unsigned char *send_file = (unsigned char *)malloc(file_size);
		if (send_file == NULL)
		{
			perror("malloc failed");
			closesocket(connfd);
			continue;
		}

		int send_file_pos = 0;

		memset(send_file, 0, file_size);
		for(unsigned int i = 0; i < file_size; i++)
		{
			int skip = 0;


			for(unsigned int j = 0; j < rnum_block; j++)
			{
				if (block[j].length == 0)
				{
					continue;
				}

				if ( i >= block[j].offset && i < block[j].offset + rblock_size )
				{
					// we are in this block, skip to the end of this block
					i = block[j].offset + rblock_size - 1;
					skip = 1;
					break;
				}
			}
			
			if (skip)
			{
				// restart again as we move passed a block
				continue;
			}
			
			// This byte needs to be sent, move into transport block
			send_file[send_file_pos++] = data[i];
		}
		
		printf("Sending client missing chunk of size %d\r\n", send_file_pos);
		printf("Sending data\r\n");
		Send(connfd, (char *)&send_file_pos, sizeof(unsigned int), 0);		
		Send(connfd, (char *)send_file, send_file_pos, 0);
		closesocket(connfd);
	}
	return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x538, %rsp            # imm = 0x538
movl %esi, %ebp
movq %rdi, %rbx
movl $0x10, 0x24(%rsp)
pushq $0x2
popq %rdi
pushq $0x1
popq %rsi
xorl %edx, %edx
callq 0x1240
cmpl $-0x1, %eax
je 0x2628
movl %eax, 0x20(%rsp)
movq %rbx, 0x10(%rsp)
leaq 0x60(%rsp), %r14
andq $0x0, 0x8(%r14)
movw $0x2, (%r14)
andl $0x0, 0x4(%r14)
rolw $0x8, %bp
movw %bp, 0x2(%r14)
pushq $0x10
popq %rbp
leaq 0x213b(%rip), %r15      # 0x41f1
leaq 0x24fd(%rip), %r12      # 0x45ba
pushq $0x5
popq %r13
movl 0x20(%rsp), %ebx
movl %ebx, %edi
movq %r14, %rsi
movl %ebp, %edx
callq 0x11b0
cmpl $-0x1, %eax
jne 0x20f0
movq %r15, %rdi
callq 0x11d0
movq %r12, %rdi
callq 0x1070
movl %r13d, %edi
callq 0x1230
jmp 0x20c5
movl 0x64(%rsp), %edi
callq 0x1090
movzwl 0x62(%rsp), %ecx
rolw $0x8, %cx
movzwl %cx, %edx
leaq 0x20f0(%rip), %rdi      # 0x41fc
movq %rax, %rsi
xorl %eax, %eax
callq 0x10e0
pushq $0x3
popq %rsi
movl %ebx, %edi
callq 0x1190
cmpl $-0x1, %eax
je 0x2631
leaq 0x130(%rsp), %rbx
leaq 0x30(%rsp), %rbp
movq 0x10(%rsp), %r14
movl $0x400, %edx            # imm = 0x400
movq %rbx, %rdi
xorl %esi, %esi
callq 0x1100
leaq 0x23bc(%rip), %rdi      # 0x450d
callq 0x1070
movl 0x20(%rsp), %edi
leaq 0x70(%rsp), %rsi
leaq 0x24(%rsp), %rdx
callq 0x11e0
cmpl $-0x1, %eax
je 0x213b
movl %eax, %r15d
xorl %edi, %edi
callq 0x1170
movq %rax, 0x58(%rsp)
leaq 0x58(%rsp), %rdi
callq 0x10b0
movl $0x400, %esi            # imm = 0x400
movq %rbx, %rdi
leaq 0x208f(%rip), %rdx      # 0x4225
movq %rax, %rcx
xorl %eax, %eax
callq 0x10f0
movl 0x74(%rsp), %edi
callq 0x1090
leaq 0x207d(%rip), %rdi      # 0x422d
movq %rax, %rsi
movq %rbx, %rdx
xorl %eax, %eax
callq 0x10e0
andl $0x0, 0xc(%rsp)
movq %r14, %rdi
leaq 0xc(%rsp), %r12
movq %r12, %rsi
callq 0x1709
testq %rax, %rax
je 0x232e
xorps %xmm0, %xmm0
movaps %xmm0, 0x120(%rsp)
movaps %xmm0, 0x110(%rsp)
movaps %xmm0, 0x100(%rsp)
movaps %xmm0, 0xf0(%rsp)
movaps %xmm0, 0xe0(%rsp)
movaps %xmm0, 0xd0(%rsp)
movaps %xmm0, 0xc0(%rsp)
movaps %xmm0, 0xb0(%rsp)
xorl %ecx, %ecx
movb %cl, 0xa0(%rsp)
movaps %xmm0, 0x90(%rsp)
movaps %xmm0, 0x80(%rsp)
movb %cl, 0x50(%rsp)
movaps %xmm0, 0x40(%rsp)
movaps %xmm0, 0x30(%rsp)
movl 0xc(%rsp), %esi
movq %rax, 0x28(%rsp)
movq %rax, %rdi
leaq 0x80(%rsp), %r13
movq %r13, %rdx
callq 0x26a0
andl $0x0, 0x8(%rsp)
movq %r14, %rdi
callq 0x10c0
cmpq $0x7f, %rax
pushq $0x7f
popq %rcx
cmovaeq %rcx, %rax
movq %r14, %rsi
leaq 0xb0(%rsp), %r14
movq %r14, %rdi
movq %rax, %rdx
callq 0x1160
movl %r15d, %edi
movq %r12, %rsi
pushq $0x4
popq %r12
movl %r12d, %edx
xorl %ecx, %ecx
callq 0x168a
movl %r15d, %edi
movq %r14, %rsi
movl $0x80, %edx
xorl %ecx, %ecx
callq 0x168a
movl %r15d, %edi
movq %r13, %rsi
pushq $0x20
popq %r14
movl %r14d, %edx
xorl %ecx, %ecx
callq 0x168a
movl %r15d, %edi
movq %rbp, %rsi
movl %r14d, %edx
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
je 0x235a
movq %rbp, %rdi
movq %r13, %rsi
callq 0x1140
testl %eax, %eax
movq 0x10(%rsp), %r14
je 0x2341
movl %r15d, %edi
leaq 0x8(%rsp), %rsi
movl %r12d, %edx
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
je 0x2325
andl $0x0, 0x18(%rsp)
movl %r15d, %edi
leaq 0x18(%rsp), %rsi
movl %r12d, %edx
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
jne 0x2373
leaq 0x2281(%rip), %rdi      # 0x45ad
jmp 0x2348
leaq 0x1d8d(%rip), %rdi      # 0x40c2
movq %r14, %rsi
xorl %eax, %eax
callq 0x10e0
jmp 0x234d
leaq 0x2250(%rip), %rdi      # 0x4598
callq 0x1070
movl %r15d, %edi
callq 0x1110
jmp 0x213b
leaq 0x224c(%rip), %rdi      # 0x45ad
callq 0x1070
movl %r15d, %edi
callq 0x1110
jmp 0x2136
movl 0x8(%rsp), %r14d
leaq (,%r14,4), %rdi
callq 0x1180
testq %rax, %rax
je 0x23ee
movq %rax, %rbp
xorl %eax, %eax
cmpq %rax, %r14
je 0x239e
orl $-0x1, (%rbp,%rax,4)
incq %rax
jmp 0x238f
leaq 0x1e98(%rip), %rdi      # 0x423d
movl %r14d, %esi
xorl %eax, %eax
callq 0x10e0
movl 0x8(%rsp), %edx
testl %edx, %edx
je 0x23d5
shll $0x2, %edx
movl %r15d, %edi
movq %rbp, %rsi
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
jne 0x23fc
leaq 0x21da(%rip), %rdi      # 0x45ad
jmp 0x23dc
leaq 0x2197(%rip), %rdi      # 0x4573
callq 0x1070
movl %r15d, %edi
callq 0x1110
jmp 0x2131
leaq 0x1d4f(%rip), %rdi      # 0x4144
callq 0x11d0
jmp 0x23e1
movl 0x8(%rsp), %ebx
leaq (,%rbx,8), %rdi
callq 0x1180
testq %rax, %rax
je 0x261a
movq %rax, %r14
xorl %r13d, %r13d
movl %ebx, %ebx
cmpq %rbx, %r13
jae 0x2464
pushq $0x1
popq %rdi
pushq $0x21
popq %rsi
callq 0x1120
movq %rax, (%r14,%r13,8)
movl %r15d, %edi
movq %rax, %rsi
pushq $0x20
popq %rdx
xorl %ecx, %ecx
callq 0x160e
cmpl $-0x1, %eax
jne 0x245b
leaq 0x215f(%rip), %rdi      # 0x45ad
callq 0x1070
movl %r15d, %edi
callq 0x1110
incq %r13
movl 0x8(%rsp), %ebx
jmp 0x241c
leaq (,%rbx,8), %rdi
callq 0x1180
testq %rax, %rax
je 0x261a
movq %rax, %r13
xorl %r12d, %r12d
leaq 0x1ddf(%rip), %rdi      # 0x4266
movl %ebx, %esi
xorl %eax, %eax
callq 0x10e0
movl 0x8(%rsp), %r8d
xorl %eax, %eax
movl $0xffffffff, %ecx       # imm = 0xFFFFFFFF
movq 0x28(%rsp), %rdi
cmpq %r12, %r8
je 0x24b7
cmpb $0x1, (%r14)
movq %rcx, (%r13,%r12,8)
adcl $0x0, %eax
incq %r12
jmp 0x24a1
cmpl %r8d, %eax
je 0x24db
movl 0xc(%rsp), %esi
movl 0x18(%rsp), %edx
decl %r8d
movq %r14, (%rsp)
movq %rbp, %rcx
movq %r13, %r9
callq 0x142b
movl 0x8(%rsp), %r8d
pushq $0x4
popq %r12
leaq 0x1da5(%rip), %rbp      # 0x428b
decl %r8d
orl $-0x1, (%r13,%r8,8)
movl 0xc(%rsp), %eax
movl %r8d, %ecx
imull 0x18(%rsp), %ecx
subl %ecx, %eax
movl %eax, 0x4(%r13,%r8,8)
leaq 0x2021(%rip), %rdi      # 0x452a
callq 0x1070
movl 0x8(%rsp), %edx
shll $0x3, %edx
movl %r15d, %edi
movq %r13, %rsi
xorl %ecx, %ecx
callq 0x168a
leaq 0x2018(%rip), %rdi      # 0x4541
callq 0x1070
xorl %r14d, %r14d
movl 0x8(%rsp), %ebx
cmpq %rbx, %r14
jae 0x2559
cmpl $-0x1, (%r13,%r14,8)
jne 0x2554
movl 0x4(%r13,%r14,8), %edx
movq %rbp, %rdi
movl %r14d, %esi
xorl %eax, %eax
callq 0x10e0
incq %r14
jmp 0x2531
movl 0xc(%rsp), %ebp
pushq $0x1
popq %rdi
movq %rbp, %rsi
callq 0x1120
testq %rax, %rax
je 0x261a
movq %rax, %r14
andl $0x0, 0x1c(%rsp)
xorl %esi, %esi
movl 0x18(%rsp), %eax
xorl %edi, %edi
movq 0x28(%rsp), %r10
cmpl %ebp, %edi
jae 0x25d0
movl %edi, %ecx
xorl %edx, %edx
cmpq %rdx, %rbx
je 0x25b8
cmpl $0x0, 0x4(%r13,%rdx,8)
je 0x25b3
movl (%r13,%rdx,8), %edi
cmpl %edi, %ecx
setae %r8b
addl %eax, %edi
cmpl %edi, %ecx
setb %r9b
testb %r9b, %r8b
jne 0x2586
incq %rdx
jmp 0x258e
movl %ecx, %edx
movb (%r10,%rdx), %dl
movl %esi, %edi
incl %esi
movl %esi, 0x1c(%rsp)
movb %dl, (%r14,%rdi)
incl %ecx
movl %ecx, %edi
jmp 0x2586
leaq 0x1cda(%rip), %rdi      # 0x42b1
xorl %eax, %eax
callq 0x10e0
leaq 0x1f80(%rip), %rdi      # 0x4565
callq 0x1070
movl %r15d, %edi
leaq 0x1c(%rsp), %rsi
movl %r12d, %edx
xorl %ecx, %ecx
callq 0x168a
movl 0x1c(%rsp), %edx
movl %r15d, %edi
movq %r14, %rsi
xorl %ecx, %ecx
callq 0x168a
movl %r15d, %edi
callq 0x1110
jmp 0x2129
leaq 0x1b23(%rip), %rdi      # 0x4144
callq 0x11d0
jmp 0x260d
leaq 0x1bb5(%rip), %rdi      # 0x41e4
jmp 0x2638
leaq 0x1be0(%rip), %rdi      # 0x4218
callq 0x11d0
pushq $-0x1
popq %rax
addq $0x538, %rsp            # imm = 0x538
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq