# HG changeset patch # User Lars Ellenberg # Date 1392200751 -3600 # Node ID 37f57a36a2dd1abf8461a9b758e62f6fe7a22f77 # Parent 6d4324633600dc7ae7aa08c56d86c2fcc767977f Medium: fix usage of SO_REUSEPORT in ucast sockets Linux learned SO_REUSEPORT only with kernel 3.9, but some linux headers already define SO_REUSEPORT. Which, on older kernels, will result in ENOPROTOOPT, "Protocol not available". Failure to set SO_REUSEPORT is NOT critical in general. It *may* be a problem on certain BSDs, with more than two nodes, all using ucast. Refusing to start because of failure to set SO_REUSEPORT is not helpful for the vast majority of the clusters out there. While at it, downgrade "critical" log messages to warnings in non-fatal situations. --- a/lib/plugins/HBcomm/ucast.c +++ b/lib/plugins/HBcomm/ucast.c @@ -461,12 +461,6 @@ static int HB_make_send_sock(struct hb_m int sockfd; struct ip_private *ei; int tos; -#if defined(SO_BINDTODEVICE) - struct ifreq i; -#endif -#if defined(SO_REUSEPORT) - int i = 1; -#endif UCASTASSERT(mp); ei = (struct ip_private*)mp->pd; @@ -494,6 +488,7 @@ static int HB_make_send_sock(struct hb_m #if defined(SO_BINDTODEVICE) { + struct ifreq i; /* * We want to send out this particular interface * @@ -515,12 +510,13 @@ static int HB_make_send_sock(struct hb_m #endif #if defined(SO_REUSEPORT) { + int one = 1; /* this is for OpenBSD to allow multiple * * ucast connections, e.g. a more than * * two node cluster */ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, - &i, sizeof(i)) == -1) { + &one, sizeof(one)) == -1) { PILCallLog(LOG, PIL_CRIT, "ucast: error setting option SO_REUSEPORT(w): %s", strerror(errno)); close(sockfd); @@ -548,7 +544,7 @@ static int HB_make_receive_sock(struct h int sockfd; int bindtries; int boundyet = 0; - int j; + int one = 1; UCASTASSERT(mp); ei = (struct ip_private*)mp->pd; @@ -563,22 +559,19 @@ static int HB_make_receive_sock(struct h strerror(errno)); return -1; } - /* - * Set SO_REUSEADDR on the server socket s. Variable j is used - * as a scratch varable. - * - * 16th February 2000 - * Added by Horms - * with thanks to Clinton Work - */ - j = 1; + /* + * Set SO_REUSEADDR on the server socket s. + * Below, also try to set SO_REUSEPORT, + * if known and supported. + */ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, - (void *)&j, sizeof j) < 0) { + &one, sizeof(one)) < 0) { /* Ignore it. It will almost always be OK anyway. */ - PILCallLog(LOG, PIL_CRIT, + PILCallLog(LOG, PIL_WARN, "ucast: error setting socket option SO_REUSEADDR: %s", strerror(errno)); - } + } else + PILCallLog(LOG, PIL_INFO, "ucast: set SO_REUSEADDR"); #if defined(SO_BINDTODEVICE) { /* @@ -600,20 +593,32 @@ static int HB_make_receive_sock(struct h } #endif #if defined(SO_REUSEPORT) - { + /* + * Needed for OpenBSD for more than two nodes in a ucast cluster + */ + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, + &one, sizeof(one)) == -1) { /* - * Needed for OpenBSD for more than two nodes in a ucast cluster + * Linux learned SO_REUSEPORT only with kernel 3.9, + * but some linux headers already define SO_REUSEPORT. + * Which will result in ENOPROTOOPT, "Protocol not available" + * on older kernels. + * Failure to set SO_REUSEPORT is NOT critical in general. + * It *may* be a problem on certain BSDs with more than + * two nodes all using ucast. + * Refusing to start because of failure to set SO_REUSEPORT is + * not helpful for the vast majority of the clusters out there. */ - int i = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, - &i, sizeof(i)) == -1) { + if (errno == ENOPROTOOPT) { + PILCallLog(LOG, PIL_WARN, + "ucast: error setting option SO_REUSEPORT: %s", strerror(errno)); + } else { PILCallLog(LOG, PIL_CRIT, - "ucast: error setting option SO_REUSEPORT(r) %s", strerror(errno)); - close(sockfd); + "ucast: error setting option SO_REUSEPORT: %s", strerror(errno)); return -1; } - PILCallLog(LOG, PIL_INFO, "ucast: set SO_REUSEPORT(w)"); - } + } else + PILCallLog(LOG, PIL_INFO, "ucast: set SO_REUSEPORT"); #endif /* Try binding a few times before giving up */