Blame src/pmi/simple/simple_pmi.c

Packit 0848f5
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit 0848f5
/*  
Packit 0848f5
 *  (C) 2001 by Argonne National Laboratory.
Packit 0848f5
 *      See COPYRIGHT in top-level directory.
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
/*********************** PMI implementation ********************************/
Packit 0848f5
/*
Packit 0848f5
 * This file implements the client-side of the PMI interface.
Packit 0848f5
 *
Packit 0848f5
 * Note that the PMI client code must not print error messages (except 
Packit 0848f5
 * when an abort is required) because MPI error handling is based on
Packit 0848f5
 * reporting error codes to which messages are attached.  
Packit 0848f5
 *
Packit 0848f5
 * In v2, we should require a PMI client interface to use MPI error codes
Packit 0848f5
 * to provide better integration with MPICH.  
Packit 0848f5
 */
Packit 0848f5
/***************************************************************************/
Packit 0848f5
Packit 0848f5
#include "mpichconf.h"
Packit 0848f5
Packit 0848f5
#define PMI_VERSION    1
Packit 0848f5
#define PMI_SUBVERSION 1
Packit 0848f5
Packit 0848f5
#include <stdio.h>
Packit 0848f5
#ifdef HAVE_UNISTD_H
Packit 0848f5
#include <unistd.h>
Packit 0848f5
#endif
Packit 0848f5
#ifdef HAVE_STDLIB_H
Packit 0848f5
#include <stdlib.h>
Packit 0848f5
#endif
Packit 0848f5
#ifdef HAVE_STRING_H
Packit 0848f5
#include <string.h>
Packit 0848f5
#endif
Packit 0848f5
#ifdef HAVE_STRINGS_H
Packit 0848f5
#include <strings.h>
Packit 0848f5
#endif
Packit 0848f5
#ifdef USE_PMI_PORT
Packit 0848f5
#ifndef MAXHOSTNAME
Packit 0848f5
#define MAXHOSTNAME 256
Packit 0848f5
#endif
Packit 0848f5
#endif
Packit 0848f5
/* This should be moved to pmiu for shutdown */
Packit 0848f5
#if defined(HAVE_SYS_SOCKET_H)
Packit 0848f5
#include <sys/socket.h>
Packit 0848f5
#endif
Packit 0848f5
Packit 0848f5
#include "mpl.h"            /* Get ATTRIBUTE, some base functions */
Packit 0848f5
/* mpimem includes the definitions for MPL_snprintf, MPIU_Malloc, and 
Packit 0848f5
   MPIU_Free */
Packit 0848f5
#include "mpimem.h"
Packit 0848f5
Packit 0848f5
/* Temporary debug definitions */
Packit 0848f5
/* #define DBG_PRINTF(args) printf args ; fflush(stdout) */
Packit 0848f5
#define DBG_PRINTF(args)
Packit 0848f5
Packit 0848f5
#include "pmi.h"
Packit 0848f5
#include "simple_pmiutil.h"
Packit 0848f5
#include "mpi.h"		/* to get MPI_MAX_PORT_NAME */
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
   These are global variable used *ONLY* in this file, and are hence
Packit 0848f5
   declared static.
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
Packit 0848f5
static int PMI_fd = -1;
Packit 0848f5
static int PMI_size = 1;
Packit 0848f5
static int PMI_rank = 0;
Packit 0848f5
Packit 0848f5
/* Set PMI_initialized to 1 for singleton init but no process manager
Packit 0848f5
   to help.  Initialized to 2 for normal initialization.  Initialized
Packit 0848f5
   to values higher than 2 when singleton_init by a process manager.
Packit 0848f5
   All values higher than 1 invlove a PM in some way.
Packit 0848f5
*/
Packit 0848f5
typedef enum { PMI_UNINITIALIZED = 0, 
Packit 0848f5
               SINGLETON_INIT_BUT_NO_PM = 1,
Packit 0848f5
	       NORMAL_INIT_WITH_PM,
Packit 0848f5
	       SINGLETON_INIT_WITH_PM } PMIState;
Packit 0848f5
static PMIState PMI_initialized = PMI_UNINITIALIZED;
Packit 0848f5
Packit 0848f5
/* ALL GLOBAL VARIABLES MUST BE INITIALIZED TO AVOID POLLUTING THE 
Packit 0848f5
   LIBRARY WITH COMMON SYMBOLS */
Packit 0848f5
static int PMI_kvsname_max = 0;
Packit 0848f5
static int PMI_keylen_max = 0;
Packit 0848f5
static int PMI_vallen_max = 0;
Packit 0848f5
Packit 0848f5
static int PMI_debug = 0;
Packit 0848f5
static int PMI_debug_init = 0;    /* Set this to true to debug the init
Packit 0848f5
				     handshakes */
