UDP IPv6连接在选择多播默认接口时失败

发布于 2025-02-05 19:38:55 字数 3500 浏览 3 评论 0原文

问题描述

我目前正在尝试使用多播设置IPv6客户端/服务器UDP通信。

连接 +发送

我面临的问题在Connect call for IPv6 udp Multicast套接字:

  • (a)如果我选择默认接口0使用SetSockoptipv6_multicast_if连接调用将失败。
  • (b)如果我选择与系统中一个实际活动的多播接口相对应的接口索引(例如f_nametoindex(“ eth0”)),则它将成功。

使用sendto没有先验连接的sendto

,在两种情况下,默认接口 0 (a)将在两种情况下成功使用。 或通过IF_NAMETOINDEX (b)的相应接口。

示例

该示例显示运行客户端以发送到多播地址的四个可能性。编译和运行:

  • 连接 +发送(a):./ main 1 - 失败:无效参数
  • 连接 + send(b):./ main 1 eth0 - 成功
  • sendto (a):./ main 0 - 成功
  • sendto(b):./ main 0 eth0 - 成功
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define MAXBUF 65536
#define ADDR "ff02::1:5"
#define PORT "50000"

int client(int use_connect_and_send, int interface_index) {
    int sock;
    int status;
    struct addrinfo sainfo, *psinfo, *linfo;
    struct sockaddr_in6 sin6;
    int sin6len;
    char buffer[MAXBUF];
    sprintf(buffer, "hello");

    sin6len = sizeof(struct sockaddr_in6);

    sock = socket(AF_INET6, SOCK_DGRAM, 0);

    memset(&sin6, 0, sizeof(struct sockaddr_in6));
    sin6.sin6_port = htons(0);
    sin6.sin6_family = AF_INET6;
    sin6.sin6_addr = in6addr_any;

    memset(&sainfo, 0, sizeof(struct addrinfo));
    memset(&sin6, 0, sin6len);

    sainfo.ai_flags = 0;
    sainfo.ai_family = AF_UNSPEC;
    sainfo.ai_socktype = SOCK_DGRAM;
    sainfo.ai_protocol = IPPROTO_UDP;
    
    status = getaddrinfo(ADDR, PORT, &sainfo, &psinfo);

    struct ipv6_mreq ipv6;
    ipv6.ipv6mr_interface = interface_index;

    if((setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const void *) &ipv6.ipv6mr_interface, 
                sizeof(ipv6.ipv6mr_interface))) < 0) {
        perror("Setting local interface error");
    }

    if (use_connect_and_send) {
        status = connect(sock, (struct sockaddr *)psinfo->ai_addr, sin6len);
        if(status != 0) {
           perror("connect failed");
           exit(EXIT_FAILURE);
        }
        status = send(sock, buffer, strlen(buffer), 0);
    } else {
        status = sendto(sock, buffer, strlen(buffer), 0,
                 (struct sockaddr *)psinfo->ai_addr, sin6len);
    }
    if (status < 0) {
        perror("send failed");
    }
    printf("buffer : %s \t%d\n", buffer, status);

    // free memory
    freeaddrinfo(psinfo);
    psinfo = NULL;

    shutdown(sock, 2);
    close(sock);
    return 0;
}


int main(int argc, char* argv[]) {
    if(argc < 2) {
        printf("specify wheter or not to use sendto (0) or connect+send (1)\n");
        exit(EXIT_FAILURE);
    }
    int use_connect_and_send = atoi(argv[1]);
    int interface_index = 0; 
    if(argc > 2) {
        interface_index = if_nametoindex(argv[2]);
        if (interface_index == 0) {
            perror("nametoindex failed, does the given interface exist?");
        }
    }
    client(use_connect_and_send, interface_index);
} 

问题

你知道我在这种情况下做错了什么<强>连接 +发送(a)?为什么它的行为与sendto在默认接口中取得成功的情况有所不同?

Problem description

I'm currently trying to set up an ipv6 client/server UDP communication with multicast.

connect + send

The problem I'm facing occurs during the connect call for ipv6 UDP multicast socket:

  • (a) If I choose the default interface 0 with setsockopt and IPV6_MULTICAST_IF the connect call will fail.
  • (b) If I choose an interface index that corresponds to one actual active multicast interface in my system (e.g. ìf_nametoindex("eth0")) then it will succeed.

sendto

When using sendto without a prior connect for the destination address it will succeed in both cases with the default interface 0 (a) or a corresponding interface via if_nametoindex (b).

Example

The example showcases the four possibilities of running the client to send to a multicast address. Compile and run:

  • connect + send (a): ./main 1 - Fails with: Invalid argument
  • connect + send (b): ./main 1 eth0 - Succeeds
  • sendto (a): ./main 0 - Succeeds
  • sendto (b): ./main 0 eth0 - Succeeds
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define MAXBUF 65536
#define ADDR "ff02::1:5"
#define PORT "50000"

int client(int use_connect_and_send, int interface_index) {
    int sock;
    int status;
    struct addrinfo sainfo, *psinfo, *linfo;
    struct sockaddr_in6 sin6;
    int sin6len;
    char buffer[MAXBUF];
    sprintf(buffer, "hello");

    sin6len = sizeof(struct sockaddr_in6);

    sock = socket(AF_INET6, SOCK_DGRAM, 0);

    memset(&sin6, 0, sizeof(struct sockaddr_in6));
    sin6.sin6_port = htons(0);
    sin6.sin6_family = AF_INET6;
    sin6.sin6_addr = in6addr_any;

    memset(&sainfo, 0, sizeof(struct addrinfo));
    memset(&sin6, 0, sin6len);

    sainfo.ai_flags = 0;
    sainfo.ai_family = AF_UNSPEC;
    sainfo.ai_socktype = SOCK_DGRAM;
    sainfo.ai_protocol = IPPROTO_UDP;
    
    status = getaddrinfo(ADDR, PORT, &sainfo, &psinfo);

    struct ipv6_mreq ipv6;
    ipv6.ipv6mr_interface = interface_index;

    if((setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (const void *) &ipv6.ipv6mr_interface, 
                sizeof(ipv6.ipv6mr_interface))) < 0) {
        perror("Setting local interface error");
    }

    if (use_connect_and_send) {
        status = connect(sock, (struct sockaddr *)psinfo->ai_addr, sin6len);
        if(status != 0) {
           perror("connect failed");
           exit(EXIT_FAILURE);
        }
        status = send(sock, buffer, strlen(buffer), 0);
    } else {
        status = sendto(sock, buffer, strlen(buffer), 0,
                 (struct sockaddr *)psinfo->ai_addr, sin6len);
    }
    if (status < 0) {
        perror("send failed");
    }
    printf("buffer : %s \t%d\n", buffer, status);

    // free memory
    freeaddrinfo(psinfo);
    psinfo = NULL;

    shutdown(sock, 2);
    close(sock);
    return 0;
}


int main(int argc, char* argv[]) {
    if(argc < 2) {
        printf("specify wheter or not to use sendto (0) or connect+send (1)\n");
        exit(EXIT_FAILURE);
    }
    int use_connect_and_send = atoi(argv[1]);
    int interface_index = 0; 
    if(argc > 2) {
        interface_index = if_nametoindex(argv[2]);
        if (interface_index == 0) {
            perror("nametoindex failed, does the given interface exist?");
        }
    }
    client(use_connect_and_send, interface_index);
} 

Question

Do you know what I'm doing wrong in the case connect + send (a) ? Why does it behave differently from sendto which succeeds with the default interface?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文