// 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., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // This file is the underlying mechanism of GUI RPC client // (not the actual RPCs) #if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_) #include "boinc_win.h" #endif #ifdef _WIN32 #include "../version.h" #else #include "config.h" #ifdef __EMX__ #include #endif #include #include #include #include #include #include #include #endif #include "diagnostics.h" #include "parse.h" #include "str_util.h" #include "util.h" #include "error_numbers.h" #include "miofile.h" #include "md5_file.h" #include "network.h" #include "common_defs.h" #include "gui_rpc_client.h" using std::string; using std::vector; RPC_CLIENT::RPC_CLIENT() { sock = -1; } RPC_CLIENT::~RPC_CLIENT() { close(); } // if any RPC returns ERR_READ or ERR_WRITE, // call this and then call init() again. // void RPC_CLIENT::close() { //fprintf(stderr, "RPC_CLIENT::close called\n"); if (sock>=0) { boinc_close_socket(sock); sock = -1; } } int RPC_CLIENT::init(const char* host, int port) { int retval; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if (port) { addr.sin_port = htons(port); } else { addr.sin_port = htons(GUI_RPC_PORT); } //printf("trying port %d\n", htons(addr.sin_port)); if (host) { hostent* hep = gethostbyname(host); if (!hep) { perror("gethostbyname"); return ERR_GETHOSTBYNAME; } addr.sin_addr.s_addr = *(int*)hep->h_addr_list[0]; } else { addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } boinc_socket(sock); retval = connect(sock, (const sockaddr*)(&addr), sizeof(addr)); if (retval) { #ifdef _WIN32 BOINCTRACE("RPC_CLIENT::init connect 2: Winsock error '%d'\n", WSAGetLastError()); #endif BOINCTRACE("RPC_CLIENT::init connect on %d returned %d\n", sock, retval); perror("connect"); close(); return ERR_CONNECT; } return 0; } int RPC_CLIENT::init_asynch( const char* host, double _timeout, bool _retry, int port ) { int retval; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); retry = _retry; timeout = _timeout; if (host) { hostent* hep = gethostbyname(host); if (!hep) { perror("gethostbyname"); return ERR_GETHOSTBYNAME; } addr.sin_addr.s_addr = *(int*)hep->h_addr_list[0]; } else { addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } retval = boinc_socket(sock); BOINCTRACE("RPC_CLIENT::init boinc_socket returned %d\n", sock); if (retval) return retval; retval = boinc_socket_asynch(sock, true); if (retval) { BOINCTRACE("RPC_CLIENT::init asynch error: %d\n", retval); } start_time = dtime(); retval = connect(sock, (const sockaddr*)(&addr), sizeof(addr)); if (retval) { perror("connect"); BOINCTRACE("RPC_CLIENT::init connect returned %d\n", retval); } BOINCTRACE("RPC_CLIENT::init attempting connect \n"); return 0; } int RPC_CLIENT::init_poll() { fd_set read_fds, write_fds, error_fds; struct timeval tv; int retval; FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&error_fds); FD_SET(sock, &read_fds); FD_SET(sock, &write_fds); FD_SET(sock, &error_fds); BOINCTRACE("RPC_CLIENT::init_poll sock = %d\n", sock); tv.tv_sec = tv.tv_usec = 0; select(FD_SETSIZE, &read_fds, &write_fds, &error_fds, &tv); retval = 0; if (FD_ISSET(sock, &error_fds)) { retval = ERR_CONNECT; } else if (FD_ISSET(sock, &write_fds)) { retval = get_socket_error(sock); if (!retval) { BOINCTRACE("RPC_CLIENT::init_poll connected to port %d\n", ntohs(addr.sin_port)); retval = boinc_socket_asynch(sock, false); if (retval) { BOINCTRACE("asynch error: %d\n", retval); return retval; } return 0; } else { BOINCTRACE("init_poll: get_socket_error(): %d\n", retval); } } if (dtime() > start_time + timeout) { BOINCTRACE("RPC_CLIENT init timed out\n"); return ERR_CONNECT; } if (retval) { if (retry) { boinc_close_socket(sock); retval = boinc_socket(sock); retval = boinc_socket_asynch(sock, true); retval = connect(sock, (const sockaddr*)(&addr), sizeof(addr)); BOINCTRACE("RPC_CLIENT::init_poll attempting connect\n"); return ERR_RETRY; } else { return ERR_CONNECT; } } return ERR_RETRY; } int RPC_CLIENT::authorize(const char* passwd) { bool found=false; int retval, n; char buf[256], nonce[256], nonce_hash[256]; RPC rpc(this); retval = rpc.do_rpc("\n"); if (retval) return retval; while (rpc.fin.fgets(buf, 256)) { if (parse_str(buf, "", nonce, sizeof(nonce))) { found = true; } } if (!found) { //fprintf(stderr, "Nonce not found\n"); return ERR_AUTHENTICATOR; } n = snprintf(buf, sizeof(buf), "%s%s", nonce, passwd); if (n >= (int)sizeof(buf)) return ERR_AUTHENTICATOR; md5_block((const unsigned char*)buf, (int)strlen(buf), nonce_hash); sprintf(buf, "\n%s\n\n", nonce_hash); retval = rpc.do_rpc(buf); if (retval) return retval; while (rpc.fin.fgets(buf, 256)) { if (match_tag(buf, "")) { return 0; } } return ERR_AUTHENTICATOR; } int RPC_CLIENT::send_request(const char* p) { char buf[4096]; sprintf(buf, "\n" "%s" "\n\003", p ); int n = send(sock, buf, (int)strlen(buf), 0); if (n < 0) { printf("send: %d\n", n); perror("send"); return ERR_WRITE; } return 0; } // get reply from server. Caller must free buf // int RPC_CLIENT::get_reply(char*& mbuf) { char buf[8193]; MFILE mf; int n; while (1) { n = recv(sock, buf, 8192, 0); if (n <= 0) return ERR_READ; buf[n]=0; mf.puts(buf); if (strchr(buf, '\003')) break; } mf.get_buf(mbuf, n); return 0; } RPC::RPC(RPC_CLIENT* rc) { mbuf = 0; rpc_client = rc; } RPC::~RPC() { if (mbuf) free(mbuf); } int RPC::do_rpc(const char* req) { int retval; //fprintf(stderr, "RPC::do_rpc rpc_client->sock = '%d'", rpc_client->sock); if (rpc_client->sock == -1) return ERR_CONNECT; #ifdef DEBUG puts(req); #endif retval = rpc_client->send_request(req); if (retval) return retval; retval = rpc_client->get_reply(mbuf); if (retval) return retval; fin.init_buf_read(mbuf); #ifdef DEBUG puts(mbuf); #endif return 0; } int RPC::parse_reply() { char buf[256]; while (fin.fgets(buf, 256)) { if (strstr(buf, "unauthorized")) return ERR_AUTHENTICATOR; if (strstr(buf, "Missing authenticator")) return ERR_AUTHENTICATOR; if (strstr(buf, "Missing URL")) return ERR_INVALID_URL; if (strstr(buf, "Already attached to project")) return ERR_ALREADY_ATTACHED; if (strstr(buf, "success")) return BOINC_SUCCESS; } return ERR_NOT_FOUND; } const char *BOINC_RCSID_6802bead97 = "$Id$";