diff --git a/src/lib/swim/swim_io.c b/src/lib/swim/swim_io.c index c8558c43e48396337a211379daf5a012ba0205ef..0002472fadbda1580dcd5e5c5a48c6ff3dfd456d 100644 --- a/src/lib/swim/swim_io.c +++ b/src/lib/swim/swim_io.c @@ -512,8 +512,26 @@ static inline void swim_complete_send(struct swim_scheduler *scheduler, struct swim_task *task, ssize_t size) { - if (size < 0) - diag_log(); + if (size < 0) { + bool is_critical = true; + int err = diag_last_error(diag_get())->saved_errno; +#if TARGET_OS_DARWIN + /* + * On Mac this error happens regularly if SWIM is bound to + * the localhost and tries to broadcast out of the machine. This + * is not critical, because will happen in the tests a lot, and + * in prod it simply should not bind to localhost if there are + * multiple machines in the cluster. Besides, Mac as a platform + * is not supposed to be used in prod. + */ + is_critical = (err != EADDRNOTAVAIL); +#else + /* The same as EADDRNOTAVAIL, but happens on Linux as EINVAL. */ + is_critical = (err != EINVAL); +#endif + if (is_critical) + diag_log(); + } if (task->complete != NULL) task->complete(task, scheduler, size); } diff --git a/src/lib/swim/swim_transport_udp.c b/src/lib/swim/swim_transport_udp.c index c0317a20b851dcbec33c420079bfdac7d81aa93d..12626cc49f7cd34cbf8c457003f9136cac849af8 100644 --- a/src/lib/swim/swim_transport_udp.c +++ b/src/lib/swim/swim_transport_udp.c @@ -80,25 +80,27 @@ swim_transport_bind(struct swim_transport *transport, return 0; } + int is_on = 1; + int real_port = new_addr->sin_port; int fd = sio_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fd < 0) return -1; - if (sio_bind(fd, (struct sockaddr *) addr, addr_len) != 0 || - evio_setsockopt_server(fd, AF_INET, SOCK_DGRAM) != 0) { + if (sio_bind(fd, (struct sockaddr *) addr, addr_len) != 0) { if (errno == EADDRINUSE) diag_set(SocketError, sio_socketname(fd), "bind"); - close(fd); - return -1; + goto end_error; } - int real_port = new_addr->sin_port; + if (sio_setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &is_on, + sizeof(is_on)) != 0) + goto end_error; + if (evio_setsockopt_server(fd, AF_INET, SOCK_DGRAM) != 0) + goto end_error; if (is_new_port_any) { struct sockaddr_in real_addr; addr_len = sizeof(real_addr); if (sio_getsockname(fd, (struct sockaddr *) &real_addr, - &addr_len) != 0) { - close(fd); - return -1; - } + &addr_len) != 0) + goto end_error; real_port = real_addr.sin_port; } if (transport->fd != -1) @@ -107,6 +109,9 @@ swim_transport_bind(struct swim_transport *transport, transport->addr = *new_addr; transport->addr.sin_port = real_port; return 0; +end_error: + close(fd); + return -1; } void