server_main.c

Go to the documentation of this file.
00001 
00012 /* $Id: server_main.c,v 1.41 2007/07/04 02:44:49 seymour Exp $ */
00013 /* $UTK_Copyright: $ */
00014 
00015 #include <stdlib.h>
00016 #include <stdio.h>
00017 #include <string.h>
00018 #include <sys/types.h>
00019 #include <unistd.h>
00020 
00021 #include "utility.h"
00022 #include "server.h"
00023 #include "comm_basics.h"
00024 #include "comm_encode.h"
00025 #include "comm_data.h"
00026 #include "comm_protocol.h"
00027 #include "mfork.h"
00028 
00039 int
00040 gs_server_verify_connectivity(gs_server_t *server, int serversocket)
00041 {
00042   int sock_agent, tag;
00043   char *reqstr = NULL;
00044 
00045   sock_agent = gs_connect_direct(server->agenthost, server->agentport);
00046 
00047   if(sock_agent < 0) {
00048     ERRPRINTF("Unable to connect to agent.\n");
00049     return -1;
00050   }
00051 
00052   if((gs_send_tag(sock_agent, GS_PROT_AVAILABILITY_REQ) < 0) ||
00053      (gs_send_string(sock_agent, VERSION) < 0)) {
00054     ERRPRINTF("failed to send tag\n");
00055     gs_close_socket(sock_agent);
00056     return -1;
00057   }
00058 
00059   if(gs_recv_tag(sock_agent, &tag) < 0) {
00060     ERRPRINTF("Error communicating with agent.\n");
00061     gs_close_socket(sock_agent);
00062     return -1;
00063   }
00064 
00065   if(tag != GS_PROT_OK) {
00066     if(tag == GS_PROT_VERSION_MISMATCH)
00067       ERRPRINTF("Error: Agent is an incompatible version\n");
00068     else
00069       ERRPRINTF("Error: Agent refused with code %d\n", tag);
00070     gs_close_socket(sock_agent);
00071     return -1;
00072   }
00073 
00074   if(gs_encode_availability_request(&reqstr, server) < 0) {
00075     ERRPRINTF("Could not encode availability request.\n");
00076     return -1;
00077   }
00078     
00079   if(gs_send_string(sock_agent, reqstr) < 0) {
00080     ERRPRINTF("failed to send string\n");
00081     if(reqstr) free(reqstr);
00082     gs_close_socket(sock_agent);
00083     return -1;
00084   }
00085 
00086   gs_close_socket(sock_agent);
00087   free(reqstr);
00088 
00089   printf("Performing connectivity test.  If it hangs at this point\n");
00090   printf("and you are behind a NAT, check your GRIDSOLVE_PROXY\n");
00091   printf("environment variable.  If you are behind a firewall,\n");
00092   printf("check your port settings.\n");
00093 
00094   if((sock_agent = gs_accept_connection(serversocket)) == -1) {
00095     ERRPRINTF("Failed to accept connection on socket\n");
00096     return -1;
00097   }
00098 
00099   printf("\n\nConnectivity test successful.\n");
00100 
00101   if(gs_recv_tag(sock_agent, &tag) < 0) {
00102     ERRPRINTF("Failed to read tag.\n");
00103     return -1;
00104   }
00105 
00106   gs_close_socket(sock_agent);
00107 
00108   if(tag != GS_PROT_OK) {
00109     ERRPRINTF("Agent rejected this server (tag = %d).\n", tag);
00110     return -1;
00111   }
00112 
00113   return 0;
00114 }
00115 
00133 int
00134 gs_server_parse_cmd_line(int argc, char **argv, char *gridsolve_root,
00135    char **logfile, int *daemon, char **srv_cfg)
00136 {
00137   int c;
00138 
00139   *logfile = NULL;
00140   *daemon = 1;
00141   *srv_cfg = NULL;
00142 
00143   /* when making changes to the command line args, update
00144    * GS_SERVER_USAGE_STR so the usage information is printed
00145    * correctly upon error.
00146    */
00147 
00148 #define GS_SERVER_USAGE_STR "Usage: GS_server [-l logfile] [-c] [-s server config]"
00149 
00150   while((c = getopt(argc,argv,"cl:s:")) != EOF) {
00151     switch(c) {
00152       case 'l':
00153         *logfile = strdup(optarg);
00154         break;
00155       case 's':
00156         *srv_cfg = strdup(optarg);
00157         break;
00158       case 'c':
00159         *daemon = 0;
00160         break;
00161       case '?':
00162         return -1;
00163         break;
00164       default:
00165         ERRPRINTF("Bad arg: '%c'.\n",c);
00166         return -1;
00167     }
00168   }
00169 
00170   /* Setup default log file name if necessary */
00171   if(!*logfile) {
00172     *logfile = dstring_sprintf("%s/gs_server.log", gridsolve_root);
00173     if(!*logfile) {
00174       fprintf(stderr,"Error generating log file name.\n");
00175       exit(EXIT_FAILURE);
00176     }
00177   }
00178 
00179   /* Setup default server config file name if necessary */
00180   if(!*srv_cfg) {
00181     *srv_cfg = dstring_sprintf("%s/server_config", gridsolve_root);
00182     if(!*srv_cfg) {
00183       fprintf(stderr,"Error generating server config file name.\n");
00184       exit(EXIT_FAILURE);
00185     }
00186   }
00187 
00188   return 0;
00189 }
00190 
00197 static void
00198 server_signal_handler(int sig)
00199 {
00200   ERRPRINTF("Server terminating on signal %d...\n", sig);
00201   unlink(GS_SERVER_JOB_COUNT_FILE);
00202   exit(0);
00203 }
00204 
00218 int 
00219 main(int argc, char** argv) 
00220 {
00221   gs_server_t *gs_server = NULL;
00222   int serversocket = -1, daemon;
00223   void **wr_args;
00224   pid_t pid;
00225   char *logfile, *gridsolve_root, *srv_cfg;
00226 
00227   if(gs_signal(SIGTERM, server_signal_handler) == SIG_ERR)
00228     ERRPRINTF("Warning: could not set up SIGTERM signal handler\n");
00229   if(gs_signal(SIGINT, server_signal_handler) == SIG_ERR)
00230     ERRPRINTF("Warning: could not set up SIGINT signal handler\n");
00231 
00232   /* Check environment */
00233   if((gridsolve_root = getenv("GRIDSOLVE_ROOT")) == NULL)
00234     gridsolve_root = GRIDSOLVE_TOP_BUILD_DIR;
00235   if(!gridsolve_root) {
00236     ERRPRINTF("Warning: GRIDSOLVE_ROOT unknown, assuming cwd.\n");
00237     gridsolve_root = strdup(".");
00238   }
00239 
00240   /* Parse command line args */
00241   if(gs_server_parse_cmd_line(argc, argv, gridsolve_root, &logfile, 
00242        &daemon, &srv_cfg) < 0) {
00243     fprintf(stderr, "%s\n", GS_SERVER_USAGE_STR);
00244     exit(EXIT_FAILURE);
00245   }
00246 
00247   /* Make current process into a daemon */
00248   if(daemon && gs_daemon_init(gridsolve_root, logfile) < 0) {
00249     fprintf(stderr, "Failed to start server as a daemon.\n");
00250     exit(EXIT_FAILURE);
00251   }
00252 
00253   /* Call the server initialization code */
00254   if ((gs_server = gs_server_init(srv_cfg)) == NULL) {
00255     fprintf(stderr, "Failed to initialize the server.\n");
00256     exit(EXIT_FAILURE);
00257   }
00258   
00259 #ifdef GS_DEBUG
00260   gs_server_dump(gs_server);
00261 #endif
00262 
00263   /* Bind server to a port.  gs_server->port should be set in gs_server_init */
00264   serversocket = gs_establish_socket(&(gs_server->port), 0);
00265 
00266   if(serversocket == -1) {
00267     ERRPRINTF("Could not bind to port %d\n", gs_server->port);
00268     exit(EXIT_FAILURE);
00269   }
00270 
00271   DBGPRINTF("Bound to port %d\n\n", gs_server->port);
00272   proxy_print_local_info();
00273 
00274   if(gs_listen_on_socket(serversocket) < 0) {
00275     ERRPRINTF("Failed to listen on server socket.\n");
00276     exit(EXIT_FAILURE);
00277   }
00278 
00279   if(gs_server_verify_connectivity(gs_server, serversocket) < 0) {
00280     fprintf(stderr, "Connectivity test failed.  If you are behind a NAT,\n");
00281     fprintf(stderr, "check your GRIDSOLVE_PROXY settings.\n");
00282     exit(EXIT_FAILURE);
00283   }
00284 
00285   /* Register the server with the agent.  Cannot do this earlier, because
00286    * the listening port is not known until now
00287    */
00288   if(gs_server_register(gs_server) < 0) {
00289     ERRPRINTF("Failed to register with the agent.\n");
00290     return -1;
00291   }
00292 
00293   /* Register the problems with the agent */
00294   if(gs_server_register_problems(gs_server) < 0) {
00295     ERRPRINTF("Failed to register my problems with the agent.\n");
00296     return -1;
00297   }
00298 
00299   wr_args = (void **)malloc(sizeof(void *));
00300   if(!wr_args) {
00301     ERRPRINTF("Failed to allocate memory for child args\n");
00302     exit(EXIT_FAILURE);
00303   }
00304 
00305   wr_args[0] = gs_server;
00306 
00307   /* Monitored fork.  Forks a child processes to repeatedly run the
00308    * routine gs_workload_report.  
00309    */
00310   pid = mfork(gs_workload_report, GS_UPDATE_FREQUENCY, wr_args, 
00311     NULL, NULL, NULL, 30);
00312 
00313   if (pid < 0) {
00314     ERRPRINTF("Failed to fork workload manager process.\n");
00315     exit(EXIT_FAILURE);
00316   }
00317 
00318 #ifdef GS_SMART_GRIDSOLVE
00319   if(gs_server->smart) {
00320     pid = mfork(gs_server_ping, GS_SERVER_PING_FREQUENCY, wr_args, 
00321       NULL, NULL, NULL, 30);
00322 
00323     if (pid < 0) {
00324       ERRPRINTF("Failed to fork server ping process.\n");
00325       exit(EXIT_FAILURE);
00326     }
00327   }
00328 #endif
00329 
00330   /* Run the actual routine which listens for and handles messages */
00331   if (gs_server_listen_and_process_messages(gs_server, serversocket) < 0) 
00332     exit(EXIT_FAILURE);
00333   else 
00334     exit(EXIT_SUCCESS);
00335 }