root/opal/mca/pmix/base/pmix_base_fns.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. opal_pmix_base_set_evbase
  2. opal_pmix_base_register_handler
  3. opal_pmix_base_evhandler
  4. opal_pmix_base_deregister_handler
  5. opal_pmix_base_notify_event
  6. opal_pmix_base_exchange
  7. opal_pmix_base_store_encoded
  8. opal_pmix_base_commit_packed
  9. opal_pmix_base_partial_commit_packed
  10. opal_pmix_base_get_packed
  11. opal_pmix_base_cache_keys_locally
  12. setup_key
  13. pmi_base64_encsym
  14. pmi_base64_decsym
  15. pmi_base64_encode_block
  16. pmi_base64_decode_block
  17. pmi_encode
  18. pmi_decode

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2012-2015 Los Alamos National Security, LLC.  All rights
   4  *                         reserved.
   5  * Copyright (c) 2014-2018 Intel, Inc. All rights reserved.
   6  * Copyright (c) 2014-2017 Research Organization for Information Science
   7  *                         and Technology (RIST). All rights reserved.
   8  * Copyright (c) 2016      Mellanox Technologies, Inc.
   9  *                         All rights reserved.
  10  * Copyright (c) 2016      Cisco Systems, Inc.  All rights reserved.
  11  * $COPYRIGHT$
  12  *
  13  * Additional copyrights may follow
  14  *
  15  * $HEADER$
  16  *
  17  */
  18 
  19 #include "opal_config.h"
  20 #include "opal/constants.h"
  21 
  22 
  23 #include <regex.h>
  24 
  25 #include <time.h>
  26 #include <string.h>
  27 #ifdef HAVE_UNISTD_H
  28 #include <unistd.h>
  29 #endif
  30 
  31 #include "opal_stdint.h"
  32 #include "opal/class/opal_pointer_array.h"
  33 #include "opal/util/argv.h"
  34 #include "opal/util/output.h"
  35 #include "opal/util/proc.h"
  36 #include "opal/util/show_help.h"
  37 
  38 #include "opal/mca/pmix/base/base.h"
  39 #include "opal/mca/pmix/base/pmix_base_fns.h"
  40 #include "opal/mca/pmix/base/pmix_base_hash.h"
  41 
  42 #define OPAL_PMI_PAD  10
  43 
  44 void opal_pmix_base_set_evbase(opal_event_base_t *evbase)
  45 {
  46     opal_pmix_base.evbase = evbase;
  47 }
  48 
  49 /********     ERRHANDLER SUPPORT FOR COMPONENTS THAT
  50  ********     DO NOT NATIVELY SUPPORT IT
  51  ********/
  52 static opal_pmix_notification_fn_t evhandler = NULL;
  53 
  54 void opal_pmix_base_register_handler(opal_list_t *event_codes,
  55                                      opal_list_t *info,
  56                                      opal_pmix_notification_fn_t err,
  57                                      opal_pmix_evhandler_reg_cbfunc_t cbfunc,
  58                                      void *cbdata)
  59 {
  60     evhandler = err;
  61     if (NULL != cbfunc) {
  62         cbfunc(OPAL_SUCCESS, 0, cbdata);
  63     }
  64 }
  65 
  66 void opal_pmix_base_evhandler(int status,
  67                               const opal_process_name_t *source,
  68                               opal_list_t *info, opal_list_t *results,
  69                               opal_pmix_notification_complete_fn_t cbfunc, void *cbdata)
  70 {
  71     if (NULL != evhandler) {
  72         evhandler(status, source, info, results, cbfunc, cbdata);
  73     }
  74 }
  75 
  76 void opal_pmix_base_deregister_handler(size_t errid,
  77                                        opal_pmix_op_cbfunc_t cbfunc,
  78                                        void *cbdata)
  79 {
  80     evhandler = NULL;
  81     if (NULL != cbfunc) {
  82         cbfunc(OPAL_SUCCESS, cbdata);
  83     }
  84 }
  85 
  86 int opal_pmix_base_notify_event(int status,
  87                                 const opal_process_name_t *source,
  88                                 opal_pmix_data_range_t range,
  89                                 opal_list_t *info,
  90                                 opal_pmix_op_cbfunc_t cbfunc, void *cbdata)
  91 {
  92     return OPAL_SUCCESS;
  93 }
  94 
  95 int opal_pmix_base_exchange(opal_value_t *indat,
  96                             opal_pmix_pdata_t *outdat,
  97                             int timeout)
  98 {
  99     int rc;
 100     opal_list_t ilist, mlist;
 101     opal_value_t *info;
 102     opal_pmix_pdata_t *pdat;
 103 
 104     /* protect the incoming value */
 105     opal_dss.copy((void**)&info, indat, OPAL_VALUE);
 106     OBJ_CONSTRUCT(&ilist, opal_list_t);
 107     opal_list_append(&ilist, &info->super);
 108     /* tell the server to delete upon read */
 109     info = OBJ_NEW(opal_value_t);
 110     info->key = strdup(OPAL_PMIX_PERSISTENCE);
 111     info->type = OPAL_PERSIST;
 112     info->data.integer = OPAL_PMIX_PERSIST_FIRST_READ;
 113     opal_list_append(&ilist, &info->super);
 114 
 115     /* publish it with "session" scope */
 116     rc = opal_pmix.publish(&ilist);
 117     OPAL_LIST_DESTRUCT(&ilist);
 118     if (OPAL_SUCCESS != rc) {
 119         return rc;
 120     }
 121 
 122     /* lookup the other side's info - if a non-blocking form
 123      * of lookup isn't available, then we use the blocking
 124      * form and trust that the underlying system will WAIT
 125      * until the other side publishes its data */
 126     pdat = OBJ_NEW(opal_pmix_pdata_t);
 127     pdat->value.key = strdup(outdat->value.key);
 128     pdat->value.type = outdat->value.type;
 129     /* setup the constraints */
 130     OBJ_CONSTRUCT(&mlist, opal_list_t);
 131     /* tell it to wait for the data to arrive */
 132     info = OBJ_NEW(opal_value_t);
 133     info->key = strdup(OPAL_PMIX_WAIT);
 134     info->type = OPAL_BOOL;
 135     info->data.flag = true;
 136     opal_list_append(&mlist, &info->super);
 137     /* pass along the given timeout as we don't know when
 138      * the other side will publish - it doesn't
 139      * have to be simultaneous */
 140     info = OBJ_NEW(opal_value_t);
 141     info->key = strdup(OPAL_PMIX_TIMEOUT);
 142     info->type = OPAL_INT;
 143     if (0 < opal_pmix_base.timeout) {
 144         /* the user has overridden the default */
 145         info->data.integer = opal_pmix_base.timeout;
 146     } else {
 147         info->data.integer = timeout;
 148     }
 149     opal_list_append(&mlist, &info->super);
 150 
 151     /* if a non-blocking version of lookup isn't
 152      * available, then use the blocking version */
 153     OBJ_CONSTRUCT(&ilist, opal_list_t);
 154     opal_list_append(&ilist, &pdat->super);
 155     rc = opal_pmix.lookup(&ilist, &mlist);
 156     OPAL_LIST_DESTRUCT(&mlist);
 157     if (OPAL_SUCCESS != rc) {
 158         OPAL_LIST_DESTRUCT(&ilist);
 159         return rc;
 160     }
 161 
 162     /* pass back the result */
 163     outdat->proc = pdat->proc;
 164     free(outdat->value.key);
 165     rc = opal_value_xfer(&outdat->value, &pdat->value);
 166     OPAL_LIST_DESTRUCT(&ilist);
 167     return rc;
 168 }
 169 
 170 
 171 /********     DATA CONSOLIDATION     ********/
 172 
 173 static char* setup_key(const opal_process_name_t* name, const char *key, int pmix_keylen_max);
 174 static char *pmi_encode(const void *val, size_t vallen);
 175 static uint8_t *pmi_decode (const char *data, size_t *retlen);
 176 
 177 int opal_pmix_base_store_encoded(const char *key, const void *data,
 178                                  opal_data_type_t type, char** buffer, int* length)
 179 {
 180     opal_byte_object_t *bo;
 181     size_t data_len = 0;
 182     size_t needed;
 183 
 184     int pmi_packed_data_off = *length;
 185     char* pmi_packed_data = *buffer;
 186 
 187     switch (type) {
 188         case OPAL_STRING:
 189         {
 190             char *ptr = *(char **)data;
 191             data_len = ptr ? strlen(ptr) + 1 : 0;
 192             data = ptr;
 193             break;
 194         }
 195         case OPAL_INT:
 196         case OPAL_UINT:
 197             data_len = sizeof (int);
 198             break;
 199         case OPAL_INT16:
 200         case OPAL_UINT16:
 201             data_len = sizeof (int16_t);
 202             break;
 203         case OPAL_INT32:
 204         case OPAL_UINT32:
 205             data_len = sizeof (int32_t);
 206             break;
 207         case OPAL_INT64:
 208         case OPAL_UINT64:
 209             data_len = sizeof (int64_t);
 210             break;
 211         case OPAL_BYTE_OBJECT:
 212             bo = (opal_byte_object_t *) data;
 213             data = bo->bytes;
 214             data_len = bo->size;
 215     }
 216 
 217     needed = 10 + data_len + strlen (key);
 218 
 219     if (NULL == pmi_packed_data) {
 220         pmi_packed_data = calloc (needed, 1);
 221     } else {
 222         /* grow the region */
 223         pmi_packed_data = realloc (pmi_packed_data, pmi_packed_data_off + needed);
 224     }
 225 
 226     /* special length meaning NULL */
 227     if (NULL == data) {
 228         data_len = 0xffff;
 229     }
 230 
 231     /* serialize the opal datatype */
 232     pmi_packed_data_off += sprintf (pmi_packed_data + pmi_packed_data_off,
 233                                     "%s%c%02x%c%04x%c", key, '\0', type, '\0',
 234                                     (int) data_len, '\0');
 235     if (NULL != data) {
 236         memmove (pmi_packed_data + pmi_packed_data_off, data, data_len);
 237         pmi_packed_data_off += data_len;
 238     }
 239 
 240     *length = pmi_packed_data_off;
 241     *buffer = pmi_packed_data;
 242     return OPAL_SUCCESS;
 243 }
 244 
 245 int opal_pmix_base_commit_packed( char** data, int* data_offset,
 246                                   char** enc_data, int* enc_data_offset,
 247                                   int max_key, int* pack_key, kvs_put_fn fn)
 248 {
 249     int rc;
 250     char *pmikey = NULL, *tmp;
 251     char tmp_key[32];
 252     char *encoded_data;
 253     int encoded_data_len;
 254     int data_len;
 255     int pkey;
 256 
 257     pkey = *pack_key;
 258 
 259     if (NULL == (tmp = malloc(max_key))) {
 260         OPAL_ERROR_LOG(OPAL_ERR_OUT_OF_RESOURCE);
 261         return OPAL_ERR_OUT_OF_RESOURCE;
 262     }
 263     data_len = *data_offset;
 264     if (NULL == (encoded_data = pmi_encode(*data, data_len))) {
 265         OPAL_ERROR_LOG(OPAL_ERR_OUT_OF_RESOURCE);
 266         free(tmp);
 267         return OPAL_ERR_OUT_OF_RESOURCE;
 268     }
 269     *data = NULL;
 270     *data_offset = 0;
 271 
 272     encoded_data_len = (int)strlen(encoded_data);
 273     while (encoded_data_len+*enc_data_offset > max_key - 2) {
 274         memcpy(tmp, *enc_data, *enc_data_offset);
 275         memcpy(tmp+*enc_data_offset, encoded_data, max_key-*enc_data_offset-1);
 276         tmp[max_key-1] = 0;
 277 
 278         sprintf (tmp_key, "key%d", pkey);
 279 
 280         if (NULL == (pmikey = setup_key(&OPAL_PROC_MY_NAME, tmp_key, max_key))) {
 281             OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM);
 282             rc = OPAL_ERR_BAD_PARAM;
 283             break;
 284         }
 285 
 286         rc = fn(pmikey, tmp);
 287         free(pmikey);
 288         if (OPAL_SUCCESS != rc) {
 289             *pack_key = pkey;
 290             free(tmp);
 291             free(encoded_data);
 292             return rc;
 293         }
 294 
 295         pkey++;
 296         memmove(encoded_data, encoded_data+max_key-1-*enc_data_offset, encoded_data_len - max_key + *enc_data_offset + 2);
 297         *enc_data_offset = 0;
 298         encoded_data_len = (int)strlen(encoded_data);
 299     }
 300     memcpy(tmp, *enc_data, *enc_data_offset);
 301     memcpy(tmp+*enc_data_offset, encoded_data, encoded_data_len+1);
 302     tmp[*enc_data_offset+encoded_data_len+1] = '\0';
 303     tmp[*enc_data_offset+encoded_data_len] = '-';
 304     free(encoded_data);
 305 
 306     sprintf (tmp_key, "key%d", pkey);
 307 
 308     if (NULL == (pmikey = setup_key(&OPAL_PROC_MY_NAME, tmp_key, max_key))) {
 309         OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM);
 310         rc = OPAL_ERR_BAD_PARAM;
 311         free(tmp);
 312         return rc;
 313     }
 314 
 315     rc = fn(pmikey, tmp);
 316     free(pmikey);
 317     if (OPAL_SUCCESS != rc) {
 318         *pack_key = pkey;
 319         free(tmp);
 320         return rc;
 321     }
 322 
 323     pkey++;
 324     free(*data);
 325     *data = NULL;
 326     *data_offset = 0;
 327     free(tmp);
 328     if (NULL != *enc_data) {
 329         free(*enc_data);
 330         *enc_data = NULL;
 331         *enc_data_offset = 0;
 332     }
 333     *pack_key = pkey;
 334     return OPAL_SUCCESS;
 335 }
 336 
 337 int opal_pmix_base_partial_commit_packed( char** data, int* data_offset,
 338                                           char** enc_data, int* enc_data_offset,
 339                                           int max_key, int* pack_key, kvs_put_fn fn)
 340 {
 341     int rc;
 342     char *pmikey = NULL, *tmp;
 343     char tmp_key[32];
 344     char *encoded_data;
 345     int encoded_data_len;
 346     int data_len;
 347     int pkey;
 348 
 349     pkey = *pack_key;
 350 
 351     if (NULL == (tmp = malloc(max_key))) {
 352         OPAL_ERROR_LOG(OPAL_ERR_OUT_OF_RESOURCE);
 353         return OPAL_ERR_OUT_OF_RESOURCE;
 354     }
 355     data_len = *data_offset - (*data_offset%3);
 356     if (NULL == (encoded_data = pmi_encode(*data, data_len))) {
 357         OPAL_ERROR_LOG(OPAL_ERR_OUT_OF_RESOURCE);
 358         free(tmp);
 359         return OPAL_ERR_OUT_OF_RESOURCE;
 360     }
 361     if (*data_offset == data_len) {
 362         *data = NULL;
 363         *data_offset = 0;
 364     } else {
 365         memmove(*data, *data+data_len, *data_offset - data_len);
 366         *data = realloc(*data, *data_offset - data_len);
 367         *data_offset -= data_len;
 368     }
 369 
 370     encoded_data_len = (int)strlen(encoded_data);
 371     while (encoded_data_len+*enc_data_offset > max_key - 2) {
 372         memcpy(tmp, *enc_data, *enc_data_offset);
 373         memcpy(tmp+*enc_data_offset, encoded_data, max_key-*enc_data_offset-1);
 374         tmp[max_key-1] = 0;
 375 
 376         sprintf (tmp_key, "key%d", pkey);
 377 
 378         if (NULL == (pmikey = setup_key(&OPAL_PROC_MY_NAME, tmp_key, max_key))) {
 379             OPAL_ERROR_LOG(OPAL_ERR_BAD_PARAM);
 380             rc = OPAL_ERR_BAD_PARAM;
 381             break;
 382         }
 383 
 384         rc = fn(pmikey, tmp);
 385         free(pmikey);
 386         if (OPAL_SUCCESS != rc) {
 387             *pack_key = pkey;
 388             free(tmp);
 389             free(encoded_data);
 390             return rc;
 391         }
 392 
 393         pkey++;
 394         memmove(encoded_data, encoded_data+max_key-1-*enc_data_offset, encoded_data_len - max_key + *enc_data_offset + 2);
 395         *enc_data_offset = 0;
 396         encoded_data_len = (int)strlen(encoded_data);
 397     }
 398     free(tmp);
 399     if (NULL != *enc_data) {
 400         free(*enc_data);
 401     }
 402     *enc_data = realloc(encoded_data, strlen(encoded_data)+1);
 403     *enc_data_offset = strlen(encoded_data);
 404     *pack_key = pkey;
 405     return OPAL_SUCCESS;
 406 }
 407 
 408 int opal_pmix_base_get_packed(const opal_process_name_t* proc, char **packed_data,
 409                               size_t *len, int vallen, kvs_get_fn fn)
 410 {
 411     char *tmp_encoded = NULL, *pmikey, *pmi_tmp;
 412     int remote_key, size;
 413     size_t bytes_read;
 414     int rc = OPAL_ERR_NOT_FOUND;
 415 
 416     /* set default */
 417     *packed_data = NULL;
 418     *len = 0;
 419 
 420     pmi_tmp = calloc (vallen, 1);
 421     if (NULL == pmi_tmp) {
 422         return OPAL_ERR_OUT_OF_RESOURCE;
 423     }
 424 
 425     /* read all of the packed data from this proc */
 426     for (remote_key = 0, bytes_read = 0 ; ; ++remote_key) {
 427         char tmp_key[32];
 428 
 429         sprintf (tmp_key, "key%d", remote_key);
 430 
 431         if (NULL == (pmikey = setup_key(proc, tmp_key, vallen))) {
 432             rc = OPAL_ERR_OUT_OF_RESOURCE;
 433             OPAL_ERROR_LOG(rc);
 434             free(pmi_tmp);
 435             if (NULL != tmp_encoded) {
 436                 free(tmp_encoded);
 437             }
 438             return rc;
 439         }
 440 
 441         OPAL_OUTPUT_VERBOSE((10, opal_pmix_base_framework.framework_output,
 442                              "GETTING KEY %s", pmikey));
 443 
 444         rc = fn(pmikey, pmi_tmp, vallen);
 445         free (pmikey);
 446         if (OPAL_SUCCESS != rc) {
 447             break;
 448         }
 449 
 450         size = strlen (pmi_tmp);
 451 
 452         if (NULL == tmp_encoded) {
 453             tmp_encoded = malloc (size + 1);
 454         } else {
 455             tmp_encoded = realloc (tmp_encoded, bytes_read + size + 1);
 456         }
 457 
 458         strcpy (tmp_encoded + bytes_read, pmi_tmp);
 459         bytes_read += size;
 460 
 461         /* is the string terminator present? */
 462         if ('-' == tmp_encoded[bytes_read-1]) {
 463             break;
 464         }
 465     }
 466 
 467     free (pmi_tmp);
 468 
 469     OPAL_OUTPUT_VERBOSE((10, opal_pmix_base_framework.framework_output,
 470                          "Read data %s\n",
 471                          (NULL == tmp_encoded) ? "NULL" : tmp_encoded));
 472 
 473     if (NULL != tmp_encoded) {
 474         *packed_data = (char *) pmi_decode (tmp_encoded, len);
 475         free (tmp_encoded);
 476         if (NULL == *packed_data) {
 477             return OPAL_ERR_OUT_OF_RESOURCE;
 478         }
 479     }
 480 
 481     return rc;
 482 }
 483 
 484 int opal_pmix_base_cache_keys_locally(const opal_process_name_t* id, const char* key,
 485                                       opal_value_t **out_kv, char* kvs_name,
 486                                       int vallen, kvs_get_fn fn)
 487 {
 488     char *tmp, *tmp2, *tmp3, *tmp_val;
 489     opal_data_type_t stored_type;
 490     size_t len, offset;
 491     int rc, size;
 492     opal_value_t *kv, *knew;
 493     opal_list_t values;
 494 
 495     /* set the default */
 496     *out_kv = NULL;
 497 
 498     /* first try to fetch data from data storage */
 499     OBJ_CONSTRUCT(&values, opal_list_t);
 500     rc = opal_pmix_base_fetch(id, key, &values);
 501     if (OPAL_SUCCESS == rc) {
 502         kv = (opal_value_t*)opal_list_get_first(&values);
 503         /* create the copy */
 504         if (OPAL_SUCCESS != (rc = opal_dss.copy((void**)&knew, kv, OPAL_VALUE))) {
 505             OPAL_ERROR_LOG(rc);
 506         } else {
 507             *out_kv = knew;
 508         }
 509         OPAL_LIST_DESTRUCT(&values);
 510         return rc;
 511     }
 512     OPAL_LIST_DESTRUCT(&values);
 513 
 514     OPAL_OUTPUT_VERBOSE((1, opal_pmix_base_framework.framework_output,
 515                          "pmix: get all keys for proc %s in KVS %s",
 516                          OPAL_NAME_PRINT(*id), kvs_name));
 517 
 518     rc = opal_pmix_base_get_packed(id, &tmp_val, &len, vallen, fn);
 519     if (OPAL_SUCCESS != rc) {
 520         return rc;
 521     }
 522 
 523     /* search for each key in the decoded data */
 524     for (offset = 0 ; offset < len ; ) {
 525         /* type */
 526         tmp = tmp_val + offset + strlen (tmp_val + offset) + 1;
 527         /* size */
 528         tmp2 = tmp + strlen (tmp) + 1;
 529         /* data */
 530         tmp3 = tmp2 + strlen (tmp2) + 1;
 531 
 532         stored_type = (opal_data_type_t) strtol (tmp, NULL, 16);
 533         size = strtol (tmp2, NULL, 16);
 534         /* cache value locally so we don't have to look it up via pmi again */
 535         kv = OBJ_NEW(opal_value_t);
 536         kv->key = strdup(tmp_val + offset);
 537         kv->type = stored_type;
 538 
 539         switch (stored_type) {
 540             case OPAL_BYTE:
 541                 kv->data.byte = *tmp3;
 542                 break;
 543             case OPAL_STRING:
 544                 kv->data.string = strdup(tmp3);
 545                 break;
 546             case OPAL_PID:
 547                 kv->data.pid = strtoul(tmp3, NULL, 10);
 548                 break;
 549             case OPAL_INT:
 550                 kv->data.integer = strtol(tmp3, NULL, 10);
 551                 break;
 552             case OPAL_INT8:
 553                 kv->data.int8 = strtol(tmp3, NULL, 10);
 554                 break;
 555             case OPAL_INT16:
 556                 kv->data.int16 = strtol(tmp3, NULL, 10);
 557                 break;
 558             case OPAL_INT32:
 559                 kv->data.int32 = strtol(tmp3, NULL, 10);
 560                 break;
 561             case OPAL_INT64:
 562                 kv->data.int64 = strtol(tmp3, NULL, 10);
 563                 break;
 564             case OPAL_UINT:
 565                 kv->data.uint = strtoul(tmp3, NULL, 10);
 566                 break;
 567             case OPAL_UINT8:
 568                 kv->data.uint8 = strtoul(tmp3, NULL, 10);
 569                 break;
 570             case OPAL_UINT16:
 571                 kv->data.uint16 = strtoul(tmp3, NULL, 10);
 572                 break;
 573             case OPAL_UINT32:
 574                 kv->data.uint32 = strtoul(tmp3, NULL, 10);
 575                 break;
 576             case OPAL_UINT64:
 577                 kv->data.uint64 = strtoull(tmp3, NULL, 10);
 578                 break;
 579             case OPAL_BYTE_OBJECT:
 580                 if (size == 0xffff) {
 581                     kv->data.bo.bytes = NULL;
 582                     kv->data.bo.size = 0;
 583                     size = 0;
 584                 } else {
 585                     kv->data.bo.bytes = malloc(size);
 586                     memcpy(kv->data.bo.bytes, tmp3, size);
 587                     kv->data.bo.size = size;
 588                 }
 589                 break;
 590             default:
 591                 opal_output(0, "UNSUPPORTED TYPE %d", stored_type);
 592                 return OPAL_ERROR;
 593         }
 594         /* store data in local hash table */
 595         if (OPAL_SUCCESS != (rc = opal_pmix_base_store(id, kv))) {
 596             OPAL_ERROR_LOG(rc);
 597         }
 598         /* keep going and cache everything locally */
 599         offset = (size_t) (tmp3 - tmp_val) + size;
 600         if (0 == strcmp(kv->key, key)) {
 601             /* create the copy */
 602             if (OPAL_SUCCESS != (rc = opal_dss.copy((void**)&knew, kv, OPAL_VALUE))) {
 603                 OPAL_ERROR_LOG(rc);
 604             } else {
 605                 *out_kv = knew;
 606             }
 607         }
 608     }
 609     free (tmp_val);
 610     /* if there was no issue with unpacking the message, but
 611      * we didn't find the requested info, then indicate that
 612      * the info wasn't found */
 613     if (OPAL_SUCCESS == rc && NULL == *out_kv) {
 614         return OPAL_ERR_NOT_FOUND;
 615     }
 616     return rc;
 617 }
 618 
 619 static char* setup_key(const opal_process_name_t* name, const char *key, int pmix_keylen_max)
 620 {
 621     char *pmi_kvs_key;
 622 
 623     if (pmix_keylen_max <= asprintf(&pmi_kvs_key, "%" PRIu32 "-%" PRIu32 "-%s",
 624                                     name->jobid, name->vpid, key)) {
 625         free(pmi_kvs_key);
 626         return NULL;
 627     }
 628 
 629     return pmi_kvs_key;
 630 }
 631 
 632 /* base64 encoding with illegal (to Cray PMI) characters removed ('=' is replaced by ' ') */
 633 static inline unsigned char pmi_base64_encsym (unsigned char value) {
 634     assert (value < 64);
 635 
 636     if (value < 26) {
 637         return 'A' + value;
 638     } else if (value < 52) {
 639         return 'a' + (value - 26);
 640     } else if (value < 62) {
 641         return '0' + (value - 52);
 642     }
 643 
 644     return (62 == value) ? '+' : '/';
 645 }
 646 
 647 static inline unsigned char pmi_base64_decsym (unsigned char value) {
 648     if ('+' == value) {
 649         return 62;
 650     } else if ('/' == value) {
 651         return 63;
 652     } else if (' ' == value) {
 653         return 64;
 654     } else if (value <= '9') {
 655         return (value - '0') + 52;
 656     } else if (value <= 'Z') {
 657         return (value - 'A');
 658     } else if (value <= 'z') {
 659         return (value - 'a') + 26;
 660     }
 661     return 64;
 662 }
 663 
 664 static inline void pmi_base64_encode_block (const unsigned char in[3], char out[4], int len) {
 665     out[0] = pmi_base64_encsym (in[0] >> 2);
 666     out[1] = pmi_base64_encsym (((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4));
 667     /* Cray PMI doesn't allow = in PMI attributes so pad with spaces */
 668     out[2] = 1 < len ? pmi_base64_encsym(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) : ' ';
 669     out[3] = 2 < len ? pmi_base64_encsym(in[2] & 0x3f) : ' ';
 670 }
 671 
 672 static inline int pmi_base64_decode_block (const char in[4], unsigned char out[3]) {
 673     char in_dec[4];
 674 
 675     in_dec[0] = pmi_base64_decsym (in[0]);
 676     in_dec[1] = pmi_base64_decsym (in[1]);
 677     in_dec[2] = pmi_base64_decsym (in[2]);
 678     in_dec[3] = pmi_base64_decsym (in[3]);
 679 
 680     out[0] = in_dec[0] << 2 | in_dec[1] >> 4;
 681     if (64 == in_dec[2]) {
 682         return 1;
 683     }
 684 
 685     out[1] = in_dec[1] << 4 | in_dec[2] >> 2;
 686     if (64 == in_dec[3]) {
 687         return 2;
 688     }
 689 
 690     out[2] = ((in_dec[2] << 6) & 0xc0) | in_dec[3];
 691     return 3;
 692 }
 693 
 694 
 695 /* PMI only supports strings. For now, do a simple base64. */
 696 static char *pmi_encode(const void *val, size_t vallen)
 697 {
 698     char *outdata, *tmp;
 699     size_t i;
 700 
 701     outdata = calloc (((2 + vallen) * 4) / 3 + 2, 1);
 702     if (NULL == outdata) {
 703         return NULL;
 704     }
 705 
 706     for (i = 0, tmp = outdata ; i < vallen ; i += 3, tmp += 4) {
 707         pmi_base64_encode_block((unsigned char *) val + i, tmp, vallen - i);
 708     }
 709 
 710     tmp[0] = (unsigned char)'\0';
 711 
 712     return outdata;
 713 }
 714 
 715 static uint8_t *pmi_decode (const char *data, size_t *retlen)
 716 {
 717     size_t input_len = strlen (data) / 4;
 718     unsigned char *ret;
 719     int out_len;
 720     size_t i;
 721 
 722     /* default */
 723     *retlen = 0;
 724 
 725     ret = calloc (1, 3 * input_len);
 726     if (NULL == ret) {
 727         return ret;
 728     }
 729     for (i = 0, out_len = 0 ; i < input_len ; i++, data += 4) {
 730         out_len += pmi_base64_decode_block(data, ret + 3 * i);
 731     }
 732     *retlen = out_len;
 733     return ret;
 734 }

/* [<][>][^][v][top][bottom][index][help] */