mirror of https://github.com/BOINC/boinc.git
Added upload authentication
svn path=/trunk/boinc/; revision=162
This commit is contained in:
parent
7e608fd1a8
commit
316de23144
44
Makefile.in
44
Makefile.in
|
@ -10,34 +10,34 @@ VPATH = @srcdir@
|
|||
# This needs to be fixed
|
||||
#
|
||||
all:
|
||||
cd db; gmake; cd ..; \
|
||||
cd RSAEuro/source/; gmake; cd ../../; \
|
||||
cd lib; gmake; cd ..; \
|
||||
cd api; gmake; cd ..; \
|
||||
cd apps; gmake; cd ..; \
|
||||
cd client; ../$(srcdir)/client/configure; gmake; cd ..; \
|
||||
cd sched; gmake; cd ..; \
|
||||
cd tools; gmake; cd ..;
|
||||
cd RSAEuro/source; make; cd ../..; \
|
||||
cd db; make; cd ..; \
|
||||
cd lib; make; cd ..; \
|
||||
cd api; make; cd ..; \
|
||||
cd apps; make; cd ..; \
|
||||
cd client; ../$(srcdir)/client/configure; make; cd ..; \
|
||||
cd sched; make; cd ..; \
|
||||
cd tools; make; cd ..;
|
||||
|
||||
clean:
|
||||
rm -f boinc.tar.gz config.cache; \
|
||||
cd db; gmake clean; cd ..; \
|
||||
cd RSAEuro/source/; gmake clean; cd ../../; \
|
||||
cd lib; gmake clean; cd ..; \
|
||||
cd api; gmake clean; cd ..; \
|
||||
cd apps; gmake clean; cd ..; \
|
||||
cd client; gmake clean; cd ..; \
|
||||
cd sched; gmake clean; cd ..; \
|
||||
cd tools; gmake clean; cd ..;
|
||||
cd RSAEuro/source/; make clean; cd ../../; \
|
||||
cd db; make clean; cd ..; \
|
||||
cd lib; make clean; cd ..; \
|
||||
cd api; make clean; cd ..; \
|
||||
cd apps; make clean; cd ..; \
|
||||
cd client; make clean; cd ..; \
|
||||
cd sched; make clean; cd ..; \
|
||||
cd tools; make clean; cd ..;
|
||||
|
||||
install: all
|
||||
-mkdir -p /usr/local/boinc;
|
||||
cd sched; gmake install;
|
||||
cd lib; gmake install;
|
||||
cd api; gmake install;
|
||||
cd apps; gmake install;
|
||||
cd client; gmake install;
|
||||
cd tools; gmake install;
|
||||
cd sched; make install;
|
||||
cd lib; make install;
|
||||
cd api; make install;
|
||||
cd apps; make install;
|
||||
cd client; make install;
|
||||
cd tools; make install;
|
||||
cp -r test /usr/local/boinc;
|
||||
|
||||
tar: clean
|
||||
|
|
14
TODO
14
TODO
|
@ -1,13 +1,14 @@
|
|||
HIGH-PRIORITY (must be done to support SETI@home)
|
||||
|
||||
- Code-signing (David)
|
||||
research tools for code-signing
|
||||
- Code-signing
|
||||
In progress - David
|
||||
|
||||
- Upload authentication (David)
|
||||
Each result contains a "certificate", signed with project key, giving
|
||||
- list of: file name, max size
|
||||
- min, max times to xfer
|
||||
modify put program to decrypt certificate, enforce name/size/time limits
|
||||
In progress - David
|
||||
|
||||
- Network retry policies (Eric?)
|
||||
can't download file: when to give up? how to retry?
|
||||
|
@ -16,18 +17,24 @@ HIGH-PRIORITY (must be done to support SETI@home)
|
|||
can't connect to sched server
|
||||
error return from sched server
|
||||
|
||||
- proxy support (Open Source)
|
||||
- make scheduling server use fast CGI
|
||||
In progress - Michael
|
||||
|
||||
- proxy support
|
||||
HTTP, Socks
|
||||
Look at other open source code
|
||||
|
||||
- team system (Barry)
|
||||
in PHP
|
||||
In progress - Barry
|
||||
|
||||
- credit display (Barry)
|
||||
in PHP
|
||||
In progress - Barry
|
||||
|
||||
- CPU accounting in the presence of checkpoint/restart (Michael)
|
||||
core client periodically gets CPU time, accumulates in state file
|
||||
In progress - Michael
|
||||
|
||||
- test versioning mechanisms for core
|
||||
Idea: need to notify user if core becomes out of date.
|
||||
|
@ -45,6 +52,7 @@ HIGH-PRIORITY (must be done to support SETI@home)
|
|||
- initialize rsc_fpops and rsc_iops in client WORKUNIT
|
||||
- check server sends correct number of work units
|
||||
- check client requests correct number of seconds of work
|
||||
In progress - Michael
|
||||
|
||||
- measure hardware parameters: CPU speed, #CPUs, memory, disk
|
||||
- define CPU benchmarks
|
||||
|
|
111
checkin_notes
111
checkin_notes
|
@ -575,6 +575,18 @@ David A June 20 2002
|
|||
prefs1.xml, prefs2.xml (new)
|
||||
test_*.php
|
||||
|
||||
David A June 21 2002
|
||||
- top-level Makefile now compiles RSAEuro/,
|
||||
and doesn't refer to sched_fcgi
|
||||
- Added <scheduler> element to html_user/index.html,
|
||||
making it the "master file" for test project.
|
||||
This file must be placed in the directory referred to by
|
||||
http://localhost/
|
||||
|
||||
Makefile.in
|
||||
html_user/
|
||||
index.html
|
||||
|
||||
Michael Gary June 21 2002
|
||||
- added install to the make system to put executables
|
||||
in /usr/local/boinc
|
||||
|
@ -732,4 +744,103 @@ Michael Gary 7/03/2002
|
|||
configure
|
||||
configure.in
|
||||
|
||||
David Anderson July 4, 2002
|
||||
- Added support for upload authentication.
|
||||
This prevents bad guys from filling up data servers with trash.
|
||||
In this scheme, each <file_info> element sent from
|
||||
server to client includes a <max_nbytes> field limiting
|
||||
the size of the file, and includes a digital signature
|
||||
based on the project's "upload authentication" key pair.
|
||||
File uploads, instead of being done by PUT, are now done by POST
|
||||
to a CGI program, "file_upload_handler".
|
||||
The request header includes the signed <file_info>,
|
||||
and the CGI program verifies the signature and enforces the size limit.
|
||||
|
||||
The affected pieces of code:
|
||||
- Added a function create_keys() in PHP test scripts
|
||||
to create encryption keys. Call it from all script.
|
||||
- Added environment var BOINC_KEY_DIR saying where keys are kept.
|
||||
- The client must maintain an exact copy of each <file_info> XML,
|
||||
and of the signature, so that it can send to upload server.
|
||||
- Added a new variant of HTTP operation, HTTP_OP_POST2.
|
||||
The existing variants all use single files for request and reply.
|
||||
The new variant (used for file upload) has a request
|
||||
consisting of a memory block followed by (part of) a file;
|
||||
the reply is in memory.
|
||||
This avoid copying possibly huge upload files.
|
||||
- FILE_XFER objects now take a FILE_INFO as initialization argument;
|
||||
needed to convey authentication info.
|
||||
The upload variant creates and sends the authentication header.
|
||||
- Result templates now include a <max_nbytes> in each
|
||||
<file_info> element, and the URLs refer to the
|
||||
file_upload_handler (with no filename)
|
||||
- process_result_template() works differently, since it must
|
||||
generate a digital signature at the end of each <file_info>
|
||||
- create_work expects the name of a private key file.
|
||||
- Added crypt/md5 functions to sign/verify in memory,
|
||||
encode/decode ASCII data in memory, checksum in memory
|
||||
- Change "gmake" to "make" in top-level makefile.
|
||||
(alias make to gmake if this is a problem)
|
||||
|
||||
boinc/
|
||||
Makefile.in
|
||||
TODO
|
||||
RSAEuro/source/
|
||||
rsaeuro.h
|
||||
client/
|
||||
Makefile.in
|
||||
client_state.C
|
||||
client_types.C,h
|
||||
cs_files.C
|
||||
file_names.C
|
||||
file_xfer.C,h
|
||||
http.C,h
|
||||
main.C
|
||||
scheduler_op.C
|
||||
test_file_xfer.C
|
||||
db/
|
||||
mysql_util.C
|
||||
doc/
|
||||
index.html
|
||||
intro.html
|
||||
master_url.html (new)
|
||||
project_startup.html (new)
|
||||
tools_security.html (new)
|
||||
html_user/
|
||||
index.html
|
||||
lib/
|
||||
Makefile.in
|
||||
crypt.C,h
|
||||
crypt_prog.C
|
||||
md5_file.C,h
|
||||
parse.C,h
|
||||
sched/
|
||||
Makefile.in
|
||||
file_upload_handler.C
|
||||
server_types.C
|
||||
test/
|
||||
1sec_result
|
||||
concat_result
|
||||
init.inc
|
||||
master.html (new)
|
||||
sah_result
|
||||
test_1sec.php
|
||||
test_concat.php
|
||||
test_dynamic.php
|
||||
test_max_water_prefs.php
|
||||
test_min_water_prefs.php
|
||||
test_normal_water_prefs.php
|
||||
test_prefs.php
|
||||
test_projects.php
|
||||
test_stderr.php
|
||||
test_uc.php
|
||||
test_uc_slow.php
|
||||
uc_result
|
||||
ucs_result
|
||||
tools/
|
||||
Makefile.in
|
||||
add.C
|
||||
backend_lib.C,h
|
||||
create_work.C
|
||||
process_result_template.C
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ TEST_HTTP_OBJS = $(TEST_NET_XFER_OBJS)
|
|||
|
||||
TEST_FX_OBJS = \
|
||||
$(TEST_HTTP_OBJS) \
|
||||
client_types.o \
|
||||
file_names.o \
|
||||
file_xfer.o
|
||||
|
||||
.C.o:
|
||||
|
|
|
@ -195,7 +195,7 @@ int CLIENT_STATE::parse_state_file() {
|
|||
}
|
||||
} else if (match_tag(buf, "<file_info>")) {
|
||||
FILE_INFO* fip = new FILE_INFO;
|
||||
fip->parse(f);
|
||||
fip->parse(f, false);
|
||||
if (project) {
|
||||
retval = link_file_info(project, fip);
|
||||
if (!retval) file_infos.push_back(fip);
|
||||
|
@ -222,7 +222,7 @@ int CLIENT_STATE::parse_state_file() {
|
|||
}
|
||||
} else if (match_tag(buf, "<result>")) {
|
||||
RESULT* rp = new RESULT;
|
||||
rp->parse(f, "</result>");
|
||||
rp->parse_state(f);
|
||||
if (project) {
|
||||
retval = link_result(project, rp);
|
||||
if (!retval) results.push_back(rp);
|
||||
|
|
|
@ -174,14 +174,17 @@ FILE_INFO::FILE_INFO() {
|
|||
FILE_INFO::~FILE_INFO() {
|
||||
}
|
||||
|
||||
int FILE_INFO::parse(FILE* in) {
|
||||
// If from server, make an exact copy of everything
|
||||
// except the start/end tags and the signature element.
|
||||
//
|
||||
int FILE_INFO::parse(FILE* in, bool from_server) {
|
||||
char buf[256];
|
||||
STRING256 url;
|
||||
|
||||
strcpy(name, "");
|
||||
//strcpy(url, "");
|
||||
strcpy(md5_cksum, "");
|
||||
nbytes = 0;
|
||||
max_nbytes = 0;
|
||||
generated_locally = false;
|
||||
file_present = false;
|
||||
executable = false;
|
||||
|
@ -191,21 +194,39 @@ int FILE_INFO::parse(FILE* in) {
|
|||
project = NULL;
|
||||
file_xfer = NULL;
|
||||
urls.clear();
|
||||
if (from_server) {
|
||||
signed_xml = strdup("");
|
||||
} else {
|
||||
signed_xml = 0;
|
||||
}
|
||||
signature = 0;
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "</file_info>")) return 0;
|
||||
else if (parse_str(buf, "<name>", name)) continue;
|
||||
else if (match_tag(buf, "<signature>")) {
|
||||
dup_element_contents(in, "</signature>", &signature);
|
||||
continue;
|
||||
}
|
||||
if (from_server) {
|
||||
strcatdup(signed_xml, buf);
|
||||
}
|
||||
if (parse_str(buf, "<name>", name)) continue;
|
||||
else if (parse_str(buf, "<url>", url.text)) {
|
||||
urls.push_back(url);
|
||||
continue;
|
||||
}
|
||||
else if (parse_str(buf, "<md5_cksum>", md5_cksum)) continue;
|
||||
else if (parse_double(buf, "<nbytes>", nbytes)) continue;
|
||||
else if (parse_double(buf, "<max_nbytes>", max_nbytes)) continue;
|
||||
else if (match_tag(buf, "<generated_locally/>")) generated_locally = true;
|
||||
else if (match_tag(buf, "<file_present/>")) file_present = true;
|
||||
else if (match_tag(buf, "<executable/>")) executable = true;
|
||||
else if (match_tag(buf, "<uploaded/>")) uploaded = true;
|
||||
else if (match_tag(buf, "<upload_when_present/>")) upload_when_present = true;
|
||||
else if (match_tag(buf, "<sticky/>")) sticky = true;
|
||||
else if (!from_server && match_tag(buf, "<signed_xml>")) {
|
||||
dup_element_contents(in, "</signed_xml>", &signed_xml);
|
||||
continue;
|
||||
}
|
||||
else fprintf(stderr, "FILE_INFO::parse(): unrecognized: %s\n", buf);
|
||||
}
|
||||
return 1;
|
||||
|
@ -217,8 +238,9 @@ int FILE_INFO::write(FILE* out, bool to_server) {
|
|||
"<file_info>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <md5_cksum>%s</md5_cksum>\n"
|
||||
" <nbytes>%f</nbytes>\n",
|
||||
name, md5_cksum, nbytes
|
||||
" <nbytes>%f</nbytes>\n"
|
||||
" <max_nbytes>%f</max_nbytes>\n",
|
||||
name, md5_cksum, nbytes, max_nbytes
|
||||
);
|
||||
if (!to_server) {
|
||||
if (generated_locally) fprintf(out, " <generated_locally/>\n");
|
||||
|
@ -231,6 +253,14 @@ int FILE_INFO::write(FILE* out, bool to_server) {
|
|||
for (i=0; i<urls.size(); i++) {
|
||||
fprintf(out, "<url>%s</url>\n", urls[i].text);
|
||||
}
|
||||
if (!to_server) {
|
||||
if (signed_xml) {
|
||||
fprintf(out, "<signed_xml>\n%s</signed_xml>\n", signed_xml);
|
||||
}
|
||||
if (signature) {
|
||||
fprintf(out, "<signature>\n%s</signature>\n", signature);
|
||||
}
|
||||
}
|
||||
fprintf(out, "</file_info>\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -369,26 +399,63 @@ int WORKUNIT::write(FILE* out) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int RESULT::parse(FILE* in, char* end_tag) {
|
||||
int RESULT::parse_ack(FILE* in) {
|
||||
char buf[256];
|
||||
FILE_REF file_ref;
|
||||
strcpy(name, "");
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "</result_ack>")) return 0;
|
||||
else if (parse_str(buf, "<name>", name)) continue;
|
||||
else fprintf(stderr, "RESULT::parse(): unrecognized: %s\n", buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RESULT::clear() {
|
||||
strcpy(name, "");
|
||||
strcpy(wu_name, "");
|
||||
strcpy(stderr_out, "");
|
||||
output_files.clear();
|
||||
is_active = false;
|
||||
is_compute_done = false;
|
||||
is_server_ack = false;
|
||||
cpu_time = 0;
|
||||
exit_status = 0;
|
||||
strcpy(stderr_out, "");
|
||||
app = NULL;
|
||||
wup = NULL;
|
||||
project = NULL;
|
||||
}
|
||||
|
||||
// parse a <result> element from scheduling server.
|
||||
//
|
||||
int RESULT::parse_server(FILE* in) {
|
||||
char buf[256];
|
||||
FILE_REF file_ref;
|
||||
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, end_tag)) return 0;
|
||||
else if (parse_str(buf, "<name>", name)) continue;
|
||||
else if (parse_str(buf, "<wu_name>", wu_name)) continue;
|
||||
else if (match_tag(buf, "<file_ref>")) {
|
||||
if (match_tag(buf, "</result>")) return 0;
|
||||
if (parse_str(buf, "<name>", name)) continue;
|
||||
if (parse_str(buf, "<wu_name>", wu_name)) continue;
|
||||
if (match_tag(buf, "<file_ref>")) {
|
||||
file_ref.parse(in);
|
||||
output_files.push_back(file_ref);
|
||||
continue;
|
||||
}
|
||||
else fprintf(stderr, "RESULT::parse(): unrecognized: %s\n", buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// parse a <result> element from state file
|
||||
//
|
||||
int RESULT::parse_state(FILE* in) {
|
||||
char buf[256];
|
||||
FILE_REF file_ref;
|
||||
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "</result>")) return 0;
|
||||
if (parse_str(buf, "<name>", name)) continue;
|
||||
if (parse_str(buf, "<wu_name>", wu_name)) continue;
|
||||
if (match_tag(buf, "<file_ref>")) {
|
||||
file_ref.parse(in);
|
||||
output_files.push_back(file_ref);
|
||||
continue;
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#define STDERR_MAX_LEN 4096
|
||||
|
||||
class FILE_XFER;
|
||||
class RESULT;
|
||||
|
||||
struct STRING256 {
|
||||
char text[256];
|
||||
|
@ -85,8 +86,8 @@ struct APP {
|
|||
class FILE_INFO {
|
||||
public:
|
||||
char name[256];
|
||||
//char url[256]; // TODO: allow multiple URLs
|
||||
char md5_cksum[33];
|
||||
double max_nbytes;
|
||||
double nbytes;
|
||||
bool generated_locally; // file is produced by app
|
||||
bool file_present;
|
||||
|
@ -95,13 +96,16 @@ public:
|
|||
bool upload_when_present;
|
||||
bool sticky; // don't delete unless instructed to do so
|
||||
FILE_XFER* file_xfer; // nonzero if in the process of being up/downloaded
|
||||
RESULT* result; // for upload files (to authenticate)
|
||||
PROJECT* project;
|
||||
int ref_cnt;
|
||||
vector<STRING256> urls;
|
||||
char* signed_xml;
|
||||
char* signature;
|
||||
|
||||
FILE_INFO();
|
||||
~FILE_INFO();
|
||||
int parse(FILE*);
|
||||
int parse(FILE*, bool from_server);
|
||||
int write(FILE*, bool to_server);
|
||||
int delete_file(); // attempt to delete the underlying file
|
||||
};
|
||||
|
@ -168,7 +172,10 @@ struct RESULT {
|
|||
WORKUNIT* wup;
|
||||
PROJECT* project;
|
||||
|
||||
int parse(FILE*, char* end_tag);
|
||||
void clear();
|
||||
int parse_server(FILE*);
|
||||
int parse_state(FILE*);
|
||||
int parse_ack(FILE*);
|
||||
int write(FILE*, bool to_server);
|
||||
bool is_upload_done(); // files uploaded?
|
||||
};
|
||||
|
|
|
@ -54,8 +54,8 @@ bool CLIENT_STATE::start_file_xfers() {
|
|||
fxp = fip->file_xfer;
|
||||
if (!fip->generated_locally && !fip->file_present && !fxp) {
|
||||
fxp = new FILE_XFER;
|
||||
get_pathname(fip, pathname);
|
||||
fxp->init_download(fip->urls[0].text, pathname);
|
||||
//get_pathname(fip, pathname);
|
||||
fxp->init_download(*fip);
|
||||
retval = file_xfers->insert(fxp);
|
||||
if (retval) {
|
||||
fprintf(stderr,
|
||||
|
@ -66,8 +66,8 @@ bool CLIENT_STATE::start_file_xfers() {
|
|||
fip->file_xfer = fxp;
|
||||
if (log_flags.file_xfer) {
|
||||
printf(
|
||||
"started download of %s to %s\n",
|
||||
fip->urls[0].text, pathname
|
||||
"started download of %s\n",
|
||||
fip->urls[0].text
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -77,8 +77,7 @@ bool CLIENT_STATE::start_file_xfers() {
|
|||
&& !fip->uploaded && !fxp
|
||||
) {
|
||||
fxp = new FILE_XFER;
|
||||
get_pathname(fip, pathname);
|
||||
fxp->init_upload( fip->urls[0].text, pathname);
|
||||
fxp->init_upload(*fip);
|
||||
retval = file_xfers->insert(fxp);
|
||||
if (retval) {
|
||||
fprintf(stderr,
|
||||
|
@ -88,10 +87,7 @@ bool CLIENT_STATE::start_file_xfers() {
|
|||
} else {
|
||||
fip->file_xfer = fxp;
|
||||
if (log_flags.file_xfer) {
|
||||
printf(
|
||||
"started upload of %s to %s\n",
|
||||
pathname, fip->urls[0].text
|
||||
);
|
||||
printf("started upload to %s\n", fip->urls[0].text);
|
||||
}
|
||||
}
|
||||
action = true;
|
||||
|
|
|
@ -71,8 +71,15 @@ void get_pathname(FILE_INFO* fip, char* path) {
|
|||
PROJECT* p = fip->project;
|
||||
char buf[256];
|
||||
|
||||
escape_url(p->master_url, buf);
|
||||
sprintf(path, "%s/%s", buf, fip->name);
|
||||
// for testing purposes, it's handy to allow a FILE_INFO without
|
||||
// an associated PROJECT.
|
||||
//
|
||||
if (p) {
|
||||
escape_url(p->master_url, buf);
|
||||
sprintf(path, "%s/%s", buf, fip->name);
|
||||
} else {
|
||||
strcpy(path, fip->name);
|
||||
}
|
||||
}
|
||||
|
||||
void get_slot_dir(int slot, char* path) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "windows_cpp.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "file_names.h"
|
||||
#include "log_flags.h"
|
||||
#include "file_xfer.h"
|
||||
|
||||
|
@ -31,6 +32,7 @@ FILE_XFER::FILE_XFER() {
|
|||
FILE_XFER::~FILE_XFER() {
|
||||
}
|
||||
|
||||
#if 0
|
||||
int FILE_XFER::init_download(char* url, char* outfile) {
|
||||
return HTTP_OP::init_get(url, outfile);
|
||||
}
|
||||
|
@ -38,6 +40,37 @@ int FILE_XFER::init_download(char* url, char* outfile) {
|
|||
int FILE_XFER::init_upload(char* url, char* infile) {
|
||||
return HTTP_OP::init_put(url, infile);
|
||||
}
|
||||
#endif
|
||||
|
||||
int FILE_XFER::init_download(FILE_INFO& file_info) {
|
||||
fip = &file_info;
|
||||
get_pathname(fip, pathname);
|
||||
return HTTP_OP::init_get((char*)(&fip->urls[0]), pathname);
|
||||
}
|
||||
|
||||
// for uploads, we need to build a header with signature etc.
|
||||
// (see file_upload_handler.C for a spec)
|
||||
// Do this in memory.
|
||||
//
|
||||
int FILE_XFER::init_upload(FILE_INFO& file_info) {
|
||||
fip = &file_info;
|
||||
get_pathname(fip, pathname);
|
||||
sprintf(header,
|
||||
"<file_info>\n"
|
||||
"%s"
|
||||
"<signature>\n"
|
||||
"%s"
|
||||
"</signature>\n"
|
||||
"</file_info>\n"
|
||||
"<nbytes>%f</nbytes>\n"
|
||||
"<offset>0</offset>\n"
|
||||
"<data>\n",
|
||||
file_info.signed_xml,
|
||||
file_info.signature,
|
||||
file_info.nbytes
|
||||
);
|
||||
return HTTP_OP::init_post2((char*)(&fip->urls[0]), header, pathname, 0);
|
||||
}
|
||||
|
||||
double FILE_XFER::elapsed_time() {
|
||||
return end_time - start_time;
|
||||
|
|
|
@ -20,9 +20,14 @@
|
|||
#ifndef _FILE_XFER_
|
||||
#define _FILE_XFER_
|
||||
|
||||
// FILE_XFER objects encapsulate the transfer of a file
|
||||
// to/from a particular server.
|
||||
// TODO: use the HTTP Range header fields to do partial xfers
|
||||
// FILE_XFER objects encapsulate the transfer of a file to/from data servers.
|
||||
// In particular it manages:
|
||||
// - the choice of data servers
|
||||
// TODO: try servers beyond the first one
|
||||
// - the retry and give-up policies
|
||||
// TODO: retry and eventually give up
|
||||
// - restarting partial transfers
|
||||
// - upload authentication
|
||||
|
||||
#include "client_types.h"
|
||||
#include "http.h"
|
||||
|
@ -32,12 +37,17 @@ public:
|
|||
double start_time;
|
||||
double end_time;
|
||||
FILE_INFO* fip;
|
||||
char pathname[256];
|
||||
char header[4096];
|
||||
int state;
|
||||
|
||||
FILE_XFER();
|
||||
~FILE_XFER();
|
||||
|
||||
int init_download(char* url, char* outfile);
|
||||
int init_upload(char* url, char* infile);
|
||||
//int init_download(char* url, char* outfile);
|
||||
//int init_upload(char* url, char* infile);
|
||||
int init_download(FILE_INFO&);
|
||||
int init_upload(FILE_INFO&);
|
||||
bool file_xfer_done;
|
||||
int file_xfer_retval;
|
||||
double elapsed_time();
|
||||
|
|
137
client/http.C
137
client/http.C
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "winsock.h"
|
||||
|
@ -35,7 +36,7 @@
|
|||
|
||||
#define HTTP_BLOCKSIZE 4096
|
||||
|
||||
void parse_url(char* url, char* host, char* file) {
|
||||
static void parse_url(char* url, char* host, char* file) {
|
||||
char* p;
|
||||
char buf[256];
|
||||
|
||||
|
@ -55,7 +56,9 @@ void parse_url(char* url, char* host, char* file) {
|
|||
// We use 1.0 so we don't have to count bytes.
|
||||
//
|
||||
|
||||
void http_get_request_header(char* buf, char* host, char* file, int offset) {
|
||||
static void http_get_request_header(
|
||||
char* buf, char* host, char* file, int offset
|
||||
) {
|
||||
if (offset) {
|
||||
sprintf(buf,
|
||||
"GET /%s;byte-range %d- HTTP/1.0\015\012"
|
||||
|
@ -79,7 +82,7 @@ void http_get_request_header(char* buf, char* host, char* file, int offset) {
|
|||
}
|
||||
}
|
||||
|
||||
void http_head_request_header(char* buf, char* host, char* file) {
|
||||
static void http_head_request_header(char* buf, char* host, char* file) {
|
||||
sprintf(buf,
|
||||
"HEAD /%s HTTP/1.0\015\012"
|
||||
"User-Agent: BOINC client\015\012"
|
||||
|
@ -90,7 +93,9 @@ void http_head_request_header(char* buf, char* host, char* file) {
|
|||
);
|
||||
}
|
||||
|
||||
void http_post_request_header(char* buf, char* host, char* file, int size) {
|
||||
static void http_post_request_header(
|
||||
char* buf, char* host, char* file, int size
|
||||
) {
|
||||
sprintf(buf,
|
||||
"POST /%s HTTP/1.0\015\012"
|
||||
"Pragma: no-cache\015\012"
|
||||
|
@ -103,6 +108,7 @@ void http_post_request_header(char* buf, char* host, char* file, int size) {
|
|||
);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void http_put_request_header(
|
||||
char* buf, char* host, char* file, int size, int offset
|
||||
) {
|
||||
|
@ -132,20 +138,17 @@ void http_put_request_header(
|
|||
);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int read_http_reply_header(int socket, HTTP_REPLY_HEADER& header) {
|
||||
int i;
|
||||
int i, n;
|
||||
char buf[1024], *p;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
header.content_length = 0;
|
||||
header.status = 404; // default to failure
|
||||
for (i=0; i<1024; i++) {
|
||||
#ifdef _WIN32
|
||||
recv(socket, buf+i, 1, 0);
|
||||
#else
|
||||
read(socket, buf+i, 1);
|
||||
#endif
|
||||
n = recv(socket, buf+i, 1, 0);
|
||||
if (strstr(buf, "\r\n\r\n") || strstr(buf, "\n\n")) {
|
||||
if (log_flags.http_debug) printf("reply header:\n%s", buf);
|
||||
p = strchr(buf, ' ');
|
||||
|
@ -162,6 +165,16 @@ int read_http_reply_header(int socket, HTTP_REPLY_HEADER& header) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int read_reply(int socket, char* buf, int len) {
|
||||
int i, n;
|
||||
for (i=0; i<len-1; i++) {
|
||||
n = recv(socket, buf+i, 1, 0);
|
||||
if (n != 1) break;
|
||||
}
|
||||
buf[i] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
HTTP_OP::HTTP_OP() {
|
||||
http_op_state = HTTP_STATE_IDLE;
|
||||
}
|
||||
|
@ -174,16 +187,18 @@ int HTTP_OP::init_head(char* url) {
|
|||
NET_XFER::init(hostname, 80, HTTP_BLOCKSIZE);
|
||||
http_op_type = HTTP_OP_HEAD;
|
||||
http_op_state = HTTP_STATE_CONNECTING;
|
||||
http_head_request_header(request_header, hostname, filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HTTP_OP::init_get(char* url, char* out, int off) {
|
||||
offset = off;
|
||||
file_offset = off;
|
||||
parse_url(url, hostname, filename);
|
||||
NET_XFER::init(hostname, 80, HTTP_BLOCKSIZE);
|
||||
strcpy(outfile, out);
|
||||
http_op_type = HTTP_OP_GET;
|
||||
http_op_state = HTTP_STATE_CONNECTING;
|
||||
http_get_request_header(request_header, hostname, filename, (int)file_offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -198,9 +213,35 @@ int HTTP_OP::init_post(char* url, char* in, char* out) {
|
|||
if (retval) return retval;
|
||||
http_op_type = HTTP_OP_POST;
|
||||
http_op_state = HTTP_STATE_CONNECTING;
|
||||
http_post_request_header(
|
||||
request_header, hostname, filename, content_length
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HTTP_OP::init_post2(
|
||||
char* url, char* r1, char* in, double offset
|
||||
) {
|
||||
int retval;
|
||||
|
||||
parse_url(url, hostname, filename);
|
||||
NET_XFER::init(hostname, 80, HTTP_BLOCKSIZE);
|
||||
req1 = r1;
|
||||
strcpy(infile, in);
|
||||
file_offset = offset;
|
||||
retval = file_size(infile, content_length);
|
||||
if (retval) return retval;
|
||||
content_length -= (int)offset;
|
||||
content_length += strlen(req1);
|
||||
http_op_type = HTTP_OP_POST2;
|
||||
http_op_state = HTTP_STATE_CONNECTING;
|
||||
http_post_request_header(
|
||||
request_header, hostname, filename, content_length
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int HTTP_OP::init_put(char* url, char* in, int off) {
|
||||
int retval;
|
||||
|
||||
|
@ -212,8 +253,12 @@ int HTTP_OP::init_put(char* url, char* in, int off) {
|
|||
if (retval) return retval;
|
||||
http_op_type = HTTP_OP_PUT;
|
||||
http_op_state = HTTP_STATE_CONNECTING;
|
||||
http_put_request_header(
|
||||
request_header, hostname, filename, content_length, offset
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool HTTP_OP::http_op_done() {
|
||||
return (http_op_state == HTTP_STATE_DONE);
|
||||
|
@ -233,7 +278,6 @@ int HTTP_OP_SET::insert(HTTP_OP* ho) {
|
|||
|
||||
bool HTTP_OP_SET::poll() {
|
||||
unsigned int i;
|
||||
char hdr[256];
|
||||
HTTP_OP* htp;
|
||||
int n;
|
||||
bool action = false;
|
||||
|
@ -251,36 +295,14 @@ bool HTTP_OP_SET::poll() {
|
|||
case HTTP_STATE_REQUEST_HEADER:
|
||||
if (htp->io_ready) {
|
||||
action = true;
|
||||
switch(htp->http_op_type) {
|
||||
case HTTP_OP_POST:
|
||||
http_post_request_header(
|
||||
hdr, htp->hostname, htp->filename, htp->content_length
|
||||
);
|
||||
break;
|
||||
case HTTP_OP_GET:
|
||||
http_get_request_header(hdr, htp->hostname, htp->filename, htp->offset);
|
||||
break;
|
||||
case HTTP_OP_HEAD:
|
||||
http_head_request_header(hdr, htp->hostname, htp->filename);
|
||||
break;
|
||||
case HTTP_OP_PUT:
|
||||
http_put_request_header(
|
||||
hdr, htp->hostname, htp->filename, htp->content_length, htp->offset
|
||||
);
|
||||
break;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
n = send(htp->socket, hdr, strlen(hdr), 0);
|
||||
#else
|
||||
n = write(htp->socket, hdr, strlen(hdr));
|
||||
#endif
|
||||
n = send(htp->socket, htp->request_header, strlen(htp->request_header), 0);
|
||||
if (log_flags.http_debug) {
|
||||
printf("wrote HTTP header: %d bytes\n", n);
|
||||
}
|
||||
htp->io_ready = false;
|
||||
switch(htp->http_op_type) {
|
||||
case HTTP_OP_POST:
|
||||
case HTTP_OP_PUT:
|
||||
//case HTTP_OP_PUT:
|
||||
htp->http_op_state = HTTP_STATE_REQUEST_BODY;
|
||||
htp->file = fopen(htp->infile, "r");
|
||||
if (!htp->file) {
|
||||
|
@ -298,9 +320,30 @@ bool HTTP_OP_SET::poll() {
|
|||
htp->want_upload = false;
|
||||
htp->want_download = true;
|
||||
break;
|
||||
case HTTP_OP_POST2:
|
||||
htp->http_op_state = HTTP_STATE_REQUEST_BODY1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_REQUEST_BODY1:
|
||||
if (htp->io_ready) {
|
||||
action = true;
|
||||
n = send(htp->socket, htp->req1, strlen(htp->req1), 0);
|
||||
htp->http_op_state = HTTP_STATE_REQUEST_BODY;
|
||||
htp->file = fopen(htp->infile, "r");
|
||||
if (!htp->file) {
|
||||
fprintf(stderr, "HTTP_OP: no input file %s\n", htp->infile);
|
||||
htp->io_done = true;
|
||||
htp->http_op_retval = ERR_FOPEN;
|
||||
htp->http_op_state = HTTP_STATE_DONE;
|
||||
break;
|
||||
}
|
||||
fseek(htp->file, (long)htp->file_offset, SEEK_SET);
|
||||
htp->io_ready = false;
|
||||
htp->do_file_io = true;
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_REQUEST_BODY:
|
||||
if (htp->io_done) {
|
||||
action = true;
|
||||
|
@ -313,6 +356,7 @@ bool HTTP_OP_SET::poll() {
|
|||
htp->do_file_io = false;
|
||||
htp->want_upload = false;
|
||||
htp->want_download = true;
|
||||
htp->io_ready = false;
|
||||
}
|
||||
case HTTP_STATE_REPLY_HEADER:
|
||||
if (htp->io_ready) {
|
||||
|
@ -349,22 +393,35 @@ bool HTTP_OP_SET::poll() {
|
|||
}
|
||||
htp->do_file_io = true;
|
||||
break;
|
||||
case HTTP_OP_POST2:
|
||||
htp->http_op_state = HTTP_STATE_REPLY_BODY;
|
||||
htp->io_ready = false;
|
||||
break;
|
||||
#if 0
|
||||
case HTTP_OP_PUT:
|
||||
htp->http_op_state = HTTP_STATE_DONE;
|
||||
htp->http_op_retval = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HTTP_STATE_REPLY_BODY:
|
||||
if (htp->io_done) {
|
||||
action = true;
|
||||
switch(htp->http_op_type) {
|
||||
case HTTP_OP_POST2:
|
||||
read_reply(htp->socket, htp->req1, 256);
|
||||
break;
|
||||
default:
|
||||
action = true;
|
||||
fclose(htp->file);
|
||||
htp->file = 0;
|
||||
break;
|
||||
}
|
||||
if (log_flags.http_debug) printf("got reply body\n");
|
||||
fclose(htp->file);
|
||||
htp->file = 0;
|
||||
htp->http_op_state = HTTP_STATE_DONE;
|
||||
htp->http_op_retval = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return action;
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
// Contributor(s):
|
||||
//
|
||||
|
||||
// HTTP_OP represents an HTTP operation.
|
||||
// There are variants for GET, POST etc.
|
||||
// as well as for the data source/sink.
|
||||
|
||||
#ifndef _HTTP_
|
||||
#define _HTTP_
|
||||
|
||||
|
@ -27,13 +31,16 @@ struct HTTP_REPLY_HEADER {
|
|||
int content_length;
|
||||
};
|
||||
|
||||
// For the first 4, data source/sink are files
|
||||
#define HTTP_OP_GET 1
|
||||
#define HTTP_OP_POST 2
|
||||
#define HTTP_OP_PUT 3
|
||||
//#define HTTP_OP_PUT 3
|
||||
#define HTTP_OP_HEAD 4
|
||||
#define HTTP_OP_POST2 5
|
||||
// a POST operation where the request comes from a combination
|
||||
// of a string and a file w/offset,
|
||||
// and the reply goes into a memory buffer
|
||||
|
||||
// represents an HTTP request in progress
|
||||
//
|
||||
class HTTP_OP : public NET_XFER {
|
||||
public:
|
||||
HTTP_OP();
|
||||
|
@ -41,10 +48,12 @@ public:
|
|||
|
||||
char hostname[256];
|
||||
char filename[256];
|
||||
char* req1;
|
||||
char infile[256];
|
||||
char outfile[256];
|
||||
int content_length;
|
||||
int offset;
|
||||
double file_offset;
|
||||
char request_header[256];
|
||||
HTTP_REPLY_HEADER hrh;
|
||||
int http_op_state; // values below
|
||||
int http_op_type;
|
||||
|
@ -53,7 +62,10 @@ public:
|
|||
int init_head(char* url);
|
||||
int init_get(char* url, char* outfile, int offset=0);
|
||||
int init_post(char* url, char* infile, char* outfile);
|
||||
int init_put(char* url, char* infile, int offset=0);
|
||||
int init_post2(
|
||||
char* url, char* req1, char* infile, double offset
|
||||
);
|
||||
//int init_put(char* url, char* infile, int offset=0);
|
||||
bool http_op_done();
|
||||
};
|
||||
|
||||
|
@ -73,10 +85,11 @@ public:
|
|||
#define HTTP_STATE_IDLE 0
|
||||
#define HTTP_STATE_CONNECTING 1
|
||||
#define HTTP_STATE_REQUEST_HEADER 2
|
||||
#define HTTP_STATE_REQUEST_BODY 3
|
||||
#define HTTP_STATE_REPLY_HEADER 4
|
||||
#define HTTP_STATE_REPLY_BODY 5
|
||||
#define HTTP_STATE_DONE 6
|
||||
#define HTTP_STATE_REQUEST_BODY1 3
|
||||
#define HTTP_STATE_REQUEST_BODY 4
|
||||
#define HTTP_STATE_REPLY_HEADER 5
|
||||
#define HTTP_STATE_REPLY_BODY 6
|
||||
#define HTTP_STATE_DONE 7
|
||||
|
||||
extern int read_http_reply_header(int socket, HTTP_REPLY_HEADER&);
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ int main(int argc, char** argv) {
|
|||
boinc_sleep(1);
|
||||
}
|
||||
if (cs.time_to_exit()) {
|
||||
printf("time to exit\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ int SCHEDULER_REPLY::parse(FILE* in) {
|
|||
apps.push_back(app);
|
||||
} else if (match_tag(buf, "<file_info>")) {
|
||||
FILE_INFO file_info;
|
||||
file_info.parse(in);
|
||||
file_info.parse(in, true);
|
||||
file_infos.push_back(file_info);
|
||||
} else if (match_tag(buf, "<app_version>")) {
|
||||
APP_VERSION av;
|
||||
|
@ -175,11 +175,11 @@ int SCHEDULER_REPLY::parse(FILE* in) {
|
|||
} else if (match_tag(buf, "<result>")) {
|
||||
RESULT result; // make sure this is here so constructor
|
||||
// gets called each time
|
||||
result.parse(in, "</result>");
|
||||
result.parse_server(in);
|
||||
results.push_back(result);
|
||||
} else if (match_tag(buf, "<result_ack>")) {
|
||||
RESULT result;
|
||||
result.parse(in, "</result_ack>");
|
||||
result.parse_ack(in);
|
||||
result_acks.push_back(result);
|
||||
} else if (parse_str(buf, "<message", message)) {
|
||||
parse_attr(buf, "priority", message_priority);
|
||||
|
|
|
@ -25,38 +25,69 @@
|
|||
#include "util.h"
|
||||
|
||||
#define DOWNLOAD_URL "http://localhost.localdomain/download/input"
|
||||
#define UPLOAD_URL "http://localhost.localdomain/upload/test_out.html"
|
||||
#define UPLOAD_URL "http://localhost.localdomain/boinc-cgi/file_upload_handler"
|
||||
|
||||
|
||||
int main() {
|
||||
NET_XFER_SET nxs;
|
||||
HTTP_OP_SET hos(&nxs);
|
||||
FILE_XFER_SET fxs(&hos);
|
||||
int retval, n;
|
||||
FILE_XFER* fx1=0, *fx2 = 0;
|
||||
bool do_upload = true;
|
||||
bool do_download = false;
|
||||
FILE_INFO fi1, fi2;
|
||||
STRING256 str;
|
||||
|
||||
FILE_XFER* fx1 = new FILE_XFER;
|
||||
retval = fx1->init_download(DOWNLOAD_URL, "test_fx_out");
|
||||
if (retval) {
|
||||
printf("init_download failed\n");
|
||||
exit(1);
|
||||
}
|
||||
FILE_XFER* fx2= new FILE_XFER;
|
||||
retval = fx2->init_upload(UPLOAD_URL, "test_fx_in");
|
||||
if (retval) {
|
||||
printf("init_upload failed\n");
|
||||
exit(1);
|
||||
if (do_download) {
|
||||
fx1 = new FILE_XFER;
|
||||
memset(&fi1, 0, sizeof(fi1));
|
||||
strcpy(fi1.name, "test_fx_out");
|
||||
strcpy(str.text, DOWNLOAD_URL);
|
||||
fi1.urls.push_back(str);
|
||||
retval = fx1->init_download(fi1);
|
||||
if (retval) {
|
||||
printf("init_download failed\n");
|
||||
exit(1);
|
||||
}
|
||||
retval = fxs.insert(fx1);
|
||||
if (retval) {
|
||||
printf("insert failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
retval = fxs.insert(fx1);
|
||||
if (retval) {
|
||||
printf("insert failed\n");
|
||||
exit(1);
|
||||
}
|
||||
retval = fxs.insert(fx2);
|
||||
if (retval) {
|
||||
printf("insert failed\n");
|
||||
exit(1);
|
||||
if (do_upload) {
|
||||
fx2= new FILE_XFER;
|
||||
memset(&fi2, 0, sizeof(fi1));
|
||||
strcpy(fi2.name, "test_fx_in");
|
||||
strcpy(str.text, UPLOAD_URL);
|
||||
fi2.urls.push_back(str);
|
||||
fi2.signed_xml = \
|
||||
" <name>uc_wu_1_0</name>\n"
|
||||
" <generated_locally/>\n"
|
||||
" <upload_when_present/>\n"
|
||||
" <max_nbytes>10000</max_nbytes>\n"
|
||||
" <url>http://localhost/upload/uc_wu_1_0</url>\n";
|
||||
fi2.signature = \
|
||||
"9d1f8152371c67af1d26b25db104014dbf7e9ad3b61fc8334ee06e01c7529b1a\n"
|
||||
"7681c3e7c7828525361a01040d1197147286085231ee5d2554e59ecb40b3e6a5\n"
|
||||
"afbaf00ff15bc5b1acf5aa6318bc84f2671a9502ada9c2ce37a9c45480a0e3b7\n"
|
||||
"b3dcb6c3bf09feaebc81b76063ef12b0031cf041eaef811166839533067b74f6\n"
|
||||
".\n";
|
||||
retval = fx2->init_upload(fi2);
|
||||
if (retval) {
|
||||
printf("init_upload failed\n");
|
||||
exit(1);
|
||||
}
|
||||
retval = fxs.insert(fx2);
|
||||
if (retval) {
|
||||
printf("insert failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (1) {
|
||||
nxs.poll(100000, n);
|
||||
hos.poll();
|
||||
|
|
|
@ -36,7 +36,7 @@ static MYSQL *mp;
|
|||
static MYSQL_RES *rp;
|
||||
static MYSQL_ROW row;
|
||||
|
||||
#define MAX_QUERY_LEN 4096
|
||||
#define MAX_QUERY_LEN 8192
|
||||
|
||||
int db_open(char* name) {
|
||||
mp = mysql_init(0);
|
||||
|
|
|
@ -19,16 +19,18 @@
|
|||
<li><a href=back_end.html>Back end examples</a>
|
||||
<li><a href=version.html>Versioning</a>
|
||||
<li><a href=api.html>The BOINC application library</a>
|
||||
<li><a href=graphics.html>Graphics</a>
|
||||
<li><a href=graphics.html>Client graphics</a>
|
||||
<li><a href=dev.html>Application development</a>
|
||||
|
||||
</ul>
|
||||
<h3>Operating a BOINC project</h3>
|
||||
<ul>
|
||||
<li><a href=install.html>Installing BOINC</a>
|
||||
<li><a href=project_startup.html>Project startup</a>
|
||||
<li><a href=master_url.html>The master URL</a>
|
||||
<li><a href=project_startup.html>Project startup checklist</a>
|
||||
<li><a href=database.html>The BOINC database</a>
|
||||
<li><a href=sched_server.html>The BOINC scheduling server</a>
|
||||
<li><a href=tools_security.html>Operational tools: security</a>
|
||||
<li><a href=tools_other.html>Operational tools: applications and versions</a>
|
||||
<li><a href=tools_work.html>Operational tools: work and results</a>
|
||||
<li><a href=web.html>The project web site</a>
|
||||
|
|
|
@ -12,7 +12,7 @@ The features of BOINC include:
|
|||
<ul>
|
||||
|
||||
<li> BOINC allows multiple independent projects
|
||||
to share a common set of participants.
|
||||
to share participants.
|
||||
Participants download a single <b>core client</b> program,
|
||||
which in turn downloads and executes project-specific executables.
|
||||
Participants can control how their resources are divided among the projects.
|
||||
|
@ -28,14 +28,18 @@ Work is dispatched only to hosts able to handle it.
|
|||
|
||||
<li> BOINC applications can be developed in any language (C++, Fortran, Perl).
|
||||
An application can consist of several files
|
||||
(e.g. several programs and a coordinating script).
|
||||
New versions of applications can be released without participant download.
|
||||
(e.g. multiple programs and a coordinating script).
|
||||
New versions of applications can be deployed without participant download.
|
||||
Separate alpha, beta, and production versions
|
||||
are distributed to the appropriate set of hosts.
|
||||
|
||||
<li> The BOINC core client can run on almost any platform
|
||||
(Mac, Windows, Linux and other Unix systems).
|
||||
|
||||
<li> A BOINC project must provide and maintain its own server systems,
|
||||
but these systems can be set up easily and involve
|
||||
only open-source components (MySQL, PHP, Apache, and Linux).
|
||||
|
||||
<li> BOINC is distributed under the Mozilla license.
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<h2>The master URL</h2>
|
||||
|
||||
<p>
|
||||
Each project is identified by a <b>master URL</b>.
|
||||
This URL is used to publicize the project.
|
||||
The <b>master page</b> at this URL has two functions.
|
||||
<ul>
|
||||
<li>
|
||||
It is the home page of the project;
|
||||
when viewed in a browser it describes the project
|
||||
and contains links for registering
|
||||
and for downloading the core client.
|
||||
<li>
|
||||
It contains XML tags of the form
|
||||
<pre>
|
||||
<scheduler>http:host.domain.edu/cgi/scheduler<scheduler>
|
||||
<scheduler>http:host2.domain.edu/cgi/scheduler<scheduler>
|
||||
</pre>
|
||||
that give the URLs of the project's scheduling servers.
|
||||
These tags can be embedded within HTML comments.
|
||||
The BOINC core client reads and parses the master page
|
||||
to find scheduler servers.
|
||||
If it is unable to connect to any scheduler server for a project,
|
||||
it rereads the master page.
|
||||
</ul>
|
||||
This mechanism lets a project change the locations of its scheduling servers,
|
||||
or add new servers.
|
|
@ -0,0 +1,25 @@
|
|||
<h3>Security tools</h3>
|
||||
|
||||
<p>
|
||||
The program <b>lib/crypt_prog</b> can be used for several purposes:
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<b>-genkey n private_keyfile public_keyfile</b>
|
||||
<br>
|
||||
Create a key pair with n bits (always use 1024).
|
||||
Write the keys in encoded ASCII form to the indicated files.
|
||||
<br>
|
||||
<b>-sign file private_keyfile</b>
|
||||
<br>
|
||||
Create a digital signature for the given file.
|
||||
Write it in encoded ASCII to stdout.
|
||||
<br>
|
||||
<b>-verify file signature_file public_keyfile</b>
|
||||
<br>
|
||||
Verify a signature for the given file.
|
||||
<br>
|
||||
<b>-test_crypt private_keyfile public_keyfile</b>
|
||||
<br>
|
||||
Perform an internal test, checking that encryption
|
||||
followed by decryption works.
|
|
@ -1,3 +1,7 @@
|
|||
<h3>Test BOINC Project</h3>
|
||||
|
||||
<scheduler>http://localhost/boinc-cgi/cgi</scheduler>
|
||||
|
||||
<br><a href=login.php>Log in or create account</a>
|
||||
<br><a href=home.php>User page</a>
|
||||
<br><a href=download.php>Download core client</a>
|
||||
|
|
|
@ -11,6 +11,10 @@ CC = @CC@ $(CFLAGS) -I ../RSAEuro/source
|
|||
|
||||
PROGS = md5_test shmem_test synch_test crypt_prog
|
||||
|
||||
OBJS = \
|
||||
countries.o \
|
||||
parse.o
|
||||
|
||||
MD5_OBJS = \
|
||||
md5.o \
|
||||
md5_file.o
|
||||
|
@ -25,7 +29,7 @@ CRYPT_LIBS = \
|
|||
COUNTRY_OBJS = \
|
||||
countries.o
|
||||
|
||||
all: $(PROGS) $(MD5_OBJS) $(CRYPT_OBJS)
|
||||
all: $(PROGS) $(OBJS) $(MD5_OBJS) $(CRYPT_OBJS)
|
||||
|
||||
.C.o:
|
||||
$(CC) -c -o $*.o $<
|
||||
|
|
97
lib/crypt.C
97
lib/crypt.C
|
@ -1,14 +1,10 @@
|
|||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "rsaeuro.h"
|
||||
extern "C" {
|
||||
#include "rsa.h"
|
||||
}
|
||||
#include "md5_file.h"
|
||||
#include "crypt.h"
|
||||
|
||||
// print some data in hex notation.
|
||||
// write some data in hex notation.
|
||||
// NOTE: since length may not be known to the reader,
|
||||
// we follow the data with a non-hex character '.'
|
||||
//
|
||||
|
@ -23,6 +19,22 @@ int print_hex_data(FILE* f, DATA_BLOCK& x) {
|
|||
fprintf(f, ".\n");
|
||||
}
|
||||
|
||||
// same, but write to buffer
|
||||
//
|
||||
int sprint_hex_data(char* p, DATA_BLOCK& x) {
|
||||
int i;
|
||||
char buf[16];
|
||||
|
||||
strcpy(p, "");
|
||||
for (i=0; i<x.len; i++) {
|
||||
sprintf(buf, "%02x", x.data[i]);
|
||||
strcat(p, buf);
|
||||
if (i%32==31) strcat(p, "\n");
|
||||
}
|
||||
if (x.len%32 != 0) strcat(p, "\n");
|
||||
strcat(p, ".\n");
|
||||
}
|
||||
|
||||
// scan data in hex notation.
|
||||
// stop when you reach a non-parsed character.
|
||||
// NOTE: buffer must be big enough.
|
||||
|
@ -38,6 +50,21 @@ int scan_hex_data(FILE* f, DATA_BLOCK& x) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// same, but read from buffer
|
||||
//
|
||||
int sscan_hex_data(char* p, DATA_BLOCK& x) {
|
||||
int n;
|
||||
x.len = 0;
|
||||
while (1) {
|
||||
n = sscanf(p, "%2x", x.data+x.len);
|
||||
if (n <= 0) break;
|
||||
x.len++;
|
||||
p += 2;
|
||||
if (*p == '\n') p++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// print a key in ASCII form
|
||||
//
|
||||
int print_key_hex(FILE* f, KEY* key, int size) {
|
||||
|
@ -52,12 +79,13 @@ int print_key_hex(FILE* f, KEY* key, int size) {
|
|||
}
|
||||
|
||||
int scan_key_hex(FILE* f, KEY* key, int size) {
|
||||
int len, i;
|
||||
int len, i, n;
|
||||
|
||||
fscanf(f, "%d", &key->bits);
|
||||
len = size - sizeof(key->bits);
|
||||
for (i=0; i<len; i++) {
|
||||
fscanf(f, "%2x", key->data+i);
|
||||
fscanf(f, "%2x", &n);
|
||||
key->data[i] = n;
|
||||
}
|
||||
fscanf(f, ".");
|
||||
return 0;
|
||||
|
@ -72,14 +100,15 @@ int encrypt_private(
|
|||
R_RSA_PRIVATE_KEY& key, DATA_BLOCK& in, DATA_BLOCK& out,
|
||||
int& nbytes_encrypted
|
||||
) {
|
||||
int retval, n;
|
||||
int retval, n, modulus_len;
|
||||
modulus_len = (key.bits+7)/8;
|
||||
n = in.len;
|
||||
if (n >= key.bits-11) {
|
||||
n = key.bits-11;
|
||||
if (n >= modulus_len-11) {
|
||||
n = modulus_len-11;
|
||||
}
|
||||
retval = RSAPrivateEncrypt(out.data, &out.len, in.data, n, &key);
|
||||
if (retval) return retval;
|
||||
nbytes_encrypted = n;
|
||||
if (retval ) return retval;
|
||||
nbytes_encrypted = retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -88,7 +117,7 @@ int decrypt_public(R_RSA_PUBLIC_KEY& key, DATA_BLOCK& in, DATA_BLOCK& out) {
|
|||
}
|
||||
|
||||
int sign_file(char* path, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) {
|
||||
char md5_buf[64];
|
||||
char md5_buf[MD5_LEN];
|
||||
double file_length;
|
||||
DATA_BLOCK in_block;
|
||||
int retval, n;
|
||||
|
@ -102,10 +131,26 @@ int sign_file(char* path, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sign_block(DATA_BLOCK& data_block, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) {
|
||||
char md5_buf[MD5_LEN];
|
||||
int retval, n;
|
||||
DATA_BLOCK in_block;
|
||||
|
||||
md5_block(data_block.data, data_block.len, md5_buf);
|
||||
in_block.data = (unsigned char*)md5_buf;
|
||||
in_block.len = strlen(md5_buf);
|
||||
retval = encrypt_private(key, in_block, signature, n);
|
||||
if (retval) {
|
||||
printf("sign_block: encrypt_private returned %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verify_file(
|
||||
char* path, R_RSA_PUBLIC_KEY& key, DATA_BLOCK& signature, bool& answer
|
||||
) {
|
||||
char md5_buf[64], clear_buf[256];
|
||||
char md5_buf[MD5_LEN], clear_buf[256];
|
||||
double file_length;
|
||||
int n, retval;
|
||||
DATA_BLOCK clear_signature;
|
||||
|
@ -120,3 +165,27 @@ int verify_file(
|
|||
answer = !strncmp(md5_buf, clear_buf, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// verify, where both text and signature are char strings
|
||||
//
|
||||
int verify_string(
|
||||
char* text, char* signature_text, R_RSA_PUBLIC_KEY& key, bool& answer
|
||||
) {
|
||||
char md5_buf[MD5_LEN];
|
||||
unsigned char signature_buf[SIGNATURE_SIZE];
|
||||
char clear_buf[MD5_LEN];
|
||||
int retval, n;
|
||||
DATA_BLOCK signature, clear_signature;
|
||||
|
||||
retval = md5_block((unsigned char*)text, strlen(text), md5_buf);
|
||||
if (retval) return retval;
|
||||
n = strlen(md5_buf);
|
||||
signature.data = signature_buf;
|
||||
sscan_hex_data(signature_text, signature);
|
||||
clear_signature.data = (unsigned char*)clear_buf;
|
||||
clear_signature.len = 256;
|
||||
retval = decrypt_public(key, signature, clear_signature);
|
||||
if (retval) return retval;
|
||||
answer = !strncmp(md5_buf, clear_buf, n);
|
||||
return 0;
|
||||
}
|
||||
|
|
17
lib/crypt.h
17
lib/crypt.h
|
@ -1,5 +1,12 @@
|
|||
#ifndef _CRYPT_
|
||||
#define _CRYPT_
|
||||
// some interface functions for RSAEuro
|
||||
|
||||
#include "rsaeuro.h"
|
||||
extern "C" {
|
||||
#include "rsa.h"
|
||||
}
|
||||
|
||||
struct KEY {
|
||||
unsigned short int bits;
|
||||
unsigned char data[1];
|
||||
|
@ -12,8 +19,14 @@ struct DATA_BLOCK {
|
|||
|
||||
#define MIN_OUT_BUFFER_SIZE MAX_RSA_MODULUS_LEN+1
|
||||
|
||||
// the size of a signature (encrypted MD5)
|
||||
//
|
||||
#define SIGNATURE_SIZE MIN_OUT_BUFFER_SIZE
|
||||
|
||||
int print_hex_data(FILE* f, DATA_BLOCK&);
|
||||
int sprint_hex_data(char* p, DATA_BLOCK&);
|
||||
int scan_hex_data(FILE* f, DATA_BLOCK&);
|
||||
int sscan_hex_data(char* p, DATA_BLOCK&);
|
||||
int print_key_hex(FILE*, KEY* key, int len);
|
||||
int scan_key_hex(FILE*, KEY* key, int len);
|
||||
int encrypt_private(
|
||||
|
@ -21,4 +34,8 @@ int encrypt_private(
|
|||
);
|
||||
int decrypt_public(R_RSA_PUBLIC_KEY& key, DATA_BLOCK& in, DATA_BLOCK& out);
|
||||
int sign_file(char* path, R_RSA_PRIVATE_KEY&, DATA_BLOCK& signature);
|
||||
int sign_block(DATA_BLOCK& data, R_RSA_PRIVATE_KEY&, DATA_BLOCK& signature);
|
||||
int verify_file(char* path, R_RSA_PUBLIC_KEY&, DATA_BLOCK& signature, bool&);
|
||||
int verify_string(char* text, char* signature, R_RSA_PUBLIC_KEY&, bool&);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
// utility program for encryption.
|
||||
//
|
||||
// -genkey n private_keyfile public_keyfile
|
||||
// create a key pair with n bits (512 <= n <= 2048)
|
||||
// create a key pair with n bits (512 <= n <= 1024)
|
||||
// write it in hex notation
|
||||
// -sign file private_keyfile
|
||||
// create a signature for a given file
|
||||
// write it in hex notation
|
||||
// -verify file signature_file public_keyfile
|
||||
// verify a signature
|
||||
// -crypt_test private_keyfile public_keyfile
|
||||
// -test_crypt private_keyfile public_keyfile
|
||||
// test encrypt/decrypt
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -50,6 +50,7 @@ main(int argc, char** argv) {
|
|||
);
|
||||
if (retval) die("R_GeneratePEMKeys\n");
|
||||
|
||||
printf("creating keys in %s and %s\n", argv[3], argv[4]);
|
||||
fpriv = fopen(argv[3], "w");
|
||||
if (!fpriv) die("fopen");
|
||||
fpub = fopen(argv[4], "w");
|
||||
|
|
|
@ -32,3 +32,18 @@ int md5_file(char* path, char* output, double& nbytes) {
|
|||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int md5_block(unsigned char* data, int nbytes, char* output) {
|
||||
unsigned char binout[16];
|
||||
int i;
|
||||
|
||||
md5_state_t state;
|
||||
md5_init(&state);
|
||||
md5_append(&state, data, nbytes);
|
||||
md5_finish(&state, binout);
|
||||
for (i=0; i<16; i++) {
|
||||
sprintf(output+2*i, "%02x", binout[i]);
|
||||
}
|
||||
output[32] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
// length of buffer to hold an MD5 hash
|
||||
#define MD5_LEN 64
|
||||
|
||||
extern int md5_file(char* path, char* output, double& nbytes);
|
||||
extern int md5_block(unsigned char* data, int nbytes, char* output);
|
||||
|
|
15
lib/parse.C
15
lib/parse.C
|
@ -87,18 +87,25 @@ void copy_stream(FILE* in, FILE* out) {
|
|||
}
|
||||
}
|
||||
|
||||
void strcatdup(char*& p, char* buf) {
|
||||
p = (char*)realloc(p, strlen(p) + strlen(buf)+1);
|
||||
if (!p) {
|
||||
fprintf(stderr, "strcatdup: realloc failed\n");
|
||||
exit(1);
|
||||
}
|
||||
strcat(p, buf);
|
||||
}
|
||||
|
||||
int dup_element_contents(FILE* in, char* end_tag, char** pp) {
|
||||
char buf[256];
|
||||
|
||||
char* p = (char*)malloc(1);
|
||||
*p = 0;
|
||||
char* p = strdup("");
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (strstr(buf, end_tag)) {
|
||||
*pp = p;
|
||||
return 0;
|
||||
}
|
||||
p = (char*)realloc(p, strlen(p) + strlen(buf)+1);
|
||||
strcat(p, buf);
|
||||
strcatdup(p, buf);
|
||||
}
|
||||
fprintf(stderr, "dup_element_contents(): no end tag\n");
|
||||
return 1;
|
||||
|
|
|
@ -26,4 +26,5 @@ extern bool parse_str(char*, char*, char*);
|
|||
extern void parse_attr(char* buf, char* attrname, char* out);
|
||||
extern bool match_tag(char*, char*);
|
||||
extern void copy_stream(FILE* in, FILE* out);
|
||||
extern void strcatdup(char*& p, char* buf);
|
||||
extern int dup_element_contents(FILE* in, char* end_tag, char** pp);
|
||||
|
|
|
@ -5,12 +5,18 @@ VPATH = @srcdir@
|
|||
|
||||
all: cgi
|
||||
|
||||
CFLAGS = -g -Wall @DEFS@ -I@top_srcdir@/db -I@top_srcdir@/lib -I@top_srcdir@/tools -I/usr/local/mysql/include
|
||||
CFLAGS = -g -Wall @DEFS@ \
|
||||
-I@top_srcdir@/db \
|
||||
-I@top_srcdir@/lib \
|
||||
-I@top_srcdir@/RSAEuro/source \
|
||||
-I@top_srcdir@/tools \
|
||||
-I/usr/local/mysql/include
|
||||
|
||||
CC = g++ $(CFLAGS)
|
||||
|
||||
CLIBS = @LIBS@
|
||||
|
||||
PROGS = cgi feeder show_shmem fcgi
|
||||
PROGS = cgi feeder show_shmem file_upload_handler fcgi
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
|
@ -22,8 +28,7 @@ CGI_OBJS = \
|
|||
../db/db_mysql.o \
|
||||
../db/mysql_util.o \
|
||||
../lib/shmem.o \
|
||||
../lib/parse.o \
|
||||
../tools/process_result_template.o
|
||||
../lib/parse.o
|
||||
|
||||
FEEDER_OBJS = \
|
||||
feeder.o \
|
||||
|
@ -39,6 +44,14 @@ SHOW_SHMEM_OBJS = \
|
|||
../db/mysql_util.o \
|
||||
../lib/shmem.o
|
||||
|
||||
FILE_UPLOAD_OBJS = \
|
||||
file_upload_handler.o \
|
||||
../lib/crypt.o \
|
||||
../lib/parse.o \
|
||||
../lib/md5.o \
|
||||
../lib/md5_file.o \
|
||||
../RSAEuro/source/rsaeuro.a
|
||||
|
||||
FCGI_OBJS = \
|
||||
handle_request.fcgi.o \
|
||||
main.fcgi.o \
|
||||
|
@ -76,6 +89,9 @@ feeder: $(FEEDER_OBJS)
|
|||
show_shmem: $(SHOW_SHMEM_OBJS)
|
||||
$(CC) $(SHOW_SHMEM_OBJS) $(MYSQL_LIBS) $(CLIBS) -o show_shmem
|
||||
|
||||
file_upload_handler: $(FILE_UPLOAD_OBJS)
|
||||
$(CC) $(FILE_UPLOAD_OBJS) $(CLIBS) -o file_upload_handler
|
||||
|
||||
fcgi: $(FCGI_OBJS)
|
||||
$(CC) $(FCGI_OBJS) $(MYSQL_LIBS) $(CLIBS) $(FCGI_LIBS) \
|
||||
-o fcgi
|
||||
|
|
|
@ -1,11 +1,192 @@
|
|||
// The input to this program looks like this:
|
||||
//
|
||||
// <result>
|
||||
// <file_info>...</file_info>
|
||||
// <file_info>
|
||||
// ...
|
||||
// <signature>
|
||||
// ...
|
||||
// </signature>
|
||||
// </result>
|
||||
// <filename>blah</filename>
|
||||
// <signature>
|
||||
// ...
|
||||
// </signature>
|
||||
// </file_info>
|
||||
// <nbytes>x</nbytes>
|
||||
// <offset>x</offset>
|
||||
// <data>
|
||||
// ... (data)
|
||||
//
|
||||
// The return looks like
|
||||
//
|
||||
// <status>0</status>
|
||||
// or
|
||||
// <status>2</status>
|
||||
// <error>bad file size</error>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "parse.h"
|
||||
#include "crypt.h"
|
||||
|
||||
#define BOINC_UPLOAD_DIR "/home/david/html/upload"
|
||||
#define BOINC_PUBLIC_KEY_PATH "/home/david/boinc_keys/upload_public"
|
||||
|
||||
#define MAX_FILES 32
|
||||
|
||||
struct FILE_INFO {
|
||||
char name[256];
|
||||
double max_nbytes;
|
||||
char* signature;
|
||||
char* signed_xml;
|
||||
int parse(FILE*);
|
||||
};
|
||||
|
||||
int FILE_INFO::parse(FILE* in) {
|
||||
char buf[256];
|
||||
int retval;
|
||||
|
||||
memset(this, 0, sizeof(FILE_INFO));
|
||||
signed_xml = strdup("");
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "</file_info>")) return 0;
|
||||
else if (match_tag(buf, "<signature>")) {
|
||||
retval = dup_element_contents(in, "</signature>", &signature);
|
||||
if (retval) return retval;
|
||||
continue;
|
||||
}
|
||||
strcatdup(signed_xml, buf);
|
||||
if (parse_str(buf, "<name>", name)) continue;
|
||||
if (parse_double(buf, "<max_nbytes>", max_nbytes)) continue;
|
||||
//fprintf(stderr, "FILE_INFO::parse: unrecognized: %s \n", buf);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int print_status(int status, char* message) {
|
||||
printf("Content-type: text/plain\n\n<status>%d</status>\n", status);
|
||||
if (message) printf("<error>%s</error>\n", message);
|
||||
#if 0
|
||||
fprintf(stderr, "Content-type: text/plain\n\n<status>%d</status>\n", status);
|
||||
if (message) fprintf(stderr, "<error>%s</error>\n", message);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BLOCK_SIZE 16382
|
||||
|
||||
// read from socket, write to file
|
||||
//
|
||||
int read_file(FILE* in, char* path, double offset, double nbytes) {
|
||||
unsigned char buf[BLOCK_SIZE];
|
||||
FILE* out;
|
||||
int retval, n, m;
|
||||
double bytes_left;
|
||||
|
||||
out = fopen(path, "wb");
|
||||
if (!out) {
|
||||
print_status(-1, "can't open file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: use a 64-bit variant
|
||||
retval = fseek(out, (long)offset, SEEK_SET);
|
||||
if (retval) {
|
||||
fclose(out);
|
||||
print_status(-1, "can't fseek file");
|
||||
return retval;
|
||||
}
|
||||
bytes_left = nbytes - offset;
|
||||
while (1) {
|
||||
m = BLOCK_SIZE;
|
||||
if (m > bytes_left) m = (int)bytes_left;
|
||||
n = fread(buf, 1, m, in);
|
||||
if (n <= 0) {
|
||||
print_status(-1, "can't fread socket");
|
||||
return -1;
|
||||
}
|
||||
m = fwrite(buf, 1, n, out);
|
||||
if (m != n) {
|
||||
print_status(-1, "can't fwrite file");
|
||||
return -1;
|
||||
}
|
||||
bytes_left -= n;
|
||||
if (bytes_left == 0) break;
|
||||
}
|
||||
fclose(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_request(FILE* in, R_RSA_PUBLIC_KEY& key) {
|
||||
char buf[256];
|
||||
double nbytes=0, offset=0;
|
||||
char path[256];
|
||||
FILE_INFO file_info;
|
||||
int retval;
|
||||
bool is_valid;
|
||||
|
||||
while (fgets(buf, 256, in)) {
|
||||
if (match_tag(buf, "<file_info>")) {
|
||||
retval = file_info.parse(in);
|
||||
if (retval) return retval;
|
||||
retval = verify_string(
|
||||
file_info.signed_xml, file_info.signature, key, is_valid
|
||||
);
|
||||
if (retval || !is_valid) {
|
||||
print_status(-1, "invalid signature");
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (parse_double(buf, "<offset>", offset)) continue;
|
||||
else if (parse_double(buf, "<nbytes>", nbytes)) continue;
|
||||
else if (match_tag(buf, "<data>")) {
|
||||
if (nbytes == 0) {
|
||||
print_status(-1, "nbytes missing");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// enforce limits in signed XML
|
||||
if (nbytes > file_info.max_nbytes) {
|
||||
sprintf(buf,
|
||||
"nbytes too large: %f > %d",
|
||||
nbytes, file_info.max_nbytes
|
||||
);
|
||||
print_status(-1, buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sprintf(path, "%s/%s", BOINC_UPLOAD_DIR, file_info.name);
|
||||
retval = read_file(in, path, offset, nbytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_key(R_RSA_PUBLIC_KEY& key) {
|
||||
FILE* f;
|
||||
int retval;
|
||||
|
||||
f = fopen(BOINC_PUBLIC_KEY_PATH, "r");
|
||||
if (!f) return -1;
|
||||
retval = scan_key_hex(f, (KEY*)&key, sizeof(key));
|
||||
fclose(f);
|
||||
if (retval) return retval;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
int retval;
|
||||
R_RSA_PUBLIC_KEY key;
|
||||
|
||||
retval = get_key(key);
|
||||
if (retval) {
|
||||
fprintf(stderr, "can't read key file\n");
|
||||
print_status(-1, "can't read key file");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
retval = handle_request(stdin, key);
|
||||
if (retval) {
|
||||
fprintf(stderr, "handle_request: %d\n", retval);
|
||||
} else {
|
||||
print_status(0, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -57,10 +57,7 @@ int SCHEDULER_REQUEST::parse(FILE* fin) {
|
|||
else if (match_tag(buf, "<preferences>")) {
|
||||
while (fgets(buf, 256, fin)) {
|
||||
if (strstr(buf, "</preferences>")) break;
|
||||
prefs_xml = (char*)realloc(
|
||||
prefs_xml, strlen(prefs_xml) + strlen(buf)+1
|
||||
);
|
||||
strcat(prefs_xml, buf);
|
||||
strcatdup(prefs_xml, buf);
|
||||
}
|
||||
}
|
||||
else if (match_tag(buf, "<host_info>")) {
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<name><OUTFILE_0/></name>
|
||||
<generated_locally/>
|
||||
<upload_when_present/>
|
||||
<url><UPLOAD_URL/><OUTFILE_0/></url>
|
||||
<url><UPLOAD_URL/></url>
|
||||
<max_nbytes>100000</max_nbytes>
|
||||
</file_info>
|
||||
<result>
|
||||
<name><RESULT_NAME/></name>
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<name><OUTFILE_0/></name>
|
||||
<generated_locally/>
|
||||
<upload_when_present/>
|
||||
<url><UPLOAD_URL/><OUTFILE_0/></url>
|
||||
<url><UPLOAD_URL/></url>
|
||||
<max_nbytes>100000</max_nbytes>
|
||||
</file_info>
|
||||
<result>
|
||||
<name><RESULT_NAME/></name>
|
||||
|
|
|
@ -23,6 +23,7 @@ $BOINC_UPLOAD_DIR = null;
|
|||
$BOINC_PLATFORM = null;
|
||||
$BOINC_EMAIL = null;
|
||||
$BOINC_URL_BASE = null;
|
||||
$BOINC_KEY_DIR = null;
|
||||
|
||||
function check_env_vars() {
|
||||
global $BOINC_DOWNLOAD_DIR;
|
||||
|
@ -30,6 +31,7 @@ function check_env_vars() {
|
|||
global $BOINC_PLATFORM;
|
||||
global $BOINC_EMAIL;
|
||||
global $BOINC_URL_BASE;
|
||||
global $BOINC_KEY_DIR;
|
||||
|
||||
$bad = false;
|
||||
$BOINC_DOWNLOAD_DIR = getenv("BOINC_DOWNLOAD_DIR");
|
||||
|
@ -57,8 +59,14 @@ function check_env_vars() {
|
|||
echo "Must define BOINC_URL_BASE\n";
|
||||
$bad = true;
|
||||
}
|
||||
$BOINC_KEY_DIR = getenv("BOINC_KEY_DIR");
|
||||
if ($BOINC_KEY_DIR == null) {
|
||||
echo "Must define BOINC_KEY_DIR\n";
|
||||
$bad = true;
|
||||
}
|
||||
if ($bad) exit();
|
||||
}
|
||||
|
||||
function clear_data_dirs() {
|
||||
global $BOINC_DOWNLOAD_DIR;
|
||||
global $BOINC_UPLOAD_DIR;
|
||||
|
@ -73,10 +81,16 @@ function clear_data_dirs() {
|
|||
echo "Must define BOINC_UPLOAD_DIR\n";
|
||||
$bad = true;
|
||||
}
|
||||
$BOINC_KEY_DIR = getenv("BOINC_KEY_DIR");
|
||||
if ($BOINC_KEY_DIR == null) {
|
||||
echo "Must define BOINC_KEY_DIR\n";
|
||||
$bad = true;
|
||||
}
|
||||
if ($bad) exit();
|
||||
|
||||
PassThru("rm -f $BOINC_DOWNLOAD_DIR/*");
|
||||
PassThru("rm -f $BOINC_UPLOAD_DIR/*");
|
||||
PassThru("rm -f $BOINC_KEY_DIR/*");
|
||||
}
|
||||
|
||||
function init_client_dirs($prefs_file) {
|
||||
|
@ -143,7 +157,13 @@ function add_app($name) {
|
|||
}
|
||||
|
||||
function create_work($x) {
|
||||
PassThru("../tools/create_work $x");
|
||||
global $BOINC_KEY_DIR;
|
||||
PassThru("../tools/create_work -keyfile $BOINC_KEY_DIR/upload_private $x");
|
||||
}
|
||||
|
||||
function create_keys() {
|
||||
global $BOINC_KEY_DIR;
|
||||
PassThru("../lib/crypt_prog -genkey 1024 $BOINC_KEY_DIR/upload_private $BOINC_KEY_DIR/upload_public");
|
||||
}
|
||||
|
||||
function run_client($args) {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<h3>Test BOINC Project</h3>
|
||||
|
||||
<scheduler>http://localhost/boinc-cgi/cgi</scheduler>
|
|
@ -2,7 +2,8 @@
|
|||
<name><OUTFILE_0/></name>
|
||||
<generated_locally/>
|
||||
<upload_when_present/>
|
||||
<url><UPLOAD_URL/><OUTFILE_0/></url>
|
||||
<url><UPLOAD_URL/></url>
|
||||
<max_nbytes>100000</max_nbytes>
|
||||
</file_info>
|
||||
<result>
|
||||
<name><RESULT_NAME/></name>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs2.xml");
|
||||
add_platform();
|
||||
add_core_client();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("input");
|
||||
add_platform(null);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("input");
|
||||
add_platform();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("small_input");
|
||||
add_platform();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("small_input");
|
||||
add_platform();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("small_input");
|
||||
add_platform();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("small_input");
|
||||
add_platform();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs2.xml");
|
||||
copy_to_download_dir("small_input");
|
||||
add_platform();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("input");
|
||||
add_platform();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("input");
|
||||
add_platform(null);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
check_env_vars();
|
||||
clear_db();
|
||||
clear_data_dirs();
|
||||
create_keys();
|
||||
init_client_dirs("prefs1.xml");
|
||||
copy_to_download_dir("small_input");
|
||||
add_platform(null);
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<name><OUTFILE_0/></name>
|
||||
<generated_locally/>
|
||||
<upload_when_present/>
|
||||
<url><UPLOAD_URL/><OUTFILE_0/></url>
|
||||
<max_nbytes>100000</max_nbytes>
|
||||
<url><UPLOAD_URL/></url>
|
||||
</file_info>
|
||||
<result>
|
||||
<name><RESULT_NAME/></name>
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<name><OUTFILE_0/></name>
|
||||
<generated_locally/>
|
||||
<upload_when_present/>
|
||||
<url><UPLOAD_URL/><OUTFILE_0/></url>
|
||||
<url><UPLOAD_URL/></url>
|
||||
<max_nbytes>100000</max_nbytes>
|
||||
</file_info>
|
||||
<result>
|
||||
<name><RESULT_NAME/></name>
|
||||
|
|
|
@ -10,11 +10,16 @@ MYSQL_INC = /usr/local/mysql/include
|
|||
CFLAGS = -g -Wall @DEFS@ \
|
||||
-DHOSTTYPE=\"@host@\" \
|
||||
-DVERSION=$(VERSION) \
|
||||
-I @top_srcdir@/lib -I @top_srcdir@/db -I $(MYSQL_INC)
|
||||
-I @top_srcdir@/lib \
|
||||
-I @top_srcdir@/RSAEuro/source \
|
||||
-I @top_srcdir@/db \
|
||||
-I $(MYSQL_INC)
|
||||
|
||||
CC = @CC@ $(CFLAGS)
|
||||
|
||||
CLIBS = @LIBS@
|
||||
CLIBS = @LIBS@ \
|
||||
../lib/crypt.o \
|
||||
../RSAEuro/source/rsaeuro.a
|
||||
|
||||
OBJS = \
|
||||
backend_lib.o \
|
||||
|
@ -34,6 +39,7 @@ LIBS = \
|
|||
process_result_template.o \
|
||||
../lib/md5_file.o \
|
||||
../lib/md5.o \
|
||||
../lib/parse.o \
|
||||
../db/db_mysql.o \
|
||||
../db/mysql_util.o
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ void add_user() {
|
|||
strcpy(user.country, "United States");
|
||||
strcpy(user.postal_code, "94703");
|
||||
if (prefs_file) {
|
||||
retval = read_file(prefs_file, user.prefs);
|
||||
retval = read_filename(prefs_file, user.prefs);
|
||||
if (retval) {
|
||||
printf("read_file: %s", prefs_file);
|
||||
return;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "crypt.h"
|
||||
#include "md5_file.h"
|
||||
|
||||
#include "backend_lib.h"
|
||||
|
@ -33,18 +34,25 @@
|
|||
#define OUTFILE_MACRO "<OUTFILE_"
|
||||
#define UPLOAD_URL_MACRO "<UPLOAD_URL/>"
|
||||
#define DOWNLOAD_URL_MACRO "<DOWNLOAD_URL/>"
|
||||
#define UPLOAD_URL "http://localhost/upload/"
|
||||
#define UPLOAD_URL "http://localhost/boinc-cgi/file_upload_handler"
|
||||
#define DOWNLOAD_URL "http://localhost/download/"
|
||||
|
||||
int read_file(char* path, char* buf) {
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) return -1;
|
||||
int read_file(FILE* f, char* buf) {
|
||||
int n = fread(buf, 1, MAX_BLOB_SIZE, f);
|
||||
buf[n] = 0;
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_filename(char* path, char* buf) {
|
||||
int retval;
|
||||
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) return -1;
|
||||
retval = read_file(f, buf);
|
||||
fclose(f);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// replace INFILE_x with filename from array,
|
||||
// MD5_x with checksum of file,
|
||||
// WU_NAME with WU name
|
||||
|
@ -114,10 +122,13 @@ static int process_wu_template(
|
|||
return 0;
|
||||
}
|
||||
|
||||
int create_result(WORKUNIT& wu, char* result_template, int i) {
|
||||
int create_result(
|
||||
WORKUNIT& wu, char* result_template_filename, int i, R_RSA_PRIVATE_KEY& key
|
||||
) {
|
||||
RESULT r;
|
||||
char base_outfile_name[256];
|
||||
int retval;
|
||||
FILE* result_template_file, *tempfile;
|
||||
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.create_time = time(0);
|
||||
|
@ -125,23 +136,35 @@ int create_result(WORKUNIT& wu, char* result_template, int i) {
|
|||
r.state = RESULT_STATE_UNSENT;
|
||||
sprintf(r.name, "%s_%d", wu.name, i);
|
||||
sprintf(base_outfile_name, "%s_", r.name);
|
||||
strcpy(r.xml_doc_in, result_template);
|
||||
|
||||
result_template_file = fopen(result_template_filename, "r");
|
||||
tempfile = tmpfile();
|
||||
retval = process_result_template(
|
||||
r.xml_doc_in, base_outfile_name, wu.name, r.name
|
||||
result_template_file,
|
||||
tempfile,
|
||||
key,
|
||||
base_outfile_name, wu.name, r.name
|
||||
);
|
||||
rewind(tempfile);
|
||||
read_file(tempfile, r.xml_doc_in);
|
||||
fclose(tempfile);
|
||||
|
||||
retval = db_result_new(r);
|
||||
if (retval) {
|
||||
fprintf(stderr, "db_result_new: %d\n", retval);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
int create_work(
|
||||
WORKUNIT& wu,
|
||||
char* wu_template,
|
||||
char* result_template,
|
||||
char* result_template_file,
|
||||
int nresults,
|
||||
char* infile_dir,
|
||||
char** infiles,
|
||||
int ninfiles
|
||||
int ninfiles,
|
||||
R_RSA_PRIVATE_KEY& key
|
||||
) {
|
||||
int i, retval;
|
||||
|
||||
|
@ -160,7 +183,7 @@ int create_work(
|
|||
|
||||
if (!wu.dynamic_results) {
|
||||
for (i=0; i<nresults; i++) {
|
||||
create_result(wu, result_template, i);
|
||||
create_result(wu, result_template_file, i, key);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -17,11 +17,16 @@
|
|||
// Contributor(s):
|
||||
//
|
||||
|
||||
#include "crypt.h"
|
||||
|
||||
extern int process_result_template(
|
||||
char* tmplate, char* base_filename, char* wu_name, char* result_name
|
||||
FILE* in, FILE* out,
|
||||
R_RSA_PRIVATE_KEY& key,
|
||||
char* base_filename, char* wu_name, char* result_name
|
||||
);
|
||||
|
||||
extern int read_file(char* path, char* buf);
|
||||
extern int read_file(FILE*, char* buf);
|
||||
extern int read_filename(char* path, char* buf);
|
||||
|
||||
extern int create_work(
|
||||
WORKUNIT& wu,
|
||||
|
@ -30,5 +35,6 @@ extern int create_work(
|
|||
int nresults,
|
||||
char* infile_dir,
|
||||
char** infiles,
|
||||
int ninfiles
|
||||
int ninfiles,
|
||||
R_RSA_PRIVATE_KEY&
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
// -wu_template filename
|
||||
// -result_template filename
|
||||
// -nresults n
|
||||
// -keyfile path
|
||||
// infile1 infile2 ...
|
||||
//
|
||||
// Create a workunit and results.
|
||||
|
@ -43,6 +44,7 @@
|
|||
#include <time.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "crypt.h"
|
||||
#include "backend_lib.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
@ -52,8 +54,10 @@ int main(int argc, char** argv) {
|
|||
char wu_template[MAX_BLOB_SIZE];
|
||||
char result_template[MAX_BLOB_SIZE];
|
||||
char wu_template_file[256], result_template_file[256];
|
||||
char keyfile[256];
|
||||
char** infiles;
|
||||
int i, ninfiles, nresults;
|
||||
R_RSA_PRIVATE_KEY key;
|
||||
char* boinc_download_dir = getenv("BOINC_DOWNLOAD_DIR");
|
||||
|
||||
srand(time(NULL));
|
||||
|
@ -68,6 +72,7 @@ int main(int argc, char** argv) {
|
|||
strcpy(wu_template_file, "");
|
||||
strcpy(result_template_file, "");
|
||||
strcpy(app.name, "");
|
||||
strcpy(keyfile, "");
|
||||
nresults = 1;
|
||||
i = 1;
|
||||
ninfiles = 0;
|
||||
|
@ -101,7 +106,10 @@ int main(int argc, char** argv) {
|
|||
wu.rsc_memory = atof(argv[i+1]);
|
||||
} else if (!strcmp(argv[i], "-rsc_disk")) {
|
||||
i++;
|
||||
wu.rsc_disk = atof(argv[i+1]);
|
||||
wu.rsc_disk = atof(argv[i]);
|
||||
} else if (!strcmp(argv[i], "-keyfile")) {
|
||||
i++;
|
||||
strcpy(keyfile, argv[i]);
|
||||
} else if (!strcmp(argv[i], "-wu_name_rand")) {
|
||||
i++;
|
||||
sprintf(wu.name, "%s_%d", argv[i], rand());
|
||||
|
@ -124,25 +132,51 @@ int main(int argc, char** argv) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
retval = read_file(wu_template_file, wu_template);
|
||||
if (retval) {fprintf(stderr, "can't open WU template\n"); exit(1); }
|
||||
retval = read_file(result_template_file, result_template);
|
||||
if (retval) {fprintf(stderr, "can't open result template\n"); exit(1); }
|
||||
retval = read_filename(wu_template_file, wu_template);
|
||||
if (retval) {
|
||||
fprintf(stderr, "can't open WU template\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (wu.dynamic_results) strcpy(app.result_xml_template, result_template);
|
||||
retval = db_app_update(app);
|
||||
if (retval) printf("db_app_update: %d\n", retval);
|
||||
#if 0
|
||||
retval = read_file(result_template_file, result_template);
|
||||
if (retval) {
|
||||
fprintf(stderr, "can't open result template\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wu.dynamic_results) {
|
||||
strcpy(app.result_xml_template, result_template);
|
||||
retval = db_app_update(app);
|
||||
if (retval) printf("db_app_update: %d\n", retval);
|
||||
}
|
||||
|
||||
wu.appid = app.id;
|
||||
|
||||
|
||||
FILE* fkey = fopen(keyfile, "r");
|
||||
if (!fkey) {
|
||||
printf("create_work: can't open key file (%s)\n", keyfile);
|
||||
exit(1);
|
||||
}
|
||||
retval = scan_key_hex(fkey, (KEY*)&key, sizeof(key));
|
||||
fclose(fkey);
|
||||
if (retval) {
|
||||
printf("can't parse key\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
retval = create_work(
|
||||
wu,
|
||||
wu_template,
|
||||
result_template,
|
||||
result_template_file,
|
||||
nresults,
|
||||
boinc_download_dir,
|
||||
infiles,
|
||||
ninfiles
|
||||
ninfiles,
|
||||
key
|
||||
);
|
||||
if (retval) printf("create_work: %d\n", retval);
|
||||
if (retval) fprintf(stderr, "create_work: %d\n", retval);
|
||||
db_close();
|
||||
}
|
||||
|
|
|
@ -17,74 +17,115 @@
|
|||
// Contributor(s):
|
||||
//
|
||||
|
||||
// macro-substitute a result template file:
|
||||
// - replace OUTFILE_x with base_filename_x,
|
||||
// - WU_NAME with WU name
|
||||
// - RESULT_NAME with result name
|
||||
// - At the end of every <file_info> element, add a signature
|
||||
// of its contents up to that point.
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "parse.h"
|
||||
#include "crypt.h"
|
||||
|
||||
#define WU_NAME_MACRO "<WU_NAME/>"
|
||||
#define RESULT_NAME_MACRO "<RESULT_NAME/>"
|
||||
#define OUTFILE_MACRO "<OUTFILE_"
|
||||
#define UPLOAD_URL_MACRO "<UPLOAD_URL/>"
|
||||
#define DOWNLOAD_URL_MACRO "<DOWNLOAD_URL/>"
|
||||
#define UPLOAD_URL "http://localhost/upload/"
|
||||
#define UPLOAD_URL "http://localhost/boinc-cgi/file_upload_handler"
|
||||
#define DOWNLOAD_URL "http://localhost/download/"
|
||||
|
||||
// replace OUTFILE_x with base_filename_x,
|
||||
// WU_NAME with WU name
|
||||
// RESULT_NAME with result name
|
||||
//
|
||||
int process_result_template(
|
||||
char* out, char* base_filename, char* wu_name, char* result_name
|
||||
FILE* in, FILE* out,
|
||||
R_RSA_PRIVATE_KEY& key,
|
||||
char* base_filename, char* wu_name, char* result_name
|
||||
) {
|
||||
char* p,*q;
|
||||
char buf[MAX_BLOB_SIZE];
|
||||
char* p,*q, *signed_xml=strdup("");
|
||||
char buf[256], temp[256];
|
||||
unsigned char signature_buf[SIGNATURE_SIZE];
|
||||
DATA_BLOCK block, signature;
|
||||
char num;
|
||||
int i;
|
||||
bool found;
|
||||
|
||||
while (1) {
|
||||
found = false;
|
||||
p = strstr(out, OUTFILE_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
i = atoi(p+strlen(OUTFILE_MACRO));
|
||||
q = p+strlen(OUTFILE_MACRO);
|
||||
num = q[0];
|
||||
strcpy(buf, p+strlen(OUTFILE_MACRO)+1+2);
|
||||
strcpy(p, base_filename);
|
||||
strncat(p, &num, 1);
|
||||
strcat(p, buf);
|
||||
|
||||
while (fgets(buf, 256, in)) {
|
||||
|
||||
// when we reach the end of a <file_info> element,
|
||||
// generate a signature for the contents thus far
|
||||
//
|
||||
if (match_tag(buf, "<file_info>")) {
|
||||
free(signed_xml);
|
||||
signed_xml = strdup("");
|
||||
fputs(buf, out);
|
||||
continue;
|
||||
}
|
||||
p = strstr(out, UPLOAD_URL_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(buf, p+strlen(UPLOAD_URL_MACRO));
|
||||
strcpy(p, UPLOAD_URL);
|
||||
strcat(p, buf);
|
||||
if (match_tag(buf, "</file_info>")) {
|
||||
block.data = (unsigned char*)signed_xml;
|
||||
block.len = strlen(signed_xml);
|
||||
signature.data = signature_buf;
|
||||
signature.len = SIGNATURE_SIZE;
|
||||
sign_block(block, key, signature);
|
||||
fprintf(out, "<signature>\n");
|
||||
print_hex_data(out, signature);
|
||||
printf("signing [\n%s]\n", signed_xml);
|
||||
printf("signature: [\n");
|
||||
print_hex_data(stdout, signature);
|
||||
printf("]\n");
|
||||
fprintf(out, "</signature>\n");
|
||||
fprintf(out, "</file_info>\n");
|
||||
continue;
|
||||
}
|
||||
p = strstr(out, DOWNLOAD_URL_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(buf, p+strlen(DOWNLOAD_URL_MACRO));
|
||||
strcpy(p, DOWNLOAD_URL);
|
||||
strcat(p, buf);
|
||||
|
||||
while (1) {
|
||||
found = false;
|
||||
p = strstr(buf, OUTFILE_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
i = atoi(p+strlen(OUTFILE_MACRO));
|
||||
q = p+strlen(OUTFILE_MACRO);
|
||||
num = q[0];
|
||||
strcpy(temp, p+strlen(OUTFILE_MACRO)+1+2);
|
||||
strcpy(p, base_filename);
|
||||
strncat(p, &num, 1);
|
||||
strcat(p, temp);
|
||||
}
|
||||
p = strstr(buf, UPLOAD_URL_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(temp, p+strlen(UPLOAD_URL_MACRO));
|
||||
strcpy(p, UPLOAD_URL);
|
||||
strcat(p, temp);
|
||||
}
|
||||
p = strstr(buf, DOWNLOAD_URL_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(temp, p+strlen(DOWNLOAD_URL_MACRO));
|
||||
strcpy(p, DOWNLOAD_URL);
|
||||
strcat(p, temp);
|
||||
}
|
||||
p = strstr(buf, WU_NAME_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(temp, p+strlen(WU_NAME_MACRO));
|
||||
strcpy(p, wu_name);
|
||||
strcat(p, temp);
|
||||
}
|
||||
p = strstr(buf, RESULT_NAME_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(temp, p+strlen(RESULT_NAME_MACRO));
|
||||
strcpy(p, result_name);
|
||||
strcat(p, temp);
|
||||
}
|
||||
if (!found) break;
|
||||
}
|
||||
p = strstr(out, WU_NAME_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(buf, p+strlen(WU_NAME_MACRO));
|
||||
strcpy(p, wu_name);
|
||||
strcat(p, buf);
|
||||
}
|
||||
p = strstr(out, RESULT_NAME_MACRO);
|
||||
if (p) {
|
||||
found = true;
|
||||
strcpy(buf, p+strlen(RESULT_NAME_MACRO));
|
||||
strcpy(p, result_name);
|
||||
strcat(p, buf);
|
||||
}
|
||||
if (!found) break;
|
||||
strcatdup(signed_xml, buf);
|
||||
fputs(buf, out);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue