// File: /workspace/github_c_makefile_star2_O1/enzo1982[P]smooth/classes/io/drivers/driver_socks5.cpp
// Function: smooth::IO::DriverSOCKS5::DriverSOCKS5(smooth::String const&, int, smooth::String const&, int, smooth::String const&, smooth::String const&)
S::IO::DriverSOCKS5::DriverSOCKS5(const String &proxy, Int socksPort, const String &hostName, Int port, const String &uname, const String &passwd) : Driver()
{
	closeStream = False;

	stream	    = -1;
	size	    = -1;

	if (hostName == NIL || hostName.Length() > 255) { lastError = IO_ERROR_BADPARAM; return; }

	/* Open TCP/IP socket.
	 */
	stream = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (stream == (unsigned) (~0)) { lastError = IO_ERROR_UNEXPECTED; return; }

	closeStream = True;

	/* Get proxy hostname.
	 */
	hostent		*host = gethostbyname(proxy);

	if (host == NIL) { Close(); lastError = IO_ERROR_UNEXPECTED; return; }

	/* Connect to proxy.
	 */
	sockaddr_in	 saddr;

	saddr.sin_family = AF_INET;
	saddr.sin_addr	 = *((in_addr *) *host->h_addr_list);
	saddr.sin_port	 = htons((short) socksPort);

	memset(&saddr.sin_zero, 0, sizeof(saddr.sin_zero));

	if (connect(stream, (sockaddr *) &saddr, sizeof(struct sockaddr)) == -1) { Close(); lastError = IO_ERROR_UNEXPECTED; return; }

	/* Send connect request.
	 */
	if (uname == NIL)
	{
		unsigned char	*socksdata = new unsigned char [3];

		socksdata[0] = 5;	// SOCKS version 5
		socksdata[1] = 1;	// One authentication method
		socksdata[2] = 0x00;	// Method 1: No authentication

		if (send(stream, (char *) socksdata, 3, 0) < 3) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

		/* Read and evaluate response.
		 */
		int	 recbytes = 0;

		while (recbytes != 2)
		{
			int	 bytes = recv(stream, (char *) socksdata + recbytes, 2 - recbytes, 0);

			if (bytes <= 0) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

			recbytes += bytes;
		}

		/* Check if proxy requires authentication.
		 */
		if (socksdata[1] == 0xFF) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

		delete [] socksdata;
	}
	else
	{
		unsigned char	*socksdata = new unsigned char [4];

		socksdata[0] = 5;	// SOCKS version 5
		socksdata[1] = 2;	// Two authentication methods
		socksdata[2] = 0x00;	// Method 0x00: No authentication
		socksdata[3] = 0x02;	// Method 0x02: Username / password

		if (send(stream, (char *) socksdata, 4, 0) < 4) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

		/* Read and evaluate response.
		 */
		int	 recbytes = 0;

		while (recbytes != 2)
		{
			int	 bytes = recv(stream, (char *) socksdata + recbytes, 2 - recbytes, 0);

			if (bytes <= 0) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

			recbytes += bytes;
		}

		/* Check if proxy accepted authentication method.
		 */
		if (socksdata[1] == 0xFF) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

		if (socksdata[1] == 0x02)
		{
			/* Method 0x02: Username / password
			 */
			delete [] socksdata;

			Int	 unameLen  = strlen(uname);
			Int	 passwdLen = passwd != NIL ? strlen(passwd) : 0;

			socksdata = new unsigned char [3 + unameLen + passwdLen];

			socksdata[0] = 1;
			socksdata[1] = unameLen;

			for (Int i = 0; i < unameLen; i++) socksdata[2 + i] = uname[i];

			socksdata[2 + unameLen] = passwdLen;

			for (Int i = 0; i < passwdLen; i++) socksdata[3 + unameLen + i] = passwd[i];

			if (send(stream, (char *) socksdata, 3 + unameLen + passwdLen, 0) < 3 + unameLen + passwdLen) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

			/* Read and evaluate response.
			 */
			int	 recbytes = 0;

			while (recbytes != 2)
			{
				int	 bytes = recv(stream, (char *) socksdata + recbytes, 2 - recbytes, 0);

				if (bytes <= 0) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

				recbytes += bytes;
			}

			/* Check if proxy accepted username/password.
			 */
			if (socksdata[1] != 0x00) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }
		}

		delete [] socksdata;
	}

	/* Send connect request.
	 */
	unsigned char	*socksdata = new unsigned char [5 + 255 + 2];

	Int	 hostNameLen = strlen(hostName);

	socksdata[0] = 5;	// SOCKS version 5
	socksdata[1] = 0x01;	// Command: Connect
	socksdata[2] = 0x00;	// Reserved field
	socksdata[3] = 0x03;	// Connect type: Domain name
	socksdata[4] = hostNameLen;

	for (Int i = 0; i < hostNameLen; i++) socksdata[5 + i] = hostName[i];

	socksdata[5 + hostNameLen] = htons((short) port) % 256;
	socksdata[6 + hostNameLen] = htons((short) port) / 256;

	if (send(stream, (char *) socksdata, 7 + hostNameLen, 0) < 7 + hostNameLen) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

	/* Receive and evaluate first 4 bytes of answer.
	 */
	int	 recbytes = 0;

	while (recbytes != 4)
	{
		int	 bytes = recv(stream, (char *) socksdata + recbytes, 4 - recbytes, 0);

		if (bytes <= 0) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

		recbytes += bytes;
	}

	/* Check if connect attempt was successful.
	 */
	if (socksdata[1] != 0x00) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

	/* Receive rest of answer.
	 */
	if (socksdata[3] == 0x01)
	{
		/* Read IP address and port.
		 */
		int	 recbytes = 0;

		while (recbytes != 6)
		{
			int	 bytes = recv(stream, (char *) socksdata + 4 + recbytes, 6 - recbytes, 0);

			if (bytes <= 0) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

			recbytes += bytes;
		}
	}
	else if (socksdata[3] == 0x03)
	{
		/* Read length of hostname.
		 */
		if (recv(stream, (char *) socksdata + 4, 1, 0) <= 0) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

		/* Read hostname and port.
		 */
		int	 neededbytes = Math::Min(255, socksdata[4]) + 2;
		int	 recbytes    = 0;

		while (recbytes != neededbytes)
		{
			int	 bytes = recv(stream, (char *) socksdata + 5 + recbytes, neededbytes - recbytes, 0);

			if (bytes <= 0) { delete [] socksdata; Close(); lastError = IO_ERROR_UNEXPECTED; return; }

			recbytes += bytes;
		}
	}

	delete [] socksdata;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %r9, %r15
