00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "gs_agent_httpd.h"
00011
00012 extern char GRIDSOLVE_STATS_FILE[];
00013
00014
00015 char *gs_content_types[][2] = {
00016 {"xsl", "application/xml"},
00017 {"html", "text/html"},
00018 {"xml", "application/xml"},
00019 {"ico", "image/x-ico"},
00020 {"avi", "video/avi"},
00021 {"md5", "text/md5"},
00022 {"srt", "text/srt"},
00023 {NULL, "text/html"}
00024 };
00025
00026 gs_agent_t *gs_httpd_agent_ptr = NULL;
00027
00034 static void
00035 gs_httpd_generic_signal_handler(int sig)
00036 {
00037
00038 if(sig == SIGHUP) {
00039 kill(getppid(), SIGHUP);
00040 return;
00041 }
00042
00043 ERRPRINTF("HTTP server terminating on signal %d.\n", sig);
00044 _exit(0);
00045 }
00046
00053 void
00054 gs_agent_exit(void **args)
00055 {
00056 _exit(0);
00057 }
00058
00066 void
00067 gs_agent_httpd(void **args)
00068 {
00069 char *gridsolve_root, *www_home_path;
00070 struct sockaddr_in servaddr;
00071 int listenfd;
00072 socklen_t dummyLen;
00073 void sig_chld(int);
00074 short port;
00075
00076 if(!args || !args[0] || !args[1]) {
00077 ERRPRINTF("Bad args\n");
00078 _exit(EXIT_FAILURE);
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088 gs_setup_signal_handlers(gs_httpd_generic_signal_handler);
00089 signal(SIGINT, SIG_IGN);
00090
00091 port = *((int *)args[0]);
00092 gs_httpd_agent_ptr = (gs_agent_t *)args[1];
00093
00094 if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00095 perror("Failed to create socket");
00096 _exit(EXIT_FAILURE);
00097 }
00098
00099 if((gridsolve_root = getenv("GRIDSOLVE_ROOT")) == NULL)
00100 gridsolve_root = GRIDSOLVE_TOP_BUILD_DIR;
00101
00102 if(!gridsolve_root) {
00103 ERRPRINTF("Warning: GRIDSOLVE_ROOT unknown, assuming cwd.\n");
00104 gridsolve_root = strdup(".");
00105 }
00106
00107 www_home_path = (char *)malloc(strlen(gridsolve_root) +
00108 strlen(GS_AGENT_WWW_DIR) + 2);
00109 if(!www_home_path) {
00110 ERRPRINTF("malloc failed\n");
00111 _exit(EXIT_FAILURE);
00112 }
00113
00114 sprintf(www_home_path, "%s/%s", gridsolve_root, GS_AGENT_WWW_DIR);
00115
00116 if(chdir(www_home_path) < 0) {
00117 ERRPRINTF("Failed to chdir to '%s'\n", www_home_path);
00118 _exit(EXIT_FAILURE);
00119 }
00120
00121 free(www_home_path);
00122
00123 memset(&servaddr, 0x0, sizeof(servaddr));
00124 servaddr.sin_family = AF_INET;
00125 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
00126 servaddr.sin_port = htons(port);
00127
00128 if(bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
00129 perror("Failed to bind");
00130 _exit(EXIT_FAILURE);
00131 }
00132
00133 if(listen(listenfd, 20) < 0) {
00134 perror("Listen failed");
00135 _exit(EXIT_FAILURE);
00136 }
00137
00138 dummyLen = sizeof(struct sockaddr);
00139 if(getsockname(listenfd, (struct sockaddr *)(&servaddr), &dummyLen) < 0)
00140 LOGPRINTF("HTTP server listening on some unknown port\n");
00141 else
00142 LOGPRINTF("HTTP server listening on port %d\n", ntohs(servaddr.sin_port));
00143
00144 if(gs_signal(SIGCHLD, sig_chld) == SIG_ERR) {
00145 ERRPRINTF("Could not set up SIGCHLD signal handler\n");
00146 _exit(EXIT_FAILURE);
00147 }
00148
00149 gs_agent_httpd_listen_and_process_connections(listenfd);
00150 _exit(EXIT_SUCCESS);
00151 }
00152
00161 int
00162 gs_agent_httpd_listen_and_process_connections(int listenfd)
00163 {
00164 struct sockaddr_in cliaddr;
00165 fd_set rset, allset;
00166 socklen_t clilen;
00167 pid_t childpid;
00168 struct timeval tv;
00169 int nready, connfd;
00170
00171 clilen = sizeof(cliaddr);
00172 FD_ZERO(&allset);
00173 FD_SET(listenfd, &allset);
00174
00175 for(;;) {
00176 rset = allset;
00177 tv.tv_sec = 1;
00178 tv.tv_usec = 0;
00179
00180 nready = select(listenfd + 1, &rset, NULL, NULL, &tv);
00181
00182 if((nready < 0) && (errno == EINTR))
00183 continue;
00184
00185 if(nready < 0) {
00186 ERRPRINTF("select failed.. aborting.\n");
00187 break;
00188 }
00189
00190 if(nready == 0) {
00191 if(!mfork_check_parent()) {
00192 ERRPRINTF("Parent died, so I am exiting\n");
00193 break;
00194 }
00195 continue;
00196 }
00197
00198 if(FD_ISSET(listenfd, &rset)) {
00199 if ((connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0) {
00200 if (errno == EINTR)
00201 continue;
00202 else {
00203 perror("accept error");
00204 _exit(-1);
00205 }
00206 }
00207
00208 if ((childpid = fork()) == 0) {
00209 close(listenfd);
00210 if(gs_agent_httpd_handle_connection(connfd) < 0) {
00211 ERRPRINTF("Failed to handle connection.\n");
00212 _exit(-1);
00213 }
00214 close(connfd);
00215 _exit(0);
00216 }
00217 close(connfd);
00218 }
00219 }
00220
00221 return 0;
00222 }
00223
00230 void
00231 sig_chld(int signo)
00232 {
00233 pid_t pid;
00234 int stat;
00235
00236 while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
00237 DBGPRINTF("child %d terminated\n", (int)pid);
00238
00239 return;
00240 }
00241
00252 const char *
00253 gs_get_content_type(const char *filename)
00254 {
00255 const char *end;
00256 int i;
00257
00258 if(filename && (strlen(filename) > 0)) {
00259 end = filename + strlen(filename) - 1;
00260
00261 while(end != filename) {
00262 if(*end == '.') {
00263 end++;
00264 break;
00265 }
00266 end--;
00267 }
00268
00269 if(end == filename)
00270 return GS_DEFAULT_CONTENT_TYPE;
00271
00272 for(i=0; gs_content_types[i][0]; i++)
00273 if(!strcmp(end, gs_content_types[i][0]))
00274 return(gs_content_types[i][1]);
00275 }
00276
00277 return GS_DEFAULT_CONTENT_TYPE;
00278 }
00279
00287 void
00288 unescape_url(char *str)
00289 {
00290 char tmp[3] = {0, 0, 0};
00291 int unescaped_char;
00292 int i, idx;
00293
00294 if(!str) return;
00295
00296 idx = 0;
00297
00298 for(i=0;i<strlen(str);i++) {
00299 memset(tmp, 0, 3);
00300
00301 if(str[i] == '%') {
00302 if(str[i+1] != 0) {
00303 tmp[0] = str[i+1];
00304
00305 if(str[i+2] != 0) {
00306 tmp[1] = str[i+2];
00307 i += 2;
00308 }
00309 else
00310 i++;
00311 }
00312
00313 sscanf(tmp, "%x", &unescaped_char);
00314 }
00315 else
00316 unescaped_char = str[i];
00317
00318 str[idx++] = unescaped_char;
00319 }
00320
00321 str[idx] = 0;
00322 }
00323
00332 int
00333 gs_agent_httpd_handle_connection(int sockfd)
00334 {
00335 ssize_t n;
00336 char *cmd, *fn, line[MAXLINE];
00337
00338 if((n = gs_readline(sockfd, line, MAXLINE)) > 0) {
00339 cmd = strtok(line, " ");
00340 fn = strtok(NULL, " ");
00341
00342 if(!strcmp(cmd, "GET")) {
00343 int rv;
00344
00345 LOGPRINTF("HTTP GET %s\n", fn);
00346
00347 gs_read_until_crlf(sockfd);
00348
00349
00350 if(!strncmp(fn, "http://", 7))
00351 return 0;
00352
00353 fn++;
00354
00355 unescape_url(fn);
00356
00357 if(*fn == '\0' || strchr(fn, '?')) {
00358 if(gs_httpd_connect_db(sockfd) < 0)
00359 return -1;
00360
00361 if(*fn == '\0' || !strcmp(fn, "status?"))
00362 rv = gs_httpd_process_status(sockfd);
00363 else if(!strcmp(fn, "problemlist?"))
00364 rv = gs_httpd_process_problem_info(sockfd, NULL);
00365 else if(!strncmp(fn, "serverinfo?", strlen("serverinfo?")))
00366 rv = gs_httpd_process_server_info(sockfd, fn);
00367 else if(!strncmp(fn, "probleminfo?", strlen("probleminfo?")))
00368 rv = gs_httpd_process_problem_info(sockfd, fn);
00369 else if(!strncmp(fn, "tasklist?", strlen("tasklist?")))
00370 rv = gs_httpd_process_task_list(sockfd);
00371 else
00372 rv = gs_httpd_get_file(sockfd, fn);
00373
00374
00375 gs_storage_finalize(NULL);
00376 }
00377 else
00378 rv = gs_httpd_get_file(sockfd, fn);
00379
00380 return rv;
00381 }
00382 else if(!strcmp(cmd, "HEAD")) {
00383 int rv;
00384
00385 LOGPRINTF("HTTP HEAD %s\n", fn);
00386
00387 gs_read_until_crlf(sockfd);
00388
00389
00390 if(!strncmp(fn, "http://", 7))
00391 return 0;
00392
00393 fn++;
00394
00395 rv = gs_httpd_head_file(sockfd, fn);
00396
00397 return rv;
00398 }
00399 }
00400
00401 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00402 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00403
00404 return -1;
00405 }
00406
00416 int
00417 gs_httpd_head_file(int sockfd, const char *filename)
00418 {
00419 struct stat stbuf;
00420 const char *mime_type;
00421
00422 if(!filename) {
00423 ERRPRINTF("Invalid filename, ptr is null.\n");
00424 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00425 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00426 return -1;
00427 }
00428
00429 if(stat(filename, &stbuf) < 0) {
00430 ERRPRINTF("Could not stat file '%s'\n", filename);
00431 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00432 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00433 return -1;
00434 }
00435
00436 if((mime_type = gs_get_content_type(filename)) == NULL) {
00437 ERRPRINTF("Failed to get content type for '%s'\n", filename);
00438 ERRPRINTF(" [probably out of memory]\n");
00439 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00440 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00441 return -1;
00442 }
00443
00444 gs_httpd_preamble(sockfd, 200, mime_type, (int)stbuf.st_size);
00445
00446 return 0;
00447 }
00448
00458 int
00459 gs_httpd_get_file(int sockfd, const char *filename)
00460 {
00461 const char *mime_type;
00462 double elapsed_time;
00463 struct stat stbuf;
00464 char buf[MAXLINE];
00465 int fd, n;
00466
00467 if(!filename) {
00468 ERRPRINTF("Invalid filename, ptr is null.\n");
00469 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00470 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00471 return -1;
00472 }
00473
00474 if(stat(filename, &stbuf) < 0) {
00475 ERRPRINTF("Could not stat file '%s'\n", filename);
00476 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00477 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00478 return -1;
00479 }
00480
00481 if((fd = open(filename, O_RDONLY)) == -1) {
00482 ERRPRINTF("Failed to open file '%s'\n", filename);
00483 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00484 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00485 return -1;
00486 }
00487
00488 if((mime_type = gs_get_content_type(filename)) == NULL) {
00489 ERRPRINTF("Failed to get content type for '%s'\n", filename);
00490 ERRPRINTF(" [probably out of memory]\n");
00491 close(fd);
00492 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00493 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00494 return -1;
00495 }
00496
00497 gs_httpd_preamble(sockfd, 200, mime_type, (int)stbuf.st_size);
00498
00499 elapsed_time = walltime();
00500
00501 while((n=read(fd, buf, MAXLINE)) > 0) {
00502 if(gs_twrite(sockfd, buf, n) != n) {
00503 ERRPRINTF("error in sending data\n");
00504 close(fd);
00505 return -1;
00506 }
00507 }
00508
00509 elapsed_time = walltime() - elapsed_time;
00510
00511 close(fd);
00512
00513 if(n < 0)
00514 ERRPRINTF("Warning: read error on file '%s'\n", filename);
00515
00516 LOGPRINTF("Sent %d bytes in %g seconds (%g Kbyte/s)\n", (int)stbuf.st_size,
00517 elapsed_time, ((double)stbuf.st_size/1024.0) / elapsed_time);
00518
00519 return 0;
00520 }
00521
00534 char *
00535 gs_get_uptime_xml(struct timeval start_time, struct timeval cur_time) {
00536 struct timeval time_diff;
00537 char *xml_time;
00538 long s_diff;
00539 long days;
00540 long hours;
00541 long minutes;
00542 long seconds;
00543
00544 timersub(&cur_time, &start_time, &time_diff);
00545
00546 s_diff = time_diff.tv_sec;
00547
00548 days = s_diff / SECSPERDAY;
00549 if(days > 0) s_diff -= days * SECSPERDAY;
00550 hours = s_diff / SECSPERHOUR;
00551 if(hours > 0) s_diff -= hours * SECSPERHOUR;
00552 minutes = s_diff / SECSPERMIN;
00553 if(minutes > 0) s_diff -= minutes * SECSPERMIN;
00554 seconds = s_diff;
00555
00556 xml_time = dstring_sprintf("<agent_uptime>\n <days>%d</days>\n <hours>%d</hours>\n <minutes>%d</minutes>\n <seconds>%d</seconds>\n </agent_uptime>\n", days, hours, minutes, seconds);
00557 if(!xml_time) goto uptime_error;
00558
00559 return xml_time;
00560
00561 uptime_error:
00562 return strdup("<agent_uptime></agent_uptime>\n");
00563 }
00564
00573 char *
00574 gs_get_agent_stats()
00575 {
00576 gs_agent_stats_t *cur_stats;
00577 char *stats_xml, *hostname_xml, *port_xml, *uptime_xml;
00578 struct timeval cur_time;
00579 int sfd;
00580
00581 stats_xml = hostname_xml = port_xml = uptime_xml = NULL;
00582
00583 sfd = open(GRIDSOLVE_STATS_FILE, O_RDONLY);
00584 if(sfd < 0) goto stats_error;
00585
00586 stats_xml = dstring_sprintf(GS_BEGIN_AGENT_STATS);
00587 if(!stats_xml) goto stats_error;
00588
00589 cur_stats = (gs_agent_stats_t *) mmap((caddr_t)0,
00590 sizeof(gs_agent_stats_t), PROT_READ, MAP_SHARED, sfd, 0);
00591
00592 if(cur_stats == (gs_agent_stats_t *)(-1))
00593 goto stats_error;
00594
00595 gettimeofday(&cur_time, NULL);
00596
00597 uptime_xml = gs_get_uptime_xml(cur_stats->start_time, cur_time);
00598 hostname_xml = dstring_sprintf("%s%s%s", GS_BEGIN_AGENT_NAME,
00599 cur_stats->hostname, GS_END_AGENT_NAME);
00600 port_xml = dstring_sprintf("%s%d%s", GS_BEGIN_AGENT_PORT,
00601 cur_stats->port, GS_END_AGENT_PORT);
00602
00603 if(hostname_xml)
00604 stats_xml = dstring_append(stats_xml, hostname_xml);
00605 if(port_xml)
00606 stats_xml = dstring_append(stats_xml, port_xml);
00607 if(uptime_xml)
00608 stats_xml = dstring_append(stats_xml, uptime_xml);
00609
00610 stats_xml = dstring_append(stats_xml, GS_END_AGENT_STATS);
00611
00612 close(sfd);
00613 if(hostname_xml) free(hostname_xml);
00614 if(port_xml) free(port_xml);
00615 if(uptime_xml) free(uptime_xml);
00616 return stats_xml;
00617
00618 stats_error:
00619 if(sfd >= 0)
00620 close(sfd);
00621 if(hostname_xml) free(hostname_xml);
00622 if(port_xml) free(port_xml);
00623 if(uptime_xml) free(uptime_xml);
00624 return strdup("<agent_stats></agent_stats>");
00625 }
00626
00636 int
00637 gs_httpd_connect_db(int sockfd)
00638 {
00639 int err;
00640
00641 err = gs_storage_init(gs_httpd_agent_ptr);
00642 if ( err < 0 ) {
00643 ERRPRINTF("Could not connect to database manager.\n");
00644 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00645 gs_httpd_reply(sockfd, GS_RESPONSE_DB_FAILURE);
00646 return -1;
00647 }
00648
00649 return 0;
00650 }
00651
00661 int
00662 gs_httpd_process_status(int sockfd)
00663 {
00664 gs_server_t **server_list = NULL;
00665 char *agent_stats;
00666 int count;
00667
00668 count = gs_get_all_servers(NULL, &server_list, &count);
00669
00670 if(count < 0)
00671 ERRPRINTF("Warning: failed to get list of all servers\n");
00672
00673 agent_stats = gs_get_agent_stats();
00674
00675 if(!agent_stats) {
00676 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00677 gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
00678 return -1;
00679 }
00680
00681 gs_httpd_preamble(sockfd, 200, "application/xml", 0);
00682 gs_httpd_reply(sockfd, GS_XML_HEADER_SERVERLIST);
00683
00684 gs_httpd_reply(sockfd, GS_BEGIN_SYSTEM_STATUS);
00685 gs_httpd_reply(sockfd, agent_stats);
00686 free(agent_stats);
00687
00688 if(count > 0) {
00689 gs_send_server_array(sockfd, server_list, count);
00690 gs_free_server_array(server_list, count);
00691 }
00692
00693 gs_httpd_reply(sockfd, GS_END_SYSTEM_STATUS);
00694
00695 return 0;
00696 }
00697
00706 int
00707 gs_httpd_process_task_list(int sockfd)
00708 {
00709 gs_server_t **server_list = NULL;
00710 int i, count;
00711
00712 count = gs_get_all_servers(NULL, &server_list, &count);
00713
00714 if(count < 0)
00715 ERRPRINTF("Warning: failed to get list of all servers\n");
00716
00717 if(!server_list) {
00718 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00719 gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
00720 return -1;
00721 }
00722
00723 gs_httpd_preamble(sockfd, 200, "application/xml", 0);
00724 gs_httpd_reply(sockfd, GS_XML_HEADER_TASKLIST);
00725
00726 gs_httpd_reply(sockfd, GS_BEGIN_TASK_LIST);
00727
00728 if(count > 0) {
00729 char printable_id[CID_LEN*2+1];
00730
00731 for(i=0;i<count;i++) {
00732 proxy_cid_to_str(printable_id, server_list[i]->componentid);
00733 gs_send_task_list(sockfd, printable_id);
00734 }
00735
00736 gs_free_server_array(server_list, count);
00737 }
00738
00739 gs_httpd_reply(sockfd, GS_END_TASK_LIST);
00740
00741 return 0;
00742 }
00743
00754 int
00755 gs_httpd_process_server_info(int sockfd, const char *filename)
00756 {
00757 gs_problem_t **problem_list;
00758 gs_server_t **server_list;
00759 char *cid, *fn_copy;
00760 int count;
00761
00762 problem_list = NULL;
00763 server_list = NULL;
00764
00765 if(!filename) {
00766 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00767 gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
00768 return -1;
00769 }
00770
00771 fn_copy = (char *)strdup(filename);
00772
00773 if(!fn_copy) {
00774 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00775 gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
00776 return -1;
00777 }
00778
00779 cid = strtok(fn_copy, "?");
00780 cid = strtok(NULL, "?");
00781
00782 if(!cid) {
00783 free(fn_copy);
00784 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00785 gs_httpd_reply(sockfd, GS_RESPONSE_BAD_SERVER_REQ);
00786 return -1;
00787 }
00788
00789 server_list = (gs_server_t **)malloc(sizeof(gs_server_t *));
00790 server_list[0] = (gs_server_t *)calloc(1, sizeof(gs_server_t));
00791
00792 if(gs_get_server_by_cid(NULL, cid, server_list[0]) < 0) {
00793 ERRPRINTF("failed to get servers\n");
00794 free(server_list[0]);
00795 free(server_list);
00796 free(fn_copy);
00797 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00798 gs_httpd_reply(sockfd, GS_RESPONSE_BAD_SERVER_REQ);
00799 return -1;
00800 }
00801
00802 gs_httpd_preamble(sockfd, 200, "application/xml", 0);
00803 gs_httpd_reply(sockfd, GS_XML_HEADER_SERVERINFO);
00804 gs_httpd_reply(sockfd, GS_BEGIN_SERVER_INFO);
00805
00806 gs_send_server_array(sockfd, server_list, 1);
00807
00808 if(gs_get_problem_list(NULL, server_list[0], &problem_list, &count) >= 0) {
00809 gs_send_problem_array(sockfd, problem_list, count);
00810 gs_free_problem_array(problem_list, count);
00811 }
00812
00813 gs_httpd_reply(sockfd, GS_END_SERVER_INFO);
00814
00815 gs_free_server_array(server_list, 1);
00816 free(fn_copy);
00817
00818 return 0;
00819 }
00820
00833 int
00834 gs_httpd_process_problem_info(int sockfd, const char *filename)
00835 {
00836 char *problem_name, *fn_copy;
00837 gs_problem_t **problem_list = NULL;
00838 int count;
00839
00840 fn_copy = problem_name = NULL;
00841
00842 if(filename) {
00843 fn_copy = (char *)strdup(filename);
00844
00845 if(!fn_copy) return -1;
00846
00847 problem_name = strtok(fn_copy, "?");
00848 problem_name = strtok(NULL, "?");
00849
00850 if(!problem_name) {
00851 ERRPRINTF("Error parsing problem info request.\n");
00852 free(fn_copy);
00853 gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
00854 gs_httpd_reply(sockfd, GS_RESPONSE_404);
00855 return -1;
00856 }
00857 }
00858
00859 if(problem_name) {
00860 count = gs_get_problem_info(NULL, &problem_list, &count, problem_name);
00861
00862 if(count == 0) {
00863 free(fn_copy);
00864 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00865 gs_httpd_reply(sockfd, GS_RESPONSE_BAD_PROBLEM_REQ);
00866 return -1;
00867 }
00868 }
00869 else
00870 count = gs_get_all_problems(NULL, &problem_list, &count);
00871
00872 if(count < 0)
00873 ERRPRINTF("Warning: failed to get problem(s)\n");
00874
00875 if(problem_name) {
00876 gs_httpd_preamble(sockfd, 200, "application/xml", 0);
00877 gs_httpd_reply(sockfd, GS_XML_HEADER_PROBLEMINFO);
00878 gs_httpd_reply(sockfd, GS_BEGIN_PROBLEM_INFO);
00879 }
00880 else {
00881 char *agent_stats = gs_get_agent_stats();
00882 if(!agent_stats) {
00883 gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
00884 gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
00885 return -1;
00886 }
00887
00888 gs_httpd_preamble(sockfd, 200, "application/xml", 0);
00889 gs_httpd_reply(sockfd, GS_XML_HEADER_SERVERLIST);
00890 gs_httpd_reply(sockfd, GS_BEGIN_SYSTEM_STATUS);
00891 gs_httpd_reply(sockfd, agent_stats);
00892 free(agent_stats);
00893 }
00894
00895 if(count > 0) {
00896 gs_send_problem_array(sockfd, problem_list, count);
00897 gs_free_problem_array(problem_list, count);
00898 }
00899
00900 if(problem_name) {
00901 gs_server_t **server_list = NULL;
00902 gs_problem_t *prob;
00903
00904 prob = (gs_problem_t *)calloc(1, sizeof(gs_problem_t));
00905
00906 if(prob) {
00907
00908
00909
00910 prob->name = strdup(problem_name);
00911
00912 if(prob->name) {
00913 count =
00914 gs_get_server_list(NULL, prob, NULL, &server_list, &count);
00915
00916 if(count > 0) {
00917 gs_send_server_array(sockfd, server_list, count);
00918 gs_free_server_array(server_list, count);
00919 }
00920 }
00921 gs_free_problem(prob);
00922 }
00923
00924 free(fn_copy);
00925 gs_httpd_reply(sockfd, GS_END_PROBLEM_INFO);
00926 }
00927 else
00928 gs_httpd_reply(sockfd, GS_END_SYSTEM_STATUS);
00929
00930 return 0;
00931 }
00932
00944 int
00945 gs_send_problem_array(int sockfd, gs_problem_t **problem_list, int count)
00946 {
00947 int i;
00948
00949 if(!problem_list) {
00950 ERRPRINTF("Invalid arg: null problem_list\n");
00951 return -1;
00952 }
00953
00954 gs_httpd_reply(sockfd, GS_BEGIN_PROBLEM_LIST);
00955
00956 for(i = 0; i < count; i++) {
00957 char *prob = NULL;
00958 if(gs_encode_problem(&prob, problem_list[i]) < 0) {
00959 FREE(prob);
00960 ERRPRINTF("Failed to send problem list\n");
00961 return -1;
00962 }
00963
00964 gs_httpd_reply(sockfd, prob);
00965 gs_httpd_reply(sockfd, "\n");
00966
00967 FREE(prob);
00968 }
00969
00970 gs_httpd_reply(sockfd, GS_END_PROBLEM_LIST);
00971
00972 return 0;
00973 }
00974
00984 int
00985 gs_free_problem_array(gs_problem_t **problem_list, int count)
00986 {
00987 int i;
00988
00989 for(i = 0; i < count; i++)
00990 gs_free_problem(problem_list[i]);
00991 FREE(problem_list);
00992 return 0;
00993 }
00994
01004 int
01005 gs_free_server_array(gs_server_t **server_list, int count)
01006 {
01007 int i;
01008
01009 for(i = 0; i < count; i++)
01010 gs_server_free(server_list[i]);
01011 FREE(server_list);
01012 return 0;
01013 }
01014
01026 int
01027 gs_send_server_array(int sockfd, gs_server_t **server_list, int count)
01028 {
01029 int i;
01030
01031 if(!server_list) {
01032 ERRPRINTF("Invalid arg: null server_list\n");
01033 return -1;
01034 }
01035
01036 gs_httpd_reply(sockfd, GS_BEGIN_SERVER_LIST);
01037
01038 for(i = 0; i < count; i++) {
01039 char *srv = NULL;
01040 DBGPRINTF("Encoding server: %s.\n", server_list[i]->hostname);
01041 if(gs_encode_server(&srv, server_list[i]) < 0) {
01042 FREE(srv);
01043 DBGPRINTF("Failed to send server list \n");
01044 return -1;
01045 }
01046
01047 gs_httpd_reply(sockfd, srv);
01048 gs_httpd_reply(sockfd, "\n");
01049
01050 FREE(srv);
01051 }
01052
01053 gs_httpd_reply(sockfd, GS_END_SERVER_LIST);
01054
01055 return 0;
01056 }
01057
01068 int
01069 gs_read_until_crlf(int sockfd)
01070 {
01071 char line[MAXLINE];
01072 int n;
01073
01074 for (;;) {
01075 if ((n = gs_readline(sockfd, line, MAXLINE)) == 0)
01076 return 0;
01077
01078 line[strlen(line)-2] = 0;
01079
01080 if(!strcmp(line, ""))
01081 return 0;
01082 }
01083
01084 return 0;
01085 }
01086
01098 int
01099 gs_httpd_reply(int sockfd, const char *msg)
01100 {
01101 char *xml;
01102 int n;
01103
01104 xml = gs_xmlize(msg);
01105
01106 n = gs_twrite(sockfd, xml, strlen(xml));
01107
01108 free(xml);
01109
01110 return n;
01111 }
01112
01125 char *
01126 gs_xmlize(const char *msg)
01127 {
01128 char *xmlized_msg, *xp;
01129 int inside_string;
01130 const char *op;
01131
01132 if(!msg) return NULL;
01133
01134
01135
01136
01137
01138
01139 xmlized_msg = (char *)malloc(5 * strlen(msg));
01140 if(!xmlized_msg)
01141 return NULL;
01142
01143 inside_string = FALSE;
01144
01145 for(op = msg, xp = xmlized_msg; *op != '\0'; op++) {
01146 if(*op == '"') {
01147 inside_string = inside_string ? FALSE : TRUE;
01148 *xp++ = *op;
01149 continue;
01150 }
01151
01152 if(inside_string) {
01153 switch(*op) {
01154 case '&':
01155 strcpy(xp, "&");
01156 xp += strlen("&");
01157 break;
01158 case '<':
01159 strcpy(xp, "<");
01160 xp += strlen("<");
01161 break;
01162 case '>':
01163 strcpy(xp, ">");
01164 xp += strlen(">");
01165 break;
01166 default:
01167 *xp++ = *op;
01168 }
01169 }
01170 else
01171 *xp++ = *op;
01172 }
01173
01174 *xp = '\0';
01175
01176 return xmlized_msg;
01177 }
01178
01195 int
01196 gs_httpd_preamble(int sockfd, int num, const char *content_type, int len)
01197 {
01198 char http_resp_line[MAXLINE], mime_type_line[MAXLINE], len_line[MAXLINE];
01199
01200 if(!content_type)
01201 content_type = GS_DEFAULT_CONTENT_TYPE;
01202
01203 sprintf(http_resp_line, "HTTP/1.1 %d OK\n", num);
01204 sprintf(mime_type_line, "Content-Type: %s\n", content_type);
01205 sprintf(len_line, "Content-Length: %d\n", len);
01206
01207 if((gs_httpd_reply(sockfd, http_resp_line) < 0) ||
01208 (gs_httpd_reply(sockfd, "Server: GridSolve beta\n") < 0) ||
01209 (gs_httpd_reply(sockfd, mime_type_line) < 0))
01210 {
01211 ERRPRINTF("Error sending preamble\n");
01212 return -1;
01213 }
01214
01215 if(len > 0) {
01216 if(gs_httpd_reply(sockfd, len_line) < 0)
01217 {
01218 ERRPRINTF("Error sending preamble\n");
01219 return -1;
01220 }
01221 }
01222
01223 if(gs_httpd_reply(sockfd, "\r\n") < 0)
01224 {
01225 ERRPRINTF("Error sending preamble\n");
01226 return -1;
01227 }
01228
01229 return 0;
01230 }
01231
01242 int
01243 gs_send_task_list(int sockfd, char *server_cid)
01244 {
01245 gs_htm_task **tasks = NULL;
01246 int i, count;
01247 char *info;
01248
01249 gs_get_tasks_for_server(server_cid, &tasks, &count, 1);
01250
01251 if(count < 0) {
01252 ERRPRINTF("failed to get list of all tasks\n");
01253 return -1;
01254 }
01255
01256 if(!tasks) {
01257 ERRPRINTF("Empty task list despite non-negative return value!\n");
01258 return -1;
01259 }
01260
01261 for(i=0;i<count;i++) {
01262 info = dstring_sprintf("<server_cid> %s </server_cid> <task_id> %s </task_id> <start> %10.2lf </start> <duration> %10.2lf </duration> <remaining> %10.2lf </remaining> <end> %10.2lf </end> <active> %d </active> <finished> %d </finished>\n",
01263 server_cid, tasks[i]->id, tasks[i]->start, tasks[i]->duration, tasks[i]->remaining,
01264 tasks[i]->end, tasks[i]->active, tasks[i]->finished);
01265
01266 free(tasks[i]);
01267
01268 if(info) {
01269 gs_httpd_reply(sockfd, GS_BEGIN_TASK_INFO);
01270
01271 gs_httpd_reply(sockfd, info);
01272
01273 free(info);
01274
01275 gs_httpd_reply(sockfd, GS_END_TASK_INFO);
01276 }
01277 }
01278
01279 free(tasks);
01280
01281 return 0;
01282 }