summaryrefslogtreecommitdiffstats
path: root/code/jasmine/udp-common.c
blob: c7314226ab426d06dda41f6c68c3d5f5b1bf5e9f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*##############################################################################
# Copyright (c) 2017 ZTE Coreporation and others.
# hu.zhijiang@zte.com.cn
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################*/

#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "buffer.h"
#include "udp-common.h"
#include "misc.h"

struct mc_info mcinfo;

int init_mcast_socket(struct in_addr *local_addr,
                      struct sockaddr_in *maddr)
{
    struct ip_mreqn mreqn;  /* multicast request new */
    int ms;  /* multicast socket */
    u_short msock_port;
    struct sockaddr_in bind_addr;

    int msock_reuse = MCAST_REUSE;
    u_char msock_loop = MCAST_LOOP;
    u_char msock_ttl = MCAST_TTL;

    if ((ms = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
        crit("socket() failed, error allocating multicast socket");
    }

    // In order to let client and server on same host to use same port
    if (setsockopt(ms, SOL_SOCKET, SO_REUSEADDR,
        &msock_reuse, sizeof(msock_reuse)) < 0) {
        crit("setsockopt() failed, can't set reuse flag");
    }

    if (setsockopt(ms, IPPROTO_IP, IP_MULTICAST_TTL,
        &msock_ttl,sizeof(msock_ttl)) < 0) {
        crit("setsockopt() failed, can't set ttl value");
    }

    if (setsockopt(ms, IPPROTO_IP, IP_MULTICAST_LOOP,
        &msock_loop, sizeof(msock_loop)) < 0) {
        crit("setsockopt() failed, can't set multicast packet looping");
    }

    /* TODO: Do we neet non-block? */

    log(4, "Using multicast address: %s:%d",
        inet_ntoa(maddr->sin_addr), ntohs(maddr->sin_port));

    mreqn.imr_multiaddr = maddr->sin_addr;
    mreqn.imr_address = *local_addr;
    mreqn.imr_ifindex = 0;

    /* Interface and remote mcast address choosing */

    /* This tell interface which has mreqn.imr_address to join
       mreqn.imr_multiaddr group, it has nothing to do with socket, port, and
       mreqn.imr_address. */
    if (setsockopt(ms, IPPROTO_IP, IP_ADD_MEMBERSHIP,
        &mreqn, sizeof(mreqn)) < 0) {
        crit("setsockopt() failed, %s can't join multicast group",
             inet_ntoa(*local_addr));
    }

    /* local address choosing */

    /* This tell kernel to use interface which has mreqn.imr_address as device
       and mreqn.imr_address as source addr when sending any multicast through
       socket. */
    if (setsockopt(ms, IPPROTO_IP, IP_MULTICAST_IF,
        &mreqn, sizeof(mreqn)) < 0) {
        crit("setsockopt() failed to IP_MULTICAST_IF.\n");
    }

    /* Local port choosing, remote port is choosed when calling sendto()! */

    /* This let us uses specific udp port number as source port when sending
       any multicast datagrams. So ip in maddr is useless here and should be
       INADDR_ANY, otherwise, bind will return Invalid argument. */
    msock_port = ntohs(maddr->sin_port);
    bind_addr = make_addr(0, msock_port);
    if (bind(ms, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) {
        crit("bind() error, can't bind mcast port");
    }

    return ms;
}