#include "gs_agent_httpd.h"
Go to the source code of this file.
Functions | |
| static void | gs_httpd_generic_signal_handler (int sig) |
| void | gs_agent_exit (void **args) |
| void | gs_agent_httpd (void **args) |
| int | gs_agent_httpd_listen_and_process_connections (int listenfd) |
| void | sig_chld (int signo) |
| const char * | gs_get_content_type (const char *filename) |
| void | unescape_url (char *str) |
| int | gs_agent_httpd_handle_connection (int sockfd) |
| int | gs_httpd_head_file (int sockfd, const char *filename) |
| int | gs_httpd_get_file (int sockfd, const char *filename) |
| char * | gs_get_uptime_xml (struct timeval start_time, struct timeval cur_time) |
| char * | gs_get_agent_stats () |
| int | gs_httpd_connect_db (int sockfd) |
| int | gs_httpd_process_status (int sockfd) |
| int | gs_httpd_process_task_list (int sockfd) |
| int | gs_httpd_process_server_info (int sockfd, const char *filename) |
| int | gs_httpd_process_problem_info (int sockfd, const char *filename) |
| int | gs_send_problem_array (int sockfd, gs_problem_t **problem_list, int count) |
| int | gs_free_problem_array (gs_problem_t **problem_list, int count) |
| int | gs_free_server_array (gs_server_t **server_list, int count) |
| int | gs_send_server_array (int sockfd, gs_server_t **server_list, int count) |
| int | gs_read_until_crlf (int sockfd) |
| int | gs_httpd_reply (int sockfd, const char *msg) |
| char * | gs_xmlize (const char *msg) |
| int | gs_httpd_preamble (int sockfd, int num, const char *content_type, int len) |
| int | gs_send_task_list (int sockfd, char *server_cid) |
Variables | |
| char | GRIDSOLVE_STATS_FILE [] |
| char * | gs_content_types [][2] |
| gs_agent_t * | gs_httpd_agent_ptr = NULL |
| void gs_agent_exit | ( | void ** | args | ) |
Func to be called on exit.
| args | -- original args specified when mforked |
Definition at line 54 of file gs_agent_httpd.c.
{
_exit(0);
}
| void gs_agent_httpd | ( | void ** | args | ) |
This is the entry point for the http server.
| args | -- args[0] should contain a pointer to an integer whose value is the port number to use. |
Definition at line 67 of file gs_agent_httpd.c.
{
char *gridsolve_root, *www_home_path;
struct sockaddr_in servaddr;
int listenfd;
socklen_t dummyLen;
void sig_chld(int);
short port;
if(!args || !args[0] || !args[1]) {
ERRPRINTF("Bad args\n");
_exit(EXIT_FAILURE);
}
/* handle all signals except SIGINT. if the agent is running in
* console mode, we only want the parent to get SIGINT, so that all
* the children will realize the parent is dead via mfork_check_parent()
* and cleanly terminate. having all processes catch SIGINT causes
* mfork to try to restart them, depending on whether they catch it
* before or after the parent.
*/
gs_setup_signal_handlers(gs_httpd_generic_signal_handler);
signal(SIGINT, SIG_IGN);
port = *((int *)args[0]);
gs_httpd_agent_ptr = (gs_agent_t *)args[1];
if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Failed to create socket");
_exit(EXIT_FAILURE);
}
if((gridsolve_root = getenv("GRIDSOLVE_ROOT")) == NULL)
gridsolve_root = GRIDSOLVE_TOP_BUILD_DIR;
if(!gridsolve_root) {
ERRPRINTF("Warning: GRIDSOLVE_ROOT unknown, assuming cwd.\n");
gridsolve_root = strdup(".");
}
www_home_path = (char *)malloc(strlen(gridsolve_root) +
strlen(GS_AGENT_WWW_DIR) + 2);
if(!www_home_path) {
ERRPRINTF("malloc failed\n");
_exit(EXIT_FAILURE);
}
sprintf(www_home_path, "%s/%s", gridsolve_root, GS_AGENT_WWW_DIR);
if(chdir(www_home_path) < 0) {
ERRPRINTF("Failed to chdir to '%s'\n", www_home_path);
_exit(EXIT_FAILURE);
}
free(www_home_path);
memset(&servaddr, 0x0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
if(bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) {
perror("Failed to bind");
_exit(EXIT_FAILURE);
}
if(listen(listenfd, 20) < 0) {
perror("Listen failed");
_exit(EXIT_FAILURE);
}
dummyLen = sizeof(struct sockaddr);
if(getsockname(listenfd, (struct sockaddr *)(&servaddr), &dummyLen) < 0)
LOGPRINTF("HTTP server listening on some unknown port\n");
else
LOGPRINTF("HTTP server listening on port %d\n", ntohs(servaddr.sin_port));
if(gs_signal(SIGCHLD, sig_chld) == SIG_ERR) {
ERRPRINTF("Could not set up SIGCHLD signal handler\n");
_exit(EXIT_FAILURE);
}
gs_agent_httpd_listen_and_process_connections(listenfd);
_exit(EXIT_SUCCESS);
}


