[WININET]
[reactos.git] / reactos / dll / win32 / wininet / utility.c
index b0d9c9c..66fbecd 100644 (file)
 #include "config.h"
 #include "wine/port.h"
 
 #include "config.h"
 #include "wine/port.h"
 
+#if defined(__MINGW32__) || defined (_MSC_VER)
+#include <ws2tcpip.h>
+#endif
+
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
@@ -40,6 +44,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
 
+#ifndef HAVE_GETADDRINFO
+
 /* critical section to protect non-reentrant gethostbyname() */
 static CRITICAL_SECTION cs_gethostbyname;
 static CRITICAL_SECTION_DEBUG critsect_debug =
 /* critical section to protect non-reentrant gethostbyname() */
 static CRITICAL_SECTION cs_gethostbyname;
 static CRITICAL_SECTION_DEBUG critsect_debug =
@@ -50,6 +56,8 @@ static CRITICAL_SECTION_DEBUG critsect_debug =
 };
 static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 };
 
 };
 static CRITICAL_SECTION cs_gethostbyname = { &critsect_debug, -1, 0, 0, 0, 0 };
 
+#endif
+
 #define TIME_STRING_LEN  30
 
 time_t ConvertTimeString(LPCWSTR asctime)
 #define TIME_STRING_LEN  30
 
 time_t ConvertTimeString(LPCWSTR asctime)
@@ -137,12 +145,18 @@ time_t ConvertTimeString(LPCWSTR asctime)
 
 
 BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
 
 
 BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
-       struct sockaddr_in *psa)
+       struct sockaddr *psa, socklen_t *sa_len)
 {
     WCHAR *found;
     char *name;
     int len, sz;
 {
     WCHAR *found;
     char *name;
     int len, sz;
+#ifdef HAVE_GETADDRINFO
+    struct addrinfo *res, hints;
+    int ret;
+#else
     struct hostent *phe;
     struct hostent *phe;
+    struct sockaddr_in *sin = (struct sockaddr_in *)psa;
+#endif
 
     TRACE("%s\n", debugstr_w(lpszServerName));
 
 
     TRACE("%s\n", debugstr_w(lpszServerName));
 
@@ -158,27 +172,75 @@ BOOL GetAddress(LPCWSTR lpszServerName, INTERNET_PORT nServerPort,
         len = strlenW(lpszServerName);
 
     sz = WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, NULL, 0, NULL, NULL );
         len = strlenW(lpszServerName);
 
     sz = WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, NULL, 0, NULL, NULL );
-    name = HeapAlloc(GetProcessHeap(), 0, sz+1);
+    if (!(name = HeapAlloc( GetProcessHeap(), 0, sz + 1 ))) return FALSE;
     WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, name, sz, NULL, NULL );
     name[sz] = 0;
 
     WideCharToMultiByte( CP_UNIXCP, 0, lpszServerName, len, name, sz, NULL, NULL );
     name[sz] = 0;
 
+#ifdef HAVE_GETADDRINFO
+    memset( &hints, 0, sizeof(struct addrinfo) );
+    /* Prefer IPv4 to IPv6 addresses, since some servers do not listen on
+     * their IPv6 addresses even though they have IPv6 addresses in the DNS.
+     */
+    hints.ai_family = AF_INET;
+
+    ret = getaddrinfo( name, NULL, &hints, &res );
+    HeapFree( GetProcessHeap(), 0, name );
+    if (ret != 0)
+    {
+        TRACE("failed to get IPv4 address of %s (%s), retrying with IPv6\n", debugstr_w(lpszServerName), gai_strerror(ret));
+        hints.ai_family = AF_INET6;
+        ret = getaddrinfo( name, NULL, &hints, &res );
+        if (ret != 0)
+        {
+            TRACE("failed to get address of %s (%s)\n", debugstr_w(lpszServerName), gai_strerror(ret));
+            return FALSE;
+        }
+    }
+    if (*sa_len < res->ai_addrlen)
+    {
+        WARN("address too small\n");
+        freeaddrinfo( res );
+        return FALSE;
+    }
+    *sa_len = res->ai_addrlen;
+    memcpy( psa, res->ai_addr, res->ai_addrlen );
+    /* Copy port */
+    switch (res->ai_family)
+    {
+    case AF_INET:
+        ((struct sockaddr_in *)psa)->sin_port = htons(nServerPort);
+        break;
+    case AF_INET6:
+        ((struct sockaddr_in6 *)psa)->sin6_port = htons(nServerPort);
+        break;
+    }
+
+    freeaddrinfo( res );
+#else
     EnterCriticalSection( &cs_gethostbyname );
     phe = gethostbyname(name);
     HeapFree( GetProcessHeap(), 0, name );
 
     if (NULL == phe)
     {
     EnterCriticalSection( &cs_gethostbyname );
     phe = gethostbyname(name);
     HeapFree( GetProcessHeap(), 0, name );
 
     if (NULL == phe)
     {
-        TRACE("Failed to get hostname: (%s)\n", debugstr_w(lpszServerName) );
+        TRACE("failed to get address of %s (%d)\n", debugstr_w(lpszServerName), h_errno);
         LeaveCriticalSection( &cs_gethostbyname );
         return FALSE;
     }
         LeaveCriticalSection( &cs_gethostbyname );
         return FALSE;
     }
