-:    0:Source:/home/MPI/testing/mpich2/mpich2/src/mpid/ch3/util/sock/ch3u_getinterfaces.c
        -:    0:Graph:ch3u_getinterfaces.gcno
        -:    0:Data:ch3u_getinterfaces.gcda
        -:    0:Runs:4382
        -:    0:Programs:1376
        -:    1:/* -*- Mode: C; c-basic-offset:4 ; -*- */
        -:    2:/*
        -:    3: *  (C) 2006 by Argonne National Laboratory.
        -:    4: *      See COPYRIGHT in top-level directory.
        -:    5: */
        -:    6:
        -:    7:/* We need to include the conf file first so that we can use
        -:    8:   the _SVID_SOURCE if needed before any file includes features.h 
        -:    9:   on GNU systems */
        -:   10:#include "mpidi_ch3_conf.h"
        -:   11:
        -:   12:
        -:   13:#ifdef USE_NOPOSIX_FOR_IFCONF
        -:   14:/* This is a very special case.  Allow the use of some extensions for 
        -:   15:   just the rest of this file so that we can get the ifconf structure */
        -:   16:#undef _POSIX_C_SOURCE
        -:   17:#endif
        -:   18:
        -:   19:#ifdef USE_SVIDSOURCE_FOR_IFCONF
        -:   20:/* This is a very special case.  Allow the use of some extensions for just
        -:   21:   the rest of this file so that we can get the ifconf structure */
        -:   22:#define _SVID_SOURCE
        -:   23:#endif
        -:   24:
        -:   25:#include "mpidi_ch3_impl.h"
        -:   26:
        -:   27:#include <stdlib.h>
        -:   28:
        -:   29:#ifdef HAVE_NETDB_H
        -:   30: #include <netdb.h>
        -:   31:#endif
        -:   32:
        -:   33:/* We set dbg_ifname to 1 to help debug the choice of interface name 
        -:   34:   used when determining which interface to advertise to other processes.
        -:   35:   The value is -1 if it has not yet been set.
        -:   36: */
        -:   37:static int dbg_ifname = -1;
        -:   38:
        -:   39:static int MPIDI_CH3U_GetIPInterface( MPIDU_Sock_ifaddr_t *, int * );
        -:   40:
        -:   41:/*
        -:   42: * Get a description of the network interface to use for socket communication
        -:   43: *
        -:   44: * Here are the steps.  This order of checks is used to provide the 
        -:   45: * user control over the choice of interface and to avoid, where possible,
        -:   46: * the use of non-scalable services, such as centeralized name servers.
        -:   47: *
        -:   48: * MPICH_INTERFACE_HOSTNAME
        -:   49: * MPICH_INTERFACE_HOSTNAME_R%d
        -:   50: * a single (non-localhost) available IP address, if possible
        -:   51: * gethostbyname(gethostname())
        -:   52: *
        -:   53: * We return the following items:
        -:   54: *
        -:   55: *    ifname - name of the interface.  This may or may not be the same
        -:   56: *             as the name returned by gethostname  (in Unix)
        -:   57: *    ifaddr - This structure includes the interface IP address (as bytes),
        -:   58: *             and the type (e.g., AF_INET or AF_INET6).  Only 
        -:   59: *             ipv4 (AF_INET) is used so far.
        -:   60: */
        -:   61:
        -:   62:#undef FUNCNAME
        -:   63:#define FUNCNAME MPIDU_CH3U_GetSockInterfaceAddr
        -:   64:#undef FCNAME
        -:   65:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:   66:int MPIDU_CH3U_GetSockInterfaceAddr( int myRank, char *ifname, int maxIfname,
        -:   67:				     MPIDU_Sock_ifaddr_t *ifaddr )
     4754:   68:{
        -:   69:    char *ifname_string;
     4754:   70:    int mpi_errno = MPI_SUCCESS;
     4754:   71:    int ifaddrFound = 0;
        -:   72:
     4754:   73:    if (dbg_ifname < 0) {
        -:   74:	int rc;
     4382:   75:	rc = MPIU_GetEnvBool( "MPICH_DBG_IFNAME", &dbg_ifname );
     4382:   76:	if (rc != 1) dbg_ifname = 0;
        -:   77:    }
        -:   78:
        -:   79:    /* Set "not found" for ifaddr */
     4754:   80:    ifaddr->len = 0;
        -:   81:
        -:   82:    /* Check for the name supplied through an environment variable */
     4754:   83:    ifname_string = getenv("MPICH_INTERFACE_HOSTNAME");
        -:   84:
     4754:   85:    if (!ifname_string) {
        -:   86:	/* See if there is a per-process name for the interfaces (e.g.,
        -:   87:	   the process manager only delievers the same values for the 
        -:   88:	   environment to each process */
        -:   89:	char namebuf[1024];
    #####:   90:	MPIU_Snprintf( namebuf, sizeof(namebuf), 
        -:   91:		       "MPICH_INTERFACE_HOSTNAME_R%d", myRank );
    #####:   92:	ifname_string = getenv( namebuf );
    #####:   93:	if (dbg_ifname && ifname_string) {
    #####:   94:	    fprintf( stdout, "Found interface name %s from %s\n", 
        -:   95:		    ifname_string, namebuf );
    #####:   96:	    fflush( stdout );
        -:   97:	}
        -:   98:    }
     4754:   99:    else if (dbg_ifname) {
    #####:  100:	fprintf( stdout, 
        -:  101:		 "Found interface name %s from MPICH_INTERFACE_HOSTNAME\n", 
        -:  102:		 ifname_string );
    #####:  103:	fflush( stdout );
        -:  104:    }
        -:  105:	 
     4754:  106:    if (!ifname_string) {
        -:  107:	int len;
        -:  108:
        -:  109:	/* If we have nothing, then use the host name */
    #####:  110:	mpi_errno = MPID_Get_processor_name(ifname, maxIfname, &len );
    #####:  111:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
    #####:  112:	ifname_string = ifname;
        -:  113:
        -:  114:	/* If we didn't find a specific name, then try to get an IP address
        -:  115:	   directly from the available interfaces, if that is supported on
        -:  116:	   this platform.  Otherwise, we'll drop into the next step that uses 
        -:  117:	   the ifname */
    #####:  118:	mpi_errno = MPIDI_CH3U_GetIPInterface( ifaddr, &ifaddrFound );
    #####:  119:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  120:    }
        -:  121:    else {
        -:  122:	/* Copy this name into the output name */
     4754:  123:	MPIU_Strncpy( ifname, ifname_string, maxIfname );
        -:  124:    }
        -:  125:
        -:  126:    /* If we don't have an IP address, try to get it from the name */
     4754:  127:    if (!ifaddrFound) {
        -:  128:	struct hostent *info;
        -:  129:	/* printf( "Name to check is %s\n", ifname_string ); fflush(stdout); */
     4754:  130:	info = gethostbyname( ifname_string );
     4754:  131:	if (info && info->h_addr_list) {
        -:  132:	    /* Use the primary address */
     4754:  133:	    ifaddr->len  = info->h_length;
     4754:  134:	    ifaddr->type = info->h_addrtype;
     4754:  135:	    if (ifaddr->len > sizeof(ifaddr->ifaddr)) {
        -:  136:		/* If the address won't fit in the field, reset to
        -:  137:		   no address */
    #####:  138:		ifaddr->len = 0;
    #####:  139:		ifaddr->type = -1;
        -:  140:	    }
        -:  141:	    else {
     4754:  142:		MPIU_Memcpy( ifaddr->ifaddr, info->h_addr_list[0], ifaddr->len );
        -:  143:#if 0
        -:  144:		printf( "ifaddr len = %d\n", ifaddr->len );
        -:  145:		{int i;
        -:  146:		    unsigned char *p = info->h_addr_list[0];
        -:  147:		    for (i=0; i<ifaddr->len; i++) { 
        -:  148:			printf( "%.2x", *p++ );
        -:  149:		    }
        -:  150:		    printf( "\n" ); fflush(stdout);
        -:  151:		    p = info->h_addr_list[0];
        -:  152:		    for (i=0; i<ifaddr->len; i++) { 
        -:  153:			printf( "%.3d", *p++ );
        -:  154:		    }
        -:  155:		    printf( "\n" ); fflush(stdout);
        -:  156:		}
        -:  157:#endif
        -:  158:	    }
        -:  159:	}
        -:  160:    }
        -:  161:
     4754:  162:fn_exit:
     4754:  163:    return mpi_errno;
        -:  164:fn_fail:
        -:  165:    goto fn_exit;
        -:  166:}
        -:  167:
        -:  168:
        -:  169:/* These includes are here because they're used just for getting the interface
        -:  170: *   names
        -:  171: */
        -:  172:
        -:  173:
        -:  174:#include <sys/types.h>
        -:  175:
        -:  176:#ifdef HAVE_SYS_SOCKET_H
        -:  177:#include <sys/socket.h>
        -:  178:#endif
        -:  179:#ifdef HAVE_NET_IF_H
        -:  180:#include <net/if.h>
        -:  181:#endif
        -:  182:#ifdef HAVE_SYS_SOCKIO_H
        -:  183:/* Needed for SIOCGIFCONF */
        -:  184:#include <sys/sockio.h>
        -:  185:#endif
        -:  186:
        -:  187:#if defined(SIOCGIFCONF) && defined(HAVE_STRUCT_IFCONF)
        -:  188:#include <netinet/in.h>
        -:  189:#include <arpa/inet.h>
        -:  190:#include <sys/ioctl.h>
        -:  191:#include <errno.h>
        -:  192:
        -:  193:/* We can only access the interfaces if we have a number of features.
        -:  194:   Test for these, otherwise define this routine to return false in the
        -:  195:   "found" variable */
        -:  196:
        -:  197:#define NUM_IFREQS 10
        -:  198:
        -:  199:static int MPIDI_CH3U_GetIPInterface( MPIDU_Sock_ifaddr_t *ifaddr, int *found )
        -:  200:{
        -:  201:    char *buf_ptr, *ptr;
        -:  202:    int buf_len, buf_len_prev;
        -:  203:    int fd;
        -:  204:    MPIDU_Sock_ifaddr_t myifaddr;
        -:  205:    int nfound = 0, foundLocalhost = 0;
        -:  206:    /* We predefine the LSB and MSB localhost addresses */
        -:  207:    unsigned int localhost = 0x0100007f;
        -:  208:#ifdef WORDS_BIGENDIAN
        -:  209:    unsigned int MSBlocalhost = 0x7f000001;
        -:  210:#endif
        -:  211:
        -:  212:    if (dbg_ifname < 0) {
        -:  213:	int rc;
        -:  214:	rc = MPIU_GetEnvBool( "MPICH_DBG_IFNAME", &dbg_ifname );
        -:  215:	if (rc != 1) dbg_ifname = 0;
        -:  216:    }
        -:  217:
        -:  218:    fd = socket(AF_INET, SOCK_DGRAM, 0);
        -:  219:    if (fd < 0) {
        -:  220:	fprintf( stderr, "Unable to open an AF_INET socket\n" );
        -:  221:	return 1;
        -:  222:    }
        -:  223:
        -:  224:    /* Use MSB localhost if necessary */
        -:  225:#ifdef WORDS_BIGENDIAN
        -:  226:    localhost = MSBlocalhost;
        -:  227:#endif
        -:  228:    
        -:  229:
        -:  230:    /*
        -:  231:     * Obtain the interface information from the operating system
        -:  232:     *
        -:  233:     * Note: much of this code is borrowed from W. Richard Stevens' book
        -:  234:     * entitled "UNIX Network Programming", Volume 1, Second Edition.  See
        -:  235:     * section 16.6 for details.
        -:  236:     */
        -:  237:    buf_len = NUM_IFREQS * sizeof(struct ifreq);
        -:  238:    buf_len_prev = 0;
        -:  239:
        -:  240:    for(;;)
        -:  241:    {
        -:  242:	struct ifconf			ifconf;
        -:  243:	int				rc;
        -:  244:
        -:  245:	buf_ptr = (char *) MPIU_Malloc(buf_len);
        -:  246:	if (buf_ptr == NULL) {
        -:  247:	    fprintf( stderr, "Unable to allocate %d bytes\n", buf_len );
        -:  248:	    return 1;
        -:  249:	}
        -:  250:	
        -:  251:	ifconf.ifc_buf = buf_ptr;
        -:  252:	ifconf.ifc_len = buf_len;
        -:  253:
        -:  254:	rc = ioctl(fd, SIOCGIFCONF, &ifconf);
        -:  255:	if (rc < 0) {
        -:  256:	    if (errno != EINVAL || buf_len_prev != 0) {
        -:  257:		fprintf( stderr, "Error from ioctl = %d\n", errno );
        -:  258:		perror(" Error is: ");
        -:  259:		return 1;
        -:  260:	    }
        -:  261:	}
        -:  262:        else {
        -:  263:	    if (ifconf.ifc_len == buf_len_prev) {
        -:  264:		buf_len = ifconf.ifc_len;
        -:  265:		break;
        -:  266:	    }
        -:  267:
        -:  268:	    buf_len_prev = ifconf.ifc_len;
        -:  269:	}
        -:  270:	
        -:  271:	MPIU_Free(buf_ptr);
        -:  272:	buf_len += NUM_IFREQS * sizeof(struct ifreq);
        -:  273:    }
        -:  274:	
        -:  275:    /*
        -:  276:     * Now that we've got the interface information, we need to run through
        -:  277:     * the interfaces and check out the ip addresses.  If we find a
        -:  278:     * unique, non-lcoal host (127.0.0.1) address, return that, otherwise
        -:  279:     * return nothing.
        -:  280:     */
        -:  281:    ptr = buf_ptr;
        -:  282:
        -:  283:    while(ptr < buf_ptr + buf_len) {
        -:  284:	struct ifreq *			ifreq;
        -:  285:
        -:  286:	ifreq = (struct ifreq *) ptr;
        -:  287:
        -:  288:	if (dbg_ifname) {
        -:  289:	    fprintf( stdout, "%10s\t", ifreq->ifr_name ); fflush(stdout);
        -:  290:	}
        -:  291:	
        -:  292:	if (ifreq->ifr_addr.sa_family == AF_INET) {
        -:  293:	    struct in_addr		addr;
        -:  294:
        -:  295:	    addr = ((struct sockaddr_in *) &(ifreq->ifr_addr))->sin_addr;
        -:  296:	    if (dbg_ifname) {
        -:  297:		fprintf( stdout, "IPv4 address = %08x (%s)\n", addr.s_addr, 
        -:  298:			 inet_ntoa( addr ) );
        -:  299:	    }
        -:  300:
        -:  301:	    if (addr.s_addr == localhost && dbg_ifname) {
        -:  302:		fprintf( stdout, "Found local host\n" );
        -:  303:	    }
        -:  304:	    /* Save localhost if we find it.  Let any new interface 
        -:  305:	       overwrite localhost.  However, if we find more than 
        -:  306:	       one non-localhost interface, then we'll choose none for the 
        -:  307:	       interfaces */
        -:  308:	    if (addr.s_addr == localhost) {
        -:  309:		foundLocalhost = 1;
        -:  310:		if (nfound == 0) {
        -:  311:		    myifaddr.type = AF_INET;
        -:  312:		    myifaddr.len  = 4;
        -:  313:		    MPIU_Memcpy( myifaddr.ifaddr, &addr.s_addr, 4 );
        -:  314:		}
        -:  315:	    }
        -:  316:	    else {
        -:  317:		nfound++;
        -:  318:		myifaddr.type = AF_INET;
        -:  319:		myifaddr.len  = 4;
        -:  320:		MPIU_Memcpy( myifaddr.ifaddr, &addr.s_addr, 4 );
        -:  321:	    }
        -:  322:	}
        -:  323:	else {
        -:  324:	    if (dbg_ifname) {
        -:  325:		fprintf( stdout, "\n" );
        -:  326:	    }
        -:  327:	}
        -:  328:
        -:  329:	/*
        -:  330:	 *  Increment pointer to the next ifreq; some adjustment may be
        -:  331:	 *  required if the address is an IPv6 address
        -:  332:	 */
        -:  333:	/* This is needed for MAX OSX */
        -:  334:#ifdef _SIZEOF_ADDR_IFREQ
        -:  335:	ptr += _SIZEOF_ADDR_IFREQ(*ifreq);
        -:  336:#else
        -:  337:	ptr += sizeof(struct ifreq);
        -:  338:	
        -:  339:#	if defined(AF_INET6)
        -:  340:	{
        -:  341:	    if (ifreq->ifr_addr.sa_family == AF_INET6)
        -:  342:	    {
        -:  343:		ptr += sizeof(struct sockaddr_in6) - sizeof(struct sockaddr);
        -:  344:	    }
        -:  345:	}
        -:  346:#	endif
        -:  347:#endif
        -:  348:    }
        -:  349:
        -:  350:    MPIU_Free(buf_ptr);
        -:  351:    close(fd);
        -:  352:    
        -:  353:    /* If we found a unique address, use that */
        -:  354:    if (nfound == 1 || (nfound == 0 && foundLocalhost == 1)) {
        -:  355:	*ifaddr = myifaddr;
        -:  356:	*found  = 1;
        -:  357:    }
        -:  358:    else {
        -:  359:	*found  = 0;
        -:  360:    }
        -:  361:
        -:  362:    return 0;
        -:  363:}
        -:  364:
        -:  365:#else /* things needed to find the interfaces */
        -:  366:
        -:  367:/* In this case, just return false for interfaces found */
        -:  368:static int MPIDI_CH3U_GetIPInterface( MPIDU_Sock_ifaddr_t *ifaddr, int *found )
    #####:  369:{
    #####:  370:    *found = 0;
    #####:  371:    return 0;
        -:  372:}
        -:  373:#endif