class TestCase::Sys::Socket {
  use Sys;
  use Sys::Socket;
  use Sys::Socket::Constant as SOCKET;
  use Sys::Socket::Sockaddr;
  use Sys::Socket::Sockaddr::In;
  use Sys::Socket::Sockaddr::In6;
  use Sys::Socket::Addrinfo;
  use Sys::Socket::AddrinfoLinkedList;
  use Sys::Socket::Sockaddr::Storage;
  use Sys::Socket::Sockaddr::Un;
  use Sys::Process;
  use Sys::IO::Constant as IO;
  use Sys::Ioctl::Constant as IOCTL;
  use Sys::Socket::Util;
  
  use Sys::Socket::Error::InetInvalidNetworkAddress;
  
  use Fn;
  
  static method htonl : int () {
    my $host_int = 20000;
    my $net_int = Sys::Socket->htonl($host_int);
    
    my $host_int_again = Sys::Socket->ntohl($net_int);
    
    warn "\n[Test Output]htonl:$host_int -> $net_int -> $host_int_again";
    
    if ($host_int == $net_int) {
      return 0;
    }
    
    unless ($host_int == $host_int_again) {
      return 0;
    }
    
    return 1;
  }
  
  static method ntohl : int () {
    my $net_int = 541982720;
    my $host_int = Sys::Socket->ntohl($net_int);
    
    my $net_int_again = Sys::Socket->htonl($host_int);
    
    warn "\n[Test Output]ntohl:$net_int -> $host_int -> $net_int_again";
    
    if ($net_int == $host_int) {
      return 0;
    }
    
    unless ($net_int == $net_int_again) {
      return 0;
    }
    
    return 1;
  }

  static method htons : int () {
    {
      my $host_short = (short)20000;
      my $net_short = Sys::Socket->htons((short)$host_short);
      
      my $host_short_again = Sys::Socket->ntohs((short)$net_short);
      
      warn "\n[Test Output]htons:$host_short -> $net_short -> $host_short_again";
      
      if ($host_short == $net_short) {
        return 0;
      }
      
      unless ($host_short == $host_short_again) {
        return 0;
      }
    }
    
    {
      my $host_short = (short)50000;
      my $net_short = Sys::Socket->htons((short)$host_short);
      
      my $host_short_again = Sys::Socket->ntohs((short)$net_short);
      
      warn "\n[Test Output]htons:$host_short -> $net_short -> $host_short_again";
      
      if ($host_short == $net_short) {
        return 0;
      }
      
      unless ($host_short == $host_short_again) {
        return 0;
      }
    }
    
    return 1;
  }
  
  static method ntohs : int () {
    {
      my $net_short = (short)8270;
      my $host_short = Sys::Socket->ntohs((short)$net_short);
      
      my $net_short_again = Sys::Socket->htons((short)$host_short);
      
      warn "\n[Test Output]ntohs:$net_short -> $host_short -> $net_short_again";
      
      if ($net_short == $host_short) {
        return 0;
      }
      
      unless ($net_short == $net_short_again) {
        return 0;
      }
    }
    
    {
      my $net_short = (short)20675;
      my $host_short = Sys::Socket->ntohs((short)$net_short);
      
      my $net_short_again = Sys::Socket->htons((short)$host_short);
      
      warn "\n[Test Output]ntohs:$net_short -> $host_short -> $net_short_again";
      
      if ($net_short == $host_short) {
        return 0;
      }
      
      unless ($net_short == $net_short_again) {
        return 0;
      }
    }
    
    return 1;
  }

  static method inet_aton : int () {
    
    {
      my $in_addr = Sys::Socket::In_addr->new;
      my $status = Sys::Socket->inet_aton("127.0.0.1", $in_addr);
      
      unless ($status == 1) {
        return 0;
      }
    }
    
    {
      my $in_addr = Sys::Socket::In_addr->new;
      my $status = Sys::Socket->inet_aton("0.0.0.0", $in_addr);
      
      unless ($status == 1) {
        return 0;
      }
      
      unless ($in_addr->s_addr == 0) {
        return 0;
      }
    }
    
    return 1;
  }