-
-    memset(psa,0,sizeof(struct sockaddr_in));
-    memcpy((char *)&psa->sin_addr, phe->h_addr, phe->h_length);
-    psa->sin_family = phe->h_addrtype;
-    psa->sin_port = htons(nServerPort);
+    if (*sa_len < sizeof(struct sockaddr_in))
+    {
+        WARN("address too small\n");
+        LeaveCriticalSection( &cs_gethostbyname );
+        return FALSE;
+    }
+    *sa_len = sizeof(struct sockaddr_in);
+    memset(sin,0,sizeof(struct sockaddr_in));
+    memcpy((char *)&sin->sin_addr, phe->h_addr, phe->h_length);
+    sin->sin_family = phe->h_addrtype;
+    sin->sin_port = htons(nServerPort);
 
     LeaveCriticalSection( &cs_gethostbyname );
 
     LeaveCriticalSection( &cs_gethostbyname );
+#endif
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -224,7 +286,7 @@ static const char *get_callback_name(DWORD dwInternetStatus) {
     return "Unknown";
 }
 
     return "Unknown";
 }
 
-VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext,
+VOID INTERNET_SendCallback(object_header_t *hdr, DWORD_PTR dwContext,
                            DWORD dwInternetStatus, LPVOID lpvStatusInfo,
                            DWORD dwStatusInfoLength)
 {
                            DWORD dwInternetStatus, LPVOID lpvStatusInfo,
                            DWORD dwStatusInfoLength)
 {
@@ -244,11 +306,11 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext,
         case INTERNET_STATUS_NAME_RESOLVED:
         case INTERNET_STATUS_CONNECTING_TO_SERVER:
         case INTERNET_STATUS_CONNECTED_TO_SERVER:
         case INTERNET_STATUS_NAME_RESOLVED:
         case INTERNET_STATUS_CONNECTING_TO_SERVER:
         case INTERNET_STATUS_CONNECTED_TO_SERVER:
-            lpvNewInfo = WININET_strdup_AtoW(lpvStatusInfo);
+            lpvNewInfo = heap_strdupAtoW(lpvStatusInfo);
             break;
         case INTERNET_STATUS_RESOLVING_NAME:
         case INTERNET_STATUS_REDIRECT:
             break;
         case INTERNET_STATUS_RESOLVING_NAME:
         case INTERNET_STATUS_REDIRECT:
-            lpvNewInfo = WININET_strdupW(lpvStatusInfo);
+            lpvNewInfo = heap_strdupW(lpvStatusInfo);
             break;
         }
     }else {
             break;
         }
     }else {
@@ -262,7 +324,7 @@ VOID INTERNET_SendCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext,
             break;
         case INTERNET_STATUS_RESOLVING_NAME:
         case INTERNET_STATUS_REDIRECT:
             break;
         case INTERNET_STATUS_RESOLVING_NAME:
         case INTERNET_STATUS_REDIRECT:
-            lpvNewInfo = WININET_strdup_WtoA(lpvStatusInfo);
+            lpvNewInfo = heap_strdupWtoA(lpvStatusInfo);
             break;
         }
     }
             break;
         }
     }
@@ -294,7 +356,7 @@ static void SendAsyncCallbackProc(WORKREQUEST *workRequest)
     HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo);
 }
 
     HeapFree(GetProcessHeap(), 0, req->lpvStatusInfo);
 }
 
-VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext,
+void SendAsyncCallback(object_header_t *hdr, DWORD_PTR dwContext,
                        DWORD dwInternetStatus, LPVOID lpvStatusInfo,
                        DWORD dwStatusInfoLength)
 {
                        DWORD dwInternetStatus, LPVOID lpvStatusInfo,
                        DWORD dwStatusInfoLength)
 {