1 /**
2 * Copyright (C) Mellanox Technologies Ltd. 2019. ALL RIGHTS RESERVED.
3 *
4 * See file LICENSE for terms.
5 */
6
7 #include <common/test.h>
8 extern "C" {
9 #include <ucs/sys/sock.h>
10 }
11
12 #include <sys/un.h>
13
14
15 static std::string socket_err_exp_str;
16
17 class test_socket : public ucs::test {
18 public:
19 protected:
20
21 static ucs_log_func_rc_t
socket_error_handler(const char * file,unsigned line,const char * function,ucs_log_level_t level,const ucs_log_component_config_t * comp_conf,const char * message,va_list ap)22 socket_error_handler(const char *file, unsigned line, const char *function,
23 ucs_log_level_t level,
24 const ucs_log_component_config_t *comp_conf,
25 const char *message, va_list ap)
26 {
27 // Ignore errors that invalid input parameters as it is expected
28 if (level == UCS_LOG_LEVEL_ERROR) {
29 std::string err_str = format_message(message, ap);
30
31 if (err_str.find(socket_err_exp_str) != std::string::npos) {
32 UCS_TEST_MESSAGE << err_str;
33 return UCS_LOG_FUNC_RC_STOP;
34 }
35 }
36
37 return UCS_LOG_FUNC_RC_CONTINUE;
38 }
39 };
40
UCS_TEST_F(test_socket,sockaddr_sizeof)41 UCS_TEST_F(test_socket, sockaddr_sizeof) {
42 struct sockaddr_in sa_in;
43 struct sockaddr_in6 sa_in6;
44 struct sockaddr_un sa_un;
45 size_t size;
46
47 sa_in.sin_family = AF_INET;
48 sa_in6.sin6_family = AF_INET6;
49 sa_un.sun_family = AF_UNIX;
50
51 /* Check with wrong IPv4 */
52 {
53 size = 0;
54 EXPECT_UCS_OK(ucs_sockaddr_sizeof((const struct sockaddr*)&sa_in, &size));
55 EXPECT_EQ(sizeof(struct sockaddr_in), size);
56 }
57
58 /* Check with wrong IPv6 */
59 {
60 size = 0;
61 EXPECT_UCS_OK(ucs_sockaddr_sizeof((const struct sockaddr*)&sa_in6, &size));
62 EXPECT_EQ(sizeof(struct sockaddr_in6), size);
63 }
64
65 /* Check with wrong address family */
66 {
67 socket_err_exp_str = "unknown address family:";
68 scoped_log_handler log_handler(socket_error_handler);
69
70 size = 0;
71 EXPECT_EQ(UCS_ERR_INVALID_PARAM,
72 ucs_sockaddr_sizeof((const struct sockaddr*)&sa_un, &size));
73 /* Check that doesn't touch provided memory in error case */
74 EXPECT_EQ(0ULL, size);
75 }
76 }
77
UCS_TEST_F(test_socket,sockaddr_get_port)78 UCS_TEST_F(test_socket, sockaddr_get_port) {
79 const uint16_t sin_port = 5555;
80 struct sockaddr_in sa_in;
81 struct sockaddr_in6 sa_in6;
82 struct sockaddr_un sa_un;
83 uint16_t port = 0;
84
85 sa_in.sin_family = AF_INET;
86 sa_in.sin_port = htons(sin_port);
87 sa_in6.sin6_family = AF_INET6;
88 sa_in6.sin6_port = htons(sin_port);
89 sa_un.sun_family = AF_UNIX;
90
91 /* Check with wrong IPv4 */
92 {
93 port = 0;
94 EXPECT_UCS_OK(ucs_sockaddr_get_port((const struct sockaddr*)&sa_in, &port));
95 EXPECT_EQ(sin_port, port);
96 }
97
98 /* Check with wrong IPv6 */
99 {
100 port = 0;
101 EXPECT_UCS_OK(ucs_sockaddr_get_port((const struct sockaddr*)&sa_in6, &port));
102 EXPECT_EQ(sin_port, port);
103 }
104
105 /* Check with wrong address family */
106 {
107 socket_err_exp_str = "unknown address family:";
108 scoped_log_handler log_handler(socket_error_handler);
109
110 port = sin_port;
111 EXPECT_EQ(UCS_ERR_INVALID_PARAM,
112 ucs_sockaddr_get_port((const struct sockaddr*)&sa_un, &port));
113 /* Check that doesn't touch provided memory in error case */
114 EXPECT_EQ(sin_port, port);
115 }
116 }
117
UCS_TEST_F(test_socket,sockaddr_get_inet_addr)118 UCS_TEST_F(test_socket, sockaddr_get_inet_addr) {
119 struct sockaddr_in sa_in;
120 struct sockaddr_in6 sa_in6;
121 struct sockaddr_un sa_un;
122 struct in_addr sin_addr;
123 struct in6_addr sin6_addr;
124
125 sa_in.sin_family = AF_INET;
126 sa_in6.sin6_family = AF_INET6;
127 sa_un.sun_family = AF_UNIX;
128
129 sin_addr.s_addr = sa_in.sin_addr.s_addr = htonl(INADDR_ANY);
130 sin6_addr = sa_in6.sin6_addr = in6addr_any;
131
132 /* Check with wrong IPv4 */
133 {
134 EXPECT_EQ(&sa_in.sin_addr,
135 ucs_sockaddr_get_inet_addr((const struct sockaddr*)&sa_in));
136 EXPECT_EQ(0, memcmp(&sa_in.sin_addr, &sin_addr,
137 sizeof(sa_in.sin_addr)));
138 }
139
140 /* Check with wrong IPv6 */
141 {
142 EXPECT_EQ(&sa_in6.sin6_addr,
143 ucs_sockaddr_get_inet_addr((const struct sockaddr*)&sa_in6));
144 EXPECT_EQ(0, memcmp(&sa_in6.sin6_addr, &sin6_addr,
145 sizeof(sa_in6.sin6_addr)));
146 }
147
148 /* Check with wrong address family */
149 {
150 socket_err_exp_str = "unknown address family:";
151 scoped_log_handler log_handler(socket_error_handler);
152
153 EXPECT_EQ(NULL, ucs_sockaddr_get_inet_addr((const struct sockaddr*)&sa_un));
154 }
155 }
156
UCS_TEST_F(test_socket,sockaddr_str)157 UCS_TEST_F(test_socket, sockaddr_str) {
158 const uint16_t port = 65534;
159 const char *ipv4_addr = "192.168.122.157";
160 const char *ipv6_addr = "fe80::218:e7ff:fe16:fb97";
161 struct sockaddr_in sa_in;
162 struct sockaddr_in6 sa_in6;
163 char ipv4_addr_out[128], ipv6_addr_out[128], *str, test_str[1024];
164
165 sa_in.sin_family = AF_INET;
166 sa_in.sin_port = htons(port);
167 sa_in6.sin6_family = AF_INET6;
168 sa_in6.sin6_port = htons(port);
169
170 sprintf(ipv4_addr_out, "%s:%d", ipv4_addr, port);
171 sprintf(ipv6_addr_out, "%s:%d", ipv6_addr, port);
172
173 inet_pton(AF_INET, ipv4_addr, &(sa_in.sin_addr));
174 inet_pton(AF_INET6, ipv6_addr, &(sa_in6.sin6_addr));
175
176 /* Check with short `str_len` to fit IP address only */
177 {
178 str = (char*)ucs_sockaddr_str((const struct sockaddr*)&sa_in,
179 test_str, INET_ADDRSTRLEN);
180 EXPECT_EQ(str, test_str);
181 EXPECT_EQ(0, strncmp(test_str, ipv4_addr_out,
182 INET_ADDRSTRLEN - 1));
183
184 str = (char*)ucs_sockaddr_str((const struct sockaddr*)&sa_in6,
185 test_str, INET6_ADDRSTRLEN);
186 EXPECT_EQ(str, test_str);
187 EXPECT_EQ(0, strncmp(test_str, ipv6_addr_out,
188 INET6_ADDRSTRLEN - 1));
189 }
190
191 /* Check with big enough `str_len` */
192 {
193 str = (char*)ucs_sockaddr_str((const struct sockaddr*)&sa_in,
194 test_str, 1024);
195 EXPECT_EQ(str, test_str);
196 EXPECT_EQ(0, strcmp(test_str, ipv4_addr_out));
197
198 str = (char*)ucs_sockaddr_str((const struct sockaddr*)&sa_in6,
199 test_str, 1024);
200 EXPECT_TRUE(str == test_str);
201 EXPECT_EQ(0, strcmp(test_str, ipv6_addr_out));
202 }
203
204 /* Check with wrong sa_family */
205 {
206 struct sockaddr_un sa_un;
207 sa_un.sun_family = AF_UNIX;
208
209 /* with big enough string */
210 {
211 str = (char*)ucs_sockaddr_str((const struct sockaddr*)&sa_un,
212 test_str, 1024);
213 EXPECT_EQ(test_str, str);
214 EXPECT_EQ(0, strcmp(str, "<invalid address family>"));
215 }
216
217 /* without string */
218 {
219 str = (char*)ucs_sockaddr_str((const struct sockaddr*)&sa_un,
220 NULL, 0);
221 EXPECT_EQ(NULL, str);
222 }
223 }
224 }
225
UCS_TEST_F(test_socket,socket_setopt)226 UCS_TEST_F(test_socket, socket_setopt) {
227 socklen_t optlen;
228 int optname;
229 int optval;
230 int level;
231 ucs_status_t status;
232 int fd;
233
234 optlen = sizeof(optval);
235
236 status = ucs_socket_create(AF_INET, SOCK_STREAM, &fd);
237 EXPECT_UCS_OK(status);
238 EXPECT_GE(fd, 0);
239
240 /* with acceptable parameters */
241 {
242 level = SOL_SOCKET;
243 optname = SO_REUSEADDR;
244 optval = 1;
245
246 status = ucs_socket_setopt(fd, level, optname, &optval, optlen);
247 EXPECT_UCS_OK(status);
248 }
249
250 /* with bad parameters */
251 {
252 level = IPPROTO_TCP;
253 optname = SO_REUSEADDR;
254 optval = 1;
255
256 socket_err_exp_str = "failed to set " + ucs::to_string(optname) + " option for " +
257 ucs::to_string(level) + " level on fd " + ucs::to_string(fd) +
258 + ": " + strerror(EINVAL);
259 scoped_log_handler log_handler(socket_error_handler);
260 status = ucs_socket_setopt(fd, level, optname, &optval, optlen);
261 EXPECT_EQ(status, UCS_ERR_IO_ERROR);
262 }
263
264 close(fd);
265 }
266
sockaddr_cmp_test(int sa_family,const char * ip_addr1,const char * ip_addr2,unsigned port1,unsigned port2,struct sockaddr * sa1,struct sockaddr * sa2)267 static void sockaddr_cmp_test(int sa_family, const char *ip_addr1,
268 const char *ip_addr2, unsigned port1,
269 unsigned port2, struct sockaddr *sa1,
270 struct sockaddr *sa2)
271 {
272 int cmp_res1, cmp_res2;
273 ucs_status_t status;
274
275 sa1->sa_family = sa_family;
276 sa2->sa_family = sa_family;
277
278 inet_pton(sa_family, ip_addr1,
279 const_cast<void*>(ucs_sockaddr_get_inet_addr(sa1)));
280 inet_pton(sa_family, ip_addr2,
281 const_cast<void*>(ucs_sockaddr_get_inet_addr(sa2)));
282
283 status = ucs_sockaddr_set_port(sa1, port1);
284 ASSERT_UCS_OK(status);
285 status = ucs_sockaddr_set_port(sa2, port2);
286 ASSERT_UCS_OK(status);
287
288 const void *addr1 = ucs_sockaddr_get_inet_addr(sa1);
289 const void *addr2 = ucs_sockaddr_get_inet_addr(sa2);
290
291 ASSERT_TRUE(addr1 != NULL);
292 ASSERT_TRUE(addr2 != NULL);
293
294 size_t addr_size = ((sa_family == AF_INET) ?
295 sizeof(UCS_SOCKET_INET_ADDR(sa1)) :
296 sizeof(UCS_SOCKET_INET6_ADDR(sa1)));
297
298 // `sa1` vs `sa2`
299 {
300 int addr_cmp_res = memcmp(addr1, addr2, addr_size);
301 int port_cmp_res =
302 (port1 == port2) ? 0 : ((port1 < port2) ? -1 : 1);
303 int expected_cmp_res =
304 addr_cmp_res ? addr_cmp_res : port_cmp_res;
305
306 cmp_res1 = ucs_sockaddr_cmp(sa1, sa2, &status);
307 EXPECT_UCS_OK(status);
308 EXPECT_EQ(expected_cmp_res, cmp_res1);
309
310 // Call w/o `status` provided
311 cmp_res2 = ucs_sockaddr_cmp(sa1, sa2, &status);
312 EXPECT_EQ(cmp_res1, cmp_res2);
313 }
314
315 // `sa2` vs `sa1`
316 {
317 int addr_cmp_res = memcmp(addr2, addr1, addr_size);
318 int port_cmp_res =
319 (port2 == port1) ? 0 : ((port2 < port1) ? -1 : 1);
320 int expected_cmp_res =
321 addr_cmp_res ? addr_cmp_res : port_cmp_res;
322
323 cmp_res1 = ucs_sockaddr_cmp(sa2, sa1, &status);
324 EXPECT_UCS_OK(status);
325 EXPECT_EQ(expected_cmp_res, cmp_res1);
326
327 // Call w/o `status` provided
328 cmp_res2 = ucs_sockaddr_cmp(sa2, sa1, &status);
329 EXPECT_EQ(cmp_res1, cmp_res2);
330 }
331 }
332
UCS_TEST_F(test_socket,sockaddr_cmp)333 UCS_TEST_F(test_socket, sockaddr_cmp) {
334 const unsigned port1 = 65534;
335 const unsigned port2 = 65533;
336 const char *ipv4_addr1 = "192.168.122.157";
337 const char *ipv4_addr2 = "192.168.123.157";
338 const char *ipv6_addr1 = "fe80::218:e7ff:fe16:fb97";
339 const char *ipv6_addr2 = "fe80::219:e7ff:fe16:fb97";
340 struct sockaddr_in sa_in_1 = { 0 };
341 struct sockaddr_in sa_in_2 = { 0 };
342 struct sockaddr_in6 sa_in6_1 = { 0 };
343 struct sockaddr_in6 sa_in6_2 = { 0 };
344
345 // Same addresses; same ports
346 sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr1,
347 port1, port1,
348 (struct sockaddr*)&sa_in_1,
349 (struct sockaddr*)&sa_in_2);
350 sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr1,
351 port1, port1,
352 (struct sockaddr*)&sa_in6_1,
353 (struct sockaddr*)&sa_in6_2);
354
355 // Same addresses; different ports
356 sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr1,
357 port1, port2,
358 (struct sockaddr*)&sa_in_1,
359 (struct sockaddr*)&sa_in_2);
360 sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr1,
361 port1, port2,
362 (struct sockaddr*)&sa_in6_1,
363 (struct sockaddr*)&sa_in6_2);
364
365 // Different addresses; same ports
366 sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr2,
367 port1, port1,
368 (struct sockaddr*)&sa_in_1,
369 (struct sockaddr*)&sa_in_2);
370 sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr2,
371 port1, port1,
372 (struct sockaddr*)&sa_in6_1,
373 (struct sockaddr*)&sa_in6_2);
374
375 // Different addresses; different ports
376 sockaddr_cmp_test(AF_INET, ipv4_addr1, ipv4_addr2,
377 port1, port2,
378 (struct sockaddr*)&sa_in_1,
379 (struct sockaddr*)&sa_in_2);
380 sockaddr_cmp_test(AF_INET6, ipv6_addr1, ipv6_addr2,
381 port1, port2,
382 (struct sockaddr*)&sa_in6_1,
383 (struct sockaddr*)&sa_in6_2);
384 }
385
sockaddr_cmp_err_test(const struct sockaddr * sa1,const struct sockaddr * sa2)386 static void sockaddr_cmp_err_test(const struct sockaddr *sa1,
387 const struct sockaddr *sa2)
388 {
389 ucs_status_t status;
390 int result;
391
392 result = ucs_sockaddr_cmp((const struct sockaddr*)sa1,
393 (const struct sockaddr*)sa2,
394 &status);
395 EXPECT_EQ(UCS_ERR_INVALID_PARAM, status);
396 EXPECT_TRUE(result > 0);
397
398 // Call w/o `status` provided
399 result = ucs_sockaddr_cmp((const struct sockaddr*)sa1,
400 (const struct sockaddr*)sa2,
401 NULL);
402 EXPECT_TRUE(result > 0);
403 }
404
UCS_TEST_F(test_socket,sockaddr_cmp_err)405 UCS_TEST_F(test_socket, sockaddr_cmp_err) {
406 // Check with wrong sa_family
407 struct sockaddr_un sa_un;
408 struct sockaddr_in sa_in;
409
410 sa_un.sun_family = AF_UNIX;
411 sa_in.sin_family = AF_INET;
412
413 socket_err_exp_str = "unknown address family: ";
414 scoped_log_handler log_handler(socket_error_handler);
415
416 sockaddr_cmp_err_test((const struct sockaddr*)&sa_un,
417 (const struct sockaddr*)&sa_un);
418
419 sockaddr_cmp_err_test((const struct sockaddr*)&sa_in,
420 (const struct sockaddr*)&sa_un);
421
422 sockaddr_cmp_err_test((const struct sockaddr*)&sa_un,
423 (const struct sockaddr*)&sa_in);
424 }
425