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