*** empty log message ***

svn path=/trunk/boinc/; revision=2913
This commit is contained in:
David Anderson 2004-01-21 07:07:16 +00:00
parent 72ce699dda
commit c236b95e8c
18 changed files with 496 additions and 78 deletions

4
aclocal.m4 vendored
View File

@ -1104,8 +1104,8 @@ AC_DEFUN([SAH_HEADER_STDCXX],[
#
# Revision Log:
# $Log$
# Revision 1.62 2004/01/17 18:47:03 davea
# version 2.19
# Revision 1.63 2004/01/21 07:07:05 davea
# *** empty log message ***
#
# Revision 1.1 2003/12/11 18:38:24 korpela
# Added checked macro files into boinc

View File

@ -9393,3 +9393,33 @@ David Jan 19 2004 (from Rom Walton)
win_build/
boinc_cli.vcproj
boinc_ss.vcproj
David Jan 20 2004
- added basic support for GUI RPCs in the core client.
This allows GUIs to be implemented in a separate process.
There can be multiple GUIs looking at the same core client.
New classes:
GUI_RPC_CONN: represents a connection to a GUI program
GUI_RPC_CONN_SET: represents the set of all such connections
has the usual poll() function.
This is currently implemented only for UNIX, using UNIX domain sockets.
Should be straightforward to do in Win using named pipes.
- The isspace() macro crashes if called with a non-ASCII arg,
so use it only after isascii()
- reimplement strip_whitespace() to do the above,
have it trim at both start and end,
and make a version for string
NOTE: the real problem is that user-supplied text is being
kept in XML elements in the state file.
Should escape it.
client/
Makefile.am,in
client_state.C,h
gui_rpc_client.C,h (new)
gui_rpc_server.C,h (new)
gui_test.C
lib/
parse.C
util.C,h

View File

@ -26,6 +26,7 @@ boinc_client_SOURCES = \
cs_statefile.C \
file_names.C \
file_xfer.C \
gui_rpc_server.C \
hostinfo.C \
hostinfo_unix.C \
http.C \

View File

@ -193,6 +193,7 @@ boinc_client_SOURCES = \
cs_statefile.C \
file_names.C \
file_xfer.C \
gui_rpc_server.C \
hostinfo.C \
hostinfo_unix.C \
http.C \
@ -256,6 +257,7 @@ am_boinc_client_OBJECTS = boinc_client-app.$(OBJEXT) \
boinc_client-cs_statefile.$(OBJEXT) \
boinc_client-file_names.$(OBJEXT) \
boinc_client-file_xfer.$(OBJEXT) \
boinc_client-gui_rpc_server.$(OBJEXT) \
boinc_client-hostinfo.$(OBJEXT) \
boinc_client-hostinfo_unix.$(OBJEXT) \
boinc_client-http.$(OBJEXT) boinc_client-log_flags.$(OBJEXT) \
@ -301,6 +303,7 @@ am__depfiles_maybe = depfiles
@AMDEP_TRUE@ ./$(DEPDIR)/boinc_client-file_names.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/boinc_client-file_xfer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/boinc_client-filesys.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/boinc_client-gui_rpc_server.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/boinc_client-hostinfo.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/boinc_client-hostinfo_unix.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/boinc_client-http.Po \
@ -385,6 +388,7 @@ boinc_client-cs_scheduler.$(OBJEXT): cs_scheduler.C
boinc_client-cs_statefile.$(OBJEXT): cs_statefile.C
boinc_client-file_names.$(OBJEXT): file_names.C
boinc_client-file_xfer.$(OBJEXT): file_xfer.C
boinc_client-gui_rpc_server.$(OBJEXT): gui_rpc_server.C
boinc_client-hostinfo.$(OBJEXT): hostinfo.C
boinc_client-hostinfo_unix.$(OBJEXT): hostinfo_unix.C
boinc_client-http.$(OBJEXT): http.C
@ -440,6 +444,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boinc_client-file_names.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boinc_client-file_xfer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boinc_client-filesys.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boinc_client-gui_rpc_server.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boinc_client-hostinfo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boinc_client-hostinfo_unix.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boinc_client-http.Po@am__quote@
@ -839,6 +844,28 @@ boinc_client-file_xfer.obj: file_xfer.C
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(boinc_client_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o boinc_client-file_xfer.obj `if test -f 'file_xfer.C'; then $(CYGPATH_W) 'file_xfer.C'; else $(CYGPATH_W) '$(srcdir)/file_xfer.C'`
boinc_client-gui_rpc_server.o: gui_rpc_server.C
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(boinc_client_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT boinc_client-gui_rpc_server.o -MD -MP -MF "$(DEPDIR)/boinc_client-gui_rpc_server.Tpo" \
@am__fastdepCXX_TRUE@ -c -o boinc_client-gui_rpc_server.o `test -f 'gui_rpc_server.C' || echo '$(srcdir)/'`gui_rpc_server.C; \
@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/boinc_client-gui_rpc_server.Tpo" "$(DEPDIR)/boinc_client-gui_rpc_server.Po"; \
@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/boinc_client-gui_rpc_server.Tpo"; exit 1; \
@am__fastdepCXX_TRUE@ fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui_rpc_server.C' object='boinc_client-gui_rpc_server.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/boinc_client-gui_rpc_server.Po' tmpdepfile='$(DEPDIR)/boinc_client-gui_rpc_server.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(boinc_client_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o boinc_client-gui_rpc_server.o `test -f 'gui_rpc_server.C' || echo '$(srcdir)/'`gui_rpc_server.C
boinc_client-gui_rpc_server.obj: gui_rpc_server.C
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(boinc_client_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT boinc_client-gui_rpc_server.obj -MD -MP -MF "$(DEPDIR)/boinc_client-gui_rpc_server.Tpo" \
@am__fastdepCXX_TRUE@ -c -o boinc_client-gui_rpc_server.obj `if test -f 'gui_rpc_server.C'; then $(CYGPATH_W) 'gui_rpc_server.C'; else $(CYGPATH_W) '$(srcdir)/gui_rpc_server.C'`; \
@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/boinc_client-gui_rpc_server.Tpo" "$(DEPDIR)/boinc_client-gui_rpc_server.Po"; \
@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/boinc_client-gui_rpc_server.Tpo"; exit 1; \
@am__fastdepCXX_TRUE@ fi
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gui_rpc_server.C' object='boinc_client-gui_rpc_server.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/boinc_client-gui_rpc_server.Po' tmpdepfile='$(DEPDIR)/boinc_client-gui_rpc_server.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(boinc_client_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o boinc_client-gui_rpc_server.obj `if test -f 'gui_rpc_server.C'; then $(CYGPATH_W) 'gui_rpc_server.C'; else $(CYGPATH_W) '$(srcdir)/gui_rpc_server.C'`
boinc_client-hostinfo.o: hostinfo.C
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(boinc_client_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT boinc_client-hostinfo.o -MD -MP -MF "$(DEPDIR)/boinc_client-hostinfo.Tpo" \
@am__fastdepCXX_TRUE@ -c -o boinc_client-hostinfo.o `test -f 'hostinfo.C' || echo '$(srcdir)/'`hostinfo.C; \

View File

@ -272,6 +272,8 @@ int CLIENT_STATE::init() {
// Just to be on the safe side; something may have been modified
//
set_client_state_dirty("init");
gui_rpcs.init("gui_rpc");
return 0;
}
@ -338,6 +340,7 @@ bool CLIENT_STATE::do_something() {
POLL_ACTION(scheduler_rpc , scheduler_rpc_poll );
POLL_ACTION(garbage_collect , garbage_collect );
POLL_ACTION(update_results , update_results );
POLL_ACTION(gui_rpc , gui_rpcs.poll );
} else {
net_stats.poll(*net_xfers);
// Call these functions in bottom to top order with
@ -354,6 +357,7 @@ bool CLIENT_STATE::do_something() {
POLL_ACTION(handle_pers_file_xfers , handle_pers_file_xfers );
POLL_ACTION(garbage_collect , garbage_collect );
POLL_ACTION(update_results , update_results );
POLL_ACTION(gui_rpc , gui_rpcs.poll );
}
retval = write_state_file_if_needed();

View File

@ -26,6 +26,7 @@
#include "app.h"
#include "client_types.h"
#include "file_xfer.h"
#include "gui_rpc_server.h"
#include "hostinfo.h"
#include "http.h"
#include "language.h"
@ -73,6 +74,7 @@ public:
GLOBAL_PREFS global_prefs;
NET_STATS net_stats;
SS_LOGIC ss_logic;
GUI_RPC_CONN_SET gui_rpcs;
LANGUAGE language;
int core_client_major_version;

View File

@ -941,7 +941,7 @@ int RESULT::write(FILE* out, bool to_server) {
if (to_server) {
fprintf(out, "<app_version>%d</app_version>\n", wup->version_num);
fprintf(out,
"<core_client_version>%d.%0.2d</core_client_version>\n",
"<core_client_version>%d.%.2d</core_client_version>\n",
gstate.core_client_major_version,
gstate.core_client_minor_version
);

View File

@ -209,15 +209,26 @@ bool FILE_XFER_SET::poll() {
remove(fxp);
i--;
// Restart the upload, using the newly obtained upload_offset
fxp->file_xfer_retval = fxp->init_upload(*fxp->fip);
// if the server's file size is bigger than ours,
// something bad has happened (like a result
// got sent to multiple users).
// Pretend the file was successfully uploaded
//
if (fxp->fip->upload_offset >= fxp->fip->nbytes) {
fxp->file_xfer_done = true;
fxp->file_xfer_retval = 0;
} else {
// Restart the upload, using the newly obtained
// upload_offset
fxp->file_xfer_retval = fxp->init_upload(*fxp->fip);
if (!fxp->file_xfer_retval) {
fxp->file_xfer_retval = insert(fxp);
if (!fxp->file_xfer_retval) {
fxp->file_xfer_done = false;
fxp->file_xfer_retval = 0;
fxp->http_op_retval = 0;
fxp->file_xfer_retval = insert(fxp);
if (!fxp->file_xfer_retval) {
fxp->file_xfer_done = false;
fxp->file_xfer_retval = 0;
fxp->http_op_retval = 0;
}
}
}
}

144
client/gui_rpc_client.C Normal file
View File

@ -0,0 +1,144 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "parse.h"
#include "error_numbers.h"
#include "gui_rpc_client.h"
int RPC_CLIENT::init(char* path) {
int sock, retval;
sockaddr_un addr;
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
sock = socket(AF_UNIX, SOCK_STREAM, 0);
retval = connect(sock, (const sockaddr*)(&addr), sizeof(addr));
if (retval) {
perror("connect");
exit(1);
}
fin = fdopen(dup(sock), "r");
fout = fdopen(sock, "w");
}
RPC_CLIENT::~RPC_CLIENT() {
fclose(fin);
fclose(fout);
}
int RPC_CLIENT::get_projects(vector<PROJECT>& projects) {
char buf[256];
int retval;
fprintf(fout, "<get_projects>\n");
fflush(fout);
while (fgets(buf, 256, fin)) {
if (match_tag(buf, "<projects>")) continue;
else if (match_tag(buf, "</projects>")) return 0;
else if (match_tag(buf, "<project>")) {
PROJECT project;
retval = project.parse_state(fin);
if (!retval) {
projects.push_back(project);
}
} else {
fprintf(stderr, "unrecognized: %s", buf);
}
}
return ERR_XML_PARSE;
}
int PROJECT::parse_state(FILE* in) {
char buf[256];
STRING256 string;
strcpy(project_name, "");
strcpy(user_name, "");
strcpy(team_name, "");
resource_share = 100;
exp_avg_cpu = 0;
exp_avg_mod_time = 0;
min_rpc_time = 0;
min_report_min_rpc_time = 0;
nrpc_failures = 0;
master_url_fetch_pending = false;
sched_rpc_pending = false;
scheduler_urls.clear();
while (fgets(buf, 256, in)) {
if (match_tag(buf, "</project>")) return 0;
else if (parse_str(buf, "<scheduler_url>", string.text, sizeof(string.text))) {
scheduler_urls.push_back(string);
continue;
}
else if (parse_str(buf, "<master_url>", master_url, sizeof(master_url))) continue;
else if (parse_str(buf, "<project_name>", project_name, sizeof(project_name))) continue;
else if (parse_str(buf, "<user_name>", user_name, sizeof(user_name))) continue;
else if (parse_str(buf, "<team_name>", team_name, sizeof(team_name))) continue;
else if (parse_double(buf, "<user_total_credit>", user_total_credit)) continue;
else if (parse_double(buf, "<user_expavg_credit>", user_expavg_credit)) continue;
else if (parse_int(buf, "<user_create_time>", (int &)user_create_time)) continue;
else if (parse_int(buf, "<rpc_seqno>", rpc_seqno)) continue;
else if (parse_int(buf, "<hostid>", hostid)) continue;
else if (parse_double(buf, "<host_total_credit>", host_total_credit)) continue;
else if (parse_double(buf, "<host_expavg_credit>", host_expavg_credit)) continue;
else if (parse_int(buf, "<host_create_time>", (int &)host_create_time)) continue;
else if (parse_double(buf, "<exp_avg_cpu>", exp_avg_cpu)) continue;
else if (parse_int(buf, "<exp_avg_mod_time>", exp_avg_mod_time)) continue;
else if (match_tag(buf, "<code_sign_key>")) {
copy_element_contents(
in,
"</code_sign_key>",
code_sign_key,
sizeof(code_sign_key)
);
}
else if (parse_int(buf, "<nrpc_failures>", nrpc_failures)) continue;
else if (parse_int(buf, "<master_fetch_failures>", master_fetch_failures)) continue;
else if (parse_int(buf, "<min_rpc_time>", (int&)min_rpc_time)) continue;
else if (match_tag(buf, "<master_url_fetch_pending/>")) master_url_fetch_pending = true;
else if (match_tag(buf, "<sched_rpc_pending/>")) sched_rpc_pending = true;
else printf("PROJECT::parse_state(): unrecognized: %s\n", buf);
}
return ERR_XML_PARSE;
}
PROJECT::PROJECT() {
init();
}
void PROJECT::init() {
strcpy(master_url, "");
strcpy(authenticator, "");
project_specific_prefs = "";
resource_share = 100;
strcpy(project_name, "");
strcpy(user_name, "");
strcpy(team_name, "");
user_total_credit = 0;
user_expavg_credit = 0;
user_create_time = 0;
rpc_seqno = 0;
hostid = 0;
host_total_credit = 0;
host_expavg_credit = 0;
host_create_time = 0;
exp_avg_cpu = 0;
exp_avg_mod_time = 0;
strcpy(code_sign_key, "");
nrpc_failures = 0;
min_rpc_time = 0;
min_report_min_rpc_time = 0;
master_fetch_failures = 0;
resource_debt = 0;
debt_order = 0;
master_url_fetch_pending = false;
sched_rpc_pending = false;
tentative = false;
}
PROJECT::~PROJECT() {
}

14
client/gui_rpc_client.h Normal file
View File

@ -0,0 +1,14 @@
#include <stdio.h>
#include "client_types.h"
class RPC_CLIENT {
int sock;
FILE* fin;
FILE* fout;
public:
~RPC_CLIENT();
int init(char*);
int get_projects(vector<PROJECT>&);
};

129
client/gui_rpc_server.C Normal file
View File

@ -0,0 +1,129 @@
#include <vector.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "parse.h"
#include "client_state.h"
GUI_RPC_CONN::GUI_RPC_CONN(int s) {
sock = s;
#ifndef _WIN32
fout = fdopen(dup(sock), "w");
#endif
}
GUI_RPC_CONN::~GUI_RPC_CONN() {
close(sock);
fclose(fout);
}
int GUI_RPC_CONN::handle_rpc() {
char buf[256];
int n;
unsigned int i;
n = read(sock, buf, 256);
if (n <= 0) return -1;
buf[n] = 0;
printf("got %s\n", buf);
if (match_tag(buf, "<get_projects")) {
fprintf(fout, "<projects>\n");
for (i=0; i<gstate.projects.size(); i++) {
PROJECT* p = gstate.projects[i];
p->write_state(fout);
}
fprintf(fout, "</projects>\n");
} else {
fprintf(fout, "<unrecognized/>\n");
}
fflush(fout);
return 0;
}
int GUI_RPC_CONN_SET::insert(GUI_RPC_CONN* p) {
gui_rpcs.push_back(p);
return 0;
}
void GUI_RPC_CONN_SET::init(char* path) {
sockaddr_un addr;
int retval;
#ifndef _WIN32
unlink(path);
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
lsock = socket(AF_UNIX, SOCK_STREAM, 0);
if (lsock < 0) {
perror("socket");
exit(1);
}
retval = bind(lsock, (const sockaddr*)(&addr), sizeof(addr));
if (retval) {
perror("bind");
exit(1);
}
retval = listen(lsock, 999);
if (retval) {
perror("listen");
exit(1);
}
#endif
}
bool GUI_RPC_CONN_SET::poll() {
#ifdef _WIN32
return false;
#else
unsigned int i;
fd_set read_fds, error_fds;
int sock, n, retval;
vector<GUI_RPC_CONN*>::iterator iter;
GUI_RPC_CONN* gr;
struct timeval tv;
FD_ZERO(&read_fds);
FD_ZERO(&error_fds);
FD_SET(lsock, &read_fds);
for (i=0; i<gui_rpcs.size(); i++) {
gr = gui_rpcs[i];
FD_SET(gr->sock, &read_fds);
FD_SET(gr->sock, &error_fds);
}
memset(&tv, 0, sizeof(tv));
n = select(FD_SETSIZE, &read_fds, 0, &error_fds, &tv);
if (FD_ISSET(lsock, &read_fds)) {
sock = accept(lsock, 0, 0);
GUI_RPC_CONN* gr = new GUI_RPC_CONN(sock);
insert(gr);
}
iter = gui_rpcs.begin();
while (iter != gui_rpcs.end()) {
gr = *iter;
if (FD_ISSET(gr->sock, &error_fds)) {
delete gr;
gui_rpcs.erase(iter);
} else {
iter++;
}
}
iter = gui_rpcs.begin();
while (iter != gui_rpcs.end()) {
gr = *iter;
if (FD_ISSET(gr->sock, &read_fds)) {
retval = gr->handle_rpc();
if (retval) {
delete gr;
gui_rpcs.erase(iter);
continue;
}
}
iter++;
}
return (n != 0);
#endif
}

18
client/gui_rpc_server.h Normal file
View File

@ -0,0 +1,18 @@
class GUI_RPC_CONN {
public:
int sock;
FILE* fout;
GUI_RPC_CONN(int);
~GUI_RPC_CONN();
int handle_rpc();
};
class GUI_RPC_CONN_SET {
vector<GUI_RPC_CONN*> gui_rpcs;
int insert(GUI_RPC_CONN*);
int lsock;
public:
bool poll();
void init(char*);
};

16
client/gui_test.C Normal file
View File

@ -0,0 +1,16 @@
#include <stdio.h>
#include "gui_rpc_client.h"
main() {
RPC_CLIENT rpc;
vector<PROJECT>projects;
unsigned int i;
rpc.init("gui_rpc");
rpc.get_projects(projects);
for (i=0; i<projects.size(); i++) {
PROJECT& project = projects[i];
printf("%s: %s\n", project.master_url, project.project_name);
}
}

2
configure vendored
View File

@ -1,5 +1,5 @@
#! /bin/sh
# From configure.ac Revision: 1.69 .
# From configure.ac Revision: 1.70 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.57 for BOINC 2.19.
#

View File

@ -25,77 +25,82 @@ Two RPC operations are used.
<b>1) Get file size</b>
<p>
The request message has the form:
<pre>
&lt;data_server_request>
&lt;core_client_major_version>1&lt;/core_client_major_version>
&lt;core_client_minor_version>1&lt;/core_client_minor_version>
&lt;get_file_size>filename&lt;/get_file_size>
&lt;/data_server_request>
</pre>
<pre> ", htmlspecialchars("
<data_server_request>
<core_client_major_version>1</core_client_major_version>
<core_client_minor_version>1</core_client_minor_version>
<get_file_size>filename</get_file_size>
</data_server_request>
"), "</pre>
<p>
The reply message has the form:
<pre>
&lt;data_server_reply>
&lt;status>x&lt;/status>
[ &lt;message>text&lt;/message>
| &lt;file_size>nbytes&lt;/file_size> ]
&lt;/data_server_reply>
</pre>
Status is
<ul>
<li> 0 on success.
Nbytes is 0 if the file doesn't exist.
<li> 1 on transient error.
<pre> ", htmlspecialchars("
<data_server_reply>
<status>x</status>
[ <message>text&<message>
| <file_size>nbytes</file_size> ]
</data_server_reply>
"), "</pre>
Status is";
list_start();
list_item("0", "Success. Nbytes is 0 if the file doesn't exist.");
list_item("1", "Transient error.
The client should try another data server, or try this one later.
<li> -1 on permanent error.
The client should give up on the result.
</ul>
");
list_item("-1", "Permanent error. The client should give up on the result.");
list_end();
echo "
In the error cases, the &lt;file_size> element is omitted
and the &lt;message> element gives an explanation.
<p>
<b>2) Upload file</b>
<p>
Request message format:
<pre>
&lt;data_server_request>
&lt;core_client_major_version>1&lt;/core_client_major_version>
&lt;core_client_minor_version>1&lt;/core_client_minor_version>
&lt;file_upload>
&lt;file_info>
<pre> ", htmlspecialchars("
<data_server_request>
<core_client_major_version>1</core_client_major_version>
<core_client_minor_version>1</core_client_minor_version>
<file_upload>
<file_info>
...
&lt;xml_signature>
<xml_signature>
...
&lt;/xml_signature>
&lt;/file_info>
&lt;nbytes>x&lt;/nbytes>
&lt;offset>x&lt;/offset>
&lt;data>
</xml_signature>
</file_info>
<nbytes>x</nbytes>
<offset>x</offset>
<data>
... (nbytes bytes of data; may include non-ASCII data)
&lt;/data>
</pre>
</data>
"), "</pre>
<p>
The &lt;file_info> element is the exact text sent from the
scheduling server to the client.
It includes a signature based on the project's file upload
authentication key pair.
&lt;nbytes> is the amount of data being uploaded.
&lt;nbytes> is the size of the file.
&lt;offset> is the offset within the file.
<p>
Reply message format:
<pre>
&lt;data_server_reply>
&lt;status>x&lt;/status>
&lt;message>text&lt;/message>
&lt;/data_server_reply>
</pre>
Status is
<ul>
<li> 0 on success.
<li> 1 on transient error.
<pre> ", htmlspecialchars("
<data_server_reply>
<status>x</status>
<message>text</message>
</data_server_reply>
"), "</pre>
Status is ";
list_start();
list_item("0", "success");
list_item("1", "transient error;
The client should try another data server, or try this one later.
<li> -1 on permanent error.
");
list_item("-1", "Permanent error.
The client should give up on the result.
");
list_end();
echo "
</ul>
In the error cases, the &lt;message> element gives an explanation.
<p>

View File

@ -70,6 +70,7 @@ bool parse_double(const char* buf, const char* tag, double& x) {
// parse a string of the form ...<tag attrs>string</tag>...;
// returns the "string" part.
// "string" may not include '<'
// Strips white space from ends.
// Use "<tag", not "<tag>", if there might be attributes
//
@ -78,14 +79,13 @@ bool parse_str(const char* buf, const char* tag, char* dest, int len) {
if (!p) return false;
p = strchr(p, '>');
++p;
while (isspace(*p)) ++p;
char* q = strchr(p, '<');
if (!q) return false;
while (isspace(*(q-1))) --q;
char save_q = *q;
*q = 0;
safe_strncpy(dest, p, len);
*q = save_q;
strip_whitespace(dest);
return true;
}
@ -96,15 +96,15 @@ bool parse_str(const char* buf, const char* tag, string& dest) {
if (!p) return false;
p = strchr(p, '>');
++p;
while (isspace(*p)) ++p;
char const* q = strchr(p, '<');
if (!q) return false;
while (isspace(*(q-1))) --q;
dest.assign(p, q-p);
strip_whitespace(dest);
return true;
}
// parse a string of the form name="string"
// parse a string of the form name="string";
// returns string in dest
//
void parse_attr(const char* buf, const char* name, char* dest, int len) {
char* p, *q;

View File

@ -289,15 +289,34 @@ void c2x(char *what) {
strcpy(what, buf);
}
// remove whitespace from start and end of a string
//
void strip_whitespace(char *str) {
int read_pos=0, write_pos=0;
while (str[read_pos]) {
if (!isspace(str[read_pos])) {
str[write_pos++] = str[read_pos];
}
read_pos++;
int n;
while (isascii(str[0]) && isspace(str[0])) {
strcpy(str, str+1);
}
while (1) {
n = strlen(str);
if (n == 0) break;
if (!isascii(str[n-1])) break;
if (!isspace(str[n-1])) break;
str[n-1] = 0;
}
}
void strip_whitespace(string& str) {
int n;
while (isascii(str[0]) && isspace(str[0])) {
str.erase(0, 1);
}
while (1) {
n = str.length();
if (n == 0) break;
if (!isascii(str[n-1])) break;
if (!isspace(str[n-1])) break;
str.erase(n-1, 1);
}
str[write_pos] = 0;
}
void unescape_url(char *url) {

View File

@ -40,6 +40,7 @@ extern int parse_command_line( char *, char ** );
extern int lock_file(char*);
extern void c2x(char *what);
extern void strip_whitespace(char *str);
extern void strip_whitespace(string&);
extern void unescape_url(char *url);
extern void escape_url(char *in, char*out);
extern void escape_url_readable(char* in, char* out);
@ -62,19 +63,16 @@ inline bool starts_with(string const& s, string const& prefix) {
}
// http://lists.debian.org/debian-gcc/2002/debian-gcc-200204/msg00092.html
inline void downcase_string(string::iterator begin, string::iterator end,
string::iterator src)
{
inline void downcase_string(
string::iterator begin, string::iterator end, string::iterator src
) {
std::transform(begin, end, src, (int(*)(int))tolower);
}
inline void downcase_string(string& w)
{
inline void downcase_string(string& w) {
downcase_string(w.begin(), w.end(), w.begin());
}
// NOTE: use #include <functional> to get max,min
// the __attribute((format...)) tags are GCC extensions that let the compiler