Path: blob/main/tests/sys/netinet/multicast-receive.c
104817 views
/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2025 Gleb Smirnoff <[email protected]>4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/socket.h>28#include <netinet/in.h>29#include <netinet/ip.h>30#include <arpa/inet.h>31#include <net/if.h>32#include <assert.h>33#include <errno.h>34#include <stdbool.h>35#include <stdio.h>36#include <stdlib.h>37#include <string.h>38#include <sysexits.h>39#include <limits.h>40#include <err.h>4142static in_port_t43atop(const char *c)44{45unsigned long ul;4647errno = 0;48if ((ul = strtol(c, NULL, 10)) < 1 || ul > IPPORT_MAX || errno != 0)49err(1, "can't parse %s", c);5051return ((in_port_t)ul);52}5354int55main(int argc, char *argv[])56{57char buf[IP_MAXPACKET + 1];58struct sockaddr_in sin = {59.sin_family = AF_INET,60.sin_len = sizeof(struct sockaddr_in),61};62socklen_t slen = sizeof(struct sockaddr_in);63struct in_addr maddr, ifaddr;64ssize_t len;65int s, ifindex;66bool index;6768if (argc < 4)69usage:70errx(1, "Usage: %s (ip_mreq|ip_mreqn|group_req) "71"IPv4-group port interface", argv[0]);7273if (inet_pton(AF_INET, argv[2], &maddr) != 1)74err(1, "inet_pton(%s) failed", argv[2]);75sin.sin_port = htons(atop(argv[3]));76if (inet_pton(AF_INET, argv[4], &ifaddr) == 1)77index = false;78else if ((ifindex = if_nametoindex(argv[4])) > 0)79index = true;80else if (strcmp(argv[4], "0") == 0) {81ifindex = 0;82index = true;83} else84err(1, "if_nametoindex(%s) failed", argv[4]);8586assert((s = socket(PF_INET, SOCK_DGRAM, 0)) > 0);87assert(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0);8889if (strcmp(argv[1], "ip_mreq") == 0) {90if (index)91errx(1, "ip_mreq doesn't accept index");92struct ip_mreq mreq = {93.imr_multiaddr = maddr,94.imr_interface = ifaddr,95};96if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,97sizeof(mreq)) != 0)98err(EX_OSERR, "setsockopt");99} else if (strcmp(argv[1], "ip_mreqn") == 0) {100/*101* ip_mreqn shall be used with index, but for testing102* purposes accept address too.103*/104struct ip_mreqn mreqn = {105.imr_multiaddr = maddr,106.imr_address = index ? (struct in_addr){ 0 } : ifaddr,107.imr_ifindex = index ? ifindex : 0,108};109if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqn,110sizeof(mreqn)) != 0)111err(EX_OSERR, "setsockopt");112} else if (strcmp(argv[1], "group_req") == 0) {113if (!index)114errx(1, "group_req expects index");115struct group_req greq = { .gr_interface = ifindex };116struct sockaddr_in *gsa = (struct sockaddr_in *)&greq.gr_group;117118gsa->sin_family = AF_INET;119gsa->sin_len = sizeof(struct sockaddr_in);120gsa->sin_addr = maddr;121if (setsockopt(s, IPPROTO_IP, MCAST_JOIN_GROUP, &greq,122sizeof(greq)) != 0)123err(EX_OSERR, "setsockopt");124} else125goto usage;126127assert((len = recvfrom(s, buf, sizeof(buf) - 1, 0,128(struct sockaddr *)&sin, &slen)) > 0);129buf[len] = '\0';130printf("%s:%u %s\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), buf);131132return (0);133}134135136