2009-12-23 18 views
19

Estoy trabajando en un puerto de Windows de un programa POSIX C++.¿Es seguro convertir SOCKET a int bajo Win64?

El problema es que las funciones POSIX estándar como aceptar() o bind() esperar un ‘int’ como primer parámetro, mientras que sus contrapartes de WinSock utilizan ‘SOCKET’.
Cuando compilado para 32 bits que todo está bien, porque ambos son de 32 bits, pero bajo Win64 socket es de 64 bits y 32 bits int permanece y se genera una gran cantidad de Advertencia del compilador de esta manera:

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

Probé para evitar el problema mediante el uso de un typedef:


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

y sustitución de 'int con sock_t en los lugares apropiados.

Esto estaba bien hasta que llegué a una parte del código que llama a las API de OpenSSL.
Como se vio, OpenSSL utiliza entradas para conectores incluso en Win64. Eso pareció muy extraño, por lo que comenzó a buscar una respuesta, pero lo único que encontré fue un antiguo puesto en la lista de correo openssl-dev, que refirió a un comentario 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. 
*/ 

Así que mi pregunta es :
¿es realmente seguro convertir SOCKET a int?

me gustaría ver algún tipo de documentación que demuestra que los valores de socket no puede ser mayor que 2^32.

¡Gracias de antemano!
Ryck

+0

+1: Tengo el mismo problema ** ** YA ... – paercebal

Respuesta

10

Esto parece post por el estar repitiendo la información sobre kernel objects en MSDN:

mangos son objeto de núcleo proceso específico. Es decir, un proceso debe crear el objeto o abrir un objeto existente para obtener un identificador de objeto kernel. El límite por proceso en los controladores del kernel es 2^24.

El hilo continúa citando Windows Internals by Russinovich and Solomon como una fuente para que los bits altos sean cero.

+0

Gracias Pete! Eso es exactamente lo que estaba buscando. Aquí hay una publicación relevante en el blog de Mark Russinovich: http://blogs.technet.com/markrussinovich/archive/2009/09/29/3283844.aspx – Ryck

+0

+1 para los enlaces múltiples – paercebal

+1

Esto es todo tipo de error. En primer lugar, un límite de 2^24 manipuladores del kernel _no implica que los identificadores tengan valores en el rango [0, 2^24-1]. En segundo lugar, la cantidad de identificadores de kernel es un detalle de implementación interna que está sujeta a cambios en cualquier momento (por lo tanto, el título "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. 
*/ 

Este comentario es correcto. SOCKET = Controlador de archivo en la serie Windows NT. Nunca había visto una serie de 9x de 64 bits, así que no debería haber nada de qué preocuparse.

3

La respuesta simple a esta pregunta es no. Echar un vistazo a la descripción de los valores zócalo en MSDN [1]:

manijas de Windows Sockets no tienen restricciones, excepto que el valor INVALID_SOCKET no es un socket válido. Las asas de toma pueden tomar cualquier valor en el rango de 0 a INVALID_SOCKET-1.

Así que, claramente, la API permite todos los valores en el rango [0, 2^64 - 1) en Windows de 64 bits. Y si la API alguna vez devolviera un valor mayor que 2^32 - 1, asignarlo a un int generaría un truncamiento del manejador.También eche un vistazo a la descripción del valor de retorno de la función socket() [2]:

Si no se produce ningún error, el socket devuelve un descriptor que hace referencia al nuevo socket.

Aviso de que la mayor parte enfáticamente no se compromete a devolver un identificador de núcleo. Esto hace que cualquier discusión sobre los posibles valores para los manejadores del kernel sea irrelevante.

Dicho todo esto, al escribir esto, la función socket() devuelve realmente un manejador de núcleo (o algo indistinguible de un manejador de kernel) [3] y los manejadores de kernel están realmente limitados a 32 bits [4] . Pero tenga en cuenta que Microsoft podría cambiar cualquiera de estas cosas mañana sin romper sus contratos de interfaz.

Sin embargo, dado que un número sin duda de aplicaciones ha dependido de estos detalles de implementación particulares (y más importante, también lo ha hecho OpenSSL), Microsoft probablemente lo pensaría dos veces antes de realizar cambios importantes. Así que adelante y lanza un SOCKET a un int. Solo tenga en cuenta que esta es una mala práctica intrínsecamente peligrosa, y nunca es justificable en nombre de la conveniencia.

  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

Editar (2018-01-29)

Desde este tema todavía parece ser de algún interés, vale la pena señalar que yo t es bastante fácil de escribir código zócalos portátiles en C++ 11 sin tener que recurrir a tipo cuestionable yesos:

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

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