static pmix_status_t mylog(const pmix_proc_t *source, const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { size_t n; pmix_status_t rc; pmix_byte_object_t bo; pmix_iof_flags_t flags= {0}; /* if there is no data, then we don't handle it */ if (NULL == data || 0 == ndata) { return PMIX_ERR_NOT_AVAILABLE; } /* if we are not a gateway, then we don't handle this */ if (!PMIX_PROC_IS_GATEWAY(pmix_globals.mypeer)) { return PMIX_ERR_TAKE_NEXT_OPTION; } /* check to see if there are any relevant directives */ for (n=0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_LOG_TIMESTAMP, PMIX_MAX_KEYLEN)) { flags.timestamp = data[n].value.data.time; } else if (0 == strncmp(directives[n].key, PMIX_LOG_XML_OUTPUT, PMIX_MAX_KEYLEN)) { flags.xml = PMIX_INFO_TRUE(&directives[n]); } else if (0 == strncmp(directives[n].key, PMIX_LOG_TAG_OUTPUT, PMIX_MAX_KEYLEN)) { flags.tag = PMIX_INFO_TRUE(&directives[n]); } } /* check to see if there are any stdfd entries */ rc = PMIX_ERR_TAKE_NEXT_OPTION; for (n=0; n < ndata; n++) { if (0 == strncmp(data[n].key, PMIX_LOG_STDERR, PMIX_MAX_KEYLEN)) { bo.bytes = data[n].value.data.string; bo.size = strlen(bo.bytes); pmix_iof_write_output(source, PMIX_FWD_STDERR_CHANNEL, &bo, &flags); /* flag that we did this one */ PMIX_INFO_OP_COMPLETED(&data[n]); rc = PMIX_SUCCESS; } else if (0 == strncmp(data[n].key, PMIX_LOG_STDOUT, PMIX_MAX_KEYLEN)) { bo.bytes = data[n].value.data.string; bo.size = strlen(bo.bytes); pmix_iof_write_output(source, PMIX_FWD_STDOUT_CHANNEL, &bo, &flags); /* flag that we did this one */ PMIX_INFO_OP_COMPLETED(&data[n]); rc = PMIX_SUCCESS; } } return rc; }
static pmix_status_t connect_to_peer(struct pmix_peer_t *peer, pmix_info_t *info, size_t ninfo) { char *evar, **uri, *suri; char *filename, *nspace=NULL; pmix_rank_t rank = PMIX_RANK_WILDCARD; char *p, *p2; int sd, rc; size_t n; char myhost[PMIX_MAXHOSTNAMELEN]; bool system_level = false; bool system_level_only = false; pid_t pid = 0; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp: connecting to server"); /* see if the connection info is in the info array - if * so, then that overrides all other options */ /* if I am a client, then we need to look for the appropriate * connection info in the environment */ if (PMIX_PROC_IS_CLIENT(pmix_globals.mypeer)) { if (NULL != (evar = getenv("PMIX_SERVER_URI21"))) { /* we are talking to a v2.1 server */ pmix_client_globals.myserver->proc_type = PMIX_PROC_SERVER | PMIX_PROC_V21; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "V21 SERVER DETECTED"); /* must use the v21 bfrops module */ pmix_globals.mypeer->nptr->compat.bfrops = pmix_bfrops_base_assign_module("v21"); if (NULL == pmix_globals.mypeer->nptr->compat.bfrops) { return PMIX_ERR_INIT; } } else if (NULL != (evar = getenv("PMIX_SERVER_URI2"))) { /* we are talking to a v2.0 server */ pmix_client_globals.myserver->proc_type = PMIX_PROC_SERVER | PMIX_PROC_V20; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "V20 SERVER DETECTED"); /* must use the v20 bfrops module */ pmix_globals.mypeer->nptr->compat.bfrops = pmix_bfrops_base_assign_module("v20"); if (NULL == pmix_globals.mypeer->nptr->compat.bfrops) { return PMIX_ERR_INIT; } } else { /* not us */ return PMIX_ERR_NOT_SUPPORTED; } /* the server will be using the same bfrops as us */ pmix_client_globals.myserver->nptr->compat.bfrops = pmix_globals.mypeer->nptr->compat.bfrops; /* mark that we are using the V2 protocol */ pmix_globals.mypeer->protocol = PMIX_PROTOCOL_V2; /* the URI consists of the following elements: * - server nspace.rank * - ptl rendezvous URI */ uri = pmix_argv_split(evar, ';'); if (2 != pmix_argv_count(uri)) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); pmix_argv_free(uri); return PMIX_ERR_NOT_SUPPORTED; } /* set the server nspace */ p = uri[0]; if (NULL == (p2 = strchr(p, '.'))) { PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM); pmix_argv_free(uri); return PMIX_ERR_NOT_SUPPORTED; } *p2 = '\0'; ++p2; nspace = strdup(p); rank = strtoull(p2, NULL, 10); /* save the URI, but do not overwrite what we may have received from * the info-key directives */ if (NULL == mca_ptl_tcp_component.super.uri) { mca_ptl_tcp_component.super.uri = strdup(uri[1]); } pmix_argv_free(uri); pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:client attempt connect to %s", mca_ptl_tcp_component.super.uri); /* go ahead and try to connect */ if (PMIX_SUCCESS != (rc = try_connect(&sd))) { free(nspace); return rc; } goto complete; } /* get here if we are a tool - check any provided directives * to see where they want us to connect to */ if (NULL != info) { for (n=0; n < ninfo; n++) { if (0 == strcmp(info[n].key, PMIX_CONNECT_TO_SYSTEM)) { system_level_only = PMIX_INFO_TRUE(&info[n]); } else if (0 == strcmp(info[n].key, PMIX_CONNECT_SYSTEM_FIRST)) { /* try the system-level */ system_level = PMIX_INFO_TRUE(&info[n]); } else if (0 == strcmp(info[n].key, PMIX_SERVER_PIDINFO)) { pid = info[n].value.data.pid; } else if (0 == strcmp(info[n].key, PMIX_SERVER_URI)) { if (NULL == mca_ptl_tcp_component.super.uri) { free(mca_ptl_tcp_component.super.uri); } mca_ptl_tcp_component.super.uri = strdup(info[n].value.data.string); } else if (0 == strcmp(info[n].key, PMIX_CONNECT_RETRY_DELAY)) { mca_ptl_tcp_component.wait_to_connect = info[n].value.data.uint32; } else if (0 == strcmp(info[n].key, PMIX_CONNECT_MAX_RETRIES)) { mca_ptl_tcp_component.max_retries = info[n].value.data.uint32; } } } /* mark that we are using the V2 protocol */ pmix_globals.mypeer->protocol = PMIX_PROTOCOL_V2; gethostname(myhost, sizeof(myhost)); /* if we were given a URI via MCA param, then look no further */ if (NULL != mca_ptl_tcp_component.super.uri) { /* if the string starts with "file:", then they are pointing * us to a file we need to read to get the URI itself */ if (0 == strncmp(mca_ptl_tcp_component.super.uri, "file:", 5)) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:tool getting connection info from %s", mca_ptl_tcp_component.super.uri); nspace = NULL; rc = parse_uri_file(&mca_ptl_tcp_component.super.uri[5], &suri, &nspace, &rank); if (PMIX_SUCCESS != rc) { return PMIX_ERR_UNREACH; } free(mca_ptl_tcp_component.super.uri); mca_ptl_tcp_component.super.uri = suri; } else { /* we need to extract the nspace/rank of the server from the string */ p = strchr(mca_ptl_tcp_component.super.uri, ';'); if (NULL == p) { return PMIX_ERR_BAD_PARAM; } *p = '\0'; p++; suri = strdup(p); // save the uri portion /* the '.' in the first part of the original string separates * nspace from rank */ p = strchr(mca_ptl_tcp_component.super.uri, '.'); if (NULL == p) { free(suri); return PMIX_ERR_BAD_PARAM; } *p = '\0'; p++; nspace = strdup(mca_ptl_tcp_component.super.uri); rank = strtoull(p, NULL, 10); /* now update the URI */ free(mca_ptl_tcp_component.super.uri); mca_ptl_tcp_component.super.uri = suri; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:tool attempt connect using given URI %s", mca_ptl_tcp_component.super.uri); /* go ahead and try to connect */ if (PMIX_SUCCESS != (rc = try_connect(&sd))) { if (NULL != nspace) { free(nspace); } return rc; } goto complete; } /* if they gave us a pid, then look for it */ if (0 != pid) { if (0 > asprintf(&filename, "pmix.%s.tool.%d", myhost, pid)) { return PMIX_ERR_NOMEM; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:tool searching for given session server %s", filename); nspace = NULL; rc = df_search(mca_ptl_tcp_component.system_tmpdir, filename, &sd, &nspace, &rank); free(filename); if (PMIX_SUCCESS == rc) { goto complete; } if (NULL != nspace) { free(nspace); } /* since they gave us a specific pid and we couldn't * connect to it, return an error */ return PMIX_ERR_UNREACH; } /* if they asked for system-level, we start there */ if (system_level || system_level_only) { if (0 > asprintf(&filename, "%s/pmix.sys.%s", mca_ptl_tcp_component.system_tmpdir, myhost)) { return PMIX_ERR_NOMEM; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:tool looking for system server at %s", filename); /* try to read the file */ rc = parse_uri_file(filename, &suri, &nspace, &rank); free(filename); if (PMIX_SUCCESS == rc) { mca_ptl_tcp_component.super.uri = suri; pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:tool attempt connect to system server at %s", mca_ptl_tcp_component.super.uri); /* go ahead and try to connect */ if (PMIX_SUCCESS == try_connect(&sd)) { goto complete; } free(nspace); } } /* we get here if they either didn't ask for a system-level connection, * or they asked for it and it didn't succeed. If they _only_ wanted * a system-level connection, then we are done */ if (system_level_only) { pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp: connecting to system failed"); return PMIX_ERR_UNREACH; } /* they didn't give us a pid, so we will search to see what session-level * tools are available to this user. We will take the first connection * that succeeds - this is based on the likelihood that there is only * one session per user on a node */ if (0 > asprintf(&filename, "pmix.%s.tool", myhost)) { return PMIX_ERR_NOMEM; } pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "ptl:tcp:tool searching for session server %s", filename); nspace = NULL; rc = df_search(mca_ptl_tcp_component.system_tmpdir, filename, &sd, &nspace, &rank); free(filename); if (PMIX_SUCCESS != rc) { if (NULL != nspace){ free(nspace); } return PMIX_ERR_UNREACH; } complete: pmix_output_verbose(2, pmix_ptl_base_framework.framework_output, "sock_peer_try_connect: Connection across to server succeeded"); /* do a final bozo check */ if (NULL == nspace || PMIX_RANK_WILDCARD == rank) { if (NULL != nspace) { free(nspace); } CLOSE_THE_SOCKET(sd); return PMIX_ERR_UNREACH; } /* mark the connection as made */ pmix_globals.connected = true; pmix_client_globals.myserver->sd = sd; /* setup the server info */ if (NULL == pmix_client_globals.myserver->info) { pmix_client_globals.myserver->info = PMIX_NEW(pmix_rank_info_t); } if (NULL == pmix_client_globals.myserver->nptr) { pmix_client_globals.myserver->nptr = PMIX_NEW(pmix_nspace_t); } if (NULL == pmix_client_globals.myserver->nptr->nspace) { pmix_client_globals.myserver->nptr->nspace = nspace; } else { free(nspace); } if (NULL == pmix_client_globals.myserver->info->pname.nspace) { pmix_client_globals.myserver->info->pname.nspace = strdup(pmix_client_globals.myserver->nptr->nspace); } pmix_client_globals.myserver->info->pname.rank = rank; pmix_ptl_base_set_nonblocking(sd); /* setup recv event */ pmix_event_assign(&pmix_client_globals.myserver->recv_event, pmix_globals.evbase, pmix_client_globals.myserver->sd, EV_READ | EV_PERSIST, pmix_ptl_base_recv_handler, pmix_client_globals.myserver); pmix_client_globals.myserver->recv_ev_active = true; PMIX_POST_OBJECT(pmix_client_globals.myserver); pmix_event_add(&pmix_client_globals.myserver->recv_event, 0); /* setup send event */ pmix_event_assign(&pmix_client_globals.myserver->send_event, pmix_globals.evbase, pmix_client_globals.myserver->sd, EV_WRITE|EV_PERSIST, pmix_ptl_base_send_handler, pmix_client_globals.myserver); pmix_client_globals.myserver->send_ev_active = false; return PMIX_SUCCESS; }
PMIX_EXPORT pmix_status_t PMIx_Log_nb(const pmix_info_t data[], size_t ndata, const pmix_info_t directives[], size_t ndirs, pmix_op_cbfunc_t cbfunc, void *cbdata) { pmix_shift_caddy_t *cd; pmix_cmd_t cmd = PMIX_LOG_CMD; pmix_buffer_t *msg; pmix_status_t rc; size_t n; time_t timestamp = 0; pmix_proc_t *source = NULL; PMIX_ACQUIRE_THREAD(&pmix_global_lock); pmix_output_verbose(2, pmix_globals.debug_output, "pmix:log non-blocking"); if (pmix_globals.init_cntr <= 0) { PMIX_RELEASE_THREAD(&pmix_global_lock); return PMIX_ERR_INIT; } if (0 == ndata || NULL == data) { PMIX_RELEASE_THREAD(&pmix_global_lock); return PMIX_ERR_BAD_PARAM; } /* check the directives - if they requested a timestamp, then * get the time, also look for a source */ if (NULL != directives) { for (n=0; n < ndirs; n++) { if (0 == strncmp(directives[n].key, PMIX_LOG_GENERATE_TIMESTAMP, PMIX_MAX_KEYLEN)) { if (PMIX_INFO_TRUE(&directives[n])) { /* pickup the timestamp */ timestamp = time(NULL); } } else if (0 == strncmp(directives[n].key, PMIX_LOG_SOURCE, PMIX_MAX_KEYLEN)) { source = directives[n].value.data.proc; } } } /* if we are a client or tool, we never do this ourselves - we * always pass this request to our server for execution */ if (!PMIX_PROC_IS_SERVER(pmix_globals.mypeer) && !PMIX_PROC_IS_LAUNCHER(pmix_globals.mypeer)) { /* if we aren't connected, don't attempt to send */ if (!pmix_globals.connected) { PMIX_RELEASE_THREAD(&pmix_global_lock); return PMIX_ERR_UNREACH; } PMIX_RELEASE_THREAD(&pmix_global_lock); /* if we are not a server, then relay this request to the server */ cd = PMIX_NEW(pmix_shift_caddy_t); cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; msg = PMIX_NEW(pmix_buffer_t); PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } /* provide the timestamp - zero will indicate * that it wasn't taken */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, ×tamp, 1, PMIX_TIME); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } /* pack the number of data entries */ PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndata, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } if (0 < ndata) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, data, ndata, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } } PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ndirs, 1, PMIX_SIZE); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } if (0 < ndirs) { PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, directives, ndirs, PMIX_INFO); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(msg); PMIX_RELEASE(cd); return rc; } } pmix_output_verbose(2, pmix_plog_base_framework.framework_output, "pmix:log sending to server"); PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, log_cbfunc, (void*)cd); if (PMIX_SUCCESS != rc) { PMIX_ERROR_LOG(rc); PMIX_RELEASE(cd); } return rc; } PMIX_RELEASE_THREAD(&pmix_global_lock); /* if no recorded source was found, then we must be it */ if (NULL == source) { source = &pmix_globals.myid; cd = PMIX_NEW(pmix_shift_caddy_t); cd->cbfunc.opcbfn = cbfunc; cd->cbdata = cbdata; cd->ndirs = ndirs + 1; PMIX_INFO_CREATE(cd->directives, cd->ndirs); for (n=0; n < ndirs; n++) { PMIX_INFO_XFER(&cd->directives[n], (pmix_info_t*)&directives[n]); } PMIX_INFO_LOAD(&cd->directives[ndirs], PMIX_LOG_SOURCE, &source, PMIX_PROC); /* call down to process the request - the various components * will thread shift as required */ rc = pmix_plog.log(source, data, ndata, cd->directives, cd->ndirs, localcbfunc, cd); if (PMIX_SUCCESS != rc) { PMIX_INFO_FREE(cd->directives, cd->ndirs); PMIX_RELEASE(cd); } } else if (0 == strncmp(source->nspace, pmix_globals.myid.nspace, PMIX_MAX_NSLEN) && source->rank == pmix_globals.myid.rank) { /* if I am the recorded source, then this is a re-submission of * something that got "upcalled" by a prior call. In this case, * we return a "not supported" error as clearly we couldn't * handle it, and neither could our host */ rc = PMIX_ERR_NOT_SUPPORTED; } else { /* call down to process the request - the various components * will thread shift as required */ rc = pmix_plog.log(source, data, ndata, directives, ndirs, cbfunc, cbdata); } return rc; }