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 : }
|