root/opal/mca/pmix/pmix4x/pmix/src/mca/ptl/base/ptl_base_connect.c

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

DEFINITIONS

This source file includes following definitions.
  1. pmix_ptl_base_set_nonblocking
  2. pmix_ptl_base_set_blocking
  3. pmix_ptl_base_send_blocking
  4. pmix_ptl_base_recv_blocking
  5. pmix_ptl_base_connect

   1 /*
   2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
   3  *                         University Research and Technology
   4  *                         Corporation.  All rights reserved.
   5  * Copyright (c) 2004-2006 The University of Tennessee and The University
   6  *                         of Tennessee Research Foundation.  All rights
   7  *                         reserved.
   8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
   9  *                         University of Stuttgart.  All rights reserved.
  10  * Copyright (c) 2004-2005 The Regents of the University of California.
  11  *                         All rights reserved.
  12  * Copyright (c) 2015-2017 Intel, Inc. All rights reserved.
  13  * $COPYRIGHT$
  14  *
  15  * Additional copyrights may follow
  16  *
  17  * $HEADER$
  18  */
  19 
  20 #include <src/include/pmix_config.h>
  21 #include "include/pmix_stdint.h"
  22 
  23 #include <stdio.h>
  24 #ifdef HAVE_UNISTD_H
  25 #include <unistd.h>
  26 #endif
  27 #ifdef HAVE_FCNTL_H
  28 #include <fcntl.h>
  29 #endif
  30 #ifdef HAVE_SYS_SOCKET_H
  31 #include <sys/socket.h>
  32 #endif
  33 
  34 #include "include/pmix_socket_errno.h"
  35 #include "src/util/argv.h"
  36 #include "src/util/error.h"
  37 #include "src/util/getid.h"
  38 #include "src/util/strnlen.h"
  39 #include "src/include/pmix_globals.h"
  40 #include "src/client/pmix_client_ops.h"
  41 #include "src/server/pmix_server_ops.h"
  42 
  43 #include "src/mca/ptl/base/base.h"
  44 
  45 pmix_status_t pmix_ptl_base_set_nonblocking(int sd)
  46 {
  47     int flags;
  48      /* setup the socket as non-blocking */
  49     if ((flags = fcntl(sd, F_GETFL, 0)) < 0) {
  50         pmix_output(0, "ptl:base:set_nonblocking: fcntl(F_GETFL) failed: %s (%d)\n",
  51                     strerror(pmix_socket_errno),
  52                     pmix_socket_errno);
  53     } else {
  54         flags |= O_NONBLOCK;
  55         if(fcntl(sd, F_SETFL, flags) < 0)
  56             pmix_output(0, "ptl:base:set_nonblocking: fcntl(F_SETFL) failed: %s (%d)\n",
  57                         strerror(pmix_socket_errno),
  58                         pmix_socket_errno);
  59     }
  60     return PMIX_SUCCESS;
  61 }
  62 
  63 pmix_status_t pmix_ptl_base_set_blocking(int sd)
  64 {
  65     int flags;
  66      /* setup the socket as non-blocking */
  67     if ((flags = fcntl(sd, F_GETFL, 0)) < 0) {
  68         pmix_output(0, "ptl:base:set_blocking: fcntl(F_GETFL) failed: %s (%d)\n",
  69                     strerror(pmix_socket_errno),
  70                     pmix_socket_errno);
  71     } else {
  72         flags &= ~(O_NONBLOCK);
  73         if(fcntl(sd, F_SETFL, flags) < 0)
  74             pmix_output(0, "ptl:base:set_blocking: fcntl(F_SETFL) failed: %s (%d)\n",
  75                         strerror(pmix_socket_errno),
  76                         pmix_socket_errno);
  77     }
  78     return PMIX_SUCCESS;
  79 }
  80 
  81 /*
  82  * A blocking send on a non-blocking socket. Used to send the small amount of connection
  83  * information that identifies the peers endpoint.
  84  */
  85 pmix_status_t pmix_ptl_base_send_blocking(int sd, char *ptr, size_t size)
  86 {
  87     size_t cnt = 0;
  88     int retval;
  89 
  90     pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
  91                         "send blocking of %"PRIsize_t" bytes to socket %d",
  92                         size, sd );
  93     while (cnt < size) {
  94         retval = send(sd, (char*)ptr+cnt, size-cnt, 0);
  95         if (retval < 0) {
  96             if (EAGAIN == pmix_socket_errno ||
  97                 EWOULDBLOCK == pmix_socket_errno) {
  98                 /* just cycle and let it try again */
  99                 pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 100                                     "blocking_send received error %d:%s from remote - cycling",
 101                                     pmix_socket_errno, strerror(pmix_socket_errno));
 102                 continue;
 103             }
 104             if (pmix_socket_errno != EINTR) {
 105                 pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 106                                     "ptl:base:peer_send_blocking: send() to socket %d failed: %s (%d)\n",
 107                                     sd, strerror(pmix_socket_errno),
 108                                     pmix_socket_errno);
 109                 return PMIX_ERR_UNREACH;
 110             }
 111             continue;
 112         }
 113         cnt += retval;
 114     }
 115 
 116     pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 117                         "blocking send complete to socket %d", sd);
 118     return PMIX_SUCCESS;
 119 }
 120 
 121 /*
 122  * A blocking recv on a non-blocking socket. Used to receive the small amount of connection
 123  * information that identifies the peers endpoint.
 124  */
 125 pmix_status_t pmix_ptl_base_recv_blocking(int sd, char *data, size_t size)
 126 {
 127     size_t cnt = 0;
 128 
 129     pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 130                         "waiting for blocking recv of %"PRIsize_t" bytes", size);
 131 
 132     while (cnt < size) {
 133         int retval = recv(sd, (char *)data+cnt, size-cnt, MSG_WAITALL);
 134 
 135         /* remote closed connection */
 136         if (retval == 0) {
 137             pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 138                                 "ptl:base:recv_blocking: remote closed connection");
 139             return PMIX_ERR_UNREACH;
 140         }
 141 
 142         /* handle errors */
 143         if (retval < 0) {
 144             if (EAGAIN == pmix_socket_errno ||
 145                 EWOULDBLOCK == pmix_socket_errno) {
 146                 /* just cycle and let it try again */
 147                 pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 148                                     "blocking_recv received error %d:%s from remote - cycling",
 149                                     pmix_socket_errno, strerror(pmix_socket_errno));
 150                 return PMIX_ERR_TEMP_UNAVAILABLE;
 151             }
 152             if (pmix_socket_errno != EINTR ) {
 153                 /* If we overflow the listen backlog, it's
 154                    possible that even though we finished the three
 155                    way handshake, the remote host was unable to
 156                    transition the connection from half connected
 157                    (received the initial SYN) to fully connected
 158                    (in the listen backlog).  We likely won't see
 159                    the failure until we try to receive, due to
 160                    timing and the like.  The first thing we'll get
 161                    in that case is a RST packet, which receive
 162                    will turn into a connection reset by peer
 163                    errno.  In that case, leave the socket in
 164                    CONNECT_ACK and propogate the error up to
 165                    recv_connect_ack, who will try to establish the
 166                    connection again */
 167                 pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 168                                     "blocking_recv received error %d:%s from remote - aborting",
 169                                     pmix_socket_errno, strerror(pmix_socket_errno));
 170                 return PMIX_ERR_UNREACH;
 171             }
 172             continue;
 173         }
 174         cnt += retval;
 175     }
 176 
 177     pmix_output_verbose(8, pmix_ptl_base_framework.framework_output,
 178                         "blocking receive complete from remote");
 179     return PMIX_SUCCESS;
 180 }
 181 
 182 #define PMIX_MAX_RETRIES 10
 183 
 184 pmix_status_t pmix_ptl_base_connect(struct sockaddr_storage *addr,
 185                                     pmix_socklen_t addrlen, int *fd)
 186 {
 187     int sd = -1;
 188     int retries = 0;
 189 
 190     pmix_output_verbose(2, pmix_ptl_base_framework.framework_output,
 191                         "ptl_base_connect: attempting to connect to server");
 192 
 193     while (retries < PMIX_MAX_RETRIES) {
 194         retries++;
 195         /* Create the new socket */
 196         sd = socket(addr->ss_family, SOCK_STREAM, 0);
 197         if (sd < 0) {
 198             pmix_output(0, "pmix:create_socket: socket() failed: %s (%d)\n",
 199                         strerror(pmix_socket_errno),
 200                         pmix_socket_errno);
 201             continue;
 202         }
 203         pmix_output_verbose(2, pmix_ptl_base_framework.framework_output,
 204                             "pmix_ptl_base_connect: attempting to connect to server on socket %d", sd);
 205         /* try to connect */
 206         if (connect(sd, (struct sockaddr*)addr, addrlen) < 0) {
 207             if (pmix_socket_errno == ETIMEDOUT) {
 208                 /* The server may be too busy to accept new connections */
 209                 pmix_output_verbose(2, pmix_ptl_base_framework.framework_output,
 210                                     "timeout connecting to server");
 211                 CLOSE_THE_SOCKET(sd);
 212                 continue;
 213             }
 214 
 215             /* Some kernels (Linux 2.6) will automatically software
 216              abort a connection that was ECONNREFUSED on the last
 217              attempt, without even trying to establish the
 218              connection.  Handle that case in a semi-rational
 219              way by trying twice before giving up */
 220             if (ECONNABORTED == pmix_socket_errno) {
 221                 pmix_output_verbose(2, pmix_ptl_base_framework.framework_output,
 222                                     "connection to server aborted by OS - retrying");
 223                 CLOSE_THE_SOCKET(sd);
 224                 continue;
 225             } else {
 226                 pmix_output_verbose(2, pmix_ptl_base_framework.framework_output,
 227                                     "Connect failed: %s (%d)", strerror(pmix_socket_errno),
 228                                     pmix_socket_errno);
 229                 CLOSE_THE_SOCKET(sd);
 230                 continue;
 231             }
 232         } else {
 233             /* otherwise, the connect succeeded - so break out of the loop */
 234             break;
 235         }
 236     }
 237 
 238     if (retries == PMIX_MAX_RETRIES || sd < 0){
 239         /* We were unsuccessful in establishing this connection, and are
 240          * not likely to suddenly become successful */
 241         if (0 <= sd) {
 242             CLOSE_THE_SOCKET(sd);
 243         }
 244         return PMIX_ERR_UNREACH;
 245     }
 246     *fd = sd;
 247 
 248     return PMIX_SUCCESS;
 249 }

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