  static method inet_ntoa : int () {
    
    {
      my $in_addr = Sys::Socket::In_addr->new;
      my $status = Sys::Socket->inet_aton("127.0.0.1", $in_addr);
      
      unless ($status == 1) {
        return 0;
      }
      
      my $address = Sys::Socket->inet_ntoa($in_addr);
      
      unless ($address eq "127.0.0.1") {
        return 0;
      }
    }
    
    {
      my $in_addr = Sys::Socket::Util->inet_aton("127.0.0.1");
      
      my $address = Sys::Socket->inet_ntoa($in_addr);
      
      unless ($address eq "127.0.0.1") {
        return 0;
      }
    }
    return 1;
  }

  static method inet_pton : int () {
    
    {
      my $in_addr = Sys::Socket::In_addr->new;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
      
      unless ($status == 1) {
        return 0;
      }
      if ($in_addr->s_addr == 0) {
        return 0;
      }
    }
    
    {
      my $in_addr = Sys::Socket::In_addr->new;
      $in_addr->set_s_addr(1);
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET, "0.0.0.0", $in_addr);
      
      unless ($status == 1) {
        return 0;
      }
      
      unless ($in_addr->s_addr == 0) {
        return 0;
      }
    }

    {
      my $in6_addr = Sys::Socket::In6_addr->new;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET6, "ABCD:EF01:2345:6789:ABCD:EF01:2345:6789", $in6_addr);
      
      unless ($status == 1) {
        return 0;
      }

