2005-01-20 23:22:22 +00:00
|
|
|
// Berkeley Open Infrastructure for Network Computing
|
|
|
|
// http://boinc.berkeley.edu
|
|
|
|
// Copyright (C) 2005 University of California
|
2004-11-14 08:29:32 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// 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.
|
2004-07-13 13:54:09 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// 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.
|
2004-06-10 07:49:50 +00:00
|
|
|
//
|
2005-01-20 23:22:22 +00:00
|
|
|
// 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
|
2004-06-10 07:49:50 +00:00
|
|
|
|
2005-07-31 23:33:12 +00:00
|
|
|
// This file is the underlying mechanism of GUI RPC client
|
|
|
|
// (not the actual RPCs)
|
|
|
|
|
2005-12-16 03:35:15 +00:00
|
|
|
#if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_)
|
2005-07-14 16:46:38 +00:00
|
|
|
#include "boinc_win.h"
|
|
|
|
#endif
|
|
|
|
|
2004-06-10 07:49:50 +00:00
|
|
|
#ifdef _WIN32
|
2005-10-03 23:14:39 +00:00
|
|
|
#include "../version.h"
|
2005-03-07 06:09:04 +00:00
|
|
|
#else
|
2004-11-11 03:59:16 +00:00
|
|
|
#include "config.h"
|
2005-12-02 22:29:35 +00:00
|
|
|
#ifdef __EMX__
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
2004-06-12 04:45:36 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
2004-07-13 13:54:09 +00:00
|
|
|
#include <cstdio>
|
2004-01-21 07:07:16 +00:00
|
|
|
#include <unistd.h>
|
2004-07-13 13:54:09 +00:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
2004-06-10 07:49:50 +00:00
|
|
|
#endif
|
2004-01-21 07:07:16 +00:00
|
|
|
|
2004-11-15 06:44:50 +00:00
|
|
|
#include "diagnostics.h"
|
2004-01-21 07:07:16 +00:00
|
|
|
#include "parse.h"
|
2005-05-25 19:26:37 +00:00
|
|
|
#include "util.h"
|
2004-01-21 07:07:16 +00:00
|
|
|
#include "error_numbers.h"
|
2004-06-12 04:45:36 +00:00
|
|
|
#include "miofile.h"
|
2005-03-07 06:09:04 +00:00
|
|
|
#include "md5_file.h"
|
2005-04-08 23:40:50 +00:00
|
|
|
#include "network.h"
|
2004-01-21 07:07:16 +00:00
|
|
|
#include "gui_rpc_client.h"
|
|
|
|
|
2004-07-02 03:20:17 +00:00
|
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
|
2005-12-04 10:57:35 +00:00
|
|
|
RPC_CLIENT::RPC_CLIENT() {
|
|
|
|
client_major_version = 0;
|
|
|
|
client_minor_version = 0;
|
|
|
|
client_release = 0;
|
2006-07-09 20:59:41 +00:00
|
|
|
sock = -1;
|
2005-12-04 10:57:35 +00:00
|
|
|
}
|
2004-09-14 15:52:06 +00:00
|
|
|
|
|
|
|
RPC_CLIENT::~RPC_CLIENT() {
|
2005-04-08 04:23:37 +00:00
|
|
|
close();
|
2004-09-14 15:52:06 +00:00
|
|
|
}
|
|
|
|
|
2004-09-30 21:55:19 +00:00
|
|
|
// if any RPC returns ERR_READ or ERR_WRITE,
|
|
|
|
// call this and then call init() again.
|
|
|
|
//
|
|
|
|
void RPC_CLIENT::close() {
|
2005-04-15 20:49:23 +00:00
|
|
|
//fprintf(stderr, "RPC_CLIENT::close called\n");
|
2006-07-09 20:59:41 +00:00
|
|
|
if (sock>=0) {
|
2005-04-16 21:33:34 +00:00
|
|
|
boinc_close_socket(sock);
|
2006-07-09 20:59:41 +00:00
|
|
|
sock = -1;
|
2005-04-16 21:33:34 +00:00
|
|
|
}
|
2004-09-30 21:55:19 +00:00
|
|
|
}
|
|
|
|
|
2005-12-13 08:04:57 +00:00
|
|
|
int RPC_CLIENT::init(const char* host, int port) {
|
2004-07-10 07:27:00 +00:00
|
|
|
int retval;
|
2005-12-16 03:35:15 +00:00
|
|
|
memset(&addr, 0, sizeof(addr));
|
2004-09-14 15:52:06 +00:00
|
|
|
addr.sin_family = AF_INET;
|
2005-12-13 08:04:57 +00:00
|
|
|
if (port) {
|
|
|
|
addr.sin_port = htons(port);
|
|
|
|
} else {
|
2005-12-20 07:35:50 +00:00
|
|
|
addr.sin_port = htons(GUI_RPC_PORT);
|
2005-12-13 08:04:57 +00:00
|
|
|
}
|
|
|
|
//printf("trying port %d\n", htons(addr.sin_port));
|
2004-07-10 07:27:00 +00:00
|
|
|
|
2004-09-14 15:52:06 +00:00
|
|
|
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 {
|
2005-11-21 18:34:44 +00:00
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
2004-09-14 15:52:06 +00:00
|
|
|
}
|
2005-05-31 21:59:29 +00:00
|
|
|
boinc_socket(sock);
|
2005-05-25 19:26:37 +00:00
|
|
|
retval = connect(sock, (const sockaddr*)(&addr), sizeof(addr));
|
2005-12-20 07:35:50 +00:00
|
|
|
if (retval) {
|
2005-04-08 23:40:50 +00:00
|
|
|
#ifdef _WIN32
|
2005-12-20 07:35:50 +00:00
|
|
|
BOINCTRACE("RPC_CLIENT::init connect 2: Winsock error '%d'\n", WSAGetLastError());
|
2004-09-14 15:52:06 +00:00
|
|
|
#endif
|
2005-12-20 07:35:50 +00:00
|
|
|
BOINCTRACE("RPC_CLIENT::init connect on %d returned %d\n", sock, retval);
|
|
|
|
perror("connect");
|
|
|
|
close();
|
|
|
|
return ERR_CONNECT;
|
2005-12-04 10:57:35 +00:00
|
|
|
}
|
|
|
|
|
2005-05-25 19:26:37 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int RPC_CLIENT::init_asynch(const char* host, double _timeout, bool _retry) {
|
|
|
|
int retval;
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sin_family = AF_INET;
|
2005-12-20 07:35:50 +00:00
|
|
|
addr.sin_port = htons(GUI_RPC_PORT);
|
2005-05-25 19:26:37 +00:00
|
|
|
retry = _retry;
|
|
|
|
timeout = _timeout;
|
|
|
|
|
|
|
|
if (host) {
|
|
|
|
hostent* hep = gethostbyname(host);
|
|
|
|
if (!hep) {
|
|
|
|
perror("gethostbyname");
|
|
|
|
return ERR_GETHOSTBYNAME;
|
2005-03-30 22:38:37 +00:00
|
|
|
}
|
2005-05-25 19:26:37 +00:00
|
|
|
addr.sin_addr.s_addr = *(int*)hep->h_addr_list[0];
|
|
|
|
} else {
|
2005-11-21 18:34:44 +00:00
|
|
|
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
2004-09-14 15:52:06 +00:00
|
|
|
}
|
2005-05-25 19:26:37 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2005-12-20 07:35:50 +00:00
|
|
|
BOINCTRACE("RPC_CLIENT::init attempting connect \n");
|
2004-04-02 00:19:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-04-08 23:40:50 +00:00
|
|
|
int RPC_CLIENT::init_poll() {
|
|
|
|
fd_set read_fds, write_fds, error_fds;
|
|
|
|
struct timeval tv;
|
2005-04-09 00:39:31 +00:00
|
|
|
int retval;
|
2005-04-08 23:40:50 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2005-04-28 17:43:13 +00:00
|
|
|
BOINCTRACE("RPC_CLIENT::init_poll sock = %d\n", sock);
|
2005-04-15 18:08:05 +00:00
|
|
|
|
2005-04-08 23:40:50 +00:00
|
|
|
tv.tv_sec = tv.tv_usec = 0;
|
2005-04-09 02:21:11 +00:00
|
|
|
select(FD_SETSIZE, &read_fds, &write_fds, &error_fds, &tv);
|
2005-04-10 18:36:12 +00:00
|
|
|
retval = 0;
|
|
|
|
if (FD_ISSET(sock, &error_fds)) {
|
|
|
|
retval = ERR_CONNECT;
|
|
|
|
} else if (FD_ISSET(sock, &write_fds)) {
|
2005-04-09 00:39:31 +00:00
|
|
|
retval = get_socket_error(sock);
|
2005-04-10 18:36:12 +00:00
|
|
|
if (!retval) {
|
2005-04-28 17:43:13 +00:00
|
|
|
BOINCTRACE("RPC_CLIENT::init_poll connected to port %d\n", ntohs(addr.sin_port));
|
2005-04-10 18:36:12 +00:00
|
|
|
retval = boinc_socket_asynch(sock, false);
|
|
|
|
if (retval) {
|
2005-11-26 08:02:05 +00:00
|
|
|
BOINCTRACE("asynch error: %d\n", retval);
|
2005-04-09 00:39:31 +00:00
|
|
|
return retval;
|
|
|
|
}
|
2005-04-10 18:36:12 +00:00
|
|
|
return 0;
|
2005-04-15 18:50:11 +00:00
|
|
|
} else {
|
2005-11-26 08:02:05 +00:00
|
|
|
BOINCTRACE("init_poll: get_socket_error(): %d\n", retval);
|
2005-04-09 00:39:31 +00:00
|
|
|
}
|
2005-04-10 18:36:12 +00:00
|
|
|
}
|
2005-05-25 19:26:37 +00:00
|
|
|
if (dtime() > start_time + timeout) {
|
2005-11-26 08:02:05 +00:00
|
|
|
BOINCTRACE("RPC_CLIENT init timed out\n");
|
2005-05-25 19:26:37 +00:00
|
|
|
return ERR_CONNECT;
|
|
|
|
}
|
|
|
|
if (retval) {
|
2005-12-20 07:35:50 +00:00
|
|
|
if (retry) {
|
2005-04-10 18:36:12 +00:00
|
|
|
boinc_close_socket(sock);
|
|
|
|
retval = boinc_socket(sock);
|
|
|
|
retval = boinc_socket_asynch(sock, true);
|
|
|
|
retval = connect(sock, (const sockaddr*)(&addr), sizeof(addr));
|
2005-12-20 07:35:50 +00:00
|
|
|
BOINCTRACE("RPC_CLIENT::init_poll attempting connect\n");
|
2005-04-10 18:36:12 +00:00
|
|
|
return ERR_RETRY;
|
2005-12-20 07:35:50 +00:00
|
|
|
} else {
|
|
|
|
return ERR_CONNECT;
|
2005-04-09 00:39:31 +00:00
|
|
|
}
|
2005-04-08 23:40:50 +00:00
|
|
|
}
|
|
|
|
return ERR_RETRY;
|
|
|
|
}
|
|
|
|
|
2005-03-30 09:24:31 +00:00
|
|
|
int RPC_CLIENT::authorize(const char* passwd) {
|
2005-03-07 06:09:04 +00:00
|
|
|
bool found=false;
|
|
|
|
int retval;
|
|
|
|
char buf[256], nonce[256], nonce_hash[256];
|
|
|
|
RPC rpc(this);
|
|
|
|
|
|
|
|
retval = rpc.do_rpc("<auth1/>\n");
|
|
|
|
if (retval) return retval;
|
|
|
|
while (rpc.fin.fgets(buf, 256)) {
|
|
|
|
if (parse_str(buf, "<nonce>", nonce, sizeof(nonce))) {
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
2005-04-19 20:53:04 +00:00
|
|
|
if (!found) {
|
2006-03-02 22:51:41 +00:00
|
|
|
//fprintf(stderr, "Nonce not found\n");
|
2005-04-19 20:53:04 +00:00
|
|
|
return ERR_AUTHENTICATOR;
|
|
|
|
}
|
2005-03-07 06:09:04 +00:00
|
|
|
|
|
|
|
sprintf(buf, "%s%s", nonce, passwd);
|
2006-07-21 08:23:26 +00:00
|
|
|
md5_block((const unsigned char*)buf, (int)strlen(buf), nonce_hash);
|
2005-03-07 21:47:28 +00:00
|
|
|
sprintf(buf, "<auth2/>\n<nonce_hash>%s</nonce_hash>\n", nonce_hash);
|
|
|
|
retval = rpc.do_rpc(buf);
|
2005-03-07 06:09:04 +00:00
|
|
|
if (retval) return retval;
|
|
|
|
while (rpc.fin.fgets(buf, 256)) {
|
|
|
|
if (match_tag(buf, "<authorized/>")) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ERR_AUTHENTICATOR;
|
|
|
|
}
|
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
int RPC_CLIENT::send_request(const char* p) {
|
2004-11-09 17:28:22 +00:00
|
|
|
char buf[4096];
|
|
|
|
sprintf(buf,
|
|
|
|
"<boinc_gui_rpc_request>\n"
|
2005-08-31 00:18:36 +00:00
|
|
|
" <major_version>%d</major_version>\n"
|
|
|
|
" <minor_version>%d</minor_version>\n"
|
|
|
|
" <release>%d</release>\n"
|
2004-11-09 17:28:22 +00:00
|
|
|
"%s"
|
|
|
|
"</boinc_gui_rpc_request>\n\003",
|
2005-08-31 00:18:36 +00:00
|
|
|
BOINC_MAJOR_VERSION,
|
|
|
|
BOINC_MINOR_VERSION,
|
|
|
|
BOINC_RELEASE,
|
2004-11-09 17:28:22 +00:00
|
|
|
p
|
|
|
|
);
|
2006-07-21 08:23:26 +00:00
|
|
|
int n = send(sock, buf, (int)strlen(buf), 0);
|
2005-04-09 00:39:31 +00:00
|
|
|
if (n < 0) {
|
|
|
|
printf("send: %d\n", n);
|
|
|
|
perror("send");
|
|
|
|
return ERR_WRITE;
|
|
|
|
}
|
2004-09-14 15:52:06 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2004-07-10 07:27:00 +00:00
|
|
|
|
2004-09-14 15:52:06 +00:00
|
|
|
// get reply from server. Caller must free buf
|
|
|
|
//
|
|
|
|
int RPC_CLIENT::get_reply(char*& mbuf) {
|
2005-05-25 19:26:37 +00:00
|
|
|
char buf[8193];
|
2004-09-14 15:52:06 +00:00
|
|
|
MFILE mf;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
while (1) {
|
2005-05-25 19:26:37 +00:00
|
|
|
n = recv(sock, buf, 8192, 0);
|
2004-09-14 15:52:06 +00:00
|
|
|
if (n <= 0) return ERR_READ;
|
|
|
|
buf[n]=0;
|
|
|
|
mf.puts(buf);
|
|
|
|
if (strchr(buf, '\003')) break;
|
|
|
|
}
|
|
|
|
mf.get_buf(mbuf, n);
|
2004-04-02 00:19:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-09-25 19:33:30 +00:00
|
|
|
RPC::RPC(RPC_CLIENT* rc) {
|
|
|
|
mbuf = 0;
|
|
|
|
rpc_client = rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
RPC::~RPC() {
|
|
|
|
if (mbuf) free(mbuf);
|
|
|
|
}
|
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
int RPC::do_rpc(const char* req) {
|
2004-09-25 19:33:30 +00:00
|
|
|
int retval;
|
|
|
|
|
2005-04-15 20:49:23 +00:00
|
|
|
//fprintf(stderr, "RPC::do_rpc rpc_client->sock = '%d'", rpc_client->sock);
|
2006-07-09 20:59:41 +00:00
|
|
|
if (rpc_client->sock == -1) return ERR_CONNECT;
|
2005-03-07 21:47:28 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
puts(req);
|
|
|
|
#endif
|
2004-09-25 19:33:30 +00:00
|
|
|
retval = rpc_client->send_request(req);
|
|
|
|
if (retval) return retval;
|
|
|
|
retval = rpc_client->get_reply(mbuf);
|
|
|
|
if (retval) return retval;
|
|
|
|
fin.init_buf(mbuf);
|
2005-03-07 21:47:28 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
puts(mbuf);
|
|
|
|
#endif
|
2004-09-27 22:21:10 +00:00
|
|
|
return 0;
|
2004-09-25 19:33:30 +00:00
|
|
|
}
|
|
|
|
|
2005-05-31 21:59:29 +00:00
|
|
|
int RPC::parse_reply() {
|
|
|
|
char buf[256];
|
|
|
|
while (fin.fgets(buf, 256)) {
|
|
|
|
if (strstr(buf, "unauthorized")) return ERR_AUTHENTICATOR;
|
2005-08-26 21:23:00 +00:00
|
|
|
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;
|
2005-05-31 21:59:29 +00:00
|
|
|
}
|
|
|
|
return ERR_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
2005-01-02 18:29:53 +00:00
|
|
|
const char *BOINC_RCSID_6802bead97 = "$Id$";
|