#include "src/include/pmix_config.h"
#include "src/include/pmix_socket_errno.h"
#include "src/include/pmix_stdint.h"
#include "include/pmix_server.h"
#include "src/include/pmix_globals.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <fcntl.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_UN_H
# include <sys/un.h>
#endif
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_TIME_H
# include <time.h>
#endif
#include <event.h>
#ifndef MAX
# define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#include "src/class/pmix_hotel.h"
#include "src/class/pmix_list.h"
#include "src/common/pmix_attributes.h"
#include "src/common/pmix_iof.h"
#include "src/hwloc/pmix_hwloc.h"
#include "src/mca/bfrops/base/base.h"
#include "src/mca/gds/base/base.h"
#include "src/mca/plog/plog.h"
#include "src/mca/pnet/pnet.h"
#include "src/mca/psensor/psensor.h"
#include "src/mca/ptl/base/base.h"
#include "src/util/pmix_argv.h"
#include "src/util/pmix_error.h"
#include "src/util/pmix_name_fns.h"
#include "src/util/pmix_output.h"
#include "src/util/pmix_environ.h"
#include "src/client/pmix_client_ops.h"
#include "src/server/pmix_server_ops.h"
pmix_status_t pmix_server_resolve_peers(pmix_server_caddy_t *cd,
pmix_buffer_t *buf,
pmix_info_cbfunc_t cbfunc)
{
int32_t cnt;
pmix_status_t rc;
char *nodename = NULL;
char *nd, *str;
pmix_info_t *iptr;
cnt = 1;
PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &nodename, &cnt, PMIX_STRING);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
if (NULL == nodename) {
nd = pmix_globals.hostname;
} else {
nd = nodename;
}
cnt = 1;
PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &str, &cnt, PMIX_STRING);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
if (NULL != nodename) {
free(nodename);
}
return rc;
}
PMIX_QUERY_CREATE(cd->query, 1);
PMIX_ARGV_APPEND(rc, cd->query->keys, PMIX_QUERY_RESOLVE_PEERS);
PMIX_INFO_CREATE(iptr, 2);
PMIX_INFO_LOAD(&iptr[0], PMIX_NSPACE, str, PMIX_STRING);
if (NULL != str) {
free(str);
}
PMIX_INFO_SET_QUALIFIER(&iptr[0]);
PMIX_INFO_LOAD(&iptr[1], PMIX_HOSTNAME, nd, PMIX_STRING);
if (NULL != nodename) {
free(nodename);
}
PMIX_INFO_SET_QUALIFIER(&iptr[1]);
cd->query->qualifiers = iptr;
cd->query->nqual = 2;
if (NULL != pmix_host_server.query) {
rc = pmix_host_server.query(&pmix_globals.myid,
cd->query, 1,
cbfunc, (void*)cd);
if (PMIX_SUCCESS == rc) {
return PMIX_SUCCESS;
}
}
PMIX_THREADSHIFT(cd, pmix_server_locally_resolve_peers);
return PMIX_SUCCESS;
}
void pmix_server_locally_resolve_peers(int sd, short args, void *cbdata)
{
pmix_server_caddy_t *cd = (pmix_server_caddy_t*)cbdata;
pmix_cb_t cb;
pmix_status_t rc, ret=PMIX_SUCCESS;
pmix_info_t info[3];
pmix_proc_t proc;
pmix_kval_t *kv;
char **p, **tmp = NULL, *prs;
char *nspace, *nd;
pmix_proc_t *pa = NULL;
size_t m, n, np = 0, ninfo = 3;
pmix_namespace_t *ns;
pmix_buffer_t *reply;
PMIX_HIDE_UNUSED_PARAMS(sd, args);
for (n=0; n < ninfo; n++) {
PMIX_INFO_CONSTRUCT(&info[n]);
}
nspace = cd->query->qualifiers[0].value.data.string;
nd = cd->query->qualifiers[1].value.data.string;
PMIX_CONSTRUCT(&cb, pmix_cb_t);
proc.rank = PMIX_RANK_UNDEF;
cb.proc = &proc;
cb.key = PMIX_LOCAL_PEERS;
cb.scope = PMIX_INTERNAL;
cb.info = info;
cb.ninfo = ninfo;
PMIX_INFO_LOAD(&info[0], PMIX_OPTIONAL, NULL, PMIX_BOOL);
PMIX_INFO_LOAD(&info[1], PMIX_NODE_INFO, NULL, PMIX_BOOL);
PMIX_INFO_LOAD(&info[2], PMIX_HOSTNAME, nd, PMIX_STRING);
if (0 == pmix_nslen(nspace)) {
rc = PMIX_ERR_DATA_VALUE_NOT_FOUND;
np = 0;
PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) {
PMIX_LOAD_NSPACE(proc.nspace, ns->nspace);
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb);
if (PMIX_SUCCESS != rc) {
if (PMIX_RANK_UNDEF == proc.rank) {
proc.rank = PMIX_RANK_WILDCARD;
PMIX_GDS_FETCH_KV(rc, pmix_globals.mypeer, &cb);
if (PMIX_SUCCESS != rc) {
continue;
}
} else {
continue;
}
}
if (0 == pmix_list_get_size(&cb.kvs)) {
continue;
}
kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs);
if (PMIX_STRING != kv->value->type) {
PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL);
PMIX_LIST_DESTRUCT(&cb.kvs);
PMIX_CONSTRUCT(&cb.kvs, pmix_list_t);
continue;
}
if (NULL == kv->value->data.string) {
PMIX_LIST_DESTRUCT(&cb.kvs);
PMIX_CONSTRUCT(&cb.kvs, pmix_list_t);
continue;
}
if (0 > asprintf(&prs, "%s:%s", ns->nspace, kv->value->data.string)) {
PMIX_LIST_DESTRUCT(&cb.kvs);
PMIX_CONSTRUCT(&cb.kvs, pmix_list_t);
continue;
}
PMIx_Argv_append_nosize(&tmp, prs);
p = PMIx_Argv_split(kv->value->data.string, ',');
np += PMIx_Argv_count(p);
PMIx_Argv_free(p);
free(prs);
PMIX_LIST_DESTRUCT(&cb.kvs);
PMIX_CONSTRUCT(&cb.kvs, pmix_list_t);
}
if (0 < np) {
PMIX_PROC_CREATE(pa, np);
if (NULL == pa) {
ret = PMIX_ERR_NOMEM;
PMIx_Argv_free(tmp);
np = 0;
PMIX_DESTRUCT(&cb);
goto done;
}
np = 0;
for (n = 0; NULL != tmp[n]; n++) {
prs = strchr(tmp[n], ':');
if (NULL == prs) {
ret = PMIX_ERR_BAD_PARAM;
PMIx_Argv_free(tmp);
PMIX_PROC_FREE(pa, np);
pa = NULL;
np = 0;
PMIX_DESTRUCT(&cb);
goto done;
}
*prs = '\0';
++prs;
p = PMIx_Argv_split(prs, ',');
for (m = 0; NULL != p[m]; m++) {
PMIX_LOAD_NSPACE(pa[np].nspace, tmp[n]);
pa[np].rank = strtoul(p[m], NULL, 10);
++np;
}
PMIx_Argv_free(p);
}
PMIx_Argv_free(tmp);
ret = PMIX_SUCCESS;
}
PMIX_DESTRUCT(&cb);
goto done;
}
PMIX_LOAD_PROCID(&proc, nspace, PMIX_RANK_UNDEF);
PMIX_GDS_FETCH_KV(ret, pmix_globals.mypeer, &cb);
if (PMIX_SUCCESS == ret) {
goto process;
}
if (PMIX_ERR_INVALID_NAMESPACE == ret) {
PMIX_DESTRUCT(&cb);
goto done;
}
if (PMIX_ERR_NOT_FOUND == ret) {
ret = PMIX_SUCCESS;
PMIX_DESTRUCT(&cb);
goto done;
}
if (PMIX_ERR_DATA_VALUE_NOT_FOUND == ret) {
PMIX_DESTRUCT(&cb);
goto done;
}
if (PMIX_RANK_UNDEF == proc.rank) {
proc.rank = PMIX_RANK_WILDCARD;
PMIX_GDS_FETCH_KV(ret, pmix_globals.mypeer, &cb);
if (PMIX_SUCCESS == ret) {
goto process;
}
if (PMIX_ERR_NOT_FOUND == ret) {
ret = PMIX_SUCCESS;
}
PMIX_DESTRUCT(&cb);
goto done;
}
process:
if (0 == pmix_list_get_size(&cb.kvs)) {
ret = PMIX_ERR_INVALID_VAL;
PMIX_DESTRUCT(&cb);
goto done;
}
kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs);
if (PMIX_STRING != kv->value->type || NULL == kv->value->data.string) {
ret = PMIX_ERR_INVALID_VAL;
PMIX_DESTRUCT(&cb);
goto done;
}
p = PMIx_Argv_split(kv->value->data.string, ',');
np = PMIx_Argv_count(p);
PMIX_PROC_CREATE(pa, np);
if (NULL == pa) {
ret = PMIX_ERR_NOMEM;
PMIx_Argv_free(p);
PMIX_DESTRUCT(&cb);
goto done;
}
for (n = 0; n < np; n++) {
PMIX_LOAD_NSPACE(pa[n].nspace, nspace);
pa[n].rank = strtoul(p[n], NULL, 10);
}
PMIx_Argv_free(p);
ret = PMIX_SUCCESS;
PMIX_DESTRUCT(&cb);
done:
for (n=0; n < ninfo; n++) {
PMIX_INFO_DESTRUCT(&info[n]);
}
reply = PMIX_NEW(pmix_buffer_t);
if (NULL == reply) {
PMIX_ERROR_LOG(PMIX_ERR_NOMEM);
PMIX_RELEASE(cd);
return;
}
PMIX_BFROPS_PACK(rc, cd->peer, reply, &ret, 1, PMIX_STATUS);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
if (PMIX_SUCCESS == ret) {
PMIX_BFROPS_PACK(rc, cd->peer, reply, &np, 1, PMIX_SIZE);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
if (0 < np) {
PMIX_BFROPS_PACK(rc, cd->peer, reply, pa, np, PMIX_PROC);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
}
}
complete:
PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply);
if (PMIX_SUCCESS != rc) {
PMIX_RELEASE(reply);
}
PMIX_RELEASE(cd);
if (NULL != pa) {
PMIX_PROC_FREE(pa, np);
}
}
pmix_status_t pmix_server_resolve_node(pmix_server_caddy_t *cd,
pmix_buffer_t *buf,
pmix_info_cbfunc_t cbfunc)
{
int32_t cnt;
pmix_status_t rc;
pmix_info_t *iptr;
char *str;
cnt = 1;
PMIX_BFROPS_UNPACK(rc, cd->peer, buf, &str, &cnt, PMIX_STRING);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
return rc;
}
PMIX_QUERY_CREATE(cd->query, 1);
PMIX_ARGV_APPEND(rc, cd->query->keys, PMIX_QUERY_RESOLVE_NODE);
PMIX_INFO_CREATE(iptr, 1);
PMIX_INFO_LOAD(&iptr[0], PMIX_NSPACE, str, PMIX_STRING);
if (NULL != str) {
free(str);
}
PMIX_INFO_SET_QUALIFIER(&iptr[0]);
cd->query->qualifiers = iptr;
cd->query->nqual = 1;
if (NULL != pmix_host_server.query) {
rc = pmix_host_server.query(&pmix_globals.myid,
cd->query, 1,
cbfunc, (void*)cd);
if (PMIX_SUCCESS == rc) {
return PMIX_SUCCESS;
}
}
PMIX_THREADSHIFT(cd, pmix_server_locally_resolve_node);
return PMIX_SUCCESS;
}
void pmix_server_locally_resolve_node(int sd, short args, void *cbdata)
{
pmix_server_caddy_t *cd = (pmix_server_caddy_t*)cbdata;
pmix_cb_t cb;
pmix_status_t rc, ret = PMIX_SUCCESS;
pmix_nspace_t nspace;
pmix_info_t info;
pmix_proc_t proc;
pmix_kval_t *kv;
pmix_value_t *val;
char **p, **tmp = NULL, *nodelist = NULL;
pmix_namespace_t *ns;
size_t n;
pmix_buffer_t *reply;
PMIX_HIDE_UNUSED_PARAMS(sd, args);
PMIX_INFO_LOAD(&info, PMIX_OPTIONAL, NULL, PMIX_BOOL);
PMIX_CONSTRUCT(&cb, pmix_cb_t);
proc.rank = PMIX_RANK_WILDCARD;
cb.proc = &proc;
cb.key = PMIX_NODE_LIST;
cb.scope = PMIX_INTERNAL;
cb.info = &info;
cb.ninfo = 1;
if (0 == pmix_nslen(nspace)) {
PMIX_LIST_FOREACH (ns, &pmix_globals.nspaces, pmix_namespace_t) {
PMIX_LOAD_NSPACE(proc.nspace, ns->nspace);
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb);
if (PMIX_SUCCESS != rc) {
continue;
}
if (0 == pmix_list_get_size(&cb.kvs)) {
continue;
}
kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs);
val = kv->value;
if (PMIX_STRING != val->type) {
PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL);
PMIX_LIST_DESTRUCT(&cb.kvs);
PMIX_CONSTRUCT(&cb.kvs, pmix_list_t);
continue;
}
if (NULL == val->data.string) {
PMIX_LIST_DESTRUCT(&cb.kvs);
PMIX_CONSTRUCT(&cb.kvs, pmix_list_t);
continue;
}
p = PMIx_Argv_split(val->data.string, ',');
for (n = 0; NULL != p[n]; n++) {
PMIx_Argv_append_unique_nosize(&tmp, p[n]);
}
PMIx_Argv_free(p);
PMIX_LIST_DESTRUCT(&cb.kvs);
PMIX_CONSTRUCT(&cb.kvs, pmix_list_t);
}
if (0 < PMIx_Argv_count(tmp)) {
nodelist = PMIx_Argv_join(tmp, ',');
PMIx_Argv_free(tmp);
}
ret = PMIX_SUCCESS;
PMIX_DESTRUCT(&cb);
goto done;
}
PMIX_LOAD_NSPACE(proc.nspace, nspace);
PMIX_GDS_FETCH_KV(rc, pmix_client_globals.myserver, &cb);
if (PMIX_SUCCESS != rc) {
PMIX_DESTRUCT(&cb);
ret = rc;
goto done;
}
if (0 == pmix_list_get_size(&cb.kvs)) {
PMIX_DESTRUCT(&cb);
goto done;
}
kv = (pmix_kval_t*)pmix_list_get_first(&cb.kvs);
val = kv->value;
if (PMIX_STRING != val->type || NULL == val->data.string) {
PMIX_ERROR_LOG(PMIX_ERR_INVALID_VAL);
ret = PMIX_ERR_INVALID_VAL;
PMIX_DESTRUCT(&cb);
goto done;
}
nodelist = strdup(val->data.string);
PMIX_DESTRUCT(&cb);
done:
reply = PMIX_NEW(pmix_buffer_t);
if (NULL == reply) {
PMIX_ERROR_LOG(PMIX_ERR_NOMEM);
PMIX_RELEASE(cd);
return;
}
PMIX_BFROPS_PACK(rc, cd->peer, reply, &ret, 1, PMIX_STATUS);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
if (PMIX_SUCCESS == ret) {
PMIX_BFROPS_PACK(rc, cd->peer, reply, &nodelist, 1, PMIX_STRING);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
}
complete:
PMIX_SERVER_QUEUE_REPLY(rc, cd->peer, cd->hdr.tag, reply);
if (PMIX_SUCCESS != rc) {
PMIX_RELEASE(reply);
}
if (NULL != nodelist) {
free(nodelist);
}
PMIX_RELEASE(cd);
}