// Berkeley Open Infrastructure for Network Computing // http://boinc.berkeley.edu // Copyright (C) 2005 University of California // // This is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any later version. // // This software 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 Lesser General Public License for more details. // // To view the GNU Lesser General Public License visit // http://www.gnu.org/copyleft/lesser.html // or write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_) #include "boinc_win.h" #endif #ifndef _WIN32 #include "config.h" #include #include #include #include #include #include #include #include #include #endif #include "error_numbers.h" #include "network.h" const char* socket_error_str() { static char buf[80]; #if defined(_WIN32) && defined(USE_WINSOCK) int e = WSAGetLastError(); switch (e) { case WSANOTINITIALISED: return "WSA not initialized"; case WSAENETDOWN: return "the network subsystem has failed"; case WSAHOST_NOT_FOUND: return "host name not found"; case WSATRY_AGAIN: return "no response from server"; case WSANO_RECOVERY: return "a nonrecoverable error occurred"; case WSANO_DATA: return "valid name, no data record of requested type"; case WSAEINPROGRESS: return "a blocking socket call in progress"; case WSAEFAULT: return "invalid part of user address space"; case WSAEINTR: return "a blocking socket call was canceled"; case WSAENOTSOCK: return "not a socket"; } sprintf(buf, "error %d", e); return buf; #else switch (h_errno) { case HOST_NOT_FOUND: return "host not found"; case NO_DATA: return "valid name, no data record of requested type"; case NO_RECOVERY: return "a nonrecoverable error occurred"; case TRY_AGAIN: return "host not found or server failure"; #ifdef NETDB_INTERNAL case NETDB_INTERNAL: sprintf(buf,"network internal error %d",errno); return buf; #endif } sprintf(buf, "error %d", h_errno); return buf; #endif } int resolve_hostname(char* hostname, int &ip_addr, char* msg) { strcpy(msg, ""); // if the hostname is in Internet Standard dotted notation, // return that address. // ip_addr = inet_addr(hostname); if (ip_addr != -1) { return 0; } // else resolve the name // hostent* hep; hep = gethostbyname(hostname); if (!hep) { sprintf(msg, "Can't resolve hostname [%s] %s", hostname, socket_error_str()); return ERR_GETHOSTBYNAME; } ip_addr = *(int*)hep->h_addr_list[0]; return 0; } int boinc_socket(int& fd) { fd = (int)socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); return ERR_SOCKET; } #ifndef _WIN32 fcntl(fd, F_SETFD, FD_CLOEXEC); #endif return 0; } int boinc_socket_asynch(int fd, bool asynch) { if (asynch) { #if defined(_WIN32) && defined(USE_WINSOCK) unsigned long one = 1; ioctlsocket(fd, FIONBIO, &one); #else int flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { return ERR_FCNTL; } if (fcntl(fd, F_SETFL, flags|O_NONBLOCK) < 0 ) { return ERR_FCNTL; } #endif } else { #if defined(_WIN32) && defined(USE_WINSOCK) unsigned long zero = 0; ioctlsocket(fd, FIONBIO, &zero); #else int flags; flags = fcntl(fd, F_GETFL, 0); if (flags < 0) { return ERR_FCNTL; } if (fcntl(fd, F_SETFL, flags&(~O_NONBLOCK)) < 0 ) { return ERR_FCNTL; } #endif } return 0; } void boinc_close_socket(int sock) { #if defined(_WIN32) && defined(USE_WINSOCK) closesocket(sock); #else close(sock); #endif } int get_socket_error(int fd) { boinc_socklen_t intsize = sizeof(int); int n; #if defined(_WIN32) && defined(USE_WINSOCK) getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&n, &intsize); #elif defined(__FreeBSD__) // workaround for FreeBSD. I don't understand this. struct sockaddr_in sin; socklen_t sinsz = sizeof(sin); n = getpeername(fd, (struct sockaddr *)&sin, &sinsz); #else getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&n, (socklen_t*)&intsize); #endif return n; } #if defined(_WIN32) && defined(USE_WINSOCK) typedef int (*pfnBOINCIsNetworkAlive)(LPDWORD lpdwFlags); int get_connected_state() { // The following is commented out because it causes // hangs in some situations. int online = 0; static bool first=true; static HMODULE lib_boinc_module; static pfnBOINCIsNetworkAlive BOINCIsNetworkAlive; DWORD connectionFlags; if (first) { lib_boinc_module = LoadLibrary("boinc.dll"); if (lib_boinc_module) { BOINCIsNetworkAlive = (pfnBOINCIsNetworkAlive) GetProcAddress(lib_boinc_module, "BOINCIsNetworkAlive"); } first = false; } if (lib_boinc_module && BOINCIsNetworkAlive) { connectionFlags = NETWORK_ALIVE_LAN | NETWORK_ALIVE_WAN | NETWORK_ALIVE_AOL; online = BOINCIsNetworkAlive(&connectionFlags); if (online) { return CONNECTED_STATE_CONNECTED; } } return CONNECTED_STATE_UNKNOWN; } int WinsockInitialize() { WSADATA wsdata; return WSAStartup( MAKEWORD( 1, 1 ), &wsdata); } int WinsockCleanup() { return WSACleanup(); } #else // anyone know how to see if this host has physical network connection? // int get_connected_state() { return CONNECTED_STATE_UNKNOWN; } #endif const char *BOINC_RCSID_557bf0741f="$Id$";