// 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 #ifdef _WIN32 #include "boinc_win.h" #else #include #include #include #include #include #include #include #include #endif #include "error_numbers.h" #include "network.h" int resolve_hostname(char* hostname, int &ip_addr, char* 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) { int n; n = sprintf(msg, "Can't resolve hostname [%s] ", hostname); #ifdef WIN32 switch (WSAGetLastError()) { case WSANOTINITIALISED: break; case WSAENETDOWN: sprintf(msg+n, "(the network subsystem has failed)"); break; case WSAHOST_NOT_FOUND: sprintf(msg+n, "(host name not found)"); break; case WSATRY_AGAIN: sprintf(msg+n, "(no response from server)"); break; case WSANO_RECOVERY: sprintf(msg+n, "(a nonrecoverable error occurred)"); break; case WSANO_DATA: sprintf(msg+n, "(valid name, no data record of requested type)"); break; case WSAEINPROGRESS: sprintf(msg+n, "(a blocking socket call in progress)"); break; case WSAEFAULT: sprintf(msg+n, "(invalid part of user address space)"); break; case WSAEINTR: sprintf(msg+n, "(a blocking socket call was canceled)"); break; } NetClose(); #else switch (h_errno) { case HOST_NOT_FOUND: sprintf(msg+n, "(host not found)"); break; case NO_DATA: sprintf(msg+n, "(valid name, no data record of requested type)"); break; case NO_RECOVERY: sprintf(msg+n, "(a nonrecoverable error occurred)"); break; case TRY_AGAIN: sprintf(msg+n, "(host not found or server failure)"); break; } #endif return ERR_GETHOSTBYNAME; } ip_addr = *(int*)hep->h_addr_list[0]; return 0; } int boinc_socket(int& fd) { fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { perror("socket"); #ifdef WIN32 NetClose(); #endif return ERR_SOCKET; } return 0; } int boinc_socket_asynch(int fd, bool asynch) { if (asynch) { #ifdef WIN32 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 { #ifdef WIN32 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) { #ifdef _WIN32 closesocket(sock); #else close(sock); #endif } int get_socket_error(int fd) { socklen_t intsize = sizeof(int); int n; #ifdef WIN32 getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&n, &intsize); #elif __APPLE__ getsockopt(fd, SOL_SOCKET, SO_ERROR, &n, (int *)&intsize); #else getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&n, &intsize); #endif return n; } #ifdef _WIN32 #define DIAL_WAIT 60 // seconds after dial to wait (in case of cancel) #define CONFIRM_WAIT 60 // seconds after user says not to connect to ask again #define CLOSE_WAIT 5 // seconds after last call to close that the connection should be terminated int net_ref_count = -1; // -1 closed, 0 open but not used, >0 number of users double net_last_req_time = 0; // last time user was requested to connect in seconds double net_last_dial_time = 0; // last time modem was dialed double net_close_time = 0; // 0 don't close, >0 time when network connection should be terminated in seconds bool dialed = false; int WinsockInitialize() { WSADATA wsdata; return WSAStartup( MAKEWORD( 1, 1 ), &wsdata); } int WinsockCleanup() { return WSACleanup(); } typedef BOOL (WINAPI *GetStateProc)( OUT LPDWORD lpdwFlags, IN DWORD dwReserved); int get_connected_state( ) { int online = 0; static bool first=true; static HMODULE libmodule; static GetStateProc GetState; DWORD connectionFlags; if (first) { libmodule = LoadLibrary("wininet.dll"); if (libmodule) { GetState = (GetStateProc) GetProcAddress(libmodule, "InternetGetConnectedState"); } first = false; } if (libmodule && GetState) { online = (*GetState)(&connectionFlags, 0); if (online) { return CONNECTED_STATE_CONNECTED; } else { return CONNECTED_STATE_NOT_CONNECTED; } } return CONNECTED_STATE_UNKNOWN; } int NetOpen() { int rc; typedef BOOL (WINAPI *GetStateProc)( OUT LPDWORD lpdwFlags, IN DWORD dwReserved); typedef BOOL (WINAPI *AutoDialProc)( IN DWORD dwFlags, IN DWORD dwReserved); if (net_ref_count >= 0) { net_ref_count ++; return 0; } GetStateProc GetState = NULL; AutoDialProc AutoDial = NULL; DWORD connectionFlags; HMODULE libmodule = NULL; libmodule = LoadLibrary("wininet.dll"); if (libmodule) { GetState = (GetStateProc)GetProcAddress(libmodule, "InternetGetConnectedState"); AutoDial = (AutoDialProc)GetProcAddress(libmodule, "InternetAutodial"); if (GetState && AutoDial) { rc = (*GetState)(&connectionFlags, 0); // Don't Autodial if already connected to Internet by Modem or LAN if (!rc) { if((double)time(NULL) < net_last_dial_time + CONFIRM_WAIT) { return ERR_USER_PERMISSION; } #if !defined(_WIN32) && !defined(_CONSOLE) if(gstate.global_prefs.confirm_before_connecting) { net_last_req_time = (double)time(NULL); if(!RequestNetConnect()) { return ERR_USER_PERMISSION; } } #endif net_last_dial_time = (double)time(NULL); rc = (*AutoDial)(INTERNET_AUTODIAL_FORCE_UNATTENDED, 0); if (rc) { dialed = true; } else { // InternetAutodial() returns error 86 for some users // and 668 for some other users, but a subsequent call // to gethostbyname() or connect() autodials successfully. // So (with one exception) we ignore failure returns // from InternetAutodial() to work around this problem. // Error 86 is "The specified Network Password is not correct." // Error 668 is RAS Error "The connection dropped." rc = GetLastError(); // Don't continue if busy signal, no answer or user cancelled if (rc == ERROR_USER_DISCONNECTION) { return ERR_USER_PERMISSION; } } } } } net_ref_count = 1; return 0; } void NetClose() { if (net_ref_count > 0) net_ref_count --; if (net_ref_count == 0) { net_close_time = (double)time(NULL) + CLOSE_WAIT; } } void NetCheck(bool hangup_if_dialed) { if (net_ref_count == 0 && net_close_time > 0 && net_close_time < (double)time(NULL)) { typedef BOOL (WINAPI *HangupProc)(IN DWORD dwReserved); HangupProc HangUp = NULL; HMODULE libmodule = NULL; // Hang up the modem if we dialed it if (dialed && hangup_if_dialed) { libmodule = LoadLibrary("wininet.dll"); if (libmodule) { HangUp = (HangupProc)GetProcAddress(libmodule, "InternetAutodialHangup"); if (HangUp) int rc = (* HangUp)(0); } } dialed = false; net_ref_count = -1; net_close_time = 0; } } #else // anyone know how to see if this host has physical network connection? // int get_connected_state() { return CONNECTED_STATE_UNKNOWN; } #endif