O IPv6 - Happy Eyeballs II
C/C++
Em C, utiliza-se muito a função gethostbyname, da bilioteca netdb.h, para realizar consultas DNS:
struct hostent *gethostbyname(const char *name); struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses from name server */ }; Porém essa função, assim como outras da biblioteca netdb.h, só possui suporte a IPv4. Para corrigir essa falha, foi criado a função gethostbyname2: struct hostent *gethostbyname2(const char *name, int af);
Como pode ser observado, foi adicionado um novo parâmetro na função chamado af (Address Family), que pode ser do tipo AF_INET para resultados exclusivamente IPv4, AF_INET6 para resultados exclusivamente IPv6 ou AF_UNSPEC para poder retornar qualquer tipo de endereço. No entanto essa função apresenta problemas caso o host em questão possua mais de 1 único IP anunciado em seu DNS.
Mais informações sobre as funções gethostbyname e gethostbyname2 podem ser encontradas em:
- http://pubs.opengroup.org/onlinepubs/009695399/functions/gethostbyname.html
- http://tools.ietf.org/html/rfc3493
Com isso a função gethostbyname2 foi depreciada e subtituída pela função getaddrinfo:
int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); struct addrinfo { int ai_flags; // AI_PASSIVE, AI_CANONNAME, etc. int ai_family; // AF_INET, AF_INET6, AF_UNSPEC int ai_socktype; // SOCK_STREAM, SOCK_DGRAM int ai_protocol; // use 0 for "any" size_t ai_addrlen; // size of ai_addr in bytes struct sockaddr *ai_addr; // struct sockaddr_in or _in6 char *ai_canonname; // full canonical hostname struct addrinfo *ai_next; // linked list, next node };
Nota-se que a função é bem mais complexa que as anteriores, isso ocorre porque o getaddrinfo possui outras funcionalidades além das consultas DNS. O parâmetro node é o host ou IP no qual queremos nos conectar. O parâmetro service indica o tipo de serviço a ser conectado, o que pode ser uma porta (como “80” ou “22”) ou o nome do serviço (“http”, “ftp”, “telnet”, etc.). O parâmetro hints é uma estrutura de dados na qual só nos interessa o campo ai_famliy (que é o mesmo campo af da função gethostbyname2) e o campoai_socktype, que em geral será preenchido com a constante SOCK_STREAM. O parâmetro res é a estrutura de dados na qual será recebida a resposta da consulta.
Abaixo um exemplo de como utilizar a função getaddrinfo para realizar uma consulta dns:
int main(int argc, char *argv[]) { struct addrinfo hints, *res, *p; int status; char ipstr[INET6_ADDRSTRLEN]; if (argc != 2) { fprintf(stderr, "Usage: %s hostname\n", argv[0]); return 1; } memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version hints.ai_socktype = SOCK_STREAM; if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); return 2; } for(p = res;p != NULL; p = p->ai_next) { void *addr; if (p->ai_family == AF_INET) { return 1; } else { struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; addr = &(ipv6->sin6_addr); /* convert the IP to a string and print it: */ inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); printf("Hostname: %s\n", argv[1]); printf("IP Address: %s\n", ipstr); } } freeaddrinfo(res); // free the linked list return 0; }
Mais informções sobre a função getaddrinfo podem ser encontradas em:
- http://pubs.opengroup.org/onlinepubs/009695399/functions/getaddrinfo.html
- http://pubs.opengroup.org/onlinepubs/009619199/getad.htm
Os sockets em C estão definidos na biblioteca sys/socket.h. Para se criar um socket é utilizado a seguinte função:
int socket(int domain, int type, int protocol);
Apesar de parecer simples, essa função é um pouco confusa, pois todos os seus parâmetros de entrada são constantes pré-definidas. O parâmetro domain é o mesmo parâmetro af da função gethostbyname e o parâmetro ai_family da função getaddrinfo, ou seja, indica o tipo de endereço utilizado pelo socket. O parâmetro type é o mesmo parâmetro ai_socktype da função getaddrinfo, que indica o tipo de socket a ser utilizado. O parâmetro protocol indica o tipo de protocolo a ser utilizado na conexão pelo socket (como tcp, udp, etc.). Note que esse parâmetro é parecido com o parâmetro service da função getaddrinfo, no entantoservice é uma string, enquanto protocol é um número do tipo int. Normalmente no parâmetro protocol é utilizado o valor IPPROTO_TCP, para indicar que a conexão deverá ser via TCP, porém se deixado seu valor como 0, a própria função ficará encarregada de decidir qual o melhor protocolo a ser utilizado para o tipo endereço e socket utilizado.
É importante observar que essa função não retorna o socket em si, mas um número que representa o id do socket criado. Em quase todas as funções de socket o procedimento é o mesmo, não há contato direto com o socket, apenas são passados os ids dos sockets dentro das funções que irão realizar as operações.
Para se conectar a um host utilizando o socket criado devemos utilizar a função connect:
int connect(int socket, const struct sockaddr *address, socklen_t address_len); O parâmetro socket é o mesmo socket id que foi gerado na função socket. O parâmetro address é uma struct retornada pela função getaddrinfo, dentro da struct addrinfo->ai_addr O parâmetro address_len também é um parâmetro retornado pela função getaddrinfo, dentro da struct addrinfo->ai_addrlen. A struct sockaddr pode ser de vários tipos: struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address }; // IPv4 AF_INET sockets: struct sockaddr_in { short sin_family; // e.g. AF_INET, AF_INET6 unsigned short sin_port; // e.g. htons(3490) struct in_addr sin_addr; // see struct in_addr, below char sin_zero[8]; // zero this if you want to }; struct in_addr { unsigned long s_addr; // load with inet_pton() }; // IPv6 AF_INET6 sockets: struct sockaddr_in6 { u_int16_t sin6_family; // address family, AF_INET6 u_int16_t sin6_port; // port number, Network Byte Order u_int32_t sin6_flowinfo; // IPv6 flow information struct in6_addr sin6_addr; // IPv6 address u_int32_t sin6_scope_id; // Scope ID }; struct in6_addr { unsigned char s6_addr[16]; // load with inet_pton() }; // General socket address holding structure, big enough to hold either // struct sockaddr_in or struct sockaddr_in6 data: struct sockaddr_storage { sa_family_t ss_family; // address family // all this is padding, implementation specific, ignore it: char __ss_pad1[_SS_PAD1SIZE]; int64_t __ss_align; char __ss_pad2[_SS_PAD2SIZE]; }; Abaixo um exemplo do uso da função connect: int sd; int rc; struct addrinfo ai_hints, *ai; /* create hints for getaddrinfo for stream socket */ memset(&ai_hints, 0, sizeof(ai_hints)); ai_hints.ai_family = AF_INET6; ai_hints.ai_socktype = SOCK_STREAM; ai_hints.ai_protocol = IPPROTO_TCP; /* get list of addresses for nodename from DNS */ rc = getaddrinfo(szNodename, szService, &ai_hints, &ai); if (rc != 0) { strcpy(szError, "getaddrinfo() failed: "); strcat(szError, gai_strerror(rc)); return -1; } /* create socket for this address */ sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sd < 0) { /* fail */ strcpy(szError, "socket() failed, "); strcat(szError, strerror(errno)); return -1; } rc = connect(sd, ai->ai_addr, ai->ai_addrlen);
É importante lembrar que ao iniciar a função connect o programa irá travar sua execução até que a conexão seja estabelecida. Para a execução do Happy Eyeballs é necessário que o programa continue sua execução mesmo após a chamada da função connect. A forma mais simples de se fazer isso é tornando o socket non-blocking. Dessa forma o programa continuará sua execução mesmo após um connect.
Mais informações sobre sockets e suas funções podem ser encontradas em:
- http://pubs.opengroup.org/onlinepubs/009695399/functions/socket.html
- http://pubs.opengroup.org/onlinepubs/009695399/functions/connect.html
- http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/socket.h.html
Para tornar o socket non-blocking pode-se utilizar a função ioctl, da biblioteca stropts.h:
int ioctl(int fildes, int request, ... /* arg */); Note que essa é uma função mais avançada, portanto deve ser utilizado com cuidado. O parâmetro fildes (File Descriptor) indica o id do arquivo a ser modificado (no nosso caso é o socket, portanto seu id). O parâmetro request indica o comando que deverá ser executado, no nosso caso seria a constante FIONBIO. O parâmetro arg são configurações ou informações adicionais específicos da operação e do tipo de fildes utilizado. Um exemplo de como utilizar a função ioctl: int sd; int opt = 1; sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); ioctl(sd, FIONBIO, &opt); Note que nesse caso foi utilizado um parâmetro chamado opt de valor 1. A função ioctl, quando utilizada com o parâmetro FIONBIO, torna o socket non-blocking caso o parâmetro arg seja diferente de zero. Portanto no exemplo a função está tornando o socket criado em um socket non-blocking. Para retornar o socket em modo blocking basta retirar a flag setada anteriormente, utilizando o parâmetro arg com valor igual a zero: int sd; int opt = 1; sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); // Seta socket non-blocking ioctl(sd, FIONBIO, &opt); // Seta socket blocking opt = 0; ioctl(sd, FIONBIO, &opt);
Mais informações sobre a função ioctl podem ser encontradas em:
Outra forma de se tornar o socket non-blocking é através da função fcntl, da biblioteca fcntl.h:
int fcntl(int fildes, int cmd, ... /* arg */ );
Novamente, essa funçao deve ser utilizada com cuidado, pois mexe nas propriedades do arquivo que queremos modificar. O parâmetro fildes é o mesmo da função ioctl, ou seja, o identificador do arquivo alvo (socket). O parâmetro cmd é similar ao parâmetro request da função ioctl, porém com constantes diferentes, o mesmo se aplica ao parâmetro arg. Abaixo um exemplo de como utilizar a função fcntl para tornar o socketnon-blocking:
int sd; sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); int flags = fcntl(sd, F_GETFL, 0); fcntl(sd, F_SETFL, flags | O_NONBLOCK);
Note que sua utilização é um pouco diferente da ioctl, pois é necessário executar a função duas vezes: uma para adquirir o parêmetro de flags do socket e outro para setar a flag indicando que o socket será non-blocking. Mais informações sobre a função fcntl podem ser acessadas em:
Quando o socket está em modo non-blocking, é necessário verificar de tempos em tempos se a conexão foi estabelecida. Existem várias formas de se verificar isso, porém para o Happy Eyeballs uma função interessante é a getpeername, da biblioteca socket.h:
int getpeername(int socket, struct sockaddr *address, socklen_t *address_len);
Como é possível notar, esta função possui os mesmos parâmetros de entrada que a função connect, ou seja, podemos utilizar as mesmas entradas utilizadas na função connect na função getpeername, como no exemplo abaixo:
/* Faz as consultas DNS */ sd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); rc = connect(sd, ai->ai_addr, ai->ai_addrlen); // Espera estabelecer a conexão while (!connected) { rc = getpeername(sd, ai->ai_addr, ai->ai_addrlen); if (rc < 0) { connected = TRUE; } } // Conexão estabelecida
Mais informações sobre a função getpeername podem ser encontradas em:
- http://pubs.opengroup.org/onlinepubs/009695399/functions/getpeername.html
- http://pubs.opengroup.org/onlinepubs/7908799/xns/getpeername.html
Java
No java devemos tomar certo cuidado, pois o tratamento de IPs é dada pela classeInetAddress (java.net.InetAddress). Esta classe possui 2 implementações diretas: Inet4Adress para IPv4 eInet6Address para IPv6. A documentação oficial das classes pode ser encontrada em:
- http://docs.oracle.com/javase/1.4.2/docs/api/java/net/InetAddress.html
- http://docs.oracle.com/javase/1.4.2/docs/api/java/net/Inet4Address.html
- http://docs.oracle.com/javase/1.4.2/docs/api/java/net/Inet6Address.html
Basicamente, a classe InetAddress é a responsável por armazenar e tratar os endereços IP. Além disso ela disponibiliza métodos de análises de escopo do IP, que estão listados a seguir:
- public boolean isAnyLocalAddress()
- public boolean isLoopbackAddress()
- public boolean isLinkLocalAddress()
- public boolean isSiteLocalAddress()
- public boolean isMCGlobal()
- public boolean isMCNodeLocal()
- public boolean isMCLinkLocal()
- public boolean isMCSiteLocal()
- public boolean isMCOrgLocal()
Esses métodos são reponsáveis por determinar o escopo do IP em questão. Eles são úteis se for necessário uma verificação prévia do IP, principalmente IPv6, onde são criados endereços link-locais automaticamente.
Abaixo um exemplo de como adquirir um IP através de um hostname:
InetAddress address = InetAddress.getByName(“hostname”); System.out.println(address.getHostAddress); Neste caso o java irá buscar um IP retornado na consulta DNS . Porém ele irá retornar apenas um dos IPs disponíveis. Portanto se quisermos utilizar o Happy Eyeballs precisamos obter todos os IPs retornados pela consulta. Isso pode ser feito da seguinte forma: InetAddress[] addressArray = InetAddress.getAllByName(“hostname”); for (InetAddress address : addressArray) { System.out.println(address.getHostAddress); }
Dessa forma todos os IPs são armazenados no array addressArray.
Outra observacão importante é com relação aos Sockets, principalmente no quesito blocking/non-blocking. Apesar do java implementar a classe Socket (java.net.Socket), para utilizar sockets non-blocking devemos usar a classe SocketChannel (java.nio.channels.SocketChannel) e setar sua propriedade interna configureBlocking para false. A documentação oficial dos sockets pode ser encontrada em:
- http://docs.oracle.com/javase/1.4.2/docs/api/java/net/Socket.html
- http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/channels/SocketChannel.html
Abaixo um exemplo de como criar um socket simples para tentar se conectar a algum host:
Socket socket = new Socket(“hostname”, “porta”); socket.connect(); // Faz o que precisa com o socket socket.close();
Esse exemplo mostra dois pontos importantes. O primeiro é que neste caso os IPs são resolvidos de forma transparente, ou seja, em nenhum momento foi necessário definir um IP para se conectar ao host. O segundo ponto implica justamente no problema que isso pode gerar quando estamos lidando com IPv6, pois se o método connect do socket não implementar o Happy Eyeballs teremos o problema descrito neste artigo.
Então para o Happy Eyeballs funcionar no java temos de utilizar um IP para conectar ao socket:
InetAddress address = InetAddress.getByName(“hostname”); Socket socket = new Socket(address, “porta”); socket.connect(); // Faz o que precisa com o socket socket.close();
Porém, como já foi dito, a classe Socket não tem suporte a sockets non-blocking (diretamente). Para corrigir esse problema utilizamos a classe SocketChannel:
InetAddress address = InetAddress.getByName(“hostname”); SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(new InetSocketAddress(address, 80));
Desta forma será criado um socket non-blocking. Um detalhe muito importante a ser notado é que o programa continuará sua execução após a chamada do método connect, ou seja, ele não esperará a conexão ser estabelecida para continuar sua execução (pois o socket está configurado como non-blocking). Assim é necessário fazer uma verificação de conectividade antes de começar a trabalhar em cima do socket:
InetAddress address = InetAddress.getByName(“hostname”); SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); channel.connect(new InetSocketAddress(address, 80)); // Espera se conectar while (!channel.finishConnect()) { // Espera um tempo } // Faz o que precisa com o socket socket.close();
É extamente isso que queremos para o Happy Eyeballs, pois enquanto esperamos uma conexão ser realizada, podemos tentar se conectar aos demais IPs disponíveis. Mas ao mesmo tempo precisamos de um IPv6 e um IPv4. Para isso utilizamos o método InetAddress.getAllByName para obter tanto as entradas IPv6 quanto IPv4:
// Pega todos os IPs disponíveis para o hostname em específico InetAddress[] addressArray = InetAddress.getAllByName(“hostname”); for (InetAddress address : addressArray) { // Faz alguma coisa com o IP }
Como devemos tentar conectar primeiro a um IPv6, devemos distinguir quais IPs retornados são IPv6 e quais são IPv4. Para confirmar se o endereço é um IPv6 ou IPv4, utilizamos as classes Inet6Address e Inet4Address e fazemos uma comparação com instanceof:
// Pega todos os IPs disponíveis para o hostname em específico InetAddress[] addressArray = InetAddress.getAllByName(“hostname”); for (InetAddress address : addressArray) { if (address instanceof Inet6Address) { // O endereço é IPv6 } if (address instanceof Inet4Address) { // O endereço é IPv4 } }
php
O php não possui a função getaddrinfo, porém ele possui a função gethostbyname:
string gethostbyname ( string $hostname );
Além disso, ele também possui outra função chamada gethostbynamel:
array gethostbynamel ( string $hostname );
A diferença básica entre os dois é que na função gethostbyname é retornado apenas um único endereço IP. Já na funçao gethostbynamel é retornado um array contendo todos os endereços encontrados. Porém em ambos os casos só são retornados endereços IPv4. Mais informações sobre estas funções podem ser encontradas em:
- http://www.php.net/manual/en/function.gethostbyname.php
- http://www.php.net/manual/en/function.gethostbynamel.php
Por isso para obter todos os endereços IP, incluindo os endereços IPv6, devemos utilizar a funçãodns_get_record, que funciona como a função getaddrinfo:
array dns_get_record ( string $hostname [, int $type = DNS_ANY [, array &$authns [, array &$addtl ]]] );
Apesar de parecer complicada, para a implementação do Happy Eyeballs não é necessário adicionar muitos parâmetros a função, somente o tipo de consulta dns a ser feita, que são do tipo DNS_A (para endereços IPv4) e DNS_AAAA (para endereços IPv6):
$host = 'www.teste.com.br'; $Arecord = dns_get_record($host, DNS_A); $AAAArecord = dns_get_record($host, DNS_AAAA);
A função dns_get_record retorna um array com várias informações, porém apenas 2 nos interessam:
- type: pode ser de vários tipos, mas nos interessam apenas os tipo A e AAAA para poder identificar o que é IPv6 e o que é IPv4;
- ip ou ipv6: dado que vem atrelado ao type quando sua resposta é A ou AAAA. Dentro dele contém qual o IP retornado.
Mais informações sobre a função dns_get_record podem ser encontradas em:
Para se criar um socket em php, utiliza-se a função socket_create:
resource socket_create ( int $domain , int $type , int $protocol );
Note que todos os parâmetros de entradas são constantes de configuração pré definidas. O parâmetrodomain indica qual o protocolo do endreço utilizado (Address Family), podendo ser AF_INET no caso de IPv4 ou AF_INET6 no caso de IPv6. O parâmetro type indica o tipo de protocolo utilizado, que normalmente é do tipo SOCK_STREAM ou SOCK_RAW. O parâmetro protocol indica o tipo de protocolo IP a ser utilizado, comotcp, udp ou icmp. Abaixo temos um exemplo de como criar um socket:
$socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP);
Para se conectar a um host utilizando o socket é utilizado a função socket_connect:
bool socket_connect ( resource $socket , string $address [, int $port = 0 ] );
O parâmetro socket é o socket que foi criado na função socket_create. O parâmetro address é o endereço no qual queremos nos conectar. O parâmetro port é a porta na qual o socket irá se conectar. Abaixo utilizaremos o socket criado para se conectar a um IP:
$socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP); socket_connect($socket, ‘2001:12ff:0:4::6’, 80)
Para setar o socket php para non-blocking basta utilizar a função socket_set_nonblock:
bool socket_set_nonblock ( resource $socket );
Onde o parâmetro socket é o socket no qual queremos tornar non-blocking. Para voltar o socket a formablocking, utilizamos a função socket_set_block:
bool socket_set_block ( resource $socket );
Abaixo um exemplo de como utilizar um socket non-blocking:
$socket = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP); socket_set_nonblock($socket); while (!($connected = @socket_connect($socket,‘2001:12ff:0:4::6’, 80))) { // Faz alguma coisa } // Conectou-se ao servidor socket_set_block($socket);
Mais informações sobre sockets em php podem ser encontrados em:
- http://php.net/manual/en/book.sockets.php
- http://www.php.net/manual/en/function.socket-create.php
- http://www.php.net/manual/en/function.socket-connect.php
- http://www.php.net/manual/en/function.socket-set-block.php
- http://www.php.net/manual/en/function.socket-set-nonblock.php
python
Em python, tanto a consulta de DNS quanto as operações de sockets estão dentro da biblioteca socket. Além disso podemos verificar se o sistema utilizado possui suporte a IPv6, através da propriedade:
socket.has_ipv6
Para realizar consultas DNS, temos a função gethostbyname:
socket.gethostbyname(hostname)
Temos também uma versão mais detalhada, chamada gethostbyname_ex:
socket.gethostbyname_ex(hostname)
A diferença básica entre as duas funções são as informações retornadas. Enquanto na funçãogethostbyname é retornado apenas o endereço IP na forma de string, na função gethostbyname_ex também são retornados a lista de nomes e a lista de IPs disponíveis. No entando nenhuma das duas funções tem suporte a IPv6, portanto não servem para implementar o algoritmo do Happy Eyeballs.
Para realizar consultas DNS que incluem o IPv6, usamos a função getaddrinfo:
socket.getaddrinfo(host, port, family=0, socktype=0, proto=0, flags=0)
Seu funcionamento é o mesmo da linguagem C, portanto as constantes são as mesmas, com o detalhe de que essas constantes estão dentro da biblioteca socket do python. Um exemplo abaixo de como utilizar a função getaddrinfo:
socket.getaddrinfo(“ipv6.br", 80, socket.AF_INET6, socket.SOCK_STREAM, socket.SOL_TCP)
A função acima irá listar os IPv6 disponíveis para uma possível conexão tcp via stream socket na porta 80 do site ipv6.br. O retorno da função getaddrinfo é do tipo:
(family, socktype, proto, canonname, sockaddr)
Para o Happy Eyeballs precisamos apenas do campo sockaddr, que indicam o endereço IP, sendo do tipo(address, port) no caso do IPv4 (AF_INET) e (address, port, flow info, scope id) no caso do IPv6 (AF_INET6). Em ambos os casos utilizaremos apenas o campo address retornado, que é o que realmente precisamos. Veja o exemplo abaixo:
>>> socket.getaddrinfo("ipv6.br", 80, socket.AF_UNSPEC, socket.SOCK_STREAM, socket.SOL_TCP) [(10, 1, 6, '', ('2001:12ff:0:4::22', 80, 0, 0)), (2, 1, 6, '', ('200.160.4.22', 80))]
Nesse caso a consulta retorna tanto os endereços IPv4 quanto os endereços IPv6, pois o parâmetro family está setado como AF_UNSPEC, o que faz com que ele aceite qualquer tipo de protocolo como resposta. Mais informações sobre a função getaddrinfo podem ser encontradas em:
Para criar um socket em python basta utilizar a função socket da biblioteca socket:
socket.socket([family[, type[, proto]]])
Sua utilização é bem simples:
s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
Nesse caso o socket criado é atribuído a variável s. É importante observar que pela definição do socket, faltam duas informações essenciais: o endereço IP e a porta na qual tentaremos conectar. Esses parâmetros são indicados quando utilizamos a função connect:
socket.connect(address)
Para setar o socket como non-blocking basta setar sua propriedade setblocking(valor) para 0.
socket.setblocking(flag)
perl
O perl possui um problema grave com relação ao IPv6, pois sua biblioteca padrão de sockets (IO::Socket::INET) não possui suporte a IPv6. Além disso, o perl utiliza um sistema de módulos para serem adicionados e incorporados a ele, porém não existe uma padronização oficial para isso, o que leva a existirem vários módulos diferentes que implementam uma mesma funcionalidade. É o que acontece no caso do módulo que suporta sockets IPv6. Nesta artigo vamos apenas abordar o módulo indicado no próprio site do perl (http://www.perl.org/about/whitepapers/perl-ipv6.html), a nova biblioteca de sockets (IO::Socket::IP), que suporta tanto IPv4 quanto IPv6.
Javascript
Javascript é um caso especial, pois não é possível realizar consultas DNS diretamente utilizando apenas javascript. Uma solução possível é criar um servidor que faça a consulta em seu lugar e tentar se conectar segundo o algoritmo do Happy Eyeballs. Porém essa prática não é recomendada, pois além de necessitar fazer uma conexão extra fora do escopo, ele fica dependente dessa resposta, além de necessitar de um servidor exclusivo para isso.
Links Úteis
- Exemplo de Happy Eyeballs em C: http://www.ipv6forum.com/ipv6_enabled/DNS.php
- Explicações detalhadas sobre o funcionamento do Dual Stack: http://owend.corp.he.net/ipv6/
- Happy Eyeballs no squid: http://squidproxy.wordpress.com/2012/07/14/happy-eyeballs/
- Hampering Eyeballs: https://labs.ripe.net/Members/emileaben/hampered-eyeballs
- Comparação entre implementações do Happy Eyeballs: http://knowipv6.digitalelement.com/?p=66
- Entendendo o Happy Eyeballs: http://www.ipjforum.org/?p=378
Fonte: IPv6.br
Comentários
Postar um comentário