LCOV - code coverage report
Current view: top level - common - remote.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 519 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 23 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2008-2024 the Pacemaker project contributors
       3             :  *
       4             :  * The version control history for this file may have further details.
       5             :  *
       6             :  * This source code is licensed under the GNU Lesser General Public License
       7             :  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
       8             :  */
       9             : 
      10             : #include <crm_internal.h>
      11             : #include <crm/crm.h>
      12             : 
      13             : #include <sys/param.h>
      14             : #include <stdio.h>
      15             : #include <sys/types.h>
      16             : #include <sys/stat.h>
      17             : #include <unistd.h>
      18             : #include <sys/socket.h>
      19             : #include <arpa/inet.h>
      20             : #include <netinet/in.h>
      21             : #include <netinet/ip.h>
      22             : #include <netinet/tcp.h>
      23             : #include <netdb.h>
      24             : #include <stdlib.h>
      25             : #include <errno.h>
      26             : #include <inttypes.h>   // PRIx32
      27             : 
      28             : #include <glib.h>
      29             : #include <bzlib.h>
      30             : 
      31             : #include <crm/common/ipc_internal.h>
      32             : #include <crm/common/xml.h>
      33             : #include <crm/common/mainloop.h>
      34             : #include <crm/common/remote_internal.h>
      35             : 
      36             : #ifdef HAVE_GNUTLS_GNUTLS_H
      37             : #  include <gnutls/gnutls.h>
      38             : #endif
      39             : 
      40             : /* Swab macros from linux/swab.h */
      41             : #ifdef HAVE_LINUX_SWAB_H
      42             : #  include <linux/swab.h>
      43             : #else
      44             : /*
      45             :  * casts are necessary for constants, because we never know how for sure
      46             :  * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
      47             :  */
      48             : #define __swab16(x) ((uint16_t)(                                      \
      49             :         (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) |                  \
      50             :         (((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))
      51             : 
      52             : #define __swab32(x) ((uint32_t)(                                      \
      53             :         (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) |            \
      54             :         (((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) |            \
      55             :         (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) |            \
      56             :         (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
      57             : 
      58             : #define __swab64(x) ((uint64_t)(                                      \
      59             :         (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) |   \
      60             :         (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) |   \
      61             :         (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) |   \
      62             :         (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) <<  8) |   \
      63             :         (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >>  8) |   \
      64             :         (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) |   \
      65             :         (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) |   \
      66             :         (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56)))
      67             : #endif
      68             : 
      69             : #define REMOTE_MSG_VERSION 1
      70             : #define ENDIAN_LOCAL 0xBADADBBD
      71             : 
      72             : struct remote_header_v0 {
      73             :     uint32_t endian;    /* Detect messages from hosts with different endian-ness */
      74             :     uint32_t version;
      75             :     uint64_t id;
      76             :     uint64_t flags;
      77             :     uint32_t size_total;
      78             :     uint32_t payload_offset;
      79             :     uint32_t payload_compressed;
      80             :     uint32_t payload_uncompressed;
      81             : 
      82             :         /* New fields get added here */
      83             : 
      84             : } __attribute__ ((packed));
      85             : 
      86             : /*!
      87             :  * \internal
      88             :  * \brief Retrieve remote message header, in local endianness
      89             :  *
      90             :  * Return a pointer to the header portion of a remote connection's message
      91             :  * buffer, converting the header to local endianness if needed.
      92             :  *
      93             :  * \param[in,out] remote  Remote connection with new message
      94             :  *
      95             :  * \return Pointer to message header, localized if necessary
      96             :  */
      97             : static struct remote_header_v0 *
      98           0 : localized_remote_header(pcmk__remote_t *remote)
      99             : {
     100           0 :     struct remote_header_v0 *header = (struct remote_header_v0 *)remote->buffer;
     101           0 :     if(remote->buffer_offset < sizeof(struct remote_header_v0)) {
     102           0 :         return NULL;
     103             : 
     104           0 :     } else if(header->endian != ENDIAN_LOCAL) {
     105           0 :         uint32_t endian = __swab32(header->endian);
     106             : 
     107           0 :         CRM_LOG_ASSERT(endian == ENDIAN_LOCAL);
     108           0 :         if(endian != ENDIAN_LOCAL) {
     109           0 :             crm_err("Invalid message detected, endian mismatch: %" PRIx32
     110             :                     " is neither %" PRIx32 " nor the swab'd %" PRIx32,
     111             :                     ENDIAN_LOCAL, header->endian, endian);
     112           0 :             return NULL;
     113             :         }
     114             : 
     115           0 :         header->id = __swab64(header->id);
     116           0 :         header->flags = __swab64(header->flags);
     117           0 :         header->endian = __swab32(header->endian);
     118             : 
     119           0 :         header->version = __swab32(header->version);
     120           0 :         header->size_total = __swab32(header->size_total);
     121           0 :         header->payload_offset = __swab32(header->payload_offset);
     122           0 :         header->payload_compressed = __swab32(header->payload_compressed);
     123           0 :         header->payload_uncompressed = __swab32(header->payload_uncompressed);
     124             :     }
     125             : 
     126           0 :     return header;
     127             : }
     128             : 
     129             : #ifdef HAVE_GNUTLS_GNUTLS_H
     130             : 
     131             : int
     132           0 : pcmk__tls_client_handshake(pcmk__remote_t *remote, int timeout_ms)
     133             : {
     134           0 :     int rc = 0;
     135           0 :     int pollrc = 0;
     136           0 :     time_t time_limit = time(NULL) + timeout_ms / 1000;
     137             : 
     138             :     do {
     139           0 :         rc = gnutls_handshake(*remote->tls_session);
     140           0 :         if ((rc == GNUTLS_E_INTERRUPTED) || (rc == GNUTLS_E_AGAIN)) {
     141           0 :             pollrc = pcmk__remote_ready(remote, 1000);
     142           0 :             if ((pollrc != pcmk_rc_ok) && (pollrc != ETIME)) {
     143             :                 /* poll returned error, there is no hope */
     144           0 :                 crm_trace("TLS handshake poll failed: %s (%d)",
     145             :                           pcmk_strerror(pollrc), pollrc);
     146           0 :                 return pcmk_legacy2rc(pollrc);
     147             :             }
     148           0 :         } else if (rc < 0) {
     149           0 :             crm_trace("TLS handshake failed: %s (%d)",
     150             :                       gnutls_strerror(rc), rc);
     151           0 :             return EPROTO;
     152             :         } else {
     153           0 :             return pcmk_rc_ok;
     154             :         }
     155           0 :     } while (time(NULL) < time_limit);
     156           0 :     return ETIME;
     157             : }
     158             : 
     159             : /*!
     160             :  * \internal
     161             :  * \brief Set minimum prime size required by TLS client
     162             :  *
     163             :  * \param[in] session  TLS session to affect
     164             :  */
     165             : static void
     166           0 : set_minimum_dh_bits(const gnutls_session_t *session)
     167             : {
     168             :     int dh_min_bits;
     169             : 
     170           0 :     pcmk__scan_min_int(pcmk__env_option(PCMK__ENV_DH_MIN_BITS), &dh_min_bits,
     171             :                        0);
     172             : 
     173             :     /* This function is deprecated since GnuTLS 3.1.7, in favor of letting
     174             :      * the priority string imply the DH requirements, but this is the only
     175             :      * way to give the user control over compatibility with older servers.
     176             :      */
     177           0 :     if (dh_min_bits > 0) {
     178           0 :         crm_info("Requiring server use a Diffie-Hellman prime of at least %d bits",
     179             :                  dh_min_bits);
     180           0 :         gnutls_dh_set_prime_bits(*session, dh_min_bits);
     181             :     }
     182           0 : }
     183             : 
     184             : static unsigned int
     185           0 : get_bound_dh_bits(unsigned int dh_bits)
     186             : {
     187             :     int dh_min_bits;
     188             :     int dh_max_bits;
     189             : 
     190           0 :     pcmk__scan_min_int(pcmk__env_option(PCMK__ENV_DH_MIN_BITS), &dh_min_bits,
     191             :                        0);
     192           0 :     pcmk__scan_min_int(pcmk__env_option(PCMK__ENV_DH_MAX_BITS), &dh_max_bits,
     193             :                        0);
     194             : 
     195           0 :     if ((dh_max_bits > 0) && (dh_max_bits < dh_min_bits)) {
     196           0 :         crm_warn("Ignoring PCMK_dh_max_bits less than PCMK_dh_min_bits");
     197           0 :         dh_max_bits = 0;
     198             :     }
     199           0 :     if ((dh_min_bits > 0) && (dh_bits < dh_min_bits)) {
     200           0 :         return dh_min_bits;
     201             :     }
     202           0 :     if ((dh_max_bits > 0) && (dh_bits > dh_max_bits)) {
     203           0 :         return dh_max_bits;
     204             :     }
     205           0 :     return dh_bits;
     206             : }
     207             : 
     208             : /*!
     209             :  * \internal
     210             :  * \brief Initialize a new TLS session
     211             :  *
     212             :  * \param[in] csock       Connected socket for TLS session
     213             :  * \param[in] conn_type   GNUTLS_SERVER or GNUTLS_CLIENT
     214             :  * \param[in] cred_type   GNUTLS_CRD_ANON or GNUTLS_CRD_PSK
     215             :  * \param[in] credentials TLS session credentials
     216             :  *
     217             :  * \return Pointer to newly created session object, or NULL on error
     218             :  */
     219             : gnutls_session_t *
     220           0 : pcmk__new_tls_session(int csock, unsigned int conn_type,
     221             :                       gnutls_credentials_type_t cred_type, void *credentials)
     222             : {
     223           0 :     int rc = GNUTLS_E_SUCCESS;
     224           0 :     const char *prio_base = NULL;
     225           0 :     char *prio = NULL;
     226           0 :     gnutls_session_t *session = NULL;
     227             : 
     228             :     /* Determine list of acceptable ciphers, etc. Pacemaker always adds the
     229             :      * values required for its functionality.
     230             :      *
     231             :      * For an example of anonymous authentication, see:
     232             :      * http://www.manpagez.com/info/gnutls/gnutls-2.10.4/gnutls_81.php#Echo-Server-with-anonymous-authentication
     233             :      */
     234             : 
     235           0 :     prio_base = pcmk__env_option(PCMK__ENV_TLS_PRIORITIES);
     236           0 :     if (prio_base == NULL) {
     237           0 :         prio_base = PCMK_GNUTLS_PRIORITIES;
     238             :     }
     239           0 :     prio = crm_strdup_printf("%s:%s", prio_base,
     240             :                              (cred_type == GNUTLS_CRD_ANON)? "+ANON-DH" : "+DHE-PSK:+PSK");
     241             : 
     242           0 :     session = gnutls_malloc(sizeof(gnutls_session_t));
     243           0 :     if (session == NULL) {
     244           0 :         rc = GNUTLS_E_MEMORY_ERROR;
     245           0 :         goto error;
     246             :     }
     247             : 
     248           0 :     rc = gnutls_init(session, conn_type);
     249           0 :     if (rc != GNUTLS_E_SUCCESS) {
     250           0 :         goto error;
     251             :     }
     252             : 
     253             :     /* @TODO On the server side, it would be more efficient to cache the
     254             :      * priority with gnutls_priority_init2() and set it with
     255             :      * gnutls_priority_set() for all sessions.
     256             :      */
     257           0 :     rc = gnutls_priority_set_direct(*session, prio, NULL);
     258           0 :     if (rc != GNUTLS_E_SUCCESS) {
     259           0 :         goto error;
     260             :     }
     261           0 :     if (conn_type == GNUTLS_CLIENT) {
     262           0 :         set_minimum_dh_bits(session);
     263             :     }
     264             : 
     265           0 :     gnutls_transport_set_ptr(*session,
     266           0 :                              (gnutls_transport_ptr_t) GINT_TO_POINTER(csock));
     267             : 
     268           0 :     rc = gnutls_credentials_set(*session, cred_type, credentials);
     269           0 :     if (rc != GNUTLS_E_SUCCESS) {
     270           0 :         goto error;
     271             :     }
     272           0 :     free(prio);
     273           0 :     return session;
     274             : 
     275           0 : error:
     276           0 :     crm_err("Could not initialize %s TLS %s session: %s "
     277             :             CRM_XS " rc=%d priority='%s'",
     278             :             (cred_type == GNUTLS_CRD_ANON)? "anonymous" : "PSK",
     279             :             (conn_type == GNUTLS_SERVER)? "server" : "client",
     280             :             gnutls_strerror(rc), rc, prio);
     281           0 :     free(prio);
     282           0 :     if (session != NULL) {
     283           0 :         gnutls_free(session);
     284             :     }
     285           0 :     return NULL;
     286             : }
     287             : 
     288             : /*!
     289             :  * \internal
     290             :  * \brief Initialize Diffie-Hellman parameters for a TLS server
     291             :  *
     292             :  * \param[out] dh_params  Parameter object to initialize
     293             :  *
     294             :  * \return Standard Pacemaker return code
     295             :  * \todo The current best practice is to allow the client and server to
     296             :  *       negotiate the Diffie-Hellman parameters via a TLS extension (RFC 7919).
     297             :  *       However, we have to support both older versions of GnuTLS (<3.6) that
     298             :  *       don't support the extension on our side, and older Pacemaker versions
     299             :  *       that don't support the extension on the other side. The next best
     300             :  *       practice would be to use a known good prime (see RFC 5114 section 2.2),
     301             :  *       possibly stored in a file distributed with Pacemaker.
     302             :  */
     303             : int
     304           0 : pcmk__init_tls_dh(gnutls_dh_params_t *dh_params)
     305             : {
     306           0 :     int rc = GNUTLS_E_SUCCESS;
     307           0 :     unsigned int dh_bits = 0;
     308             : 
     309           0 :     rc = gnutls_dh_params_init(dh_params);
     310           0 :     if (rc != GNUTLS_E_SUCCESS) {
     311           0 :         goto error;
     312             :     }
     313             : 
     314           0 :     dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
     315             :                                           GNUTLS_SEC_PARAM_NORMAL);
     316           0 :     if (dh_bits == 0) {
     317           0 :         rc = GNUTLS_E_DH_PRIME_UNACCEPTABLE;
     318           0 :         goto error;
     319             :     }
     320           0 :     dh_bits = get_bound_dh_bits(dh_bits);
     321             : 
     322           0 :     crm_info("Generating Diffie-Hellman parameters with %u-bit prime for TLS",
     323             :              dh_bits);
     324           0 :     rc = gnutls_dh_params_generate2(*dh_params, dh_bits);
     325           0 :     if (rc != GNUTLS_E_SUCCESS) {
     326           0 :         goto error;
     327             :     }
     328             : 
     329           0 :     return pcmk_rc_ok;
     330             : 
     331           0 : error:
     332           0 :     crm_err("Could not initialize Diffie-Hellman parameters for TLS: %s "
     333             :             CRM_XS " rc=%d", gnutls_strerror(rc), rc);
     334           0 :     return EPROTO;
     335             : }
     336             : 
     337             : /*!
     338             :  * \internal
     339             :  * \brief Process handshake data from TLS client
     340             :  *
     341             :  * Read as much TLS handshake data as is available.
     342             :  *
     343             :  * \param[in] client  Client connection
     344             :  *
     345             :  * \return Standard Pacemaker return code (of particular interest, EAGAIN
     346             :  *         if some data was successfully read but more data is needed)
     347             :  */
     348             : int
     349           0 : pcmk__read_handshake_data(const pcmk__client_t *client)
     350             : {
     351           0 :     int rc = 0;
     352             : 
     353           0 :     CRM_ASSERT(client && client->remote && client->remote->tls_session);
     354             : 
     355             :     do {
     356           0 :         rc = gnutls_handshake(*client->remote->tls_session);
     357           0 :     } while (rc == GNUTLS_E_INTERRUPTED);
     358             : 
     359           0 :     if (rc == GNUTLS_E_AGAIN) {
     360             :         /* No more data is available at the moment. This function should be
     361             :          * invoked again once the client sends more.
     362             :          */
     363           0 :         return EAGAIN;
     364           0 :     } else if (rc != GNUTLS_E_SUCCESS) {
     365           0 :         crm_err("TLS handshake with remote client failed: %s "
     366             :                 CRM_XS " rc=%d", gnutls_strerror(rc), rc);
     367           0 :         return EPROTO;
     368             :     }
     369           0 :     return pcmk_rc_ok;
     370             : }
     371             : 
     372             : // \return Standard Pacemaker return code
     373             : static int
     374           0 : send_tls(gnutls_session_t *session, struct iovec *iov)
     375             : {
     376           0 :     const char *unsent = iov->iov_base;
     377           0 :     size_t unsent_len = iov->iov_len;
     378             :     ssize_t gnutls_rc;
     379             : 
     380           0 :     if (unsent == NULL) {
     381           0 :         return EINVAL;
     382             :     }
     383             : 
     384           0 :     crm_trace("Sending TLS message of %llu bytes",
     385             :               (unsigned long long) unsent_len);
     386             :     while (true) {
     387           0 :         gnutls_rc = gnutls_record_send(*session, unsent, unsent_len);
     388             : 
     389           0 :         if (gnutls_rc == GNUTLS_E_INTERRUPTED || gnutls_rc == GNUTLS_E_AGAIN) {
     390           0 :             crm_trace("Retrying to send %llu bytes remaining",
     391             :                       (unsigned long long) unsent_len);
     392             : 
     393           0 :         } else if (gnutls_rc < 0) {
     394             :             // Caller can log as error if necessary
     395           0 :             crm_info("TLS connection terminated: %s " CRM_XS " rc=%lld",
     396             :                      gnutls_strerror((int) gnutls_rc),
     397             :                      (long long) gnutls_rc);
     398           0 :             return ECONNABORTED;
     399             : 
     400           0 :         } else if (gnutls_rc < unsent_len) {
     401           0 :             crm_trace("Sent %lld of %llu bytes remaining",
     402             :                       (long long) gnutls_rc, (unsigned long long) unsent_len);
     403           0 :             unsent_len -= gnutls_rc;
     404           0 :             unsent += gnutls_rc;
     405             :         } else {
     406           0 :             crm_trace("Sent all %lld bytes remaining", (long long) gnutls_rc);
     407           0 :             break;
     408             :         }
     409             :     }
     410           0 :     return pcmk_rc_ok;
     411             : }
     412             : #endif
     413             : 
     414             : // \return Standard Pacemaker return code
     415             : static int
     416           0 : send_plaintext(int sock, struct iovec *iov)
     417             : {
     418           0 :     const char *unsent = iov->iov_base;
     419           0 :     size_t unsent_len = iov->iov_len;
     420             :     ssize_t write_rc;
     421             : 
     422           0 :     if (unsent == NULL) {
     423           0 :         return EINVAL;
     424             :     }
     425             : 
     426           0 :     crm_debug("Sending plaintext message of %llu bytes to socket %d",
     427             :               (unsigned long long) unsent_len, sock);
     428             :     while (true) {
     429           0 :         write_rc = write(sock, unsent, unsent_len);
     430           0 :         if (write_rc < 0) {
     431           0 :             int rc = errno;
     432             : 
     433           0 :             if ((errno == EINTR) || (errno == EAGAIN)) {
     434           0 :                 crm_trace("Retrying to send %llu bytes remaining to socket %d",
     435             :                           (unsigned long long) unsent_len, sock);
     436           0 :                 continue;
     437             :             }
     438             : 
     439             :             // Caller can log as error if necessary
     440           0 :             crm_info("Could not send message: %s " CRM_XS " rc=%d socket=%d",
     441             :                      pcmk_rc_str(rc), rc, sock);
     442           0 :             return rc;
     443             : 
     444           0 :         } else if (write_rc < unsent_len) {
     445           0 :             crm_trace("Sent %lld of %llu bytes remaining",
     446             :                       (long long) write_rc, (unsigned long long) unsent_len);
     447           0 :             unsent += write_rc;
     448           0 :             unsent_len -= write_rc;
     449           0 :             continue;
     450             : 
     451             :         } else {
     452           0 :             crm_trace("Sent all %lld bytes remaining: %.100s",
     453             :                       (long long) write_rc, (char *) (iov->iov_base));
     454           0 :             break;
     455             :         }
     456             :     }
     457           0 :     return pcmk_rc_ok;
     458             : }
     459             : 
     460             : // \return Standard Pacemaker return code
     461             : static int
     462           0 : remote_send_iovs(pcmk__remote_t *remote, struct iovec *iov, int iovs)
     463             : {
     464           0 :     int rc = pcmk_rc_ok;
     465             : 
     466           0 :     for (int lpc = 0; (lpc < iovs) && (rc == pcmk_rc_ok); lpc++) {
     467             : #ifdef HAVE_GNUTLS_GNUTLS_H
     468           0 :         if (remote->tls_session) {
     469           0 :             rc = send_tls(remote->tls_session, &(iov[lpc]));
     470           0 :             continue;
     471             :         }
     472             : #endif
     473           0 :         if (remote->tcp_socket) {
     474           0 :             rc = send_plaintext(remote->tcp_socket, &(iov[lpc]));
     475             :         } else {
     476           0 :             rc = ESOCKTNOSUPPORT;
     477             :         }
     478             :     }
     479           0 :     return rc;
     480             : }
     481             : 
     482             : /*!
     483             :  * \internal
     484             :  * \brief Send an XML message over a Pacemaker Remote connection
     485             :  *
     486             :  * \param[in,out] remote  Pacemaker Remote connection to use
     487             :  * \param[in]     msg     XML to send
     488             :  *
     489             :  * \return Standard Pacemaker return code
     490             :  */
     491             : int
     492           0 : pcmk__remote_send_xml(pcmk__remote_t *remote, const xmlNode *msg)
     493             : {
     494           0 :     int rc = pcmk_rc_ok;
     495             :     static uint64_t id = 0;
     496           0 :     GString *xml_text = NULL;
     497             : 
     498             :     struct iovec iov[2];
     499             :     struct remote_header_v0 *header;
     500             : 
     501           0 :     CRM_CHECK((remote != NULL) && (msg != NULL), return EINVAL);
     502             : 
     503           0 :     xml_text = g_string_sized_new(1024);
     504           0 :     pcmk__xml_string(msg, 0, xml_text, 0);
     505           0 :     CRM_CHECK(xml_text->len > 0,
     506             :               g_string_free(xml_text, TRUE); return EINVAL);
     507             : 
     508           0 :     header = pcmk__assert_alloc(1, sizeof(struct remote_header_v0));
     509             : 
     510           0 :     iov[0].iov_base = header;
     511           0 :     iov[0].iov_len = sizeof(struct remote_header_v0);
     512             : 
     513           0 :     iov[1].iov_len = 1 + xml_text->len;
     514           0 :     iov[1].iov_base = g_string_free(xml_text, FALSE);
     515             : 
     516           0 :     id++;
     517           0 :     header->id = id;
     518           0 :     header->endian = ENDIAN_LOCAL;
     519           0 :     header->version = REMOTE_MSG_VERSION;
     520           0 :     header->payload_offset = iov[0].iov_len;
     521           0 :     header->payload_uncompressed = iov[1].iov_len;
     522           0 :     header->size_total = iov[0].iov_len + iov[1].iov_len;
     523             : 
     524           0 :     rc = remote_send_iovs(remote, iov, 2);
     525           0 :     if (rc != pcmk_rc_ok) {
     526           0 :         crm_err("Could not send remote message: %s " CRM_XS " rc=%d",
     527             :                 pcmk_rc_str(rc), rc);
     528             :     }
     529             : 
     530           0 :     free(iov[0].iov_base);
     531           0 :     g_free((gchar *) iov[1].iov_base);
     532           0 :     return rc;
     533             : }
     534             : 
     535             : /*!
     536             :  * \internal
     537             :  * \brief Obtain the XML from the currently buffered remote connection message
     538             :  *
     539             :  * \param[in,out] remote  Remote connection possibly with message available
     540             :  *
     541             :  * \return Newly allocated XML object corresponding to message data, or NULL
     542             :  * \note This effectively removes the message from the connection buffer.
     543             :  */
     544             : xmlNode *
     545           0 : pcmk__remote_message_xml(pcmk__remote_t *remote)
     546             : {
     547           0 :     xmlNode *xml = NULL;
     548           0 :     struct remote_header_v0 *header = localized_remote_header(remote);
     549             : 
     550           0 :     if (header == NULL) {
     551           0 :         return NULL;
     552             :     }
     553             : 
     554             :     /* Support compression on the receiving end now, in case we ever want to add it later */
     555           0 :     if (header->payload_compressed) {
     556           0 :         int rc = 0;
     557           0 :         unsigned int size_u = 1 + header->payload_uncompressed;
     558             :         char *uncompressed =
     559           0 :             pcmk__assert_alloc(1, header->payload_offset + size_u);
     560             : 
     561           0 :         crm_trace("Decompressing message data %d bytes into %d bytes",
     562             :                  header->payload_compressed, size_u);
     563             : 
     564           0 :         rc = BZ2_bzBuffToBuffDecompress(uncompressed + header->payload_offset, &size_u,
     565           0 :                                         remote->buffer + header->payload_offset,
     566             :                                         header->payload_compressed, 1, 0);
     567           0 :         rc = pcmk__bzlib2rc(rc);
     568             : 
     569           0 :         if (rc != pcmk_rc_ok && header->version > REMOTE_MSG_VERSION) {
     570           0 :             crm_warn("Couldn't decompress v%d message, we only understand v%d",
     571             :                      header->version, REMOTE_MSG_VERSION);
     572           0 :             free(uncompressed);
     573           0 :             return NULL;
     574             : 
     575           0 :         } else if (rc != pcmk_rc_ok) {
     576           0 :             crm_err("Decompression failed: %s " CRM_XS " rc=%d",
     577             :                     pcmk_rc_str(rc), rc);
     578           0 :             free(uncompressed);
     579           0 :             return NULL;
     580             :         }
     581             : 
     582           0 :         CRM_ASSERT(size_u == header->payload_uncompressed);
     583             : 
     584           0 :         memcpy(uncompressed, remote->buffer, header->payload_offset);       /* Preserve the header */
     585           0 :         remote->buffer_size = header->payload_offset + size_u;
     586             : 
     587           0 :         free(remote->buffer);
     588           0 :         remote->buffer = uncompressed;
     589           0 :         header = localized_remote_header(remote);
     590             :     }
     591             : 
     592             :     /* take ownership of the buffer */
     593           0 :     remote->buffer_offset = 0;
     594             : 
     595           0 :     CRM_LOG_ASSERT(remote->buffer[sizeof(struct remote_header_v0) + header->payload_uncompressed - 1] == 0);
     596             : 
     597           0 :     xml = pcmk__xml_parse(remote->buffer + header->payload_offset);
     598           0 :     if (xml == NULL && header->version > REMOTE_MSG_VERSION) {
     599           0 :         crm_warn("Couldn't parse v%d message, we only understand v%d",
     600             :                  header->version, REMOTE_MSG_VERSION);
     601             : 
     602           0 :     } else if (xml == NULL) {
     603           0 :         crm_err("Couldn't parse: '%.120s'", remote->buffer + header->payload_offset);
     604             :     }
     605             : 
     606           0 :     return xml;
     607             : }
     608             : 
     609             : static int
     610           0 : get_remote_socket(const pcmk__remote_t *remote)
     611             : {
     612             : #ifdef HAVE_GNUTLS_GNUTLS_H
     613           0 :     if (remote->tls_session) {
     614           0 :         void *sock_ptr = gnutls_transport_get_ptr(*remote->tls_session);
     615             : 
     616           0 :         return GPOINTER_TO_INT(sock_ptr);
     617             :     }
     618             : #endif
     619             : 
     620           0 :     if (remote->tcp_socket) {
     621           0 :         return remote->tcp_socket;
     622             :     }
     623             : 
     624           0 :     crm_err("Remote connection type undetermined (bug?)");
     625           0 :     return -1;
     626             : }
     627             : 
     628             : /*!
     629             :  * \internal
     630             :  * \brief Wait for a remote session to have data to read
     631             :  *
     632             :  * \param[in] remote      Connection to check
     633             :  * \param[in] timeout_ms  Maximum time (in ms) to wait
     634             :  *
     635             :  * \return Standard Pacemaker return code (of particular interest, pcmk_rc_ok if
     636             :  *         there is data ready to be read, and ETIME if there is no data within
     637             :  *         the specified timeout)
     638             :  */
     639             : int
     640           0 : pcmk__remote_ready(const pcmk__remote_t *remote, int timeout_ms)
     641             : {
     642           0 :     struct pollfd fds = { 0, };
     643           0 :     int sock = 0;
     644           0 :     int rc = 0;
     645             :     time_t start;
     646           0 :     int timeout = timeout_ms;
     647             : 
     648           0 :     sock = get_remote_socket(remote);
     649           0 :     if (sock <= 0) {
     650           0 :         crm_trace("No longer connected");
     651           0 :         return ENOTCONN;
     652             :     }
     653             : 
     654           0 :     start = time(NULL);
     655           0 :     errno = 0;
     656             :     do {
     657           0 :         fds.fd = sock;
     658           0 :         fds.events = POLLIN;
     659             : 
     660             :         /* If we got an EINTR while polling, and we have a
     661             :          * specific timeout we are trying to honor, attempt
     662             :          * to adjust the timeout to the closest second. */
     663           0 :         if (errno == EINTR && (timeout > 0)) {
     664           0 :             timeout = timeout_ms - ((time(NULL) - start) * 1000);
     665           0 :             if (timeout < 1000) {
     666           0 :                 timeout = 1000;
     667             :             }
     668             :         }
     669             : 
     670           0 :         rc = poll(&fds, 1, timeout);
     671           0 :     } while (rc < 0 && errno == EINTR);
     672             : 
     673           0 :     if (rc < 0) {
     674           0 :         return errno;
     675             :     }
     676           0 :     return (rc == 0)? ETIME : pcmk_rc_ok;
     677             : }
     678             : 
     679             : /*!
     680             :  * \internal
     681             :  * \brief Read bytes from non-blocking remote connection
     682             :  *
     683             :  * \param[in,out] remote  Remote connection to read
     684             :  *
     685             :  * \return Standard Pacemaker return code (of particular interest, pcmk_rc_ok if
     686             :  *         a full message has been received, or EAGAIN for a partial message)
     687             :  * \note Use only with non-blocking sockets after polling the socket.
     688             :  * \note This function will return when the socket read buffer is empty or an
     689             :  *       error is encountered.
     690             :  */
     691             : static int
     692           0 : read_available_remote_data(pcmk__remote_t *remote)
     693             : {
     694           0 :     int rc = pcmk_rc_ok;
     695           0 :     size_t read_len = sizeof(struct remote_header_v0);
     696           0 :     struct remote_header_v0 *header = localized_remote_header(remote);
     697           0 :     bool received = false;
     698             :     ssize_t read_rc;
     699             : 
     700           0 :     if(header) {
     701             :         /* Stop at the end of the current message */
     702           0 :         read_len = header->size_total;
     703             :     }
     704             : 
     705             :     /* automatically grow the buffer when needed */
     706           0 :     if(remote->buffer_size < read_len) {
     707           0 :         remote->buffer_size = 2 * read_len;
     708           0 :         crm_trace("Expanding buffer to %llu bytes",
     709             :                   (unsigned long long) remote->buffer_size);
     710           0 :         remote->buffer = pcmk__realloc(remote->buffer, remote->buffer_size + 1);
     711             :     }
     712             : 
     713             : #ifdef HAVE_GNUTLS_GNUTLS_H
     714           0 :     if (!received && remote->tls_session) {
     715           0 :         read_rc = gnutls_record_recv(*(remote->tls_session),
     716           0 :                                      remote->buffer + remote->buffer_offset,
     717           0 :                                      remote->buffer_size - remote->buffer_offset);
     718           0 :         if (read_rc == GNUTLS_E_INTERRUPTED) {
     719           0 :             rc = EINTR;
     720           0 :         } else if (read_rc == GNUTLS_E_AGAIN) {
     721           0 :             rc = EAGAIN;
     722           0 :         } else if (read_rc < 0) {
     723           0 :             crm_debug("TLS receive failed: %s (%lld)",
     724             :                       gnutls_strerror(read_rc), (long long) read_rc);
     725           0 :             rc = EIO;
     726             :         }
     727           0 :         received = true;
     728             :     }
     729             : #endif
     730             : 
     731           0 :     if (!received && remote->tcp_socket) {
     732           0 :         read_rc = read(remote->tcp_socket,
     733           0 :                        remote->buffer + remote->buffer_offset,
     734           0 :                        remote->buffer_size - remote->buffer_offset);
     735           0 :         if (read_rc < 0) {
     736           0 :             rc = errno;
     737             :         }
     738           0 :         received = true;
     739             :     }
     740             : 
     741           0 :     if (!received) {
     742           0 :         crm_err("Remote connection type undetermined (bug?)");
     743           0 :         return ESOCKTNOSUPPORT;
     744             :     }
     745             : 
     746             :     /* process any errors. */
     747           0 :     if (read_rc > 0) {
     748           0 :         remote->buffer_offset += read_rc;
     749             :         /* always null terminate buffer, the +1 to alloc always allows for this. */
     750           0 :         remote->buffer[remote->buffer_offset] = '\0';
     751           0 :         crm_trace("Received %lld more bytes (%llu total)",
     752             :                   (long long) read_rc,
     753             :                   (unsigned long long) remote->buffer_offset);
     754             : 
     755           0 :     } else if ((rc == EINTR) || (rc == EAGAIN)) {
     756           0 :         crm_trace("No data available for non-blocking remote read: %s (%d)",
     757             :                   pcmk_rc_str(rc), rc);
     758             : 
     759           0 :     } else if (read_rc == 0) {
     760           0 :         crm_debug("End of remote data encountered after %llu bytes",
     761             :                   (unsigned long long) remote->buffer_offset);
     762           0 :         return ENOTCONN;
     763             : 
     764             :     } else {
     765           0 :         crm_debug("Error receiving remote data after %llu bytes: %s (%d)",
     766             :                   (unsigned long long) remote->buffer_offset,
     767             :                   pcmk_rc_str(rc), rc);
     768           0 :         return ENOTCONN;
     769             :     }
     770             : 
     771           0 :     header = localized_remote_header(remote);
     772           0 :     if(header) {
     773           0 :         if(remote->buffer_offset < header->size_total) {
     774           0 :             crm_trace("Read partial remote message (%llu of %u bytes)",
     775             :                       (unsigned long long) remote->buffer_offset,
     776             :                       header->size_total);
     777             :         } else {
     778           0 :             crm_trace("Read full remote message of %llu bytes",
     779             :                       (unsigned long long) remote->buffer_offset);
     780           0 :             return pcmk_rc_ok;
     781             :         }
     782             :     }
     783             : 
     784           0 :     return EAGAIN;
     785             : }
     786             : 
     787             : /*!
     788             :  * \internal
     789             :  * \brief Read one message from a remote connection
     790             :  *
     791             :  * \param[in,out] remote      Remote connection to read
     792             :  * \param[in]     timeout_ms  Fail if message not read in this many milliseconds
     793             :  *                            (10s will be used if 0, and 60s if negative)
     794             :  *
     795             :  * \return Standard Pacemaker return code
     796             :  */
     797             : int
     798           0 : pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms)
     799             : {
     800           0 :     int rc = pcmk_rc_ok;
     801           0 :     time_t start = time(NULL);
     802           0 :     int remaining_timeout = 0;
     803             : 
     804           0 :     if (timeout_ms == 0) {
     805           0 :         timeout_ms = 10000;
     806           0 :     } else if (timeout_ms < 0) {
     807           0 :         timeout_ms = 60000;
     808             :     }
     809             : 
     810           0 :     remaining_timeout = timeout_ms;
     811           0 :     while (remaining_timeout > 0) {
     812             : 
     813           0 :         crm_trace("Waiting for remote data (%d ms of %d ms timeout remaining)",
     814             :                   remaining_timeout, timeout_ms);
     815           0 :         rc = pcmk__remote_ready(remote, remaining_timeout);
     816             : 
     817           0 :         if (rc == ETIME) {
     818           0 :             crm_err("Timed out (%d ms) while waiting for remote data",
     819             :                     remaining_timeout);
     820           0 :             return rc;
     821             : 
     822           0 :         } else if (rc != pcmk_rc_ok) {
     823           0 :             crm_debug("Wait for remote data aborted (will retry): %s "
     824             :                       CRM_XS " rc=%d", pcmk_rc_str(rc), rc);
     825             : 
     826             :         } else {
     827           0 :             rc = read_available_remote_data(remote);
     828           0 :             if (rc == pcmk_rc_ok) {
     829           0 :                 return rc;
     830           0 :             } else if (rc == EAGAIN) {
     831           0 :                 crm_trace("Waiting for more remote data");
     832             :             } else {
     833           0 :                 crm_debug("Could not receive remote data: %s " CRM_XS " rc=%d",
     834             :                           pcmk_rc_str(rc), rc);
     835             :             }
     836             :         }
     837             : 
     838             :         // Don't waste time retrying after fatal errors
     839           0 :         if ((rc == ENOTCONN) || (rc == ESOCKTNOSUPPORT)) {
     840           0 :             return rc;
     841             :         }
     842             : 
     843           0 :         remaining_timeout = timeout_ms - ((time(NULL) - start) * 1000);
     844             :     }
     845           0 :     return ETIME;
     846             : }
     847             : 
     848             : struct tcp_async_cb_data {
     849             :     int sock;
     850             :     int timeout_ms;
     851             :     time_t start;
     852             :     void *userdata;
     853             :     void (*callback) (void *userdata, int rc, int sock);
     854             : };
     855             : 
     856             : // \return TRUE if timer should be rescheduled, FALSE otherwise
     857             : static gboolean
     858           0 : check_connect_finished(gpointer userdata)
     859             : {
     860           0 :     struct tcp_async_cb_data *cb_data = userdata;
     861             :     int rc;
     862             : 
     863             :     fd_set rset, wset;
     864           0 :     struct timeval ts = { 0, };
     865             : 
     866           0 :     if (cb_data->start == 0) {
     867             :         // Last connect() returned success immediately
     868           0 :         rc = pcmk_rc_ok;
     869           0 :         goto dispatch_done;
     870             :     }
     871             : 
     872             :     // If the socket is ready for reading or writing, the connect succeeded
     873           0 :     FD_ZERO(&rset);
     874           0 :     FD_SET(cb_data->sock, &rset);
     875           0 :     wset = rset;
     876           0 :     rc = select(cb_data->sock + 1, &rset, &wset, NULL, &ts);
     877             : 
     878           0 :     if (rc < 0) { // select() error
     879           0 :         rc = errno;
     880           0 :         if ((rc == EINPROGRESS) || (rc == EAGAIN)) {
     881           0 :             if ((time(NULL) - cb_data->start) < (cb_data->timeout_ms / 1000)) {
     882           0 :                 return TRUE; // There is time left, so reschedule timer
     883             :             } else {
     884           0 :                 rc = ETIMEDOUT;
     885             :             }
     886             :         }
     887           0 :         crm_trace("Could not check socket %d for connection success: %s (%d)",
     888             :                   cb_data->sock, pcmk_rc_str(rc), rc);
     889             : 
     890           0 :     } else if (rc == 0) { // select() timeout
     891           0 :         if ((time(NULL) - cb_data->start) < (cb_data->timeout_ms / 1000)) {
     892           0 :             return TRUE; // There is time left, so reschedule timer
     893             :         }
     894           0 :         crm_debug("Timed out while waiting for socket %d connection success",
     895             :                   cb_data->sock);
     896           0 :         rc = ETIMEDOUT;
     897             : 
     898             :     // select() returned number of file descriptors that are ready
     899             : 
     900           0 :     } else if (FD_ISSET(cb_data->sock, &rset)
     901           0 :                || FD_ISSET(cb_data->sock, &wset)) {
     902             : 
     903             :         // The socket is ready; check it for connection errors
     904           0 :         int error = 0;
     905           0 :         socklen_t len = sizeof(error);
     906             : 
     907           0 :         if (getsockopt(cb_data->sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
     908           0 :             rc = errno;
     909           0 :             crm_trace("Couldn't check socket %d for connection errors: %s (%d)",
     910             :                       cb_data->sock, pcmk_rc_str(rc), rc);
     911           0 :         } else if (error != 0) {
     912           0 :             rc = error;
     913           0 :             crm_trace("Socket %d connected with error: %s (%d)",
     914             :                       cb_data->sock, pcmk_rc_str(rc), rc);
     915             :         } else {
     916           0 :             rc = pcmk_rc_ok;
     917             :         }
     918             : 
     919             :     } else { // Should not be possible
     920           0 :         crm_trace("select() succeeded, but socket %d not in resulting "
     921             :                   "read/write sets", cb_data->sock);
     922           0 :         rc = EAGAIN;
     923             :     }
     924             : 
     925           0 :   dispatch_done:
     926           0 :     if (rc == pcmk_rc_ok) {
     927           0 :         crm_trace("Socket %d is connected", cb_data->sock);
     928             :     } else {
     929           0 :         close(cb_data->sock);
     930           0 :         cb_data->sock = -1;
     931             :     }
     932             : 
     933           0 :     if (cb_data->callback) {
     934           0 :         cb_data->callback(cb_data->userdata, rc, cb_data->sock);
     935             :     }
     936           0 :     free(cb_data);
     937           0 :     return FALSE; // Do not reschedule timer
     938             : }
     939             : 
     940             : /*!
     941             :  * \internal
     942             :  * \brief Attempt to connect socket, calling callback when done
     943             :  *
     944             :  * Set a given socket non-blocking, then attempt to connect to it,
     945             :  * retrying periodically until success or a timeout is reached.
     946             :  * Call a caller-supplied callback function when completed.
     947             :  *
     948             :  * \param[in]  sock        Newly created socket
     949             :  * \param[in]  addr        Socket address information for connect
     950             :  * \param[in]  addrlen     Size of socket address information in bytes
     951             :  * \param[in]  timeout_ms  Fail if not connected within this much time
     952             :  * \param[out] timer_id    If not NULL, store retry timer ID here
     953             :  * \param[in]  userdata    User data to pass to callback
     954             :  * \param[in]  callback    Function to call when connection attempt completes
     955             :  *
     956             :  * \return Standard Pacemaker return code
     957             :  */
     958             : static int
     959           0 : connect_socket_retry(int sock, const struct sockaddr *addr, socklen_t addrlen,
     960             :                      int timeout_ms, int *timer_id, void *userdata,
     961             :                      void (*callback) (void *userdata, int rc, int sock))
     962             : {
     963           0 :     int rc = 0;
     964           0 :     int interval = 500;
     965             :     int timer;
     966           0 :     struct tcp_async_cb_data *cb_data = NULL;
     967             : 
     968           0 :     rc = pcmk__set_nonblocking(sock);
     969           0 :     if (rc != pcmk_rc_ok) {
     970           0 :         crm_warn("Could not set socket non-blocking: %s " CRM_XS " rc=%d",
     971             :                  pcmk_rc_str(rc), rc);
     972           0 :         return rc;
     973             :     }
     974             : 
     975           0 :     rc = connect(sock, addr, addrlen);
     976           0 :     if (rc < 0 && (errno != EINPROGRESS) && (errno != EAGAIN)) {
     977           0 :         rc = errno;
     978           0 :         crm_warn("Could not connect socket: %s " CRM_XS " rc=%d",
     979             :                  pcmk_rc_str(rc), rc);
     980           0 :         return rc;
     981             :     }
     982             : 
     983           0 :     cb_data = pcmk__assert_alloc(1, sizeof(struct tcp_async_cb_data));
     984           0 :     cb_data->userdata = userdata;
     985           0 :     cb_data->callback = callback;
     986           0 :     cb_data->sock = sock;
     987           0 :     cb_data->timeout_ms = timeout_ms;
     988             : 
     989           0 :     if (rc == 0) {
     990             :         /* The connect was successful immediately, we still return to mainloop
     991             :          * and let this callback get called later. This avoids the user of this api
     992             :          * to have to account for the fact the callback could be invoked within this
     993             :          * function before returning. */
     994           0 :         cb_data->start = 0;
     995           0 :         interval = 1;
     996             :     } else {
     997           0 :         cb_data->start = time(NULL);
     998             :     }
     999             : 
    1000             :     /* This timer function does a non-blocking poll on the socket to see if we
    1001             :      * can use it. Once we can, the connect has completed. This method allows us
    1002             :      * to connect without blocking the mainloop.
    1003             :      *
    1004             :      * @TODO Use a mainloop fd callback for this instead of polling. Something
    1005             :      *       about the way mainloop is currently polling prevents this from
    1006             :      *       working at the moment though. (See connect(2) regarding EINPROGRESS
    1007             :      *       for possible new handling needed.)
    1008             :      */
    1009           0 :     crm_trace("Scheduling check in %dms for whether connect to fd %d finished",
    1010             :               interval, sock);
    1011           0 :     timer = g_timeout_add(interval, check_connect_finished, cb_data);
    1012           0 :     if (timer_id) {
    1013           0 :         *timer_id = timer;
    1014             :     }
    1015             : 
    1016             :     // timer callback should be taking care of cb_data
    1017             :     // cppcheck-suppress memleak
    1018           0 :     return pcmk_rc_ok;
    1019             : }
    1020             : 
    1021             : /*!
    1022             :  * \internal
    1023             :  * \brief Attempt once to connect socket and set it non-blocking
    1024             :  *
    1025             :  * \param[in]  sock        Newly created socket
    1026             :  * \param[in]  addr        Socket address information for connect
    1027             :  * \param[in]  addrlen     Size of socket address information in bytes
    1028             :  *
    1029             :  * \return Standard Pacemaker return code
    1030             :  */
    1031             : static int
    1032           0 : connect_socket_once(int sock, const struct sockaddr *addr, socklen_t addrlen)
    1033             : {
    1034           0 :     int rc = connect(sock, addr, addrlen);
    1035             : 
    1036           0 :     if (rc < 0) {
    1037           0 :         rc = errno;
    1038           0 :         crm_warn("Could not connect socket: %s " CRM_XS " rc=%d",
    1039             :                  pcmk_rc_str(rc), rc);
    1040           0 :         return rc;
    1041             :     }
    1042             : 
    1043           0 :     rc = pcmk__set_nonblocking(sock);
    1044           0 :     if (rc != pcmk_rc_ok) {
    1045           0 :         crm_warn("Could not set socket non-blocking: %s " CRM_XS " rc=%d",
    1046             :                  pcmk_rc_str(rc), rc);
    1047           0 :         return rc;
    1048             :     }
    1049             : 
    1050           0 :     return pcmk_ok;
    1051             : }
    1052             : 
    1053             : /*!
    1054             :  * \internal
    1055             :  * \brief Connect to server at specified TCP port
    1056             :  *
    1057             :  * \param[in]  host        Name of server to connect to
    1058             :  * \param[in]  port        Server port to connect to
    1059             :  * \param[in]  timeout_ms  If asynchronous, fail if not connected in this time
    1060             :  * \param[out] timer_id    If asynchronous and this is non-NULL, retry timer ID
    1061             :  *                         will be put here (for ease of cancelling by caller)
    1062             :  * \param[out] sock_fd     Where to store socket file descriptor
    1063             :  * \param[in]  userdata    If asynchronous, data to pass to callback
    1064             :  * \param[in]  callback    If NULL, attempt a single synchronous connection,
    1065             :  *                         otherwise retry asynchronously then call this
    1066             :  *
    1067             :  * \return Standard Pacemaker return code
    1068             :  */
    1069             : int
    1070           0 : pcmk__connect_remote(const char *host, int port, int timeout, int *timer_id,
    1071             :                      int *sock_fd, void *userdata,
    1072             :                      void (*callback) (void *userdata, int rc, int sock))
    1073             : {
    1074             :     char buffer[INET6_ADDRSTRLEN];
    1075           0 :     struct addrinfo *res = NULL;
    1076           0 :     struct addrinfo *rp = NULL;
    1077             :     struct addrinfo hints;
    1078           0 :     const char *server = host;
    1079             :     int rc;
    1080           0 :     int sock = -1;
    1081             : 
    1082           0 :     CRM_CHECK((host != NULL) && (sock_fd != NULL), return EINVAL);
    1083             : 
    1084             :     // Get host's IP address(es)
    1085           0 :     memset(&hints, 0, sizeof(struct addrinfo));
    1086           0 :     hints.ai_family = AF_UNSPEC;        /* Allow IPv4 or IPv6 */
    1087           0 :     hints.ai_socktype = SOCK_STREAM;
    1088           0 :     hints.ai_flags = AI_CANONNAME;
    1089             : 
    1090           0 :     rc = getaddrinfo(server, NULL, &hints, &res);
    1091           0 :     rc = pcmk__gaierror2rc(rc);
    1092             : 
    1093           0 :     if (rc != pcmk_rc_ok) {
    1094           0 :         crm_err("Unable to get IP address info for %s: %s",
    1095             :                 server, pcmk_rc_str(rc));
    1096           0 :         goto async_cleanup;
    1097             :     }
    1098             : 
    1099           0 :     if (!res || !res->ai_addr) {
    1100           0 :         crm_err("Unable to get IP address info for %s: no result", server);
    1101           0 :         rc = ENOTCONN;
    1102           0 :         goto async_cleanup;
    1103             :     }
    1104             : 
    1105             :     // getaddrinfo() returns a list of host's addresses, try them in order
    1106           0 :     for (rp = res; rp != NULL; rp = rp->ai_next) {
    1107           0 :         struct sockaddr *addr = rp->ai_addr;
    1108             : 
    1109           0 :         if (!addr) {
    1110           0 :             continue;
    1111             :         }
    1112             : 
    1113           0 :         if (rp->ai_canonname) {
    1114           0 :             server = res->ai_canonname;
    1115             :         }
    1116           0 :         crm_debug("Got canonical name %s for %s", server, host);
    1117             : 
    1118           0 :         sock = socket(rp->ai_family, SOCK_STREAM, IPPROTO_TCP);
    1119           0 :         if (sock == -1) {
    1120           0 :             rc = errno;
    1121           0 :             crm_warn("Could not create socket for remote connection to %s:%d: "
    1122             :                      "%s " CRM_XS " rc=%d", server, port, pcmk_rc_str(rc), rc);
    1123           0 :             continue;
    1124             :         }
    1125             : 
    1126             :         /* Set port appropriately for address family */
    1127             :         /* (void*) casts avoid false-positive compiler alignment warnings */
    1128           0 :         if (addr->sa_family == AF_INET6) {
    1129           0 :             ((struct sockaddr_in6 *)(void*)addr)->sin6_port = htons(port);
    1130             :         } else {
    1131           0 :             ((struct sockaddr_in *)(void*)addr)->sin_port = htons(port);
    1132             :         }
    1133             : 
    1134           0 :         memset(buffer, 0, PCMK__NELEM(buffer));
    1135           0 :         pcmk__sockaddr2str(addr, buffer);
    1136           0 :         crm_info("Attempting remote connection to %s:%d", buffer, port);
    1137             : 
    1138           0 :         if (callback) {
    1139           0 :             if (connect_socket_retry(sock, rp->ai_addr, rp->ai_addrlen, timeout,
    1140             :                                      timer_id, userdata, callback) == pcmk_rc_ok) {
    1141           0 :                 goto async_cleanup; /* Success for now, we'll hear back later in the callback */
    1142             :             }
    1143             : 
    1144           0 :         } else if (connect_socket_once(sock, rp->ai_addr,
    1145             :                                        rp->ai_addrlen) == pcmk_rc_ok) {
    1146           0 :             break;          /* Success */
    1147             :         }
    1148             : 
    1149             :         // Connect failed
    1150           0 :         close(sock);
    1151           0 :         sock = -1;
    1152           0 :         rc = ENOTCONN;
    1153             :     }
    1154             : 
    1155           0 : async_cleanup:
    1156             : 
    1157           0 :     if (res) {
    1158           0 :         freeaddrinfo(res);
    1159             :     }
    1160           0 :     *sock_fd = sock;
    1161           0 :     return rc;
    1162             : }
    1163             : 
    1164             : /*!
    1165             :  * \internal
    1166             :  * \brief Convert an IP address (IPv4 or IPv6) to a string for logging
    1167             :  *
    1168             :  * \param[in]  sa  Socket address for IP
    1169             :  * \param[out] s   Storage for at least INET6_ADDRSTRLEN bytes
    1170             :  *
    1171             :  * \note sa The socket address can be a pointer to struct sockaddr_in (IPv4),
    1172             :  *          struct sockaddr_in6 (IPv6) or struct sockaddr_storage (either),
    1173             :  *          as long as its sa_family member is set correctly.
    1174             :  */
    1175             : void
    1176           0 : pcmk__sockaddr2str(const void *sa, char *s)
    1177             : {
    1178           0 :     switch (((const struct sockaddr *) sa)->sa_family) {
    1179           0 :         case AF_INET:
    1180           0 :             inet_ntop(AF_INET, &(((const struct sockaddr_in *) sa)->sin_addr),
    1181             :                       s, INET6_ADDRSTRLEN);
    1182           0 :             break;
    1183             : 
    1184           0 :         case AF_INET6:
    1185           0 :             inet_ntop(AF_INET6,
    1186           0 :                       &(((const struct sockaddr_in6 *) sa)->sin6_addr),
    1187             :                       s, INET6_ADDRSTRLEN);
    1188           0 :             break;
    1189             : 
    1190           0 :         default:
    1191           0 :             strcpy(s, "<invalid>");
    1192             :     }
    1193           0 : }
    1194             : 
    1195             : /*!
    1196             :  * \internal
    1197             :  * \brief Accept a client connection on a remote server socket
    1198             :  *
    1199             :  * \param[in]  ssock  Server socket file descriptor being listened on
    1200             :  * \param[out] csock  Where to put new client socket's file descriptor
    1201             :  *
    1202             :  * \return Standard Pacemaker return code
    1203             :  */
    1204             : int
    1205           0 : pcmk__accept_remote_connection(int ssock, int *csock)
    1206             : {
    1207             :     int rc;
    1208             :     struct sockaddr_storage addr;
    1209           0 :     socklen_t laddr = sizeof(addr);
    1210             :     char addr_str[INET6_ADDRSTRLEN];
    1211             : #ifdef TCP_USER_TIMEOUT
    1212           0 :     long sbd_timeout = 0;
    1213             : #endif
    1214             : 
    1215             :     /* accept the connection */
    1216           0 :     memset(&addr, 0, sizeof(addr));
    1217           0 :     *csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
    1218           0 :     if (*csock == -1) {
    1219           0 :         rc = errno;
    1220           0 :         crm_err("Could not accept remote client connection: %s "
    1221             :                 CRM_XS " rc=%d", pcmk_rc_str(rc), rc);
    1222           0 :         return rc;
    1223             :     }
    1224           0 :     pcmk__sockaddr2str(&addr, addr_str);
    1225           0 :     crm_info("Accepted new remote client connection from %s", addr_str);
    1226             : 
    1227           0 :     rc = pcmk__set_nonblocking(*csock);
    1228           0 :     if (rc != pcmk_rc_ok) {
    1229           0 :         crm_err("Could not set socket non-blocking: %s " CRM_XS " rc=%d",
    1230             :                 pcmk_rc_str(rc), rc);
    1231           0 :         close(*csock);
    1232           0 :         *csock = -1;
    1233           0 :         return rc;
    1234             :     }
    1235             : 
    1236             : #ifdef TCP_USER_TIMEOUT
    1237           0 :     sbd_timeout = pcmk__get_sbd_watchdog_timeout();
    1238           0 :     if (sbd_timeout > 0) {
    1239             :         // Time to fail and retry before watchdog
    1240           0 :         long half = sbd_timeout / 2;
    1241           0 :         unsigned int optval = (half <= UINT_MAX)? half : UINT_MAX;
    1242             : 
    1243           0 :         rc = setsockopt(*csock, SOL_TCP, TCP_USER_TIMEOUT,
    1244             :                         &optval, sizeof(optval));
    1245           0 :         if (rc < 0) {
    1246           0 :             rc = errno;
    1247           0 :             crm_err("Could not set TCP timeout to %d ms on remote connection: "
    1248             :                     "%s " CRM_XS " rc=%d", optval, pcmk_rc_str(rc), rc);
    1249           0 :             close(*csock);
    1250           0 :             *csock = -1;
    1251           0 :             return rc;
    1252             :         }
    1253             :     }
    1254             : #endif
    1255             : 
    1256           0 :     return rc;
    1257             : }
    1258             : 
    1259             : /*!
    1260             :  * \brief Get the default remote connection TCP port on this host
    1261             :  *
    1262             :  * \return Remote connection TCP port number
    1263             :  */
    1264             : int
    1265           0 : crm_default_remote_port(void)
    1266             : {
    1267             :     static int port = 0;
    1268             : 
    1269           0 :     if (port == 0) {
    1270           0 :         const char *env = pcmk__env_option(PCMK__ENV_REMOTE_PORT);
    1271             : 
    1272           0 :         if (env) {
    1273           0 :             errno = 0;
    1274           0 :             port = strtol(env, NULL, 10);
    1275           0 :             if (errno || (port < 1) || (port > 65535)) {
    1276           0 :                 crm_warn("Environment variable PCMK_" PCMK__ENV_REMOTE_PORT
    1277             :                          " has invalid value '%s', using %d instead",
    1278             :                          env, DEFAULT_REMOTE_PORT);
    1279           0 :                 port = DEFAULT_REMOTE_PORT;
    1280             :             }
    1281             :         } else {
    1282           0 :             port = DEFAULT_REMOTE_PORT;
    1283             :         }
    1284             :     }
    1285           0 :     return port;
    1286             : }

Generated by: LCOV version 1.14