diff --git a/src/net/win32/socket_helper.c b/src/net/common/socket_helper_cmn.cpp similarity index 61% rename from src/net/win32/socket_helper.c rename to src/net/common/socket_helper_cmn.cpp index 65501732..b582128c 100644 --- a/src/net/win32/socket_helper.c +++ b/src/net/common/socket_helper_cmn.cpp @@ -16,22 +16,42 @@ * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#ifndef _WIN32 -#error This source code is Win32 only. -#endif -#include "socket_helper.h" +#include +#include + +using namespace std; bool -socket_string_to_addr(const char *str, int addrFamily, struct sockaddr * addr, int addrLen) -{ - // TODO: convert str from UTF-8 to UTF-16 (Win32 byte order) - //return (WSAStringToAddress((wchar_t *)str, addrFamily, NULL, addr, &addrLen) != SOCKET_ERROR); -} - -bool -socket_resolve(const char *str, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen) +internal_socket_resolve(const char *str, const char *port, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen) { + bool retVal = false; + + if (str && *str != 0) + { + struct addrinfo aiHints; + struct addrinfo *aiList = NULL; + + memset(&aiHints, 0, sizeof(aiHints)); + aiHints.ai_family = addrFamily; + aiHints.ai_socktype = sockType; + aiHints.ai_protocol = protocol; + + // Try to resolve the name. + // Will (hopefully) use UTF-8 if called on Linux. + bool success = (getaddrinfo(str, port, &aiHints, &aiList) == 0); + + if (success && aiList) + { + if ((int)aiList->ai_addrlen <= addrLen) + { + memcpy(addr, aiList->ai_addr, aiList->ai_addrlen); + retVal = true; + } + freeaddrinfo(aiList); + } + } + return retVal; } diff --git a/src/net/genericsocket.h b/src/net/genericsocket.h index 390b6056..873842ac 100644 --- a/src/net/genericsocket.h +++ b/src/net/genericsocket.h @@ -23,6 +23,7 @@ #ifdef _WIN32 #include #include +#include #else #include #include diff --git a/src/net/linux/socket_helper.c b/src/net/linux/socket_helper.cpp similarity index 87% rename from src/net/linux/socket_helper.c rename to src/net/linux/socket_helper.cpp index c1a90135..317df944 100644 --- a/src/net/linux/socket_helper.c +++ b/src/net/linux/socket_helper.cpp @@ -20,7 +20,7 @@ #error This source code is not for Win32. #endif -#include "socket_helper.h" +#include bool @@ -35,7 +35,8 @@ socket_string_to_addr(const char *str, int addrFamily, struct sockaddr * addr, i } bool -socket_resolve(const char *str, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen) +socket_resolve(const char *str, const char *port, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen) { + return internal_socket_resolve(str, port, addrFamily, sockType, protocol, addr, addrLen); } diff --git a/src/net/linux/socket_startup.c b/src/net/linux/socket_startup.cpp similarity index 97% rename from src/net/linux/socket_startup.c rename to src/net/linux/socket_startup.cpp index 40cb2dfc..bbb13167 100644 --- a/src/net/linux/socket_startup.c +++ b/src/net/linux/socket_startup.cpp @@ -20,7 +20,7 @@ #error This source code is not for Win32. #endif -#include "socket_startup.h" +#include bool socket_startup() diff --git a/src/net/socket_helper.h b/src/net/socket_helper.h index ab19e5e2..8b871770 100644 --- a/src/net/socket_helper.h +++ b/src/net/socket_helper.h @@ -20,7 +20,7 @@ #ifndef _SOCKET_HELPER_H_ #define _SOCKET_HELPER_H_ -#include "genericsocket.h" +#include #ifndef bzero #include @@ -54,7 +54,12 @@ bool socket_string_to_addr(const char *str, int addrFamily, struct sockaddr *add * Resolve a name to a numeric address. * str is assumed to be UTF-8 encoded. */ -bool socket_resolve(const char *str, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen); +bool socket_resolve(const char *str, const char *port, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen); + +/** + * Internal function (common for all OSs). + */ +bool internal_socket_resolve(const char *str, const char *port, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen); #endif diff --git a/src/net/win32/socket_helper.cpp b/src/net/win32/socket_helper.cpp new file mode 100644 index 00000000..2a3c831d --- /dev/null +++ b/src/net/win32/socket_helper.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 2007 by Lothar May * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef _WIN32 +#error This source code is Win32 only. +#endif + +#include + +#include +#include +#include + +using namespace std; + +typedef int (WSAAPI * getaddrinfow_ptr_t)(const wchar_t *nodename, const wchar_t* servname, + const ADDRINFOW *hints, PADDRINFOW *res); +typedef void (WSAAPI * freeaddrinfow_ptr_t)(PADDRINFOW ai); + +static wstring +utf8ToWchar(const char *str) +{ + // convert str from UTF-8 to UTF-16 (Win32 byte order) + wstring retStr; + if (str) + { + size_t len = strlen(str) + 1; + if (len > 1) + { + size_t reqLen = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, len, NULL, 0); + + if (reqLen) + { + wchar_t *wstr = new wchar_t[reqLen]; + wstr[0] = L'\0'; + if (::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, len, wstr, reqLen) == reqLen) + retStr = wstr; + delete[] wstr; + } + } + } + return retStr; +} + +bool +socket_string_to_addr(const char *str, int addrFamily, struct sockaddr * addr, int addrLen) +{ + bool retVal = false; +#ifdef UNICODE + // convert str from UTF-8 to UTF-16 (Win32 byte order) + wstring wstr(utf8ToWchar(str)); + if (!wstr.empty()) + retVal = (WSAStringToAddress((LPWSTR)wstr.c_str(), addrFamily, NULL, addr, &addrLen) != SOCKET_ERROR); +#else + if (str && *str != 0) + retVal = (WSAStringToAddress(str, addrFamily, NULL, addr, &addrLen) != SOCKET_ERROR); +#endif + + return retVal; +} + +bool +socket_resolve(const char *str, const char *port, int addrFamily, int sockType, int protocol, struct sockaddr *addr, int addrLen) +{ + bool retVal = false; + bool useUnicodeCall = false; + + if (str && *str != 0) + { + HMODULE hWsock = ::LoadLibraryA("ws2_32"); + + if (hWsock) + { + // Determine functions at runtime, because some operating system do not + // support the unicode version of getaddrinfo. + getaddrinfow_ptr_t getaddrinfow_ptr = (getaddrinfow_ptr_t)::GetProcAddress(hWsock, "GetAddrInfoW"); + freeaddrinfow_ptr_t freeaddrinfow_ptr = (freeaddrinfow_ptr_t)::GetProcAddress(hWsock, "FreeAddrInfoW"); + + if (getaddrinfow_ptr && freeaddrinfow_ptr) + { + useUnicodeCall = true; + + // convert str from UTF-8 to UTF-16 (Win32 byte order) + wstring wstr(utf8ToWchar(str)); + wstring wport(utf8ToWchar(port)); + ADDRINFOW aiHints; + ADDRINFOW *aiList = NULL; + + memset(&aiHints, 0, sizeof(aiHints)); + aiHints.ai_family = addrFamily; + aiHints.ai_socktype = sockType; + aiHints.ai_protocol = protocol; + + bool success = (getaddrinfow_ptr(wstr.c_str(), wport.c_str(), &aiHints, &aiList) == 0); + + if (success && aiList) + { + if ((int)aiList->ai_addrlen <= addrLen) + { + memcpy(addr, aiList->ai_addr, aiList->ai_addrlen); + retVal = true; + } + freeaddrinfow_ptr(aiList); + } + } + ::FreeLibrary(hWsock); + } + // If we cannot use the unicode function (OS older than XP SP 2), + // we call the "classic" getaddrinfo. + if (!useUnicodeCall) + retVal = internal_socket_resolve(str, port, addrFamily, sockType, protocol, addr, addrLen); + } + return retVal; +} + diff --git a/src/net/win32/socket_startup.c b/src/net/win32/socket_startup.cpp similarity index 95% rename from src/net/win32/socket_startup.c rename to src/net/win32/socket_startup.cpp index 60d4d178..2aec0c21 100644 --- a/src/net/win32/socket_startup.c +++ b/src/net/win32/socket_startup.cpp @@ -20,7 +20,8 @@ #error This source code is Win32 only. #endif -#include +#include +#include #define USE_SOCKET_VERSION_MAJOR 2 #define USE_SOCKET_VERSION_MINOR 2