int aeron_udp_channel_transport_init( aeron_udp_channel_transport_t *transport, struct sockaddr_storage *bind_addr, struct sockaddr_storage *multicast_if_addr, unsigned int multicast_if_index, uint8_t ttl, size_t socket_rcvbuf, size_t socket_sndbuf) { bool is_ipv6, is_multicast; struct sockaddr_in *in4 = (struct sockaddr_in *)bind_addr; struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)bind_addr; transport->fd = -1; if ((transport->fd = socket(bind_addr->ss_family, SOCK_DGRAM, 0)) < 0) { goto error; } is_ipv6 = (AF_INET6 == bind_addr->ss_family); is_multicast = aeron_is_addr_multicast(bind_addr); socklen_t bind_addr_len = is_ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); if (!is_multicast) { if (bind(transport->fd, (struct sockaddr *)bind_addr, bind_addr_len) < 0) { int errcode = errno; aeron_set_err(errcode, "unicast bind: %s", strerror(errcode)); goto error; } } else { int reuse = 1; #if defined(SO_REUSEADDR) if (setsockopt(transport->fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(SO_REUSEADDR): %s", strerror(errcode)); goto error; } #endif #if defined(SO_REUSEPORT) if (setsockopt(transport->fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(SO_REUSEPORT): %s", strerror(errcode)); goto error; } #endif if (bind(transport->fd, (struct sockaddr *) bind_addr, bind_addr_len) < 0) { int errcode = errno; aeron_set_err(errcode, "multicast bind: %s", strerror(errcode)); goto error; } if (is_ipv6) { struct ipv6_mreq mreq; memcpy(&mreq.ipv6mr_multiaddr, &in6->sin6_addr, sizeof(in6->sin6_addr)); mreq.ipv6mr_interface = multicast_if_index; if (setsockopt(transport->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errcode)); goto error; } if (setsockopt( transport->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_if_index, sizeof(multicast_if_index)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errcode)); goto error; } if (ttl > 0) { if (setsockopt(transport->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errcode)); goto error; } } } else { struct ip_mreq mreq; struct sockaddr_in *interface_addr = (struct sockaddr_in *) &multicast_if_addr; mreq.imr_multiaddr.s_addr = in4->sin_addr.s_addr; mreq.imr_interface.s_addr = interface_addr->sin_addr.s_addr; if (setsockopt(transport->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(IP_ADD_MEMBERSHIP): %s", strerror(errcode)); goto error; } if (setsockopt(transport->fd, IPPROTO_IP, IP_MULTICAST_IF, interface_addr, sizeof(struct in_addr)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(IP_MULTICAST_IF): %s", strerror(errcode)); goto error; } if (ttl > 0) { if (setsockopt(transport->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(IP_MULTICAST_TTL): %s", strerror(errcode)); goto error; } } } } if (socket_rcvbuf > 0) { if (setsockopt(transport->fd, SOL_SOCKET, SO_RCVBUF, &socket_rcvbuf, sizeof(socket_rcvbuf)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(SO_RCVBUF): %s", strerror(errcode)); goto error; } } if (socket_sndbuf > 0) { if (setsockopt(transport->fd, SOL_SOCKET, SO_SNDBUF, &socket_sndbuf, sizeof(socket_sndbuf)) < 0) { int errcode = errno; aeron_set_err(errcode, "setsockopt(SO_SNDBUF): %s", strerror(errcode)); goto error; } } int flags; if ((flags = fcntl(transport->fd, F_GETFL, 0)) < 0) { int errcode = errno; aeron_set_err(errcode, "fcntl(F_GETFL): %s", strerror(errcode)); goto error; } flags |= O_NONBLOCK; if (fcntl(transport->fd, F_SETFL, flags) < 0) { int errcode = errno; aeron_set_err(errcode, "fcntl(F_SETFL): %s", strerror(errcode)); goto error; } return 0; error: close(transport->fd); transport->fd = -1; return -1; }
int aeron_udp_channel_parse(const char *uri, size_t uri_length, aeron_udp_channel_t **channel) { aeron_udp_channel_t *_channel = NULL; struct sockaddr_storage endpoint_addr, explicit_control_addr, interface_addr; unsigned int interface_index = 0; memset(&endpoint_addr, 0, sizeof(endpoint_addr)); memset(&explicit_control_addr, 0, sizeof(explicit_control_addr)); memset(&interface_addr, 0, sizeof(interface_addr)); if (aeron_alloc((void **)&_channel, sizeof(aeron_udp_channel_t)) < 0) { aeron_set_err(ENOMEM, "%s", "could not allocate UDP channel"); return -1; } if (aeron_uri_parse(uri, &_channel->uri) < 0) { goto error_cleanup; } size_t copy_length = sizeof(_channel->original_uri) - 1; copy_length = uri_length < copy_length ? uri_length : copy_length; strncpy(_channel->original_uri, uri, copy_length); _channel->original_uri[copy_length] = '\0'; _channel->uri_length = copy_length; _channel->explicit_control = false; _channel->multicast = false; if (_channel->uri.type != AERON_URI_UDP) { aeron_set_err(EINVAL, "%s", "UDP channels must use UDP URIs"); goto error_cleanup; } if (NULL == _channel->uri.params.udp.endpoint_key && NULL == _channel->uri.params.udp.control_key) { aeron_set_err(EINVAL, "%s", "Aeron URIs for UDP must specify an endpoint address and/or a control address"); goto error_cleanup; } if (NULL != _channel->uri.params.udp.endpoint_key) { if (aeron_host_and_port_parse_and_resolve(_channel->uri.params.udp.endpoint_key, &endpoint_addr) < 0) { aeron_set_err( aeron_errcode(), "could not resolve endpoint address=(%s): %s", _channel->uri.params.udp.endpoint_key, aeron_errmsg()); goto error_cleanup; } } else { aeron_set_ipv4_wildcard_host_and_port(&endpoint_addr); } if (NULL != _channel->uri.params.udp.control_key) { if (aeron_host_and_port_parse_and_resolve(_channel->uri.params.udp.control_key, &explicit_control_addr) < 0) { aeron_set_err( aeron_errcode(), "could not resolve control address=(%s): %s", _channel->uri.params.udp.control_key, aeron_errmsg()); goto error_cleanup; } } if (aeron_is_addr_multicast(&endpoint_addr)) { memcpy(&_channel->remote_data, &endpoint_addr, AERON_ADDR_LEN(&endpoint_addr)); if (aeron_multicast_control_address(&endpoint_addr, &_channel->remote_control) < 0) { goto error_cleanup; } if (aeron_find_multicast_interface( endpoint_addr.ss_family, _channel->uri.params.udp.interface_key, &interface_addr, &interface_index) < 0) { aeron_set_err( aeron_errcode(), "could not find interface=(%s): %s", _channel->uri.params.udp.interface_key, aeron_errmsg()); goto error_cleanup; } _channel->interface_index = interface_index; _channel->multicast_ttl = aeron_uri_multicast_ttl(&_channel->uri); memcpy(&_channel->local_data, &interface_addr, AERON_ADDR_LEN(&interface_addr)); memcpy(&_channel->local_control, &interface_addr, AERON_ADDR_LEN(&interface_addr)); aeron_uri_udp_canonicalise( _channel->canonical_form, sizeof(_channel->canonical_form), &interface_addr, &endpoint_addr); _channel->canonical_length = strlen(_channel->canonical_form); _channel->multicast = true; } else if (NULL != _channel->uri.params.udp.control_key) { _channel->interface_index = 0; _channel->multicast_ttl = 0; memcpy(&_channel->remote_data, &endpoint_addr, AERON_ADDR_LEN(&endpoint_addr)); memcpy(&_channel->remote_control, &endpoint_addr, AERON_ADDR_LEN(&endpoint_addr)); memcpy(&_channel->local_data, &explicit_control_addr, AERON_ADDR_LEN(&explicit_control_addr)); memcpy(&_channel->local_control, &explicit_control_addr, AERON_ADDR_LEN(&explicit_control_addr)); aeron_uri_udp_canonicalise( _channel->canonical_form, sizeof(_channel->canonical_form), &explicit_control_addr, &endpoint_addr); _channel->canonical_length = strlen(_channel->canonical_form); _channel->explicit_control = true; } else { if (aeron_find_unicast_interface( endpoint_addr.ss_family, _channel->uri.params.udp.interface_key, &interface_addr, &interface_index) < 0) { goto error_cleanup; } _channel->interface_index = interface_index; _channel->multicast_ttl = 0; memcpy(&_channel->remote_data, &endpoint_addr, AERON_ADDR_LEN(&endpoint_addr)); memcpy(&_channel->remote_control, &endpoint_addr, AERON_ADDR_LEN(&endpoint_addr)); memcpy(&_channel->local_data, &interface_addr, AERON_ADDR_LEN(&interface_addr)); memcpy(&_channel->local_control, &interface_addr, AERON_ADDR_LEN(&interface_addr)); aeron_uri_udp_canonicalise( _channel->canonical_form, sizeof(_channel->canonical_form), &interface_addr, &endpoint_addr); _channel->canonical_length = strlen(_channel->canonical_form); } *channel = _channel; return 0; error_cleanup: *channel = NULL; if (NULL != _channel) { aeron_udp_channel_delete(_channel); } return -1; }