// File: Distrotech[P]stund/stun.cxx
// Function: stunEncodeMessage(StunMessage const&, char*, unsigned int, StunAtrString const&, bool)
unsigned int
stunEncodeMessage( const StunMessage& msg, 
                   char* buf, 
                   unsigned int bufLen, 
                   const StunAtrString& password, 
                   bool verbose)
{
   assert(bufLen >= sizeof(StunMsgHdr));
   char* ptr = buf;
	
   ptr = encode16(ptr, msg.msgHdr.msgType);
   char* lengthp = ptr;
   ptr = encode16(ptr, 0);
   ptr = encode(ptr, reinterpret_cast<const char*>(msg.msgHdr.id.octet), sizeof(msg.msgHdr.id));
	
   if (verbose) clog << "Encoding stun message: " << endl;
   if (msg.hasMappedAddress)
   {
      if (verbose) clog << "Encoding MappedAddress: " << msg.mappedAddress.ipv4 << endl;
      ptr = encodeAtrAddress4 (ptr, MappedAddress, msg.mappedAddress);
   }
   if (msg.hasResponseAddress)
   {
      if (verbose) clog << "Encoding ResponseAddress: " << msg.responseAddress.ipv4 << endl;
      ptr = encodeAtrAddress4(ptr, ResponseAddress, msg.responseAddress);
   }
   if (msg.hasChangeRequest)
   {
      if (verbose) clog << "Encoding ChangeRequest: " << msg.changeRequest.value << endl;
      ptr = encodeAtrChangeRequest(ptr, msg.changeRequest);
   }
   if (msg.hasSourceAddress)
   {
      if (verbose) clog << "Encoding SourceAddress: " << msg.sourceAddress.ipv4 << endl;
      ptr = encodeAtrAddress4(ptr, SourceAddress, msg.sourceAddress);
   }
   if (msg.hasChangedAddress)
   {
      if (verbose) clog << "Encoding ChangedAddress: " << msg.changedAddress.ipv4 << endl;
      ptr = encodeAtrAddress4(ptr, ChangedAddress, msg.changedAddress);
   }
   if (msg.hasUsername)
   {
      if (verbose) clog << "Encoding Username: " << msg.username.value << endl;
      ptr = encodeAtrString(ptr, Username, msg.username);
   }
   if (msg.hasPassword)
   {
      if (verbose) clog << "Encoding Password: " << msg.password.value << endl;
      ptr = encodeAtrString(ptr, Password, msg.password);
   }
   if (msg.hasErrorCode)
   {
      if (verbose) clog << "Encoding ErrorCode: class=" 
			<< int(msg.errorCode.errorClass)  
			<< " number=" << int(msg.errorCode.number) 
			<< " reason=" 
			<< msg.errorCode.reason 
			<< endl;
		
      ptr = encodeAtrError(ptr, msg.errorCode);
   }
   if (msg.hasUnknownAttributes)
   {
      if (verbose) clog << "Encoding UnknownAttribute: ???" << endl;
      ptr = encodeAtrUnknown(ptr, msg.unknownAttributes);
   }
   if (msg.hasReflectedFrom)
   {
      if (verbose) clog << "Encoding ReflectedFrom: " << msg.reflectedFrom.ipv4 << endl;
      ptr = encodeAtrAddress4(ptr, ReflectedFrom, msg.reflectedFrom);
   }
   if (msg.hasXorMappedAddress)
   {
      if (verbose) clog << "Encoding XorMappedAddress: " << msg.xorMappedAddress.ipv4 << endl;
      ptr = encodeAtrAddress4 (ptr, XorMappedAddress, msg.xorMappedAddress);
   }
   if (msg.xorOnly)
   {
      if (verbose) clog << "Encoding xorOnly: " << endl;
      ptr = encodeXorOnly( ptr );
   }
   if (msg.hasServerName)
   {
      if (verbose) clog << "Encoding ServerName: " << msg.serverName.value << endl;
      ptr = encodeAtrString(ptr, ServerName, msg.serverName);
   }
   if (msg.hasSecondaryAddress)
   {
      if (verbose) clog << "Encoding SecondaryAddress: " << msg.secondaryAddress.ipv4 << endl;
      ptr = encodeAtrAddress4 (ptr, SecondaryAddress, msg.secondaryAddress);
   }

   if (password.sizeValue > 0)
   {
      if (verbose) clog << "HMAC with password: " << password.value << endl;
		
      StunAtrIntegrity integrity;
      computeHmac(integrity.hash, buf, int(ptr-buf) , password.value, password.sizeValue);
      ptr = encodeAtrIntegrity(ptr, integrity);
   }
   if (verbose) clog << endl;
	
   encode16(lengthp, UInt16(ptr - buf - sizeof(StunMsgHdr)));
   return int(ptr - buf);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movb %r8b, %al
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movq %rcx, -0x20(%rbp)
andb $0x1, %al
movb %al, -0x21(%rbp)
movl -0x14(%rbp), %eax
cmpq $0x14, %rax
jb 0x44ea
jmp 0x4509
leaq 0x6247(%rip), %rdi      # 0xa738
leaq 0x625d(%rip), %rsi      # 0xa755
movl $0x225, %edx            # imm = 0x225
leaq 0x625a(%rip), %rcx      # 0xa75e
callq 0x2140
movq -0x10(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rax
movzwl (%rax), %esi
callq 0x4bc0
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x30(%rbp), %rdi
xorl %esi, %esi
callq 0x4bc0
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rsi
addq $0x4, %rsi
movl $0x10, %edx
callq 0x4c00
movq %rax, -0x30(%rbp)
testb $0x1, -0x21(%rbp)
je 0x457e
movq 0x9a4d(%rip), %rdi      # 0xdfb0
leaq 0x625b(%rip), %rsi      # 0xa7c5
callq 0x21f0
movq %rax, %rdi
movq 0x9a47(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x8(%rbp), %rax
testb $0x1, 0x14(%rax)
je 0x45de
testb $0x1, -0x21(%rbp)
je 0x45c4
movq 0x9a1b(%rip), %rdi      # 0xdfb0
leaq 0x6241(%rip), %rsi      # 0xa7dd
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x18, %rsi
addq $0x4, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x9a01(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x18, %rdx
movl $0x1, %esi
callq 0x4c40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x24(%rax)
je 0x463e
testb $0x1, -0x21(%rbp)
je 0x4624
movq 0x99bb(%rip), %rdi      # 0xdfb0
leaq 0x61fa(%rip), %rsi      # 0xa7f6
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x28, %rsi
addq $0x4, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x99a1(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x28, %rdx
movl $0x2, %esi
callq 0x4c40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x34(%rax)
je 0x4694
testb $0x1, -0x21(%rbp)
je 0x467f
movq 0x995b(%rip), %rdi      # 0xdfb0
leaq 0x61b5(%rip), %rsi      # 0xa811
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rax
movl 0x38(%rax), %esi
callq 0x2260
movq %rax, %rdi
movq 0x9946(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rsi
addq $0x38, %rsi
callq 0x4ce0
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x3c(%rax)
je 0x46f4
testb $0x1, -0x21(%rbp)
je 0x46da
movq 0x9905(%rip), %rdi      # 0xdfb0
leaq 0x6178(%rip), %rsi      # 0xa82a
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x40, %rsi
addq $0x4, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x98eb(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x40, %rdx
movl $0x4, %esi
callq 0x4c40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x4c(%rax)
je 0x4754
testb $0x1, -0x21(%rbp)
je 0x473a
movq 0x98a5(%rip), %rdi      # 0xdfb0
leaq 0x6131(%rip), %rsi      # 0xa843
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x50, %rsi
addq $0x4, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x988b(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x50, %rdx
movl $0x5, %esi
callq 0x4c40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x5c(%rax)
je 0x47b0
testb $0x1, -0x21(%rbp)
je 0x4796
movq 0x9845(%rip), %rdi      # 0xdfb0
leaq 0x60eb(%rip), %rsi      # 0xa85d
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x5e, %rsi
callq 0x21f0
movq %rax, %rdi
movq 0x982f(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x5e, %rdx
movl $0x6, %esi
callq 0x4d40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x160(%rax)
je 0x4815
testb $0x1, -0x21(%rbp)
je 0x47f8
movq 0x97e6(%rip), %rdi      # 0xdfb0
leaq 0x60a0(%rip), %rsi      # 0xa871
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x162, %rsi            # imm = 0x162
callq 0x21f0
movq %rax, %rdi
movq 0x97cd(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x162, %rdx            # imm = 0x162
movl $0x7, %esi
callq 0x4d40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x279(%rax)
je 0x48c1
testb $0x1, -0x21(%rbp)
je 0x48a9
movq 0x977d(%rip), %rdi      # 0xdfb0
leaq 0x604b(%rip), %rsi      # 0xa885
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rax
movzbl 0x27c(%rax), %esi
callq 0x2300
movq %rax, %rdi
leaq 0x6044(%rip), %rsi      # 0xa8a0
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rax
movzbl 0x27d(%rax), %esi
callq 0x2300
movq %rax, %rdi
leaq 0x602b(%rip), %rsi      # 0xa8a9
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x27a, %rsi            # imm = 0x27A
addq $0x4, %rsi
callq 0x21f0
movq %rax, %rdi
movq 0x971c(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rsi
addq $0x27a, %rsi            # imm = 0x27A
callq 0x4de0
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x380(%rax)
je 0x490e
testb $0x1, -0x21(%rbp)
je 0x48f6
movq 0x96d5(%rip), %rdi      # 0xdfb0
leaq 0x5fd0(%rip), %rsi      # 0xa8b2
callq 0x21f0
movq %rax, %rdi
movq 0x96cf(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rsi
addq $0x382, %rsi            # imm = 0x382
callq 0x4e90
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x394(%rax)
je 0x4977
testb $0x1, -0x21(%rbp)
je 0x495a
movq 0x9688(%rip), %rdi      # 0xdfb0
leaq 0x5fa2(%rip), %rsi      # 0xa8d1
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x398, %rsi            # imm = 0x398
addq $0x4, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x966b(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x398, %rdx            # imm = 0x398
movl $0xb, %esi
callq 0x4c40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x3a4(%rax)
je 0x49e0
testb $0x1, -0x21(%rbp)
je 0x49c3
movq 0x961f(%rip), %rdi      # 0xdfb0
leaq 0x5f52(%rip), %rsi      # 0xa8ea
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x3a8, %rsi            # imm = 0x3A8
addq $0x4, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x9602(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x3a8, %rdx            # imm = 0x3A8
movl $0x8020, %esi           # imm = 0x8020
callq 0x4c40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x3b4(%rax)
je 0x4a22
testb $0x1, -0x21(%rbp)
je 0x4a15
movq 0x95b6(%rip), %rdi      # 0xdfb0
leaq 0x5f05(%rip), %rsi      # 0xa906
callq 0x21f0
movq %rax, %rdi
movq 0x95b0(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
callq 0x4f20
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x3b5(%rax)
je 0x4a87
testb $0x1, -0x21(%rbp)
je 0x4a6a
movq 0x9574(%rip), %rdi      # 0xdfb0
leaq 0x5ed6(%rip), %rsi      # 0xa919
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x3b6, %rsi            # imm = 0x3B6
callq 0x21f0
movq %rax, %rdi
movq 0x955b(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x3b6, %rdx            # imm = 0x3B6
movl $0x8022, %esi           # imm = 0x8022
callq 0x4d40
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
testb $0x1, 0x4b8(%rax)
je 0x4af0
testb $0x1, -0x21(%rbp)
je 0x4ad3
movq 0x950f(%rip), %rdi      # 0xdfb0
leaq 0x5e87(%rip), %rsi      # 0xa92f
callq 0x21f0
movq %rax, %rdi
movq -0x8(%rbp), %rsi
addq $0x4bc, %rsi            # imm = 0x4BC
addq $0x4, %rsi
callq 0x4040
movq %rax, %rdi
movq 0x94f2(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x30(%rbp), %rdi
movq -0x8(%rbp), %rdx
addq $0x4bc, %rdx            # imm = 0x4BC
movl $0x8050, %esi           # imm = 0x8050
callq 0x4c40
movq %rax, -0x30(%rbp)
movq -0x20(%rbp), %rax
movzwl 0x100(%rax), %eax
cmpl $0x0, %eax
jle 0x4b6f
testb $0x1, -0x21(%rbp)
je 0x4b34
movq 0x94a3(%rip), %rdi      # 0xdfb0
leaq 0x5e37(%rip), %rsi      # 0xa94b
callq 0x21f0
movq %rax, %rdi
movq -0x20(%rbp), %rsi
callq 0x21f0
movq %rax, %rdi
movq 0x9491(%rip), %rsi      # 0xdfc0
callq 0x2200
leaq -0x4c(%rbp), %rdi
movq -0x10(%rbp), %rsi
movq -0x30(%rbp), %rax
movq -0x10(%rbp), %rcx
subq %rcx, %rax
movl %eax, %edx
movq -0x20(%rbp), %rcx
movq -0x20(%rbp), %rax
movzwl 0x100(%rax), %r8d
callq 0x4f50
movq -0x30(%rbp), %rdi
leaq -0x4c(%rbp), %rsi
callq 0x4f90
movq %rax, -0x30(%rbp)
testb $0x1, -0x21(%rbp)
je 0x4b88
movq 0x9434(%rip), %rdi      # 0xdfb0
movq 0x943d(%rip), %rsi      # 0xdfc0
callq 0x2200
movq -0x38(%rbp), %rdi
movq -0x30(%rbp), %rax
movq -0x10(%rbp), %rcx
subq %rcx, %rax
subq $0x14, %rax
movzwl %ax, %esi
callq 0x4bc0
movq -0x30(%rbp), %rax
movq -0x10(%rbp), %rcx
subq %rcx, %rax
addq $0x50, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)