| int gs_agent_httpd_handle_connection | ( | int | sockfd | ) |
Handle a newly accepted http connection.
| sockfd | -- the socket to communicate on |
Definition at line 333 of file gs_agent_httpd.c.
{
ssize_t n;
char *cmd, *fn, line[MAXLINE];
if((n = gs_readline(sockfd, line, MAXLINE)) > 0) {
cmd = strtok(line, " ");
fn = strtok(NULL, " ");
if(!strcmp(cmd, "GET")) {
int rv;
LOGPRINTF("HTTP GET %s\n", fn);
gs_read_until_crlf(sockfd);
/* ignore idiots */
if(!strncmp(fn, "http://", 7))
return 0;
fn++; /* skip '/' */
unescape_url(fn);
if(*fn == '\0' || strchr(fn, '?')) {
if(gs_httpd_connect_db(sockfd) < 0)
return -1;
if(*fn == '\0' || !strcmp(fn, "status?"))
rv = gs_httpd_process_status(sockfd);
else if(!strcmp(fn, "problemlist?"))
rv = gs_httpd_process_problem_info(sockfd, NULL);
else if(!strncmp(fn, "serverinfo?", strlen("serverinfo?")))
rv = gs_httpd_process_server_info(sockfd, fn);
else if(!strncmp(fn, "probleminfo?", strlen("probleminfo?")))
rv = gs_httpd_process_problem_info(sockfd, fn);
else if(!strncmp(fn, "tasklist?", strlen("tasklist?")))
rv = gs_httpd_process_task_list(sockfd);
else
rv = gs_httpd_get_file(sockfd, fn);
/* Disconnect from database manager */
gs_storage_finalize(NULL);
}
else
rv = gs_httpd_get_file(sockfd, fn);
return rv;
}
else if(!strcmp(cmd, "HEAD")) {
int rv;
LOGPRINTF("HTTP HEAD %s\n", fn);
gs_read_until_crlf(sockfd);
/* ignore idiots */
if(!strncmp(fn, "http://", 7))
return 0;
fn++; /* skip '/' */
rv = gs_httpd_head_file(sockfd, fn);
return rv;
}
}
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}


