gsgrpc.c

Go to the documentation of this file.
00001 
00015 /*
00016  * $Id: gsgrpc.c,v 1.175 2010/04/27 16:43:56 tbrady Exp $ 
00017  */
00018 /*
00019  * $UTK_Copyright: $ 
00020  */
00021 
00022 #include <stdio.h>
00023 #include <stdarg.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <signal.h>
00027 
00028 #define ERROR_MAIN
00029 
00030 #ifdef HAVE_CONFIG_H
00031 #include "config.h"
00032 #endif /* HAVE_CONFIG_H */
00033 
00034 #include "portability.h"
00035 #include "grpc.h"
00036 #include "icl_hash.h"
00037 #ifdef GS_SMART_GRIDSOLVE
00038 #include "gs_smart_clib.h"
00039 #include "gs_smart_mapping_graph.h"
00040 #include "gs_smart_mapping_heuristics.h"
00041 #include "gs_smart_app_pm_builder.h"
00042 #endif
00043 
00044 #ifndef TRUE
00045 #define TRUE 1
00046 #endif
00047 #ifndef FALSE
00048 #define FALSE 0
00049 #endif
00050 
00051 /*
00052  * va_copy is not portable.  GNU suggests the following work-around -JL
00053  * 10/13/2004 
00054  */
00055 #if ! defined va_copy
00056 #if defined __va_copy
00057 #define va_copy __va_copy
00058 #else
00059 #define va_copy(dst, src) memcpy (&dst, &src, sizeof(va_list))
00060 #endif
00061 #endif
00062 
00063 
00064 
00065 
00066 #ifdef GS_SMART_GRIDSOLVE
00067 
00068 /*
00069  * call type indicates whether the one pass or two pass method for
00070  * mapping a group of tasks has been called
00071  */
00072   static int call_type;
00073 
00074 
00075 
00076 
00077  /*
00078   * map_call_type indicates whether the group of task to be mapped has been specified
00079   * explicitly as a parameter to the gs_smart_map function or implicitly by using either 
00080   * paranthesis or the gs_smart_end_map call.
00081   */
00082   static int group_type;  
00083 
00084 
00085 /*
00086  * smart_phase indicates the operation are we currently doing 
00087  * (building, mapping, executing stored handles, executing called handles or standard gridsolve execution)
00088  * default is set to standard gridsolve execution
00089  */
00090   static int smart_phase=GS_SMART_STANDARD_EXEC;  
00091 
00092 
00093 
00094 /*
00095  * smart_app_num is a unique number given to each execution of an application
00096  * this number is appended on to the file names where remote arguments are stored.
00097  * this is to ensure that file names of remote arguments are unique.
00098  * in addition the process id and unique argument id is also appended to the file name.
00099  */
00100   static int smart_app_num;
00101 
00102 
00103 /*
00104  * handle_task_count variable is used when executing called handles 
00105  * in the second  pass on a two pass call type.
00106  * the variable is used to determine which handle the called handle is in 
00107  * the group of mapped handles.
00108  * this information is used to retrieve the relevant mapping information for
00109  * the called handle.
00110  */
00111 
00112   static int total_nb_mapped_tasks=0;
00113   
00114 
00115  static int nb_mapped_tasks_executed=0;
00116 
00117  /* type of communication scheme to implement in task graph*/ 
00118  char * set_comm_type;
00119 
00120 
00121 #endif
00122 
00123 /*
00124  * current_pass indicates which pass is currently been undertaken.
00125  *
00126  * for the two pass call type the first pass  (current_pass=0) will be the
00127  * task discovery phase.
00128  * the second pass (current_pass=1) will be first the mapping phase 
00129  * and then executing called handles phase.
00130  *
00131  * for the one pass call type the first pass will involve  all phases.
00132  * first the building phase, when all tasks in the group have been called
00133  * it enters the mapping phase. This is followed by the executing stored handles 
00134  * phase.
00135  */
00136   static int current_pass=0;
00137 
00138 
00139 
00140 
00142 char *GRPC_ERROR_MESSAGES[] = {
00143   "Success",
00144   "GRPC client not initialized yet",
00145   "GRPC client already initialized",
00146   "Specified configuration file not found",
00147   "An error occurred parsing or processing the configuration file",
00148   "GRPC client cannot find any server",
00149   "GRPC client cannot find the function on the default server",
00150   "Function handle is not valid",
00151   "Session ID is not valid",
00152   "RPC invocation refused by the server",
00153   "Communication with the server failed somehow",
00154   "The specified session failed",
00155   "Call has not completed",
00156   "No calls have completed",
00157   "Internal error detected",
00158   "Error description string requested for an unknown error code",
00159   "Highest error code; used to bound error codes [does not denote actual error]"
00160 };
00161 
00162 /* note that minor error codes begin at 256, so to reference the string
00163  * in this array, just subtract GRPC_NO_MINOR_ERROR from the index
00164  * (e.g. GRPC_MINOR_ERROR_MESSAGES[err-GRPC_NO_MINOR_ERROR]).
00165  */
00166 char *GRPC_MINOR_ERROR_MESSAGES[] = {
00167   "No minor error specified",
00168   "Function handle is NULL",
00169   "Function name is NULL",
00170   "Argument stack is NULL",
00171   "Out of memory",
00172   "Hostname could not be resolved",
00173   "GridSolve agent not set or unavailable",
00174   "Failed to encode submit request",
00175   "Failed to encode solve request",
00176   "Failed to decode problem structure",
00177   "Failed to encode problem structure",
00178   "Failed to decode server structure",
00179   "Failed to encode server structure",
00180   "Could not parse host name",
00181   "Could not establish connection to server",
00182   "Could not kill data transfer process",
00183   "Invalid serialized request",
00184   "Could not duplicate problem structure",
00185   "Profiling is not enabled",
00186   "Invalid (or NULL) major",
00187   "Invalid LANGUAGE",
00188   "No match found for session ID",
00189   "Iterator is NULL",
00190   "Could not setup farming args",
00191   "Could not build argument stack for farming",
00192   "Agent or server has incompatible version",
00193   "DSI Disabled",
00194   "DSI Manage Error",
00195   "DSI Unknown File",
00196   "DSI Allocation Error",
00197   "DSI Permission Denied",
00198   "DSI Load Error",
00199   "DSI Store Error",
00200   "DSI Internal Error",
00201   "Highest error code; used to bound error codes [does not denote actual error]"
00202 };
00203 
00212 #define GS_PORT_DELIM '/'
00213 #define GS_PROXY_DELIM '%'
00214 #define GS_MAX_PINGS 5
00215 #define GS_DEFAULT_CACHE_TTL 300
00216 #define GS_DEFAULT_TIME_THRESH 1.0
00217 
00219 grpc_error_t grpc_errno = GRPC_NO_ERROR;
00220 gs_service_error_enum_t grpc_minor_errno = GRPC_NO_MINOR_ERROR;
00221 int grpc_client_major = 'r';
00222 int grpc_client_lang = GS_CALL_FROM_C;
00223 int grpc_user_set_major = FALSE;
00224 grpc_profile_t *grpc_profile_next = NULL;
00225 char grpc_user[GRPC_USER_INFO_LEN];
00226 char grpc_host[GRPC_USER_INFO_LEN];
00227 char grpc_domain[GRPC_USER_INFO_LEN];
00228 char grpc_cid_str[2*CID_LEN+1];
00229 int grpc_measure_comm = 1;
00230 int grpc_measure_comm_num_servers = GS_MAX_PINGS;
00231 int grpc_measure_comm_cache_ttl = GS_DEFAULT_CACHE_TTL;
00232 double grpc_measure_comm_time_thresh = GS_DEFAULT_TIME_THRESH;
00233 icl_hash_t *grpc_comm_cache = NULL;
00234 
00238 static grpc_request_t *grpc_outstanding_requests[MAX_GRPC_REQUESTS];
00239 static grpc_profile_t *grpc_profile_info[MAX_GRPC_REQUESTS];
00240 static grpc_error_t grpc_errors[MAX_GRPC_REQUESTS];
00241 static grpc_sessionid_t grpc_last_failed_sid[MAX_GRPC_REQUESTS];
00242 static int grpc_last_failed_idx = -1;
00243 static gs_service_error_enum_t grpc_minor_errors[MAX_GRPC_REQUESTS];
00244 static int grpc_initialized = FALSE;
00245 static agent_host_info_t *agent_resolved = NULL;
00246 
00247 /*
00248  * Local function prototypes 
00249  */
00250 
00251 static grpc_error_t
00252   gs_call_common(grpc_function_handle_t *, grpc_sessionid_t *, gs_va_list *, 
00253      void **, int),
00254   gs_call_common_ft(grpc_function_handle_t *, grpc_sessionid_t *, gs_va_list *, 
00255      void **, int),
00256   grpc_function_handle_common(grpc_function_handle_t *, char *, char *),
00257   gs_resubmit_common(int);
00258 
00259 static int 
00260   gs_notify_agent_of_failure(grpc_function_handle_t *, char *),
00261   gs_notify_agent_of_cancel(grpc_function_handle_t *, char *),
00262   gs_get_server_mapping(char *, grpc_function_handle_t *, gs_va_list *,
00263                         void **, int, int, int),
00264   gs_parse_host_port(char *, ipaddr_t *, in_port_t *),
00265   gs_parse_host_info(char *, ipaddr_t *, in_port_t *, ipaddr_t *, in_port_t *,
00266                      char *), 
00267   grpc_request_destruct(grpc_request_t *), 
00268   gs_free_handle_server_list(grpc_function_handle_t *);
00269 
00270 static void
00271   grpc_function_handle_clear(grpc_function_handle_t *);
00272 
00274 #define GRPC_CLEAR_ERRORS() do { \
00275   memset(grpc_errors, 0, MAX_GRPC_REQUESTS * sizeof(*grpc_errors));\
00276   memset(grpc_minor_errors, 0, MAX_GRPC_REQUESTS * sizeof(*grpc_minor_errors));\
00277   } while(0);
00278 
00279 #define GRPC_FAIL_IF_NOT_INITIALIZED(retval) \
00280   if(!grpc_initialized) { \
00281     grpc_errno = GRPC_NOT_INITIALIZED; \
00282     grpc_minor_errno = GRPC_NO_MINOR_ERROR; \
00283     return retval; \
00284   }
00285 
00293 SOCKET
00294 gs_connect_to_agent()
00295 {
00296   char agent_cid[CID_LEN];
00297   struct timeval cur;
00298 
00299   /* all ones will match any component ID */
00300   memset(agent_cid, 0xFF, CID_LEN);
00301 
00302   gettimeofday(&cur, NULL);
00303 
00304   /* check if the cached entry has expired */
00305 
00306   if(agent_resolved) {
00307     if(cur.tv_sec - agent_resolved->creation_time.tv_sec > AGENT_IP_EXPIRATION) {
00308       free(agent_resolved->hostname);
00309       free(agent_resolved);
00310       agent_resolved = NULL;
00311     }
00312   }
00313 
00314   if(!agent_resolved) {
00315     struct hostent *hp;
00316     char *tmp;
00317 
00318     agent_resolved = (agent_host_info_t *) malloc(sizeof(agent_host_info_t));
00319 
00320     if(!agent_resolved) {
00321       grpc_errno = GRPC_OTHER_ERROR_CODE;
00322       grpc_minor_errno = GRPC_OUT_OF_MEMORY;
00323       return INVALID_SOCKET;
00324     }
00325 
00326     tmp = getenv("GRIDSOLVE_AGENT");
00327 
00328     agent_resolved->hostname = tmp ? strdup(tmp) : NULL;
00329 
00330     if(!agent_resolved->hostname) {
00331       grpc_errno = GRPC_OTHER_ERROR_CODE;
00332       grpc_minor_errno = GRPC_AGENT_NOT_SET;
00333       return INVALID_SOCKET;
00334     }
00335 
00336     agent_resolved->port =
00337         getenv_int("GRIDSOLVE_AGENT_PORT", GRIDSOLVE_AGENT_PORT_DEFAULT);
00338 
00339     if((hp = gethostbyname(agent_resolved->hostname)) == NULL) {
00340       ERRPRINTF("Could not resolve host name '%s'\n", agent_resolved->hostname);
00341       perror("gethostbyname()");
00342       grpc_errno = GRPC_RPC_REFUSED;
00343       grpc_minor_errno = GRPC_AGENT_NOT_SET;
00344       return INVALID_SOCKET;
00345     }
00346 
00347     memcpy((void *) &(agent_resolved->ipaddr), hp->h_addr_list[0], sizeof(ipaddr_t));
00348 
00349     agent_resolved->creation_time = cur;
00350   }
00351 
00352   return gs_connect_to_host(agent_cid, agent_resolved->ipaddr, agent_resolved->port, 0, 0);
00353 }
00354 
00369 grpc_error_t
00370 grpc_process_config_file(char *config_file_name)
00371 {
00372   gs_info_t *attr_list = NULL;
00373   gs_struct_stat stbuf;
00374 
00375   if(!config_file_name)
00376     GRPC_RETURN(GRPC_CONFIGFILE_NOT_FOUND, GRPC_NO_MINOR_ERROR);
00377 
00378   if(gs_stat(config_file_name, &stbuf) < 0)
00379     GRPC_RETURN(GRPC_CONFIGFILE_NOT_FOUND, GRPC_NO_MINOR_ERROR);
00380 
00381   if(gs_parse_config_file(config_file_name, &attr_list) != 0)
00382     GRPC_RETURN(GRPC_CONFIGFILE_ERROR, GRPC_NO_MINOR_ERROR);
00383 
00384   if(attr_list) {
00385     gs_info_t *p;
00386 
00387     for(p = attr_list; p != NULL; p = p->next) {
00388       if(!strcasecmp(p->type, "MEASURE_COMM"))
00389         grpc_measure_comm = strcasecmp(p->value, "y") == 0;
00390       else if(!strcasecmp(p->type, "MEASURE_COMM_NUM_SERVERS"))
00391         grpc_measure_comm_num_servers = atoi(p->value);
00392       else if(!strcasecmp(p->type, "MEASURE_COMM_CACHE_TTL"))
00393         grpc_measure_comm_cache_ttl = atoi(p->value);
00394       else if(!strcasecmp(p->type, "MEASURE_COMM_TIME_THRESH"))
00395         grpc_measure_comm_time_thresh = atof(p->value);
00396     }
00397   }
00398 
00399   gs_free_infolist(attr_list);
00400 
00401   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00402 }
00403 
00420 grpc_error_t
00421 grpc_initialize(char *config_file_name)
00422 {
00423   PROXY_COMPONENTADDR proxy_info;
00424   char *username=NULL, *tmp_host;
00425   int i;
00426 
00427 #ifdef GS_SMART_GRIDSOLVE
00428   /*
00429    * Reads and increments the application file number.
00430    * This number is used to give each remote argument a
00431    * unique file name.
00432    */ 
00433   if(gs_smart_read_update_app_no_file("/tmp/gs_app_num", &smart_app_num)<0)
00434     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
00435 
00436 #endif
00437 
00438 
00439 
00440   /*
00441    * Repeated initializations return GRPC_ALREADY_INITIALIZED 
00442    */
00443   if(grpc_initialized == TRUE)
00444     GRPC_RETURN(GRPC_ALREADY_INITIALIZED, GRPC_NO_MINOR_ERROR);
00445 
00446   if(config_file_name)
00447     if(grpc_process_config_file(config_file_name) != GRPC_NO_ERROR)
00448       GRPC_RETURN(grpc_errno, GRPC_NO_MINOR_ERROR);
00449 
00450   GRPC_CLEAR_ERRORS();
00451 
00452   grpc_errno = GRPC_NO_ERROR;
00453   grpc_minor_errno = GRPC_NO_MINOR_ERROR;
00454 
00455   for(i = 0; i < MAX_GRPC_REQUESTS; i++) {
00456     grpc_outstanding_requests[i] = NULL;
00457     grpc_profile_info[i] = NULL;
00458     grpc_errors[i] = GRPC_NO_ERROR;
00459     grpc_minor_errors[i] = GRPC_NO_MINOR_ERROR;
00460   }
00461 
00462   /* Startup winsock in win32 */
00463   initialize_sockets();
00464 
00465   /*
00466    * Initialize the proxy library 
00467    */
00468   proxy_init("");
00469 
00470   if((username = gs_get_login_name())) {
00471     strncpy(grpc_user, username, GRPC_USER_INFO_LEN);
00472     grpc_user[GRPC_USER_INFO_LEN-1] = '\0';
00473     free(username);
00474   }
00475   else {
00476     strncpy(grpc_user, "unknown_user", GRPC_USER_INFO_LEN);
00477     grpc_user[GRPC_USER_INFO_LEN-1] = '\0';
00478   }
00479 
00480   tmp_host = gs_get_machine_name();
00481   if(!tmp_host) {
00482     strncpy(grpc_host, "unknown_host", GRPC_USER_INFO_LEN);
00483     grpc_host[GRPC_USER_INFO_LEN-1] = '\0';
00484     strncpy(grpc_domain, "unknown_domain", GRPC_USER_INFO_LEN);
00485     grpc_domain[GRPC_USER_INFO_LEN-1] = '\0';
00486   }
00487   else {
00488     char *p;
00489 
00490     strncpy(grpc_host, tmp_host, GRPC_USER_INFO_LEN);
00491     grpc_host[GRPC_USER_INFO_LEN-1] = '\0';
00492         
00493     if((p = strstr(grpc_host, "."))) {
00494       *p = '\0';
00495       strncpy(grpc_domain, p+1, GRPC_USER_INFO_LEN);
00496     }
00497     else
00498       strncpy(grpc_domain, "unknown_domain", GRPC_USER_INFO_LEN);
00499 
00500     grpc_domain[GRPC_USER_INFO_LEN-1] = '\0';
00501 
00502     free(tmp_host);
00503   }
00504 
00505   proxy_info = proxy_get_local_addr();
00506 
00507   proxy_cid_to_str(grpc_cid_str, proxy_info.ID);
00508 
00509   grpc_comm_cache = icl_hash_create(37, NULL);
00510 
00511   grpc_initialized = TRUE;
00512 
00513   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00514 }
00515 
00525 grpc_error_t
00526 grpc_finalize()
00527 {
00528   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
00529 
00530   cleanup_sockets();
00531 
00532   grpc_initialized = FALSE;
00533 
00534   if(grpc_comm_cache)
00535     icl_hash_destroy(grpc_comm_cache, free, free);
00536 
00537   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00538 }
00539 
00554 grpc_error_t
00555 grpc_set_criteria(grpc_function_handle_t *handle, char *c)
00556 {
00557   if(!handle)
00558     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
00559 
00560   if(c) {
00561     handle->criteria = strdup(c);
00562     if(!handle->criteria) {
00563       ERRPRINTF("Can't allocate memory, strdup failed\n");
00564       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
00565     }
00566   }
00567   else {
00568     /*
00569      * Client has set criteria to NULL.  If there was already some criteria
00570      * set, then free it first. 
00571      */
00572     if(handle->criteria)
00573       free(handle->criteria);
00574 
00575     handle->criteria = NULL;
00576   }
00577 
00578   /*
00579    * since the criteria have changed, request that the next call using this
00580    * handle gets a new binding (i.e. server list). 
00581    */
00582   handle->bind_servers_at_call_time = 1;
00583 
00584   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00585 }
00586 
00596 static void
00597 grpc_function_handle_clear(grpc_function_handle_t *handle)
00598 {
00599   if(!handle)
00600     return;
00601 
00602   handle->func_name = NULL;
00603   handle->num_servers = 0;
00604   handle->srv_idx = 0;
00605   handle->server_list = NULL;
00606   handle->problem_desc = NULL;
00607   handle->criteria = NULL;
00608   handle->bind_servers_at_call_time = 0;
00609   handle->agent_taskid = -1;
00610   handle->num_calls = 0;
00611 }
00612 
00633 grpc_error_t
00634 grpc_function_handle_default(grpc_function_handle_t *handle, char *func_name)
00635 {
00636   grpc_function_handle_clear(handle);
00637   if(handle)
00638     handle->bind_servers_at_call_time = 0;
00639   return grpc_function_handle_common(handle, NULL, func_name);
00640 }
00641 
00664 grpc_error_t
00665 grpc_function_handle_default_ns(grpc_function_handle_t *handle,
00666                                 char *func_name)
00667 {
00668   grpc_function_handle_clear(handle);
00669   /*
00670    * Use any non-blank hostname and set handle->bind_servers_at_call_time to
00671    * 1 
00672    */
00673   if(handle)
00674     handle->bind_servers_at_call_time = 1;
00675   return grpc_function_handle_common(handle, "bind_servers_at_call_time",
00676                                      func_name);
00677 }
00678 
00700 grpc_error_t
00701 grpc_function_handle_init(grpc_function_handle_t *handle, char *host_name,
00702                           char *func_name)
00703 {
00704 
00705 #ifdef GS_SMART_GRIDSOLVE
00706 
00707   /*
00708    * if the task graph is being built then we do not want to bind the servers at call time
00709    */
00710   if(smart_phase==GS_SMART_TASK_DISCOVERY){
00711     return grpc_function_handle_default(handle, func_name);
00712   }
00713 
00714    
00715   /*
00716    * if we are in executing mode then we don't need to set up handles, just return with no errors
00717    */
00718   if(smart_phase==GS_SMART_EXEC_CALLED_HANDLES) {
00719     return grpc_function_handle_default(handle, func_name);
00720       GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00721   }
00722 
00723   /*
00724    * else if we are not building or executing (i.e. we are executing in the standard gridsolve approach)
00725    * then just set up the handle_init as normal
00726    */
00727   else if(smart_phase==GS_SMART_STANDARD_EXEC)
00728   {   
00729     grpc_function_handle_clear(handle);
00730     if((handle) && strcmp(host_name, "bind_servers_at_call_time") == 0)
00731       handle->bind_servers_at_call_time = 1;
00732     else if(handle)
00733       handle->bind_servers_at_call_time = 0;
00734     return grpc_function_handle_common(handle, host_name, func_name);
00735   }
00736   
00737   /*
00738    * if none of the above set up handle_init as normal
00739    * 
00740    */
00741   else
00742   {   
00743     grpc_function_handle_clear(handle);
00744     if((handle) && strcmp(host_name, "bind_servers_at_call_time") == 0)
00745       handle->bind_servers_at_call_time = 1;
00746     else if(handle)
00747       handle->bind_servers_at_call_time = 0;
00748     return grpc_function_handle_common(handle, host_name, func_name);
00749   }
00750 
00751 
00752 
00753 #else
00754 
00755 
00756   grpc_function_handle_clear(handle);
00757   if((handle) && strcmp(host_name, "bind_servers_at_call_time") == 0)
00758     handle->bind_servers_at_call_time = 1;
00759   else if(handle)
00760     handle->bind_servers_at_call_time = 0;
00761   return grpc_function_handle_common(handle, host_name, func_name);
00762 #endif
00763 }
00764 
00786 static grpc_error_t
00787 grpc_function_handle_common(grpc_function_handle_t *handle, char *host_name,
00788                             char *func_name)
00789 {
00790   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
00791 
00792   if(!handle)
00793     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
00794 
00795   if(!func_name)
00796     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
00797 
00798   if(host_name) {
00799     int i, parse_host = 0;
00800     gs_server_t *srv;
00801 
00802     handle->srv_idx = 0;
00803     handle->num_servers = 1;
00804     handle->server_list = (gs_server_t **) malloc(sizeof(gs_server_t *));
00805 
00806     if(!handle->server_list)
00807       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
00808 
00809     handle->server_list[handle->srv_idx] =
00810         (gs_server_t *) CALLOC(1, sizeof(gs_server_t));
00811 
00812     if(!handle->server_list[handle->srv_idx])
00813       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
00814 
00815     for(i = 0; i < (int)strlen(host_name); i++) {
00816       if(host_name[i] == GS_PORT_DELIM || host_name[i] == GS_PROXY_DELIM) {
00817         parse_host = 1;
00818         break;
00819       }
00820     }
00821 
00822     srv = handle->server_list[handle->srv_idx];
00823     srv->arch = strdup("unknown");
00824     srv->problemlist = NULL;
00825     srv->agenthost = NULL;
00826     srv->sa_list = NULL;
00827 
00828     if(parse_host) {
00829       if(gs_parse_host_info(host_name, &srv->ipaddress, &srv->port,
00830                             &srv->proxyip, &srv->proxyport,
00831                             srv->componentid) < 0) {
00832         ERRPRINTF("Error parsing info\n");
00833         GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_PARSE_HOST_INFO);
00834       }
00835       srv->hostname = strdup("unspecified");
00836     }
00837     else {
00838       srv->hostname = strdup(host_name);
00839       srv->port =
00840           getenv_int("GRIDSOLVE_SERVER_PORT",
00841                      GRIDSOLVE_SERVER_PORT_DEFAULT);
00842 
00843       if(!handle->bind_servers_at_call_time) {
00844         struct hostent *hp;
00845 
00846         if((hp = gethostbyname(host_name)) == NULL) {
00847           ERRPRINTF("Can't resolve host name '%s'\n", host_name);
00848           GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_RESOLV_FAILED);
00849         }
00850 
00851         memcpy((void *) &(srv->ipaddress), hp->h_addr_list[0], 
00852           sizeof(srv->ipaddress));
00853 
00854         /* since there was only hostname specified, componentID is
00855          * unavailable.  So initialize it with the 'wildcard' value.
00856          */
00857 
00858         memset(srv->componentid, 0xFF, CID_LEN);
00859       }
00860     }
00861 
00862     handle->func_name = strdup(func_name);
00863     handle->problem_desc = NULL;
00864   }
00865   else {
00866     /*
00867      * Use NULLS as the arg and argptr and -1 as the dsig to indicate that
00868      * the input args are NOT to be transferred at this time. They are not
00869      * known/bound yet in the standard GridRPC protocol, so they could not be 
00870      * transferred yet. 
00871      */
00872     if(gs_get_server_mapping(func_name, handle, NULL, NULL, -1,
00873           grpc_client_lang, grpc_client_major) < 0) {
00874       if(grpc_errno == GRPC_SERVER_NOT_FOUND ||
00875          grpc_errno == GRPC_NOT_INITIALIZED ||
00876          grpc_errno == GRPC_FUNCTION_NOT_FOUND)
00877         GRPC_RETURN(grpc_errno, grpc_minor_errno);
00878  
00879       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, grpc_minor_errno);
00880     }
00881 
00882     GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00883   }
00884 
00885   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00886 }
00887 
00904 grpc_error_t
00905 grpc_function_handle_destruct(grpc_function_handle_t *handle)
00906 {
00907   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
00908 
00909   if(!handle)
00910     GRPC_RETURN(GRPC_INVALID_FUNCTION_HANDLE, GRPC_NULL_FUNCTION_HANDLE);
00911 
00912   if(handle->func_name)
00913     free(handle->func_name);
00914   gs_free_problem(handle->problem_desc);
00915   gs_free_handle_server_list(handle);
00916 
00917   if(handle->criteria) {
00918     free(handle->criteria);
00919     handle->criteria = NULL;
00920   }
00921 
00922   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00923 }
00924 
00939 grpc_error_t
00940 grpc_get_handle(grpc_function_handle_t **handle, grpc_sessionid_t sessionId)
00941 {
00942   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
00943 
00944   if((sessionId < 0) || (sessionId >= MAX_GRPC_REQUESTS))
00945     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
00946 
00947   if(!grpc_outstanding_requests[sessionId])
00948     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
00949 
00950   *handle = grpc_outstanding_requests[sessionId]->handle;
00951 
00952   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
00953 }
00954 
00965 grpc_request_t *
00966 grpc_get_request(grpc_sessionid_t sessionId)
00967 {
00968   GRPC_FAIL_IF_NOT_INITIALIZED(NULL);
00969 
00970   if((sessionId < 0) || (sessionId >= MAX_GRPC_REQUESTS))
00971     return NULL;
00972 
00973   if(!grpc_outstanding_requests[sessionId])
00974     return NULL;
00975 
00976   return grpc_outstanding_requests[sessionId];
00977 }
00978 
01000 grpc_error_t
01001 grpc_call(grpc_function_handle_t *handle, ...)
01002 {
01003 
01004 #ifdef GS_SMART_GRIDSOLVE
01005 
01006   if(smart_phase==GS_SMART_EXEC_TASK_FAIL){
01007     return GRPC_NO_ERROR;
01008   }
01009 #endif
01010 
01011   gs_va_list argptr;
01012 
01013   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01014 
01015   va_start(argptr.args, handle);
01016 
01017   return gs_call_common(handle, NULL, &argptr, NULL, TRUE);
01018 }
01019 
01043 grpc_error_t
01044 grpc_call_async(grpc_function_handle_t *handle, 
01045   grpc_sessionid_t *sessionId, ...)
01046 {
01047 
01048 #ifdef GS_SMART_GRIDSOLVE
01049   if(smart_phase==GS_SMART_EXEC_TASK_FAIL){
01050     return GRPC_NO_ERROR;
01051   }
01052 
01053 #endif
01054 
01055 
01056   gs_va_list argptr;
01057 
01058   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01059 
01060   va_start(argptr.args, sessionId);
01061 
01062   return gs_call_common(handle, sessionId, &argptr, NULL, FALSE);
01063 }
01064 
01065 
01066 /*************************************************************************/
01067 /*------ new GridRPC API functions for GridSolve request sequencing -----*/
01068 /*************************************************************************/
01069 grpc_error_t
01070 grpc_call_arg_list(grpc_function_handle_t *handle, gs_va_list *list) {
01071         return gs_call_common(handle, NULL, list, NULL, TRUE);
01072 }
01073 
01074 grpc_error_t grpc_call_arg_list_async(grpc_function_handle_t *handle,
01075             grpc_sessionid_t *sessionId, gs_va_list *list) {
01076         return gs_call_common(handle, sessionId, list, NULL, FALSE);
01077 }
01078 /*************************************************************************/
01079 
01080 
01103 grpc_error_t
01104 grpc_call_arg_stack(grpc_function_handle_t *handle, grpc_arg_stack *stack)
01105 {
01106   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01107 
01108   if(!stack || !stack->args)
01109     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_ARGSTACK);
01110   if(!handle)
01111     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
01112   if(!handle->func_name)
01113     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
01114 
01115   return gs_call_common(handle, NULL, NULL, stack->args, TRUE);
01116 }
01117 
01142 grpc_error_t
01143 grpc_call_arg_stack_async(grpc_function_handle_t *handle, 
01144    grpc_sessionid_t *sessionId, grpc_arg_stack *stack)
01145 {
01146   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01147 
01148   if(!stack || !stack->args) 
01149     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_ARGSTACK);
01150   if(!handle)
01151     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
01152   if(!handle->func_name)
01153     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
01154 
01155   return gs_call_common(handle, sessionId, NULL, stack->args, FALSE);
01156 }
01157 
01171 static int
01172 gs_req_child_waitpid(grpc_request_t *req, int options)
01173 {
01174   pid_t pid, tmp_pid;
01175   int stat;
01176 
01177   pid = waitpid(req->s_pid, &stat, options);
01178 
01179   switch (pid) {
01180     case WAIT_ABANDONED:        /* -1 */
01181       /*
01182        * if we reach here, most likely it's because the user has their own
01183        * signal handler catching SIGCHLD signals and they're calling waitpid
01184        * on the process forked by grpc, so it's gone by the time we get here. 
01185        * in any case, just clear the s_pid field so we won't wait on it again
01186        * and return normally. 
01187        */
01188       tmp_pid = req->s_pid;
01189       req->s_pid = -1;
01190       return tmp_pid;
01191 
01192     case WAIT_TIMEOUT:      /* 0 */
01193       /*
01194        * the child process is still sending the data 
01195        */
01196       return 0;
01197 
01198     default:
01199       /*
01200        * the child process has completed 
01201        */
01202       tmp_pid = req->s_pid;
01203       req->s_pid = -1;
01204       return tmp_pid;
01205   }
01206 }
01207 
01223 grpc_error_t
01224 grpc_probe(grpc_sessionid_t sessionID)
01225 {
01226   grpc_function_handle_t *handle;
01227   gs_server_t *srv;
01228   SOCKET sock;
01229   int tag;
01230 
01231   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01232 
01233   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
01234     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01235 
01236   if(!grpc_outstanding_requests[sessionID])
01237     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01238 
01239   if(grpc_outstanding_requests[sessionID]->s_pid > 0) {
01240     if(gs_req_child_waitpid(grpc_outstanding_requests[sessionID], GS_WNOHANG) == 0) {
01241       /*
01242        * the child is still sending data to the parent 
01243        */
01244       GRPC_RETURN(GRPC_NOT_COMPLETED, GRPC_NO_MINOR_ERROR);
01245     }
01246   }
01247 
01248   handle = grpc_outstanding_requests[sessionID]->handle;
01249 
01250   if(!handle)
01251     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
01252 
01253   srv = handle->server_list[handle->srv_idx];
01254 
01255   sock = gs_connect_to_host(srv->componentid, srv->ipaddress, srv->port,
01256                             srv->proxyip, srv->proxyport);
01257 
01258   if(sock == INVALID_SOCKET)
01259     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_SERVER_CONNECTION);
01260 
01261   if((gs_send_tag(sock, GS_PROT_PROBE_REQUEST) < 0) ||
01262      (gs_send_string(sock, VERSION) < 0)) {
01263     proxy_close(sock);
01264     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01265   }
01266 
01267   if(gs_recv_tag(sock, &tag) < 0) {
01268     proxy_close(sock);
01269     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01270   }
01271     
01272   if(tag != GS_PROT_OK) {
01273     if(tag == GS_PROT_VERSION_MISMATCH)
01274       grpc_minor_errno = GRPC_VERSION_MISMATCH;
01275     else
01276       grpc_minor_errno = GRPC_NO_MINOR_ERROR;
01277     
01278     proxy_close(sock);
01279     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, grpc_minor_errno);
01280   } 
01281 
01282   if(gs_send_string(sock, grpc_outstanding_requests[sessionID]->request_id) < 0)
01283     goto probe_failure;
01284 
01285   if(gs_recv_tag(sock, &tag) < 0)
01286     goto probe_failure;
01287 
01288   proxy_close(sock);
01289 
01290   switch (tag) {
01291     case GS_PROT_OK:
01292       GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
01293     case GS_SVC_ERR_NOT_FINISHED:
01294       GRPC_RETURN(GRPC_NOT_COMPLETED, GRPC_NO_MINOR_ERROR);
01295     default:
01296       ERRPRINTF("Probe failed: %s\n", gs_service_error[tag]);
01297       if(gs_notify_agent_of_failure(handle, 
01298            grpc_outstanding_requests[sessionID]->request_id) < 0)
01299         ERRPRINTF("Warning: failed to notify agent of server failure.\n");
01300       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, tag);
01301   }
01302 
01303 probe_failure:
01304   proxy_close(sock);
01305   if(gs_notify_agent_of_failure(handle, 
01306        grpc_outstanding_requests[sessionID]->request_id) < 0)
01307     ERRPRINTF("Warning: failed to notify agent of server failure.\n");
01308   GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01309   
01310   /*
01311    * shouldn't reach here 
01312    */
01313   GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01314 }
01315 
01334 grpc_error_t
01335 grpc_probe_or(grpc_sessionid_t *idArray, size_t length, grpc_sessionid_t *idPtr)
01336 {   
01337   gs_service_error_enum_t retval_minor;
01338   grpc_error_t retval;
01339   int i; 
01340 
01341   *idPtr = GRPC_SESSIONID_VOID;
01342 
01343   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01344   
01345   /*
01346    * first validate the numbers 
01347    */
01348   for(i = 0; i < (int)length; i++)
01349     if((idArray[i] < 0) || (idArray[i] >= MAX_GRPC_REQUESTS))
01350       GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01351 
01352   retval = GRPC_NONE_COMPLETED;
01353   retval_minor = GRPC_NO_MINOR_ERROR;
01354 
01355   for(i = 0; i < (int)length; i++) {
01356     grpc_sessionid_t s = idArray[i];
01357       
01358     if(grpc_outstanding_requests[s] != NULL) {
01359       grpc_error_t r;
01360 
01361       r = grpc_probe(s);
01362 
01363       if(r == GRPC_NO_ERROR) {
01364         *idPtr = s;
01365         GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
01366       }
01367       else if(r != GRPC_NOT_COMPLETED) {
01368         retval = r;
01369         retval_minor = grpc_minor_errno;
01370       }
01371     }
01372   }
01373 
01374   GRPC_RETURN(retval, retval_minor);
01375 }
01376 
01390 grpc_error_t
01391 grpc_cancel(grpc_sessionid_t sessionID)
01392 {
01393   grpc_function_handle_t *handle;
01394   gs_server_t *srv;
01395   SOCKET sock;
01396   int tag;
01397 
01398   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01399 
01400   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
01401     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01402 
01403   if(!grpc_outstanding_requests[sessionID])
01404     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01405 
01406   if(gs_notify_agent_of_cancel(grpc_outstanding_requests[sessionID]->handle, 
01407        grpc_outstanding_requests[sessionID]->request_id) < 0)
01408     ERRPRINTF("Warning: failed to notify agent of job cancellation.\n");
01409 
01410   if(grpc_outstanding_requests[sessionID]->s_pid > 0) {
01411     if(gs_req_child_waitpid(grpc_outstanding_requests[sessionID], GS_WNOHANG) == 0) {
01412       /*
01413        * the child is still sending data to the parent.  kill it. 
01414        */
01415 
01416       kill(grpc_outstanding_requests[sessionID]->s_pid, GS_SIGKILL);
01417     }
01418   }
01419 
01420   handle = grpc_outstanding_requests[sessionID]->handle;
01421 
01422   if(!handle)
01423     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01424 
01425   srv = handle->server_list[handle->srv_idx];
01426 
01427   sock = gs_connect_to_host(srv->componentid, srv->ipaddress, srv->port,
01428                             srv->proxyip, srv->proxyport);
01429 
01430   if(sock == INVALID_SOCKET)
01431     GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_SERVER_CONNECTION);
01432 
01433   if((gs_send_tag(sock, GS_PROT_KILL_JOB) < 0) ||
01434      (gs_send_string(sock, VERSION) < 0)) {
01435     proxy_close(sock);
01436     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01437   }
01438             
01439   if(gs_recv_tag(sock, &tag) < 0) {
01440     proxy_close(sock);
01441     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01442   } 
01443     
01444   if(tag != GS_PROT_OK) {
01445     if(tag == GS_PROT_VERSION_MISMATCH)
01446       grpc_minor_errno = GRPC_VERSION_MISMATCH;
01447     else
01448       grpc_minor_errno = GRPC_NO_MINOR_ERROR;
01449 
01450     proxy_close(sock);
01451     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, grpc_minor_errno);
01452   } 
01453 
01454   if(gs_send_string(sock, grpc_outstanding_requests[sessionID]->request_id) < 0) {
01455     proxy_close(sock);
01456     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01457   }
01458 
01459   if(gs_recv_tag(sock, &tag) < 0) {
01460     proxy_close(sock);
01461     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01462   }
01463 
01464   proxy_close(sock);
01465 
01466   switch (tag) {
01467     case GS_PROT_OK:
01468       grpc_request_destruct(grpc_outstanding_requests[sessionID]);
01469       free(grpc_outstanding_requests[sessionID]);
01470       grpc_outstanding_requests[sessionID] = NULL;
01471       grpc_profile_info[sessionID] = NULL;
01472       GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
01473     default:
01474       ERRPRINTF("cancel failed: %s\n", gs_service_error[tag]);
01475       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, tag);
01476   }
01477 
01478   /*
01479    * shouldn't reach here 
01480    */
01481   GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01482 }
01483 
01493 grpc_error_t
01494 grpc_cancel_all(void)
01495 {
01496   grpc_error_t last_minor_error = GRPC_NO_MINOR_ERROR;
01497   int i, saw_failure = FALSE;
01498 
01499   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01500 
01501   for(i = 0; i < MAX_GRPC_REQUESTS; i++)
01502     if(grpc_outstanding_requests[i] != NULL)
01503       if(grpc_cancel(i) != GRPC_NO_ERROR) {
01504         saw_failure = TRUE;
01505         last_minor_error = grpc_minor_errno;
01506       }
01507 
01508   if(saw_failure)
01509     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, last_minor_error);
01510 
01511   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
01512 }
01513 
01530 grpc_error_t
01531 grpc_wait(grpc_sessionid_t sessionID)
01532 {
01533 #ifdef GS_SMART_GRIDSOLVE
01534   if(smart_phase==GS_SMART_EXEC_TASK_FAIL){
01535     return GRPC_NO_ERROR;
01536   }
01537 
01538 #endif
01539   gs_service_error_enum_t save_minor_errno;
01540   grpc_error_t status;
01541 
01542   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01543 
01544   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
01545     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01546 
01547   if(!grpc_outstanding_requests[sessionID])
01548     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01549 
01550   status = gs_wait_common(grpc_outstanding_requests[sessionID]);
01551   save_minor_errno = grpc_minor_errno;
01552 
01553 #ifdef GS_PROFILING
01554   if(grpc_profile_info[sessionID]) {
01555     GRPC_TIMER_STOP(grpc_profile_info[sessionID]);
01556     grpc_profile_info[sessionID]->recv_output =
01557         GRPC_TIMER_ELAPSED(grpc_profile_info[sessionID]);
01558   }
01559 #endif
01560 
01561   if(status != GRPC_NO_ERROR) {
01562     grpc_last_failed_idx = 0;
01563     grpc_last_failed_sid[grpc_last_failed_idx] = sessionID;
01564   }
01565   else 
01566     grpc_last_failed_idx = -1;
01567 
01568   grpc_request_destruct(grpc_outstanding_requests[sessionID]);
01569   free(grpc_outstanding_requests[sessionID]);
01570   grpc_outstanding_requests[sessionID] = NULL;
01571   grpc_profile_info[sessionID] = NULL;
01572 
01573   GRPC_RETURN(status, save_minor_errno);
01574 }
01575 
01592 grpc_error_t
01593 grpc_wait_and(grpc_sessionid_t *idArray, size_t length)
01594 {
01595   int i, tmp_idx, requests_remaining = TRUE, saw_failure = FALSE;
01596   grpc_sessionid_t tmp_sid[MAX_GRPC_REQUESTS];
01597 
01598   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01599 
01600   tmp_idx = -1;
01601 
01602   /*
01603    * first validate the numbers 
01604    */
01605   for(i = 0; i < (int)length; i++)
01606     if((idArray[i] < 0) || (idArray[i] >= MAX_GRPC_REQUESTS))
01607       GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01608 
01609   while(requests_remaining) {
01610     requests_remaining = FALSE;
01611 
01612     for(i = 0; i < (int)length; i++) {
01613       grpc_sessionid_t s = idArray[i];
01614 
01615       if(grpc_outstanding_requests[s] != NULL) {
01616         requests_remaining = TRUE;
01617 
01618         /* if the job is no longer running (i.e. it either successfully
01619          * completed or it failed) call wait and check the error status.
01620          */
01621 
01622         if(grpc_probe(s) != GRPC_NOT_COMPLETED) {
01623           if(grpc_wait(s) != GRPC_NO_ERROR) {
01624             saw_failure = TRUE;
01625             grpc_errors[s] = grpc_errno;
01626             grpc_minor_errors[s] = grpc_minor_errno;
01627             tmp_idx++;
01628             tmp_sid[tmp_idx] = s;
01629           }
01630         }
01631       }
01632     }
01633 
01634     sleep(1);
01635   }
01636 
01637   /* copy failed session IDs to the global array */
01638   grpc_last_failed_idx = tmp_idx;
01639   memcpy(grpc_last_failed_sid, tmp_sid, (tmp_idx+1) * sizeof(*tmp_sid));
01640 
01641   GRPC_RETURN(saw_failure ? GRPC_SESSION_FAILED : GRPC_NO_ERROR,
01642      GRPC_NO_MINOR_ERROR);
01643 }
01644 
01663 grpc_error_t
01664 grpc_wait_or(grpc_sessionid_t *idArray, size_t length, grpc_sessionid_t *idPtr)
01665 {
01666   int i, jobCount = 0;
01667 
01668   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01669 
01670   /*
01671    * first validate the numbers 
01672    */
01673   for(i = 0; i < (int)length; i++)
01674     if((idArray[i] < 0) || (idArray[i] >= MAX_GRPC_REQUESTS))
01675       GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01676 
01677   for(;;) {
01678 
01679     for(i = 0; i < (int)length; i++) {
01680       grpc_sessionid_t s = idArray[i];
01681 
01682       if(grpc_outstanding_requests[s] != NULL) {
01683         /* if the job is no longer running (i.e. it either successfully
01684          * completed or it failed) call wait and check the error status.
01685          */
01686 
01687         if(grpc_probe(s) != GRPC_NOT_COMPLETED) {
01688           grpc_error_t r;
01689 
01690           *idPtr = s;
01691 
01692           r = grpc_wait(s);
01693 
01694           if(r != GRPC_NO_ERROR) {
01695             grpc_errors[s] = grpc_errno;
01696             grpc_minor_errors[s] = grpc_minor_errno;
01697           }
01698 
01699           GRPC_RETURN(r, grpc_minor_errno);
01700         }
01701 
01702         jobCount++;
01703       }
01704     }
01705 
01706     if(jobCount == 0) {
01707       *idPtr = -1;
01708       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01709     }
01710 
01711     sleep(1);
01712   }
01713 
01714   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
01715 }
01716 
01729 grpc_error_t
01730 grpc_wait_all(void)
01731 {
01732   grpc_sessionid_t tmp_sid[MAX_GRPC_REQUESTS];
01733   int tmp_idx, saw_failure = FALSE;
01734   grpc_sessionid_t sid = 0;
01735   grpc_error_t r;
01736 
01737   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01738 
01739   tmp_idx = -1;
01740 
01741   for(;;) {
01742     r = grpc_wait_any(&sid);
01743 
01744     if(r != GRPC_NO_ERROR) {
01745 
01746       if(sid >= 0) {
01747         tmp_idx++;
01748         tmp_sid[tmp_idx] = sid;
01749       }
01750 
01751       /* if there are no more jobs to wait for */
01752       if(r == GRPC_OTHER_ERROR_CODE) {
01753 
01754         /* copy failed session IDs to the global array */
01755         grpc_last_failed_idx = tmp_idx;
01756         memcpy(grpc_last_failed_sid, tmp_sid, (tmp_idx+1) * sizeof(*tmp_sid));
01757 
01758         GRPC_RETURN(saw_failure ? GRPC_SESSION_FAILED : GRPC_NO_ERROR,
01759           grpc_minor_errno);
01760       }
01761 
01762       saw_failure = TRUE;
01763     }
01764   }
01765 
01766   /* should not reach here */
01767   GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01768 }
01769 
01785 grpc_error_t
01786 grpc_wait_any(grpc_sessionid_t *idPtr)
01787 {
01788   int i, jobCount = 0;
01789 
01790   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01791 
01792   for(;;) {
01793     for(i = 0; i < MAX_GRPC_REQUESTS; i++)
01794       if(grpc_outstanding_requests[i] != NULL) {
01795         /* if the job is no longer running (i.e. it either successfully
01796          * completed or it failed) call wait and check the error status.
01797          */
01798 
01799         if(grpc_probe(i) != GRPC_NOT_COMPLETED) {
01800           grpc_error_t r = grpc_wait(i);
01801 
01802           *idPtr = i;
01803 
01804           if(r != GRPC_NO_ERROR) {
01805             grpc_errors[i] = grpc_errno;
01806             grpc_minor_errors[i] = grpc_minor_errno;
01807           }
01808 
01809           GRPC_RETURN(r, grpc_minor_errno);
01810         }
01811 
01812         jobCount++;
01813       }
01814 
01815     if(jobCount == 0) {
01816       *idPtr = -1;
01817       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
01818     }
01819 
01820     sleep(1);
01821   }
01822 
01823   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
01824 }
01825 
01832 void
01833 grpc_perror(char *str)
01834 {
01835   /* check if this is a server-specific error code */
01836   if((grpc_minor_errno > GS_SVC_NO_ERROR) && 
01837      (grpc_minor_errno < GRPC_NO_MINOR_ERROR))
01838     fprintf(stderr, "%s: %s -- %s\n", str, grpc_error_string(grpc_errno),
01839        gs_service_error[grpc_minor_errno]);
01840   else if((grpc_minor_errno > GRPC_NO_MINOR_ERROR) &&
01841           (grpc_minor_errno < GRPC_LAST_MINOR_ERROR_CODE))
01842     fprintf(stderr, "%s: %s -- %s\n", str, grpc_error_string(grpc_errno),
01843        GRPC_MINOR_ERROR_MESSAGES[grpc_minor_errno-GRPC_NO_MINOR_ERROR]);
01844   else
01845     fprintf(stderr, "%s: %s\n", str, grpc_error_string(grpc_errno));
01846 }
01847 
01855 char *
01856 grpc_minor_error_string(grpc_error_t minor_errno)
01857 {
01858   if((minor_errno > GRPC_NO_MINOR_ERROR) &&
01859      (minor_errno < GRPC_LAST_MINOR_ERROR_CODE))
01860     return GRPC_MINOR_ERROR_MESSAGES[minor_errno-GRPC_NO_MINOR_ERROR];
01861   else
01862     return "";
01863 }
01864 
01865 
01875 char *
01876 grpc_error_string(grpc_error_t error_code)
01877 {
01878   if((error_code < 0) || (error_code >= GRPC_LAST_ERROR_CODE))
01879     return "Invalid Error Code";
01880 
01881   return GRPC_ERROR_MESSAGES[error_code];
01882 }
01883 
01893 grpc_error_t
01894 grpc_get_error(grpc_sessionid_t sessionID)
01895 {
01896   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01897 
01898   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
01899     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01900 
01901   if(!grpc_outstanding_requests[sessionID])
01902     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
01903 
01904   return grpc_errors[sessionID];
01905 }
01906 
01913 grpc_error_t
01914 grpc_get_failed_sessionid(grpc_sessionid_t *idPtr)
01915 {
01916   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
01917 
01918   if(grpc_last_failed_idx < 0) {
01919     *idPtr = GRPC_SESSIONID_VOID;
01920     return GRPC_NO_ERROR;
01921   }
01922 
01923   *idPtr = grpc_last_failed_sid[grpc_last_failed_idx];
01924 
01925   grpc_last_failed_idx--;
01926 
01927   return GRPC_NO_ERROR;
01928 }
01929 
01940 grpc_arg_stack *
01941 grpc_arg_stack_new(int max)
01942 {
01943   grpc_arg_stack *tmp;
01944 
01945   tmp = (grpc_arg_stack *) malloc(sizeof(grpc_arg_stack));
01946 
01947   if(!tmp)
01948     return NULL;
01949 
01950   tmp->max_size = max;
01951   tmp->top = -1;
01952   tmp->args = (void **) calloc(max, sizeof(void *));
01953 
01954   if(!tmp->args) {
01955     free(tmp);
01956     return NULL;
01957   }
01958 
01959   return tmp;
01960 }
01961 
01971 int
01972 grpc_arg_stack_push_arg(grpc_arg_stack *stack, void *arg)
01973 {
01974   if(!stack)
01975     return -1;
01976 
01977   if(stack->top == (stack->max_size - 1))
01978     return -1;
01979 
01980   stack->args[++stack->top] = arg;
01981 
01982   return 0;
01983 }
01984 
01993 void *
01994 grpc_arg_stack_pop_arg(grpc_arg_stack *stack)
01995 {
01996   if(!stack)
01997     return NULL;
01998 
01999   if(stack->top == -1)
02000     return NULL;
02001 
02002   return stack->args[stack->top--];
02003 }
02004 
02013 int
02014 grpc_arg_stack_destruct(grpc_arg_stack *stack)
02015 {
02016   if(!stack)
02017     return -1;
02018 
02019   if(stack->args)
02020     free(stack->args);
02021 
02022   free(stack);
02023 
02024   return 0;
02025 }
02026 
02045 grpc_error_t
02046 grpc_serialize_request(grpc_sessionid_t sessionID, char **str)
02047 {
02048   char *server_str, *problem_str;
02049   grpc_function_handle_t *handle;
02050   grpc_request_t *req;
02051 
02052   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
02053 
02054   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
02055     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
02056 
02057   req = grpc_outstanding_requests[sessionID];
02058 
02059   if(!req)
02060     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02061 
02062   handle = req->handle;
02063 
02064   if(!handle)
02065     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02066 
02067   if(gs_encode_server(&server_str, handle->server_list[handle->srv_idx]) < 0)
02068     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_SERVER_ENCODE);
02069 
02070   if(!server_str)
02071     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02072 
02073   if(gs_encode_problem(&problem_str, handle->problem_desc) < 0)
02074     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_PROBLEM_ENCODE);
02075 
02076   if(!problem_str) {
02077     free(server_str);
02078     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02079   }
02080 
02081   *str =
02082       dstring_sprintf
02083       ("<request id=\"%s\">\n  <handle func_name=\"%s\">\n%s\n%s\n  </handle>\n</request>\n",
02084        req->request_id, handle->func_name, server_str, problem_str);
02085 
02086   free(server_str);
02087   free(problem_str);
02088 
02089   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
02090 }
02091 
02108 grpc_error_t
02109 grpc_deserialize_request(char *str, grpc_request_t *req)
02110 {
02111   char *p, *endp, *tmp_str;
02112   int i, len;
02113 
02114   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
02115 
02116   tmp_str = strdup(str);
02117   if(!tmp_str)
02118     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02119 
02120   p = tmp_str;
02121   len = strlen(tmp_str);
02122 
02123   for(i = 0; (tmp_str[i] != '\n') && (i < len); i++)
02124     /*
02125      * spin 
02126      */ ;
02127 
02128   if(i == len) {
02129     free(tmp_str);
02130     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_INVALID_SERIALIZED_REQ);
02131   }
02132 
02133   tmp_str[i] = '\0';
02134 
02135   req->request_id = CALLOC(strlen(p), sizeof(char));
02136   if(!req->request_id) {
02137     free(tmp_str);
02138     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02139   }
02140 
02141   sscanf(p, "<request id=\"%[^\"]\">", req->request_id);
02142 
02143   req->handle = (grpc_function_handle_t *) CALLOC(1, 
02144      sizeof(grpc_function_handle_t));
02145   if(!req->handle) {
02146     free(tmp_str);
02147     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02148   }
02149 
02150   p = tmp_str + i + 1;
02151   p = strstr(p, "<handle");
02152 
02153   for(; (tmp_str[i] != '\n') && (i < len); i++)
02154     /*
02155      * spin 
02156      */ ;
02157 
02158   if(i == len) {
02159     free(tmp_str);
02160     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_INVALID_SERIALIZED_REQ);
02161   }
02162 
02163   tmp_str[i] = '\0';
02164 
02165   req->handle->func_name = CALLOC(strlen(p), sizeof(char));
02166   if(!req->handle->func_name) {
02167     free(tmp_str);
02168     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02169   }
02170 
02171   sscanf(p, "<handle func_name=\"%[^\"]\">", req->handle->func_name);
02172 
02173   p = tmp_str + i + 1;
02174 
02175   endp = strstr(p, "<problem name");
02176   if(!endp) {
02177     free(tmp_str);
02178     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_INVALID_SERIALIZED_REQ);
02179   }
02180 
02181   *(endp - 1) = '\0';
02182 
02183   req->handle->srv_idx = 0;
02184   req->handle->num_servers = 1;
02185   req->handle->server_list =
02186       (gs_server_t **) CALLOC(1, sizeof(gs_server_t *));
02187   if(!req->handle->server_list) {
02188     free(tmp_str);
02189     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02190   }
02191 
02192   req->handle->server_list[req->handle->srv_idx] =
02193       (gs_server_t *) CALLOC(1, sizeof(gs_server_t));
02194   if(!req->handle->server_list[req->handle->srv_idx]) {
02195     free(tmp_str);
02196     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02197   }
02198   req->s_pid = -1;
02199 
02200   if(gs_decode_server(p, req->handle->server_list[req->handle->srv_idx]) < 0) {
02201     free(tmp_str);
02202     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_SERVER_DECODE);
02203   }
02204 
02205   p = endp;
02206 
02207   endp = strstr(p, "</problem>");
02208   if(!endp) {
02209     free(tmp_str);
02210     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_INVALID_SERIALIZED_REQ);
02211   }
02212 
02213   endp += strlen("</problem>");
02214   *endp = '\0';
02215 
02216   req->problem = (gs_problem_t *) CALLOC(1, sizeof(gs_problem_t));
02217   if(!req->problem) {
02218     free(tmp_str);
02219     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02220   }
02221 
02222   if(gs_decode_problem(p, req->problem) < 0) {
02223     free(tmp_str);
02224     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_PROBLEM_DECODE);
02225   }
02226 
02227   free(tmp_str);
02228 
02229   req->handle->problem_desc = (gs_problem_t *) malloc(sizeof(gs_problem_t));
02230 
02231   if(!req->handle->problem_desc)
02232     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02233 
02234   if(gs_dup_problem(req->handle->problem_desc, req->problem) < 0)
02235     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_DUP_PROBLEM_FAILED);
02236 
02237   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
02238 }
02239 
02258 grpc_error_t
02259 grpc_retrieve(char *request_str, ...)
02260 {
02261   gs_service_error_enum_t save_minor_errno;
02262   grpc_request_t *req;
02263   gs_va_list argptr;
02264   grpc_error_t status;
02265 
02266   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
02267 
02268   va_start(argptr.args, request_str);
02269 
02270   req = (grpc_request_t *) malloc(sizeof(grpc_request_t));
02271 
02272   if(!req)
02273     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
02274 
02275   if(grpc_deserialize_request(request_str, req) != GRPC_NO_ERROR)
02276     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, grpc_minor_errno);
02277 
02278   if(gs_sender_compute_arg_sizes(&argptr, NULL, req->problem,
02279        grpc_client_lang, grpc_client_major) < 0)
02280     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
02281 
02282   status = gs_wait_common(req);
02283   save_minor_errno = grpc_minor_errno;
02284 
02285   grpc_function_handle_destruct(req->handle);
02286   free(req->handle);
02287   grpc_request_destruct(req);
02288   free(req);
02289 
02290   GRPC_RETURN(status, save_minor_errno);
02291 }
02292 
02302 int
02303 gs_measure_network_perf(grpc_function_handle_t *handle)
02304 {
02305   int i, len, ns, nping;
02306   char *msg;
02307   grpc_profile_t profile_tmp;
02308 
02309   memset(&profile_tmp, 0, sizeof(grpc_profile_t));
02310 
02311 #ifdef GS_PROFILING
02312   GRPC_TIMER_START(&profile_tmp);
02313 #endif
02314 
02315   ns = MIN(handle->num_servers, grpc_measure_comm_num_servers);
02316   len = 32 * 1024;
02317 
02318   msg = (char *)malloc(len);
02319 
02320   if(!msg)
02321     return -1;
02322 
02323   nping = 0;
02324 
02325   for(i=0;i<handle->num_servers;i++) {
02326     char srv_cid[2*CID_LEN+1];
02327     grpc_cache_entry_t *ent;
02328     double elapsed_time;
02329 
02330     proxy_cid_to_str(srv_cid, handle->server_list[i]->componentid);
02331 
02332     if(grpc_comm_cache) {
02333       ent = (grpc_cache_entry_t *) icl_hash_find(grpc_comm_cache, srv_cid);
02334 
02335       /* check if this entry is out of date */
02336       if(ent) {
02337         struct timeval ctv;
02338 
02339         gettimeofday(&ctv, NULL);
02340 
02341         if(ctv.tv_sec - ent->tv.tv_sec > grpc_measure_comm_cache_ttl)
02342           ent = NULL;
02343       }
02344     }
02345     else
02346       ent = NULL;
02347 
02348     if(ent) {
02349       handle->server_list[i]->comm_bw = ent->comm_bw; 
02350     }
02351     else {
02352       if(gs_do_ping(handle->server_list[i], msg, len, &elapsed_time) < 0) {
02353         handle->server_list[i]->comm_bw = 0.0;
02354       }
02355       else {
02356         handle->server_list[i]->comm_bw = len / elapsed_time;
02357 
02358         if(grpc_comm_cache) {
02359           ent = (grpc_cache_entry_t *)malloc(sizeof(grpc_cache_entry_t));
02360 
02361           if(ent) {
02362             char *cid_dup;
02363 
02364             cid_dup = strdup(srv_cid);
02365 
02366             if(!cid_dup) {
02367               free(ent);
02368             }
02369             else {
02370               void *old_ent;
02371 
02372               gettimeofday(&(ent->tv), NULL);
02373               ent->comm_bw = handle->server_list[i]->comm_bw;
02374 
02375               icl_hash_update_insert(grpc_comm_cache, cid_dup, ent, &old_ent);
02376             }
02377           }
02378         }
02379       }
02380 
02381       nping++;
02382     }
02383   
02384     if(nping == ns)
02385       break;
02386   }
02387 
02388   free(msg);
02389 
02390 #ifdef GS_PROFILING
02391   GRPC_TIMER_STOP(&profile_tmp);
02392   if(grpc_profile_next)
02393     grpc_profile_next->measure_comm = GRPC_TIMER_ELAPSED(&profile_tmp);
02394 #endif
02395 
02396   return 0;
02397 }
02398 
02411 static int
02412 gs_server_compare_total_time(const void *p1, const void *p2)
02413 {
02414   gs_server_t *s1, *s2;
02415   double s1_time, s2_time;
02416 
02417   if(!p1 || !p2) return 0;
02418 
02419   s1 = *((gs_server_t **) p1);
02420   s2 = *((gs_server_t **) p2);
02421 
02422   s1_time = s1->score + s1->comm_time;
02423   s2_time = s2->score + s2->comm_time;
02424 
02425   /* if the measurements are pretty close, then we just
02426    * consider them equal.
02427    */
02428   if(abs(s1_time - s2_time) < grpc_measure_comm_time_thresh)
02429     return 0;
02430 
02431   if(s1_time > s2_time)
02432     return 1;
02433   if(s1_time < s2_time)
02434     return -1;
02435 
02436   return 0;
02437 }
02438 
02451 int
02452 gs_sort_servers_on_comp_plus_comm(grpc_function_handle_t *handle, int data_size)
02453 {
02454   gs_server_t *srv;
02455   double avg_bw, sum;
02456   int i, nnzs;
02457 
02458   sum = avg_bw = 0.0;
02459   nnzs = 0;
02460 
02461   for(i=0;i<handle->num_servers;i++) {
02462     srv = handle->server_list[i];
02463 
02464     if(srv->comm_bw != 0.0) {
02465       sum += srv->comm_bw;
02466       nnzs++;
02467     }
02468   }
02469 
02470   if(nnzs > 0)
02471     avg_bw = sum / (double) nnzs;
02472  
02473   if(avg_bw == 0.0)
02474     avg_bw = 20000.0;
02475     
02476   for(i=0;i<handle->num_servers;i++) {
02477     srv = handle->server_list[i];
02478 
02479     if(srv->comm_bw == 0.0)
02480       srv->comm_time = data_size / avg_bw;
02481     else
02482       srv->comm_time = data_size / srv->comm_bw;
02483   }
02484 
02485   /* Sort the servers */
02486   qsort(handle->server_list, handle->num_servers, sizeof(gs_server_t *),
02487      gs_server_compare_total_time);
02488 
02489   return 0;
02490 }
02491 
02501 int
02502 gs_get_total_arg_size(grpc_function_handle_t *handle)
02503 {
02504   int my_dsig, total_bytes;
02505   gs_argument_t *argptr;
02506 
02507   my_dsig = pvmgetdsig();
02508   total_bytes = 0;
02509     
02510   for(argptr=handle->problem_desc->arglist;argptr;argptr=argptr->next) {
02511     int elsize = 0;
02512 
02513     /* For input/output args, double the elsize since it will be
02514      * a round trip.  Workspace args are not transferred, so use zero
02515      * for them.  For variable length output, we have no idea what the
02516      * size will be, so just choose some small value.
02517      */
02518 
02519     switch(argptr->inout) {
02520       case GS_INOUT:
02521         elsize = 2 * argptr->rows * argptr->cols * 
02522                  gs_get_element_size(argptr->datatype, my_dsig);
02523         break;
02524       case GS_WORKSPACE:
02525         elsize = 0;
02526         break;
02527       case GS_VAROUT:
02528         elsize = 8;
02529         break;
02530       default:
02531         elsize = argptr->rows * argptr->cols * 
02532                  gs_get_element_size(argptr->datatype, my_dsig);
02533     }
02534 
02535     total_bytes += elsize;
02536   }
02537 
02538   return total_bytes;
02539 }
02540 
02567 static int
02568 gs_get_server_mapping(char *func_name, grpc_function_handle_t *handle,
02569    gs_va_list *args, void **argstack, int my_dsig,
02570    int lang, int major)
02571 {
02572   char *msg = NULL;
02573   int tag, i, argsize;
02574   SOCKET sock;
02575   int scalar_args_to_be_transferred = 0;
02576   int problem_desc_to_be_transferred = 0;
02577   handle->agent_taskid = -1;
02578 
02579   grpc_minor_errno = GRPC_NO_MINOR_ERROR;
02580 
02581   if(!func_name) {
02582     grpc_errno = GRPC_OTHER_ERROR_CODE;
02583     grpc_minor_errno = GRPC_NULL_FUNCTION_NAME;
02584     return -1;
02585   }
02586 
02587   if((sock = gs_connect_to_agent()) == INVALID_SOCKET) {
02588     grpc_errno = GRPC_RPC_REFUSED;
02589     grpc_minor_errno = GRPC_AGENT_NOT_SET;
02590     return -1;
02591   }
02592 
02593   if((gs_send_tag(sock, GS_PROT_PROBLEM_SUBMIT) < 0) ||
02594      (gs_send_string(sock, VERSION) < 0))
02595     goto error_communication_failed;
02596 
02597   if(gs_recv_tag(sock, &tag) < 0)
02598     goto error_communication_failed;
02599   
02600   if(tag != GS_PROT_OK) {
02601     if(tag == GS_PROT_VERSION_MISMATCH)
02602       grpc_minor_errno = GRPC_VERSION_MISMATCH;
02603     else
02604       grpc_minor_errno = GRPC_NO_MINOR_ERROR;
02605 
02606     grpc_errno = GRPC_OTHER_ERROR_CODE;
02607     return -1;
02608   }
02609 
02610   if(gs_encode_problem_submit_request(&msg, func_name, my_dsig, handle->criteria) < 0) {
02611     grpc_minor_errno = GRPC_SUBMIT_REQ_ENCODE;
02612     goto error_client_internal_error;
02613   }
02614 
02615   if(gs_send_string(sock, msg) < 0)
02616     goto error_communication_failed;
02617   FREE(msg);
02618   msg = NULL;
02619 
02637   /*
02638    * Receive the problem description if necessary 
02639    */
02640   if(handle->problem_desc != NULL) {
02641     problem_desc_to_be_transferred = 0;
02642     if(gs_send_int(sock, problem_desc_to_be_transferred) < 0)
02643       goto error_communication_failed;
02644   }
02645   else {
02646     problem_desc_to_be_transferred = 1;
02647     if(gs_send_int(sock, problem_desc_to_be_transferred) < 0)
02648       goto error_communication_failed;
02649     if(gs_recv_string(sock, &msg) < 0)
02650       goto error_communication_failed;
02651     if((handle->problem_desc =
02652         (gs_problem_t *) CALLOC(1, sizeof(gs_problem_t))) == NULL) {
02653       grpc_minor_errno = GRPC_OUT_OF_MEMORY;
02654       goto error_client_internal_error;
02655     }
02656     if(gs_decode_problem(msg, handle->problem_desc) < 0) {
02657       grpc_minor_errno = GRPC_PROBLEM_DECODE;
02658       goto error_communication_failed;
02659     }
02660     FREE(msg);
02661   }
02662 
02663   if(!strcmp(handle->problem_desc->description, GS_UNKNOWN_PROB)) {
02664     DBGPRINTF("Client Error: problem not found\n");
02665     if(sock != INVALID_SOCKET)
02666       proxy_close(sock);
02667     gs_free_problem(handle->problem_desc);
02668     handle->problem_desc = NULL;
02669     grpc_errno = GRPC_FUNCTION_NOT_FOUND;
02670     return -1;
02671   }
02672 
02673   /*
02674    * If one of args,argstack,my_dsig is passed in, then we need to send input 
02675    * scalars so that the agent can do agent side scheduling 
02676    */
02677   if(args || argstack || my_dsig != -1) {
02678     gs_va_list *vlptr, tmp_va_list;
02679 
02680     scalar_args_to_be_transferred = 1;
02681 
02682     if(gs_send_int(sock, scalar_args_to_be_transferred) < 0)
02683       goto error_communication_failed;
02684 
02685     /*
02686      * make a copy of the va_list if necessary before the call to
02687      * gs_send_input_scalar_args() since it seems to get clobbered and causes 
02688      * problems to reuse it for the actual submission. 
02689      */
02690 
02691     if(args) {
02692       va_copy(tmp_va_list.args, args->args);
02693       vlptr = &tmp_va_list;
02694     }
02695     else
02696       vlptr = NULL;
02697 
02698     if(gs_send_input_scalar_args(vlptr, argstack, sock, handle->problem_desc,
02699                                  my_dsig, grpc_client_lang,
02700                                  grpc_client_major) < 0)
02701       goto error_communication_failed;
02702   }
02703   else {
02704     scalar_args_to_be_transferred = 0;
02705     if(gs_send_int(sock, scalar_args_to_be_transferred) < 0)
02706       goto error_communication_failed;
02707   }
02708 
02709   /*
02710    * Receive the agent's task id.
02711    */
02712   if(gs_recv_int(sock, &(handle->agent_taskid)) < 0)
02713     goto error_communication_failed;
02714 
02715   /* agent task id useless if not transferring args */
02716 
02717   if(!scalar_args_to_be_transferred)
02718     handle->agent_taskid = -1;
02719 
02720   /*
02721    * Receive number of servers 
02722    */
02723   if(gs_recv_int(sock, &(handle->num_servers)) < 0)
02724     goto error_communication_failed;
02725 
02726   /*
02727    * If no servers return error 
02728    */
02729   if(handle->num_servers <= 0)
02730     goto error_server_not_found;
02731 
02732   if(handle->server_list)
02733     gs_free_handle_server_list(handle);
02734 
02735   handle->server_list = (gs_server_t **)
02736       CALLOC(handle->num_servers, sizeof(gs_server_t *));
02737   if(!handle->server_list) {
02738     grpc_minor_errno = GRPC_OUT_OF_MEMORY;
02739     goto error_client_internal_error;
02740   }
02741 
02742   for(i = 0; i < handle->num_servers; i++) {
02743     handle->server_list[i] = (gs_server_t *) CALLOC(1, sizeof(gs_server_t));
02744     if(gs_recv_string(sock, &msg) < 0)
02745       goto error_communication_failed;
02746     if(gs_decode_server(msg, handle->server_list[i]) < 0) {
02747       grpc_minor_errno = GRPC_SERVER_DECODE;
02748       goto error_client_internal_error;
02749     }
02750 
02751     FREE(msg);
02752   }
02753 
02754 #ifdef GS_PROFILING
02755   if(grpc_profile_next)
02756     grpc_profile_next->measure_comm = 0.0;
02757 #endif
02758 
02759   if(grpc_measure_comm) {
02760     argsize = gs_get_total_arg_size(handle);
02761 
02762     if(argsize > GS_ARG_SIZE_THRESH)
02763       if(gs_measure_network_perf(handle) == 0)
02764         gs_sort_servers_on_comp_plus_comm(handle, argsize);
02765   }
02766 
02767   if(handle->num_servers > 0) {
02768     if(gs_recv_string(sock, &msg) < 0)
02769       goto error_communication_failed;
02770 
02771     if(handle->problem_desc)
02772       gs_free_problem(handle->problem_desc);
02773 
02774     handle->problem_desc = (gs_problem_t *) CALLOC(1, sizeof(gs_problem_t));
02775     if(!handle->problem_desc) {
02776       grpc_minor_errno = GRPC_OUT_OF_MEMORY;
02777       goto error_client_internal_error;
02778     }
02779     if(gs_decode_problem(msg, handle->problem_desc) < 0) {
02780       grpc_minor_errno = GRPC_PROBLEM_DECODE;
02781       goto error_client_internal_error;
02782     }
02783     FREE(msg);
02784   }
02785 
02786   proxy_close(sock);
02787 
02788   handle->srv_idx = 0;
02789 
02790   handle->func_name = strdup(func_name);
02791 
02792   DBGPRINTF("Got %d servers from agent for problem %s\n",
02793             handle->num_servers, func_name);
02794 
02795   return 0;
02796 
02797 error_communication_failed:
02798   DBGPRINTF("Client Error: Communication failed\n");
02799   FREE(msg);
02800   if(sock != INVALID_SOCKET)
02801     proxy_close(sock);
02802   grpc_errno = GRPC_COMMUNICATION_FAILED;
02803   return -1;
02804 
02805 error_client_internal_error:
02806   DBGPRINTF("Client Error: Client internal error\n");
02807   FREE(msg);
02808   if(sock != INVALID_SOCKET)
02809     proxy_close(sock);
02810   grpc_errno = GRPC_OTHER_ERROR_CODE;
02811   return -1;
02812 
02813 error_server_not_found:
02814   DBGPRINTF("Client Error: Server not found\n");
02815   FREE(msg);
02816   if(sock != INVALID_SOCKET)
02817     proxy_close(sock);
02818   grpc_errno = GRPC_SERVER_NOT_FOUND;
02819   return -1;
02820 }
02821 
02822 
02835 static int
02836 gs_parse_host_port(char *str, ipaddr_t *ip, in_port_t * port)
02837 {
02838   struct hostent *hp;
02839   char *tok, *host_tok = NULL, *port_tok = NULL, delim[2];
02840 
02841   delim[0] = GS_PORT_DELIM;
02842   delim[1] = '\0';
02843 
02844   tok = strtok(str, delim);
02845   if(!tok)
02846     goto gs_parse_host_port_error;
02847 
02848   host_tok = strdup(tok);
02849   if(!host_tok)
02850     goto gs_parse_host_port_error;
02851 
02852   tok = strtok(NULL, delim);
02853   if(!tok)
02854     goto gs_parse_host_port_error;
02855 
02856   port_tok = strdup(tok);
02857   if(!port_tok)
02858     goto gs_parse_host_port_error;
02859 
02860   if((hp = gethostbyname(host_tok)) == NULL)
02861     goto gs_parse_host_port_error;
02862 
02863   memcpy((void *) ip, hp->h_addr_list[0], sizeof(*ip));
02864 
02865   *port = atoi(port_tok);
02866 
02867   if(host_tok)
02868     free(host_tok);
02869   if(port_tok)
02870     free(port_tok);
02871   return 0;
02872 
02873 gs_parse_host_port_error:
02874   if(host_tok)
02875     free(host_tok);
02876   if(port_tok)
02877     free(port_tok);
02878   return -1;
02879 }
02880 
02905 static int
02906 gs_parse_host_info(char *host_str, ipaddr_t *ip, in_port_t * port,
02907                    ipaddr_t *proxyip, in_port_t * proxyport, char *cid)
02908 {
02909   char *tok, *component_tok = NULL, *proxy_tok = NULL, delim[2];
02910 
02911   delim[0] = GS_PROXY_DELIM;
02912   delim[1] = '\0';
02913 
02914   /*
02915    * first get the part before the proxy delimiter.  this will be the server
02916    * host name and port. 
02917    */
02918 
02919   tok = strtok(host_str, delim);
02920   if(!tok)
02921     goto gs_parse_host_info_error;
02922 
02923   /*
02924    * copy this token for use later since strtok trashes things 
02925    */
02926 
02927   component_tok = strdup(tok);
02928   if(!component_tok)
02929     goto gs_parse_host_info_error;
02930 
02931   /*
02932    * now get the proxy part of the string 
02933    */
02934   tok = strtok(NULL, delim);
02935   if(!tok) {
02936     /*
02937      * no proxy specified 
02938      */
02939     proxy_tok = NULL;
02940     *proxyip = 0;
02941     *proxyport = 0;
02942     memset(cid, 0xFF, CID_LEN);
02943   }
02944   else {
02945     proxy_tok = strdup(tok);
02946     if(!proxy_tok)
02947       goto gs_parse_host_info_error;
02948 
02949     if(gs_parse_host_port(proxy_tok, proxyip, proxyport) < 0)
02950       goto gs_parse_host_info_error;
02951   }
02952 
02953   /*
02954    * check whether the server host name looks like a component ID 
02955    */
02956 
02957   if(component_tok[0] == '0' &&
02958      (component_tok[1] == 'x' || component_tok[1] == 'X')) {
02959     char delim[2];
02960 
02961     if(*proxyip == 0) {
02962       ERRPRINTF("If specifying a cid, proxy must be specified\n");
02963       goto gs_parse_host_info_error;
02964     }
02965 
02966     delim[0] = GS_PORT_DELIM;
02967     delim[1] = '\0';
02968 
02969     tok = strtok(component_tok, delim);
02970     if(!tok)
02971       goto gs_parse_host_info_error;
02972 
02973     proxy_str_to_cid(cid, tok);
02974     *ip = 0;
02975 
02976     tok = strtok(NULL, delim);
02977     if(!tok)
02978       goto gs_parse_host_info_error;
02979 
02980     *port = atoi(tok);
02981   }
02982   else {
02983     if(*proxyip != 0) {
02984       ERRPRINTF
02985           ("If proxy is used, component ID must be specified (not IP)\n");
02986       goto gs_parse_host_info_error;
02987     }
02988 
02989     memset(cid, 0xFF, CID_LEN);
02990     if(gs_parse_host_port(component_tok, ip, port) < 0)
02991       goto gs_parse_host_info_error;
02992   }
02993 
02994   if(component_tok)
02995     free(component_tok);
02996   if(proxy_tok)
02997     free(proxy_tok);
02998 
02999   return 0;
03000 
03001 gs_parse_host_info_error:
03002   if(component_tok)
03003     free(component_tok);
03004   if(proxy_tok)
03005     free(proxy_tok);
03006   return -1;
03007 }
03008 
03015 static int
03016 get_next_request_id()
03017 {
03018   int i;
03019 
03020   for(i = 0; i < MAX_GRPC_REQUESTS; i++) {
03021     if(grpc_outstanding_requests[i] == NULL)
03022       return i;
03023   }
03024 
03025   return -1;
03026 }
03027 
03044 static int
03045 gs_handle_blocking_call(grpc_function_handle_t *handle, gs_va_list *argptr,
03046                     void **argstack, SOCKET sock, int my_dsig)
03047 {
03048   int status_tag;
03049 
03050 
03051 
03052 #ifdef GS_SMART_GRIDSOLVE
03053 
03054   /*
03055    * Sending has_smart_arg_comm variable to the assigned server.
03056    * This variable specifies whether the remote task requires 
03057    * remote communication. This variable will be set to 1,
03058    * if the inputs are stored remotely or if the output arguments
03059    * should be sent remotely or cached locally.
03060    * 
03061    */ 
03062 
03063   if(gs_send_int(sock, handle->problem_desc->has_smart_arg_comm)<0){
03064     ERRPRINTF("SMART: Error sending has smart comm\n");
03065     return -1;
03066   }
03067  
03068  
03069   if(handle->problem_desc->has_smart_arg_comm){
03070    /*
03071     * If the remote task requires remote communication, then the mapping
03072     * information is sent to the server. This mapping info outlines
03073     * which inputs should be received from client, server file or server
03074     * memory. It also outlines which should be sent to client, stored
03075     * locally or sent remotely to another or 
03076     * multiple servers.
03077     */  
03078     if(gs_smart_send_map_info(sock, handle->problem_desc)<0){
03079       ERRPRINTF("SMART : Error sending mapping info\n");
03080       return -1;
03081     }
03082    /*
03083     * The client sends only the input arguments to the server
03084     * which have been outlined in the mapping solution.
03085     */  
03086     if(gs_smart_send_input_args(argptr, argstack, sock, handle->problem_desc,
03087                         my_dsig, grpc_client_lang, grpc_client_major) < 0)
03088       return -1;
03089 
03090 
03091 
03092      int pid; 
03093      pid=fork();
03094       if(pid==-1){
03095         ERRPRINTF("SMART: Out of memory could not fork\n");
03096         return -1;
03097       }
03098 
03099       if(pid==0){
03100         /*
03101          * Send input arguments from client to other servers as outlined by 
03102          * mapping solution
03103          */ 
03104         if(gs_smart_send_input_args_remotely(sock, handle->problem_desc, my_dsig)<0){
03105           ERRPRINTF("SMART : Error sending smart sending arguments\n");
03106           return -1;
03107         }
03108         _exit(0);
03109       }
03110 
03111  
03112   }
03113   else{
03114     if(gs_send_input_args(argptr, argstack, sock, handle->problem_desc,
03115                         my_dsig, grpc_client_lang, grpc_client_major) < 0)
03116       return -1;
03117   }
03118 #else
03119   if(gs_send_input_args(argptr, argstack, sock, handle->problem_desc,
03120                         my_dsig, grpc_client_lang, grpc_client_major) < 0)
03121     return -1;
03122 #endif
03123 
03124 
03125 
03126 #ifdef GS_PROFILING
03127   if(grpc_profile_next) {
03128     GRPC_TIMER_STOP(grpc_profile_next);
03129     grpc_profile_next->send_input = GRPC_TIMER_ELAPSED(grpc_profile_next);
03130     GRPC_TIMER_START(grpc_profile_next);
03131   }
03132 #endif
03133 
03134   if(gs_wait_for_output(sock) < 0) {
03135     ERRPRINTF("error waiting for output to be ready\n");
03136     return -1;
03137   }
03138 
03139   if(gs_recv_tag(sock, &status_tag) < 0)
03140     return -1;
03141 
03142   if(status_tag != GS_PROT_OK) {
03143     ERRPRINTF("Service failed: %s\n", gs_service_error[status_tag]);
03144     return -1;
03145   }
03146 
03147 
03148 #ifdef GS_SMART_GRIDSOLVE
03149   if(handle->problem_desc->has_smart_arg_comm==1){
03150    /*
03151     * The client receives only the output arguments from the server
03152     * which have been outlined in the mapping solution.
03153     */  
03154     if(gs_smart_recv_output_args(sock, handle->problem_desc, handle->server_list[handle->srv_idx]->data_format, 
03155                                  my_dsig) < 0){
03156       ERRPRINTF("SMART: Error trying to receive output args\n");
03157       return -1;
03158     }
03159   }
03160   else{
03161     if(gs_recv_output_args(sock, handle->problem_desc,
03162                          handle->server_list[handle->srv_idx]->data_format,
03163                          my_dsig) < 0)
03164       return -1;
03165   }
03166 #else
03167   if(gs_recv_output_args(sock, handle->problem_desc,
03168                          handle->server_list[handle->srv_idx]->data_format,
03169                          my_dsig) < 0)
03170     return -1;
03171 #endif
03172 
03173 
03174 #ifdef GS_PROFILING
03175   if(grpc_profile_next) {
03176     GRPC_TIMER_STOP(grpc_profile_next);
03177     grpc_profile_next->recv_output = GRPC_TIMER_ELAPSED(grpc_profile_next);
03178   }
03179 #endif
03180 
03181   return 0;
03182 }
03183 
03204 static int
03205 gs_handle_nonblocking_call(grpc_function_handle_t *handle, 
03206    grpc_sessionid_t *sessionId, gs_va_list *argptr,
03207    void **argstack, SOCKET sock, int my_dsig, char *request_id)
03208 {
03209   int idx = get_next_request_id();
03210   grpc_request_t *new_req;
03211   int retval = 0;
03212 
03213 
03214 #ifdef GS_SMART_GRIDSOLVE
03215   /*
03216    * Sending has_smart_arg_comm variable to the assigned server.
03217    * This variable specifies whether the remote task requires 
03218    * remote communication. This variable will be set to 1,
03219    * if the inputs are stored remotely or if the output arguments
03220    * should be sent remotely or cached locally.
03221    * 
03222    */ 
03223   if(gs_send_int(sock, handle->problem_desc->has_smart_arg_comm)<0){
03224     ERRPRINTF("SMART: Error sending has smart comm\n");
03225     return -1;
03226   }
03227 
03228 
03229   if(handle->problem_desc->has_smart_arg_comm){
03230    /*
03231     * If the remote task requires remote communication, then the mapping
03232     * information is sent to the server. This mapping info outlines
03233     * which inputs should be received from client, server file or server
03234     * memory. It also outlines which should be sent to client, stored
03235     * locally or sent remotely to another or 
03236     * multiple servers.
03237     */  
03238     if(gs_smart_send_map_info(sock, handle->problem_desc)<0){
03239       ERRPRINTF("SMART : Error sending mapping info\n");
03240       return -1;
03241     }
03242   }  
03243 
03244 #endif
03245 
03246 
03247 
03248 
03249   /*
03250    * before forking, call gs_send_input_scalar_args() so that the arg sizes
03251    * will be computed and stored in this problem struct.  it's better to do
03252    * this prior to forking because we'd otherwise need to communicate the
03253    * sizes back to the parent process. 
03254    */
03255 
03256   if(gs_send_input_scalar_args(argptr, argstack, sock, handle->problem_desc,
03257                                my_dsig, grpc_client_lang,
03258                                grpc_client_major) < 0)
03259     return -1;
03260 
03261   new_req = (grpc_request_t *) malloc(sizeof(grpc_request_t));
03262   if(!new_req || (idx < 0))
03263     return -1;
03264 
03265   new_req->request_id = request_id;
03266   new_req->handle = handle;
03267 
03268   /*
03269    * we need to dup the problem in case the user submits subsequent requests
03270    * with different arguments. 
03271    */
03272   new_req->problem = (gs_problem_t *) malloc(sizeof(gs_problem_t));
03273   if(!new_req->problem)
03274     return -1;
03275 
03276   if(gs_dup_problem(new_req->problem, handle->problem_desc) < 0)
03277     return -1;
03278 
03279   grpc_outstanding_requests[idx] = new_req;
03280   grpc_profile_info[idx] = grpc_profile_next;
03281 
03282 
03283 /* NOTE: On Win32 we do not fork to send the arguments, we send them in this process */
03284 /* TODO: ayk, should replace WIN32 with ifndef HAVE_FORK */
03285 #if defined (WIN32) || defined (WINNT)
03286   grpc_outstanding_requests[idx]->s_pid = 0;
03287   retval = gs_send_input_nonscalar_args(sock, handle->problem_desc, my_dsig);
03288   proxy_close(sock);
03289 #else
03290   grpc_outstanding_requests[idx]->s_pid = fork();
03291 
03292   switch (grpc_outstanding_requests[idx]->s_pid) {
03293     case -1:
03294       ERRPRINTF("Failed to fork process to send input data\n");
03295       grpc_request_destruct_free_clear(idx);
03296       return -1;
03297 
03298     case 0:                    /* child */
03299 
03300 #ifdef GS_SMART_GRIDSOLVE
03301       if(handle->problem_desc->has_smart_arg_comm==1){
03302        /*
03303         * The client sends only the input arguments to the server 
03304         * which have been outlined in the mapping solution.
03305         */  
03306         if(gs_smart_send_input_nonscalar_args(sock, handle->problem_desc, my_dsig) < 0)
03307           _exit(-1);
03308      
03309 
03310         int pid; 
03311         pid=fork();
03312         if(pid==-1){
03313           ERRPRINTF("SMART: Out of memory could not fork\n");
03314           return -1;
03315         }
03316 
03317         if(pid==0){
03318          /*
03319           * Send input arguments from client to other servers as outlined by mapping solution
03320           */ 
03321           if(gs_smart_send_input_args_remotely(sock ,handle->problem_desc, my_dsig)<0){
03322             ERRPRINTF("SMART : Error sending smart sending arguments\n");
03323             return -1;
03324           }
03325           _exit(0);
03326         }
03327 
03328       }
03329       else{
03330         if(gs_send_input_nonscalar_args(sock, handle->problem_desc, my_dsig) < 0)
03331           _exit(-1);
03332       
03333       }
03334 #else
03335 
03336       if(gs_send_input_nonscalar_args(sock, handle->problem_desc, my_dsig) < 0)
03337         _exit(-1);
03338 #endif
03339       proxy_close(sock);
03340       _exit(0);
03341 
03342     default:                   /* parent */
03343       proxy_close(sock);
03344   }
03345 #endif
03346 
03347   *sessionId = idx;
03348   return retval;
03349 }
03350 
03360 static int
03361 gs_notify_agent_of_cancel(grpc_function_handle_t *handle, char *reqid)
03362 {
03363   char *msg, srv_cid[2*CID_LEN+1];
03364   SOCKET sock;
03365   int tag, agent_taskid;
03366 
03367 #if !defined (WIN32) && !defined (WINNT)
03368   pid_t childpid;
03369   childpid = fork();
03370 
03371   if(childpid < 0) {
03372     ERRPRINTF("Failed to fork.\n");
03373     return -1;
03374   }
03375 
03376   if(childpid > 0)
03377     return 0;
03378 #endif
03379 
03380   if(handle->num_calls > 1)
03381     agent_taskid = -1;
03382   else
03383     agent_taskid = handle->agent_taskid;
03384 
03385   /* all code after here is executed in the child process */
03386 
03387   if((sock = gs_connect_to_agent()) == INVALID_SOCKET) {
03388     grpc_errno = GRPC_RPC_REFUSED;
03389     _exit(-1);
03390   }
03391 
03392   proxy_cid_to_str(srv_cid, handle->server_list[handle->srv_idx]->componentid);
03393 
03394   if((gs_send_tag(sock, GS_PROT_NOTIFY_CANCEL) < 0) ||
03395      (gs_send_string(sock, VERSION) < 0)) {
03396     ERRPRINTF("failed to send tag\n");
03397     close_socket(sock);
03398     _exit(-1);
03399   }
03400 
03401   if(gs_recv_tag(sock, &tag) < 0) {
03402     ERRPRINTF("Error communicating with agent.\n");
03403     close_socket(sock);
03404     _exit(-1);
03405   }
03406 
03407   if(tag != GS_PROT_OK) {
03408     if(tag == GS_PROT_VERSION_MISMATCH)
03409       ERRPRINTF("Error: Agent is an incompatible version\n");
03410     else
03411       ERRPRINTF("Error: Agent refused with code %d\n", tag);
03412     close_socket(sock);
03413     _exit(-1);
03414   }
03415 
03416   if(gs_encode_cancel_notification(&msg, srv_cid, reqid, agent_taskid) < 0)
03417   {
03418     ERRPRINTF("Failed to encode message\n");
03419     close_socket(sock);
03420     _exit(-1);
03421   }
03422 
03423   if(gs_send_string(sock, msg) < 0) {
03424     ERRPRINTF("failed to send tag\n");
03425     free(msg);
03426     close_socket(sock);
03427     _exit(-1);
03428   }
03429 
03430   free(msg);
03431 #if !defined (WIN32) && !defined (WINNT)
03432   close_socket(sock);
03433   _exit(0);
03434 #endif
03435   return 0;
03436 }
03437 
03447 static int
03448 gs_notify_agent_of_failure(grpc_function_handle_t *handle, char *reqid)
03449 {
03450   char *msg, srv_cid[2*CID_LEN+1];
03451   SOCKET sock;
03452   int tag, agent_taskid;
03453 
03454 #if !defined (WIN32) && !defined (WINNT)
03455   pid_t childpid;
03456   childpid = fork();
03457 
03458   if(childpid < 0) {
03459     ERRPRINTF("Failed to fork.\n");
03460     return -1;
03461   }
03462 
03463   if(childpid > 0)
03464     return 0;
03465 #endif /* WIN32 */
03466 
03467   if(handle->num_calls > 1)
03468     agent_taskid = -1;
03469   else
03470     agent_taskid = handle->agent_taskid;
03471 
03472   /* all code after here is executed in the child process */
03473 
03474   if((sock = gs_connect_to_agent()) == INVALID_SOCKET) {
03475     grpc_errno = GRPC_RPC_REFUSED;
03476     _exit(-1);
03477   }
03478 
03479   proxy_cid_to_str(srv_cid, handle->server_list[handle->srv_idx]->componentid);
03480 
03481   if((gs_send_tag(sock, GS_PROT_NOTIFY_FAILURE) < 0) ||
03482      (gs_send_string(sock, VERSION) < 0)) {
03483     ERRPRINTF("failed to send tag\n");
03484     close_socket(sock);
03485     _exit(-1);
03486   }
03487 
03488   if(gs_recv_tag(sock, &tag) < 0) {
03489     ERRPRINTF("Error communicating with agent.\n");
03490     close_socket(sock);
03491     _exit(-1);
03492   }
03493 
03494   if(tag != GS_PROT_OK) {
03495     if(tag == GS_PROT_VERSION_MISMATCH)
03496       ERRPRINTF("Error: Agent is an incompatible version\n");
03497     else
03498       ERRPRINTF("Error: Agent refused with code %d\n", tag);
03499     close_socket(sock);
03500     _exit(-1);
03501   }
03502 
03503   if(gs_encode_failure_notification(&msg, srv_cid, reqid, agent_taskid) < 0)
03504   {
03505     ERRPRINTF("Failed to encode message\n");
03506     close_socket(sock);
03507     _exit(-1);
03508   }
03509 
03510   if(gs_send_string(sock, msg) < 0) {
03511     ERRPRINTF("failed to send tag\n");
03512     free(msg);
03513     close_socket(sock);
03514     _exit(-1);
03515   }
03516 
03517   free(msg);
03518 #if !defined (WIN32) && !defined (WINNT)
03519   close(sock);
03520   _exit(0);
03521 #endif /* WIN32 */
03522   return 0;
03523 }
03524 
03555 static grpc_error_t
03556 gs_call_common(grpc_function_handle_t *handle, grpc_sessionid_t *sessionId,
03557     gs_va_list *argptr, void **argstack, int blocking)
03558 {
03559   int tag, agent_taskid;
03560   SOCKET sock;
03561   int my_dsig;
03562   char *msg, *request_id = NULL;
03563   gs_server_t *srv;
03564 
03565   if(!handle)
03566     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
03567   if(!handle->func_name)
03568     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
03569 
03570   grpc_minor_errno = GRPC_NO_MINOR_ERROR;
03571 
03572 
03573 #ifdef GS_SMART_GRIDSOLVE
03574 /*
03575  * when the user has explicitly speficied the number of tasks to build
03576  * check if there are still tasks to be built. if so set the phase to building.
03577  */
03578   if(group_type==GS_SMART_EXPLICIT_GROUP){
03579     if( gs_smart_get_nb_auto_tasks_left_to_build()>0 ){
03580       smart_phase=GS_SMART_TASK_DISCOVERY;
03581     }
03582   }
03583 
03584  /*
03585   * if we are still executing mapped tasks 
03586   * (i.e. when nb_mapped_tasks_executed<total_nb_mapped_tasks)
03587   * then embed the mapping information into this task handle.
03588   * If smart_phase has been set to GS_SMART_STANDARD_EXEC
03589   * then it means the task has already failed execution on 
03590   * a different server. Therefore we do not implement
03591   * the mapping for this task and execute it in the
03592   * standard gs protocol. 
03593   */
03594 
03595  if((nb_mapped_tasks_executed<total_nb_mapped_tasks) && 
03596     (smart_phase!=GS_SMART_STANDARD_EXEC) && (smart_phase!=GS_SMART_TASK_DISCOVERY)){
03597    if(gs_smart_mg_embed_mapping(handle, nb_mapped_tasks_executed)<0){
03598      ERRPRINTF("SMART : Error embedding mapping\n");
03599      return -1;
03600    }
03601  }
03602 #endif
03603 
03604 #ifdef GS_PROFILING
03605   if(grpc_profile_next) {
03606     /*
03607      * clear profiling info 
03608      */
03609     memset(grpc_profile_next, 0, sizeof(grpc_profile_t));
03610 
03611     GRPC_TIMER_START(grpc_profile_next);
03612   }
03613 #endif
03614 
03615 
03616 
03617 #ifdef GS_PROFILING
03618   if(grpc_profile_next) {
03619     /*
03620      * clear profiling info 
03621      */
03622     memset(grpc_profile_next, 0, sizeof(grpc_profile_t));
03623 
03624     GRPC_TIMER_START(grpc_profile_next);
03625   }
03626 #endif
03627 
03628   my_dsig = pvmgetdsig();
03629 
03630   /*
03631    * Check if the servers are to be bound now.  If so talk with the agent.
03632    * This variable was set when the handle was initialized 
03633    */
03634  
03635 #ifdef GS_SMART_GRIDSOLVE
03636 
03637 /*
03638  * if the current phase is the building phase, store the handle and exit
03639  * the gs_call_common_function
03640  */
03641   if( ( smart_phase==GS_SMART_TASK_DISCOVERY ) ){       
03642     /*
03643      * If the bind_servers_at_call_time parameter has been specified
03644      * i.e. the user has requested that the task gets mapped at 
03645      * run-time, then the handle's problem desc will not be initialised
03646      * for the task discovery phase. In this case we get the problem
03647      * description here.  And then when the task is called for execution
03648      * the problem description will not be retrieved like it normally would.
03649      * 
03650      */ 
03651     if(handle->bind_servers_at_call_time == 1) {
03652       char *tmp_name;
03653 
03654       /*
03655        * get_server_mapping will over-write both server_list and func_name.  we 
03656        * can go ahead and free the server_list now, but we will have to save a
03657        * pointer to func_name and free it afterwards. 
03658        */
03659       gs_free_handle_server_list(handle);
03660       tmp_name = handle->func_name;
03661       handle->func_name = NULL;
03662 
03663       /*
03664        * Get server mapping is a full transaction with the agent that can can
03665        * include the input arguments if they are provided 
03666        */
03667       if(gs_get_server_mapping(tmp_name, handle, argptr, argstack,
03668             my_dsig, grpc_client_lang, grpc_client_major) < 0) {
03669         /* restore the handle's function name */
03670         handle->func_name = tmp_name;
03671         handle->valid_mapping=0;
03672         GRPC_RETURN(grpc_errno, grpc_minor_errno);
03673       }
03674       handle->valid_mapping=1;
03675       free(tmp_name);
03676 
03677       /*
03678        * Keep this binding from now on, so that fault tolerance works correctly 
03679        */
03680       handle->bind_servers_at_call_time = 0;
03681     }
03682     
03683     if(gs_smart_store_handle(handle, sessionId, argptr, blocking, grpc_client_lang, grpc_client_major, group_type)<0){
03684        ERRPRINTF("SMART : Error storing handle \n");
03685        return -1;
03686     }
03687 
03688     /*
03689      * if the user has explicitly specified and the last task in that group has just
03690      * been built, then execute stored handles and exit the gs_call_common function.
03691      */
03692     if(group_type==GS_SMART_EXPLICIT_GROUP){
03693       if( gs_smart_get_nb_auto_tasks_left_to_build()==0 ){
03694          
03695         smart_phase=GS_SMART_EXEC_STORED_HANDLES;    
03696        /*
03697         TODO : reintroduce execute stored handles for explicit calls to gs_smart_map
03698         */
03699        smart_phase=GS_SMART_STANDARD_EXEC;
03700      }
03701    }
03702    handle->valid_mapping=1;
03703    return 0;
03704  }
03705 
03706  if(smart_phase==GS_SMART_STANDARD_EXEC){
03707    if(handle->bind_servers_at_call_time == 1) {
03708      char *tmp_name;
03709 
03710      /*
03711       * get_server_mapping will over-write both server_list and func_name.  we 
03712       * can go ahead and free the server_list now, but we will have to save a
03713       * pointer to func_name and free it afterwards. 
03714       */
03715      gs_free_handle_server_list(handle);
03716      tmp_name = handle->func_name;
03717      handle->func_name = NULL;
03718 
03719      /*
03720       * Get server mapping is a full transaction with the agent that can can
03721       * include the input arguments if they are provided 
03722       */
03723      if(gs_get_server_mapping(tmp_name, handle, argptr, argstack,
03724            my_dsig, grpc_client_lang, grpc_client_major) < 0) {
03725        /* restore the handle's function name */
03726        handle->func_name = tmp_name;
03727        GRPC_RETURN(grpc_errno, grpc_minor_errno);
03728      }
03729 
03730      free(tmp_name);
03731 
03732      /*
03733       * Keep this binding from now on, so that fault tolerance works correctly 
03734       */
03735      handle->bind_servers_at_call_time = 0;
03736    }  
03737    handle->valid_mapping=1;
03738  } 
03739 
03740 
03741 
03742 #else
03743  if(handle->bind_servers_at_call_time == 1) {
03744     char *tmp_name;
03745 
03746     /*
03747      * get_server_mapping will over-write both server_list and func_name.  we 
03748      * can go ahead and free the server_list now, but we will have to save a
03749      * pointer to func_name and free it afterwards. 
03750      */
03751     gs_free_handle_server_list(handle);
03752     tmp_name = handle->func_name;
03753     handle->func_name = NULL;
03754 
03755     /*
03756      * Get server mapping is a full transaction with the agent that can can
03757      * include the input arguments if they are provided 
03758      */
03759     if(gs_get_server_mapping(tmp_name, handle, argptr, argstack,
03760           my_dsig, grpc_client_lang, grpc_client_major) < 0) {
03761       /* restore the handle's function name */
03762       handle->func_name = tmp_name;
03763       GRPC_RETURN(grpc_errno, grpc_minor_errno);
03764     }
03765 
03766     free(tmp_name);
03767 
03768     /*
03769      * Keep this binding from now on, so that fault tolerance works correctly 
03770      */
03771     handle->bind_servers_at_call_time = 0;
03772   }
03773 #endif
03774 
03775 #ifdef GS_SMART_GRIDSOLVE
03776 /*
03777   if(!handle->valid_mapping){
03778       GRPC_RETURN(grpc_errno, grpc_minor_errno);
03779   }
03780 */
03781 #endif
03782   srv = handle->server_list[handle->srv_idx];
03783 
03784 #ifdef GS_PROFILING
03785   if(grpc_profile_next) {
03786     GRPC_TIMER_STOP(grpc_profile_next);
03787     grpc_profile_next->agent_comm = GRPC_TIMER_ELAPSED(grpc_profile_next);
03788     GRPC_TIMER_START(grpc_profile_next);
03789   }
03790 #endif
03791 
03792   /* compare greater than 0 here; elsewhere greater than 1.  this is because
03793    * at this point we haven't incremented yet.
03794    */
03795   if(handle->num_calls > 0)
03796     agent_taskid = -1;
03797   else
03798     agent_taskid = handle->agent_taskid;
03799 
03800 
03801 #ifdef GS_SMART_GRIDSOLVE
03802 
03803 printf("\n\n\n\n");
03804 printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
03805 printf("Executing task %s on server %s:%d\n", handle->problem_desc->name, srv->hostname, srv->port);
03806 
03807 #endif
03808 
03809   sock = gs_connect_to_host(srv->componentid, srv->ipaddress, srv->port,
03810                             srv->proxyip, srv->proxyport);
03811 
03812 
03813 
03814 /*
03815  * Implementing fault tolerance for SmartGridSolve
03816  */ 
03817 
03818  if(sock == INVALID_SOCKET){
03819 #ifdef GS_SMART_GRIDSOLVE
03820   if(smart_phase!=GS_SMART_STANDARD_EXEC){
03821     smart_phase=GS_SMART_EXEC_TASK_FAIL;
03822 
03823     /*
03824      * SmartGridSolve fault tolerance
03825      * Failed to connect to server
03826      * Sending failed server to agent to be removed from pm
03827      */
03828 
03829   printf("SMART: Server %s has failed during execution .\n", srv->hostname);
03830      if((sock = gs_connect_to_agent()) == INVALID_SOCKET)
03831        GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_AGENT_NOT_SET);
03832 
03833 
03834   if((gs_send_tag(sock, GS_SMART_FAULT_UPDATE_PM) < 0) ||
03835      (gs_send_string(sock, VERSION) < 0) ||
03836      (gs_recv_tag(sock, &tag) < 0))
03837     goto error_communication_failed;
03838   if(tag != GS_PROT_OK) {
03839     if(tag == GS_PROT_VERSION_MISMATCH) {
03840       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_VERSION_MISMATCH);
03841     } else {
03842       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
03843     }
03844   }
03845 
03846 
03847     char *srv_str = NULL;
03848     if((gs_encode_server(&srv_str, srv) < 0) ||
03849        (gs_send_string(sock, srv_str) < 0)) {
03850       FREE(srv);
03851       DBGPRINTF("Failed to send server list \n");
03852       return -1;
03853     }
03854 
03855     FREE(srv_str);
03856 
03857     
03858 
03859   printf("SMART: Server %s has been removed from network graph .\n", srv->hostname);
03860   printf("SMART: Remapping group of tasks.\n");
03861 
03862 
03863   if(gs_recv_tag(sock, &tag) < 0)
03864     goto error_communication_failed;
03865 
03866  
03867 
03868 
03869     return GRPC_NO_ERROR;
03870   }
03871   else{
03872     GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_SERVER_CONNECTION);
03873   } 
03874 #else 
03875     GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_SERVER_CONNECTION);
03876 #endif
03877   }
03878 
03879   if(gs_encode_problem_solve_request(&msg, handle->func_name, 
03880      grpc_user, grpc_host, grpc_domain, grpc_cid_str, my_dsig, 
03881      agent_taskid, srv->score) < 0) {
03882     grpc_minor_errno = GRPC_SOLVE_REQ_ENCODE;
03883     goto error_client_internal_error;
03884   }
03885 
03886   if(handle->problem_desc == NULL)
03887     tag = GS_PROT_PROBLEM_SOLVE_ASSIGNED;
03888   else
03889     tag = GS_PROT_PROBLEM_SOLVE;
03890 
03891   if((gs_send_tag(sock, tag) < 0) ||
03892      (gs_send_string(sock, VERSION) < 0))
03893     goto error_communication_failed;
03894 
03895   if(gs_recv_tag(sock, &tag) < 0)
03896     goto error_communication_failed;
03897   
03898   if(tag != GS_PROT_OK) {
03899     if(tag == GS_PROT_VERSION_MISMATCH)
03900       grpc_minor_errno = GRPC_VERSION_MISMATCH;
03901     else
03902       grpc_minor_errno = GRPC_NO_MINOR_ERROR;
03903 
03904     goto error_client_internal_error;
03905   }
03906 
03907   tag = (blocking) ? GS_PROT_BLOCKING : GS_PROT_NONBLOCKING;
03908 
03909   if(gs_send_tag(sock, tag) < 0)
03910     goto error_communication_failed;
03911 
03912   if(gs_send_string(sock, msg) < 0)
03913     goto error_communication_failed;
03914 
03915   FREE(msg);
03916 
03917   if(gs_recv_tag(sock, &tag) < 0)
03918     goto error_communication_failed;
03919 
03920   if(tag != GS_PROT_OK) {
03921     ERRPRINTF("Error occured\n");
03922     switch (tag) {
03923       case GS_SVC_ERR_EXEC:
03924         proxy_close(sock);
03925         GRPC_RETURN(GRPC_FUNCTION_NOT_FOUND, GRPC_NO_MINOR_ERROR);
03926       default:
03927         ERRPRINTF("%s\n", gs_service_error[tag]);
03928         proxy_close(sock);
03929         GRPC_RETURN(GRPC_OTHER_ERROR_CODE, tag);
03930     }
03931   }
03932 
03933   if(gs_recv_string(sock, &request_id) < 0)
03934     goto error_communication_failed;
03935 
03936   if(handle->problem_desc == NULL) {
03937     /*
03938      * this must be an assigned server request, so get the problem desc from 
03939      * the server.  also since the client won't know what architecture the
03940      * server is, the server will send its data signature now. 
03941      */
03942     if(gs_recv_string(sock, &msg) < 0)
03943       goto error_communication_failed;
03944     sscanf(msg, "%d", &(handle->server_list[handle->srv_idx]->data_format));
03945     free(msg);
03946 
03947     if(gs_recv_string(sock, &msg) < 0)
03948       goto error_communication_failed;
03949     handle->problem_desc = (gs_problem_t *) CALLOC(1, sizeof(gs_problem_t));
03950     if(gs_decode_problem(msg, handle->problem_desc) < 0) {
03951       grpc_minor_errno = GRPC_PROBLEM_DECODE;
03952       goto error_client_internal_error;
03953     }
03954     FREE(msg);
03955   }
03956 
03957   handle->num_calls++;
03958 #ifdef GS_SMART_GRIDSOLVE
03959   if((nb_mapped_tasks_executed<total_nb_mapped_tasks) &
03960     (smart_phase==GS_SMART_STANDARD_EXEC)){
03961     /*
03962      * If previous execution of this mapped tasks 
03963      * failed then set the remote comm variable to 0
03964      */
03965     handle->problem_desc->has_smart_arg_comm=0;
03966 
03967   }
03968 #endif
03969 
03970   if(blocking) {
03971     if(gs_handle_blocking_call(handle, argptr, argstack, sock, my_dsig) < 0)
03972     {
03973       if(gs_notify_agent_of_failure(handle, request_id) < 0)
03974         ERRPRINTF("Warning: failed to notify agent of server failure.\n");
03975       FREE(request_id);
03976       goto error_communication_failed;
03977     }
03978 #ifdef GS_SMART_GRIDSOLVE
03979    /*
03980     * after this blocking task is executed, check if there are still more 
03981     * mapped tasks to execute. if so then increment the number of mapped tasks executed
03982     */    
03983     if(nb_mapped_tasks_executed<total_nb_mapped_tasks){
03984       nb_mapped_tasks_executed++;
03985     }
03986     /*
03987      * if the last mapped task has just been executed
03988      * then reset counters
03989      */ 
03990     else{
03991       //free mapping and maybe task graph
03992       nb_mapped_tasks_executed=0;
03993       total_nb_mapped_tasks=0;
03994     }
03995 #endif
03996 
03997 
03998     FREE(request_id);
03999   }
04000   else {
04001     if(gs_handle_nonblocking_call(handle, sessionId, argptr, argstack, sock,
04002           my_dsig, request_id) < 0)
04003     {
04004       if(gs_notify_agent_of_failure(handle, request_id) < 0)
04005         ERRPRINTF("Warning: failed to notify agent of server failure.\n");
04006       goto error_communication_failed;
04007     }
04008 
04009 #ifdef GS_SMART_GRIDSOLVE
04010    /*
04011     * after this blocking task is executed, check if there are still more 
04012     * mapped tasks to execute. if so then increment the number of mapped tasks executed
04013     */    
04014     if(nb_mapped_tasks_executed<total_nb_mapped_tasks){
04015       nb_mapped_tasks_executed++;
04016     }
04017     /*
04018      * if the last mapped task has just been executed
04019      * then reset counters
04020      */ 
04021     else{
04022       //free mapping and maybe task graph
04023       nb_mapped_tasks_executed=0;
04024       total_nb_mapped_tasks=0;
04025     }
04026 #endif
04027     FREE(msg);
04028     GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04029   }
04030 
04031   FREE(msg)
04032   proxy_close(sock);
04033   return GRPC_NO_ERROR;
04034 
04035 
04036 error_communication_failed:
04037 #ifdef GS_SMART_GRIDSOLVE
04038   if(smart_phase!=GS_SMART_STANDARD_EXEC){
04039     smart_phase=GS_SMART_EXEC_TASK_FAIL;
04040     if(sock != INVALID_SOCKET){
04041       proxy_close(sock);
04042     }
04043     FREE(msg);
04044 
04045   printf("SMART: Server %s has failed during execution .\n", srv->hostname);
04046     /*
04047      * SmartGridSolve fault tolerance
04048      * Failed to communicate with servers (inputs, outputs, tags etc.)
04049      * Sending failed server to agent to be removed from pm
04050      */
04051     
04052      if((sock = gs_connect_to_agent()) == INVALID_SOCKET)
04053        GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_AGENT_NOT_SET);
04054   
04055      if((gs_send_tag(sock, GS_SMART_FAULT_UPDATE_PM) < 0) ||
04056         (gs_send_string(sock, VERSION) < 0) ||
04057         (gs_recv_tag(sock, &tag) < 0))
04058           goto error_communication_failed;
04059         
04060      if(tag != GS_PROT_OK) {
04061        if(tag == GS_PROT_VERSION_MISMATCH) {
04062          GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_VERSION_MISMATCH);
04063        } else {
04064         GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
04065       }
04066     }
04067 
04068 
04069     char *srv_str = NULL;
04070     if((gs_encode_server(&srv_str, srv) < 0) ||
04071        (gs_send_string(sock, srv_str) < 0)) {
04072       FREE(srv);
04073       DBGPRINTF("Failed to send server list \n");
04074       return -1;
04075     }
04076 
04077 
04078     
04079   if(gs_recv_tag(sock, &tag) < 0)
04080     goto error_communication_failed;
04081 
04082   printf("SMART: Server %s has been removed from network graph .\n", srv->hostname);
04083   printf("SMART: Remapping of the group of tasks will now be implemented .\n");
04084     
04085 FREE(srv_str);
04086     return GRPC_NO_ERROR;
04087 
04088   }
04089   else{
04090     if(sock != INVALID_SOCKET){
04091       proxy_close(sock);
04092     }
04093     FREE(msg);
04094     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, grpc_minor_errno);
04095   }
04096 #else
04097   if(sock != INVALID_SOCKET){
04098     proxy_close(sock);
04099   }
04100   FREE(msg);
04101   GRPC_RETURN(GRPC_COMMUNICATION_FAILED, grpc_minor_errno);
04102 #endif
04103 
04104 error_client_internal_error:
04105   if(sock != INVALID_SOCKET)
04106     proxy_close(sock);
04107   FREE(msg);
04108   GRPC_RETURN(GRPC_OTHER_ERROR_CODE, grpc_minor_errno);
04109 }
04110 
04126 grpc_error_t
04127 gs_wait_common(grpc_request_t *req)
04128 {
04129   int my_dsig;
04130   SOCKET sock;
04131   int tag;
04132   gs_server_t *srv;
04133 
04134   grpc_minor_errno = GRPC_NO_MINOR_ERROR;
04135 
04136   my_dsig = pvmgetdsig();
04137 
04138   if(!req->handle)
04139     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
04140 
04141 
04142 #ifdef GS_SMART_GRIDSOLVE
04143   /*
04144    * Count the number of output arguments that should be 
04145    * received from the server as outlined in the mapping 
04146    * solution. If there are none the function returns.
04147    */ 
04148   
04149   gs_argument_t *argptr;
04150   int nb_args_to_receive=0;
04151   for(argptr= req->handle->problem_desc->arglist;argptr!=NULL;argptr=argptr->next) {
04152     if(argptr->objecttype!=GS_SCALAR){
04153       if( ( argptr->inout==GS_INOUT ) || ( argptr->inout==GS_OUT ) ) {
04154         if(argptr->output_arg_sent_remotely==0) nb_args_to_receive++;
04155       }
04156     }
04157   }
04158   if(nb_args_to_receive==0){
04159     GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04160   }
04161 #endif
04162 
04163 
04164   if(req->s_pid > 0)
04165     gs_req_child_waitpid(req, GS_WBLOCK);
04166 
04167   srv = req->handle->server_list[req->handle->srv_idx];
04168 
04169   sock = gs_connect_to_host(srv->componentid, srv->ipaddress,
04170                             srv->port, srv->proxyip, srv->proxyport);
04171 
04172   if(sock == INVALID_SOCKET)
04173     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_SERVER_CONNECTION);
04174 
04175   if((gs_send_tag(sock, GS_PROT_AWAIT_COMPLETION) < 0) ||
04176      (gs_send_string(sock, VERSION) < 0))
04177     goto error_communication_failed;
04178 
04179   if(gs_recv_tag(sock, &tag) < 0)
04180     goto error_communication_failed;
04181 
04182   if(tag != GS_PROT_OK) {
04183     if(tag == GS_PROT_VERSION_MISMATCH)
04184       grpc_minor_errno = GRPC_VERSION_MISMATCH;
04185     else
04186       grpc_minor_errno = GRPC_NO_MINOR_ERROR;
04187 
04188     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, grpc_minor_errno);
04189   }
04190 
04191   if(gs_send_string(sock, req->request_id) < 0)
04192     goto error_communication_failed;
04193 
04194 
04195 #ifdef GS_SMART_GRIDSOLVE
04196   
04197  /*
04198   * For each output argument send the variable output_arg_sent_remotely to 
04199   * the server. This specifies whether the output arg is sent remotely or
04200   * back to the client as outlined by the mapping solution.  
04201   */  
04202 
04203   for(argptr= req->handle->problem_desc->arglist;argptr!=NULL;argptr=argptr->next) {
04204     if(argptr->objecttype!=GS_SCALAR){
04205       if( ( argptr->inout==GS_INOUT ) || ( argptr->inout==GS_OUT ) ) {
04206         if(gs_send_int(sock, argptr->output_arg_sent_remotely) < 0) {
04207           ERRPRINTF("gs_send output remote param\n");
04208           return -1;         
04209         }
04210       }
04211     }
04212   }
04213 
04214 
04215 #endif
04216 
04217 
04218 
04219   if(gs_wait_for_output(sock) < 0)
04220     goto error_communication_failed;
04221 
04222   if(gs_recv_tag(sock, &tag) < 0)
04223     goto error_communication_failed;
04224 
04225   if(tag != GS_PROT_OK) {
04226     ERRPRINTF("Service failed: %s\n", gs_service_error[tag]);
04227     grpc_minor_errno = tag;
04228     goto error_protocol_error;
04229   }
04230 
04231 
04232 
04233 #ifdef GS_SMART_GRIDSOLVE
04234  /*
04235   * The client receives only the output arguments from the server
04236   * which have been outlined in the mapping solution.
04237   */
04238   
04239   if(gs_smart_recv_output_args_from_server(sock, req->problem, req->handle->problem_desc,
04240               req->handle->server_list[req->handle->srv_idx]->data_format,  my_dsig) < 0){
04241     goto error_communication_failed;
04242   }
04243 
04244 #else
04245 
04246   if(gs_recv_output_args(sock, req->problem,
04247        req->handle->server_list[req->handle->srv_idx]->data_format, 
04248        my_dsig) < 0)
04249     goto error_communication_failed;
04250 #endif
04251 
04252   proxy_close(sock);
04253 
04254   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04255 
04256 error_communication_failed:
04257   if(sock != INVALID_SOCKET)
04258     proxy_close(sock);
04259   if(gs_notify_agent_of_failure(req->handle, req->request_id) < 0)
04260     ERRPRINTF("Warning: failed to notify agent of server failure.\n");
04261   GRPC_RETURN(GRPC_COMMUNICATION_FAILED, grpc_minor_errno);
04262 
04263 error_protocol_error:
04264   if(sock != INVALID_SOCKET)
04265     proxy_close(sock);
04266   if(gs_notify_agent_of_failure(req->handle, req->request_id) < 0)
04267     ERRPRINTF("Warning: failed to notify agent of server failure.\n");
04268   GRPC_RETURN(GRPC_SESSION_FAILED, grpc_minor_errno);
04269 }
04270 
04279 static int
04280 grpc_request_destruct(grpc_request_t *req)
04281 {
04282   if(!req)
04283     return -1;
04284 
04285   /*
04286    * don't free handle since it's only a pointer to the user's data. we'll
04287    * let them free it. 
04288    */
04289   if(req->request_id)
04290     free(req->request_id);
04291   req->request_id = NULL;
04292   if(req->problem)
04293     gs_free_problem(req->problem);
04294 
04295   return 0;
04296 }
04297 
04309 int
04310 grpc_request_destruct_free_clear(grpc_sessionid_t sessionId)
04311 {
04312   int rc = -1;
04313 
04314   if((sessionId < 0) || (sessionId >= MAX_GRPC_REQUESTS))
04315     return 0;
04316 
04317   rc = grpc_request_destruct(grpc_outstanding_requests[sessionId]);
04318   if(rc != 0)
04319     return -1;
04320   if(grpc_outstanding_requests[sessionId])
04321     free(grpc_outstanding_requests[sessionId]);
04322   grpc_outstanding_requests[sessionId] = NULL;
04323   grpc_profile_info[sessionId] = NULL;
04324 
04325   return 0;
04326 }
04327 
04352 grpc_error_t
04353 grpc_call_ft(grpc_function_handle_t *handle, ...)
04354 {
04355   gs_va_list argptr;
04356 
04357   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04358 
04359   va_start(argptr.args, handle);
04360 
04361   return gs_call_common_ft(handle, NULL, &argptr, NULL, TRUE);
04362 }
04363 
04387 grpc_error_t
04388 grpc_call_valist_ft(grpc_function_handle_t *handle, gs_va_list *argptr)
04389 {
04390   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04391 
04392   return gs_call_common_ft(handle, NULL, argptr, NULL, TRUE);
04393 }
04394 
04421 grpc_error_t
04422 grpc_call_async_ft(grpc_function_handle_t *handle, 
04423    grpc_sessionid_t *sessionId, ...)
04424 {
04425   gs_va_list argptr;
04426 
04427   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04428 
04429   va_start(argptr.args, sessionId);
04430 
04431   return gs_call_common_ft(handle, sessionId, &argptr, NULL, FALSE);
04432 }
04433 
04459 grpc_error_t
04460 grpc_call_valist_async_ft(grpc_function_handle_t *handle, 
04461    grpc_sessionid_t *sessionId, gs_va_list *argptr)
04462 {
04463   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04464 
04465   return gs_call_common_ft(handle, sessionId, argptr, NULL, FALSE);
04466 }
04467 
04491 grpc_error_t
04492 grpc_call_arg_stack_ft(grpc_function_handle_t *handle, grpc_arg_stack *stack)
04493 {
04494   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04495 
04496   if(!stack || !stack->args)
04497     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_ARGSTACK);
04498   if(!handle)
04499     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
04500   if(!handle->func_name)
04501     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
04502 
04503   return gs_call_common_ft(handle, NULL, NULL, stack->args, TRUE);
04504 }
04505 
04531 grpc_error_t
04532 grpc_call_arg_stack_async_ft(grpc_function_handle_t *handle,
04533    grpc_sessionid_t *sessionId, grpc_arg_stack *stack)
04534 {
04535   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04536 
04537   if(!stack || !stack->args)
04538     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_ARGSTACK);
04539   if(!handle)
04540     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
04541   if(!handle->func_name)
04542     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
04543 
04544   return gs_call_common_ft(handle, sessionId, NULL, stack->args, FALSE);
04545 }
04546 
04577 static grpc_error_t
04578 gs_call_common_ft(grpc_function_handle_t *handle, grpc_sessionid_t *sessionId, 
04579    gs_va_list *argptr, void **argstack, int blocking)
04580 {
04581   int c;
04582   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04583 
04584   for(c = 0; c < handle->num_servers; c++) {
04585     grpc_error_t rv;
04586 #ifdef GS_SMART_GRIDSOLVE
04587     /*
04588      * If currently executing a mapped group of tasks 
04589      * a task fails on its first server, then set
04590      * standard exec phase so that the execution
04591      * proceeds using the standard gridsolve protocol.
04592      */ 
04593     if((c>0) && (nb_mapped_tasks_executed<total_nb_mapped_tasks)){
04594       smart_phase=GS_SMART_STANDARD_EXEC;
04595     }
04596 #endif
04597     rv = gs_call_common(handle, sessionId, argptr, argstack, blocking);
04598 
04599     if(rv == GRPC_NO_ERROR)
04600       GRPC_RETURN(rv, GRPC_NO_MINOR_ERROR);
04601 
04602     if(handle->num_servers == 0)
04603       break;
04604     handle->srv_idx = (handle->srv_idx + 1) % handle->num_servers;
04605   }
04606   handle->srv_idx = 0;
04607   GRPC_RETURN(GRPC_SERVER_NOT_FOUND, GRPC_NO_MINOR_ERROR);
04608 }
04609 
04622 grpc_error_t
04623 grpc_profile(grpc_profile_t *prof)
04624 {
04625 #ifdef GS_PROFILING
04626   grpc_profile_next = prof;
04627   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04628 #else
04629 
04630   GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_PROFILING_NOT_ENABLED);
04631 #endif
04632 }
04633 
04648 grpc_error_t
04649 grpc_set_client_major(char *maj)
04650 {
04651   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04652 
04653   if(!maj)
04654     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_INVALID_MAJOR);
04655 
04656   if((maj[0] == 'R') || (maj[0] == 'r')) {
04657     grpc_client_major = 'r';
04658     grpc_user_set_major = TRUE;
04659   }
04660   else if((maj[0] == 'C') || (maj[0] == 'c')) {
04661     grpc_client_major = 'c';
04662     grpc_user_set_major = TRUE;
04663   }
04664   else
04665     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_INVALID_MAJOR);
04666 
04667   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04668 }
04669 
04684 grpc_error_t
04685 grpc_set_default_major(char *maj)
04686 {
04687   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04688 
04689   if(!grpc_user_set_major)
04690     return grpc_set_client_major(maj);
04691 
04692   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04693 }
04694 
04706 grpc_error_t
04707 grpc_set_client_language(int lang)
04708 {
04709   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04710 
04711   if((lang != GS_CALL_FROM_C) && (lang != GS_CALL_FROM_FORTRAN))
04712     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_INVALID_LANG);
04713 
04714   grpc_client_lang = lang;
04715 
04716   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04717 }
04718 
04737 grpc_error_t
04738 grpc_probe_ft(grpc_sessionid_t sessionID)
04739 {
04740   grpc_function_handle_t *handle;
04741   grpc_error_t retval;
04742   int c; 
04743 
04744   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04745 
04746   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
04747     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
04748 
04749   retval = grpc_probe(sessionID);
04750 
04751   /*
04752    * if probe returns 
04753    */
04754 
04755   if((retval == GRPC_NO_ERROR) || (retval == GRPC_NOT_COMPLETED))
04756     GRPC_RETURN(retval, grpc_minor_errno);
04757 
04758   handle = grpc_outstanding_requests[sessionID]->handle;
04759 
04760   if(!handle)
04761     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
04762   if(!handle->func_name)
04763     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
04764 
04765   /*
04766    * if we reach this point, then the call to grpc_probe detected a failure
04767    * and we should resubmit the request to another server. 
04768    */
04769 
04770   for(c = 0; c < handle->num_servers; c++) {
04771     if(gs_resubmit_common(sessionID) == GRPC_NO_ERROR)
04772       GRPC_RETURN(GRPC_NOT_COMPLETED, GRPC_NO_MINOR_ERROR);
04773 
04774     if(handle->num_servers == 0)
04775       break;
04776 
04777     handle->srv_idx = (handle->srv_idx + 1) % handle->num_servers;
04778   }
04779 
04780   handle->srv_idx = 0;
04781 
04782   GRPC_RETURN(GRPC_SERVER_NOT_FOUND, GRPC_NO_MINOR_ERROR);
04783 }
04784 
04804 grpc_error_t
04805 grpc_wait_ft(grpc_sessionid_t sessionID)
04806 {
04807   grpc_function_handle_t *handle;
04808   int c;
04809 
04810   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
04811 
04812   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
04813     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
04814 
04815   if(grpc_wait(sessionID) == GRPC_NO_ERROR)
04816     return GRPC_NO_ERROR;
04817 
04818   handle = grpc_outstanding_requests[sessionID]->handle;
04819 
04820   if(!handle)
04821     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
04822   if(!handle->func_name)
04823     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
04824 
04825   /*
04826    * if we reach this point, then the call to grpc_wait detected a failure
04827    * and we should resubmit the request to another server. 
04828    */
04829 
04830   for(c = 0; c < handle->num_servers; c++) {
04831     if(gs_resubmit_common(sessionID) == GRPC_NO_ERROR) {
04832 
04833       /*
04834        * ok, we were able to resubmit the job successfully, so now we wait
04835        * for it to complete.  if this wait fails, we keep attempting to
04836        * resubmit until no more servers remain. 
04837        */
04838       if(grpc_wait(sessionID) == GRPC_NO_ERROR)
04839         return GRPC_NO_ERROR;
04840     }
04841 
04842     if(handle->num_servers == 0)
04843       break;
04844     handle->srv_idx = (handle->srv_idx + 1) % handle->num_servers;
04845   }
04846 
04847   handle->srv_idx = 0;
04848   GRPC_RETURN(GRPC_SERVER_NOT_FOUND, GRPC_NO_MINOR_ERROR);
04849 }
04850 
04872 static grpc_error_t
04873 gs_resubmit_common(grpc_sessionid_t sessionID)
04874 {
04875   grpc_function_handle_t *handle;
04876   int tag;
04877   SOCKET sock;
04878   int my_dsig;
04879   char *msg, *request_id = NULL;
04880   gs_server_t *srv;
04881 
04882   if((sessionID < 0) || (sessionID >= MAX_GRPC_REQUESTS))
04883     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
04884 
04885   if(!grpc_outstanding_requests[sessionID])
04886     GRPC_RETURN(GRPC_INVALID_SESSION_ID, GRPC_NO_MINOR_ERROR);
04887 
04888   handle = grpc_outstanding_requests[sessionID]->handle;
04889 
04890   if(!handle)
04891     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
04892   if(!handle->func_name)
04893     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_NAME);
04894 
04895   srv = handle->server_list[handle->srv_idx];
04896 
04897   sock = gs_connect_to_host(srv->componentid, srv->ipaddress, srv->port,
04898                             srv->proxyip, srv->proxyport);
04899 
04900   if(sock < 0)
04901     GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_SERVER_CONNECTION);
04902 
04903   my_dsig = pvmgetdsig();
04904   handle->agent_taskid = -1;
04905 
04906   if(gs_encode_problem_solve_request(&msg, handle->func_name, 
04907      grpc_user, grpc_host, grpc_domain, grpc_cid_str, my_dsig,
04908      handle->agent_taskid, srv->score) < 0) {
04909     proxy_close(sock);
04910     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_SOLVE_REQ_ENCODE);
04911   }
04912 
04913   tag = GS_PROT_PROBLEM_SOLVE;
04914 
04915   if((gs_send_tag(sock, tag) < 0) ||
04916      (gs_send_string(sock, VERSION) < 0)) {
04917     proxy_close(sock);
04918     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
04919   }
04920 
04921   if(gs_recv_tag(sock, &tag) < 0) {
04922     proxy_close(sock);
04923     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
04924   }
04925 
04926   if(tag != GS_PROT_OK) {
04927     if(tag == GS_PROT_VERSION_MISMATCH)
04928       grpc_minor_errno = GRPC_VERSION_MISMATCH;
04929     else
04930       grpc_minor_errno = GRPC_NO_MINOR_ERROR;
04931 
04932     proxy_close(sock);
04933     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, grpc_minor_errno);
04934   }
04935 
04936   tag = GS_PROT_NONBLOCKING;
04937 
04938   if(gs_send_tag(sock, tag) < 0) {
04939     proxy_close(sock);
04940     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
04941   }
04942 
04943   if(gs_send_string(sock, msg) < 0) {
04944     proxy_close(sock);
04945     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
04946   }
04947 
04948   free(msg);
04949 
04950   if(gs_recv_tag(sock, &tag) < 0) {
04951     proxy_close(sock);
04952     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
04953   }
04954 
04955   if(tag != GS_PROT_OK) {
04956     switch (tag) {
04957       case GS_SVC_ERR_EXEC:
04958         proxy_close(sock);
04959         GRPC_RETURN(GRPC_FUNCTION_NOT_FOUND, GRPC_NO_MINOR_ERROR);
04960       default:
04961         ERRPRINTF("%s\n", gs_service_error[tag]);
04962         proxy_close(sock);
04963         GRPC_RETURN(GRPC_OTHER_ERROR_CODE, tag);
04964         break;
04965     }
04966   }
04967 
04968   if(gs_recv_string(sock, &request_id) < 0) {
04969     proxy_close(sock);
04970     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
04971   }
04972 
04973   if(gs_send_input_args(NULL, NULL, sock, handle->problem_desc,
04974                         my_dsig, grpc_client_lang, grpc_client_major) < 0) {
04975     proxy_close(sock);
04976     GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
04977   }
04978 
04979   /*
04980    * free the old request id and assign the new one 
04981    */
04982   free(grpc_outstanding_requests[sessionID]->request_id);
04983   grpc_outstanding_requests[sessionID]->request_id = request_id;
04984 
04985   proxy_close(sock);
04986 
04987   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
04988 }
04989 
04998 static int
04999 gs_free_handle_server_list(grpc_function_handle_t *handle)
05000 {
05001   int i;
05002 
05003   if(!handle)
05004     return -1;
05005 
05006   if(handle->server_list) {
05007     /*
05008      * Remove/destroy any old server mapping memory/data-structures 
05009      */
05010     for(i = 0; i < handle->num_servers; i++)
05011       gs_server_free(handle->server_list[i]);
05012     free(handle->server_list);
05013     handle->srv_idx = 0;
05014     handle->num_servers = 0;
05015     handle->server_list = NULL;
05016   }
05017 
05018   return 0;
05019 }
05020 
05037 grpc_error_t *
05038 grpc_farm(char *iteration, char *func_name, ...)
05039 {
05040   int start, end, *returned_value;
05041   va_list argptr;
05042   char *buf;
05043 
05044   GRPC_FAIL_IF_NOT_INITIALIZED(NULL);
05045 
05046   if((!iteration) || (!func_name)) {
05047     grpc_errno = GRPC_OTHER_ERROR_CODE;
05048     return NULL;
05049   }
05050 
05051   buf = strdup(iteration);
05052 
05053   if(!buf) {
05054     grpc_errno = GRPC_OTHER_ERROR_CODE;
05055     return NULL;
05056   }
05057 
05058   /* get the <start> end the <end> */
05059   if (sscanf(buf,"i=%d,%d",&start,&end) != 2)
05060   {
05061     free(buf);
05062     grpc_errno = GRPC_OTHER_ERROR_CODE;
05063     returned_value = (int *)calloc(1,sizeof(int));
05064     returned_value[0] = GRPC_OTHER_ERROR_CODE;
05065     return returned_value;
05066   }
05067 
05068   free(buf);
05069 
05070   va_start(argptr, func_name);
05071 
05072   return grpc_farming(start, end, func_name, argptr);
05073 }
05074 
05087 grpc_error_t
05088 grpc_farm_set_failure_status(int *statuses, int num_req, 
05089    grpc_sessionid_t *sessionids)
05090 {
05091   grpc_sessionid_t failed_sid;
05092   int i;
05093 
05094   if(grpc_get_failed_sessionid(&failed_sid) == GRPC_NO_ERROR) {
05095     for(i = 0; i < num_req; i++) {
05096       if(sessionids[i] == failed_sid) {
05097         statuses[i] = grpc_get_error(failed_sid);
05098         GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05099       }
05100     }
05101   }
05102 
05103   /* if we reach here, the session id was not found */
05104   GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_FARM_SESSIONID_NOT_FOUND);
05105 }
05106 
05123 grpc_error_t *
05124 grpc_farming(int start, int end, char *func_name, va_list argptr)
05125 {
05126   int *statuses;
05127   int nb_requests;
05128   int window_size;          /* window size = 2 * # of capable servers */
05129   int status;
05130   int i, j;
05131   int nb_args;
05132   int pending;
05133   gs_argument_t *argp = NULL;
05134   grpc_iterator_t **iterator_array = NULL;
05135   grpc_error_t *returned_value;
05136   grpc_sessionid_t *sessionids;
05137   grpc_function_handle_t *handles;
05138 
05139   GRPC_FAIL_IF_NOT_INITIALIZED(NULL);
05140 
05141   if(!func_name) {
05142     grpc_errno = GRPC_NOT_INITIALIZED;
05143     grpc_minor_errno = GRPC_NULL_FUNCTION_NAME;
05144     return NULL;
05145   }
05146 
05147   /*
05148    * Start the farming 
05149    */
05150   nb_requests = end - start + 1;
05151   statuses = (int *) calloc(nb_requests, sizeof(int));
05152   sessionids = (grpc_sessionid_t *) calloc(nb_requests,
05153      sizeof(grpc_sessionid_t));
05154   handles = (grpc_function_handle_t *) calloc(nb_requests,
05155      sizeof(grpc_function_handle_t));
05156 
05157   if(!statuses || !sessionids || !handles) {
05158     if(statuses) free(statuses);
05159     if(sessionids) free(sessionids);
05160     if(handles) free(handles);
05161     grpc_errno = GRPC_OTHER_ERROR_CODE;
05162     grpc_minor_errno = GRPC_NO_MINOR_ERROR;
05163     return NULL;
05164   }
05165 
05166   if(grpc_function_handle_default(&handles[0], func_name) != GRPC_NO_ERROR) {
05167     ERRPRINTF("Could not get function handle\n");
05168     grpc_errno = GRPC_OTHER_ERROR_CODE;
05169     grpc_minor_errno = GRPC_NO_MINOR_ERROR;
05170     return NULL;
05171   }
05172 
05173   /*
05174    * Getting the nb_args 
05175    */
05176   nb_args = 0;
05177   for(argp = handles[0].problem_desc->arglist; argp != NULL; argp = argp->next)
05178     nb_args++;
05179 
05180   window_size = handles[0].num_servers * 2;
05181 
05182   grpc_function_handle_destruct(&handles[0]);
05183 
05184   if(grpc_construct_iterator_array(argptr, nb_args, &iterator_array, start) == -1)
05185     ERRPRINTF("Could not construct iterator array\n");
05186 
05187   /*
05188    * Filling problem_desc->arglist->data 
05189    */
05190 
05191   DBGPRINTF("# of requests is %d \n", nb_requests);
05192 
05193   if(nb_requests <= window_size) {
05194     j = nb_requests;
05195     pending = 0;
05196   }
05197   else {
05198     j = window_size;
05199     pending = 1;
05200   }
05201 
05202   for(i = 0; i < j; i++)
05203   {
05204     
05205     if(grpc_function_handle_default(&handles[i], func_name) != 
05206         GRPC_NO_ERROR)
05207     {
05208       statuses[i] = grpc_errno;
05209       sessionids[i] = -1;
05210     }
05211     else 
05212       statuses[i] = grpc_send_farming_request(&handles[i], &sessionids[i], 
05213         iterator_array, nb_args);
05214   }
05215 
05216   if(!pending) {
05217     if(grpc_wait_and(sessionids, nb_requests) != GRPC_NO_ERROR)
05218       grpc_farm_set_failure_status(statuses, nb_requests, sessionids);
05219   }
05220   else {                        
05221     int num_retrieved = 0;
05222 
05223     while(num_retrieved < nb_requests) {
05224       if(grpc_wait_any(&status) != GRPC_NO_ERROR)
05225         grpc_farm_set_failure_status(statuses, nb_requests, sessionids);
05226       
05227       num_retrieved++;
05228 
05229       if(i < nb_requests) {
05230         if(grpc_function_handle_default(&handles[i], func_name) != 
05231             GRPC_NO_ERROR)
05232         {
05233           statuses[i] = grpc_errno;
05234           sessionids[i] = -1;
05235         }
05236         else
05237           statuses[i] =
05238             grpc_send_farming_request(&handles[i], &sessionids[i], 
05239                iterator_array, nb_args);
05240         i++;
05241       }
05242     }
05243   }
05244 
05245   status = 1;
05246   for(i = 0; i < nb_requests; i++) {
05247     if(statuses[i] != GRPC_NO_ERROR)
05248       status = -1;
05249 
05250     grpc_function_handle_destruct(&handles[i]);
05251   }
05252   free(handles);
05253 
05254   if(status == -1) {
05255     returned_value = (grpc_error_t *) calloc(nb_requests + 1, sizeof(grpc_error_t));
05256     returned_value[0] = GRPC_OTHER_ERROR_CODE;
05257     for(i = 0; i < nb_requests; i++)
05258       returned_value[i + 1] = statuses[i];
05259     grpc_errno = GRPC_OTHER_ERROR_CODE;
05260     grpc_minor_errno = GRPC_NO_MINOR_ERROR;
05261   }
05262   else {
05263     returned_value = (grpc_error_t *) calloc(1, sizeof(grpc_error_t));
05264     returned_value[0] = GRPC_NO_ERROR;
05265     grpc_errno = GRPC_NO_ERROR;
05266     grpc_minor_errno = GRPC_NO_MINOR_ERROR;
05267   }
05268 
05269   return returned_value;
05270 }
05271 
05272 
05294 grpc_error_t
05295 grpc_send_farming_request(grpc_function_handle_t *handle, grpc_sessionid_t *sid,
05296                           grpc_iterator_t **iterator_array, int nb_args)
05297 {
05298   gs_service_error_enum_t save_minor_errno;
05299   grpc_arg_stack *stack = NULL;
05300   gs_argument_t *argp = NULL;
05301   grpc_error_t status;
05302 
05303   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
05304 
05305   if(!handle)
05306     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NULL_FUNCTION_HANDLE);
05307   if(!iterator_array)
05308     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_FARM_NULL_ITERATOR);
05309 
05310   status =
05311       grpc_setup_farming_args(handle->problem_desc, iterator_array, nb_args);
05312   if(status != GRPC_NO_ERROR)
05313     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_FARM_SETUP_ARGS_FAILED);
05314 
05315   /*
05316    * Creating Stack 
05317    */
05318   stack = grpc_arg_stack_new(nb_args);
05319   if(!stack)
05320     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_FARM_CREATE_STACK_FAILED);
05321 
05322   for(argp = handle->problem_desc->arglist; argp != NULL; argp = argp->next) {
05323     if(grpc_arg_stack_push_arg(stack, argp->data) < 0)
05324       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_FARM_CREATE_STACK_FAILED);
05325   }
05326 
05327   /*
05328    * Calling solve routine with stack interface 
05329    */
05330   status = grpc_call_arg_stack_async_ft(handle, sid, stack);
05331   save_minor_errno = grpc_minor_errno;
05332   grpc_arg_stack_destruct(stack);
05333   GRPC_RETURN(status, save_minor_errno);
05334 }
05335 
05349 grpc_error_t
05350 grpc_setup_farming_args(gs_problem_t *problem, grpc_iterator_t **it_array,
05351                         int nb_args)
05352 {
05353   void *dataptr = NULL;
05354   gs_argument_t *argp = NULL;
05355   int i = 0;
05356   grpc_void_star_or_int_t *stackarray;
05357 
05358   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
05359 
05360   if(!problem || !it_array)
05361     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05362 
05363   /*
05364    * Creating Array from Iterators 
05365    */
05366   if(grpc_generate_array_from_iterators
05367      (problem, &stackarray, it_array, nb_args) != GRPC_NO_ERROR)
05368     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05369 
05370   /*
05371    * For each argument, check datatype, and attach a dataptr to the arg->data 
05372    */
05373   for(argp = problem->arglist, i = 0; argp != NULL; argp = argp->next, i++) {
05374     switch (argp->datatype) {
05375       case GS_DOUBLE:
05376         dataptr = (double *) calloc(1, sizeof(double));
05377         if(!dataptr)
05378           GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05379         dataptr = (double *) (stackarray[i].ptr);
05380         break;
05381       case GS_SCOMPLEX:
05382         dataptr = (gs_scomplex *) calloc(1, sizeof(gs_scomplex));
05383         if(!dataptr)
05384           GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05385         dataptr = (gs_scomplex *) (stackarray[i].ptr);
05386         break;
05387       case GS_DCOMPLEX:
05388         dataptr = (gs_dcomplex *) calloc(1, sizeof(gs_dcomplex));
05389         if(!dataptr)
05390           GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05391         dataptr = (gs_dcomplex *) (stackarray[i].ptr);
05392         break;
05393       case GS_INT:
05394         dataptr = (int *) calloc(1, sizeof(int));
05395         if(!dataptr)
05396           GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05397         if(argp->objecttype == GS_SCALAR)
05398           ((int *) dataptr)[0] = stackarray[i].i;
05399         else
05400           dataptr = (int *) (stackarray[i].ptr);
05401         break;
05402       case GS_FLOAT:
05403         dataptr = (float *) calloc(1, sizeof(float));
05404         if(!dataptr)
05405           GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05406         /*
05407          * if (argp->inout == GS_IN || argp->inout == GS_INOUT) 
05408          */
05409         dataptr = (float *) (stackarray[i].ptr);
05410         break;
05411       case GS_CHAR:
05412         dataptr = (char *) calloc(1, sizeof(char));
05413         dataptr = (char *) (stackarray[i].ptr);
05414         break;
05415       default:
05416         ERRPRINTF("This datatype is not handled yet\n");
05417         GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05418     }
05419     argp->data = dataptr;
05420   }
05421 
05422   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05423 }
05424 
05438 grpc_error_t
05439 grpc_generate_array_from_iterators(gs_problem_t *pd,
05440                                    grpc_void_star_or_int_t **stackarray,
05441                                    grpc_iterator_t **iterator_array,
05442                                    int nb_args)
05443 {
05444   grpc_void_star_or_int_t *new;
05445   int i;
05446   grpc_iterator_t *it;
05447   int arg_type;
05448 
05449   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
05450 
05451   if(!pd || !iterator_array)
05452     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05453 
05454   new =
05455       (grpc_void_star_or_int_t *) calloc(nb_args,
05456                                          sizeof(grpc_void_star_or_int_t));
05457   for(i = 0; i < nb_args; i++) {
05458     it = iterator_array[i];
05459     arg_type = it->returned_type;
05460     switch (arg_type) {
05461       case IGNORE:
05462         new[i].ptr = NULL;
05463         break;
05464       case POINTER:
05465         new[i].ptr = grpc_get_next(it, arg_type).ptr;
05466         break;
05467       case INTEGER:
05468         new[i].i = grpc_get_next(it, arg_type).i;
05469         break;
05470     }
05471   }
05472 
05473   *stackarray = new;
05474 
05475   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05476 }
05477 
05492 grpc_error_t
05493 grpc_construct_iterator_array(va_list argptr, int nb_args,
05494                               grpc_iterator_t ***iterator_array, int start)
05495 {
05496   grpc_iterator_t **new;
05497   int i;
05498 
05499   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
05500 
05501   new = (grpc_iterator_t **) calloc(nb_args, sizeof(grpc_iterator_t *));
05502 
05503   for(i = 0; i < nb_args; i++) {
05504     new[i] = (grpc_iterator_t *) va_arg(argptr, void *);
05505     new[i]->i = start;
05506   }
05507   *iterator_array = new;
05508 
05509   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05510 }
05511 
05518 void
05519 grpc_free_iterator(grpc_iterator_t *it)
05520 {
05521   if(!it) {
05522     grpc_errno = GRPC_OTHER_ERROR_CODE;
05523     return;
05524   }
05525 
05526   grpc_free_specific_iterator(it->specific);
05527   free(it);
05528 }
05529 
05536 void
05537 grpc_free_specific_iterator(grpc_specific_iterator_t *it)
05538 {
05539   if(!it) {
05540     grpc_errno = GRPC_OTHER_ERROR_CODE;
05541     return;
05542   }
05543 
05544   switch (it->type) {
05545     case INT_ITERATOR:
05546       free(it->it.int_iterator->expression);
05547       free(it->it.int_iterator);
05548       break;
05549     case INT_ARRAY_ITERATOR:
05550       free(it->it.int_array_iterator->expression);
05551       free(it->it.int_array_iterator);
05552       break;
05553     case PTR_ARRAY_ITERATOR:
05554       free(it->it.ptr_array_iterator->expression);
05555       free(it->it.ptr_array_iterator);
05556       break;
05557   }
05558 
05559   free(it);
05560 }
05561 
05570 grpc_iterator_t *
05571 grpc_int(char *s)
05572 {
05573   grpc_iterator_t *it;
05574 
05575   if(!s) {
05576     grpc_errno = GRPC_OTHER_ERROR_CODE;
05577     return NULL;
05578   }
05579 
05580   it = (grpc_iterator_t *) calloc(1, sizeof(grpc_iterator_t));
05581   it->returned_type = INTEGER;
05582   it->specific =
05583       (grpc_specific_iterator_t *) calloc(1,
05584                                           sizeof(grpc_specific_iterator_t));
05585   it->specific->type = INT_ITERATOR;
05586   it->specific->it.int_iterator =
05587       (grpc_int_iterator_t *) calloc(1, sizeof(grpc_int_iterator_t));
05588   it->specific->it.int_iterator->expression = strdup(s);
05589 
05590   return it;
05591 }
05592 
05602 grpc_iterator_t *
05603 grpc_int_array(int *array, char *expression)
05604 {
05605   grpc_iterator_t *it;
05606 
05607   if(!expression) {
05608     grpc_errno = GRPC_OTHER_ERROR_CODE;
05609     return NULL;
05610   }
05611 
05612   it = (grpc_iterator_t *) calloc(1, sizeof(grpc_iterator_t));
05613   it->returned_type = INTEGER;
05614   it->specific =
05615       (grpc_specific_iterator_t *) calloc(1,
05616                                           sizeof(grpc_specific_iterator_t));
05617   it->specific->type = INT_ARRAY_ITERATOR;
05618   it->specific->it.int_array_iterator =
05619       (grpc_int_array_iterator_t *) calloc(1,
05620                                            sizeof(grpc_int_array_iterator_t));
05621   it->specific->it.int_array_iterator->array = array;
05622   it->specific->it.int_array_iterator->expression = strdup(expression);
05623 
05624   return it;
05625 }
05626 
05636 grpc_iterator_t *
05637 grpc_ptr_array(void **array, char *expression)
05638 {
05639   grpc_iterator_t *it;
05640 
05641   if(!expression) {
05642     grpc_errno = GRPC_OTHER_ERROR_CODE;
05643     return NULL;
05644   }
05645 
05646   it = (grpc_iterator_t *) calloc(1, sizeof(grpc_iterator_t));
05647   it->returned_type = POINTER;
05648   it->specific =
05649       (grpc_specific_iterator_t *) calloc(1,
05650                                           sizeof(grpc_specific_iterator_t));
05651   it->specific->type = PTR_ARRAY_ITERATOR;
05652   it->specific->it.ptr_array_iterator =
05653       (grpc_ptr_array_iterator_t *) calloc(1,
05654                                            sizeof(grpc_ptr_array_iterator_t));
05655   it->specific->it.ptr_array_iterator->array = array;
05656   it->specific->it.ptr_array_iterator->expression = strdup(expression);
05657 
05658   return it;
05659 }
05660 
05670 grpc_void_star_or_int_t
05671 grpc_get_next(grpc_iterator_t *it, int arg_type)
05672 {
05673   grpc_void_star_or_int_t stuff;
05674   stuff.ptr = NULL;
05675 
05676   if(!it) {
05677     grpc_errno = GRPC_OTHER_ERROR_CODE;
05678     return stuff;
05679   }
05680 
05681   stuff = grpc_get_value(it->specific, it->i, arg_type);
05682   (it->i)++;
05683 
05684   return stuff;
05685 }
05686 
05697 grpc_void_star_or_int_t
05698 grpc_get_value(grpc_specific_iterator_t *it, int i, int arg_type)
05699 {
05700   grpc_void_star_or_int_t stuff;
05701   int *x;
05702   stuff.ptr = NULL;
05703 
05704   if(!it) {
05705     grpc_errno = GRPC_OTHER_ERROR_CODE;
05706     return stuff;
05707   }
05708 
05709   switch (it->type) {
05710     case INT_ITERATOR:
05711       stuff.i = grpc_eval_integer(it->it.int_iterator->expression, i);
05712       break;
05713     case INT_ARRAY_ITERATOR:
05714       if(arg_type == INTEGER) {
05715         stuff.i =
05716             (it->it.int_array_iterator->
05717              array)[grpc_eval_integer(it->it.int_array_iterator->expression,
05718                                       i)];
05719       }
05720       else if(arg_type == POINTER) {
05721         stuff.ptr = (it->it.int_array_iterator->array) +
05722             grpc_eval_integer(it->it.int_array_iterator->expression, i);
05723       }
05724       break;
05725     case PTR_ARRAY_ITERATOR:
05726       if(arg_type == POINTER) {
05727         stuff.ptr =
05728             (it->it.ptr_array_iterator->
05729              array)[grpc_eval_integer(it->it.ptr_array_iterator->expression,
05730                                       i)];
05731       }
05732       if(arg_type == INTEGER) {
05733         x = (it->it.ptr_array_iterator->
05734              array)[grpc_eval_integer(it->it.ptr_array_iterator->expression,
05735                                       i)];
05736         stuff.i = *x;
05737       }
05738       break;
05739     default:
05740       ERRPRINTF("Unknown ITERATOR\n");
05741       stuff.i = 0;
05742   }
05743 
05744   return stuff;
05745 }
05746 
05757 int
05758 grpc_eval_integer(char *s, int i)
05759 {
05760   return i;
05761 }
05762 
05763 
05764 
05765 #ifdef GS_SMART_GRIDSOLVE
05766 
05767 
05768 
05769 
05770 grpc_error_t
05771 grpc_update_server_list(char **info)
05772 {
05773   char dottedIP[20], proxy_dottedIP[20];
05774   char *msg=NULL;
05775   int i, num_servers, tag;
05776   gs_server_t **server_list;
05777   SOCKET sock;
05778   char *str1 = NULL;
05779   char *str2 = NULL;
05780 
05781   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
05782 
05783   if((sock = gs_connect_to_agent()) == INVALID_SOCKET)
05784     GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_AGENT_NOT_SET);
05785 
05786   if((gs_send_tag(sock, GS_PROT_SERVER_LIST) < 0) ||
05787      (gs_send_string(sock, VERSION) < 0) || 
05788      (gs_recv_tag(sock, &tag) < 0))
05789     goto error_communication_failed;
05790   if(tag != GS_PROT_OK) {
05791     if(tag == GS_PROT_VERSION_MISMATCH) {
05792       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_VERSION_MISMATCH);
05793     } else {
05794       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05795     }
05796   }
05797 
05798   if(gs_recv_int(sock, &num_servers) < 0)
05799     goto error_communication_failed;
05800   
05801   str1 = dstring_sprintf("AGENT: %s [%d servers]\n", agent_resolved->hostname,
05802      num_servers);
05803   
05804   if(num_servers <= 0) {
05805     *info = str1;
05806     GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05807   }
05808 
05809   server_list = (gs_server_t **) CALLOC(num_servers, sizeof(gs_server_t *));
05810   if(!server_list) 
05811     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
05812 
05813   for(i=0;i<num_servers;i++) {
05814     server_list[i] = (gs_server_t *) CALLOC(1,sizeof(gs_server_t));
05815     if(gs_recv_string(sock, &msg) < 0) {
05816       goto error_communication_failed;
05817     }
05818     if(gs_decode_server(msg, server_list[i]) < 0) {
05819       FREE(msg);
05820       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_SERVER_DECODE);
05821     }
05822     FREE(msg)
05823   }
05824 
05825   for(i=0;i<num_servers;i++) {
05826     proxy_ip_to_str(server_list[i]->ipaddress, dottedIP);
05827     proxy_ip_to_str(server_list[i]->proxyip, proxy_dottedIP);
05828     if(server_list[i]->proxyip != 0)
05829       str2 = dstring_sprintf("SERVER: %s (%s:%d, proxy=%s:%d)\n", server_list[i]->hostname, 
05830                  dottedIP, server_list[i]->port, proxy_dottedIP, 
05831                  server_list[i]->proxyport);
05832     else
05833       str2 = dstring_sprintf("SERVER: %s (%s:%d)\n", server_list[i]->hostname, 
05834                  dottedIP, server_list[i]->port);
05835     str1 = dstring_append_free(str1, str2);
05836   }
05837 
05838   for(i=0;i<num_servers;i++) 
05839     FREE(server_list[i]);
05840   FREE(server_list);
05841 
05842   if(sock != INVALID_SOCKET)  proxy_close(sock);
05843 
05844   *info = str1;
05845   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05846   
05847   
05848  error_communication_failed:
05849   DBGPRINTF("Client Error: Communication failed\n");
05850   FREE(msg);
05851   if(sock != INVALID_SOCKET)  proxy_close(sock);
05852   GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
05853   
05854 }
05855 
05856 
05857 
05858 
05859 #endif
05860 
05861 
05862 
05874 grpc_error_t
05875 grpc_get_servers(char **info)
05876 {
05877   char dottedIP[20], proxy_dottedIP[20];
05878   char *msg=NULL;
05879   int i, num_servers, tag;
05880   gs_server_t **server_list;
05881   SOCKET sock;
05882   char *str1 = NULL;
05883   char *str2 = NULL;
05884 
05885   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
05886 
05887   if((sock = gs_connect_to_agent()) == INVALID_SOCKET)
05888     GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_AGENT_NOT_SET);
05889 
05890   if((gs_send_tag(sock, GS_PROT_SERVER_LIST) < 0) ||
05891      (gs_send_string(sock, VERSION) < 0) || 
05892      (gs_recv_tag(sock, &tag) < 0))
05893     goto error_communication_failed;
05894   if(tag != GS_PROT_OK) {
05895     if(tag == GS_PROT_VERSION_MISMATCH) {
05896       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_VERSION_MISMATCH);
05897     } else {
05898       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05899     }
05900   }
05901 
05902   if(gs_recv_int(sock, &num_servers) < 0)
05903     goto error_communication_failed;
05904   
05905   str1 = dstring_sprintf("AGENT: %s [%d servers]\n", agent_resolved->hostname,
05906      num_servers);
05907   
05908   if(num_servers <= 0) {
05909     *info = str1;
05910     GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05911   }
05912 
05913   server_list = (gs_server_t **) CALLOC(num_servers, sizeof(gs_server_t *));
05914   if(!server_list) 
05915     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
05916 
05917   for(i=0;i<num_servers;i++) {
05918     server_list[i] = (gs_server_t *) CALLOC(1,sizeof(gs_server_t));
05919     if(gs_recv_string(sock, &msg) < 0) {
05920       goto error_communication_failed;
05921     }
05922     if(gs_decode_server(msg, server_list[i]) < 0) {
05923       FREE(msg);
05924       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_SERVER_DECODE);
05925     }
05926     FREE(msg)
05927   }
05928 
05929   for(i=0;i<num_servers;i++) {
05930     proxy_ip_to_str(server_list[i]->ipaddress, dottedIP);
05931     proxy_ip_to_str(server_list[i]->proxyip, proxy_dottedIP);
05932     if(server_list[i]->proxyip != 0)
05933       str2 = dstring_sprintf("SERVER: %s (%s:%d, proxy=%s:%d)\n", server_list[i]->hostname, 
05934                  dottedIP, server_list[i]->port, proxy_dottedIP, 
05935                  server_list[i]->proxyport);
05936     else
05937       str2 = dstring_sprintf("SERVER: %s (%s:%d)\n", server_list[i]->hostname, 
05938                  dottedIP, server_list[i]->port);
05939     str1 = dstring_append_free(str1, str2);
05940   }
05941 
05942   for(i=0;i<num_servers;i++) 
05943     FREE(server_list[i]);
05944   FREE(server_list);
05945 
05946   if(sock != INVALID_SOCKET)  proxy_close(sock);
05947 
05948   *info = str1;
05949   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
05950   
05951   
05952  error_communication_failed:
05953   DBGPRINTF("Client Error: Communication failed\n");
05954   FREE(msg);
05955   if(sock != INVALID_SOCKET)  proxy_close(sock);
05956   GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
05957   
05958 }
05959 
05960 
05972 grpc_error_t
05973 grpc_get_problems(char **info)
05974 {
05975   char *msg=NULL;
05976   int i, tag;
05977   SOCKET sock;
05978   char *str1 = NULL;
05979   char *str2 = NULL;
05980   int num_problems;
05981   gs_problem_t ** problem_list;
05982 
05983   GRPC_FAIL_IF_NOT_INITIALIZED(GRPC_NOT_INITIALIZED);
05984 
05985   if((sock = gs_connect_to_agent()) == INVALID_SOCKET)
05986     GRPC_RETURN(GRPC_RPC_REFUSED, GRPC_AGENT_NOT_SET);
05987 
05988   if((gs_send_tag(sock, GS_PROT_PROBLEM_LIST) < 0) ||
05989      (gs_send_string(sock, VERSION) < 0) || 
05990      (gs_recv_tag(sock, &tag) < 0))
05991     goto error_communication_failed;
05992   if(tag != GS_PROT_OK) {
05993     grpc_errno = GRPC_OTHER_ERROR_CODE;
05994     if(tag == GS_PROT_VERSION_MISMATCH) {
05995       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_VERSION_MISMATCH);
05996     } else {
05997       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_NO_MINOR_ERROR);
05998     }
05999   }
06000 
06001   if(gs_recv_int(sock, &num_problems) < 0) {
06002     goto error_communication_failed;
06003   }
06004 
06005   str1 = dstring_sprintf("AGENT: %s [%d problems]\n", agent_resolved->hostname,
06006     num_problems);
06007 
06008   if(num_problems <= 0) {
06009     *info = str1;
06010     GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
06011   }
06012 
06013   problem_list = (gs_problem_t **) CALLOC(num_problems, sizeof(gs_problem_t *));
06014   if(!problem_list) { 
06015     GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_OUT_OF_MEMORY);
06016   }
06017 
06018   for(i=0;i<num_problems;i++) {
06019     problem_list[i] = (gs_problem_t *) CALLOC(1,sizeof(gs_problem_t));
06020     if(gs_recv_string(sock, &msg) < 0) {
06021       goto error_communication_failed;
06022     }
06023     if(gs_decode_problem(msg, problem_list[i]) < 0) {
06024       FREE(msg);
06025       GRPC_RETURN(GRPC_OTHER_ERROR_CODE, GRPC_SERVER_DECODE);
06026     }
06027     FREE(msg);
06028   }
06029 
06030   for(i=0;i<num_problems;i++) {
06031     str2 = dstring_sprintf("%s\n", problem_list[i]->name);
06032     str1 = dstring_append_free(str1, str2);
06033   }
06034   
06035   for(i=0;i<num_problems;i++) 
06036     FREE(problem_list[i]);
06037   FREE(problem_list);
06038 
06039   if(sock != INVALID_SOCKET) proxy_close(sock);
06040   
06041   *info = str1;
06042   GRPC_RETURN(GRPC_NO_ERROR, GRPC_NO_MINOR_ERROR);
06043   
06044   
06045  error_communication_failed:
06046   DBGPRINTF("Client Error: Communication failed\n");
06047   FREE(msg);
06048   if(sock != INVALID_SOCKET)  proxy_close(sock);
06049   GRPC_RETURN(GRPC_COMMUNICATION_FAILED, GRPC_NO_MINOR_ERROR);
06050   
06051 }
06052 
06064 int gs_smart_map_two_cycles(char * mapper_name, char * comm_type){
06065 
06066 #ifdef GS_SMART_GRIDSOLVE
06067   /*
06068    * list of handles session ids and blocking array of the group of 
06069    * tasks to be mapped. These structures are initialised
06070    * when gs_smart_get_handle_list is called which gets the list of
06071    * handles,session ids and blocking arrays which were initialised
06072    * in the previous pass through the group of tasks. 
06073    * This is used to generate the app_pm.
06074    * 
06075    */  
06076   grpc_function_handle_t ** handle_list;
06077   int nb_tasks;
06078   int ** blocking_array;
06079   grpc_sessionid_t ** session_ids;
06080 
06081   /* 
06082    * application performance model is used by agent 
06083    * to generate task graph for the group of tasks.
06084    */
06085   gs_smart_app_pm * app_pm=NULL;
06086 
06087   /*
06088    * task graph and network performance model
06089    * used by mapping heuristic to generate
06090    * a mapping solution for the group of tasks.
06091    */
06092   gs_smart_tg * tg=NULL;
06093   gs_smart_netpm * netpm=NULL;
06094 
06095   call_type=GS_SMART_TWO_PASS_CALL;  
06096   group_type=GS_SMART_IMPLICIT_GROUP;  
06097 
06098   if(!mapper_name){
06099     ERRPRINTF("SMART : Error mapper name is NULL\n");
06100     smart_phase=GS_SMART_MAP_FAIL;
06101     return -1;
06102   }
06103 
06104   /*
06105    * The first time  gs_smart_map is called 
06106    * the GS_SMART_TASK_DISCOVERY phase is set, the 
06107    * mapping parameters parameters are then set. After this we enter the first pass (pass 0)
06108    * through the scope of the group of tasks, this is done by returning 1.
06109    * In this pass task discovery is performed.
06110    */ 
06111   if((current_pass==0) && (smart_phase==GS_SMART_STANDARD_EXEC)){
06112 
06113 
06114     /* Free the previous handle list */
06115     if(gs_smart_free_handle_list()<0){
06116       ERRPRINTF("SMART: Error freeing handle list\n");
06117       return -1;
06118     } 
06119 
06120     /*** First time this function is called enter here ***/
06121     smart_phase=GS_SMART_TASK_DISCOVERY;
06122     nb_mapped_tasks_executed=0;
06123     total_nb_mapped_tasks=0;
06124 
06125     /*
06126      *  if mapper name is left empty use default mapper
06127      */
06128     if(strcmp(mapper_name, "")==0){    
06129       if(gs_smart_set_mapper_type("greedy_map")<0){
06130         ERRPRINTF("SMART: Default mapper not found\n");
06131         smart_phase=GS_SMART_MAP_FAIL;
06132         return -1;
06133       }
06134     }
06135     else{
06136       if(gs_smart_set_mapper_type(mapper_name)<0){
06137         ERRPRINTF("SMART: %s mapper not found\n", mapper_name);
06138         smart_phase=GS_SMART_MAP_FAIL;
06139         return -1;
06140       }
06141     }
06142     if(strcmp(comm_type, "")==0){    
06143       set_comm_type="enable_remote_comm";
06144     }
06145     else{
06146       if((strcmp(comm_type,"enable_remote_comm")==0) |
06147          (strcmp(comm_type, "disable_remote_comm")==0) |
06148          (strcmp(comm_type, "no_dep")==0) |
06149          (strcmp(comm_type, "server_comm")==0)){
06150         set_comm_type=comm_type;
06151       }
06152       else{
06153        ERRPRINTF("SMART : Did not recognise the second parameter to GS_SMART_MAP\n");
06154        set_comm_type="enable_remote_comm";
06155       }
06156     }
06157     return 1;
06158   }
06159 
06160 
06161   /*
06162    * The second time  gs_smart_map is called 
06163    * the GS_SMART_MAPPING phase is set.
06164    * Once this is done the group of tasks is mapped.
06165    * After this is the second pass (pass 1) 
06166    * through the scope of the group of tasks. Therefore 1 is returned to enter second pass.
06167    *  On this pass through the group of tasks, each called handle is executed 
06168    *  according to the mapping. This phase is called the GS_SMART_EXEC_CALLED_HANDLES phase.
06169    */ 
06170 
06171   else if((current_pass==0) && (smart_phase==GS_SMART_TASK_DISCOVERY)){
06172     /*** Second time this function is called enter here ***/
06173     smart_phase=GS_SMART_MAPPING;
06174    /*
06175     * Get the stored list of handles which was initalised on the first pass through
06176     * the group of tasks.  These are the handles of each task in the group of tasks
06177     * which are to be mapped.
06178     */  
06179    if(gs_smart_get_handle_list(&handle_list,&session_ids, &blocking_array, &nb_tasks)<0){   
06180       ERRPRINTF("SMART: Error getting handle list\n");
06181        smart_phase=GS_SMART_MAP_FAIL;
06182       return -1;
06183     }
06184     if((!handle_list) || (!session_ids) || (!blocking_array)) return -1;
06185 
06186     app_pm=(gs_smart_app_pm *)calloc(1, sizeof(gs_smart_app_pm));
06187     if(!app_pm){
06188       smart_phase=GS_SMART_MAP_FAIL;
06189       return -1;
06190     }
06191 
06192     /*
06193      * Generate the application performance model based on the stored
06194      * list of handles and blocking array. 
06195      */ 
06196 
06197     if(gs_smart_generate_app_pm(handle_list, blocking_array, nb_tasks, app_pm)<0){
06198       ERRPRINTF("SMART: Error building application performance model\n");
06199       smart_phase=GS_SMART_MAP_FAIL;
06200       return -1;
06201     }
06202 
06203     tg = (gs_smart_tg *)calloc(1,sizeof(gs_smart_tg)); 
06204     netpm=(gs_smart_netpm *)calloc(1, sizeof(gs_smart_netpm));
06205  
06206     if( (!tg) || (!netpm)){
06207       smart_phase=GS_SMART_MAP_FAIL;
06208       return -1;
06209     }
06210 
06211     /*
06212      * Send app_pm to agent. The agent then generates the task graph
06213      * based on the app_pm and the information in the idl files of each
06214      * task which is stored on the ageny. 
06215      *
06216      * The agent also sends back the a list of servers and the
06217      * network performance model is generated from this list of servers
06218      */ 
06219     if(gs_smart_generate_netpm_and_task_graph(app_pm,  tg, netpm,set_comm_type)){
06220       ERRPRINTF("SMART: Error generating task graph\n");
06221       smart_phase=GS_SMART_MAP_FAIL;
06222       return -1;
06223     }
06224  
06225     /* 
06226      * THESE FUNCTIONS ARE JUST TEMPORARY FOR DEMONSTRATION OF HOW
06227      * SMARTGRIDSOLVE EXTENSION WORKS 
06228      */
06229 /*
06230     if(gs_smart_net_pm_print_to_dotgraph(netpm, "smart_graphs/netpm.dot")<0){
06231       ERRPRINTF("SMART : Error printing network performance model dotgraph\n");
06232     }
06233    
06234     if(gs_smart_tg_print_to_dotgraph(tg, "smart_graphs/task_graph.dot")<0){
06235       ERRPRINTF("SMART : Error printing dotgraph\n ");
06236       return -1;
06237     }
06238     system("dot -Tjpg smart_graphs/task_graph.dot -o smart_graphs/task_graph.jpg");
06239     system("dot -Tjpg smart_graphs/netpm.dot -o smart_graphs/netpm.jpg");
06240      
06241 */
06242 
06243     if(gs_smart_get_mapper_type(&mapper_name)<0){
06244       ERRPRINTF("SMART: Error getting automatic mapper type\n");
06245       smart_phase=GS_SMART_MAP_FAIL;
06246       return -1;
06247     }
06248 
06249     /*
06250      * Call the mapping heuristic (mapper_name) specified by the application programmer.
06251      * The group of tasks is mapped based  on the task graph and network performance 
06252      * model.  This function generates a mapping solution 
06253      * (best_mg in gs_smart_mapping_solution.h) which will be used when
06254      * executing the group of tasks.
06255      */      
06256     if(gs_smart_map_common(mapper_name, tg, netpm, &total_nb_mapped_tasks)<0){
06257       ERRPRINTF("SMART: Error doing automatic mapping");
06258       smart_phase=GS_SMART_MAP_FAIL;
06259       return -1;
06260     }
06261 
06262     smart_phase=GS_SMART_EXEC_CALLED_HANDLES;
06263     current_pass=1;
06264     return 1;
06265   }
06266 
06267   /*
06268    * The third time  gs_smart_map is called 
06269    * we reset the current pass variable and set
06270    * the smart_phase to GS_SMART_STANDARD_EXEC so that each of the called handles
06271    * is executed in standard GridSolve.
06272    * And then we exit out of the scope of the group of tasks which is done by returning 0;
06273    */ 
06274   else if((current_pass==1) && (smart_phase==GS_SMART_EXEC_CALLED_HANDLES)){
06275     current_pass=0;
06276     smart_phase=GS_SMART_STANDARD_EXEC;
06277 
06278     if(app_pm){
06279       if(gs_smart_app_pm_free(app_pm)<0){
06280         ERRPRINTF("SMART : Error freeing application performance model\n");
06281         smart_phase=GS_SMART_MAP_FAIL;
06282         return -1;
06283       }
06284     }
06285     if(tg){
06286       if(gs_smart_tg_free(tg)<0){
06287         ERRPRINTF("SMART : Error freeing task graph\n");
06288         smart_phase=GS_SMART_MAP_FAIL;
06289         return -1;
06290       }
06291     }
06292      if(netpm){
06293       if(gs_smart_netpm_free(netpm)<0){
06294         ERRPRINTF("SMART : Error freeing network performance model\n");
06295         smart_phase=GS_SMART_MAP_FAIL;
06296         return -1;
06297       }
06298 
06299     }
06300     return 0;
06301   } 
06302 return 0;
06303 
06304 #else
06305  
06306  if(current_pass==0){
06307     printf("SMART: Unable to map tasks as GRIDSOLVE was not configured with the SMARTGRIDSOLVE extension\n");
06308     printf("SMART: The application will execute normally\n");
06309     current_pass++;
06310     return 1;
06311   }
06312   if(current_pass==1){
06313     current_pass=0;
06314     return 0;
06315   }
06316 #endif
06317  return 0;
06318 }
06319 
06320 /*
06321  * The macro in gs_smart_clib.h wraps a while loop around 
06322  * this function. Therefore  this means the function 
06323  * gs_smart_map_two cycles function and each
06324  * call in the scope of the parenthis is called twice.
06325  * The parameter "enable_remote_comm" is passed so
06326  * that a mapping solution may outline both client
06327  * and server broadcast communication, as well as 
06328  * standard client server communication.
06329  * 
06330  */
06331 
06332 int gs_smart_map_X(char * mapper_name) {
06333 
06334 #ifdef GS_SMART_GRIDSOLVE
06335   if(smart_phase==GS_SMART_EXEC_TASK_FAIL){
06336     current_pass=0;
06337     smart_phase=GS_SMART_STANDARD_EXEC;
06338   }
06339 #endif
06340   return gs_smart_map_two_cycles(mapper_name, "enable_remote_comm"); 
06341 }
06342 
06343 /*
06344  * The macro in gs_smart_clib.h wraps a while loop around 
06345  * this function. Therefore  this means the function 
06346  * gs_smart_map_two_cycles function and each
06347  * call in the scope of the parenthis is called twice.
06348  * The parameter "disable_remote_comm" is passed so
06349  * that a mapping solution may only outline  client
06350  *  broadcast communication and  
06351  * standard client server communication.
06352  */
06353 
06354 int gs_smart_map_ft_X(char * mapper_name){
06355   return gs_smart_map_two_cycles(mapper_name, "disable_remote_comm"); 
06356 }
06357 
06375 int grpc_local_X(){
06376 
06377 
06378 #ifdef GS_SMART_GRIDSOLVE
06379   if(smart_phase==GS_SMART_STANDARD_EXEC){
06380     return 1;
06381   }
06382   else if(smart_phase==GS_SMART_EXEC_TASK_FAIL){
06383     return 0;
06384   }
06385   else if(smart_phase==GS_SMART_MAP_FAIL){
06386     return 0;
06387   }
06388   else if(smart_phase==GS_SMART_TASK_DISCOVERY){
06389     return 0;
06390   }
06391   else if(smart_phase==GS_SMART_MAPPING){
06392    return 0; 
06393   }
06394   else if(smart_phase==GS_SMART_EXEC_CALLED_HANDLES){
06395     return 1;
06396   }
06397 #else
06398   return 1;
06399 #endif
06400   return 1;
06401 }
06402 
06403 
06404 
06405 
06406 #ifdef GS_SMART_GRIDSOLVE
06407 
06425 int gs_smart_get_current_phase(int * cur_phase){
06426   *cur_phase=smart_phase;
06427   return 0;
06428 }
06429 
06430 #endif