2012-07-18 3 views
9
struct hostent *gethostbyname(const char *name) 

Si noti che host.h_addr_list è un campo con lunghezza variante.In che modo `gethostbyname` restituisce` struct hostent * `senza richiedere al chiamante di rilasciare la risorsa?

In che modo la funzione gethostbyname ha l'implementazione che restituisce un puntatore che punta a una struttura ma non richiede che il chiamante rilasci la risorsa?

Tutti gli esempi utilizzati nel famoso libro Unix Network Programming Vol 1 di R. Stevens non contengono codice per rilasciare i puntatori restituiti e presumo che questi non siano ignoranza. Anche un esempio di MSDN fa la stessa cosa example of usage

+4

Questo è uno dei motivi per cui dovresti passare a 'getaddrinfo', che è la versione moderna di' gethostbyname'. Dopo aver chiamato 'getaddrinfo', devi' freeaddrinfo'. –

+0

Mi piace 'strerror'! – curiousguy

risposta

3

Supponendo che un'implementazione vuole per gestire arbitrariamente grandi liste di indirizzi, si potrebbe fare qualcosa di simile:

struct hostent *gethostbyname(const char *name) { 
    static struct hostent *results = 0; 
    static size_t resultsize = 0; 
    size_t count = get_count_of_addresses(name) 
    if (count > resultsize) { 
     struct hostent *tmp = realloc(results, N * count + M); 
     if (tmp) { 
      results = tmp; 
      resultsize = count; 
     } else { 
      // handle error, I can't remember what the docs say 
     } 
    } 
    fill_in_hostent(results, name); 
    return results; 
}; 

Opzionalmente, la prese biblioteca potrebbe fare qualcosa per liberare results in uscita (come ad esempio installare un Gestore atexit), per evitare il debug degli strumenti che riportano una perdita di memoria.

Ho ignorato la possibilità che il conteggio degli indirizzi possa cambiare tra il dimensionamento della struttura e il suo riempimento - in pratica si otterrebbe il risultato DNS e quindi si farebbe roba con esso, in modo che non sarebbe possibile. L'ho lasciato come due chiamate separate per evitare di introdurre una rappresentazione di pseudo-codice per il risultato DNS.

1

Probabilmente punta alla memoria statica, cioè è lo stesso puntatore per ogni chiamata.

3

Il man pagina si collega a vale la risposta:

Quando non nullo, il valore di ritorno può puntare a dati statici, vedere le note di seguito .

E poco dopo:

Il gethostbyname() e gethostbyaddr() può restituire i puntatori ai dati statici, che possono essere sovrascritti da chiamate successive.

1

E può indicare la memoria statica. Dovrai fare una copia approfondita di questo se vuoi conservare più risultati. Non una copia superficiale, perché quella struttura stessa contiene dei puntatori.

Fare attenzione alla sicurezza del filo.

+0

Come ho sottolineato nell'OP, il campo di h_add_list in struct hostent ha una lunghezza variante. Ciò significa che la struttura statica deve essere allocata abbastanza spazio per contenere potenziali lunghe liste di IP. – q0987

+0

Probabilmente è vero, ma nota la documentazione, e la mia risposta, diciamo "può" essere statica. Potrebbero esserci circostanze in cui la struttura viene creata dinamicamente per ospitare una lunghezza eccezionale, ma utilizza la memoria statica per casi e prestazioni tipici. –

0

MS ci dice che https://msdn.microsoft.com/en-us/library/windows/desktop/ms738524%28v=vs.85%29.aspx

The memory for the hostent structure returned by the 
gethostbyname function is allocated internally by the 
Winsock DLL from thread local storage. Only a single 
hostent structure is allocated and used, no matter how 
many times the gethostbyaddr or gethostbyname functions 
are called on the thread 

quindi sarebbe al sicuro su Windows thread, ma ...

E 'stato lasciato cadere da POSIX, e man7.org ci dice che su Linux il nome host locale non è thread-safe. http://man7.org/linux/man-pages/man3/gethostbyname.3.html

..e MS ci dice che

The gethostbyname function has been deprecated 
by the introduction of the getaddrinfo function 

Purtroppo, la sostituzione (getaddrinfo, thread-safe sulla maggior parte delle piattaforme) non faceva parte di prese 1.x, e non è disponibile su vecchie piattaforme.