| int gs_agent_httpd_listen_and_process_connections | ( | int | listenfd | ) |
This is the main loop that accepts and processes incoming requests.
| listenfd | -- the socket to accept connections on |
Definition at line 162 of file gs_agent_httpd.c.
{
struct sockaddr_in cliaddr;
fd_set rset, allset;
socklen_t clilen;
pid_t childpid;
struct timeval tv;
int nready, connfd;
clilen = sizeof(cliaddr);
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
for(;;) {
rset = allset;
tv.tv_sec = 1;
tv.tv_usec = 0;
nready = select(listenfd + 1, &rset, NULL, NULL, &tv);
if((nready < 0) && (errno == EINTR))
continue;
if(nready < 0) {
ERRPRINTF("select failed.. aborting.\n");
break;
}
if(nready == 0) {
if(!mfork_check_parent()) {
ERRPRINTF("Parent died, so I am exiting\n");
break;
}
continue;
}
if(FD_ISSET(listenfd, &rset)) {
if ((connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue;
else {
perror("accept error");
_exit(-1);
}
}
if ((childpid = fork()) == 0) { /* child process */
close(listenfd);
if(gs_agent_httpd_handle_connection(connfd) < 0) {
ERRPRINTF("Failed to handle connection.\n");
_exit(-1);
}
close(connfd);
_exit(0);
}
close(connfd); /* parent closes connected socket */
}
}
return 0;
}


| int gs_free_problem_array | ( | gs_problem_t ** | problem_list, | |
| int | count | |||
| ) |
Free the memory allocated for the problem array.
| problem_list | -- the array of problems to free | |
| count | -- the number of elements in the problem_list array |
Definition at line 985 of file gs_agent_httpd.c.
{
int i;
for(i = 0; i < count; i++)
gs_free_problem(problem_list[i]);
FREE(problem_list);
return 0;
}


| int gs_free_server_array | ( | gs_server_t ** | server_list, | |
| int | count | |||
| ) |
Free the memory allocated for the server array.
| server_list | -- the array of servers to free | |
| count | -- the number of elements in the server_list array |
Definition at line 1005 of file gs_agent_httpd.c.
{
int i;
for(i = 0; i < count; i++)
gs_server_free(server_list[i]);
FREE(server_list);
return 0;
}


| char* gs_get_agent_stats | ( | ) |
Return XML formatted information with all relevant agent statistics.
Definition at line 574 of file gs_agent_httpd.c.
{
gs_agent_stats_t *cur_stats;
char *stats_xml, *hostname_xml, *port_xml, *uptime_xml;
struct timeval cur_time;
int sfd;
stats_xml = hostname_xml = port_xml = uptime_xml = NULL;
sfd = open(GRIDSOLVE_STATS_FILE, O_RDONLY);
if(sfd < 0) goto stats_error;
stats_xml = dstring_sprintf(GS_BEGIN_AGENT_STATS);
if(!stats_xml) goto stats_error;
cur_stats = (gs_agent_stats_t *) mmap((caddr_t)0,
sizeof(gs_agent_stats_t), PROT_READ, MAP_SHARED, sfd, 0);
if(cur_stats == (gs_agent_stats_t *)(-1))
goto stats_error;
gettimeofday(&cur_time, NULL);
uptime_xml = gs_get_uptime_xml(cur_stats->start_time, cur_time);
hostname_xml = dstring_sprintf("%s%s%s", GS_BEGIN_AGENT_NAME,
cur_stats->hostname, GS_END_AGENT_NAME);
port_xml = dstring_sprintf("%s%d%s", GS_BEGIN_AGENT_PORT,
cur_stats->port, GS_END_AGENT_PORT);
if(hostname_xml)
stats_xml = dstring_append(stats_xml, hostname_xml);
if(port_xml)
stats_xml = dstring_append(stats_xml, port_xml);
if(uptime_xml)
stats_xml = dstring_append(stats_xml, uptime_xml);
stats_xml = dstring_append(stats_xml, GS_END_AGENT_STATS);
close(sfd);
if(hostname_xml) free(hostname_xml);
if(port_xml) free(port_xml);
if(uptime_xml) free(uptime_xml);
return stats_xml;
stats_error:
if(sfd >= 0)
close(sfd);
if(hostname_xml) free(hostname_xml);
if(port_xml) free(port_xml);
if(uptime_xml) free(uptime_xml);
return strdup("<agent_stats></agent_stats>");
}


| const char* gs_get_content_type | ( | const char * | filename | ) |
Gets the content type of a filename based on its extension.
| filename | -- the filename whose extension should be returned. if an appropriate content type can't be determined "text/html" is returned. DONT free the string returned by this function. |
Definition at line 253 of file gs_agent_httpd.c.
{
const char *end;
int i;
if(filename && (strlen(filename) > 0)) {
end = filename + strlen(filename) - 1;
while(end != filename) {
if(*end == '.') {
end++;
break;
}
end--;
}
if(end == filename)
return GS_DEFAULT_CONTENT_TYPE;
for(i=0; gs_content_types[i][0]; i++)
if(!strcmp(end, gs_content_types[i][0]))
return(gs_content_types[i][1]);
}
return GS_DEFAULT_CONTENT_TYPE;
}

| char* gs_get_uptime_xml | ( | struct timeval | start_time, | |
| struct timeval | cur_time | |||
| ) |
Computes the agent's uptime in terms of days, hours, minutes, and seconds based on two timeval structs (start time and current time). Return an XML string containing the information.
| start_time | -- the time the agent was started | |
| cur_time | -- the current time |
Definition at line 535 of file gs_agent_httpd.c.
{
struct timeval time_diff;
char *xml_time;
long s_diff;
long days;
long hours;
long minutes;
long seconds;
timersub(&cur_time, &start_time, &time_diff);
s_diff = time_diff.tv_sec;
days = s_diff / SECSPERDAY;
if(days > 0) s_diff -= days * SECSPERDAY;
hours = s_diff / SECSPERHOUR;
if(hours > 0) s_diff -= hours * SECSPERHOUR;
minutes = s_diff / SECSPERMIN;
if(minutes > 0) s_diff -= minutes * SECSPERMIN;
seconds = s_diff;
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);
if(!xml_time) goto uptime_error;
return xml_time;
uptime_error:
return strdup("<agent_uptime></agent_uptime>\n");
}


