int main(int argc, char** argv) { #ifndef _USING_FCGI_ FILE* fin, *fout; #else FCGI_FILE *fin, *fout; #endif int i, retval; char req_path[MAXPATHLEN], reply_path[MAXPATHLEN]; char log_path[MAXPATHLEN], path[MAXPATHLEN]; unsigned int counter=0; char* code_sign_key; int length = -1; log_messages.pid = getpid(); bool debug_log = false; for (i=1; i<argc; i++) { if (!strcmp(argv[i], "--batch")) { batch = true; continue; } else if (!strcmp(argv[i], "--mark_jobs_done")) { mark_jobs_done = true; } else if (!strcmp(argv[i], "--debug_log")) { debug_log = true; #ifdef GCL_SIMULATOR } else if (!strcmp(argv[i], "--simulator")) { if(!argv[++i]) { log_messages.printf(MSG_CRITICAL, "%s requires an argument\n\n", argv[--i]); usage(argv[0]); exit(1); } simtime = atof(argv[i]); #endif } else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { usage(argv[0]); exit(0); } else if(!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { printf("%s\n", SVN_VERSION); exit(0); } else if (strlen(argv[i])){ log_messages.printf(MSG_CRITICAL, "unknown command line argument: %s\n\n", argv[i]); usage(argv[0]); exit(1); } } // install a signal handler that catches SIGTERMS sent by Apache if the CGI // times out. // signal(SIGTERM, sigterm_handler); if (debug_log) { if (!freopen("debug_log", "w", stderr)) { fprintf(stderr, "Can't redirect stderr\n"); exit(1); } } else { char *stderr_buffer; get_log_path(path, "scheduler.log"); #ifndef _USING_FCGI_ char buf[256]; if (!freopen(path, "a", stderr)) { fprintf(stderr, "Can't redirect stderr\n"); sprintf(buf, "Server can't open log file (%s)", path); send_message(buf, 3600); exit(1); } #else FCGI_FILE* f = FCGI::fopen(path, "a"); if (f) { log_messages.redirect(f); } else { char buf[256]; fprintf(stderr, "Can't redirect FCGI log messages\n"); sprintf(buf, "Server can't open log file for FCGI (%s)", path); send_message(buf, 3600); exit(1); } #endif // install a larger buffer for stderr. This ensures that // log information from different scheduler requests running // in parallel aren't intermingled in the log file. // if (config.scheduler_log_buffer) { stderr_buffer = (char*)malloc(config.scheduler_log_buffer); if (!stderr_buffer) { log_messages.printf(MSG_CRITICAL, "Unable to allocate stderr buffer\n" ); } else { #ifdef _USING_FCGI_ retval = setvbuf( f->stdio_stream, stderr_buffer, _IOFBF, config.scheduler_log_buffer ); #else retval = setvbuf( stderr, stderr_buffer, _IOFBF, config.scheduler_log_buffer ); #endif if (retval) { log_messages.printf(MSG_CRITICAL, "Unable to change stderr buffering\n" ); } } } } srand(time(0)+getpid()); log_messages.set_debug_level(DEBUG_LEVEL); #if DUMP_CORE_ON_SEGV set_core_dump_size_limit(); #endif retval = config.parse_file(); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse config.xml: %s\n", boincerror(retval) ); send_message("Server can't parse configuration file", 3600); exit(0); } log_messages.set_debug_level(config.sched_debug_level); if (config.sched_debug_level == 4) g_print_queries = true; gui_urls.init(); project_files.init(); init_file_delete_regex(); sprintf(path, "%s/code_sign_public", config.key_dir); retval = read_file_malloc(path, code_sign_key); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't read code sign key file (%s)\n", path ); send_message("Server can't find key file", 3600); exit(0); } strip_whitespace(code_sign_key); g_pid = getpid(); #ifdef _USING_FCGI_ //while(FCGI_Accept() >= 0 && counter < MAX_FCGI_COUNT) { while(FCGI_Accept() >= 0) { counter++; log_messages.set_indent_level(0); #endif if (config.debug_request_headers) { log_request_headers(length); } if (!debug_log && check_stop_sched()) { send_message("Project is temporarily shut down for maintenance", 3600); goto done; } if (!ssp) { attach_to_feeder_shmem(); } if (!ssp) { send_message("Server error: can't attach shared memory", 3600); goto done; } if (strlen(config.debug_req_reply_dir)) { struct stat statbuf; // the code below is convoluted because, // instead of going from stdin to stdout directly, // we go via a pair of disk files // (this makes it easy to save the input, // and to know the length of the output). // NOTE: to use this, you must create group-writeable dirs // boinc_req and boinc_reply in the project dir // sprintf(req_path, "%s/%d_%u_sched_request.xml", config.debug_req_reply_dir, g_pid, counter); sprintf(reply_path, "%s/%d_%u_sched_reply.xml", config.debug_req_reply_dir, g_pid, counter); // keep an own 'log' per PID in case general logging fails // this allows to associate at leas the scheduler request with the client // IP address (as shown in httpd error log) in case of a crash sprintf(log_path, "%s/%d_%u_sched.log", config.debug_req_reply_dir, g_pid, counter); #ifndef _USING_FCGI_ fout = fopen(log_path, "a"); #else fout = FCGI::fopen(log_path,"a"); #endif fprintf(fout, "PID: %d Client IP: %s\n", g_pid, get_remote_addr()); fclose(fout); log_messages.printf(MSG_DEBUG, "keeping sched_request in %s, sched_reply in %s, custom log in %s\n", req_path, reply_path, log_path ); #ifndef _USING_FCGI_ fout = fopen(req_path, "w"); #else fout = FCGI::fopen(req_path,"w"); #endif if (!fout) { log_messages.printf(MSG_CRITICAL, "can't write request file\n" ); exit(1); } copy_stream(stdin, fout); fclose(fout); stat(req_path, &statbuf); if (length>=0 && (statbuf.st_size != length)) { log_messages.printf(MSG_CRITICAL, "Request length %d != CONTENT_LENGTH %d\n", (int)statbuf.st_size, length ); } #ifndef _USING_FCGI_ fin = fopen(req_path, "r"); #else fin = FCGI::fopen(req_path,"r"); #endif if (!fin) { log_messages.printf(MSG_CRITICAL, "can't read request file\n" ); exit(1); } #ifndef _USING_FCGI_ fout = fopen(reply_path, "w"); #else fout = FCGI::fopen(reply_path, "w"); #endif if (!fout) { log_messages.printf(MSG_CRITICAL, "can't write reply file\n" ); exit(1); } handle_request(fin, fout, code_sign_key); fclose(fin); fclose(fout); #ifndef _USING_FCGI_ fin = fopen(reply_path, "r"); #else fin = FCGI::fopen(reply_path, "r"); #endif if (!fin) { log_messages.printf(MSG_CRITICAL, "can't read reply file\n" ); exit(1); } copy_stream(fin, stdout); fclose(fin); // if not contacted from a client, don't keep the log files /* not sure what lead to the assumption of a client setting CONTENT_LENGTH, but it's wrong at least on our current project / Apache / Client configuration. Commented out. if (getenv("CONTENT_LENGTH")) { unlink(req_path); unlink(reply_path); } */ #ifndef _USING_FCGI_ } else if (batch) { while (!feof(stdin)) { handle_request(stdin, stdout, code_sign_key); fflush(stdout); } #endif } else { handle_request(stdin, stdout, code_sign_key); fflush(stderr); } done: #ifdef _USING_FCGI_ if (config.debug_fcgi) { log_messages.printf(MSG_NORMAL, "FCGI: counter: %d\n", counter ); log_messages.flush(); } } // do() if (counter == MAX_FCGI_COUNT) { fprintf(stderr, "FCGI: counter passed MAX_FCGI_COUNT - exiting..\n"); } else { fprintf(stderr, "FCGI: FCGI_Accept failed - exiting..\n"); } // when exiting, write headers back to apache so it won't complain // about "incomplete headers" fprintf(stdout,"Content-type: text/plain\n\n"); #endif if (db_opened) { boinc_db.close(); } }
int main(int argc, char** argv) { #ifndef _USING_FCGI_ FILE* fin, *fout; #else FCGI_FILE *fin, *fout; #endif int i, retval; char req_path[256], reply_path[256], path[256]; unsigned int counter=0; char* code_sign_key; int length=-1; log_messages.pid = getpid(); bool debug_log = false; for (i=1; i<argc; i++) { if (!strcmp(argv[i], "--batch")) { batch = true; continue; } else if (!strcmp(argv[i], "--mark_jobs_done")) { mark_jobs_done = true; } else if (!strcmp(argv[i], "--debug_log")) { debug_log = true; #ifdef GCL_SIMULATOR } else if (!strcmp(argv[i], "--simulator")) { simtime = atof(argv[++i]); #endif } else { usage(argv[0]); } } // install a signal handler that catches SIGTERMS sent by Apache if the cgi // times out. // signal(SIGTERM, sigterm_handler); if (debug_log) { freopen("debug_log", "w", stderr); } else { char *stderr_buffer, buf[256]; get_log_path(path, "scheduler.log"); #ifndef _USING_FCGI_ if (!freopen(path, "a", stderr)) { fprintf(stderr, "Can't redirect stderr\n"); sprintf(buf, "Server can't open log file (%s)", path); send_message(buf, 3600); exit(1); } // install a larger buffer for stderr. This ensures that // log information from different scheduler requests running // in parallel don't collide in the log file and appear intermingled. // if (!(stderr_buffer=(char *)malloc(32768)) || setvbuf(stderr, stderr_buffer, _IOFBF, 32768)) { log_messages.printf(MSG_CRITICAL, "Unable to change stderr buffering preferences\n" ); } #else FCGI_FILE* f = FCGI::fopen(path, "a"); if (f) { log_messages.redirect(f); } else { char buf[256]; fprintf(stderr, "Can't redirect FCGI log messages\n"); sprintf(buf, "Server can't open log file for FCGI (%s)", path); send_message(buf, 3600); exit(1); } // set buffer as above, note that f is really a struct from fcgi_stdio.h if (!(stderr_buffer=(char *)malloc(32768)) || setvbuf(f->stdio_stream, stderr_buffer, _IOFBF, 32768)) { log_messages.printf(MSG_CRITICAL, "Unable to change stderr FCGI buffering preferences\n" ); } #endif } srand(time(0)+getpid()); log_messages.set_debug_level(DEBUG_LEVEL); #if DUMP_CORE_ON_SEGV set_core_dump_size_limit(); #endif retval = config.parse_file(); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't parse config.xml: %s\n", boincerror(retval) ); send_message("Server can't parse configuration file", 3600); exit(0); } log_messages.set_debug_level(config.sched_debug_level); gui_urls.init(); project_files.init(); sprintf(path, "%s/code_sign_public", config.key_dir); retval = read_file_malloc(path, code_sign_key); if (retval) { log_messages.printf(MSG_CRITICAL, "Can't read code sign key file (%s)\n", path ); send_message("Server can't find key file", 3600); exit(0); } g_pid = getpid(); #ifdef _USING_FCGI_ //while(FCGI_Accept() >= 0 && counter < MAX_FCGI_COUNT) { while(FCGI_Accept() >= 0) { counter++; log_messages.set_indent_level(0); #endif if (config.debug_request_headers) { log_request_headers(length); } if (check_stop_sched()) { send_message("Project is temporarily shut down for maintenance", 3600); goto done; } if (!ssp) { attach_to_feeder_shmem(); } if (!ssp) { send_message("Server error: can't attach shared memory", 3600); goto done; } if (use_files) { struct stat statbuf; // the code below is convoluted because, // instead of going from stdin to stdout directly, // we go via a pair of disk files // (this makes it easy to save the input, // and to know the length of the output). // NOTE: to use this, you must create group-writeable dirs // boinc_req and boinc_reply in the project dir // sprintf(req_path, "%s%d_%u", config.project_path(REQ_FILE_PREFIX), g_pid, counter); sprintf(reply_path, "%s%d_%u", config.project_path(REPLY_FILE_PREFIX), g_pid, counter); #ifndef _USING_FCGI_ fout = fopen(req_path, "w"); #else fout = FCGI::fopen(req_path,"w"); #endif if (!fout) { log_messages.printf(MSG_CRITICAL, "can't write request file\n" ); exit(1); } copy_stream(stdin, fout); fclose(fout); stat(req_path, &statbuf); if (length>=0 && (statbuf.st_size != length)) { log_messages.printf(MSG_CRITICAL, "Request length %d != CONTENT_LENGTH %d\n", (int)statbuf.st_size, length ); } #ifndef _USING_FCGI_ fin = fopen(req_path, "r"); #else fin = FCGI::fopen(req_path,"r"); #endif if (!fin) { log_messages.printf(MSG_CRITICAL, "can't read request file\n" ); exit(1); } #ifndef _USING_FCGI_ fout = fopen(reply_path, "w"); #else fout = FCGI::fopen(reply_path, "w"); #endif if (!fout) { log_messages.printf(MSG_CRITICAL, "can't write reply file\n" ); exit(1); } handle_request(fin, fout, code_sign_key); fclose(fin); fclose(fout); #ifndef _USING_FCGI_ fin = fopen(reply_path, "r"); #else fin = FCGI::fopen(reply_path, "r"); #endif if (!fin) { log_messages.printf(MSG_CRITICAL, "can't read reply file\n" ); exit(1); } copy_stream(fin, stdout); fclose(fin); #ifdef EINSTEIN_AT_HOME if (getenv("CONTENT_LENGTH")) unlink(req_path); if (getenv("CONTENT_LENGTH")) unlink(reply_path); #else // unlink(req_path); // unlink(reply_path); #endif #ifndef _USING_FCGI_ } else if (batch) { while (!feof(stdin)) { handle_request(stdin, stdout, code_sign_key); fflush(stdout); } #endif } else { handle_request(stdin, stdout, code_sign_key); } done: #ifdef _USING_FCGI_ log_messages.printf(MSG_DEBUG, "FCGI: counter: %d\n", counter ); log_messages.flush(); } // do() if (counter == MAX_FCGI_COUNT) { fprintf(stderr, "FCGI: counter passed MAX_FCGI_COUNT - exiting..\n"); } else { fprintf(stderr, "FCGI: FCGI_Accept failed - exiting..\n"); } // when exiting, write headers back to apache so it won't complain // about "incomplete headers" fprintf(stdout,"Content-type: text/plain\n\n"); #endif if (db_opened) { boinc_db.close(); } }