• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
safe_sethostname(const char * file,const int lineno,const char * name,size_t size)472 int safe_sethostname(const char *file, const int lineno,
473 		     const char *name, size_t size)
474 {
475 	int rval = sethostname(name, size);
476 
477 	if (rval == -1) {
478 		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
479 			"sethostname(%p, %zu) failed", name, size);
480 	} else if (rval) {
481 		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
482 			"Invalid sethostname(%p, %zu) return value %d", name,
483 			size, rval);
484 	}
485 
486 	return rval;
487 }
488 
489 /*
490  * @return port in network byte order.
491  */
tst_get_unused_port(const char * file,const int lineno,void (cleanup_fn)(void),unsigned short family,int type)492 unsigned short tst_get_unused_port(const char *file, const int lineno,
493 	      void (cleanup_fn)(void), unsigned short family, int type)
494 {
495 	int sock, ret;
496 	socklen_t slen;
497 	struct sockaddr_storage _addr;
498 	struct sockaddr *addr = (struct sockaddr *)&_addr;
499 	struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
500 	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
501 
502 	switch (family) {
503 	case AF_INET:
504 		addr4->sin_family = AF_INET;
505 		addr4->sin_port = 0;
506 		addr4->sin_addr.s_addr = INADDR_ANY;
507 		slen = sizeof(*addr4);
508 		break;
509 
510 	case AF_INET6:
511 		addr6->sin6_family = AF_INET6;
512 		addr6->sin6_port = 0;
513 		addr6->sin6_addr = in6addr_any;
514 		slen = sizeof(*addr6);
515 		break;
516 
517 	default:
518 		tst_brkm_(file, lineno, TBROK, cleanup_fn,
519 			"%s(): Unsupported socket family %d", __func__,
520 			family);
521 		return -1;
522 	}
523 
524 	sock = safe_socket(file, lineno, cleanup_fn, addr->sa_family, type, 0);
525 
526 	if (sock < 0)
527 		return sock;
528 
529 	ret = safe_bind(file, lineno, cleanup_fn, sock, addr, slen);
530 
531 	if (ret)
532 		return ret;
533 
534 	ret = safe_getsockname(file, lineno, cleanup_fn, sock, addr, &slen);
535 
536 	if (ret)
537 		return ret;
538 
539 	ret = safe_close(file, lineno, cleanup_fn, sock);
540 
541 	if (ret)
542 		return ret;
543 
544 	switch (family) {
545 	case AF_INET:
546 		return addr4->sin_port;
547 	case AF_INET6:
548 		return addr6->sin6_port;
549 	default:
550 		return -1;
551 	}
552 }
553