Error de WSAStringToAddress

Estoy tratando de llenar una estructura sockaddr_in desde una dirección de cadena IPv4 usando el siguiente código C++:

// WSAStringToAddress
struct sockaddr_in sock;

int addrSize = sizeof( struct sockaddr_in );

memset( &sock, 0, addrSize );

sock.sin_family = AF_INET;

rc = WSAStringToAddress( (LPWSTR) "192.168.0.1", 
                         AF_INET, 
                         NULL, 
                        (LPSOCKADDR) &sock, 
                        &addrSize ); 

if ( rc != 0 )
{
    rc = WSAGetLastError();

    printf( "WSAStringToAddress: error=[%d]\n", rc );
}

Está fallando con el código de error 10022, que es WSAEINVAL. Sobre http://msdn.microsoft.com/en-us/library/windows/desktop/ms742214%28v=vs.85%29.aspx indica que este código de error ocurre cuando la familia de direcciones de sockaddr_in no está configurada en AF_INET o AF_INET6, lo cual claramente he hecho.

Estoy ejecutando Visual C++ 2008 Express Edition en Windows Server 2008 R2 SP1, pero no estoy usando las funciones de conversión de direcciones más nuevas porque necesito compatibilidad con versiones anteriores de Windows XP/Windows Server 2000 en adelante.

¿Alguien sabe cómo resolver este problema/qué está mal con mi código? Cualquier solución que pueda dar es apreciada: D

EDITAR: descubrí que usar WSAStringToAddressA permitía el uso de caracteres ASCII en lugar de tchar

preguntado el 27 de julio de 12 a las 20:07

Según su descubrimiento reciente, sí, cada vez que una función de la API de Win32 trate con cadenas, habrá una versión ANSI (estrecha) y una versión ancha (Unicode). La versión ANSI tiene un A sufijo y la versión Unicode tiene un W sufijo (para ancho). Pero deberías siempre llamar a la versión Unicode de la función. Windows ha sido completamente Unicode durante más de una década. El material de ANSI es obsoleto desde hace mucho tiempo y solo está allí por razones de compatibilidad con versiones anteriores. Internamente, las versiones ANSI de las funciones convierten la cadena a Unicode y luego llaman a la versión Unicode. -

Por lo tanto, básicamente no tiene sentido llamarlos, especialmente cuando se trata de un literal de cadena que se puede convertir fácilmente en un literal de cadena ancho prefijándolo con un L (o usando el TEXT macro, que maneja esto automáticamente). Cualquiera de los dos es lo que debes siempre hacer. Olvídese del hecho de que incluso existen cadenas de caracteres estrechas. char* no es lo que usará para las cadenas de estilo C al programar Windows, siempre será wchar_t*. -

Esta es también una buena lección de por qué nunca debes lanzar moldes solo para cerrar el compilador. El compilador le está dando un error por una razón y está tratando de ayudarlo a corregir su código. Al ignorarlo y convertir el valor en su lugar, está activando efectivamente el interruptor de anulación para decirle al compilador "Sé lo que estoy haciendo, cállate ya". Eso es una tragedia, porque el compilador está ahí para ayudarte como programador. Si encuentra un error, es probable que su código sea incorrecto. Y lanzar un molde no hará que su código sea correcto, solo pospondrá el error del tiempo de compilación al tiempo de ejecución. -

@CodyGray Gracias por sus comentarios. Otra razón por la que quería forzar el uso de char * es para mi aplicación, también tengo soporte para Linux y quería una función para ambos. Dado que tchar no está disponible en Linux, char parecía ser el camino a seguir... La compatibilidad con versiones anteriores también es una preocupación para mí. Internamente, tengo un #ifdef _WIN32 para el caso de WSA y uso otras funciones para Linux, pero ambos toman char * y funcionan correctamente, así que estoy feliz: D Si no fuera por el soporte multiplataforma y la compatibilidad con versiones anteriores, yo Estaría usando la versión UNICODE. -

3 Respuestas

WSAStringToAddress() falla con WSAEINVAL cuando no puede traducir la dirección solicitada. Un valor familiar no coincidente no es la única forma en que un WSAEINVAL puede ocurrir un error. Como dijo @ChristianStieber, está utilizando un tipo de conversión para pasar un 8-bit char[] cadena literal donde un 16 bits wchar_t* se espera el puntero. Eso es simplemente incorrecto. Estás pasando basura a WSAStringToAddress(), y lo está detectando.

Necesitas usar el TEXT() macro en su lugar al pasar un literal de cadena a un LPTSTR valor, por ejemplo:

rc = WSAStringToAddress( TEXT("192.168.0.1"), ... );

De lo contrario, llame a la versión Unicode de WSAStringToAddress() directamente, y poner un L prefijo delante del literal de cadena para convertirlo en un wchar_t[] en lugar de un char[], p.ej:

rc = WSAStringToAddressW( L"192.168.0.1", ... );

Respondido 27 Jul 12, 20:07

TEXTO () funcionó, y cambiar la respuesta correcta a la suya ya que es más extensa. - weedwacker44

Ahora, en 2015, WSAStringToAddress está en desuso, por lo que está atascado con L"...". - Alex

¿Dónde dice MSDN que WSAStringToAddressA() ¿es obsoleto? En todo caso, getaddrinfo() se suele preferir hoy en día, y es más portátil con otras plataformas. - Rémy Lebeau

Los ejemplos que he visto en línea establecen addrSize en sizeof (struct sockaddr_storage).

Hay un ejemplo en este enlace.

Respondido 27 Jul 12, 20:07

sockaddr_storage se utiliza para el código que admite tanto IPv4 como IPv6. Este código de ejemplo solo es compatible con IPv4, por lo que sockaddr_in es apropiado para usar. - Rémy Lebeau

En mi opinión, este comentario no dice que sea la única razón posible de este error.

En particular, esta línea me llama la atención:

(LPWSTR) "192.168.0.1",

Estás tomando una cadena de 8 bits y simplemente transfiriéndola a la versión ancha. ¿Intentaste usar L"192...."?

Respondido 27 Jul 12, 20:07

De hecho, simplemente NO puede emitir nada y también omitir la "L", que luego llamará a la versión "ANSI" de la función. No me gustan demasiado, ya que depende de la página de códigos, y no sé si todas las páginas de códigos están basadas en ASCII... - Christian Stieber

Intenté sin convertir como había visto en otros ejemplos... pero obtengo un error de tiempo de compilación: error C2664: 'WSAStringToAddressW': no ​​puedo convertir el parámetro 1 de 'const char [17]' a 'LPWSTR', así que mientras tanto Solo lo lanzaré, ya que parece estar funcionando... - weedwacker44

Ah, OK. En ese caso probablemente estaba confundido, ya que otra cosa que no uso es la selección automática de functionW() vs. functionA(). Supongo que está compilando con el conjunto "UNICODE", lo cual es algo bueno y debe mantenerse :-) Sin embargo, aún puede quitar el yeso y conservar la L. La transmisión siempre tiene una mala sensación como "el compilador me da un error aquí, así que lo descarto"; siempre es mejor NO transmitir y simplemente hacer lo correcto en su lugar :-) - Christian Stieber

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.