2014-10-23 35 views
7

Sto lavorando a un progetto di rete C/C++ che dovrebbe essere in grado di utilizzare entrambi gli stack di rete IPv4 e IPv6. Il progetto funziona solo su Linux. Quindi, ho cercato di trovare un modo efficiente per archiviare gli indirizzi IP e differenziare le famiglie di protocolli. Il primo approccio è stato quello di avere un'unione:Modo efficiente per archiviare gli indirizzi IPv4/IPv6

struct ip_addr { 
    uint8_t fam; // socket family type 
    union { 
     struct in_addr ipv4_sin_addr; 
     struct in6_addr ipv6_sin_addr; 
    }addr; 
}; 

Il secondo approccio è stato quello di definire un typedef std::vector<unsigned char> IPAddressNumber e fare la differenza dopo il numero di byte dal vettore.

Il terzo approccio è stato quello di utilizzare int128_t/uint128_t o __int128_t da gcc.

Per quest'ultimo caso, vorrei sapere da quale versione di GCC questi tipi sono supportati, per i quali le piattaforme (soprattutto IA-32/IA-64) e anche se ci sono bug conosciuti. Inoltre, quale delle soluzioni di cui sopra potrebbe essere la più conveniente?

+1

Non sono sicuro che 'int128_t' sia necessario o adatto per indirizzi IPv6. Posix offre altri tipi nella sua API. Per GCC, utilizzare l'ultima versione (GCC 4.9.1 nell'ottobre 2014) e utilizzare C++ 11 se possibile. –

+2

Vorrei anche raccomandare di usare la struttura ['struct sockaddr_in6'] (http://man7.org/linux/man-pages/man7/ipv6.7.html) per gestire gli indirizzi IPv6. –

+0

Utilizzerai raramente gli indirizzi IP come numeri reali (inoltre dovranno essere forniti nell'ordine dei byte di rete). Quindi ancora: usare un 'uint128_t' per la rappresentazione di un indirizzo IPv6 è probabilmente una ** pessima idea **! –

risposta

3

Secondo this thread__int128_t e __uint128_t sono stati introdotti da qualche parte intorno alla versione 4.2. E secondo la documentazione di GCC __int128 e la sua controparte non firmata unsigned __int128 sono supportate dal GCC 4.6.4.

Si noti che un numero intero a 128 bit non importabile è sicuramente non il tipo appropriato per salvare e utilizzare indirizzi IPv6. Come menzionato nei commenti ci sono strutture dati speciali per questo, come sockaddr_in6.

+0

Bene, questa risposta per il supporto di interi a 128 bit, ma temo che non sia il tipo di dati giusto per la rappresentazione degli indirizzi IPv6: -/... –

+0

@ πάνταῥεῖ Ho aggiornato la risposta. Meglio? – Columbo

+0

Ho messo la mia risposta ora, come è stato consigliato così. Ma sì, sottolineando il problema Y migliora la tua risposta. –

9

Come indicato nel numero 1st answer, il supporto per numeri interi a 128 bit è disponibile dal GCC 4.6.4.

Il tuo problema non è di 128 supporto bit integer, ma come rappresentare un indirizzo IPv6 correttamente.
La risposta corretta per questo è utilizzare le definizioni struct disponibili da socket API.

Questi sono disponibili e standardizzati per varie implementazioni del sistema operativo dello stack IPv6.
Inoltre non è necessario preoccuparsi di efficienza utilizzando questi. L'imballo di allineamento funzionerà correttamente e non dovrai preoccuparti dei problemi di endianità e di ordine dei byte di rete della rappresentazione effettiva.


Per quanto riguarda le modifiche:

Non è necessario reinventare la ruota! Sono già disponibili le definizioni struct appropriate rispettando il tipo di famiglia AF_xxx correttamente.

Controllare queste risorse per spiegazioni più dettagliate:

Abbiamo una classe IpAddr in produzione, che utilizza le opache sockaddr_in* e sockaddr_in6* puntatori per incapsulare un indirizzo IPv4 o IPv6 basato su un puntatore sockaddr* e reinterpret_cast<> basato sul sa_family membro della struttura.

+0

In realtà ho visto un progetto open source (chromium) che utilizza una rappresentazione simile a quella menzionata da te: utilizza una struttura chiamata SockaddrStorage [1] e una classe denominata IPEndPoint che funziona con questa struttura. Il problema con questa struttura è che è utile quando si ha anche una porta o si intende creare un socket (ad esempio: bind, connettere le chiamate) e non solo per memorizzare l'ip. [1] http://goo.gl/hSyW8o – evelina

+0

Ho bisogno di un modo interno per memorizzare l'ip dopo averlo convertito da una rappresentazione di stringa (ad esempio da una bandiera o una variabile di ambiente). Trovo più utile la rappresentazione con struct ip_addr perché è più conveniente per le chiamate come inet_ntop/inet_pton Non è possibile utilizzare sockaddr (solo e non come puntatore) perché il campo sa_data non è abbastanza grande per memorizzare un indirizzo IPv6 . – evelina

+0

@evelina _ "Ho bisogno di un modo interno per memorizzare l'ip dopo averlo convertito da una rappresentazione di stringa (ad esempio da una bandiera o da una variabile di ambiente)." _ Beh, non capisco, cosa stai realmente preoccupando di _efficienza_. Le strutture menzionate rappresenteranno bene i tipi dipendenti dal protocollo IP. –