blob: 5948abc09c85a40fbffce77b2388fb2be169488b [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
Pau Espin Pedrol88955fb2023-01-18 18:54:00 +010034#include "config.h"
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +020035
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);
Pau Espin Pedrol5b4135c2023-12-05 18:28:05 +0100110 close(fd);
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +0200111
112 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv4 & IPv6\n");
113 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
114 addrv4_rem, addrv4_size, 0,
115 addrv6_rem, addrv6_size, listen_port_v6,
116 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
117 OSMO_ASSERT(fd < 0);
118
119 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) must fail on mixed IPv6 & IPv4\n");
120 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
121 addrv6_rem, addrv6_size, 0,
122 addrv4_rem, addrv4_size, listen_port_v4,
123 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
124 OSMO_ASSERT(fd < 0);
125
126 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4\n");
127 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
128 addrv4_rem, addrv4_size, 0,
129 addrv4_rem, addrv4_size, listen_port_v4,
130 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
131 OSMO_ASSERT(fd >= 0);
Pau Espin Pedrol5b4135c2023-12-05 18:28:05 +0100132 close(fd);
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +0200133
134 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv6\n");
135 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
136 addrv6_rem, addrv6_size, 0,
137 addrv6_rem, addrv6_size, listen_port_v6,
138 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
139 OSMO_ASSERT(fd >= 0);
Pau Espin Pedrol5b4135c2023-12-05 18:28:05 +0100140 close(fd);
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +0200141
142 close(listen_fd_v4);
143 close(listen_fd_v6);
144 printf("Done\n");
145 return 0;
146}
147
148/* Test API osmo_sock_init2_multiaddr with 1 local/remote address */
149static int test_sockinit2_multiaddr_simple(void)
150{
151 const char *addrv4_loc[] = { "0.0.0.0" };
152 const char *addrv6_loc[] = { "::" };
153 const char *addrv4_rem[] = { "127.0.0.1" };
154 const char *addrv6_rem[] = { "::1" };
155
156 return test_sockinit2_multiaddr(addrv4_loc, addrv6_loc,
157 addrv4_rem, addrv6_rem, 1, 1);
158}
159
160/* Test API osmo_sock_init2_multiaddr with several local/remote address */
161static int test_sockinit2_multiaddr_several(void)
162{
163 const char *addrv4_localhost[] = { "127.0.0.1", "127.0.0.2" };
164 const char *addrv6_localhost[] = { "::1" };
165
166 return test_sockinit2_multiaddr(addrv4_localhost, addrv6_localhost,
167 addrv4_localhost, addrv6_localhost, 2, 1);
168}
169
170/* Test API osmo_sock_init2_multiaddr with several local/remote address, using both ipv4+v6 */
171static int test_sockinit2_multiaddr_mixed(void)
172{
173 const char *addr_localhost[] = { "127.0.0.1", "127.0.0.2", "::1" };
174 size_t addr_size = ARRAY_SIZE(addr_localhost);
175
176 int listen_fd, listen_port, fd;
177
178 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET IPv4+v6 fails\n");
179 listen_fd = osmo_sock_init2_multiaddr(AF_INET, SOCK_STREAM, IPPROTO_SCTP,
180 addr_localhost, addr_size, 0,
181 NULL, 0, 0, OSMO_SOCK_F_BIND);
182 OSMO_ASSERT(listen_fd < 0);
183
184 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_INET6 IPv4+v6 fails\n");
185 listen_fd = osmo_sock_init2_multiaddr(AF_INET6, SOCK_STREAM, IPPROTO_SCTP,
186 addr_localhost, addr_size, 0,
187 NULL, 0, 0, OSMO_SOCK_F_BIND);
188 OSMO_ASSERT(listen_fd < 0);
189
190 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND on AF_UNSPEC IPv4+v6 succeeds\n");
191 listen_fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
192 addr_localhost, addr_size, 0,
193 NULL, 0, 0, OSMO_SOCK_F_BIND);
194 OSMO_ASSERT(listen_fd >= 0);
195
196 listen_port = sock_get_local_port(listen_fd, true);
197
198 printf("Checking osmo_sock_init2_multiaddr(AF_UNSPEC) BIND + CONNECT on IPv4\n");
199 fd = osmo_sock_init2_multiaddr(AF_UNSPEC, SOCK_STREAM, IPPROTO_SCTP,
200 addr_localhost, addr_size, 0,
201 addr_localhost, addr_size, listen_port,
202 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT);
203 OSMO_ASSERT(fd >= 0);
204 close(fd);
205
206 close(listen_fd);
207 return 0;
208}
209#endif /* ifdef HAVE_LIBSCTP */
210
211const struct log_info_cat default_categories[] = {
212};
213
214static struct log_info info = {
215 .cat = default_categories,
216 .num_cat = ARRAY_SIZE(default_categories),
217};
218
219int main(int argc, char *argv[])
220{
221 ctx = talloc_named_const(NULL, 0, "socket_test_sctp");
222 osmo_init_logging2(ctx, &info);
223 log_set_use_color(osmo_stderr_target, 0);
Pau Espin Pedrol01e0d3e2021-02-18 19:25:44 +0100224 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
Pau Espin Pedrol690b6612021-02-18 19:10:28 +0100225 log_set_print_category(osmo_stderr_target, 0);
226 log_set_print_category_hex(osmo_stderr_target, 0);
Pau Espin Pedrol16b076c2020-08-25 13:56:43 +0200227#ifdef HAVE_LIBSCTP
228 test_sockinit2_multiaddr_simple();
229 test_sockinit2_multiaddr_several();
230 test_sockinit2_multiaddr_mixed();
231#endif /* ifdef HAVE_LIBSCTP */
232
233 return EXIT_SUCCESS;
234}