File: testnet.c

package info (click to toggle)
librecast 0.11.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,760 kB
  • sloc: ansic: 31,144; asm: 28,570; sh: 3,164; makefile: 713; python: 70
file content (137 lines) | stat: -rw-r--r-- 3,631 bytes parent folder | download | duplicates (4)
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2022-2023 Brett Sheffield <bacs@librecast.net> */

#include "test.h"
#include <errno.h>
#include <ifaddrs.h>
#ifdef __linux__
# include <librecast.h>
# include <librecast/if.h>
#endif
#include <limits.h>
#include <net/if.h>
#include <sys/types.h>

#ifndef AF_LINK
# ifdef AF_PACKET
#  define AF_LINK AF_PACKET
# endif
#endif

unsigned int get_invalid_ifx(void)
{
	char ifname[IF_NAMESIZE];
	for (unsigned int ifx = 1; ifx < UINT_MAX; ifx++) {
		if (!if_indextoname(ifx, ifname)) return ifx;
	}
	return 0;
}

/* find an interface that supports multicast */
unsigned get_multicast_if(void)
{
	unsigned ifidx = 0;
	/* create tap interface and bring it up */
	char ifname[IFNAMSIZ] = {0};
#ifdef __linux__
	lc_tuntap_create(ifname, IFF_TAP | IFF_NO_PI);
	lc_ctx_t *lctx = lc_ctx_new();
	lc_link_set(lctx, ifname, 1);
	lc_ctx_free(lctx);
	ifidx = if_nametoindex(ifname);
#endif
	if (!ifidx) {
		test_log("unable to create tap device: %s\n", strerror(errno));
		/* failed to create tap, find multicast capable interface */
		struct ifaddrs *ifa = NULL, *ifap = NULL;
		test_assert(getifaddrs(&ifa) != -1, "getifaddrs(): %s", strerror(errno));
		for (ifap = ifa; ifap; ifap = ifap->ifa_next) {
			if (!(ifap->ifa_flags & IFF_MULTICAST)) continue;
			/* we don't want the loopback interface */
			if (ifap->ifa_flags & IFF_LOOPBACK) continue;
			if (ifap->ifa_addr == NULL) continue;
			if (ifap->ifa_addr->sa_family != AF_INET6) continue;
			ifidx = if_nametoindex(ifap->ifa_name);
			test_log("found multicast interface %s [%u]\n", ifap->ifa_name, ifidx);
			break;
		}
		freeifaddrs(ifa);
	}
	else {
		test_log("tap %s created\n", ifname);
	}
	return ifidx;
}

int test_net_level(void)
{
	struct ifaddrs *ifaddr;
	int ifaces = 0;
	int ifup = 0;
	int mcast = 0;
	int addr6 = 0;
	int addr4 = 0;
	int level = 0;
	int mroutes = 0;
	char * have_multicast = getenv("HAVE_MULTICAST_ROUTES");

	test_init();
	test_log("Checking network connectivity...\n");
	if (getifaddrs(&ifaddr) == -1) return -1;

	for (struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
		switch (ifa->ifa_addr->sa_family) {
			case AF_LINK:
				ifaces++;
				if (ifa->ifa_flags & IFF_UP) {
					ifup++;
					/* test MULTICAST flag, skip loopback interfaces */
					if (ifa->ifa_flags & IFF_LOOPBACK) break;
					if (ifa->ifa_flags & IFF_MULTICAST) mcast++;
				}
				break;
			case AF_INET6:
				if (ifa->ifa_flags & IFF_UP) addr6++;
				break;
			case AF_INET:
				if (ifa->ifa_flags & IFF_UP) addr4++;
				break;
		}
	}
	freeifaddrs(ifaddr);

	test_log("have_multicast: %s\n", have_multicast);

	if (have_multicast) mroutes = atoi(have_multicast);

	test_log(" %i network interfaces found\n", ifaces);
	test_log(" %i network interfaces up\n", ifup);
	test_log(" %i MULTICAST interfaces up\n", mcast);
	test_log(" %i IPv6 addresses\n", addr6);
	test_log(" %i IPv4 addresses\n", addr4);
	test_log(" %i multicast routes\n", mroutes);

	level |= (ifaces > 0);
	level |= (ifup > 0) << 1;
	level |= (addr4 > 0) << 2;
	level |= (addr6 > 0) << 3;
	level |= (mcast > 0) << 4;
	level |= (mroutes > 0) << 5;
	test_log("connectivity level = %i (%06b)\n", level, level);

	return level;
}


int test_require_net(int required)
{
	int lvl = test_net_level();
	if ((lvl & required) != required) {
		test_log("------------------------------------------------------\n");
		test_log("Required network level not met. Skipping test.        \n");
		test_log("(%06b/%06b)\n", lvl, required);
		test_log("------------------------------------------------------\n");
		exit(TEST_WARN);
	}
	return lvl;
}