blob: b318fe5d1e28e7344a4e5b7cf250a61eca23aedc [file] [log] [blame]
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +02001/*
2 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +020015 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21#include <fcntl.h>
22#include <inttypes.h>
23
24#include <sys/socket.h>
25#include <arpa/inet.h>
26#include <netinet/in.h>
27
28#include <osmocom/core/application.h>
29#include <osmocom/core/utils.h>
30#include <osmocom/core/socket.h>
31#include <osmocom/core/logging.h>
32#include <osmocom/core/bits.h>
33
34#include "../config.h"
35
36void *ctx = NULL;
37
38#ifdef HAVE_LIBSCTP
39static uint16_t sock_get_local_port(int fd, bool is_v6) {
40 struct sockaddr_storage sa;
41 struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
42 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
43 socklen_t len = sizeof(sa);
44 int local_port;
45
46 OSMO_ASSERT(getsockname(fd, (struct sockaddr*)&sa, &len) == 0);
47 if(!is_v6)
48 local_port = osmo_load16be(&sin->sin_port);
49 else
50 local_port = osmo_load16be(&sin6->sin6_port);
51 //printf("Checking osmo_sock_init2_multiaddr() port: %" PRIu16 "\n", listen_port_v4);
52 return local_port;
53}
54
55/* Test API osmo_sock_init2_multiaddr with 1 local/remote address */
56static int test_sockinit2_multiaddr(const char **addrv4_loc, const char **addrv6_loc,
57 const char **addrv4_rem, const char **addrv6_rem,
58 size_t addrv4_size, size_t addrv6_size)
59{
60 int fd, rc;
61 int listen_fd_v4, listen_fd_v6;
62 int listen_port_v4, listen_port_v6;
63
64 printf("Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv4 port\n");
65
66 listen_fd_v4 = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,
67 addrv4_loc, addrv4_size, 0,
68 NULL, 0, 0, OSMO_SOCK_F_BIND);
69 OSMO_ASSERT(listen_fd_v4 >= 0);
70 /* expect it to be blocking */
71 rc = fcntl(listen_fd_v4, F_GETFL);
72 OSMO_ASSERT(!(rc & O_NONBLOCK));
73
74 listen_port_v4 = sock_get_local_port(listen_fd_v4, false);
75
76 printf("Checking osmo_sock_init2_multiaddr() with bind to a random local SCTP IPv6 port\n");
77
78 listen_fd_v6 = osmo_sock_init2_multiaddr(AF_INET6, SOCK_STREAM, IPPROTO_SCTP,
79 addrv6_loc, addrv6_size, 0,
80 NULL, 0, 0, OSMO_SOCK_F_BIND);
81 OSMO_ASSERT(listen_fd_v6 >= 0);
82 /* expect it to be blocking */
83 rc = fcntl(listen_fd_v6, F_GETFL);
84 OSMO_ASSERT(!(rc & O_NONBLOCK));
85
86 listen_port_v6 = sock_get_local_port(listen_fd_v6, true);
87
88 printf("Checking osmo_sock_init2_multiaddr() for OSMO_SOCK_F_NONBLOCK\n");
89 fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,
90 addrv4_loc, addrv4_size, 0,
91 NULL, 0, 0, OSMO_SOCK_F_BIND|OSMO_SOCK_F_NONBLOCK);
92 OSMO_ASSERT(fd >= 0);
93 /* expect it to be blocking */
94 rc = fcntl(fd, F_GETFL);
95 OSMO_ASSERT(rc & O_NONBLOCK);
96 close(fd);
97
98 printf("Checking osmo_sock_init2_multiaddr() for invalid flags\n");
99 fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,
100 addrv4_loc, addrv4_size, 0,
101 NULL, 0, 0, 0);
102 OSMO_ASSERT(fd < 0);
103
104 printf("Checking osmo_sock_init2_multiaddr() for combined BIND + CONNECT\n");
105 fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,
106 addrv4_rem, addrv4_size, 0,
107 addrv4_rem, addrv4_size, listen_port_v4,
108 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
109 OSMO_ASSERT(fd >= 0);
110
111 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv4 & IPv6\n");
112 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
113 addrv4_rem, addrv4_size, 0,
114 addrv6_rem, addrv6_size, listen_port_v6,
115 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
116 OSMO_ASSERT(fd < 0);
117
118 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv6 & IPv4\n");
119 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
120 addrv6_rem, addrv6_size, 0,
121 addrv4_rem, addrv4_size, listen_port_v4,
122 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
123 OSMO_ASSERT(fd < 0);
124
125 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4\n");
126 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
127 addrv4_rem, addrv4_size, 0,
128 addrv4_rem, addrv4_size, listen_port_v4,
129 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
130 OSMO_ASSERT(fd >= 0);
131
132 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv6\n");
133 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
134 addrv6_rem, addrv6_size, 0,
135 addrv6_rem, addrv6_size, listen_port_v6,
136 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
137 OSMO_ASSERT(fd >= 0);
138
139 close(listen_fd_v4);
140 close(listen_fd_v6);
141 printf("Done\n");
142 return 0;
143}
144
145/* Test API osmo_sock_init2_multiaddr with 1 local/remote address */
146static int test_sockinit2_multiaddr_simple(void)
147{
148 const char *addrv4_loc[] = { "0.0.0.0" };
149 const char *addrv6_loc[] = { "::" };
150 const char *addrv4_rem[] = { "127.0.0.1" };
151 const char *addrv6_rem[] = { "::1" };
152
153 return test_sockinit2_multiaddr(addrv4_loc, addrv6_loc,
154 addrv4_rem, addrv6_rem, 1, 1);
155}
156
157/* Test API osmo_sock_init2_multiaddr with several local/remote address */
158static int test_sockinit2_multiaddr_several(void)
159{
160 const char *addrv4_localhost[] = { "127.0.0.1", "127.0.0.2" };
161 const char *addrv6_localhost[] = { "::1" };
162
163 return test_sockinit2_multiaddr(addrv4_localhost, addrv6_localhost,
164 addrv4_localhost, addrv6_localhost, 2, 1);
165}
166
167/* Test API osmo_sock_init2_multiaddr with several local/remote address, using both ipv4+v6 */
168static int test_sockinit2_multiaddr_mixed(void)
169{
170 const char *addr_localhost[] = { "127.0.0.1", "127.0.0.2", "::1" };
171 size_t addr_size = ARRAY_SIZE(addr_localhost);
172
173 int listen_fd, listen_port, fd;
174
175 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET IPv4+v6 fails\n");
176 listen_fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,
177 addr_localhost, addr_size, 0,
178 NULL, 0, 0, OSMO_SOCK_F_BIND);
179 OSMO_ASSERT(listen_fd < 0);
180
181 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET6 IPv4+v6 fails\n");
182 listen_fd = osmo_sock_init2_multiaddr(AF_INET6, SOCK_STREAM, IPPROTO_SCTP,
183 addr_localhost, addr_size, 0,
184 NULL, 0, 0, OSMO_SOCK_F_BIND);
185 OSMO_ASSERT(listen_fd < 0);
186
187 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_UNSPEC IPv4+v6 succeeds\n");
188 listen_fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
189 addr_localhost, addr_size, 0,
190 NULL, 0, 0, OSMO_SOCK_F_BIND);
191 OSMO_ASSERT(listen_fd >= 0);
192
193 listen_port = sock_get_local_port(listen_fd, true);
194
195 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4\n");
196 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
197 addr_localhost, addr_size, 0,
198 addr_localhost, addr_size, listen_port,
199 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
200 OSMO_ASSERT(fd >= 0);
201 close(fd);
202
203 close(listen_fd);
204 return 0;
205}
206#endif /* ifdef HAVE_LIBSCTP */
207
208const struct log_info_cat default_categories[] = {
209};
210
211static struct log_info info = {
212 .cat = default_categories,
213 .num_cat = ARRAY_SIZE(default_categories),
214};
215
216int main(int argc, char *argv[])
217{
218 ctx = talloc_named_const(NULL, 0, "socket_test_sctp");
219 osmo_init_logging2(ctx, &info);
220 log_set_use_color(osmo_stderr_target, 0);
Pau Espin Pedrol01e0d3e2021-02-18 19:25:44 +0100221 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
Pau Espin Pedrol690b6612021-02-18 19:10:28 +0100222 log_set_print_category(osmo_stderr_target, 0);
223 log_set_print_category_hex(osmo_stderr_target, 0);
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +0200224#ifdef HAVE_LIBSCTP
225 test_sockinit2_multiaddr_simple();
226 test_sockinit2_multiaddr_several();
227 test_sockinit2_multiaddr_mixed();
228#endif /* ifdef HAVE_LIBSCTP */
229
230 return EXIT_SUCCESS;
231}