Packit 0848f5
static int PMI_spawned = 0;
Packit 0848f5
Packit 0848f5
/* Function prototypes for internal routines */
Packit 0848f5
static int PMII_getmaxes( int *kvsname_max, int *keylen_max, int *vallen_max );
Packit 0848f5
static int PMII_Set_from_port( int, int );
Packit 0848f5
static int PMII_Connect_to_pm( char *, int );
Packit 0848f5
Packit 0848f5
static int GetResponse( const char [], const char [], int );
Packit 0848f5
static int getPMIFD( int * );
Packit 0848f5
Packit 0848f5
#ifdef USE_PMI_PORT
Packit 0848f5
static int PMII_singinit(void);
Packit 0848f5
static int PMI_totalview = 0;
Packit 0848f5
#endif
Packit 0848f5
static int PMIi_InitIfSingleton(void);
Packit 0848f5
static int accept_one_connection(int);
Packit 0848f5
static int cached_singinit_inuse = 0;
Packit 0848f5
static char cached_singinit_key[PMIU_MAXLINE];
Packit 0848f5
static char cached_singinit_val[PMIU_MAXLINE];
Packit 0848f5
static char singinit_kvsname[256];
Packit 0848f5
Packit 0848f5
/******************************** Group functions *************************/
Packit 0848f5
Packit 0848f5
int PMI_Init( int *spawned )
Packit 0848f5
{
Packit 0848f5
    char *p;
Packit 0848f5
    int notset = 1;
Packit 0848f5
    int rc;
Packit 0848f5
    
Packit 0848f5
    PMI_initialized = PMI_UNINITIALIZED;
Packit 0848f5
    
Packit 0848f5
    /* FIXME: Why is setvbuf commented out? */
Packit 0848f5
    /* FIXME: What if the output should be fully buffered (directed to file)?
Packit 0848f5
       unbuffered (user explicitly set?) */
Packit 0848f5
    /* setvbuf(stdout,0,_IONBF,0); */
Packit 0848f5
    setbuf(stdout,NULL);
Packit 0848f5
    /* PMIU_printf( 1, "PMI_INIT\n" ); */
Packit 0848f5
Packit 0848f5
    /* Get the value of PMI_DEBUG from the environment if possible, since
Packit 0848f5
       we may have set it to help debug the setup process */
Packit 0848f5
    p = getenv( "PMI_DEBUG" );
Packit 0848f5
    if (p) PMI_debug = atoi( p );
Packit 0848f5
Packit 0848f5
    /* Get the fd for PMI commands; if none, we're a singleton */
Packit 0848f5
    rc = getPMIFD(&notset);
Packit 0848f5
    if (rc) {
Packit 0848f5
	return rc;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    if ( PMI_fd == -1 ) {
Packit 0848f5
	/* Singleton init: Process not started with mpiexec, 
Packit 0848f5
	   so set size to 1, rank to 0 */
Packit 0848f5
	PMI_size = 1;
Packit 0848f5
	PMI_rank = 0;
Packit 0848f5
	*spawned = 0;
Packit 0848f5
	
Packit 0848f5
	PMI_initialized = SINGLETON_INIT_BUT_NO_PM;
Packit 0848f5
	/* 256 is picked as the minimum allowed length by the PMI servers */
Packit 0848f5
	PMI_kvsname_max = 256;
Packit 0848f5
	PMI_keylen_max  = 256;
Packit 0848f5
	PMI_vallen_max  = 256;
Packit 0848f5
	
Packit 0848f5
	return( 0 );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    /* If size, rank, and debug are not set from a communication port,
Packit 0848f5
       use the environment */
Packit 0848f5
    if (notset) {
Packit 0848f5
	if ( ( p = getenv( "PMI_SIZE" ) ) )
Packit 0848f5
	    PMI_size = atoi( p );
Packit 0848f5
	else 
Packit 0848f5
	    PMI_size = 1;
Packit 0848f5
	
Packit 0848f5
	if ( ( p = getenv( "PMI_RANK" ) ) ) {
Packit 0848f5
	    PMI_rank = atoi( p );
Packit 0848f5
	    /* Let the util routine know the rank of this process for 
Packit 0848f5
	       any messages (usually debugging or error) */
Packit 0848f5
	    PMIU_Set_rank( PMI_rank );
Packit 0848f5
	}
Packit 0848f5
	else 
Packit 0848f5
	    PMI_rank = 0;
Packit 0848f5
	
Packit 0848f5
	if ( ( p = getenv( "PMI_DEBUG" ) ) )
Packit 0848f5
	    PMI_debug = atoi( p );
Packit 0848f5
	else 
Packit 0848f5
	    PMI_debug = 0;
Packit 0848f5
Packit 0848f5
	/* Leave unchanged otherwise, which indicates that no value
Packit 0848f5
	   was set */
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
/* FIXME: Why does this depend on their being a port??? */
Packit 0848f5
/* FIXME: What is this for? */
Packit 0848f5
#ifdef USE_PMI_PORT
Packit 0848f5
    if ( ( p = getenv( "PMI_TOTALVIEW" ) ) )
Packit 0848f5
	PMI_totalview = atoi( p );
Packit 0848f5
    if ( PMI_totalview ) {
Packit 0848f5
	char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit 0848f5
	/* FIXME: This should use a cmd/response rather than a expecting the
Packit 0848f5
	   server to set a value in this and only this case */
Packit 0848f5
	/* FIXME: And it most ceratainly should not happen *before* the
Packit 0848f5
	   initialization handshake */
Packit 0848f5
	PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
Packit 0848f5
	PMIU_parse_keyvals( buf );
Packit 0848f5
	PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
	if ( strncmp( cmd, "tv_ready", PMIU_MAXLINE ) != 0 ) {
Packit 0848f5
	    PMIU_printf( 1, "expecting cmd=tv_ready, got %s\n", buf );
Packit 0848f5
	    return( PMI_FAIL );
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
#endif
Packit 0848f5
Packit 0848f5
    PMII_getmaxes( &PMI_kvsname_max, &PMI_keylen_max, &PMI_vallen_max );
Packit 0848f5
Packit 0848f5
    /* FIXME: This is something that the PM should tell the process,
Packit 0848f5
       rather than deliver it through the environment */
Packit 0848f5
    if ( ( p = getenv( "PMI_SPAWNED" ) ) )
Packit 0848f5
	PMI_spawned = atoi( p );
Packit 0848f5
    else
Packit 0848f5
	PMI_spawned = 0;
Packit 0848f5
    if (PMI_spawned)
Packit 0848f5
	*spawned = 1;
Packit 0848f5
    else
Packit 0848f5
	*spawned = 0;
Packit 0848f5
Packit 0848f5
    if ( ! PMI_initialized )
Packit 0848f5
	PMI_initialized = NORMAL_INIT_WITH_PM;
Packit 0848f5
Packit 0848f5
    return( 0 );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Initialized( int *initialized )
Packit 0848f5
{
Packit 0848f5
    /* Turn this into a logical value (1 or 0) .  This allows us
Packit 0848f5
       to use PMI_initialized to distinguish between initialized with
Packit 0848f5
       an PMI service (e.g., via mpiexec) and the singleton init, 
Packit 0848f5
       which has no PMI service */
Packit 0848f5
    *initialized = (PMI_initialized != 0);
Packit 0848f5
    return PMI_SUCCESS;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Get_size( int *size )
Packit 0848f5
{
Packit 0848f5
    if ( PMI_initialized )
Packit 0848f5
	*size = PMI_size;
Packit 0848f5
    else
Packit 0848f5
	*size = 1;
Packit 0848f5
    return( 0 );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Get_rank( int *rank )
Packit 0848f5
{
Packit 0848f5
    if ( PMI_initialized )
Packit 0848f5
	*rank = PMI_rank;
Packit 0848f5
    else
Packit 0848f5
	*rank = 0;
Packit 0848f5
    return( 0 );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* 
Packit 0848f5
 * Get_universe_size is one of the routines that needs to communicate
Packit 0848f5
 * with the process manager.  If we started as a singleton init, then
Packit 0848f5
 * we first need to connect to the process manager and acquire the 
Packit 0848f5
 * needed information.
Packit 0848f5
 */
Packit 0848f5
int PMI_Get_universe_size( int *size)
Packit 0848f5
{
Packit 0848f5
    int  err;
Packit 0848f5
    char size_c[PMIU_MAXLINE];
Packit 0848f5
Packit 0848f5
    /* Connect to the PM if we haven't already */
Packit 0848f5
    if (PMIi_InitIfSingleton() != 0) return -1;
Packit 0848f5
Packit 0848f5
    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM)  {
Packit 0848f5
	err = GetResponse( "cmd=get_universe_size\n", "universe_size", 0 );
Packit 0848f5
	if (err == PMI_SUCCESS) {
Packit 0848f5
	    PMIU_getval( "size", size_c, PMIU_MAXLINE );
Packit 0848f5
	    *size = atoi(size_c);
Packit 0848f5
	    return( PMI_SUCCESS );
Packit 0848f5
	}
Packit 0848f5
	else return err;
Packit 0848f5
    }
Packit 0848f5
    else
Packit 0848f5
	*size = 1;
Packit 0848f5
    return( PMI_SUCCESS );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Get_appnum( int *appnum )
Packit 0848f5
{
Packit 0848f5
    int  err;
Packit 0848f5
    char appnum_c[PMIU_MAXLINE];
Packit 0848f5
Packit 0848f5
    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
	err = GetResponse( "cmd=get_appnum\n", "appnum", 0 );
Packit 0848f5
	if (err == PMI_SUCCESS) {
Packit 0848f5
	    PMIU_getval( "appnum", appnum_c, PMIU_MAXLINE );
Packit 0848f5
	    *appnum = atoi(appnum_c);
Packit 0848f5
	    return( PMI_SUCCESS );
Packit 0848f5
	}
Packit 0848f5
	else return err;
Packit 0848f5
	
Packit 0848f5
    }
Packit 0848f5
    else
Packit 0848f5
	*appnum = -1;
Packit 0848f5
Packit 0848f5
    return( PMI_SUCCESS );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Barrier( void )
Packit 0848f5
{
Packit 0848f5
    int err = PMI_SUCCESS;
Packit 0848f5
Packit 0848f5
    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
	err = GetResponse( "cmd=barrier_in\n", "barrier_out", 0 );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Inform the process manager that we're in finalize */
Packit 0848f5
int PMI_Finalize( void )
Packit 0848f5
{
Packit 0848f5
    int err = PMI_SUCCESS;
Packit 0848f5
Packit 0848f5
    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
	err = GetResponse( "cmd=finalize\n", "finalize_ack", 0 );
Packit 0848f5
	shutdown( PMI_fd, SHUT_RDWR );
Packit 0848f5
	close( PMI_fd );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Abort(int exit_code, const char error_msg[])
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE];
Packit 0848f5
Packit 0848f5
    /* include exit_code in the abort command */
Packit 0848f5
    MPL_snprintf( buf, PMIU_MAXLINE, "cmd=abort exitcode=%d\n", exit_code);
Packit 0848f5
Packit 0848f5
    PMIU_printf(PMI_debug, "aborting job:\n%s\n", error_msg);
Packit 0848f5
    GetResponse( buf, "", 0 );
Packit 0848f5
Packit 0848f5
    /* the above command should not return */
Packit 0848f5
    return -1;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/************************************* Keymap functions **********************/
Packit 0848f5
Packit 0848f5
/*FIXME: need to return an error if the value of the kvs name returned is 
Packit 0848f5
  truncated because it is larger than length */
Packit 0848f5
/* FIXME: My name should be cached rather than re-acquired, as it is
Packit 0848f5
   unchanging (after singleton init) */
Packit 0848f5
int PMI_KVS_Get_my_name( char kvsname[], int length )
Packit 0848f5
{
Packit 0848f5
    int err;
Packit 0848f5
Packit 0848f5
    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
	/* Return a dummy name */
Packit 0848f5
	/* FIXME: We need to support a distinct kvsname for each 
Packit 0848f5
	   process group */
Packit 0848f5
	MPL_snprintf( kvsname, length, "singinit_kvs_%d_0", (int)getpid() );
Packit 0848f5
	return 0;
Packit 0848f5
    }
Packit 0848f5
    err = GetResponse( "cmd=get_my_kvsname\n", "my_kvsname", 0 );
Packit 0848f5
    if (err == PMI_SUCCESS) {
Packit 0848f5
	PMIU_getval( "kvsname", kvsname, length );
Packit 0848f5
    }
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_KVS_Get_name_length_max( int *maxlen )
Packit 0848f5
{
Packit 0848f5
    if (maxlen == NULL)
Packit 0848f5
	return PMI_ERR_INVALID_ARG;
Packit 0848f5
    *maxlen = PMI_kvsname_max;
Packit 0848f5
    return PMI_SUCCESS;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_KVS_Get_key_length_max( int *maxlen )
Packit 0848f5
{
Packit 0848f5
    if (maxlen == NULL)
Packit 0848f5
	return PMI_ERR_INVALID_ARG;
Packit 0848f5
    *maxlen = PMI_keylen_max;
Packit 0848f5
    return PMI_SUCCESS;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_KVS_Get_value_length_max( int *maxlen )
Packit 0848f5
{
Packit 0848f5
    if (maxlen == NULL)
Packit 0848f5
	return PMI_ERR_INVALID_ARG;
Packit 0848f5
    *maxlen = PMI_vallen_max;
Packit 0848f5
    return PMI_SUCCESS;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_KVS_Put( const char kvsname[], const char key[], const char value[] )
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE];
Packit 0848f5
    int  err = PMI_SUCCESS;
Packit 0848f5
    int  rc;
Packit 0848f5
Packit 0848f5
    /* This is a special hack to support singleton initialization */
Packit 0848f5
    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
        if (cached_singinit_inuse)
Packit 0848f5
            return PMI_FAIL;
Packit 0848f5
	rc = MPIU_Strncpy(cached_singinit_key,key,PMI_keylen_max);
Packit 0848f5
	if (rc != 0) return PMI_FAIL;
Packit 0848f5
	rc = MPIU_Strncpy(cached_singinit_val,value,PMI_vallen_max);
Packit 0848f5
	if (rc != 0) return PMI_FAIL;
Packit 0848f5
        cached_singinit_inuse = 1;
Packit 0848f5
	return PMI_SUCCESS;
Packit 0848f5
    }
Packit 0848f5
    
Packit 0848f5
    rc = MPL_snprintf( buf, PMIU_MAXLINE, 
Packit 0848f5
			"cmd=put kvsname=%s key=%s value=%s\n",
Packit 0848f5
			kvsname, key, value);
Packit 0848f5
    if (rc < 0) return PMI_FAIL;
Packit 0848f5
    err = GetResponse( buf, "put_result", 1 );
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_KVS_Commit( const char kvsname[] ATTRIBUTE((unused)))
Packit 0848f5
{
Packit 0848f5
    /* no-op in this implementation */
Packit 0848f5
    return( 0 );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/*FIXME: need to return an error if the value returned is truncated
Packit 0848f5
  because it is larger than length */
Packit 0848f5
int PMI_KVS_Get( const char kvsname[], const char key[], char value[], 
Packit 0848f5
		 int length)
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE];
Packit 0848f5
    int err = PMI_SUCCESS;
Packit 0848f5
    int  rc;
Packit 0848f5
Packit 0848f5
    /* Connect to the PM if we haven't already.  This is needed in case
Packit 0848f5
       we're doing an MPI_Comm_join or MPI_Comm_connect/accept from
Packit 0848f5
       the singleton init case.  This test is here because, in the way in 
Packit 0848f5
       which MPICH uses PMI, this is where the test needs to be. */
Packit 0848f5
    if (PMIi_InitIfSingleton() != 0) return -1;
Packit 0848f5
Packit 0848f5
    rc = MPL_snprintf( buf, PMIU_MAXLINE, "cmd=get kvsname=%s key=%s\n", 
Packit 0848f5
			kvsname, key );
Packit 0848f5
    if (rc < 0) return PMI_FAIL;
Packit 0848f5
Packit 0848f5
    err = GetResponse( buf, "get_result", 0 );
Packit 0848f5
    if (err == PMI_SUCCESS) {
Packit 0848f5
	PMIU_getval( "rc", buf, PMIU_MAXLINE );
Packit 0848f5
	rc = atoi( buf );
Packit 0848f5
	if ( rc == 0 ) {
Packit 0848f5
	    PMIU_getval( "value", value, length );
Packit 0848f5
	    return( 0 );
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    return( -1 );
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/*************************** Name Publishing functions **********************/
Packit 0848f5
Packit 0848f5
int PMI_Publish_name( const char service_name[], const char port[] )
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit 0848f5
    int err;
Packit 0848f5
Packit 0848f5
    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
        MPL_snprintf( cmd, PMIU_MAXLINE, 
Packit 0848f5
		       "cmd=publish_name service=%s port=%s\n",
Packit 0848f5
		       service_name, port );
Packit 0848f5
	err = GetResponse( cmd, "publish_result", 0 );
Packit 0848f5
	if (err == PMI_SUCCESS) {
Packit 0848f5
	    PMIU_getval( "rc", buf, PMIU_MAXLINE );
Packit 0848f5
	    if ( strcmp(buf,"0") != 0 ) {
Packit 0848f5
                PMIU_getval( "msg", buf, PMIU_MAXLINE );
Packit 0848f5
                PMIU_printf( PMI_debug, "publish failed; reason = %s\n", buf );
Packit 0848f5
Packit 0848f5
	        return( PMI_FAIL );
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    else
Packit 0848f5
    {
Packit 0848f5
	PMIU_printf( 1, "PMI_Publish_name called before init\n" );
Packit 0848f5
	return( PMI_FAIL );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return( PMI_SUCCESS );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Unpublish_name( const char service_name[] )
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit 0848f5
    int err = PMI_SUCCESS;
Packit 0848f5
Packit 0848f5
    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
        MPL_snprintf( cmd, PMIU_MAXLINE, "cmd=unpublish_name service=%s\n", 
Packit 0848f5
		       service_name );
Packit 0848f5
	err = GetResponse( cmd, "unpublish_result", 0 );
Packit 0848f5
	if (err == PMI_SUCCESS) {
Packit 0848f5
	    PMIU_getval( "rc", buf, PMIU_MAXLINE );
Packit 0848f5
	    if ( strcmp(buf,"0") != 0 ) {
Packit 0848f5
                PMIU_getval( "msg", buf, PMIU_MAXLINE );
Packit 0848f5
                PMIU_printf( PMI_debug, "unpublish failed; reason = %s\n", buf );
Packit 0848f5
Packit 0848f5
                return( PMI_FAIL );
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    else
Packit 0848f5
    {
Packit 0848f5
	PMIU_printf( 1, "PMI_Unpublish_name called before init\n" );
Packit 0848f5
	return( PMI_FAIL );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return( PMI_SUCCESS );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
int PMI_Lookup_name( const char service_name[], char port[] )
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit 0848f5
    int err;
Packit 0848f5
Packit 0848f5
    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit 0848f5
        MPL_snprintf( cmd, PMIU_MAXLINE, "cmd=lookup_name service=%s\n", 
Packit 0848f5
		       service_name );
Packit 0848f5
	err = GetResponse( cmd, "lookup_result", 0 );
Packit 0848f5
	if (err == PMI_SUCCESS) {
Packit 0848f5
	    PMIU_getval( "rc", buf, PMIU_MAXLINE );
Packit 0848f5
	    if ( strcmp(buf,"0") != 0 ) {
Packit 0848f5
                PMIU_getval( "msg", buf, PMIU_MAXLINE );
Packit 0848f5
                PMIU_printf( PMI_debug, "lookup failed; reason = %s\n", buf );
Packit 0848f5
Packit 0848f5
	        return( PMI_FAIL );
Packit 0848f5
	    }
Packit 0848f5
	    PMIU_getval( "port", port, MPI_MAX_PORT_NAME );
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    else
Packit 0848f5
    {
Packit 0848f5
	PMIU_printf( 1, "PMI_Lookup_name called before init\n" );
Packit 0848f5
	return( PMI_FAIL );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return( PMI_SUCCESS );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
Packit 0848f5
/************************** Process Creation functions **********************/
Packit 0848f5
Packit 0848f5
int PMI_Spawn_multiple(int count,
Packit 0848f5
                       const char * cmds[],
Packit 0848f5
                       const char ** argvs[],
Packit 0848f5
                       const int maxprocs[],
Packit 0848f5
                       const int info_keyval_sizes[],
Packit 0848f5
                       const PMI_keyval_t * info_keyval_vectors[],
Packit 0848f5
                       int preput_keyval_size,
Packit 0848f5
                       const PMI_keyval_t preput_keyval_vector[],
Packit 0848f5
                       int errors[])
Packit 0848f5
{
Packit 0848f5
    int  i,rc,argcnt,spawncnt,total_num_processes,num_errcodes_found;
Packit 0848f5
    char buf[PMIU_MAXLINE], tempbuf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit 0848f5
    char *lead, *lag;
Packit 0848f5
Packit 0848f5
    /* Connect to the PM if we haven't already */
Packit 0848f5
    if (PMIi_InitIfSingleton() != 0) return -1;
Packit 0848f5
Packit 0848f5
    total_num_processes = 0;
Packit 0848f5
Packit 0848f5
    for (spawncnt=0; spawncnt < count; spawncnt++)
Packit 0848f5
    {
Packit 0848f5
        total_num_processes += maxprocs[spawncnt];
Packit 0848f5
Packit 0848f5
        rc = MPL_snprintf(buf, PMIU_MAXLINE, 
Packit 0848f5
			   "mcmd=spawn\nnprocs=%d\nexecname=%s\n",
Packit 0848f5
			   maxprocs[spawncnt], cmds[spawncnt] );
Packit 0848f5
	if (rc < 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
	rc = MPL_snprintf(tempbuf, PMIU_MAXLINE,
Packit 0848f5
			   "totspawns=%d\nspawnssofar=%d\n",
Packit 0848f5
			   count, spawncnt+1);
Packit 0848f5
Packit 0848f5
	if (rc < 0) { 
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
Packit 0848f5
	if (rc != 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
        argcnt = 0;
Packit 0848f5
        if ((argvs != NULL) && (argvs[spawncnt] != NULL)) {
Packit 0848f5
            for (i=0; argvs[spawncnt][i] != NULL; i++)
Packit 0848f5
            {
Packit 0848f5
		/* FIXME (protocol design flaw): command line arguments
Packit 0848f5
		   may contain both = and <space> (and even tab!).
Packit 0848f5
		*/
Packit 0848f5
		/* Note that part of this fixme was really a design error -
Packit 0848f5
		   because this uses the mcmd form, the data can be
Packit 0848f5
		   sent in multiple writelines.  This code now takes 
Packit 0848f5
		   advantage of that.  Note also that a correct parser 
Packit 0848f5
		   of the commands will permit any character other than a 
Packit 0848f5
		   new line in the argument, since the form is 
Packit 0848f5
		   argn=<any nonnewline><newline> */
Packit 0848f5
                rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"arg%d=%s\n",
Packit 0848f5
				   i+1,argvs[spawncnt][i]);
Packit 0848f5
		if (rc < 0) {
Packit 0848f5
		    return PMI_FAIL;
Packit 0848f5
		}
Packit 0848f5
                rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
Packit 0848f5
		if (rc != 0) {
Packit 0848f5
		    return PMI_FAIL;
Packit 0848f5
		}
Packit 0848f5
                argcnt++;
Packit 0848f5
		rc = PMIU_writeline( PMI_fd, buf );
Packit 0848f5
                if (rc)
Packit 0848f5
                    return PMI_FAIL;
Packit 0848f5
		buf[0] = 0;
Packit 0848f5
Packit 0848f5
            }
Packit 0848f5
        }
Packit 0848f5
        rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"argcnt=%d\n",argcnt);
Packit 0848f5
	if (rc < 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
        rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
Packit 0848f5
	if (rc != 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
    
Packit 0848f5
        rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"preput_num=%d\n", 
Packit 0848f5
			   preput_keyval_size);
Packit 0848f5
	if (rc < 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
        rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
Packit 0848f5
	if (rc != 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
        for (i=0; i < preput_keyval_size; i++) {
Packit 0848f5
	    rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"preput_key_%d=%s\n",
Packit 0848f5
			       i,preput_keyval_vector[i].key);
Packit 0848f5
	    if (rc < 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
	    rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
Packit 0848f5
	    if (rc != 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
	    rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"preput_val_%d=%s\n",
Packit 0848f5
			       i,preput_keyval_vector[i].val);
Packit 0848f5
	    if (rc < 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
	    rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
Packit 0848f5
	    if (rc != 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
        } 
Packit 0848f5
        rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"info_num=%d\n", 
Packit 0848f5
			   info_keyval_sizes[spawncnt]);
Packit 0848f5
	if (rc < 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
        rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
Packit 0848f5
	if (rc != 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	for (i=0; i < info_keyval_sizes[spawncnt]; i++)
Packit 0848f5
	{
Packit 0848f5
	    rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"info_key_%d=%s\n",
Packit 0848f5
			       i,info_keyval_vectors[spawncnt][i].key);
Packit 0848f5
	    if (rc < 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
	    rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
Packit 0848f5
	    if (rc != 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
	    rc = MPL_snprintf(tempbuf,PMIU_MAXLINE,"info_val_%d=%s\n",
Packit 0848f5
			       i,info_keyval_vectors[spawncnt][i].val);
Packit 0848f5
	    if (rc < 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
	    rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
Packit 0848f5
	    if (rc != 0) {
Packit 0848f5
		return PMI_FAIL;
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
        rc = MPIU_Strnapp(buf, "endcmd\n", PMIU_MAXLINE);
Packit 0848f5
	if (rc != 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
        rc = PMIU_writeline( PMI_fd, buf );
Packit 0848f5
	if (rc) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
Packit 0848f5
    PMIU_parse_keyvals( buf ); 
Packit 0848f5
    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
    if ( strncmp( cmd, "spawn_result", PMIU_MAXLINE ) != 0 ) {
Packit 0848f5
	PMIU_printf( 1, "got unexpected response to spawn :%s:\n", buf );
Packit 0848f5
	return( -1 );
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
	PMIU_getval( "rc", buf, PMIU_MAXLINE );
Packit 0848f5
	rc = atoi( buf );
Packit 0848f5
	if ( rc != 0 ) {
Packit 0848f5
	    /****
Packit 0848f5
	    PMIU_getval( "status", tempbuf, PMIU_MAXLINE );
Packit 0848f5
	    PMIU_printf( 1, "pmi_spawn_mult failed; status: %s\n",tempbuf);
Packit 0848f5
	    ****/
Packit 0848f5
	    return( -1 );
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
    
Packit 0848f5
    PMIU_Assert(errors != NULL);
Packit 0848f5
    if (PMIU_getval( "errcodes", tempbuf, PMIU_MAXLINE )) {
Packit 0848f5
        num_errcodes_found = 0;
Packit 0848f5
        lag = &tempbuf[0];
Packit 0848f5
        do {
Packit 0848f5
            lead = strchr(lag, ',');
Packit 0848f5
            if (lead) *lead = '\0';
Packit 0848f5
            errors[num_errcodes_found++] = atoi(lag);
Packit 0848f5
            lag = lead + 1; /* move past the null char */
Packit 0848f5
            PMIU_Assert(num_errcodes_found <= total_num_processes);
Packit 0848f5
        } while (lead != NULL);
Packit 0848f5
        PMIU_Assert(num_errcodes_found == total_num_processes);
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        /* gforker doesn't return errcodes, so we'll just pretend that means
Packit 0848f5
           that it was going to send all `0's. */
Packit 0848f5
        for (i = 0; i < total_num_processes; ++i) {
Packit 0848f5
            errors[i] = 0;
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return( 0 );
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/***************** Internal routines not part of PMI interface ***************/
Packit 0848f5
Packit 0848f5
/* to get all maxes in one message */
Packit 0848f5
/* FIXME: This mixes init with get maxes */
Packit 0848f5
static int PMII_getmaxes( int *kvsname_max, int *keylen_max, int *vallen_max )
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE], errmsg[PMIU_MAXLINE];
Packit 0848f5
    int err, rc;
Packit 0848f5
Packit 0848f5
    rc = MPL_snprintf( buf, PMIU_MAXLINE, 
Packit 0848f5
			"cmd=init pmi_version=%d pmi_subversion=%d\n",
Packit 0848f5
			PMI_VERSION, PMI_SUBVERSION );
Packit 0848f5
    if (rc < 0) {
Packit 0848f5
	return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    rc = PMIU_writeline( PMI_fd, buf );
Packit 0848f5
    if (rc != 0) {
Packit 0848f5
	PMIU_printf( 1, "Unable to write to PMI_fd\n" );
Packit 0848f5
	return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
    buf[0] = 0;   /* Ensure buffer is empty if read fails */
Packit 0848f5
    err = PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
Packit 0848f5
    if (err < 0) {
Packit 0848f5
	PMIU_printf( 1, "Error reading initack on %d\n", PMI_fd );
Packit 0848f5
	perror( "Error on readline:" );
Packit 0848f5
	PMI_Abort(-1, "Above error when reading after init" );
Packit 0848f5
    }
Packit 0848f5
    PMIU_parse_keyvals( buf );
Packit 0848f5
    cmd[0] = 0;
Packit 0848f5
    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
    if ( strncmp( cmd, "response_to_init", PMIU_MAXLINE ) != 0 ) {
Packit 0848f5
	MPL_snprintf(errmsg, PMIU_MAXLINE, 
Packit 0848f5
		      "got unexpected response to init :%s: (full line = %s)",
Packit 0848f5
		      cmd, buf  );
Packit 0848f5
	PMI_Abort( -1, errmsg );
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
	char buf1[PMIU_MAXLINE];
Packit 0848f5
        PMIU_getval( "rc", buf, PMIU_MAXLINE );
Packit 0848f5
        if ( strncmp( buf, "0", PMIU_MAXLINE ) != 0 ) {
Packit 0848f5
            PMIU_getval( "pmi_version", buf, PMIU_MAXLINE );
Packit 0848f5
            PMIU_getval( "pmi_subversion", buf1, PMIU_MAXLINE );
Packit 0848f5
	    MPL_snprintf(errmsg, PMIU_MAXLINE, 
Packit 0848f5
			  "pmi_version mismatch; client=%d.%d mgr=%s.%s",
Packit 0848f5
			  PMI_VERSION, PMI_SUBVERSION, buf, buf1 );
Packit 0848f5
	    PMI_Abort( -1, errmsg );
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
    err = GetResponse( "cmd=get_maxes\n", "maxes", 0 );
Packit 0848f5
    if (err == PMI_SUCCESS) {
Packit 0848f5
	PMIU_getval( "kvsname_max", buf, PMIU_MAXLINE );
Packit 0848f5
	*kvsname_max = atoi( buf );
Packit 0848f5
	PMIU_getval( "keylen_max", buf, PMIU_MAXLINE );
Packit 0848f5
	*keylen_max = atoi( buf );
Packit 0848f5
	PMIU_getval( "vallen_max", buf, PMIU_MAXLINE );
Packit 0848f5
	*vallen_max = atoi( buf );
Packit 0848f5
    }
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* ----------------------------------------------------------------------- */
Packit 0848f5
/* 
Packit 0848f5
 * This function is used to request information from the server and check
Packit 0848f5
 * that the response uses the expected command name.  On a successful
Packit 0848f5
 * return from this routine, additional PMIU_getval calls may be used
Packit 0848f5
 * to access information about the returned value.
Packit 0848f5
 *
Packit 0848f5
 * If checkRc is true, this routine also checks that the rc value returned
Packit 0848f5
 * was 0.  If not, it uses the "msg" value to report on the reason for
Packit 0848f5
 * the failure.
Packit 0848f5
 */
Packit 0848f5
static int GetResponse( const char request[], const char expectedCmd[],
Packit 0848f5
			int checkRc )
Packit 0848f5
{
Packit 0848f5
    int err, n;
Packit 0848f5
    char *p;
Packit 0848f5
    char recvbuf[PMIU_MAXLINE];
Packit 0848f5
    char cmdName[PMIU_MAXLINE];
Packit 0848f5
Packit 0848f5
    /* FIXME: This is an example of an incorrect fix - writeline can change
Packit 0848f5
       the second argument in some cases, and that will break the const'ness
Packit 0848f5
       of request.  Instead, writeline should take a const item and return
Packit 0848f5
       an error in the case in which it currently truncates the data. */
Packit 0848f5
    err = PMIU_writeline( PMI_fd, (char *)request );
Packit 0848f5
    if (err) {
Packit 0848f5
	return err;
Packit 0848f5
    }
Packit 0848f5
    n = PMIU_readline( PMI_fd, recvbuf, sizeof(recvbuf) );
Packit 0848f5
    if (n <= 0) {
Packit 0848f5
	PMIU_printf( 1, "readline failed\n" );
Packit 0848f5
	return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
    err = PMIU_parse_keyvals( recvbuf );
Packit 0848f5
    if (err) {
Packit 0848f5
	PMIU_printf( 1, "parse_kevals failed %d\n", err );
Packit 0848f5
	return err;
Packit 0848f5
    }
Packit 0848f5
    p = PMIU_getval( "cmd", cmdName, sizeof(cmdName) );
Packit 0848f5
    if (!p) {
Packit 0848f5
	PMIU_printf( 1, "getval cmd failed\n" );
Packit 0848f5
	return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
    if (strcmp( expectedCmd, cmdName ) != 0) {
Packit 0848f5
	PMIU_printf( 1, "expecting cmd=%s, got %s\n", expectedCmd, cmdName );
Packit 0848f5
	return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
    if (checkRc) {
Packit 0848f5
	p = PMIU_getval( "rc", cmdName, PMIU_MAXLINE );
Packit 0848f5
	if ( p && strcmp(cmdName,"0") != 0 ) {
Packit 0848f5
	    PMIU_getval( "msg", cmdName, PMIU_MAXLINE );
Packit 0848f5
	    PMIU_printf( 1, "Command %s failed, reason='%s'\n", 
Packit 0848f5
			 request, cmdName );
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return err;
Packit 0848f5
}
Packit 0848f5
/* ----------------------------------------------------------------------- */
Packit 0848f5
Packit 0848f5
Packit 0848f5
#ifdef USE_PMI_PORT
Packit 0848f5
/*
Packit 0848f5
 * This code allows a program to contact a host/port for the PMI socket.
Packit 0848f5
 */
Packit 0848f5
#include <errno.h>
Packit 0848f5
#if defined(HAVE_SYS_TYPES_H)
Packit 0848f5
#include <sys/types.h>
Packit 0848f5
#endif
Packit 0848f5
#include <sys/param.h>
Packit 0848f5
#include <sys/socket.h>
Packit 0848f5
Packit 0848f5
/* sockaddr_in (Internet) */
Packit 0848f5
#include <netinet/in.h>
Packit 0848f5
/* TCP_NODELAY */
Packit 0848f5
#include <netinet/tcp.h>
Packit 0848f5
Packit 0848f5
/* sockaddr_un (Unix) */
Packit 0848f5
#include <sys/un.h>
Packit 0848f5
Packit 0848f5
/* defs of gethostbyname */
Packit 0848f5
#include <netdb.h>
Packit 0848f5
Packit 0848f5
/* fcntl, F_GET/SETFL */
Packit 0848f5
#include <fcntl.h>
Packit 0848f5
Packit 0848f5
/* This is really IP!? */
Packit 0848f5
#ifndef TCP
Packit 0848f5
#define TCP 0
Packit 0848f5
#endif
Packit 0848f5
Packit 0848f5
/* stub for connecting to a specified host/port instead of using a 
Packit 0848f5
   specified fd inherited from a parent process */
Packit 0848f5
static int PMII_Connect_to_pm( char *hostname, int portnum )
Packit 0848f5
{
Packit 0848f5
    struct hostent     *hp;
Packit 0848f5
    struct sockaddr_in sa;
Packit 0848f5
    int                fd;
Packit 0848f5
    int                optval = 1;
Packit 0848f5
    int                q_wait = 1;
Packit 0848f5
    
Packit 0848f5
    hp = gethostbyname( hostname );
Packit 0848f5
    if (!hp) {
Packit 0848f5
	PMIU_printf( 1, "Unable to get host entry for %s\n", hostname );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    
Packit 0848f5
    memset( (void *)&sa, 0, sizeof(sa) );
Packit 0848f5
    /* POSIX might define h_addr_list only and node define h_addr */
Packit 0848f5
#ifdef HAVE_H_ADDR_LIST
Packit 0848f5
    memcpy( (void *)&sa.sin_addr, (void *)hp->h_addr_list[0], hp->h_length);
Packit 0848f5
#else
Packit 0848f5
    memcpy( (void *)&sa.sin_addr, (void *)hp->h_addr, hp->h_length);
Packit 0848f5
#endif
Packit 0848f5
    sa.sin_family = hp->h_addrtype;
Packit 0848f5
    sa.sin_port   = htons( (unsigned short) portnum );
Packit 0848f5
    
Packit 0848f5
    fd = socket( AF_INET, SOCK_STREAM, TCP );
Packit 0848f5
    if (fd < 0) {
Packit 0848f5
	PMIU_printf( 1, "Unable to get AF_INET socket\n" );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    
Packit 0848f5
    if (setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, 
Packit 0848f5
		    (char *)&optval, sizeof(optval) )) {
Packit 0848f5
	perror( "Error calling setsockopt:" );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    /* We wait here for the connection to succeed */
Packit 0848f5
    if (connect( fd, (struct sockaddr *)&sa, sizeof(sa) ) < 0) {
Packit 0848f5
	switch (errno) {
Packit 0848f5
	case ECONNREFUSED:
Packit 0848f5
	    PMIU_printf( 1, "connect failed with connection refused\n" );
Packit 0848f5
	    /* (close socket, get new socket, try again) */
Packit 0848f5
	    if (q_wait)
Packit 0848f5
		close(fd);
Packit 0848f5
	    return -1;
Packit 0848f5
	    
Packit 0848f5
	case EINPROGRESS: /*  (nonblocking) - select for writing. */
Packit 0848f5
	    break;
Packit 0848f5
	    
Packit 0848f5
	case EISCONN: /*  (already connected) */
Packit 0848f5
	    break;
Packit 0848f5
	    
Packit 0848f5
	case ETIMEDOUT: /* timed out */
Packit 0848f5
	    PMIU_printf( 1, "connect failed with timeout\n" );
Packit 0848f5
	    return -1;
Packit 0848f5
Packit 0848f5
	default:
Packit 0848f5
	    PMIU_printf( 1, "connect failed with errno %d\n", errno );
Packit 0848f5
	    return -1;
Packit 0848f5
	}
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return fd;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
static int PMII_Set_from_port( int fd, int id )
Packit 0848f5
{
Packit 0848f5
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit 0848f5
    int err, rc;
Packit 0848f5
Packit 0848f5
    /* We start by sending a startup message to the server */
Packit 0848f5
Packit 0848f5
    if (PMI_debug) {
Packit 0848f5
	PMIU_printf( 1, "Writing initack to destination fd %d\n", fd );
Packit 0848f5
    }
Packit 0848f5
    /* Handshake and initialize from a port */
Packit 0848f5
Packit 0848f5
    rc = MPL_snprintf( buf, PMIU_MAXLINE, "cmd=initack pmiid=%d\n", id );
Packit 0848f5
    if (rc < 0) {
Packit 0848f5
	return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
    PMIU_printf( PMI_debug, "writing on fd %d line :%s:\n", fd, buf );
Packit 0848f5
    err = PMIU_writeline( fd, buf );
Packit 0848f5
    if (err) {
Packit 0848f5
	PMIU_printf( 1, "Error in writeline initack\n" );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    /* cmd=initack */
Packit 0848f5
    buf[0] = 0;
Packit 0848f5
    PMIU_printf( PMI_debug, "reading initack\n" );
Packit 0848f5
    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
Packit 0848f5
    if (err < 0) {
Packit 0848f5
	PMIU_printf( 1, "Error reading initack on %d\n", fd );
Packit 0848f5
	perror( "Error on readline:" );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    PMIU_parse_keyvals( buf );
Packit 0848f5
    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
    if ( strcmp( cmd, "initack" ) ) {
Packit 0848f5
	PMIU_printf( 1, "got unexpected input %s\n", buf );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    
Packit 0848f5
    /* Read, in order, size, rank, and debug.  Eventually, we'll want 
Packit 0848f5
       the handshake to include a version number */
Packit 0848f5
Packit 0848f5
    /* size */
Packit 0848f5
    PMIU_printf( PMI_debug, "reading size\n" );
Packit 0848f5
    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
Packit 0848f5
    if (err < 0) {
Packit 0848f5
	PMIU_printf( 1, "Error reading size on %d\n", fd );
Packit 0848f5
	perror( "Error on readline:" );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    PMIU_parse_keyvals( buf );
Packit 0848f5
    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
    if ( strcmp(cmd,"set")) {
Packit 0848f5
	PMIU_printf( 1, "got unexpected command %s in %s\n", cmd, buf );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    /* cmd=set size=n */
Packit 0848f5
    PMIU_getval( "size", cmd, PMIU_MAXLINE );
Packit 0848f5
    PMI_size = atoi(cmd);
Packit 0848f5
Packit 0848f5
    /* rank */
Packit 0848f5
    PMIU_printf( PMI_debug, "reading rank\n" );
Packit 0848f5
    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
Packit 0848f5
    if (err < 0) {
Packit 0848f5
	PMIU_printf( 1, "Error reading rank on %d\n", fd );
Packit 0848f5
	perror( "Error on readline:" );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    PMIU_parse_keyvals( buf );
Packit 0848f5
    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
    if ( strcmp(cmd,"set")) {
Packit 0848f5
	PMIU_printf( 1, "got unexpected command %s in %s\n", cmd, buf );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    /* cmd=set rank=n */
Packit 0848f5
    PMIU_getval( "rank", cmd, PMIU_MAXLINE );
Packit 0848f5
    PMI_rank = atoi(cmd);
Packit 0848f5
    PMIU_Set_rank( PMI_rank );
Packit 0848f5
Packit 0848f5
    /* debug flag */
Packit 0848f5
    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
Packit 0848f5
    if (err < 0) {
Packit 0848f5
	PMIU_printf( 1, "Error reading debug on %d\n", fd );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    PMIU_parse_keyvals( buf );
Packit 0848f5
    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
    if ( strcmp(cmd,"set")) {
Packit 0848f5
	PMIU_printf( 1, "got unexpected command %s in %s\n", cmd, buf );
Packit 0848f5
	return -1;
Packit 0848f5
    }
Packit 0848f5
    /* cmd=set debug=n */
Packit 0848f5
    PMIU_getval( "debug", cmd, PMIU_MAXLINE );
Packit 0848f5
    PMI_debug = atoi(cmd);
Packit 0848f5
Packit 0848f5
    if (PMI_debug) {
Packit 0848f5
	DBG_PRINTF( ("end of handshake, rank = %d, size = %d\n", 
Packit 0848f5
		    PMI_rank, PMI_size )); 
Packit 0848f5
	DBG_PRINTF( ("Completed init\n" ) );
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    return 0;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* ------------------------------------------------------------------------- */
Packit 0848f5
/* 
Packit 0848f5
 * Singleton Init.
Packit 0848f5
 * 
Packit 0848f5
 * MPI-2 allows processes to become MPI processes and then make MPI calls,
Packit 0848f5
 * such as MPI_Comm_spawn, that require a process manager (this is different 
Packit 0848f5
 * than the much simpler case of allowing MPI programs to run with an 
Packit 0848f5
 * MPI_COMM_WORLD of size 1 without an mpiexec or process manager).
Packit 0848f5
 *
Packit 0848f5
 * The process starts when either the client or the process manager contacts
Packit 0848f5
 * the other.  If the client starts, it sends a singinit command and
Packit 0848f5
 * waits for the server to respond with its own singinit command.
Packit 0848f5
 * If the server start, it send a singinit command and waits for the 
Packit 0848f5
 * client to respond with its own singinit command
Packit 0848f5
 *
Packit 0848f5
 * client sends singinit with these required values
Packit 0848f5
 *   pmi_version=<value of PMI_VERSION>
Packit 0848f5
 *   pmi_subversion=<value of PMI_SUBVERSION>
Packit 0848f5
 *
Packit 0848f5
 * and these optional values
Packit 0848f5
 *   stdio=[yes|no]
Packit 0848f5
 *   authtype=[none|shared|<other-to-be-defined>]
Packit 0848f5
 *   authstring=<string>
Packit 0848f5
 *
Packit 0848f5
 * server sends singinit with the same required and optional values as
Packit 0848f5
 * above.
Packit 0848f5
 *
Packit 0848f5
 * At this point, the protocol is now the same in both cases, and has the
Packit 0848f5
 * following components:
Packit 0848f5
 *
Packit 0848f5
 * server sends singinit_info with these required fields
Packit 0848f5
 *   versionok=[yes|no]
Packit 0848f5
 *   stdio=[yes|no]
Packit 0848f5
 *   kvsname=<string>
Packit 0848f5
 *
Packit 0848f5
 * The client then issues the init command (see PMII_getmaxes)
Packit 0848f5
 *
Packit 0848f5
 * cmd=init pmi_version=<val> pmi_subversion=<val>
Packit 0848f5
 *
Packit 0848f5
 * and expects to receive a 
Packit 0848f5
 *
Packit 0848f5
 * cmd=response_to_init rc=0 pmi_version=<val> pmi_subversion=<val> 
Packit 0848f5
 *
Packit 0848f5
 * (This is the usual init sequence).
Packit 0848f5
 *
Packit 0848f5
 */
Packit 0848f5
/* ------------------------------------------------------------------------- */
Packit 0848f5
/* This is a special routine used to re-initialize PMI when it is in 
Packit 0848f5
   the singleton init case.  That is, the executable was started without 
Packit 0848f5
   mpiexec, and PMI_Init returned as if there was only one process.
Packit 0848f5
Packit 0848f5
   Note that PMI routines should not call PMII_singinit; they should
Packit 0848f5
   call PMIi_InitIfSingleton(), which both connects to the process mangager
Packit 0848f5
   and sets up the initial KVS connection entry.
Packit 0848f5
*/
Packit 0848f5
Packit 0848f5
static int PMII_singinit(void)
Packit 0848f5
{
Packit 0848f5
    int pid, rc;
Packit 0848f5
    int singinit_listen_sock, stdin_sock, stdout_sock, stderr_sock;
Packit 0848f5
    const char *newargv[8];
Packit 0848f5
    char charpid[8], port_c[8];
Packit 0848f5
    struct sockaddr_in sin;
Packit 0848f5
    socklen_t len;
Packit 0848f5
Packit 0848f5
    /* Create a socket on which to allow an mpiexec to connect back to
Packit 0848f5
       us */
Packit 0848f5
    memset(&sin, 0, sizeof(sin));
Packit 0848f5
    sin.sin_family	= AF_INET;
Packit 0848f5
    sin.sin_addr.s_addr	= INADDR_ANY;
Packit 0848f5
    sin.sin_port	= htons(0);    /* anonymous port */
Packit 0848f5
Packit 0848f5
    singinit_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
Packit 0848f5
    if (singinit_listen_sock == -1) {
Packit 0848f5
        perror("PMII_singinit: socket creation failed");
Packit 0848f5
        return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    rc = bind(singinit_listen_sock, (struct sockaddr *)&sin ,sizeof(sin));
Packit 0848f5
    if (rc == -1) {
Packit 0848f5
        perror("PMII_singinit: socket bind failed");
Packit 0848f5
        return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    len = sizeof(struct sockaddr_in);
Packit 0848f5
    rc = getsockname( singinit_listen_sock, (struct sockaddr *) &sin, &len ); 
Packit 0848f5
    if (rc == -1) {
Packit 0848f5
        perror("PMII_singinit: getsockname failed");
Packit 0848f5
        return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    MPL_snprintf(port_c, sizeof(port_c), "%d",ntohs(sin.sin_port));
Packit 0848f5
    rc = listen(singinit_listen_sock, 5);
Packit 0848f5
    if (rc == -1) {
Packit 0848f5
        perror("PMII_singinit: listen failed");
Packit 0848f5
        return PMI_FAIL;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    PMIU_printf( PMI_debug_init, "Starting mpiexec with %s\n", port_c );
Packit 0848f5
Packit 0848f5
    /* Launch the mpiexec process with the name of this port */
Packit 0848f5
    pid = fork();
Packit 0848f5
    if (pid < 0) {
Packit 0848f5
	perror("PMII_singinit: fork failed");
Packit 0848f5
	exit(-1);
Packit 0848f5
    }
Packit 0848f5
    else if (pid == 0) {
Packit 0848f5
	newargv[0] = "mpiexec";
Packit 0848f5
	newargv[1] = "-pmi_args";
Packit 0848f5
	newargv[2] = port_c;
Packit 0848f5
	/* FIXME: Use a valid hostname */
Packit 0848f5
	newargv[3] = "default_interface";  /* default interface name, for now */
Packit 0848f5
	newargv[4] = "default_key";   /* default authentication key, for now */
Packit 0848f5
	MPL_snprintf(charpid, sizeof(charpid), "%d",getpid());
Packit 0848f5
	newargv[5] = charpid;
Packit 0848f5
	newargv[6] = NULL;
Packit 0848f5
	rc = execvp(newargv[0], (char **)newargv);
Packit 0848f5
	perror("PMII_singinit: execv failed");
Packit 0848f5
	PMIU_printf(1, "  This singleton init program attempted to access some feature\n");
Packit 0848f5
	PMIU_printf(1, "  for which process manager support was required, e.g. spawn or universe_size.\n");
Packit 0848f5
	PMIU_printf(1, "  But the necessary mpiexec is not in your path.\n");
Packit 0848f5
	return(-1);
Packit 0848f5
    }
Packit 0848f5
    else
Packit 0848f5
    {
Packit 0848f5
	char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit 0848f5
	char *p;
Packit 0848f5
	int connectStdio = 0;
Packit 0848f5
Packit 0848f5
	/* Allow one connection back from the created mpiexec program */
Packit 0848f5
	PMI_fd =  accept_one_connection(singinit_listen_sock);
Packit 0848f5
	if (PMI_fd < 0) {
Packit 0848f5
	    PMIU_printf( 1, "Failed to establish singleton init connection\n" );
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	/* Execute the singleton init protocol */
Packit 0848f5
	rc = PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
Packit 0848f5
	PMIU_printf( PMI_debug_init, "Singinit: read %s\n", buf );
Packit 0848f5
Packit 0848f5
	PMIU_parse_keyvals( buf );
Packit 0848f5
	PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
Packit 0848f5
	if (strcmp( cmd, "singinit" ) != 0) {
Packit 0848f5
	    PMIU_printf( 1, "unexpected command from PM: %s\n", cmd );
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	p = PMIU_getval( "authtype", cmd, PMIU_MAXLINE );
Packit 0848f5
	if (p && strcmp( cmd, "none" ) != 0) {
Packit 0848f5
	    PMIU_printf( 1, "unsupported authentication method %s\n", cmd );
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	/* p = PMIU_getval( "authstring", cmd, PMIU_MAXLINE ); */
Packit 0848f5
	
Packit 0848f5
	/* If we're successful, send back our own singinit */
Packit 0848f5
	rc = MPL_snprintf( buf, PMIU_MAXLINE, 
Packit 0848f5
     "cmd=singinit pmi_version=%d pmi_subversion=%d stdio=yes authtype=none\n",
Packit 0848f5
			PMI_VERSION, PMI_SUBVERSION );
Packit 0848f5
	if (rc < 0) {
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	PMIU_printf( PMI_debug_init, "GetResponse with %s\n", buf );
Packit 0848f5
Packit 0848f5
	rc = GetResponse( buf, "singinit_info", 0 );
Packit 0848f5
	if (rc != 0) {
Packit 0848f5
	    PMIU_printf( 1, "GetResponse failed\n" );
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	p = PMIU_getval( "versionok", cmd, PMIU_MAXLINE );
Packit 0848f5
	if (p && strcmp( cmd, "yes" ) != 0) {
Packit 0848f5
	    PMIU_printf( 1, "Process manager needs a different PMI version\n" );
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
	p = PMIU_getval( "stdio", cmd, PMIU_MAXLINE );
Packit 0848f5
	if (p && strcmp( cmd, "yes" ) == 0) {
Packit 0848f5
	    PMIU_printf( PMI_debug_init, "PM agreed to connect stdio\n" );
Packit 0848f5
	    connectStdio = 1;
Packit 0848f5
	}
Packit 0848f5
	p = PMIU_getval( "kvsname", singinit_kvsname, sizeof(singinit_kvsname) );
Packit 0848f5
	PMIU_printf( PMI_debug_init, "kvsname to use is %s\n", 
Packit 0848f5
		     singinit_kvsname );
Packit 0848f5
	
Packit 0848f5
	if (connectStdio) {
Packit 0848f5
	    PMIU_printf( PMI_debug_init, 
Packit 0848f5
			 "Accepting three connections for stdin, out, err\n" );
Packit 0848f5
	    stdin_sock  = accept_one_connection(singinit_listen_sock);
Packit 0848f5
	    dup2(stdin_sock, 0);
Packit 0848f5
	    stdout_sock = accept_one_connection(singinit_listen_sock);
Packit 0848f5
	    dup2(stdout_sock,1);
Packit 0848f5
	    stderr_sock = accept_one_connection(singinit_listen_sock);
Packit 0848f5
	    dup2(stderr_sock,2);
Packit 0848f5
	}
Packit 0848f5
	PMIU_printf( PMI_debug_init, "Done with singinit handshake\n" );
Packit 0848f5
    }
Packit 0848f5
    return 0;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
/* Promote PMI to a fully initialized version if it was started as
Packit 0848f5
   a singleton init */
Packit 0848f5
static int PMIi_InitIfSingleton(void)
Packit 0848f5
{
Packit 0848f5
    int rc;
Packit 0848f5
    static int firstcall = 1;
Packit 0848f5
Packit 0848f5
    if (PMI_initialized != SINGLETON_INIT_BUT_NO_PM || !firstcall) return 0;
Packit 0848f5
Packit 0848f5
    /* We only try to init as a singleton the first time */
Packit 0848f5
    firstcall = 0;
Packit 0848f5
Packit 0848f5
    /* First, start (if necessary) an mpiexec, connect to it, 
Packit 0848f5
       and start the singleton init handshake */
Packit 0848f5
    rc = PMII_singinit();
Packit 0848f5
Packit 0848f5
    if (rc < 0)
Packit 0848f5
	return(-1);
Packit 0848f5
    PMI_initialized = SINGLETON_INIT_WITH_PM;    /* do this right away */
Packit 0848f5
    PMI_size	    = 1;
Packit 0848f5
    PMI_rank	    = 0;
Packit 0848f5
    PMI_debug	    = 0;
Packit 0848f5
    PMI_spawned	    = 0;
Packit 0848f5
Packit 0848f5
    PMII_getmaxes( &PMI_kvsname_max, &PMI_keylen_max, &PMI_vallen_max );
Packit 0848f5
Packit 0848f5
    /* FIXME: We need to support a distinct kvsname for each 
Packit 0848f5
       process group */
Packit 0848f5
    PMI_KVS_Put( singinit_kvsname, cached_singinit_key, cached_singinit_val );
Packit 0848f5
Packit 0848f5
    return 0;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
static int accept_one_connection(int list_sock)
Packit 0848f5
{
Packit 0848f5
    int gotit, new_sock;
Packit 0848f5
    struct sockaddr_in from;
Packit 0848f5
    socklen_t len;
Packit 0848f5
Packit 0848f5
    len = sizeof(from);
Packit 0848f5
    gotit = 0;
Packit 0848f5
    while ( ! gotit )
Packit 0848f5
    {
Packit 0848f5
	new_sock = accept(list_sock, (struct sockaddr *)&from, &len;;
Packit 0848f5
	if (new_sock == -1)
Packit 0848f5
	{
Packit 0848f5
	    if (errno == EINTR)    /* interrupted? If so, try again */
Packit 0848f5
		continue;
Packit 0848f5
	    else
Packit 0848f5
	    {
Packit 0848f5
		PMIU_printf(1, "accept failed in accept_one_connection\n");
Packit 0848f5
		exit(-1);
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	else
Packit 0848f5
	    gotit = 1;
Packit 0848f5
    }
Packit 0848f5
    return(new_sock);
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
#endif
Packit 0848f5
/* end USE_PMI_PORT */
Packit 0848f5
Packit 0848f5
/* Get the FD to use for PMI operations.  If a port is used, rather than 
Packit 0848f5
   a pre-established FD (i.e., via pipe), this routine will handle the 
Packit 0848f5
   initial handshake.  
Packit 0848f5
*/
Packit 0848f5
static int getPMIFD( int *notset )
Packit 0848f5
{
Packit 0848f5
    char *p;
Packit 0848f5
Packit 0848f5
    /* Set the default */
Packit 0848f5
    PMI_fd = -1;
Packit 0848f5
    
Packit 0848f5
    p = getenv( "PMI_FD" );
Packit 0848f5
Packit 0848f5
    if (p) {
Packit 0848f5
	PMI_fd = atoi( p );
Packit 0848f5
	return 0;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
#ifdef USE_PMI_PORT
Packit 0848f5
    p = getenv( "PMI_PORT" );
Packit 0848f5
    if (p) {
Packit 0848f5
	int portnum;
Packit 0848f5
	char hostname[MAXHOSTNAME+1];
Packit 0848f5
	char *pn, *ph;
Packit 0848f5
	int id = 0;
Packit 0848f5
Packit 0848f5
	/* Connect to the indicated port (in format hostname:portnumber) 
Packit 0848f5
	   and get the fd for the socket */
Packit 0848f5
	
Packit 0848f5
	/* Split p into host and port */
Packit 0848f5
	pn = p;
Packit 0848f5
	ph = hostname;
Packit 0848f5
	while (*pn && *pn != ':' && (ph - hostname) < MAXHOSTNAME) {
Packit 0848f5
	    *ph++ = *pn++;
Packit 0848f5
	}
Packit 0848f5
	*ph = 0;
Packit 0848f5
Packit 0848f5
	if (PMI_debug) {
Packit 0848f5
	    DBG_PRINTF( ("Connecting to %s\n", p) );
Packit 0848f5
	}
Packit 0848f5
	if (*pn == ':') {
Packit 0848f5
	    portnum = atoi( pn+1 );
Packit 0848f5
	    /* FIXME: Check for valid integer after : */
Packit 0848f5
	    /* This routine only gets the fd to use to talk to 
Packit 0848f5
	       the process manager. The handshake below is used
Packit 0848f5
	       to setup the initial values */
Packit 0848f5
	    PMI_fd = PMII_Connect_to_pm( hostname, portnum );
Packit 0848f5
	    if (PMI_fd < 0) {
Packit 0848f5
		PMIU_printf( 1, "Unable to connect to %s on %d\n", 
Packit 0848f5
			     hostname, portnum );
Packit 0848f5
		return -1;
Packit 0848f5
	    }
Packit 0848f5
	}
Packit 0848f5
	else {
Packit 0848f5
	    PMIU_printf( 1, "unable to decode hostport from %s\n", p );
Packit 0848f5
	    return PMI_FAIL;
Packit 0848f5
	}
Packit 0848f5
Packit 0848f5
	/* We should first handshake to get size, rank, debug. */
Packit 0848f5
	p = getenv( "PMI_ID" );
Packit 0848f5
	if (p) {
Packit 0848f5
	    id = atoi( p );
Packit 0848f5
	    /* PMII_Set_from_port sets up the values that are delivered
Packit 0848f5
	       by enviroment variables when a separate port is not used */
Packit 0848f5
 	    PMII_Set_from_port( PMI_fd, id );
Packit 0848f5
	    *notset = 0;
Packit 0848f5
	}
Packit 0848f5
	return 0;
Packit 0848f5
    }
Packit 0848f5
#endif
Packit 0848f5
Packit 0848f5
    /* Singleton init case - its ok to return success with no fd set */
Packit 0848f5
    return 0;
Packit 0848f5
}