1 /*
2  * $Header$
3  *
4  * Handles watchdog connection, and protocol communication with pgpool-II
5  *
6  * pgpool: a language independent connection pool server for PostgreSQL
7  * written by Tatsuo Ishii
8  *
9  * Copyright (c) 2003-2015	PgPool Global Development Group
10  *
11  * Permission to use, copy, modify, and distribute this software and
12  * its documentation for any purpose and without fee is hereby
13  * granted, provided that the above copyright notice appear in all
14  * copies and that both that copyright notice and this permission
15  * notice appear in supporting documentation, and that the name of the
16  * author not be used in advertising or publicity pertaining to
17  * distribution of the software without specific, written prior
18  * permission. The author makes no representations about the
19  * suitability of this software for any purpose.  It is provided "as
20  * is" without express or implied warranty.
21  *
22  */
23 
24 #include <stdio.h>
25 #include <errno.h>
26 #include <ctype.h>
27 #include <time.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <sys/un.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
36 #include <netinet/ip.h>
37 #include <netdb.h>
38 #include <arpa/inet.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 
42 #if defined(SO_BINDTODEVICE)
43 #include <net/if.h>
44 #endif
45 
46 #include "pool.h"
47 #include "utils/palloc.h"
48 #include "utils/memutils.h"
49 #include "utils/elog.h"
50 #include "pool_config.h"
51 #include "auth/md5.h"
52 #include "watchdog/watchdog.h"
53 #include "watchdog/wd_lifecheck.h"
54 #include "watchdog/wd_utils.h"
55 
56 #define MAX_BIND_TRIES 5
57 /*
58  * heartbeat packet
59  */
60 typedef struct {
61 	char from[WD_MAX_HOST_NAMELEN];
62 	int from_pgpool_port;
63 	struct timeval send_time;
64 	char hash[WD_AUTH_HASH_LEN + 1];
65 } WdHbPacket;
66 
67 
68 static RETSIGTYPE hb_sender_exit(int sig);
69 static RETSIGTYPE hb_receiver_exit(int sig);
70 static int hton_wd_hb_packet(WdHbPacket *to, WdHbPacket *from);
71 static int ntoh_wd_hb_packet(WdHbPacket *to, WdHbPacket *from);
72 static int packet_to_string_hb(WdHbPacket *pkt, char * str, int maxlen);
73 static void wd_set_reuseport(int sock);
74 
75 static int wd_create_hb_send_socket(WdHbIf * hb_if);
76 static int wd_create_hb_recv_socket(WdHbIf * hb_if);
77 
78 static void wd_hb_send(int sock, WdHbPacket * pkt, int len, const char * destination, const int dest_port);
79 static void wd_hb_recv(int sock, WdHbPacket * pkt, char *from_addr);
80 
81 /* create socket for sending heartbeat */
82 static int
wd_create_hb_send_socket(WdHbIf * hb_if)83 wd_create_hb_send_socket(WdHbIf *hb_if)
84 {
85 	int sock;
86 	int tos;
87 
88 	/* create socket */
89 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
90 	{
91 		/* socket create failed */
92 		ereport(ERROR,
93 			(errmsg("failed to create watchdog heartbeat sender socket"),
94 				 errdetail("create socket failed with reason: \"%s\"", strerror(errno))));
95 	}
96 
97 	/* set socket option */
98 	tos = IPTOS_LOWDELAY;
99 	if (setsockopt(sock, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(tos)) == -1 )
100 	{
101 		close(sock);
102 		ereport(ERROR,
103 			(errmsg("failed to create watchdog heartbeat sender socket"),
104 				 errdetail("setsockopt(IP_TOS) failed with reason: \"%s\"", strerror(errno))));
105 	}
106 
107 	if (hb_if->if_name[0] != '\0')
108 	{
109 #if defined(SO_BINDTODEVICE)
110 		{
111 			if (geteuid() == 0) /* check root privileges */
112 			{
113 				struct ifreq i;
114 				strlcpy(i.ifr_name, hb_if->if_name, sizeof(i.ifr_name));
115 
116 				if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) == -1)
117 				{
118 					close(sock);
119 					ereport(ERROR,
120 						(errmsg("failed to create watchdog heartbeat sender socket"),
121 							 errdetail("setsockopt(SO_BINDTODEVICE) failed with reason: \"%s\"", strerror(errno))));
122 
123 				}
124 				ereport(LOG,
125 					(errmsg("creating socket for sending heartbeat"),
126 						 errdetail("bind send socket to device: %s", i.ifr_name)));
127 			}
128 			else
129 				ereport(LOG,
130 					(errmsg("creating socket for sending heartbeat"),
131 						 errdetail("setsockopt(SO_BINDTODEVICE) requires root privilege")));
132 		}
133 #else
134 		ereport(LOG,
135 			(errmsg("creating socket for sending heartbeat"),
136 				 errdetail("setsockopt(SO_BINDTODEVICE) is not available on this platform")));
137 #endif
138 	}
139 
140 	wd_set_reuseport(sock);
141 	ereport(LOG,
142 		(errmsg("creating socket for sending heartbeat"),
143 			 errdetail("set SO_REUSEPORT")));
144 
145  	if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0)
146 	{
147 		close(sock);
148 		ereport(ERROR,
149 				(errmsg("failed to create watchdog heartbeat sender socket"),
150 				 errdetail("setting close-on-exec flag failed with reason: \"%s\"", strerror(errno))));
151 	}
152 
153 	return sock;
154 }
155 
156 /* create socket for receiving heartbeat */
157 static int
wd_create_hb_recv_socket(WdHbIf * hb_if)158 wd_create_hb_recv_socket(WdHbIf *hb_if)
159 {
160 	struct sockaddr_in addr;
161 	int sock;
162 	const int one = 1;
163 	int bind_tries;
164 	int bind_is_done;
165 
166 	memset(&(addr), 0, sizeof(addr));
167 	addr.sin_family = AF_INET;
168 	addr.sin_port = htons(pool_config->wd_heartbeat_port);
169 	addr.sin_addr.s_addr = INADDR_ANY;
170 
171 	/* create socket */
172 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
173 	{
174 		/* socket create failed */
175 		ereport(ERROR,
176 			(errmsg("failed to create watchdog heartbeat receive socket"),
177 				 errdetail("create socket failed with reason: \"%s\"", strerror(errno))));
178 	}
179 
180 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1 )
181 	{
182 		close(sock);
183 		ereport(ERROR,
184 			(errmsg("failed to create watchdog heartbeat receive socket"),
185 				 errdetail("setsockopt(SO_REUSEADDR) failed with reason: \"%s\"", strerror(errno))));
186 	}
187 
188 	if (hb_if->if_name[0] != '\0')
189 	{
190 #if defined(SO_BINDTODEVICE)
191 		{
192 			if (geteuid() == 0) /* check root privileges */
193 			{
194 				struct ifreq i;
195 				strlcpy(i.ifr_name, hb_if->if_name, sizeof(i.ifr_name));
196 
197 				if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) == -1)
198 				{
199 					close(sock);
200 					ereport(ERROR,
201 						(errmsg("failed to create watchdog heartbeat receive socket"),
202 							 errdetail("setsockopt(SO_BINDTODEVICE) failed with reason: \"%s\"", strerror(errno))));
203 				}
204 				ereport(LOG,
205 					(errmsg("createing watchdog heartbeat receive socket."),
206 						 errdetail("bind receive socket to device: \"%s\"", i.ifr_name)));
207 
208 			}
209 			else
210 				ereport(LOG,
211 					(errmsg("failed to create watchdog heartbeat receive socket."),
212 						 errdetail("setsockopt(SO_BINDTODEVICE) requies root privilege")));
213 		}
214 #else
215 		ereport(LOG,
216 			(errmsg("failed to create watchdog heartbeat receive socket"),
217 				 errdetail("setsockopt(SO_BINDTODEVICE) is not available on this platform")));
218 #endif
219 	}
220 
221 	wd_set_reuseport(sock);
222 
223 	ereport(LOG,
224 		(errmsg("creating watchdog heartbeat receive socket."),
225 			 errdetail("set SO_REUSEPORT")));
226 
227 	bind_is_done = 0;
228 	for (bind_tries = 0; !bind_is_done && bind_tries < MAX_BIND_TRIES; bind_tries++)
229 	{
230 		if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr)) < 0)
231 		{
232 			ereport(LOG,
233 				(errmsg("failed to create watchdog heartbeat receive socket. retrying..."),
234 					errdetail("bind failed with reason: \"%s\"",
235 						   strerror(errno))));
236 
237 			sleep(1);
238 		}
239 		else
240 		{
241 			bind_is_done = 1;
242 		}
243 	}
244 
245 	/* bind failed finally */
246 	if (!bind_is_done)
247 	{
248 		close(sock);
249 		ereport(ERROR,
250 			(errmsg("failed to create watchdog heartbeat receive socket"),
251 				 errdetail("bind socket failed with reason: \"%s\"", strerror(errno))));
252 	}
253 
254  	if (fcntl(sock, F_SETFD, FD_CLOEXEC) < 0)
255 	{
256 		close(sock);
257 		ereport(ERROR,
258 			(errmsg("failed to create watchdog heartbeat receive socket"),
259 				 errdetail("setting close-on-exec flag failed with reason: \"%s\"", strerror(errno))));
260 	}
261 
262 	return sock;
263 }
264 
265 /* send heartbeat signal */
266 static void
wd_hb_send(int sock,WdHbPacket * pkt,int len,const char * host,const int port)267 wd_hb_send(int sock, WdHbPacket * pkt, int len, const char * host, const int port)
268 {
269 	int rtn;
270 	struct sockaddr_in addr;
271 	struct hostent *hp;
272 	WdHbPacket buf;
273 
274 	if (!host || !strlen(host))
275 		ereport(ERROR,
276 			(errmsg("failed to send watchdog heartbeat. host name is empty")));
277 
278 	hp = gethostbyname(host);
279 	if ((hp == NULL) || (hp->h_addrtype != AF_INET))
280 		ereport(ERROR,
281 			(errmsg("failed to send watchdog heartbeat, gethostbyname() failed"),
282 				 errdetail("gethostbyname on \"%s\" failed with reason: \"%s\"",host, hstrerror(h_errno))));
283 
284 	memmove((char *) &(addr.sin_addr), (char *) hp->h_addr, hp->h_length);
285 
286 	addr.sin_family = AF_INET;
287 	addr.sin_port = htons(port);
288 
289 	hton_wd_hb_packet(&buf, pkt);
290 
291 	if ((rtn = sendto(sock, &buf, sizeof(WdHbPacket), 0,
292 	                  (struct sockaddr *)&addr, sizeof(addr))) != len)
293 	{
294 		ereport(ERROR,
295 			(errmsg("failed to send watchdog heartbeat, sendto failed"),
296 				 errdetail("sending packet to \"%s\" failed with reason: \"%s\"",host, strerror(errno))));
297 
298 	}
299 	ereport(DEBUG2,
300 			(errmsg("watchdog heartbeat: send %d byte packet", rtn)));
301 
302 }
303 
304 /*
305  * receive heartbeat signal
306  * the function expects the from_addr to be at least WD_MAX_HOST_NAMELEN bytes long
307  */
308 void
wd_hb_recv(int sock,WdHbPacket * pkt,char * from_addr)309 static wd_hb_recv(int sock, WdHbPacket * pkt, char *from_addr)
310 {
311 	int rtn;
312 	struct sockaddr_in senderinfo;
313 	socklen_t addrlen;
314 	WdHbPacket buf;
315 
316 	addrlen = sizeof(senderinfo);
317 
318 	rtn = recvfrom(sock, &buf, sizeof(WdHbPacket), 0,
319 	               (struct sockaddr *)&senderinfo, &addrlen);
320 	if (rtn < 0)
321 		ereport(ERROR,
322 			(errmsg("failed to receive heartbeat packet")));
323 	else if (rtn == 0)
324 		ereport(ERROR,
325 				(errmsg("failed to receive heartbeat received zero length packet")));
326 	else
327 		ereport(DEBUG2,
328 				(errmsg("watchdog heartbeat: received %d byte packet", rtn)));
329 
330 	strncpy(from_addr,inet_ntoa(senderinfo.sin_addr),WD_MAX_HOST_NAMELEN-1);
331 
332 	ntoh_wd_hb_packet(pkt, &buf);
333 }
334 
335 /* fork heartbeat receiver child */
336 pid_t
wd_hb_receiver(int fork_wait_time,WdHbIf * hb_if)337 wd_hb_receiver(int fork_wait_time, WdHbIf *hb_if)
338 {
339 	int sock;
340 	pid_t pid = 0;
341 	WdHbPacket pkt;
342 	struct timeval tv;
343 	char from[WD_MAX_HOST_NAMELEN];
344 	int from_pgpool_port;
345 	char buf[WD_AUTH_HASH_LEN + 1];
346 	char pack_str[WD_MAX_PACKET_STRING];
347 	int pack_str_len;
348 	sigjmp_buf	local_sigjmp_buf;
349 
350 	pid = fork();
351 	if (pid != 0)
352 	{
353 		if (pid == -1)
354 			ereport(PANIC,
355 					(errmsg("failed to fork a heartbeat receiver child")));
356 		return pid;
357 	}
358 
359 	on_exit_reset();
360 	processType = PT_HB_RECEIVER;
361 
362 	if (fork_wait_time > 0)
363 	{
364 		sleep(fork_wait_time);
365 	}
366 
367 	POOL_SETMASK(&UnBlockSig);
368 
369 	pool_signal(SIGTERM, hb_receiver_exit);
370 	pool_signal(SIGINT, hb_receiver_exit);
371 	pool_signal(SIGQUIT, hb_receiver_exit);
372 	pool_signal(SIGCHLD, SIG_DFL);
373 	pool_signal(SIGHUP, SIG_IGN);
374 	pool_signal(SIGUSR1, SIG_IGN);
375 	pool_signal(SIGUSR2, SIG_IGN);
376 	pool_signal(SIGPIPE, SIG_IGN);
377 	pool_signal(SIGALRM, SIG_IGN);
378 
379 	init_ps_display("", "", "", "");
380 	/* Create per loop iteration memory context */
381 	ProcessLoopContext = AllocSetContextCreate(TopMemoryContext,
382 											   "wdhb_hb_receiver",
383 											   ALLOCSET_DEFAULT_MINSIZE,
384 											   ALLOCSET_DEFAULT_INITSIZE,
385 											   ALLOCSET_DEFAULT_MAXSIZE);
386 
387 	MemoryContextSwitchTo(TopMemoryContext);
388 
389 	sock = wd_create_hb_recv_socket(hb_if);
390 
391 	set_ps_display("heartbeat receiver", false);
392 
393 	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
394 	{
395 		/* Since not using PG_TRY, must reset error stack by hand */
396 		error_context_stack = NULL;
397 
398 		EmitErrorReport();
399 		MemoryContextSwitchTo(TopMemoryContext);
400 		FlushErrorState();
401 	}
402 
403 	/* We can now handle ereport(ERROR) */
404 	PG_exception_stack = &local_sigjmp_buf;
405 
406 	for(;;)
407 	{
408 		int i;
409 		MemoryContextSwitchTo(ProcessLoopContext);
410 		MemoryContextResetAndDeleteChildren(ProcessLoopContext);
411 
412 		/* receive heartbeat signal */
413 		wd_hb_recv(sock, &pkt, from);
414 			/* authentication */
415 		if (strlen(pool_config->wd_authkey))
416 		{
417 			/* calculate hash from packet */
418 			pack_str_len = packet_to_string_hb(&pkt, pack_str, sizeof(pack_str));
419 			wd_calc_hash(pack_str, pack_str_len, buf);
420 
421 			if (buf[0] == '\0')
422 				ereport(WARNING,
423 					(errmsg("failed to calculate wd_authkey hash from a received heartbeat packet")));
424 
425 			if (strcmp(pkt.hash, buf))
426 				ereport(ERROR,
427 					(errmsg("watchdog heartbeat receive"),
428 						 errdetail("authentication failed")));
429 		}
430 
431 		/* get current time */
432 		gettimeofday(&tv, NULL);
433 
434 		/* who send this packet? */
435 		from_pgpool_port = pkt.from_pgpool_port;
436 		for (i = 0; i< gslifeCheckCluster->nodeCount; i++)
437 		{
438 			LifeCheckNode* node = &gslifeCheckCluster->lifeCheckNodes[i];
439 
440 			ereport(DEBUG2,
441 					(errmsg("received heartbeat signal from \"%s:%d\" hostname:%s",
442 							from, from_pgpool_port, pkt.from)));
443 
444 			if ( (!strcmp(node->hostName, pkt.from) || !strcmp(node->hostName, from)) && node->pgpoolPort == from_pgpool_port)
445 			{
446 				/* this is the first packet or the latest packet */
447 				if (!WD_TIME_ISSET(node->hb_send_time) ||
448 					WD_TIME_BEFORE(node->hb_send_time, pkt.send_time))
449 				{
450 					ereport(DEBUG1,
451 							(errmsg("received heartbeat signal from \"%s(%s):%d\" node:%s",
452 									from,pkt.from, from_pgpool_port, node->nodeName)));
453 
454 					node->hb_send_time = pkt.send_time;
455 					node->hb_last_recv_time = tv;
456 				}
457 				else
458 				{
459 					ereport(NOTICE,
460 							(errmsg("received heartbeat signal is older than the latest, ignored")));
461 				}
462 				break;
463 			}
464 		}
465 	}
466 
467 	return pid;
468 }
469 
470 /* fork heartbeat sender child */
471 pid_t
wd_hb_sender(int fork_wait_time,WdHbIf * hb_if)472 wd_hb_sender(int fork_wait_time, WdHbIf *hb_if)
473 {
474 	int sock;
475 	pid_t pid = 0;
476 	WdHbPacket pkt;
477 
478 	char pack_str[WD_MAX_PACKET_STRING];
479 	int pack_str_len;
480 	sigjmp_buf	local_sigjmp_buf;
481 
482 	pid = fork();
483 	if (pid != 0)
484 	{
485 		if (pid == -1)
486 			ereport(PANIC,
487 					(errmsg("failed to fork a heartbeat sender child")));
488 		return pid;
489 	}
490 
491 	on_exit_reset();
492 	processType = PT_HB_SENDER;
493 
494 	if (fork_wait_time > 0)
495 	{
496 		sleep(fork_wait_time);
497 	}
498 
499 	POOL_SETMASK(&UnBlockSig);
500 
501 	pool_signal(SIGTERM, hb_sender_exit);
502 	pool_signal(SIGINT, hb_sender_exit);
503 	pool_signal(SIGQUIT, hb_sender_exit);
504 	pool_signal(SIGCHLD, SIG_DFL);
505 	pool_signal(SIGHUP, SIG_IGN);
506 	pool_signal(SIGUSR1, SIG_IGN);
507 	pool_signal(SIGUSR2, SIG_IGN);
508 	pool_signal(SIGPIPE, SIG_IGN);
509 	pool_signal(SIGALRM, SIG_IGN);
510 
511 	init_ps_display("", "", "", "");
512 	/* Create per loop iteration memory context */
513 	ProcessLoopContext = AllocSetContextCreate(TopMemoryContext,
514 											   "wdhb_sender",
515 											   ALLOCSET_DEFAULT_MINSIZE,
516 											   ALLOCSET_DEFAULT_INITSIZE,
517 											   ALLOCSET_DEFAULT_MAXSIZE);
518 
519 	MemoryContextSwitchTo(TopMemoryContext);
520 
521 	sock = wd_create_hb_send_socket(hb_if);
522 
523 	set_ps_display("heartbeat sender", false);
524 
525 	if (sigsetjmp(local_sigjmp_buf, 1) != 0)
526 	{
527 		/* Since not using PG_TRY, must reset error stack by hand */
528 		error_context_stack = NULL;
529 
530 		EmitErrorReport();
531 		MemoryContextSwitchTo(TopMemoryContext);
532 		FlushErrorState();
533 		sleep(pool_config->wd_heartbeat_keepalive);
534 	}
535 
536 	/* We can now handle ereport(ERROR) */
537 	PG_exception_stack = &local_sigjmp_buf;
538 
539 	for(;;)
540 	{
541 		MemoryContextSwitchTo(ProcessLoopContext);
542 		MemoryContextResetAndDeleteChildren(ProcessLoopContext);
543 
544 		/* contents of packet */
545 		gettimeofday(&pkt.send_time, NULL);
546 		strlcpy(pkt.from, pool_config->wd_hostname, sizeof(pkt.from));
547 		pkt.from_pgpool_port = pool_config->port;
548 
549 		/* authentication key */
550 		if (strlen(pool_config->wd_authkey))
551 		{
552 			/* calculate hash from packet */
553 			pack_str_len = packet_to_string_hb(&pkt, pack_str, sizeof(pack_str));
554 			wd_calc_hash(pack_str, pack_str_len, pkt.hash);
555 
556 			if (pkt.hash[0] == '\0')
557 				ereport(WARNING,
558 					(errmsg("failed to calculate wd_authkey hash from a heartbeat packet to be sent")));
559 		}
560 
561 		/* send heartbeat signal */
562 		wd_hb_send(sock, &pkt, sizeof(pkt), hb_if->addr, hb_if->dest_port);
563 		ereport(DEBUG1,
564 				(errmsg("watchdog heartbeat: send heartbeat signal to %s:%d", hb_if->addr, hb_if->dest_port)));
565 		sleep(pool_config->wd_heartbeat_keepalive);
566 	}
567 
568 	return pid;
569 }
570 
571 static RETSIGTYPE
hb_sender_exit(int sig)572 hb_sender_exit(int sig)
573 {
574 	switch (sig)
575 	{
576 		case SIGTERM:	/* smart shutdown */
577 		case SIGINT:	/* fast shutdown */
578 		case SIGQUIT:	/* immediate shutdown */
579 			ereport(DEBUG1,
580 					(errmsg("watchdog heartbeat sender child receives shutdown request signal %d", sig )));
581 			break;
582 		default:
583 			ereport(LOG,
584 					(errmsg("hb_sender child receives unknown signal: %d", sig )));
585 	}
586 
587 	exit(0);
588 }
589 
590 static RETSIGTYPE
hb_receiver_exit(int sig)591 hb_receiver_exit(int sig)
592 {
593 	switch (sig)
594 	{
595 		case SIGTERM:	/* smart shutdown */
596 		case SIGINT:	/* fast shutdown */
597 		case SIGQUIT:	/* immediate shutdown */
598 			ereport(DEBUG1,
599 				(errmsg("watchdog heartbeat receiver child receives shutdown request signal %d", sig )));
600 			break;
601 		default:
602 			ereport(LOG,
603 					(errmsg("hb_receiver child receives unknown signal: %d", sig )));
604 	}
605 
606 	exit(0);
607 }
608 
609 static int
hton_wd_hb_packet(WdHbPacket * to,WdHbPacket * from)610 hton_wd_hb_packet(WdHbPacket * to, WdHbPacket * from)
611 {
612 	if ((to == NULL) || (from == NULL))
613 	{
614 		return WD_NG;
615 	}
616 
617 	to->send_time.tv_sec = htonl(from->send_time.tv_sec);
618 	to->send_time.tv_usec = htonl(from->send_time.tv_usec);
619 	memcpy(to->from, from->from, sizeof(to->from));
620 	to->from_pgpool_port = htonl(from->from_pgpool_port);
621 	memcpy(to->hash, from->hash, sizeof(to->hash));
622 
623 	return WD_OK;
624 }
625 
626 static int
ntoh_wd_hb_packet(WdHbPacket * to,WdHbPacket * from)627 ntoh_wd_hb_packet(WdHbPacket * to, WdHbPacket * from)
628 {
629 	if ((to == NULL) || (from == NULL))
630 	{
631 		return WD_NG;
632 	}
633 
634 	to->send_time.tv_sec = ntohl(from->send_time.tv_sec);
635 	to->send_time.tv_usec = ntohl(from->send_time.tv_usec);
636 	memcpy(to->from, from->from, sizeof(to->from));
637 	to->from_pgpool_port = ntohl(from->from_pgpool_port);
638 	memcpy(to->hash, from->hash, sizeof(to->hash));
639 
640 	return WD_OK;
641 }
642 
643 /* convert packet to string and return length of the string */
644 static int
packet_to_string_hb(WdHbPacket * pkt,char * str,int maxlen)645 packet_to_string_hb(WdHbPacket *pkt, char *str, int maxlen)
646 {
647 	int len;
648 	len = snprintf(str, maxlen, "tv_sec=%ld tv_usec=%ld from=%s",
649 	                pkt->send_time.tv_sec, pkt->send_time.tv_usec, pkt->from);
650 
651 	return len;
652 }
653 
654 /*
655  * Set SO_REUSEPORT option to the socket.  If the option is available
656  * in the compile time but not available in the run time, just emit a
657  * log and treat it as normal.
658  */
wd_set_reuseport(int sock)659 static void wd_set_reuseport(int sock)
660 {
661 #if defined(SO_REUSEPORT)
662 	int one = 1;
663 
664 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) == -1)
665 	{
666 		if (errno == EINVAL || errno == ENOPROTOOPT)
667 		{
668 			ereport(LOG,
669 				(errmsg("error seting SO_REUSEPORT option to the socket"),
670 					 errdetail("setsockopt(SO_REUSEPORT) is not supported by the kernel. detail: %s",
671 							   strerror(errno))));
672 		}
673 		else
674 		{
675 			close(sock);
676 			ereport(ERROR,
677 				(errmsg("failed to create watchdog heartbeat socket"),
678 					 errdetail("setsockopt(SO_REUSEPORT) failed with reason: \"%s\"", strerror(errno))));
679 		}
680 	}
681 	else
682 		ereport(LOG,
683 				(errmsg("set SO_REUSEPORT option to the socket")));
684 
685 #endif
686 }
687