2012-07-12 40 views
7

Estoy portar una aplicaciónIPv4 a una base de código AF-independiente (que debería funcionar con IPv4 e IPv6). Ahora estoy usando sockaddr_storage donde puedo, sin embargo ahora tengo que configurar (poblar) un sockaddr_storage. Pero no sé cuál es la forma correcta. El código anterior era:Definición de la dirección IPv4/IPv6 y el puerto a una estructura sockaddr_storage

// defined in data_socket.h 
struct sockaddr_in laddr; 

Ahora hay esta función que establece sin_addr y sin_port:

void DataSocket::SetLocalAddr(const char *addr, const int port) 
{ 
    this->laddr.sin_port = htons(port); 
    if(addr != NULL) 
     this->laddr.sin_addr.s_addr = inet_addr(addr); 
    else 
     this->laddr.sin_addr.s_addr = inet_addr("0.0.0.0"); 
} 

Como se ve es el viejo estilo (utiliza IPv4).

Ahora mis cambios están por debajo. En primer lugar he cambiado sockaddr_in a sockaddr_storage

// defined in data_socket.h 
struct sockaddr_storage laddr; 

Luego cambié el código anterior para apoyar IPv4 y IPv6:

void DataSocket::SetLocalAddr(const char *addr, const int port) 
{ 
switch (this->GetAddrFamily(addr)) { 
    case AF_INET: 
     (struct sockaddr_in *) this->laddr.sin_port = htons(port); 
     if(addr != NULL) 
      inet_pton(AF_INET, addr, (struct sockaddr_in *) this->laddr.sin_addr); 
     else 
      inet_pton(AF_INET, "0.0.0.0", (struct sockaddr_in *) this->laddr.sin_addr); 
     break; 

    case AF_INET6: 
     (struct sockaddr_in6 *) this->laddr.sin6_port = htons(port); 
     if(addr != NULL) 
      inet_pton(AF_INET6, addr, (struct sockaddr_in6 *) this->laddr.sin6_addr); 
     else 
      inet_pton(AF_INET6, "0:0:0:0:0:0:0:0", (struct sockaddr_in6 *) this->laddr.sin6_addr); 
     break; 

    default: 
     return NULL; 

} 

}

Donde es GetAddrFamily() :

int DataSocket::GetAddrFamily(const char *addr) 
{ 
    struct addrinfo hints, *res; 
    int status, result; 

    memset(&hints, 0, sizeof(hints)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 

    if ((status = getaddrinfo(addr, 0, &hints, &res)) != 0) 
    { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); 
     return false; 
    } 

    result = res->ai_family; // This might be AF_INET, AF_INET6,etc.. 
    freeaddrinfo(res); // We're done with res, free it up 

    return result; 
} 

Parece que mi camino es complejo. ¿Es esta la forma correcta de hacer esto? Debido a que he cambiado sockaddr_in a sockaddr_storage, en realidad sólo quiero el reverso de esta pregunta: Getting IPV4 address from a sockaddr structure

Estoy tratando de encontrar la mejor solución, por ejemplo aquí: http://www.kame.net/newsletter/19980604/ nunca dice que el uso inet_ntop() y inet_pton(), sin embargo algunos otros (como el tutorial de red de Beej) dice que inet_ntop() y inet_pton() se deben usar para la aplicación basada en IPv6.

¿Mi forma de implementación es correcta o debería cambiarla?

+1

Esta es una razón por la que me gusta 'boost :: asio :: ip :: address', abstrae' boost :: asio :: ip :: address_v4' y 'boost :: asio :: ip :: address_v6'. – Chad

+1

Avíseme cuando C obtenga funciones de miembro. – Puppy

+0

@DeadMG uy disculpe por la etiqueta 'c' –

Respuesta

5

Recomiendo encarecidamente dejar que getaddrinfo haga todo el trabajo pesado, ej.

+0

Gracias por el código. Pero estoy confundido con la línea 'memcpy (& this-> laddr, res-> ai_addr, res-> ai_addrlen);'. El 'res-> ai_addr' es una estructura sockaddr, ¿supongo que se convierte automáticamente en' sockaddr_in' o 'sockaddr_in6'? ¿Cómo se almacena en 'this-> laddr' (porque' this-> laddr' es una estructura 'sockaddr_storage')? –

+0

Y supongo que debería usar 'port_buffer' en lugar de' port' en 'getaddrinfo', porque' getaddrinfo() 'exceptó un const char * (aka string)? –

+1

'res-> ai_addr' apunta a alguna variante de' struct sockaddr', ya sea 'sockaddr_in' o' sockaddr_in6'. No hay conversión, la estructura simplemente se copia como está. 'struct sockaddr_storage' es de un tamaño y diseño que permite su conversión a cualquiera de las variantes' sockaddr', que comparten un encabezado común. re: pasando una cadena como el puerto, no me molestaría, pero es tu código. (también, error ortográfico fijo, getaddrinfo estaba destinado a ser el buffer) – Hasturkun

1

Si entiendo correctamente, estás lanzando this al primer miembro? no hagas eso, nombra al miembro.

Me gustaría también que sea más fácil de leer mediante la introducción de un endoscopio {} y una variable local para los dos casos, algo así como:

{ 
struct sockaddr_in * in4 = reinterpret_cast< struct sockaddr_in * >(&this->addr); 
in4->laddr.sin_port = htons(port); 
... etc 
} 

Un dado que está utilizando C++ y no en C para eso, el uso Moldes de estilo C++. Los moldes de estilo C en C++ son muy ambiguos.

Cuestiones relacionadas