      if ($in6_addr->s6_addr eq "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0") {
        return 0;
      }
    }

    {
      my $in6_addr = Sys::Socket::In6_addr->new;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET6, "::1", $in6_addr);
      
      unless ($status == 1) {
        return 0;
      }

      unless ($in6_addr->s6_addr eq "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1") {
        return 0;
      }
    }

    {
      my $in6_addr = Sys::Socket::In6_addr->new;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET6, "::0", $in6_addr);
      
      unless ($status == 1) {
        return 0;
      }
      
      unless ($in6_addr->s6_addr eq "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0") {
        return 0;
      }
    }
    
    return 1;
  }

  static method inet_ntop : int () {
    {
      my $in_addr = Sys::Socket::In_addr->new;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
      
      unless ($status == 1) {
        return 0;
      }

      my $buffer = (mutable string)new_string_len SOCKET->INET_ADDRSTRLEN;
      
      my $address = Sys::Socket->inet_ntop(SOCKET->AF_INET, $in_addr, $buffer, SOCKET->INET_ADDRSTRLEN);
      
      unless ($address) {
        return 0;
      }
      
      Fn->shorten_null_char($address);
      
      unless ($address eq "127.0.0.1") {
        return 0;
      }
    }
    
    {
      my $in6_addr = Sys::Socket::In6_addr->new;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET6, "abcd:ef01:2345:6789:abcd:ef01:2345:6789", $in6_addr);
      
      unless ($status == 1) {
        return 0;
      }

      my $buffer = (mutable string)new_string_len SOCKET->INET6_ADDRSTRLEN;
      
      my $address = Sys::Socket->inet_ntop(SOCKET->AF_INET6, $in6_addr, $buffer, SOCKET->INET6_ADDRSTRLEN);
      
      unless ($address) {
        return 0;
      }
      
      Fn->shorten_null_char($address);
      
      unless ($address eq "abcd:ef01:2345:6789:abcd:ef01:2345:6789") {
        return 0;
      }
    }
    
    {
      my $in6_addr = Sys::Socket::Util->inet_pton(SOCKET->AF_INET6, "abcd:ef01:2345:6789:abcd:ef01:2345:6789");
      
      my $buffer = (mutable string)new_string_len SOCKET->INET6_ADDRSTRLEN;
      
      my $address = Sys::Socket->inet_ntop(SOCKET->AF_INET6, $in6_addr, $buffer, SOCKET->INET6_ADDRSTRLEN);
      
      unless ($address) {
        return 0;
      }
      
      Fn->shorten_null_char($address);
      
      unless ($address eq "abcd:ef01:2345:6789:abcd:ef01:2345:6789") {
        return 0;
      }
    }
    return 1;
  }

  static method socket : int () {
    
    # IPv4/TCP
    {
      my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
      
      unless ($socket> 0) {
        return 0;
      }
    }
    
    # IPv4/UDP
    {
      my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_DGRAM, 0);
      
      unless ($socket> 0) {
        return 0;
      }
    }
    
    # IPv6/TCP
    {
      my $socket = Sys::Socket->socket(SOCKET->AF_INET6, SOCKET->SOCK_STREAM, 0);
      
      unless ($socket> 0) {
        return 0;
      }
    }
    
    # IPv6/UDP
    {
      my $socket = Sys::Socket->socket(SOCKET->AF_INET6, SOCKET->SOCK_DGRAM, 0);
      
      unless ($socket> 0) {
        return 0;
      }
    }
    
    # IPv4/TCP
    {
      my $socket = -1;
      Sys->socket(\$socket, SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
      
      unless ($socket > 0) {
        return 0;
      }
    }
    return 1;
  }
  
  static method sockaddr : int ($port : int) {
    
    # IPv4
    {
      my $sockaddr = Sys::Socket::Sockaddr::In->new;
      
      $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
      $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
      my $in_addr = $sockaddr->sin_addr;
      my $status = Sys::Socket->inet_aton("127.0.0.1", $in_addr);
      $sockaddr->set_sin_addr($in_addr);
      
      unless ($status == 1) {
        return 0;
      }
    }

    # IPv4
    {
      my $sockaddr = Sys::Socket::Sockaddr::In->new;
      
      $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
      $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
      my $in_addr = $sockaddr->sin_addr;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
      $sockaddr->set_sin_addr($in_addr);
      unless ($status == 1) {
        return 0;
      }
    }
    
    # IPv6
    {
      my $sockaddr = Sys::Socket::Sockaddr::In6->new;
      
      $sockaddr->set_sin6_family((byte)SOCKET->AF_INET6);
      $sockaddr->set_sin6_port(Sys::Socket->htons((short)$port));
      my $in6_addr = $sockaddr->sin6_addr;
      my $status = Sys::Socket->inet_pton(SOCKET->AF_INET6, "::1", $in6_addr);
      $sockaddr->set_sin6_addr($in6_addr);
      unless ($status == 1) {
        return 0;
      }
    }
    
    return 1;
  }
  
  static method connect : int ($port : int) {
    # IPv4 address
    {
      my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
      
      unless ($socket> 0) {
        return 0;
      }
      
      my $in_addr = Sys::Socket::Util->inet_aton("127.0.0.1");
      my $sockaddr_in = Sys::Socket::Util->sockaddr_in($port, $in_addr);
      
      Sys->connect($socket, $sockaddr_in);
      
      my $status_close = Sys::Socket->close($socket);
      
      unless ($status_close == 0) {
        return 0;
      }
    }
    
    # Exception
    {
      # AF_INET6 is wrong setting
      my $socket = Sys::Socket->socket(SOCKET->AF_INET6, SOCKET->SOCK_STREAM, 0);
      
      unless ($socket> 0) {
        return 0;
      }
      
      my $in_addr = Sys::Socket::Util->inet_aton("127.0.0.1");
      my $sockaddr_in = Sys::Socket::Util->sockaddr_in($port, $in_addr);
      
      eval { Sys->connect($socket, $sockaddr_in); }
      
      unless ($@) {
        return 0;
      }
      
      unless (eval_error_id is_error Error::System) {
        return 0;
      }
      
    }
    
    return 1;
  }
  
  static method connect_ipv6 : int ($port : int) {
  
    # IPv6 address
    {
      my $socket = Sys::Socket->socket(SOCKET->AF_INET6, SOCKET->SOCK_STREAM, 0);
      
      unless ($socket> 0) {
        return 0;
      }
      
      my $in6_addr = (Sys::Socket::In6_addr)Sys::Socket::Util->inet_pton(SOCKET->AF_INET6, "::1");
      my $sockaddr_in6 = Sys::Socket::Util->sockaddr_in6($port, $in6_addr);
      Sys->connect($socket, $sockaddr_in6);
      my $status_close = Sys::Socket->close($socket);
      unless ($status_close == 0) {
        return 0;
      }
    }
    
    return 1;
  }
  
  static method close : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    unless ($socket> 0) {
      return 0;
    }
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    my $status_connect = Sys::Socket->connect($socket, $sockaddr, $sockaddr->size);
    
    unless ($status_connect == 0) {
      return 0;
    }

    my $status_close = Sys::Socket->close($socket);
    
    unless ($status_close == 0) {
      return 0;
    }
    
    return 1;
  }

  static method shutdown : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    unless ($socket> 0) {
      return 0;
    }
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    my $status_connect = Sys::Socket->connect($socket, $sockaddr, $sockaddr->size);
    
    unless ($status_connect == 0) {
      return 0;
    }

    Sys->shutdown($socket, SOCKET->SHUT_WR);
    
    my $status_close = Sys::Socket->close($socket);
    
    unless ($status_close == 0) {
      return 0;
    }
    
    return 1;
  }

  static method send_and_recv : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);

    unless ($socket> 0) {
      return 0;
    }
    
    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    my $status_connect = Sys::Socket->connect($socket, $sockaddr, $sockaddr->size);
    
    unless ($status_connect == 0) {
      Sys::Socket->close($socket);
      return 0;
    }
    
    {
      my $send_buffer = "abcd";
      
      my $send_length = Sys->send($socket, $send_buffer, 0);
      
      unless ($send_length == 4) {
        return 0;
      }
    }
    
    {
      my $send_buffer = "ef";
      
      my $send_length = Sys::Socket->send($socket, $send_buffer, length $send_buffer, 0);
      
      unless ($send_length == 2) {
        return 0;
      }
    }
    
    my $status_shutdown = Sys::Socket->shutdown($socket, SOCKET->SHUT_WR);
    
    unless ($status_shutdown == 0) {
      return 0;
    }
    
    my $recv_string_buffer = StringBuffer->new;
    
    while (1) {
      my $recv_buffer = (mutable string)new_string_len 1024;
      my $recv_length = Sys->recv($socket, $recv_buffer, length $recv_buffer, 0);
      
      if ($recv_length > 0) {
        my $recv_string_part = Fn->substr($recv_buffer, 0, $recv_length);
        
        $recv_string_buffer->push($recv_string_part);
      }
      else {
        last;
      }
    }
    
    my $recv_string = $recv_string_buffer->to_string;
    
    unless ($recv_string eq "abcdef") {
      return 0;
    }
    
    return 1;
  }
  
  static method sendto_and_recvfrom : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    unless ($socket> 0) {
      return 0;
    }
    
    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    my $status_connect = Sys::Socket->connect($socket, $sockaddr, $sockaddr->size);
    
    unless ($status_connect == 0) {
      Sys::Socket->close($socket);
      return 0;
    }
    
    {
      my $send_buffer = "abcd";
      
      my $send_length = Sys->sendto($socket, $send_buffer, 0, undef);
      
      unless ($send_length == 4) {
        return 0;
      }
    }
    
    {
      my $send_buffer = "ef";
      
      my $send_length = Sys->sendto($socket, $send_buffer, 0, undef, length $send_buffer, 0);
      
      unless ($send_length == 2) {
        return 0;
      }
    }
    
    my $status_shutdown = Sys::Socket->shutdown($socket, SOCKET->SHUT_WR);
    
    unless ($status_shutdown == 0) {
      return 0;
    }
    
    my $recv_string_buffer = StringBuffer->new;
    
    while (1) {
      my $sockaddr_tmp_ref = (Sys::Socket::Sockaddr[])undef;
      my $recv_buffer = (mutable string)new_string_len 1024;
      my $recv_length = Sys->recvfrom($socket, $recv_buffer, length $recv_buffer, 0, $sockaddr_tmp_ref);
      
      if ($recv_length > 0) {
        my $recv_string_part = Fn->substr($recv_buffer, 0, $recv_length);
        
        $recv_string_buffer->push($recv_string_part);
      }
      else {
        last;
      }
    }
    
    my $recv_string = $recv_string_buffer->to_string;
    
    unless ($recv_string eq "abcdef") {
      return 0;
    }
    
    return 1;
  }
  
  static method bind : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    unless ($socket> 0) {
      return 0;
    }

    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    Sys->setsockopt($socket, SOCKET->SOL_SOCKET, SOCKET->SO_REUSEADDR, 1);
    
    Sys->bind($socket, $sockaddr);
    
    return 1;
  }
  
  static method listen : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    unless ($socket> 0) {
      return 0;
    }
    
    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    Sys->setsockopt($socket, SOCKET->SOL_SOCKET, SOCKET->SO_REUSEADDR, 1);
    
    my $status_bind = Sys::Socket->bind($socket, $sockaddr, $sockaddr->size);
    
    unless ($status_bind == 0) {
      return 0;
    }

    Sys->listen($socket, SOCKET->SOMAXCONN);
    
    return 1;
  }

  # accept
  static method run_echo_server : void ($port : int) {

    # Socket
    my $server_socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);

    Sys->setsockopt($server_socket, SOCKET->SOL_SOCKET, SOCKET->SO_REUSEADDR, 1);
    
    Sys::Socket->bind($server_socket, $sockaddr, $sockaddr->size);
    
    Sys::Socket->listen($server_socket, SOCKET->SOMAXCONN);
    
    my $warned = 0;
    
    while (1) {
      my $client_socket = -1;
      my $peer_address = Sys->accept(\$client_socket, $server_socket);
      
      my $recv_buffer = (mutable string)new_string_len 1024;
      my $recv_length = Sys::Socket->recv($client_socket, $recv_buffer, length $recv_buffer, 0);
      
      Sys::Socket->send($client_socket, $recv_buffer, $recv_length, 0);
      
      Sys::Socket->close($client_socket);
    }
  }

  static method getpeername : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);

    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    unless ($socket> 0) {
      return 0;
    }
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    my $status_connect = Sys::Socket->connect($socket, $sockaddr, $sockaddr->size);
    
    {
      my $result_address = Sys::Socket::Sockaddr::In->new;
      
      my $result_address_size = $result_address->size;
      my $status_getpeername = Sys::Socket->getpeername($socket, $result_address, \$result_address_size);
      unless ($status_getpeername == 0) {
        return 0;
      }
      my $port_got = ((int)Sys::Socket->ntohs((short)$result_address->sin_port)) & 0xFFFF;
      
      unless ($port_got == $port) {
        return 0;
      }
      unless ($result_address->sin_addr->s_addr == $in_addr->s_addr) {
        return 0;
      }
      unless ($result_address->size == $sockaddr->size) {
        return 0;
      }
    }
    {
      my $result_address = (Sys::Socket::Sockaddr::In)Sys->getpeername($socket);
      unless ($result_address->sin_family == SOCKET->AF_INET) {
        return 0;
      }
      unless (Sys::Socket->ntohs((short)$result_address->sin_port) != 0) {
        return 0;
      }
      unless ($result_address->sin_addr->s_addr == $in_addr->s_addr) {
        return 0;
      }
    }
    return 1;
  }

  static method getsockname : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);

    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    
    unless ($socket> 0) {
      return 0;
    }
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    Sys::Socket->inet_pton(SOCKET->AF_INET, "127.0.0.1", $in_addr);
    $sockaddr->set_sin_addr($in_addr);
    
    my $status_connect = Sys::Socket->connect($socket, $sockaddr, $sockaddr->size);
    
    {
      my $result_address = Sys::Socket::Sockaddr::In->new;
      
      my $result_address_size = $result_address->size;
      my $status_getsockname = Sys::Socket->getsockname($socket, $result_address, \$result_address_size);

      unless ($status_getsockname == 0) {
        return 0;
      }
      
      unless (Sys::Socket->ntohs((short)$result_address->sin_port) != 0) {
        return 0;
      }
      
      unless ($result_address->sin_addr->s_addr == $in_addr->s_addr) {
        return 0;
      }

      unless ($result_address->size == $sockaddr->size) {
        return 0;
      }
    }
    
    {
      my $result_address = (Sys::Socket::Sockaddr::In)Sys->getsockname($socket);
      
      unless ($result_address->sin_family == SOCKET->AF_INET) {
        return 0;
      }
      
      unless (Sys::Socket->ntohs((short)$result_address->sin_port) != 0) {
        return 0;
      }
      
      unless ($result_address->sin_addr->s_addr == $in_addr->s_addr) {
        return 0;
      }
    }
    
    return 1;
  }

  static method socketpair : int () {
    
    {
      my $sockets = new int[2];
      my $status = Sys::Socket->socketpair(SOCKET->AF_UNIX, SOCKET->SOCK_STREAM, 0, $sockets);
      
      unless ($status == 0) {
        return 0;
      }
      
      my $sockets0 = $sockets->[0];
      Fn->defer([$sockets0 : int] method :void () {
        Sys::Socket->close($sockets0);
      });
      
      my $sockets1 = $sockets->[1];
      Fn->defer([$sockets1 : int] method :void () {
        Sys::Socket->close($sockets1);
      });
      
      unless ($sockets->[0] > 0) {
        return 0;
      }
      
      unless ($sockets->[1] > 0) {
        return 0;
      }
    }
    
    {
      my $socket1 = -1;
      my $socket2 = -1;
      Sys->socketpair(\$socket1, \$socket2, SOCKET->AF_UNIX, SOCKET->SOCK_STREAM, 0);
      
      Fn->defer([$socket1 : int] method :void () {
        Sys::Socket->close($socket1);
      });
      
      Fn->defer([$socket2 : int] method :void () {
        Sys::Socket->close($socket2);
      });
      
      unless ($socket1 > 0) {
        return 0;
      }
      
      unless ($socket2 > 0) {
        return 0;
      }
    }
    
    return 1;
  }

  static method setsockopt_int : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    unless ($socket> 0) {
      return 0;
    }

    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    $in_addr->set_s_addr(Sys::Socket->htonl(SOCKET->INADDR_ANY));
    $sockaddr->set_sin_addr($in_addr);
    
    Sys->setsockopt($socket, SOCKET->SOL_SOCKET, SOCKET->SO_REUSEADDR, 1);
    
    return 1;
  }

  static method getsockopt_int : int ($port : int) {
    # Socket
    my $socket = Sys::Socket->socket(SOCKET->AF_INET, SOCKET->SOCK_STREAM, 0);
    
    unless ($socket> 0) {
      return 0;
    }

    Fn->defer([$socket : int] method :void () {
      Sys::Socket->close($socket);
    });
    
    
    # IPv4 address
    my $sockaddr = Sys::Socket::Sockaddr::In->new;
    $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
    $sockaddr->set_sin_port(Sys::Socket->htons((short)$port));
    my $in_addr = $sockaddr->sin_addr;
    $in_addr->set_s_addr(Sys::Socket->htonl(SOCKET->INADDR_ANY));
    $sockaddr->set_sin_addr($in_addr);
    
    {
      my $result_packed = Sys->getsockopt($socket, SOCKET->SOL_SOCKET, SOCKET->SO_REUSEADDR);
      my $result_ref = [0];
      Fn->memcpy($result_ref, 0, $result_packed, 0, 4);
      my $result = $result_ref->[0];
      
      unless ($result == 0) {
        return 0;
      }
    }
    
    {
      Sys->setsockopt($socket, SOCKET->SOL_SOCKET, SOCKET->SO_REUSEADDR, 1);
      
      my $result_packed = Sys->getsockopt($socket, SOCKET->SOL_SOCKET, SOCKET->SO_REUSEADDR);
      my $result_ref = [0];
      Fn->memcpy($result_ref, 0, $result_packed, 0, 4);
      my $result = $result_ref->[0];
      
      if ($result == 0) {
        return 0;
      }
    }
    
    return 1;
  }

  static method sockaddr_strage : int () {
    my $sockaddr = Sys::Socket::Sockaddr::Storage->new;
    
    $sockaddr->set_ss_family(1);
    
    unless ($sockaddr->ss_family == 1) {
      return 0;
    }
    
    unless ($sockaddr->sa_family == 1) {
      return 0;
    }
    
    unless ($sockaddr->size > 0) {
      return 0;
    }
    
    return 1;
  }

  static method sockaddr_un : int () {
    my $sockaddr = Sys::Socket::Sockaddr::Un->new;
    
    $sockaddr->set_sun_family(1);
    
    unless ($sockaddr->sun_family == 1) {
      return 0;
    }
    
    unless ($sockaddr->sa_family == 1) {
      return 0;
    }
    
    $sockaddr->set_sun_path("abc");
    
    unless ($sockaddr->sun_path eq "abc") {
      return 0;
    }
    
    unless ($sockaddr->size > 0) {
      return 0;
    }
    
    return 1;
  }

  static method getaddrinfo : int () {
    {
      my $servname = "localhost";
      my $hints = Sys::Socket::Addrinfo->new;
      my $res = new Sys::Socket::AddrinfoLinkedList[1];
      
      $hints->set_ai_socktype(SOCKET->SOCK_STREAM);
      $hints->set_ai_family(SOCKET->AF_INET);
      
      my $status = Sys::Socket->getaddrinfo($servname, undef, $hints, $res);
      
      unless ($status == 0) {
        return 0;
      }

      my $addrinfos = $res->[0]->to_array;
      
      {
        my $addrinfo = $addrinfos->[0];
        
        my $ai_addr = $addrinfo->ai_addr;
        
        my $in_addr : Sys::Socket::In_addr = $ai_addr->(Sys::Socket::Sockaddr::In)->sin_addr;

        my $addr_string = Sys::Socket->inet_ntoa($in_addr);
        
        unless ($addr_string eq "127.0.0.1") {
          return 0;
        }
      }

      if (@$addrinfos >= 2 ){
        my $addrinfo = $addrinfos->[1];
        
        my $ai_addr = $addrinfo->ai_addr;
        
        my $in_addr : Sys::Socket::In_addr = $ai_addr->(Sys::Socket::Sockaddr::In)->sin_addr;

        my $addr_string = Sys::Socket->inet_ntoa($in_addr);
        
        unless ($addr_string eq "127.0.0.1") {
          return 0;
        }
      }
    }
    
    {
      my $servname = "localhost";
      my $hints = Sys::Socket::Addrinfo->new;
      my $res = new Sys::Socket::AddrinfoLinkedList[1];
      
      $hints->set_ai_socktype(SOCKET->SOCK_STREAM);
      $hints->set_ai_family(SOCKET->AF_INET6);
      
      my $status = Sys::Socket->getaddrinfo($servname, undef, $hints, $res);
      
      unless ($status == 0) {
        return 0;
      }
      
      my $addrinfos = $res->[0]->to_array;
      
      my $addrinfo = $addrinfos->[0];
      
      my $ai_addr = $addrinfo->ai_addr;
      
      my $in_addr : Sys::Socket::In6_addr = $ai_addr->(Sys::Socket::Sockaddr::In6)->sin6_addr;
      
      my $addr_string = (mutable string)new_string_len SOCKET->INET_ADDRSTRLEN;
      Sys::Socket->inet_ntop(SOCKET->AF_INET6, $in_addr, $addr_string, SOCKET->INET_ADDRSTRLEN);
      Fn->shorten_null_char($addr_string);
      
      unless ($addr_string eq "::1") {
        return 0;
      }
    }

    {
      my $servname = "http";
      my $hints = Sys::Socket::Addrinfo->new;
      my $res = new Sys::Socket::AddrinfoLinkedList[1];
      
      $hints->set_ai_socktype(SOCKET->SOCK_STREAM);
      $hints->set_ai_family(SOCKET->AF_INET);
      
      my $status = Sys::Socket->getaddrinfo(undef, $servname, $hints, $res);
      
      unless ($status == 0) {
        return 0;
      }
      
      my $addrinfos = $res->[0]->to_array;
      
      my $addrinfo = $addrinfos->[0];
      
      my $ai_addr = $addrinfo->ai_addr;
      
      my $port_net = $ai_addr->(Sys::Socket::Sockaddr::In)->sin_port;

      my $port_host = (int)Sys::Socket->ntohs((short)$port_net);
      
      unless ($port_host == 80) {
        return 0;
      }
    }
    
    return 1;
  }

  static method getnameinfo : int () {
    
    # IPv4
    {
      my $sockaddr = Sys::Socket::Sockaddr::In->new;
      $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
      my $in_addr = $sockaddr->sin_addr;
      Sys::Socket->inet_aton("127.0.0.1", $in_addr);
      $sockaddr->set_sin_addr($in_addr);
      
      my $host = (mutable string)new_string_len SOCKET->NI_MAXHOST;
      my $status = Sys::Socket->getnameinfo($sockaddr, $sockaddr->size, $host, length $host, undef, 0, 0);

      unless ($status == 0) {
        return 0;
      }
      
      Fn->shorten_null_char($host);
      
      # Generally this is localhost, but if localhost is not defined in /etc/hosts, this is resolved by DNS.
      if ($host eq "") {
        return 0;
      }
    }

    # IPv6
    {
      my $sockaddr = Sys::Socket::Sockaddr::In6->new;
      $sockaddr->set_sin6_family((byte)SOCKET->AF_INET6);
      my $in_addr = $sockaddr->sin6_addr;
      Sys::Socket->inet_pton(SOCKET->AF_INET6, "::1", $in_addr);
      $sockaddr->set_sin6_addr($in_addr);
      
      my $host = (mutable string)new_string_len SOCKET->NI_MAXHOST;
      my $status = Sys::Socket->getnameinfo($sockaddr, $sockaddr->size, $host, length $host, undef, 0, 0);

      unless ($status == 0) {
        return 0;
      }
      
      Fn->shorten_null_char($host);
      
      # Generally this is localhost, but if localhost is not defined in /etc/hosts, this is resolved by DNS.
      if ($host eq "") {
        return 0;
      }
    }

    # Service
    {
      my $sockaddr = Sys::Socket::Sockaddr::In->new;
      $sockaddr->set_sin_family((byte)SOCKET->AF_INET);
      $sockaddr->set_sin_port(Sys::Socket->htons(80));
      
      my $service = (mutable string)new_string_len SOCKET->NI_MAXSERV;
      my $status = Sys::Socket->getnameinfo($sockaddr, $sockaddr->size, undef, 0, $service, length $service, 0);

      unless ($status == 0) {
        return 0;
      }
      
      Fn->shorten_null_char($service);
      
      unless ($service eq "http") {
        return 0;
      }
    }
    
    return 1;
  }
}