2009-12-23 15 views
19

Sto lavorando su una porta Windows di un programma POSIX C++.È sicuro trasmettere SOCKET a int con Win64?

Il problema è che le funzioni POSIX standard come accept() o bind() prevedono un 'int' come primo parametro mentre le sue controparti WinSock usano 'SOCKET'.
Quando compilato per 32bit tutto va bene, perché entrambi sono a 32 bit, ma sotto Win64 presa è a 64 bit e int rimane a 32 bit e genera un sacco di compilatore di avviso come questo:

warning C4244: '=' : conversion from 'SOCKET' to 'int', possible loss of data

ho provato per aggirare il problema utilizzando un typedef:


#ifdef _WIN32 
typedef SOCKET sock_t; 
#else 
typedef int sock_t; 
#endif 

e sostituendo int di con sock_t nei luoghi appropriati.

Questo andava bene fino a quando non ho raggiunto una parte del codice che chiama API OpenSSL.
Come si è scoperto OpenSSL utilizza inte per socket anche su Win64. Che sembrava davvero strano, così ho iniziato la ricerca di una risposta, ma l'unica cosa che ho trovato è stato un vecchio post sulla mailing list openssl-dev, che riferisce a un commento e_os.h:


/* 
* Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because 
* the value constitutes an index in per-process table of limited size 
* and not a real pointer. 
*/ 

Quindi la mia domanda è :
è davvero sicuro trasmettere SOCKET a int?

Mi piacerebbe vedere una sorta di documentazione che dimostra che i valori per SOCKET non possono essere maggiori di 2^32.

Grazie in anticipo!
Ryck

+0

+1: Ho lo stesso problema ** ** LA SOCIETÀ ... – paercebal

risposta

10

Questo post sembra dal di essere ripetendo le informazioni sulla kernel objects a MSDN:

maniglie degli oggetti del kernel sono processo specifico. Cioè, un processo deve creare l'oggetto o aprire un oggetto esistente per ottenere un handle dell'oggetto kernel. Il limite per processo sugli handle del kernel è 2^24.

Il thread continua a citare Windows Internals by Russinovich and Solomon come origine per i bit alti pari a zero.

+0

Grazie Pete! Questo è esattamente quello che stavo cercando. Ecco un post pertinente sul blog di Mark Russinovich: http://blogs.technet.com/markrussinovich/archive/2009/09/29/3283844.aspx – Ryck

+0

+1 per i collegamenti multipli – paercebal

+1

Questo è tutto sbagliato. Prima di tutto, un limite di 2^24 handle del kernel _non_ implica che le maniglie abbiano valori nell'intervallo [0, 2^24-1]. In secondo luogo, il numero di handle del kernel è un dettaglio di implementazione interno che è soggetto a modifiche in qualsiasi momento (quindi il titolo "Windows _Internals_"). –

0
/* 
* Even though sizeof(SOCKET) is 8, it's safe to cast it to int, because 
* the value constitutes an index in per-process table of limited size 
* and not a real pointer. 
*/ 

Questo commento è corretta. SOCKET = Gestione file su serie Windows NT. Non ho mai visto una serie 9x a 64 bit, quindi non dovrebbe esserci nulla di cui preoccuparsi.

3

La semplice risposta a questa domanda è no. Dai un'occhiata alla descrizione dei valori SOCKET su MSDN [1]:

Gli handle di Windows Sockets non hanno restrizioni, a parte il fatto che il valore INVALID_SOCKET non è un socket valido. Gli handle di socket possono assumere qualsiasi valore compreso tra 0 e INVALID_SOCKET-1.

Così chiaramente, l'API consente tutti i valori nell'intervallo [0, 2^64 - 1) su Windows a 64 bit. E se l'API ha mai restituito un valore superiore a 2^32 - 1, assegnarlo a un int risulterebbe nel troncamento dell'handle.Date anche un'occhiata alla descrizione del valore restituito dalla funzione socket() [2]:

Se non si verifica alcun errore, socket restituisce un descrittore che fa riferimento al nuovo socket.

noti che ne hanno più enfaticamente non promette per restituire un handle del kernel. Ciò rende discutibile qualsiasi possibile valore per i manici del kernel.

Tutto ciò che viene detto, al momento della scrittura, la funzione socket() restituisce effettivamente un handle del kernel (o qualcosa di indistinguibile da un handle del kernel) [3] e gli handle del kernel sono veramente limitati a 32-bit [4] . Ma tieni presente che Microsoft potrebbe cambiare una di queste cose domani senza rompere i loro contratti di interfaccia.

Tuttavia, dal momento che un numero indubbiamente elevato di applicazioni ha preso una dipendenza da questi particolari particolari di implementazione (e, cosa ancora più importante, ha anche OpenSSL), Microsoft probabilmente ci penserebbe due volte su come apportare eventuali modifiche. Quindi vai avanti e lancia un SOCKET a un int. Basta tenere a mente che questa è una pratica pericolosa, intrinsecamente pericolosa, e non è mai giustificabile in nome dell'opportunità.

  1. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740516(v=vs.85).aspx
  2. http://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx
  3. http://msdn.microsoft.com/en-us/library/windows/desktop/ms742295(v=vs.85).aspx
  4. http://msdn.microsoft.com/en-us/library/windows/desktop/aa384267(v=vs.85).aspx

Edit (2018-01-29)

Dal momento che questo argomento sembra ancora essere di un certo interesse, vale la pena sottolineare che io t è abbastanza facile da scrivere codice prese portatile in C++ 11 senza ricorrere a discutibili tipo getta:

using socket_t = decltype(socket(0, 0, 0)); 

socket_t s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
Problemi correlati