From 88b86d6a7a0c5a2a6ae5ef228b0a774487b8af94 Mon Sep 17 00:00:00 2001 From: Jon Shallow <supjps-libcoap@jpshallow.com> Date: Fri, 10 Jan 2025 20:13:17 +0000 Subject: [PATCH] mcast: Support specifying output interface for IPv6 multicast packets Specify the interface or scope_id in the IP address as a %suffix. For example:- examples/coap-client -N coap://[ff02::fd%interface] --- examples/coap-client.c | 1 + man/coap-client.txt.in | 7 +++++++ src/coap_address.c | 2 +- src/coap_io.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/examples/coap-client.c b/examples/coap-client.c index 46cdd2b711..eb4fd8fe31 100644 --- a/examples/coap-client.c +++ b/examples/coap-client.c @@ -651,6 +651,7 @@ usage(const char *program, const char *version) { "\tcoap-client -m get coap+tcp://%%2Funix%%2Fdomain%%2Fpath%%2Fstream/.well-known/core\n" "\tcoap-client -m get coaps://[::1]/.well-known/core\n" "\tcoap-client -m get coaps+tcp://[::1]/.well-known/core\n" + "\tcoap-client -m get -N coap://[ff02::fd%%ens32]/.well-known/core\n" "\tcoap-client -m get coaps://%%2Funix%%2Fdomain%%2Fpath%%2Fdtls/.well-known/core\n" "\tcoap-client -m get coaps+tcp://%%2Funix%%2Fdomain%%2Fpath%%2Ftls/.well-known/core\n" "\tcoap-client -m get -T cafe coap://[::1]/time\n" diff --git a/man/coap-client.txt.in b/man/coap-client.txt.in index 0c4424445e..d57ffad489 100644 --- a/man/coap-client.txt.in +++ b/man/coap-client.txt.in @@ -319,6 +319,13 @@ coap-client -m get coap://[::1]/.well-known/core Query on the resource '.well-known/core' on localhost to get back a list of the known resources along with their attribute definitions. +* Example +---- +coap-client -m get -N coap://[ff02::fd%ens32]/.well-known/core +---- +Discover the available resources along with their attribute definitions using +a multicast IP sent out over the ethernet interface ens32. + * Example ---- echo -n "mode=on" | coap-client -m put \ diff --git a/src/coap_address.c b/src/coap_address.c index 857ca847df..f2864f67ae 100644 --- a/src/coap_address.c +++ b/src/coap_address.c @@ -547,7 +547,7 @@ coap_resolve_address_info(const coap_str_const_t *address, error = getaddrinfo(addrstr, NULL, &hints, &res); if (error != 0) { - coap_log_warn("getaddrinfo: %s\n", gai_strerror(error)); + coap_log_warn("getaddrinfo: %s: %s\n", addrstr, gai_strerror(error)); return NULL; } diff --git a/src/coap_io.c b/src/coap_io.c index 8b36a4c294..882a31ca60 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -312,6 +312,11 @@ coap_socket_connect_udp(coap_socket_t *sock, coap_address_init(&bind_addr); bind_addr.addr.sa.sa_family = connect_addr.addr.sa.sa_family; +#if COAP_IPV6_SUPPORT + if (connect_addr.addr.sa.sa_family == AF_INET6) { + bind_addr.addr.sin6.sin6_scope_id = connect_addr.addr.sin6.sin6_scope_id; + } +#endif /* COAP_IPV6_SUPPORT */ if (bind(sock->fd, &bind_addr.addr.sa, #if COAP_IPV4_SUPPORT bind_addr.addr.sa.sa_family == AF_INET ? @@ -323,6 +328,16 @@ coap_socket_connect_udp(coap_socket_t *sock, goto error; } } +#if COAP_IPV6_SUPPORT + if (connect_addr.addr.sa.sa_family == AF_INET6 && !coap_is_bcast(&connect_addr)) { + int value = connect_addr.addr.sin6.sin6_scope_id; + + if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, OPTVAL_T(&value), + sizeof(value)) == COAP_SOCKET_ERROR) + coap_log_warn("coap_socket_connect_udp: getsockopt IPV6_MULTICAST_IF: %d: %s\n", + value, coap_socket_strerror()); + } +#endif /* COAP_IPV6_SUPPORT */ if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) { coap_log_warn("coap_socket_connect_udp: getsockname for multicast socket: %s\n", coap_socket_strerror()); @@ -841,6 +856,19 @@ coap_socket_send(coap_socket_t *sock, coap_session_t *session, #else bytes_written = send(sock->fd, data, datalen, 0); #endif +#if COAP_IPV6_SUPPORT + } else if (session->addr_info.remote.addr.sa.sa_family == AF_INET6 && + coap_is_mcast(&session->addr_info.remote)) { +#ifdef _WIN32 + bytes_written = sendto(sock->fd, (const void *)data, (int)datalen, 0, + &session->addr_info.remote.addr.sa, + (int)session->addr_info.remote.size); +#else + bytes_written = sendto(sock->fd, (const void *)data, datalen, 0, + &session->addr_info.remote.addr.sa, + session->addr_info.remote.size); +#endif +#endif /* COAP_IPV6_SUPPORT */ } else { #if defined(_WIN32) DWORD dwNumberOfBytesSent = 0;