// File: /workspace/github_c_makefile_star2_O3/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, %r13d
movq %rcx, %r14
movl %edx, %ebp
movq %rsi, %r12
movq %rdi, %rbx
callq 0x58560
movq 0xca285(%rip), %rax     # 0x16bc38
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 0xa19ea
movq %r14, %rdi
callq 0x57180
cmpl $0x100, %eax            # imm = 0x100
jl 0xa19f6
movl $0x2, 0x18(%rbx)
jmp 0xa1ee3
movl $0x2, %edi
movl $0x1, %esi
movl $0x6, %edx
callq 0x56660
movl %eax, 0x38(%rbx)
cmpl $-0x1, %eax
je 0xa1edc
movb $0x1, 0x3c(%rbx)
movq %r12, %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56530
testq %rax, %rax
je 0xa1abd
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 0xa1acb
movq %r15, %rdi
xorl %esi, %esi
callq 0x55260
testb %al, %al
je 0xa1ad9
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 0xa1b1a
movq %r15, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
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 0xa1b64
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
xorl %ebp, %ebp
movl 0x38(%rbx), %edi
movl %ebp, %esi
addq %r15, %rsi
movl $0x2, %eax
subl %ebp, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
testl %eax, %eax
jle 0xa1bb6
addl %eax, %ebp
cmpl $0x2, %ebp
jne 0xa1b1c
movb 0x1(%r15), %bpl
movq %r15, %rdi
callq 0x561e0
cmpb $-0x1, %bpl
jne 0xa1d51
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
xorl %ebp, %ebp
movl 0x38(%rbx), %edi
movl %ebp, %esi
addq %r12, %rsi
movl $0x2, %eax
subl %ebp, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
testl %eax, %eax
jle 0xa1bcc
addl %eax, %ebp
cmpl $0x2, %ebp
jne 0xa1b66
movzbl 0x1(%r12), %eax
cmpl $0x2, %eax
je 0xa1be2
cmpl $0xff, %eax
jne 0xa1d49
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq %r15, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq %r12, %rdi
callq 0x561e0
movq %r15, %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56370
movq %rax, 0x8(%rsp)
movq $0x0, 0x18(%rsp)
movq 0x70(%rsp), %rdi
xorl %esi, %esi
callq 0x56bd0
testb %al, %al
je 0xa1c2f
movq 0x70(%rsp), %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56370
movq %rax, 0x18(%rsp)
movslq 0x8(%rsp), %rax
addq $0x3, %rax
movq %rax, (%rsp)
movq 0x18(%rsp), %rcx
addl %ecx, %eax
movslq %eax, %rbp
movq %rbp, %rdi
callq 0x56670
movq %rax, %r12
movq %rbp, 0x20(%rsp)
movb $0x1, (%rax)
movq 0x8(%rsp), %rax
movb %al, 0x1(%r12)
testl %eax, %eax
jle 0xa1c91
movq 0x8(%rsp), %rax
andl $0x7fffffff, %eax       # imm = 0x7FFFFFFF
movq %rax, 0x10(%rsp)
xorl %ebp, %ebp
movq %r15, %rdi
movl %ebp, %esi
callq 0x57fe0
movb %al, 0x2(%r12,%rbp)
incq %rbp
cmpq %rbp, 0x10(%rsp)
jne 0xa1c78
movq 0x8(%rsp), %rax
addl $0x2, %eax
cltq
movq 0x18(%rsp), %rcx
movb %cl, (%r12,%rax)
movq %rcx, %rax
testl %eax, %eax
jle 0xa1cd1
movl %eax, %ebp
addq %r12, (%rsp)
xorl %r15d, %r15d
movq 0x70(%rsp), %rdi
movl %r15d, %esi
callq 0x57fe0
movq (%rsp), %rcx
movb %al, (%rcx,%r15)
incq %r15
cmpq %r15, %rbp
jne 0xa1cb4
movl 0x38(%rbx), %edi
movq %r12, %rsi
movq 0x20(%rsp), %r15
movq %r15, %rdx
xorl %ecx, %ecx
callq 0x56130
cmpq %r15, %rax
jge 0xa1d01
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
xorl %ebp, %ebp
movl 0x38(%rbx), %edi
movl %ebp, %esi
addq %r12, %rsi
movl $0x2, %eax
subl %ebp, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
testl %eax, %eax
jle 0xa1ecb
addl %eax, %ebp
cmpl $0x2, %ebp
jne 0xa1d03
cmpb $0x0, 0x1(%r12)
je 0xa1d49
movq %r12, %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq %r12, %rdi
callq 0x561e0
movl $0x106, %edi            # imm = 0x106
callq 0x56670
movq %rax, (%rsp)
movq %r14, %rdi
callq 0x585e0
movq %rax, %rdi
callq 0x56370
movq (%rsp), %rcx
movl $0x3000105, (%rcx)      # imm = 0x3000105
movb %al, 0x4(%rcx)
leaq 0x5(%rcx), %rbp
movq %rax, 0x10(%rsp)
testl %eax, %eax
jle 0xa1db0
movq 0x10(%rsp), %r15
andl $0x7fffffff, %r15d      # imm = 0x7FFFFFFF
xorl %r12d, %r12d
movq %r14, %rdi
movl %r12d, %esi
callq 0x57fe0
movb %al, (%rbp,%r12)
incq %r12
cmpq %r12, %r15
jne 0xa1d98
movl %r13d, %ecx
rolw $0x8, %cx
movq 0x10(%rsp), %rdx
shlq $0x20, %rdx
movabsq $0x500000000, %rax      # imm = 0x500000000
addq %rdx, %rax
sarq $0x20, %rax
movq (%rsp), %rsi
movb %cl, (%rsi,%rax)
movabsq $0x600000000, %rax      # imm = 0x600000000
addq %rdx, %rax
sarq $0x20, %rax
movb %ch, (%rsi,%rax)
movl 0x38(%rbx), %edi
movabsq $0x700000000, %r14      # imm = 0x700000000
addq %rdx, %r14
sarq $0x20, %r14
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x56130
cmpq %r14, %rax
jge 0xa1e26
movq (%rsp), %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq (%rsp), %rax
leaq 0x4(%rax), %r14
xorl %r15d, %r15d
movl 0x38(%rbx), %edi
movl %r15d, %esi
addq (%rsp), %rsi
movl $0x4, %eax
subl %r15d, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
testl %eax, %eax
jle 0xa1e74
addl %eax, %r15d
cmpl $0x4, %r15d
jne 0xa1e31
movq (%rsp), %rdi
cmpb $0x0, 0x1(%rdi)
je 0xa1e88
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq (%rsp), %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movzbl 0x3(%rdi), %eax
cmpl $0x3, %eax
je 0xa1ef2
cmpl $0x1, %eax
jne 0xa1f39
xorl %r15d, %r15d
movl 0x38(%rbx), %edi
movl %r15d, %esi
addq %r14, %rsi
movl $0x6, %eax
subl %r15d, %eax
movslq %eax, %rdx
xorl %ecx, %ecx
callq 0x582d0
testl %eax, %eax
jle 0xa1f44
addl %eax, %r15d
cmpl $0x6, %r15d
jne 0xa1e9d
jmp 0xa1f39
movq %r12, %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
movl 0x38(%rbx), %edi
movl $0x1, %edx
movq %r14, %rsi
xorl %ecx, %ecx
callq 0x582d0
testq %rax, %rax
jle 0xa1f58
movzbl (%r14), %r14d
addq $0x2, %r14
xorl %r15d, %r15d
movl 0x38(%rbx), %edi
movl %r15d, %esi
addq %rbp, %rsi
movslq %r15d, %rax
movq %r14, %rdx
subq %rax, %rdx
xorl %ecx, %ecx
callq 0x582d0
testl %eax, %eax
jle 0xa1f6f
addl %eax, %r15d
cmpl %r14d, %r15d
jne 0xa1f14
movq (%rsp), %rdi
callq 0x561e0
jmp 0xa1ee3
movq (%rsp), %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq (%rsp), %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
movq (%rsp), %rdi
callq 0x561e0
movq (%rbx), %rax
movq %rbx, %rdi
callq *0x38(%rax)
jmp 0xa1edc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
jmp 0xa1fbc
movq %rax, %r14
movq %rbx, %rdi
callq 0x56c30
movq %r14, %rdi
callq 0x57090
nop