// File: Distrotech[P]stund/stun.cxx
// Function: stunOpenSocketPair(StunAddress4&, StunAddress4*, int*, int*, int, StunAddress4*, bool)
bool
stunOpenSocketPair( StunAddress4& dest, StunAddress4* mapAddr, 
                    int* fd1, int* fd2, 
                    int port, StunAddress4* srcAddr, 
                    bool verbose )
{
   assert( dest.addr!= 0 );
   assert( dest.port != 0 );
   assert( mapAddr );
   
   const int NUM=3;
	
   if ( port == 0 )
   {
      port = stunRandomPort();
   }
	
   *fd1=-1;
   *fd2=-1;
	
   char msg[STUN_MAX_MESSAGE_SIZE];
   int msgLen =sizeof(msg);
	
   StunAddress4 from;
   int fd[NUM];
   int i;
	
   unsigned int interfaceIp = 0;
   if ( srcAddr )
   {
      interfaceIp = srcAddr->addr;
   }

   for( i=0; i<NUM; i++)
   {
      fd[i] = openPort( (port == 0) ? 0 : (port + i), 
                        interfaceIp, verbose);
      if (fd[i] < 0) 
      {
         while (i > 0)
         {
            closesocket(fd[--i]);
         }
         return false;
      }
   }
	
   StunAtrString username;
   StunAtrString password;
	
   username.sizeValue = 0;
   password.sizeValue = 0;
	
#ifdef USE_TLS
   stunGetUserNameAndPassword( dest, username, password );
#endif
	
   for( i=0; i<NUM; i++)
   {
      stunSendTest(fd[i], dest, username, password, 1/*testNum*/, verbose );
   }
	
   StunAddress4 mappedAddr[NUM];
   for( i=0; i<NUM; i++)
   {
      msgLen = sizeof(msg)/sizeof(*msg);
      getMessage( fd[i],
                  msg,
                  &msgLen,
                  &from.addr,
                  &from.port ,verbose);
		
      StunMessage resp;
      memset(&resp, 0, sizeof(StunMessage));
		
      bool ok = stunParseMessage( msg, msgLen, resp, verbose );
      if (!ok) 
      {
         return false;
      }
		
      mappedAddr[i] = resp.mappedAddress.ipv4;
      StunAddress4 changedAddr = resp.changedAddress.ipv4;
   }
	
   if (verbose)
   {               
      clog << "--- stunOpenSocketPair --- " << endl;
      for( i=0; i<NUM; i++)
      {
         clog << "\t mappedAddr=" << mappedAddr[i] << endl;
      }
   }
	
   if ( mappedAddr[0].port %2 == 0 )
   {
      if (  mappedAddr[0].port+1 ==  mappedAddr[1].port )
      {
         *mapAddr = mappedAddr[0];
         *fd1 = fd[0];
         *fd2 = fd[1];
         closesocket( fd[2] );
         return true;
      }
   }
   else
   {
      if (( mappedAddr[1].port %2 == 0 )
          && (  mappedAddr[1].port+1 ==  mappedAddr[2].port ))
      {
         *mapAddr = mappedAddr[1];
         *fd1 = fd[1];
         *fd2 = fd[2];
         closesocket( fd[0] );
         return true;
      }
   }

   // something failed, close all and return error
   for( i=0; i<NUM; i++)
   {
      closesocket( fd[i] );
   }
	
   return false;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xf60, %rsp            # imm = 0xF60
movb 0x10(%rbp), %al
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movl %r8d, -0x2c(%rbp)
movq %r9, -0x38(%rbp)
andb $0x1, %al
movb %al, -0x39(%rbp)
movq -0x10(%rbp), %rax
cmpl $0x0, 0x4(%rax)
je 0x89c7
jmp 0x89e6
leaq 0x27d2(%rip), %rdi      # 0xb1a0
leaq 0x1d80(%rip), %rsi      # 0xa755
movl $0x90e, %edx            # imm = 0x90E
leaq 0x27cd(%rip), %rcx      # 0xb1ae
callq 0x2140
movq -0x10(%rbp), %rax
movzwl (%rax), %eax
cmpl $0x0, %eax
je 0x89f4
jmp 0x8a13
leaq 0x251e(%rip), %rdi      # 0xaf19
leaq 0x1d53(%rip), %rsi      # 0xa755
movl $0x90f, %edx            # imm = 0x90F
leaq 0x27a0(%rip), %rcx      # 0xb1ae
callq 0x2140
cmpq $0x0, -0x18(%rbp)
je 0x8a1c
jmp 0x8a3b
leaq 0x2775(%rip), %rdi      # 0xb198
leaq 0x1d2b(%rip), %rsi      # 0xa755
movl $0x910, %edx            # imm = 0x910
leaq 0x2778(%rip), %rcx      # 0xb1ae
callq 0x2140
movl $0x3, -0x40(%rbp)
cmpl $0x0, -0x2c(%rbp)
jne 0x8a50
callq 0x5050
movl %eax, -0x2c(%rbp)
movq -0x20(%rbp), %rax
movl $0xffffffff, (%rax)     # imm = 0xFFFFFFFF
movq -0x28(%rbp), %rax
movl $0xffffffff, (%rax)     # imm = 0xFFFFFFFF
movl $0x800, -0x844(%rbp)    # imm = 0x800
movl $0x0, -0x860(%rbp)
cmpq $0x0, -0x38(%rbp)
je 0x8a8c
movq -0x38(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, -0x860(%rbp)
movl $0x0, -0x85c(%rbp)
cmpl $0x3, -0x85c(%rbp)
jge 0x8b4b
cmpl $0x0, -0x2c(%rbp)
jne 0x8ab3
xorl %eax, %eax
movl %eax, -0xf58(%rbp)
jmp 0x8ac2
movl -0x2c(%rbp), %eax
addl -0x85c(%rbp), %eax
movl %eax, -0xf58(%rbp)
movl -0xf58(%rbp), %eax
movw %ax, %cx
movl -0x860(%rbp), %esi
movb -0x39(%rbp), %al
andb $0x1, %al
movzwl %cx, %edi
movzbl %al, %edx
callq 0x8e90
movl %eax, %ecx
movslq -0x85c(%rbp), %rax
movl %ecx, -0x858(%rbp,%rax,4)
movslq -0x85c(%rbp), %rax
cmpl $0x0, -0x858(%rbp,%rax,4)
jge 0x8b35
jmp 0x8b04
cmpl $0x0, -0x85c(%rbp)
jle 0x8b2c
movl -0x85c(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x85c(%rbp)
cltq
movl -0x858(%rbp,%rax,4), %edi
callq 0x31c0
jmp 0x8b04
movb $0x0, -0x1(%rbp)
jmp 0x8e2b
jmp 0x8b37
movl -0x85c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x85c(%rbp)
jmp 0x8a96
movw $0x0, -0x862(%rbp)
movw $0x0, -0x964(%rbp)
movl $0x0, -0x85c(%rbp)
cmpl $0x3, -0x85c(%rbp)
jge 0x8bb5
movslq -0x85c(%rbp), %rax
movl -0x858(%rbp,%rax,4), %edi
movq -0x10(%rbp), %rsi
movb -0x39(%rbp), %al
leaq -0x962(%rbp), %rdx
leaq -0xa64(%rbp), %rcx
movl $0x1, %r8d
andb $0x1, %al
movzbl %al, %r9d
callq 0x7b70
movl -0x85c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x85c(%rbp)
jmp 0x8b67
movl $0x0, -0x85c(%rbp)
cmpl $0x3, -0x85c(%rbp)
jge 0x8c98
movl $0x800, -0x844(%rbp)    # imm = 0x800
movslq -0x85c(%rbp), %rax
movl -0x858(%rbp,%rax,4), %edi
leaq -0x840(%rbp), %rsi
leaq -0x84c(%rbp), %rcx
addq $0x4, %rcx
leaq -0x84c(%rbp), %r8
movb -0x39(%rbp), %al
leaq -0x844(%rbp), %rdx
andb $0x1, %al
movzbl %al, %r9d
callq 0x91a0
leaq -0xf48(%rbp), %rdi
xorl %esi, %esi
movl $0x4c8, %edx            # imm = 0x4C8
callq 0x2130
leaq -0x840(%rbp), %rdi
movl -0x844(%rbp), %esi
movb -0x39(%rbp), %al
leaq -0xf48(%rbp), %rdx
andb $0x1, %al
movzbl %al, %ecx
callq 0x3380
andb $0x1, %al
movb %al, -0xf49(%rbp)
testb $0x1, -0xf49(%rbp)
jne 0x8c60
movb $0x0, -0x1(%rbp)
jmp 0x8e2b
movslq -0x85c(%rbp), %rax
movq -0xf2c(%rbp), %rcx
movq %rcx, -0xa80(%rbp,%rax,8)
movq -0xef4(%rbp), %rax
movq %rax, -0xf54(%rbp)
movl -0x85c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x85c(%rbp)
jmp 0x8bbf
testb $0x1, -0x39(%rbp)
je 0x8d29
movq 0x5307(%rip), %rdi      # 0xdfb0
leaq 0x255f(%rip), %rsi      # 0xb20f
callq 0x21f0
movq %rax, %rdi
movq 0x5301(%rip), %rsi      # 0xdfc0
callq 0x2200
movl $0x0, -0x85c(%rbp)
cmpl $0x3, -0x85c(%rbp)
jge 0x8d27
movq 0x52d2(%rip), %rdi      # 0xdfb0
leaq 0x22fa(%rip), %rsi      # 0xafdf
callq 0x21f0
movq %rax, %rdi
movslq -0x85c(%rbp), %rax
leaq -0xa80(%rbp), %rsi
shlq $0x3, %rax
addq %rax, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x52af(%rip), %rsi      # 0xdfc0
callq 0x2200
movl -0x85c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x85c(%rbp)
jmp 0x8cce
jmp 0x8d29
movzwl -0xa80(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0x8d8e
movzwl -0xa80(%rbp), %eax
addl $0x1, %eax
movzwl -0xa78(%rbp), %ecx
cmpl %ecx, %eax
jne 0x8d8c
movq -0x18(%rbp), %rax
movq -0xa80(%rbp), %rcx
movq %rcx, (%rax)
movl -0x858(%rbp), %ecx
movq -0x20(%rbp), %rax
movl %ecx, (%rax)
movl -0x854(%rbp), %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
movl -0x850(%rbp), %edi
callq 0x31c0
movb $0x1, -0x1(%rbp)
jmp 0x8e2b
jmp 0x8df0
movzwl -0xa78(%rbp), %eax
movl $0x2, %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0x8dee
movzwl -0xa78(%rbp), %eax
addl $0x1, %eax
movzwl -0xa70(%rbp), %ecx
cmpl %ecx, %eax
jne 0x8dee
movq -0x18(%rbp), %rax
movq -0xa78(%rbp), %rcx
movq %rcx, (%rax)
movl -0x854(%rbp), %ecx
movq -0x20(%rbp), %rax
movl %ecx, (%rax)
movl -0x850(%rbp), %ecx
movq -0x28(%rbp), %rax
movl %ecx, (%rax)
movl -0x858(%rbp), %edi
callq 0x31c0
movb $0x1, -0x1(%rbp)
jmp 0x8e2b
jmp 0x8df0
movl $0x0, -0x85c(%rbp)
cmpl $0x3, -0x85c(%rbp)
jge 0x8e27
movslq -0x85c(%rbp), %rax
movl -0x858(%rbp,%rax,4), %edi
callq 0x31c0
movl -0x85c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x85c(%rbp)
jmp 0x8dfa
movb $0x0, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0xf60, %rsp            # imm = 0xF60
popq %rbp
retq
nopl (%rax)