movl %r8d, 0xc(%rsp)
movq %rcx, %r14
movl %edx, %ebp
movq %rsi, %r12
movq %rdi, %rbx
callq 0x58560
movq 0xca82b(%rip), %rax     # 0x16cc38
addq $0x10, %rax
movq %rax, (%rbx)
movb $0x0, 0x3c(%rbx)
movl $0xffffffff, 0x38(%rbx) # imm = 0xFFFFFFFF
movq $-0x1, 0x8(%rbx)
movq %r14, %rdi
xorl %esi, %esi
callq 0x55260
testb %al, %al
jne 0xa2444
movq %r14, %rdi
callq 0x57180
cmpl $0x100, %eax            # imm = 0x100
jl 0xa2450
movl $0x2, 0x18(%rbx)
jmp 0xa2929
movl $0x2, %edi
movl $0x1, %esi
movl $0x6, %edx
callq 0x56660
movl %eax, 0x38(%rbx)
cmpl $-0x1, %eax
je 0xa2922
movb $0x1, 0x3c(%rbx)
movq %r12, %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56530
testq %rax, %rax
je 0xa2517
leaq 0x28(%rsp), %rsi
movw $0x2, (%rsi)
movq 0x18(%rax), %rax
movq (%rax), %rax
movl (%rax), %eax
rolw $0x8, %bp
movl %eax, 0x4(%rsi)
movw %bp, 0x2(%rsi)
movq $0x0, 0x8(%rsi)
movl 0x38(%rbx), %edi
movl $0x10, %edx
callq 0x56230
cmpl $-0x1, %eax
je 0xa2525
movq %r15, %rdi
xorl %esi, %esi
callq 0x55260
testb %al, %al
je 0xa2533
movl $0x3, %edi
callq 0x56670
movq %rax, %r15
movw $0x105, (%rax)          # imm = 0x105
movb $0x0, 0x2(%rax)
movl 0x38(%rbx), %edi
movl $0x3, %edx
movq %rax, %rsi
xorl %ecx, %ecx
callq 0x56130
cmpq $0x3, %rax
jge 0xa2574
movq %r15, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
movl $0x4, %edi
callq 0x56670
movq %rax, %r12
movl $0x2000205, (%rax)      # imm = 0x2000205
movl 0x38(%rbx), %edi
movl $0x4, %edx
movq %rax, %rsi
xorl %ecx, %ecx
callq 0x56130
cmpq $0x4, %rax
jge 0xa25c7
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
xorl %ebp, %ebp
cmpl $0x2, %ebp
je 0xa2618
movl 0x38(%rbx), %edi
movl %ebp, %esi
addq %r15, %rsi
movl $0x2, %eax
subl %ebp, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
movq %rax, %r12
testl %r12d, %r12d
jle 0xa25a5
addl %r12d, %ebp
jmp 0xa25bd
movq %r15, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
movl $0x3, 0x18(%rbx)
testl %r12d, %r12d
jg 0xa2576
jmp 0xa2929
xorl %r13d, %r13d
cmpl $0x2, %r13d
je 0xa263c
movl 0x38(%rbx), %edi
movl %r13d, %esi
addq %r12, %rsi
movl $0x2, %eax
subl %r13d, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
movq %rax, %rbp
testl %ebp, %ebp
jle 0xa25f7
addl %ebp, %r13d
jmp 0xa260f
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
movl $0x3, 0x18(%rbx)
testl %ebp, %ebp
jg 0xa25ca
jmp 0xa2929
movb 0x1(%r15), %bpl
movq %r15, %rdi
callq 0x561e0
cmpb $-0x1, %bpl
jne 0xa27f3
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
movzbl 0x1(%r12), %eax
cmpl $0x2, %eax
je 0xa2668
cmpl $0xff, %eax
jne 0xa27eb
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
movq %r12, %rdi
callq 0x561e0
movq %r15, %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56370
movq %rax, %rbp
movq $0x0, (%rsp)
movq 0x70(%rsp), %rdi
xorl %esi, %esi
callq 0x56bd0
testb %al, %al
je 0xa26b1
movq 0x70(%rsp), %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56370
movq %rax, (%rsp)
movslq %ebp, %rax
addq $0x3, %rax
movq %rax, 0x18(%rsp)
movq (%rsp), %rcx
addl %ecx, %eax
movslq %eax, %r13
movq %r13, %rdi
callq 0x56670
movq %rax, %r12
movq %r13, 0x20(%rsp)
movb $0x1, (%rax)
movb %bpl, 0x1(%rax)
movq %rbp, 0x10(%rsp)
testl %ebp, %ebp
jle 0xa270c
movq 0x10(%rsp), %rbp
andl $0x7fffffff, %ebp       # imm = 0x7FFFFFFF
xorl %r13d, %r13d
movq %r15, %rdi
movl %r13d, %esi
callq 0x57fe0
movb %al, 0x2(%r12,%r13)
incq %r13
cmpq %r13, %rbp
jne 0xa26f4
movq 0x10(%rsp), %rax
addl $0x2, %eax
cltq
movq (%rsp), %rcx
movb %cl, (%r12,%rax)
movq %rcx, %rax
testl %eax, %eax
jle 0xa274e
movl %eax, %r13d
addq %r12, 0x18(%rsp)
xorl %r15d, %r15d
movq 0x70(%rsp), %rdi
movl %r15d, %esi
callq 0x57fe0
movq 0x18(%rsp), %rcx
movb %al, (%rcx,%r15)
incq %r15
cmpq %r15, %r13
jne 0xa2730
movl 0x38(%rbx), %edi
movq %r12, %rsi
movq 0x20(%rsp), %r15
movq %r15, %rdx
xorl %ecx, %ecx
callq 0x56130
cmpq %r15, %rax
jge 0xa277e
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
xorl %ebp, %ebp
cmpl $0x2, %ebp
je 0xa27cd
movl 0x38(%rbx), %edi
movl %ebp, %esi
addq %r12, %rsi
movl $0x2, %eax
subl %ebp, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
movq %rax, %r15
testl %r15d, %r15d
jle 0xa27ab
addl %r15d, %ebp
jmp 0xa27c3
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
movl $0x3, 0x18(%rbx)
testl %r15d, %r15d
jg 0xa2780
jmp 0xa2929
cmpb $0x0, 0x1(%r12)
je 0xa27eb
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
movq %r12, %rdi
callq 0x561e0
movl $0x106, %edi            # imm = 0x106
callq 0x56670
movq %rax, %rbp
movq %r14, %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56370
movq %rax, %r15
movl $0x3000105, (%rbp)      # imm = 0x3000105
movb %r15b, 0x4(%rbp)
testl %r15d, %r15d
jle 0xa2848
movl %r15d, %r13d
andl $0x7fffffff, %r13d      # imm = 0x7FFFFFFF
xorl %r12d, %r12d
movq %r14, %rdi
movl %r12d, %esi
callq 0x57fe0
movb %al, 0x5(%rbp,%r12)
incq %r12
cmpq %r12, %r13
jne 0xa2830
movl 0xc(%rsp), %ecx
rolw $0x8, %cx
shlq $0x20, %r15
movabsq $0x500000000, %rax      # imm = 0x500000000
addq %r15, %rax
sarq $0x20, %rax
movb %cl, (%rbp,%rax)
movabsq $0x600000000, %rax      # imm = 0x600000000
addq %r15, %rax
sarq $0x20, %rax
movb %ch, (%rbp,%rax)
movl 0x38(%rbx), %edi
movabsq $0x700000000, %r14      # imm = 0x700000000
addq %r15, %r14
sarq $0x20, %r14
movq %rbp, %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x56130
cmpq %r14, %rax
jge 0xa28b7
movq %rbp, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
leaq 0x4(%rbp), %r14
xorl %r12d, %r12d
cmpl $0x4, %r12d
je 0xa290b
movl 0x38(%rbx), %edi
movl %r12d, %esi
addq %rbp, %rsi
movl $0x4, %eax
subl %r12d, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
movq %rax, %r15
testl %r15d, %r15d
jle 0xa28ec
addl %r15d, %r12d
jmp 0xa2904
movq %rbp, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
movl $0x3, 0x18(%rbx)
testl %r15d, %r15d
jg 0xa28be
jmp 0xa2929
cmpb $0x0, 0x1(%rbp)
je 0xa2938
movq %rbp, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
movl $0x3, 0x18(%rbx)
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movzbl 0x3(%rbp), %eax
cmpl $0x3, %eax
je 0xa299e
cmpl $0x1, %eax
jne 0xa2a18
xorl %r12d, %r12d
cmpl $0x6, %r12d
je 0xa2a18
movl 0x38(%rbx), %edi
movl %r12d, %esi
addq %r14, %rsi
movl $0x6, %eax
subl %r12d, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
movq %rax, %r15
testl %r15d, %r15d
jle 0xa297f
addl %r15d, %r12d
jmp 0xa2997
movq %rbp, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
movl $0x3, 0x18(%rbx)
testl %r15d, %r15d
jg 0xa294d
jmp 0xa2929
movl 0x38(%rbx), %edi
movl $0x1, %edx
movq %r14, %rsi
xorl %ecx, %ecx
callq 0x582d0
testq %rax, %rax
jle 0xa2a25
movzbl 0x4(%rbp), %r15d
addq $0x2, %r15
movq %rbp, %rax
addq $0x5, %rax
movq %rax, %r13
xorl %r12d, %r12d
cmpl %r12d, %r15d
je 0xa2a18
movl 0x38(%rbx), %edi
movl %r12d, %esi
addq %r13, %rsi
movslq %r12d, %rax
movq %r15, %rdx
subq %rax, %rdx
xorl %ecx, %ecx
callq 0x582d0
movq %rax, %r14
testl %r14d, %r14d
jle 0xa29f6
addl %r14d, %r12d
jmp 0xa2a0e
movq %rbp, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
movl $0x3, 0x18(%rbx)
testl %r14d, %r14d
jg 0xa29cb
jmp 0xa2929
movq %rbp, %rdi
callq 0x561e0
jmp 0xa2929
movq %rbp, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa2922
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
jmp 0xa2a65
movq %rax, %r14
movq %rbx, %rdi
callq 0x56c30
movq %r14, %rdi
callq 0x57090