| int gs_httpd_connect_db | ( | int | sockfd | ) |
Connect to the database manager.
| sockfd | -- on error, the error information will be written to this descriptor. |
Definition at line 637 of file gs_agent_httpd.c.
{
int err;
err = gs_storage_init(gs_httpd_agent_ptr);
if ( err < 0 ) {
ERRPRINTF("Could not connect to database manager.\n");
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_DB_FAILURE);
return -1;
}
return 0;
}


| static void gs_httpd_generic_signal_handler | ( | int | sig | ) | [static] |
Signal handler for various signals. Exit with normal status.
| sig | -- the signal that was caught |
Definition at line 35 of file gs_agent_httpd.c.
{
/* pass along SIGHUP to parent */
if(sig == SIGHUP) {
kill(getppid(), SIGHUP);
return;
}
ERRPRINTF("HTTP server terminating on signal %d.\n", sig);
_exit(0);
}

| int gs_httpd_get_file | ( | int | sockfd, | |
| const char * | filename | |||
| ) |
Handle an HTTP GET request.
| sockfd | -- the socket to communicate on | |
| filename | -- the name of the requested file |
Definition at line 459 of file gs_agent_httpd.c.
{
const char *mime_type;
double elapsed_time;
struct stat stbuf;
char buf[MAXLINE];
int fd, n;
if(!filename) {
ERRPRINTF("Invalid filename, ptr is null.\n");
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
if(stat(filename, &stbuf) < 0) {
ERRPRINTF("Could not stat file '%s'\n", filename);
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
if((fd = open(filename, O_RDONLY)) == -1) {
ERRPRINTF("Failed to open file '%s'\n", filename);
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
if((mime_type = gs_get_content_type(filename)) == NULL) {
ERRPRINTF("Failed to get content type for '%s'\n", filename);
ERRPRINTF(" [probably out of memory]\n");
close(fd);
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
gs_httpd_preamble(sockfd, 200, mime_type, (int)stbuf.st_size);
elapsed_time = walltime();
while((n=read(fd, buf, MAXLINE)) > 0) {
if(gs_twrite(sockfd, buf, n) != n) {
ERRPRINTF("error in sending data\n");
close(fd);
return -1;
}
}
elapsed_time = walltime() - elapsed_time;
close(fd);
if(n < 0)
ERRPRINTF("Warning: read error on file '%s'\n", filename);
LOGPRINTF("Sent %d bytes in %g seconds (%g Kbyte/s)\n", (int)stbuf.st_size,
elapsed_time, ((double)stbuf.st_size/1024.0) / elapsed_time);
return 0;
}


| int gs_httpd_head_file | ( | int | sockfd, | |
| const char * | filename | |||
| ) |
Handle an HTTP HEAD request.
| sockfd | -- the socket to communicate on | |
| filename | -- the name of the requested file |
Definition at line 417 of file gs_agent_httpd.c.
{
struct stat stbuf;
const char *mime_type;
if(!filename) {
ERRPRINTF("Invalid filename, ptr is null.\n");
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
if(stat(filename, &stbuf) < 0) {
ERRPRINTF("Could not stat file '%s'\n", filename);
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
if((mime_type = gs_get_content_type(filename)) == NULL) {
ERRPRINTF("Failed to get content type for '%s'\n", filename);
ERRPRINTF(" [probably out of memory]\n");
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
gs_httpd_preamble(sockfd, 200, mime_type, (int)stbuf.st_size);
return 0;
}


| int gs_httpd_preamble | ( | int | sockfd, | |
| int | num, | |||
| const char * | content_type, | |||
| int | len | |||
| ) |
Sends the usual premble stuff back to the browser. Currently this consists of: HTTP/1.1 <num> OK Server: GridSolve beta Content-Type: <content_type> Content-Length: <file_length>
| sockfd | -- the socket to communicate on | |
| num | -- the protocol number (e.g. 200, 404, etc) | |
| content_type | -- the content type of the reply | |
| len | -- the content length of the file |
Definition at line 1196 of file gs_agent_httpd.c.
{
char http_resp_line[MAXLINE], mime_type_line[MAXLINE], len_line[MAXLINE];
if(!content_type)
content_type = GS_DEFAULT_CONTENT_TYPE;
sprintf(http_resp_line, "HTTP/1.1 %d OK\n", num);
sprintf(mime_type_line, "Content-Type: %s\n", content_type);
sprintf(len_line, "Content-Length: %d\n", len);
if((gs_httpd_reply(sockfd, http_resp_line) < 0) ||
(gs_httpd_reply(sockfd, "Server: GridSolve beta\n") < 0) ||
(gs_httpd_reply(sockfd, mime_type_line) < 0))
{
ERRPRINTF("Error sending preamble\n");
return -1;
}
if(len > 0) {
if(gs_httpd_reply(sockfd, len_line) < 0)
{
ERRPRINTF("Error sending preamble\n");
return -1;
}
}
if(gs_httpd_reply(sockfd, "\r\n") < 0)
{
ERRPRINTF("Error sending preamble\n");
return -1;
}
return 0;
}


| int gs_httpd_process_problem_info | ( | int | sockfd, | |
| const char * | filename | |||
| ) |
Handle a problem information request. Return all relevant information about the specified problem.
| sockfd | -- the socket to communicate on | |
| filename | -- the request string. if NULL, returns all problems, if "probleminfo?problemname", then only returns information about "problemname". |
Definition at line 834 of file gs_agent_httpd.c.
{
char *problem_name, *fn_copy;
gs_problem_t **problem_list = NULL;
int count;
fn_copy = problem_name = NULL;
if(filename) {
fn_copy = (char *)strdup(filename);
if(!fn_copy) return -1;
problem_name = strtok(fn_copy, "?");
problem_name = strtok(NULL, "?");
if(!problem_name) {
ERRPRINTF("Error parsing problem info request.\n");
free(fn_copy);
gs_httpd_preamble(sockfd, 404, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_404);
return -1;
}
}
if(problem_name) {
count = gs_get_problem_info(NULL, &problem_list, &count, problem_name);
if(count == 0) {
free(fn_copy);
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_BAD_PROBLEM_REQ);
return -1;
}
}
else
count = gs_get_all_problems(NULL, &problem_list, &count);
if(count < 0)
ERRPRINTF("Warning: failed to get problem(s)\n");
if(problem_name) {
gs_httpd_preamble(sockfd, 200, "application/xml", 0);
gs_httpd_reply(sockfd, GS_XML_HEADER_PROBLEMINFO);
gs_httpd_reply(sockfd, GS_BEGIN_PROBLEM_INFO);
}
else {
char *agent_stats = gs_get_agent_stats();
if(!agent_stats) {
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
return -1;
}
gs_httpd_preamble(sockfd, 200, "application/xml", 0);
gs_httpd_reply(sockfd, GS_XML_HEADER_SERVERLIST);
gs_httpd_reply(sockfd, GS_BEGIN_SYSTEM_STATUS);
gs_httpd_reply(sockfd, agent_stats);
free(agent_stats);
}
if(count > 0) {
gs_send_problem_array(sockfd, problem_list, count);
gs_free_problem_array(problem_list, count);
}
if(problem_name) {
gs_server_t **server_list = NULL;
gs_problem_t *prob;
prob = (gs_problem_t *)calloc(1, sizeof(gs_problem_t));
if(prob) {
/* dup the string here since gs_get_server_list will free it
* before filling out the rest of the problem structure.
*/
prob->name = strdup(problem_name);
if(prob->name) {
count =
gs_get_server_list(NULL, prob, NULL, &server_list, &count);
if(count > 0) {
gs_send_server_array(sockfd, server_list, count);
gs_free_server_array(server_list, count);
}
}
gs_free_problem(prob);
}
free(fn_copy);
gs_httpd_reply(sockfd, GS_END_PROBLEM_INFO);
}
else
gs_httpd_reply(sockfd, GS_END_SYSTEM_STATUS);
return 0;
}


| int gs_httpd_process_server_info | ( | int | sockfd, | |
| const char * | filename | |||
| ) |
Handle a server information request. Return all relevant information about the specified server.
| sockfd | -- the socket to communicate on | |
| filename | -- the request string: "serverinfo?servername" |
Definition at line 755 of file gs_agent_httpd.c.
{
gs_problem_t **problem_list;
gs_server_t **server_list;
char *cid, *fn_copy;
int count;
problem_list = NULL;
server_list = NULL;
if(!filename) {
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
return -1;
}
fn_copy = (char *)strdup(filename);
if(!fn_copy) {
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
return -1;
}
cid = strtok(fn_copy, "?");
cid = strtok(NULL, "?");
if(!cid) {
free(fn_copy);
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_BAD_SERVER_REQ);
return -1;
}
server_list = (gs_server_t **)malloc(sizeof(gs_server_t *));
server_list[0] = (gs_server_t *)calloc(1, sizeof(gs_server_t));
if(gs_get_server_by_cid(NULL, cid, server_list[0]) < 0) {
ERRPRINTF("failed to get servers\n");
free(server_list[0]);
free(server_list);
free(fn_copy);
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_BAD_SERVER_REQ);
return -1;
}
gs_httpd_preamble(sockfd, 200, "application/xml", 0);
gs_httpd_reply(sockfd, GS_XML_HEADER_SERVERINFO);
gs_httpd_reply(sockfd, GS_BEGIN_SERVER_INFO);
gs_send_server_array(sockfd, server_list, 1);
if(gs_get_problem_list(NULL, server_list[0], &problem_list, &count) >= 0) {
gs_send_problem_array(sockfd, problem_list, count);
gs_free_problem_array(problem_list, count);
}
gs_httpd_reply(sockfd, GS_END_SERVER_INFO);
gs_free_server_array(server_list, 1);
free(fn_copy);
return 0;
}


| int gs_httpd_process_status | ( | int | sockfd | ) |
Handle a status request. Return agent statistics and a list of all available servers.
| sockfd | -- the socket to communicate on |
Definition at line 662 of file gs_agent_httpd.c.
{
gs_server_t **server_list = NULL;
char *agent_stats;
int count;
count = gs_get_all_servers(NULL, &server_list, &count);
if(count < 0)
ERRPRINTF("Warning: failed to get list of all servers\n");
agent_stats = gs_get_agent_stats();
if(!agent_stats) {
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
return -1;
}
gs_httpd_preamble(sockfd, 200, "application/xml", 0);
gs_httpd_reply(sockfd, GS_XML_HEADER_SERVERLIST);
gs_httpd_reply(sockfd, GS_BEGIN_SYSTEM_STATUS);
gs_httpd_reply(sockfd, agent_stats);
free(agent_stats);
if(count > 0) {
gs_send_server_array(sockfd, server_list, count);
gs_free_server_array(server_list, count);
}
gs_httpd_reply(sockfd, GS_END_SYSTEM_STATUS);
return 0;
}


| int gs_httpd_process_task_list | ( | int | sockfd | ) |
Return list of all task info stored in the database.
| sockfd | -- the socket to communicate on |
Definition at line 707 of file gs_agent_httpd.c.
{
gs_server_t **server_list = NULL;
int i, count;
count = gs_get_all_servers(NULL, &server_list, &count);
if(count < 0)
ERRPRINTF("Warning: failed to get list of all servers\n");
if(!server_list) {
gs_httpd_preamble(sockfd, 403, GS_DEFAULT_CONTENT_TYPE, 0);
gs_httpd_reply(sockfd, GS_RESPONSE_INTERNAL_ERROR);
return -1;
}
gs_httpd_preamble(sockfd, 200, "application/xml", 0);
gs_httpd_reply(sockfd, GS_XML_HEADER_TASKLIST);
gs_httpd_reply(sockfd, GS_BEGIN_TASK_LIST);
if(count > 0) {
char printable_id[CID_LEN*2+1];
for(i=0;i<count;i++) {
proxy_cid_to_str(printable_id, server_list[i]->componentid);
gs_send_task_list(sockfd, printable_id);
}
gs_free_server_array(server_list, count);
}
gs_httpd_reply(sockfd, GS_END_TASK_LIST);
return 0;
}


| int gs_httpd_reply | ( | int | sockfd, | |
| const char * | msg | |||
| ) |
Send a string on the socket. Before sending, the string is processed to remove characters that XML doesn't like such as <, >, and &.
| sockfd | -- the socket to communicate on | |
| msg | -- the string to be sent. |
Definition at line 1099 of file gs_agent_httpd.c.
{
char *xml;
int n;
xml = gs_xmlize(msg);
n = gs_twrite(sockfd, xml, strlen(xml));
free(xml);
return n;
}


| int gs_read_until_crlf | ( | int | sockfd | ) |
Reads from the socket until a newline is seen. This is used to grab and throw away all the junk that the browser sends after the HTTP GET.
| sockfd | -- the socket to communicate on |
Definition at line 1069 of file gs_agent_httpd.c.
{
char line[MAXLINE];
int n;
for (;;) {
if ((n = gs_readline(sockfd, line, MAXLINE)) == 0)
return 0;
line[strlen(line)-2] = 0;
if(!strcmp(line, ""))
return 0;
}
return 0;
}


| int gs_send_problem_array | ( | int | sockfd, | |
| gs_problem_t ** | problem_list, | |||
| int | count | |||
| ) |
Send an array of problems on the socket.
| sockfd | -- the socket to communicate on | |
| problem_list | -- array of problem structures to be sent in xml form | |
| count | -- the number of elements in the problem_list array |
Definition at line 945 of file gs_agent_httpd.c.
{
int i;
if(!problem_list) {
ERRPRINTF("Invalid arg: null problem_list\n");
return -1;
}
gs_httpd_reply(sockfd, GS_BEGIN_PROBLEM_LIST);
for(i = 0; i < count; i++) {
char *prob = NULL;
if(gs_encode_problem(&prob, problem_list[i]) < 0) {
FREE(prob);
ERRPRINTF("Failed to send problem list\n");
return -1;
}
gs_httpd_reply(sockfd, prob);
gs_httpd_reply(sockfd, "\n");
FREE(prob);
}
gs_httpd_reply(sockfd, GS_END_PROBLEM_LIST);
return 0;
}


| int gs_send_server_array | ( | int | sockfd, | |
| gs_server_t ** | server_list, | |||
| int | count | |||
| ) |
Send an array of servers on the socket.
| sockfd | -- the socket to communicate on | |
| server_list | -- array of server structures to be sent in xml form | |
| count | -- the number of elements in the server_list array |
Definition at line 1027 of file gs_agent_httpd.c.
{
int i;
if(!server_list) {
ERRPRINTF("Invalid arg: null server_list\n");
return -1;
}
gs_httpd_reply(sockfd, GS_BEGIN_SERVER_LIST);
for(i = 0; i < count; i++) {
char *srv = NULL;
DBGPRINTF("Encoding server: %s.\n", server_list[i]->hostname);
if(gs_encode_server(&srv, server_list[i]) < 0) {
FREE(srv);
DBGPRINTF("Failed to send server list \n");
return -1;
}
gs_httpd_reply(sockfd, srv);
gs_httpd_reply(sockfd, "\n");
FREE(srv);
}
gs_httpd_reply(sockfd, GS_END_SERVER_LIST);
return 0;
}


| int gs_send_task_list | ( | int | sockfd, | |
| char * | server_cid | |||
| ) |
Pulls all the task information out of the database and sends it back as xml-like document.
| sockfd | -- the socket to communicate on | |
| server_cid | -- the server whose tasks we should return |
Definition at line 1243 of file gs_agent_httpd.c.
{
gs_htm_task **tasks = NULL;
int i, count;
char *info;
gs_get_tasks_for_server(server_cid, &tasks, &count, 1);
if(count < 0) {
ERRPRINTF("failed to get list of all tasks\n");
return -1;
}
if(!tasks) {
ERRPRINTF("Empty task list despite non-negative return value!\n");
return -1;
}
for(i=0;i<count;i++) {
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",
server_cid, tasks[i]->id, tasks[i]->start, tasks[i]->duration, tasks[i]->remaining,
tasks[i]->end, tasks[i]->active, tasks[i]->finished);
free(tasks[i]);
if(info) {
gs_httpd_reply(sockfd, GS_BEGIN_TASK_INFO);
gs_httpd_reply(sockfd, info);
free(info);
gs_httpd_reply(sockfd, GS_END_TASK_INFO);
}
}
free(tasks);
return 0;
}


| char* gs_xmlize | ( | const char * | msg | ) |
This funciton "XMLizes" a string. The input string is already in an xml-like format, but may have <, >, or & embedded in the attributes. This function only removes those characters that are in double-quoted attribute values. they are replaced with <, >, and &.
| msg | -- the string to "XMLize" |
Definition at line 1126 of file gs_agent_httpd.c.
{
char *xmlized_msg, *xp;
int inside_string;
const char *op;
if(!msg) return NULL;
/* in the worst case, the string will be 5 times longer, so
* rather than constantly checking whether we need to realloc,
* just alloc 5 * strlen(msg) here.
*/
xmlized_msg = (char *)malloc(5 * strlen(msg));
if(!xmlized_msg)
return NULL;
inside_string = FALSE;
for(op = msg, xp = xmlized_msg; *op != '\0'; op++) {
if(*op == '"') {
inside_string = inside_string ? FALSE : TRUE;
*xp++ = *op;
continue;
}
if(inside_string) {
switch(*op) {
case '&':
strcpy(xp, "&");
xp += strlen("&");
break;
case '<':
strcpy(xp, "<");
xp += strlen("<");
break;
case '>':
strcpy(xp, ">");
xp += strlen(">");
break;
default:
*xp++ = *op;
}
}
else
*xp++ = *op;
}
*xp = '\0';
return xmlized_msg;
}

| void sig_chld | ( | int | signo | ) |
Handler for SIGCHLD. calls waitpid() to get rid of zombies.
| signo | -- the signal caught (SIGCHLD) |
Definition at line 231 of file gs_agent_httpd.c.
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
DBGPRINTF("child %d terminated\n", (int)pid);
return;
}

| void unescape_url | ( | char * | str | ) |
Remove percent escape sequences from the URL.
| str | -- string containing the URL. This is modified in place to contain the unescaped URL. |
Definition at line 288 of file gs_agent_httpd.c.
{
char tmp[3] = {0, 0, 0};
int unescaped_char;
int i, idx;
if(!str) return;
idx = 0;
for(i=0;i<strlen(str);i++) {
memset(tmp, 0, 3);
if(str[i] == '%') {
if(str[i+1] != 0) {
tmp[0] = str[i+1];
if(str[i+2] != 0) {
tmp[1] = str[i+2];
i += 2;
}
else
i++;
}
sscanf(tmp, "%x", &unescaped_char);
}
else
unescaped_char = str[i];
str[idx++] = unescaped_char;
}
str[idx] = 0;
}

| char GRIDSOLVE_STATS_FILE[] |
| char* gs_content_types[][2] |
{
{"xsl", "application/xml"},
{"html", "text/html"},
{"xml", "application/xml"},
{"ico", "image/x-ico"},
{"avi", "video/avi"},
{"md5", "text/md5"},
{"srt", "text/srt"},
{NULL, "text/html"}
}
Definition at line 15 of file gs_agent_httpd.c.
| gs_agent_t* gs_httpd_agent_ptr = NULL |
Definition at line 26 of file gs_agent_httpd.c.
1.6.3-20100507