1 /*
2 * Copyright (c) 2015 Fujitsu Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #include <errno.h>
20 #include "test.h"
21 #include "safe_macros_fn.h"
22 #include "safe_net_fn.h"
23
tst_sock_addr(const struct sockaddr * sa,socklen_t salen,char * res,size_t len)24 char *tst_sock_addr(const struct sockaddr *sa, socklen_t salen, char *res,
25 size_t len)
26 {
27 char portstr[8];
28
29 switch (sa->sa_family) {
30
31 case AF_INET: {
32 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
33
34 if (!inet_ntop(AF_INET, &sin->sin_addr, res, len))
35 return NULL;
36
37 if (ntohs(sin->sin_port) != 0) {
38 snprintf(portstr, sizeof(portstr), ":%d",
39 ntohs(sin->sin_port));
40 strcat(res, portstr);
41 }
42
43 return res;
44 }
45
46 case AF_INET6: {
47 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
48
49 res[0] = '[';
50 if (!inet_ntop(AF_INET6, &sin6->sin6_addr, res + 1, len - 1))
51 return NULL;
52
53 if (ntohs(sin6->sin6_port) != 0) {
54 snprintf(portstr, sizeof(portstr), "]:%d",
55 ntohs(sin6->sin6_port));
56 strcat(res, portstr);
57 return res;
58 }
59
60 return res + 1;
61 }
62
63 case AF_UNIX: {
64 struct sockaddr_un *unp = (struct sockaddr_un *)sa;
65
66 if (unp->sun_path[0] == '\0')
67 strcpy(res, "(no pathname bound)");
68 else
69 snprintf(res, len, "%s", unp->sun_path);
70
71 return res;
72 }
73
74 default: {
75 snprintf(res, len,
76 "sock_ntop: unknown AF_xxx: %d, len: %d",
77 sa->sa_family, salen);
78
79 return res;
80 }
81
82 }
83 }
84
tst_getsockport(const char * file,const int lineno,int sockfd)85 int tst_getsockport(const char *file, const int lineno, int sockfd)
86 {
87 struct sockaddr_storage ss;
88 socklen_t addrlen = sizeof(ss);
89 struct sockaddr *sa = (struct sockaddr *)&ss;
90
91 safe_getsockname(file, lineno, NULL, sockfd, sa, &addrlen);
92
93 switch (sa->sa_family) {
94 case AF_INET: {
95 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
96
97 return ntohs(sin->sin_port);
98 }
99 case AF_INET6: {
100 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
101
102 return ntohs(sin6->sin6_port);
103 } }
104
105 return -1;
106 }
107
safe_socket(const char * file,const int lineno,void (cleanup_fn)(void),int domain,int type,int protocol)108 int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void),
109 int domain, int type, int protocol)
110 {
111 int rval, ttype;
112
113 rval = socket(domain, type, protocol);
114
115 if (rval == -1) {
116 switch (errno) {
117 case EPROTONOSUPPORT:
118 case ESOCKTNOSUPPORT:
119 case EOPNOTSUPP:
120 case EPFNOSUPPORT:
121 case EAFNOSUPPORT:
122 ttype = TCONF;
123 break;
124 default:
125 ttype = TBROK;
126 }
127
128 tst_brkm_(file, lineno, ttype | TERRNO, cleanup_fn,
129 "socket(%d, %d, %d) failed", domain, type, protocol);
130 } else if (rval < 0) {
131 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
132 "Invalid socket(%d, %d, %d) return value %d", domain,
133 type, protocol, rval);
134 }
135
136 return rval;
137 }
138
safe_socketpair(const char * file,const int lineno,int domain,int type,int protocol,int sv[])139 int safe_socketpair(const char *file, const int lineno, int domain, int type,
140 int protocol, int sv[])
141 {
142 int rval, ttype;
143
144 rval = socketpair(domain, type, protocol, sv);
145
146 if (rval == -1) {
147 switch (errno) {
148 case EPROTONOSUPPORT:
149 case EOPNOTSUPP:
150 case EAFNOSUPPORT:
151 ttype = TCONF;
152 break;
153 default:
154 ttype = TBROK;
155 }
156
157 tst_brkm_(file, lineno, ttype | TERRNO, NULL,
158 "socketpair(%d, %d, %d, %p) failed", domain, type,
159 protocol, sv);
160 } else if (rval) {
161 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
162 "Invalid socketpair(%d, %d, %d, %p) return value %d",
163 domain, type, protocol, sv, rval);
164 }
165
166 return rval;
167 }
168
safe_getsockopt(const char * file,const int lineno,int sockfd,int level,int optname,void * optval,socklen_t * optlen)169 int safe_getsockopt(const char *file, const int lineno, int sockfd, int level,
170 int optname, void *optval, socklen_t *optlen)
171 {
172 int rval = getsockopt(sockfd, level, optname, optval, optlen);
173
174 if (rval == -1) {
175 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
176 "getsockopt(%d, %d, %d, %p, %p) failed",
177 sockfd, level, optname, optval, optlen);
178 } else if (rval) {
179 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
180 "Invalid getsockopt(%d, %d, %d, %p, %p) return value %d",
181 sockfd, level, optname, optval, optlen, rval);
182 }
183
184 return rval;
185 }
186
safe_setsockopt(const char * file,const int lineno,int sockfd,int level,int optname,const void * optval,socklen_t optlen)187 int safe_setsockopt(const char *file, const int lineno, int sockfd, int level,
188 int optname, const void *optval, socklen_t optlen)
189 {
190 int rval;
191
192 rval = setsockopt(sockfd, level, optname, optval, optlen);
193
194 if (rval == -1) {
195 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
196 "setsockopt(%d, %d, %d, %p, %d) failed",
197 sockfd, level, optname, optval, optlen);
198 } else if (rval) {
199 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
200 "Invalid setsockopt(%d, %d, %d, %p, %d) return value %d",
201 sockfd, level, optname, optval, optlen, rval);
202 }
203
204 return rval;
205 }
206
safe_send(const char * file,const int lineno,char len_strict,int sockfd,const void * buf,size_t len,int flags)207 ssize_t safe_send(const char *file, const int lineno, char len_strict,
208 int sockfd, const void *buf, size_t len, int flags)
209 {
210 ssize_t rval;
211
212 rval = send(sockfd, buf, len, flags);
213
214 if (rval == -1 || (len_strict && (size_t)rval != len)) {
215 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
216 "send(%d, %p, %zu, %d) failed", sockfd, buf, len,
217 flags);
218 } else if (rval < 0) {
219 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
220 "Invalid send(%d, %p, %zu, %d) return value %zd",
221 sockfd, buf, len, flags, rval);
222 }
223
224 return rval;
225 }
226
safe_sendto(const char * file,const int lineno,char len_strict,int sockfd,const void * buf,size_t len,int flags,const struct sockaddr * dest_addr,socklen_t addrlen)227 ssize_t safe_sendto(const char *file, const int lineno, char len_strict,
228 int sockfd, const void *buf, size_t len, int flags,
229 const struct sockaddr *dest_addr, socklen_t addrlen)
230 {
231 ssize_t rval;
232 char res[128];
233
234 rval = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
235
236 if (rval == -1 || (len_strict && (size_t)rval != len)) {
237 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
238 "sendto(%d, %p, %zu, %d, %s, %d) failed",
239 sockfd, buf, len, flags,
240 tst_sock_addr(dest_addr, addrlen, res, sizeof(res)),
241 addrlen);
242 } else if (rval < 0) {
243 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
244 "Invalid sendto(%d, %p, %zu, %d, %s, %d) return value %zd",
245 sockfd, buf, len, flags,
246 tst_sock_addr(dest_addr, addrlen, res, sizeof(res)),
247 addrlen, rval);
248 }
249
250 return rval;
251 }
252
safe_sendmsg(const char * file,const int lineno,size_t len,int sockfd,const struct msghdr * msg,int flags)253 ssize_t safe_sendmsg(const char *file, const int lineno, size_t len,
254 int sockfd, const struct msghdr *msg, int flags)
255 {
256 ssize_t rval;
257
258 rval = sendmsg(sockfd, msg, flags);
259
260 if (rval == -1) {
261 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
262 "sendmsg(%d, %p, %d) failed", sockfd, msg, flags);
263 } else if (rval < 0) {
264 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
265 "Invalid sendmsg(%d, %p, %d) return value %zd",
266 sockfd, msg, flags, rval);
267 } else if (len && (size_t)rval != len) {
268 tst_brkm_(file, lineno, TBROK, NULL,
269 "sendmsg(%d, %p, %d) ret(%zd) != len(%zu)",
270 sockfd, msg, flags, rval, len);
271 }
272
273 return rval;
274 }
275
safe_recv(const char * file,const int lineno,size_t len,int sockfd,void * buf,size_t size,int flags)276 ssize_t safe_recv(const char *file, const int lineno, size_t len,
277 int sockfd, void *buf, size_t size, int flags)
278 {
279 ssize_t rval;
280
281 rval = recv(sockfd, buf, size, flags);
282
283 if (rval == -1) {
284 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
285 "recv(%d, %p, %zu, %d) failed", sockfd, buf, size,
286 flags);
287 } else if (rval < 0) {
288 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
289 "Invalid recv(%d, %p, %zu, %d) return value %zd",
290 sockfd, buf, size, flags, rval);
291 } else if (len && (size_t)rval != len) {
292 tst_brkm_(file, lineno, TBROK, NULL,
293 "recv(%d, %p, %zu, %d) ret(%zd) != len(%zu)",
294 sockfd, buf, size, flags, rval, len);
295 }
296
297 return rval;
298
299 }
300
safe_recvmsg(const char * file,const int lineno,size_t len,int sockfd,struct msghdr * msg,int flags)301 ssize_t safe_recvmsg(const char *file, const int lineno, size_t len,
302 int sockfd, struct msghdr *msg, int flags)
303 {
304 ssize_t rval;
305
306 rval = recvmsg(sockfd, msg, flags);
307
308 if (rval == -1) {
309 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
310 "recvmsg(%d, %p, %d) failed", sockfd, msg, flags);
311 } else if (rval < 0) {
312 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
313 "Invalid recvmsg(%d, %p, %d) return value %zd",
314 sockfd, msg, flags, rval);
315 } else if (len && (size_t)rval != len) {
316 tst_brkm_(file, lineno, TBROK, NULL,
317 "recvmsg(%d, %p, %d) ret(%zd) != len(%zu)",
318 sockfd, msg, flags, rval, len);
319 }
320
321 return rval;
322
323 }
324
safe_bind(const char * file,const int lineno,void (cleanup_fn)(void),int socket,const struct sockaddr * address,socklen_t address_len)325 int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void),
326 int socket, const struct sockaddr *address,
327 socklen_t address_len)
328 {
329 int i, ret;
330 char buf[128];
331
332 for (i = 0; i < 120; i++) {
333 ret = bind(socket, address, address_len);
334
335 if (!ret)
336 return 0;
337
338 if (ret != -1) {
339 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
340 "Invalid bind(%d, %s, %d) return value %d",
341 socket, tst_sock_addr(address, address_len,
342 buf, sizeof(buf)), address_len, ret);
343 return ret;
344 } else if (errno != EADDRINUSE) {
345 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
346 "bind(%d, %s, %d) failed", socket,
347 tst_sock_addr(address, address_len, buf,
348 sizeof(buf)), address_len);
349 return ret;
350 }
351
352 if ((i + 1) % 10 == 0) {
353 tst_resm_(file, lineno, TINFO,
354 "address is in use, waited %3i sec", i + 1);
355 }
356
357 sleep(1);
358 }
359
360 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
361 "Failed to bind(%d, %s, %d) after 120 retries", socket,
362 tst_sock_addr(address, address_len, buf, sizeof(buf)),
363 address_len);
364 return -1;
365 }
366
safe_listen(const char * file,const int lineno,void (cleanup_fn)(void),int socket,int backlog)367 int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void),
368 int socket, int backlog)
369 {
370 int rval;
371 int res = TBROK;
372
373 rval = listen(socket, backlog);
374
375 if (rval == -1) {
376 if (errno == ENOSYS)
377 res = TCONF;
378 tst_brkm_(file, lineno, res | TERRNO, cleanup_fn,
379 "listen(%d, %d) failed", socket, backlog);
380 } else if (rval) {
381 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
382 "Invalid listen(%d, %d) return value %d", socket,
383 backlog, rval);
384 }
385
386 return rval;
387 }
388
safe_accept(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,struct sockaddr * addr,socklen_t * addrlen)389 int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void),
390 int sockfd, struct sockaddr *addr, socklen_t *addrlen)
391 {
392 int rval;
393
394 rval = accept(sockfd, addr, addrlen);
395
396 if (rval == -1) {
397 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
398 "accept(%d, %p, %d) failed", sockfd, addr, *addrlen);
399 } else if (rval < 0) {
400 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
401 "Invalid accept(%d, %p, %d) return value %d", sockfd,
402 addr, *addrlen, rval);
403 }
404
405 return rval;
406 }
407
safe_connect(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,const struct sockaddr * addr,socklen_t addrlen)408 int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void),
409 int sockfd, const struct sockaddr *addr, socklen_t addrlen)
410 {
411 int rval;
412 char buf[128];
413
414 rval = connect(sockfd, addr, addrlen);
415
416 if (rval == -1) {
417 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
418 "connect(%d, %s, %d) failed", sockfd,
419 tst_sock_addr(addr, addrlen, buf, sizeof(buf)),
420 addrlen);
421 } else if (rval) {
422 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
423 "Invalid connect(%d, %s, %d) return value %d", sockfd,
424 tst_sock_addr(addr, addrlen, buf, sizeof(buf)),
425 addrlen, rval);
426 }
427
428 return rval;
429 }
430
safe_getsockname(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,struct sockaddr * addr,socklen_t * addrlen)431 int safe_getsockname(const char *file, const int lineno,
432 void (cleanup_fn)(void), int sockfd, struct sockaddr *addr,
433 socklen_t *addrlen)
434 {
435 int rval;
436 char buf[128];
437
438 rval = getsockname(sockfd, addr, addrlen);
439
440 if (rval == -1) {
441 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
442 "getsockname(%d, %s, %d) failed", sockfd,
443 tst_sock_addr(addr, *addrlen, buf, sizeof(buf)),
444 *addrlen);
445 } else if (rval) {
446 tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
447 "Invalid getsockname(%d, %s, %d) return value %d",
448 sockfd, tst_sock_addr(addr, *addrlen, buf,
449 sizeof(buf)), *addrlen, rval);
450 }
451
452 return rval;
453 }
454
safe_gethostname(const char * file,const int lineno,char * name,size_t size)455 int safe_gethostname(const char *file, const int lineno,
456 char *name, size_t size)
457 {
458 int rval = gethostname(name, size);
459
460 if (rval == -1) {
461 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
462 "gethostname(%p, %zu) failed", name, size);
463 } else if (rval) {
464 tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
465 "Invalid gethostname(%p, %zu) return value %d", name,
466 size, rval);
467 }
468
469 return rval;
470 }
471
472 /*
473 * @return port in network byte order.
474 */
tst_get_unused_port(const char * file,const int lineno,void (cleanup_fn)(void),unsigned short family,int type)475 unsigned short tst_get_unused_port(const char *file, const int lineno,
476 void (cleanup_fn)(void), unsigned short family, int type)
477 {
478 int sock, ret;
479 socklen_t slen;
480 struct sockaddr_storage _addr;
481 struct sockaddr *addr = (struct sockaddr *)&_addr;
482 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
483 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
484
485 switch (family) {
486 case AF_INET:
487 addr4->sin_family = AF_INET;
488 addr4->sin_port = 0;
489 addr4->sin_addr.s_addr = INADDR_ANY;
490 slen = sizeof(*addr4);
491 break;
492
493 case AF_INET6:
494 addr6->sin6_family = AF_INET6;
495 addr6->sin6_port = 0;
496 addr6->sin6_addr = in6addr_any;
497 slen = sizeof(*addr6);
498 break;
499
500 default:
501 tst_brkm_(file, lineno, TBROK, cleanup_fn,
502 "%s(): Unsupported socket family %d", __func__,
503 family);
504 return -1;
505 }
506
507 sock = safe_socket(file, lineno, cleanup_fn, addr->sa_family, type, 0);
508
509 if (sock < 0)
510 return sock;
511
512 ret = safe_bind(file, lineno, cleanup_fn, sock, addr, slen);
513
514 if (ret)
515 return ret;
516
517 ret = safe_getsockname(file, lineno, cleanup_fn, sock, addr, &slen);
518
519 if (ret)
520 return ret;
521
522 ret = safe_close(file, lineno, cleanup_fn, sock);
523
524 if (ret)
525 return ret;
526
527 switch (family) {
528 case AF_INET:
529 return addr4->sin_port;
530 case AF_INET6:
531 return addr6->sin6_port;
532 default:
533 return -1;
534 }
535 }
536