xref: /aosp_15_r20/external/openthread/tests/scripts/thread-cert/mcast6.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cfb92d14SAndroid Build Coastguard Worker#
3*cfb92d14SAndroid Build Coastguard Worker#  Copyright (c) 2020, The OpenThread Authors.
4*cfb92d14SAndroid Build Coastguard Worker#  All rights reserved.
5*cfb92d14SAndroid Build Coastguard Worker#
6*cfb92d14SAndroid Build Coastguard Worker#  Redistribution and use in source and binary forms, with or without
7*cfb92d14SAndroid Build Coastguard Worker#  modification, are permitted provided that the following conditions are met:
8*cfb92d14SAndroid Build Coastguard Worker#  1. Redistributions of source code must retain the above copyright
9*cfb92d14SAndroid Build Coastguard Worker#     notice, this list of conditions and the following disclaimer.
10*cfb92d14SAndroid Build Coastguard Worker#  2. Redistributions in binary form must reproduce the above copyright
11*cfb92d14SAndroid Build Coastguard Worker#     notice, this list of conditions and the following disclaimer in the
12*cfb92d14SAndroid Build Coastguard Worker#     documentation and/or other materials provided with the distribution.
13*cfb92d14SAndroid Build Coastguard Worker#  3. Neither the name of the copyright holder nor the
14*cfb92d14SAndroid Build Coastguard Worker#     names of its contributors may be used to endorse or promote products
15*cfb92d14SAndroid Build Coastguard Worker#     derived from this software without specific prior written permission.
16*cfb92d14SAndroid Build Coastguard Worker#
17*cfb92d14SAndroid Build Coastguard Worker#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18*cfb92d14SAndroid Build Coastguard Worker#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*cfb92d14SAndroid Build Coastguard Worker#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*cfb92d14SAndroid Build Coastguard Worker#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21*cfb92d14SAndroid Build Coastguard Worker#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*cfb92d14SAndroid Build Coastguard Worker#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*cfb92d14SAndroid Build Coastguard Worker#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*cfb92d14SAndroid Build Coastguard Worker#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*cfb92d14SAndroid Build Coastguard Worker#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*cfb92d14SAndroid Build Coastguard Worker#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*cfb92d14SAndroid Build Coastguard Worker#  POSSIBILITY OF SUCH DAMAGE.
28*cfb92d14SAndroid Build Coastguard Worker#
29*cfb92d14SAndroid Build Coastguard Workerimport ctypes
30*cfb92d14SAndroid Build Coastguard Workerimport ctypes.util
31*cfb92d14SAndroid Build Coastguard Workerimport socket
32*cfb92d14SAndroid Build Coastguard Workerimport struct
33*cfb92d14SAndroid Build Coastguard Workerimport sys
34*cfb92d14SAndroid Build Coastguard Workerimport time
35*cfb92d14SAndroid Build Coastguard Worker
36*cfb92d14SAndroid Build Coastguard WorkerMYPORT = 8123
37*cfb92d14SAndroid Build Coastguard WorkerMYTTL = 1  # Increase to reach other networks
38*cfb92d14SAndroid Build Coastguard Worker
39*cfb92d14SAndroid Build Coastguard Workerlibc = ctypes.CDLL(ctypes.util.find_library('c'))
40*cfb92d14SAndroid Build Coastguard Worker
41*cfb92d14SAndroid Build Coastguard Worker
42*cfb92d14SAndroid Build Coastguard Workerdef if_nametoindex(name):
43*cfb92d14SAndroid Build Coastguard Worker    if not isinstance(name, str):
44*cfb92d14SAndroid Build Coastguard Worker        raise TypeError('name must be a string.')
45*cfb92d14SAndroid Build Coastguard Worker    ret = libc.if_nametoindex(name.encode('ascii'))
46*cfb92d14SAndroid Build Coastguard Worker    if not ret:
47*cfb92d14SAndroid Build Coastguard Worker        raise RuntimeError("Invalid Name")
48*cfb92d14SAndroid Build Coastguard Worker    return ret
49*cfb92d14SAndroid Build Coastguard Worker
50*cfb92d14SAndroid Build Coastguard Worker
51*cfb92d14SAndroid Build Coastguard Workerdef if_indextoname(index):
52*cfb92d14SAndroid Build Coastguard Worker    if not isinstance(index, int):
53*cfb92d14SAndroid Build Coastguard Worker        raise TypeError('index must be an int.')
54*cfb92d14SAndroid Build Coastguard Worker    libc.if_indextoname.argtypes = [ctypes.c_uint32, ctypes.c_char_p]
55*cfb92d14SAndroid Build Coastguard Worker    libc.if_indextoname.restype = ctypes.c_char_p
56*cfb92d14SAndroid Build Coastguard Worker
57*cfb92d14SAndroid Build Coastguard Worker    ifname = ctypes.create_string_buffer(32)
58*cfb92d14SAndroid Build Coastguard Worker    ifname = libc.if_indextoname(index, ifname)
59*cfb92d14SAndroid Build Coastguard Worker    if not ifname:
60*cfb92d14SAndroid Build Coastguard Worker        raise RuntimeError("Invalid Index")
61*cfb92d14SAndroid Build Coastguard Worker    return ifname
62*cfb92d14SAndroid Build Coastguard Worker
63*cfb92d14SAndroid Build Coastguard Worker
64*cfb92d14SAndroid Build Coastguard Workerdef main():
65*cfb92d14SAndroid Build Coastguard Worker    args = sys.argv[1:]
66*cfb92d14SAndroid Build Coastguard Worker    is_sender = False
67*cfb92d14SAndroid Build Coastguard Worker
68*cfb92d14SAndroid Build Coastguard Worker    if args[0] == '-s':
69*cfb92d14SAndroid Build Coastguard Worker        is_sender = True
70*cfb92d14SAndroid Build Coastguard Worker        args.pop(0)
71*cfb92d14SAndroid Build Coastguard Worker    elif args[0] == '-u':
72*cfb92d14SAndroid Build Coastguard Worker        is_multicast_receiver = False
73*cfb92d14SAndroid Build Coastguard Worker        args.pop(0)
74*cfb92d14SAndroid Build Coastguard Worker    else:
75*cfb92d14SAndroid Build Coastguard Worker        is_multicast_receiver = True
76*cfb92d14SAndroid Build Coastguard Worker
77*cfb92d14SAndroid Build Coastguard Worker    ifname, group = args
78*cfb92d14SAndroid Build Coastguard Worker
79*cfb92d14SAndroid Build Coastguard Worker    if is_sender:
80*cfb92d14SAndroid Build Coastguard Worker        sender(ifname, group)
81*cfb92d14SAndroid Build Coastguard Worker    else:
82*cfb92d14SAndroid Build Coastguard Worker        receiver(ifname, group, is_multicast_receiver=is_multicast_receiver)
83*cfb92d14SAndroid Build Coastguard Worker
84*cfb92d14SAndroid Build Coastguard Worker
85*cfb92d14SAndroid Build Coastguard Workerdef sender(ifname, group):
86*cfb92d14SAndroid Build Coastguard Worker    addrinfo = socket.getaddrinfo(group, None)[0]
87*cfb92d14SAndroid Build Coastguard Worker
88*cfb92d14SAndroid Build Coastguard Worker    s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
89*cfb92d14SAndroid Build Coastguard Worker    s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, (ifname + '\0').encode('ascii'))
90*cfb92d14SAndroid Build Coastguard Worker
91*cfb92d14SAndroid Build Coastguard Worker    # Set Time-to-live (optional)
92*cfb92d14SAndroid Build Coastguard Worker    ttl_bin = struct.pack('@i', MYTTL)
93*cfb92d14SAndroid Build Coastguard Worker    assert addrinfo[0] == socket.AF_INET6
94*cfb92d14SAndroid Build Coastguard Worker    s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl_bin)
95*cfb92d14SAndroid Build Coastguard Worker
96*cfb92d14SAndroid Build Coastguard Worker    while True:
97*cfb92d14SAndroid Build Coastguard Worker        data = repr(time.time())
98*cfb92d14SAndroid Build Coastguard Worker        s.sendto((data + '\0').encode('ascii'), (addrinfo[4][0], MYPORT))
99*cfb92d14SAndroid Build Coastguard Worker        time.sleep(1)
100*cfb92d14SAndroid Build Coastguard Worker
101*cfb92d14SAndroid Build Coastguard Worker
102*cfb92d14SAndroid Build Coastguard Workerdef receiver(ifname, group, is_multicast_receiver=True):
103*cfb92d14SAndroid Build Coastguard Worker    # Look up multicast group address in name server and find out IP version
104*cfb92d14SAndroid Build Coastguard Worker    addrinfo = socket.getaddrinfo(group, None)[0]
105*cfb92d14SAndroid Build Coastguard Worker    assert addrinfo[0] == socket.AF_INET6
106*cfb92d14SAndroid Build Coastguard Worker
107*cfb92d14SAndroid Build Coastguard Worker    # Create a socket
108*cfb92d14SAndroid Build Coastguard Worker    s = socket.socket(addrinfo[0], socket.SOCK_DGRAM)
109*cfb92d14SAndroid Build Coastguard Worker    s.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, (ifname + '\0').encode('ascii'))
110*cfb92d14SAndroid Build Coastguard Worker
111*cfb92d14SAndroid Build Coastguard Worker    # Allow multiple copies of this program on one machine
112*cfb92d14SAndroid Build Coastguard Worker    # (not strictly needed)
113*cfb92d14SAndroid Build Coastguard Worker    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
114*cfb92d14SAndroid Build Coastguard Worker
115*cfb92d14SAndroid Build Coastguard Worker    # Bind it to the port
116*cfb92d14SAndroid Build Coastguard Worker    s.bind(('', MYPORT))
117*cfb92d14SAndroid Build Coastguard Worker
118*cfb92d14SAndroid Build Coastguard Worker    if is_multicast_receiver:
119*cfb92d14SAndroid Build Coastguard Worker        group_bin = socket.inet_pton(addrinfo[0], addrinfo[4][0])
120*cfb92d14SAndroid Build Coastguard Worker        # Join group
121*cfb92d14SAndroid Build Coastguard Worker        interface_index = if_nametoindex(ifname)
122*cfb92d14SAndroid Build Coastguard Worker        mreq = group_bin + struct.pack('@I', interface_index)
123*cfb92d14SAndroid Build Coastguard Worker        s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, mreq)
124*cfb92d14SAndroid Build Coastguard Worker
125*cfb92d14SAndroid Build Coastguard Worker    # Loop, printing any data we receive
126*cfb92d14SAndroid Build Coastguard Worker    while True:
127*cfb92d14SAndroid Build Coastguard Worker        data, sender = s.recvfrom(1500)
128*cfb92d14SAndroid Build Coastguard Worker        while data[-1:] == '\0':
129*cfb92d14SAndroid Build Coastguard Worker            data = data[:-1]  # Strip trailing \0's
130*cfb92d14SAndroid Build Coastguard Worker        print(str(sender) + '  ' + repr(data))
131*cfb92d14SAndroid Build Coastguard Worker
132*cfb92d14SAndroid Build Coastguard Worker
133*cfb92d14SAndroid Build Coastguard Workerif __name__ == '__main__':
134*cfb92d14SAndroid Build Coastguard Worker    main()
135