// File: romkatv[P]hcproxy/src/hcproxy.cc
// Function: hcproxy::(anonymous namespace)::RunProxy(hcproxy::(anonymous namespace)::Options const&)
void RunProxy(const Options& opt) {
  auto IsAllowedPort = [&](std::string_view host_port) {
    auto sep = host_port.find(':');
    if (sep == std::string_view::npos) return false;
    std::string_view port = host_port.substr(sep + 1);
    return opt.allowed_ports.empty() || opt.allowed_ports.count(port);
  };

  signal(SIGPIPE, SIG_IGN);

  if (opt.max_num_open_files > 0) {
    struct rlimit lim;
    CHECK(getrlimit(RLIMIT_NOFILE, &lim) == 0) << Errno();
    lim.rlim_cur = opt.max_num_open_files;
    // It'll fail if opt.max_num_open_files is greater than lim.rlim_max.
    CHECK(setrlimit(RLIMIT_NOFILE, &lim) == 0) << Errno();
  }

  auto& acceptor = *new Acceptor(opt);
  auto& parser = *new Parser(opt);
  auto& dns_resolver = *new DnsResolver(opt);
  auto& connector = *new Connector(opt);
  auto& forwarder = *new Forwarder(opt);

  while (true) {
    int client_fd = acceptor.Accept();
    parser.ParseRequest(client_fd, [&, client_fd](std::string_view host_port) {
      if (host_port.empty() || !IsAllowedPort(host_port)) {
        CHECK(close(client_fd) == 0) << Errno();
        return;
      }
      dns_resolver.Resolve(host_port, [&, client_fd](std::shared_ptr<const addrinfo> addr) {
        if (!addr) {
          LOG(WARN) << "[" << client_fd << "] DNS error: " << host_port;
          CHECK(close(client_fd) == 0) << Errno();
          return;
        }
        LOG(INFO) << "[" << client_fd << "] tunnel to " << IpPort(*addr);
        connector.Connect(*addr, [&, client_fd](int server_fd) {
          if (server_fd < 0) {
            CHECK(close(client_fd) == 0) << Errno();
            return;
          }
          forwarder.Forward(client_fd, server_fd);
        });
      });
    });
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x200, %rsp            # imm = 0x200
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x10(%rbp)
movl $0xd, %edi
movl $0x1, %esi
callq 0x155a0
movq -0x8(%rbp), %rax
cmpq $0x0, 0xb8(%rax)
jbe 0x294c2
movl $0x7, %edi
leaq -0x20(%rbp), %rsi
callq 0x15770
movb $0x0, -0x41(%rbp)
cmpl $0x0, %eax
jne 0x292e4
jmp 0x29386
leaq 0xbb9fa(%rip), %rsi     # 0xe4ce5
leaq -0x40(%rbp), %rdi
movq %rdi, -0x160(%rbp)
movl $0x40, %edx
movl $0x3, %ecx
callq 0x194b0
movq -0x160(%rbp), %rdi
movb $0x1, -0x41(%rbp)
callq 0x194e0
movq %rax, -0x158(%rbp)
jmp 0x2931e
movq -0x158(%rbp), %rdi
leaq 0xbba03(%rip), %rsi     # 0xe4d2f
callq 0x2b0a0
movq %rax, -0x168(%rbp)
jmp 0x2933a
movq -0x168(%rbp), %rdi
leaq 0xc0043(%rip), %rsi     # 0xe938b
callq 0x19450
movq %rax, -0x170(%rbp)
jmp 0x29356
callq 0x1c0c0
jmp 0x2935d
movq -0x170(%rbp), %rdi
callq 0x1c050
movq %rax, -0x178(%rbp)
jmp 0x29372
movq -0x178(%rbp), %rsi
leaq -0x57(%rbp), %rdi
callq 0x194f0
jmp 0x29384
jmp 0x29386
testb $0x1, -0x41(%rbp)
jne 0x2938e
jmp 0x293b2
leaq -0x40(%rbp), %rdi
callq 0x19500
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
testb $0x1, -0x41(%rbp)
jne 0x29490
jmp 0x29499
movq -0x8(%rbp), %rax
movq 0xb8(%rax), %rax
movq %rax, -0x20(%rbp)
movl $0x7, %edi
leaq -0x20(%rbp), %rsi
callq 0x15190
movb $0x0, -0x79(%rbp)
cmpl $0x0, %eax
jne 0x293dd
jmp 0x2947f
leaq 0xbb901(%rip), %rsi     # 0xe4ce5
leaq -0x78(%rbp), %rdi
movq %rdi, -0x188(%rbp)
movl $0x43, %edx
movl $0x3, %ecx
callq 0x194b0
movq -0x188(%rbp), %rdi
movb $0x1, -0x79(%rbp)
callq 0x194e0
movq %rax, -0x180(%rbp)
jmp 0x29417
movq -0x180(%rbp), %rdi
leaq 0xbb92e(%rip), %rsi     # 0xe4d53
callq 0x2b0a0
movq %rax, -0x190(%rbp)
jmp 0x29433
movq -0x190(%rbp), %rdi
leaq 0xbff4a(%rip), %rsi     # 0xe938b
callq 0x19450
movq %rax, -0x198(%rbp)
jmp 0x2944f
callq 0x1c0c0
jmp 0x29456
movq -0x198(%rbp), %rdi
callq 0x1c050
movq %rax, -0x1a0(%rbp)
jmp 0x2946b
movq -0x1a0(%rbp), %rsi
leaq -0x7c(%rbp), %rdi
callq 0x194f0
jmp 0x2947d
jmp 0x2947f
testb $0x1, -0x79(%rbp)
jne 0x29487
jmp 0x294b2
leaq -0x78(%rbp), %rdi
callq 0x19500
leaq -0x40(%rbp), %rdi
callq 0x19500
jmp 0x2978e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
testb $0x1, -0x79(%rbp)
jne 0x294b4
jmp 0x294bd
jmp 0x294c2
leaq -0x78(%rbp), %rdi
callq 0x19500
jmp 0x2978e
movl $0x4, %edi
callq 0x35bb0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1a8(%rbp)
movq -0x8(%rbp), %rsi
callq 0x1caa0
jmp 0x294e4
movq -0x1a8(%rbp), %rax
movq %rax, -0x88(%rbp)
movl $0x18, %edi
callq 0x35bb0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1b0(%rbp)
movq -0x8(%rbp), %rax
movups 0x30(%rax), %xmm0
movaps %xmm0, -0xa0(%rbp)
movq -0xa0(%rbp), %rsi
movq -0x98(%rbp), %rdx
callq 0x197a0
jmp 0x2952d
movq -0x1b0(%rbp), %rax
movq %rax, -0x90(%rbp)
movl $0x148, %edi            # imm = 0x148
callq 0x35bb0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1b8(%rbp)
movq -0x8(%rbp), %rax
movups 0x40(%rax), %xmm0
movups 0x50(%rax), %xmm1
movaps %xmm1, -0xc0(%rbp)
movaps %xmm0, -0xd0(%rbp)
movaps -0xd0(%rbp), %xmm0
movaps -0xc0(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
callq 0x1f120
jmp 0x2958b
movq -0x1b8(%rbp), %rax
movq %rax, -0xa8(%rbp)
movl $0x8, %edi
callq 0x35bb0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1c0(%rbp)
movq -0x8(%rbp), %rsi
addq $0x60, %rsi
callq 0x1de10
jmp 0x295bf
movq -0x1c0(%rbp), %rax
movq %rax, -0xd8(%rbp)
movl $0x20, %edi
callq 0x35bb0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x1c8(%rbp)
movq -0x8(%rbp), %rax
movq 0x78(%rax), %rcx
movq %rcx, -0xf0(%rbp)
movups 0x68(%rax), %xmm0
movaps %xmm0, -0x100(%rbp)
movq -0xf0(%rbp), %rcx
movq %rsp, %rax
movq %rcx, 0x10(%rax)
movaps -0x100(%rbp), %xmm0
movups %xmm0, (%rax)
callq 0x2d930
jmp 0x2961d
movq -0x1c8(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0x88(%rbp), %rdi
callq 0x1d390
movl %eax, -0x104(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0x1e0(%rbp)
movl -0x104(%rbp), %eax
movl %eax, -0x1d4(%rbp)
movl %eax, -0x150(%rbp)
leaq -0x10(%rbp), %rax
movq %rax, -0x148(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0x140(%rbp)
movq -0xd8(%rbp), %rax
movq %rax, -0x138(%rbp)
movq -0xe0(%rbp), %rax
movq %rax, -0x130(%rbp)
leaq -0x128(%rbp), %rdi
movq %rdi, -0x1d0(%rbp)
leaq -0x150(%rbp), %rsi
callq 0x297d0
movq -0x1e0(%rbp), %rdi
movl -0x1d4(%rbp), %esi
movq -0x1d0(%rbp), %rdx
callq 0x19830
jmp 0x296c7
leaq -0x128(%rbp), %rdi
callq 0x1af00
jmp 0x2962b
movq -0x1a8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
movl $0x4, %esi
callq 0x34c20
jmp 0x2978e
movq -0x1b0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
movl $0x18, %esi
callq 0x34c20
jmp 0x2978e
movq -0x1b8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
movl $0x148, %esi            # imm = 0x148
callq 0x34c20
jmp 0x2978e
movq -0x1c0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
movl $0x8, %esi
callq 0x34c20
jmp 0x2978e
movq -0x1c8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
movl $0x20, %esi
callq 0x34c20
jmp 0x2978e
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x128(%rbp), %rdi
callq 0x1af00
movq -0x50(%rbp), %rdi
callq 0xe1080
nopw (%rax,%rax)