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_net_fn.h"
22 
tst_sock_addr(const struct sockaddr * sa,socklen_t salen,char * res,size_t len)23 char *tst_sock_addr(const struct sockaddr *sa, socklen_t salen, char *res,
24 		    size_t len)
25 {
26 	char portstr[8];
27 
28 	switch (sa->sa_family) {
29 
30 	case AF_INET: {
31 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
32 
33 		if (!inet_ntop(AF_INET, &sin->sin_addr, res, len))
34 			return NULL;
35 
36 		if (ntohs(sin->sin_port) != 0) {
37 			snprintf(portstr, sizeof(portstr), ":%d",
38 				 ntohs(sin->sin_port));
39 			strcat(res, portstr);
40 		}
41 
42 		return res;
43 	}
44 
45 	case AF_INET6: {
46 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
47 
48 		res[0] = '[';
49 		if (!inet_ntop(AF_INET6, &sin6->sin6_addr, res + 1, len - 1))
50 			return NULL;
51 
52 		if (ntohs(sin6->sin6_port) != 0) {
53 			snprintf(portstr, sizeof(portstr), "]:%d",
54 				 ntohs(sin6->sin6_port));
55 			strcat(res, portstr);
56 			return res;
57 		}
58 
59 		return res + 1;
60 	}
61 
62 	case AF_UNIX: {
63 		struct sockaddr_un *unp = (struct sockaddr_un *)sa;
64 
65 		if (unp->sun_path[0] == '\0')
66 			strcpy(res, "(no pathname bound)");
67 		else
68 			snprintf(res, len, "%s", unp->sun_path);
69 
70 		return res;
71 	}
72 
73 	default: {
74 		snprintf(res, len,
75 			 "sock_ntop: unknown AF_xxx: %d, len: %d",
76 			 sa->sa_family, salen);
77 
78 		return res;
79 	}
80 
81 	}
82 }
83 
tst_getsockport(const char * file,const int lineno,int sockfd)84 int tst_getsockport(const char *file, const int lineno, int sockfd)
85 {
86 	struct sockaddr_storage ss;
87 	socklen_t addrlen = sizeof(ss);
88 	struct sockaddr *sa = (struct sockaddr *)&ss;
89 
90 	safe_getsockname(file, lineno, NULL, sockfd, sa, &addrlen);
91 
92 	switch (sa->sa_family) {
93 	case AF_INET: {
94 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
95 
96 		return ntohs(sin->sin_port);
97 	}
98 	case AF_INET6: {
99 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
100 
101 		return ntohs(sin6->sin6_port);
102 	} }
103 
104 	return -1;
105 }
106 
safe_socket(const char * file,const int lineno,void (cleanup_fn)(void),int domain,int type,int protocol)107 int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void),
108 		int domain, int type, int protocol)
109 {
110 	int rval, ttype;
111 
112 	rval = socket(domain, type, protocol);
113 
114 	if (rval < 0) {
115 		switch (errno) {
116 		case EPROTONOSUPPORT:
117 		case ESOCKTNOSUPPORT:
118 		case EOPNOTSUPP:
119 		case EPFNOSUPPORT:
120 		case EAFNOSUPPORT:
121 			ttype = TCONF;
122 			break;
123 		default:
124 			ttype = TBROK;
125 		}
126 
127 		tst_brkm(ttype | TERRNO, cleanup_fn,
128 			 "%s:%d: socket(%d, %d, %d) failed", file, lineno,
129 			 domain, type, protocol);
130 	}
131 
132 	return rval;
133 }
134 
safe_socketpair(const char * file,const int lineno,int domain,int type,int protocol,int sv[])135 int safe_socketpair(const char *file, const int lineno, int domain, int type,
136 		    int protocol, int sv[])
137 {
138 	int rval, ttype;
139 
140 	rval = socketpair(domain, type, protocol, sv);
141 
142 	if (rval < 0) {
143 		switch (errno) {
144 		case EPROTONOSUPPORT:
145 		case EOPNOTSUPP:
146 		case EAFNOSUPPORT:
147 			ttype = TCONF;
148 			break;
149 		default:
150 			ttype = TBROK;
151 		}
152 
153 		tst_brkm(ttype | TERRNO, NULL,
154 			 "%s:%d: socketpair(%d, %d, %d, %p) failed",
155 			 file, lineno, domain, type, protocol, sv);
156 	}
157 
158 	return rval;
159 }
160 
safe_getsockopt(const char * file,const int lineno,int sockfd,int level,int optname,void * optval,socklen_t * optlen)161 int safe_getsockopt(const char *file, const int lineno, int sockfd, int level,
162 		    int optname, void *optval, socklen_t *optlen)
163 {
164 	int rval = getsockopt(sockfd, level, optname, optval, optlen);
165 
166 	if (!rval)
167 		return 0;
168 
169 	tst_brkm(TBROK | TERRNO, NULL,
170 		 "%s:%d: getsockopt(%d, %d, %d, %p, %p) failed",
171 		 file, lineno, sockfd, level, optname, optval, optlen);
172 
173 	return rval;
174 }
175 
safe_setsockopt(const char * file,const int lineno,int sockfd,int level,int optname,const void * optval,socklen_t optlen)176 int safe_setsockopt(const char *file, const int lineno, int sockfd, int level,
177 		    int optname, const void *optval, socklen_t optlen)
178 {
179 	int rval;
180 
181 	rval = setsockopt(sockfd, level, optname, optval, optlen);
182 
183 	if (rval) {
184 		tst_brkm(TBROK | TERRNO, NULL,
185 			 "%s:%d: setsockopt(%d, %d, %d, %p, %d) failed",
186 			 file, lineno, sockfd, level, optname, optval, optlen);
187 	}
188 
189 	return rval;
190 }
191 
safe_send(const char * file,const int lineno,char len_strict,int sockfd,const void * buf,size_t len,int flags)192 ssize_t safe_send(const char *file, const int lineno, char len_strict,
193 		  int sockfd, const void *buf, size_t len, int flags)
194 {
195 	ssize_t rval;
196 
197 	rval = send(sockfd, buf, len, flags);
198 
199 	if (rval == -1 || (len_strict && (size_t)rval != len)) {
200 		tst_brkm(TBROK | TERRNO, NULL,
201 			 "%s:%d: send(%d, %p, %zu, %d) failed",
202 			 file, lineno, sockfd, buf, len, flags);
203 	}
204 
205 	return rval;
206 }
207 
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)208 ssize_t safe_sendto(const char *file, const int lineno, char len_strict,
209 		    int sockfd, const void *buf, size_t len, int flags,
210 		    const struct sockaddr *dest_addr, socklen_t addrlen)
211 {
212 	ssize_t rval;
213 	char res[128];
214 
215 	rval = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
216 
217 	if (rval == -1 || (len_strict && (size_t)rval != len)) {
218 		tst_brkm(TBROK | TERRNO, NULL,
219 			 "%s:%d: sendto(%d, %p, %zu, %d, %s, %d) failed",
220 			 file, lineno, sockfd, buf, len, flags,
221 			 tst_sock_addr(dest_addr, addrlen, res, sizeof(res)),
222 			 addrlen);
223 	}
224 
225 	return rval;
226 }
227 
safe_sendmsg(const char * file,const int lineno,size_t len,int sockfd,const struct msghdr * msg,int flags)228 ssize_t safe_sendmsg(const char *file, const int lineno, size_t len,
229 		     int sockfd, const struct msghdr *msg, int flags)
230 {
231 	ssize_t rval;
232 
233 	rval = sendmsg(sockfd, msg, flags);
234 
235 	if (rval == -1) {
236 		tst_brkm(TBROK | TERRNO, NULL,
237 			 "%s:%d: sendmsg(%d, %p, %d) failed",
238 			 file, lineno, sockfd, msg, flags);
239 	}
240 
241 	if (len && (size_t)rval != len) {
242 		tst_brkm(TBROK, NULL,
243 			 "%s:%d: sendmsg(%d, %p, %d) ret(%zd) != len(%zu)",
244 			 file, lineno, sockfd, msg, flags, rval, len);
245 	}
246 
247 	return rval;
248 }
249 
safe_recvmsg(const char * file,const int lineno,size_t len,int sockfd,struct msghdr * msg,int flags)250 ssize_t safe_recvmsg(const char *file, const int lineno, size_t len,
251 		     int sockfd, struct msghdr *msg, int flags)
252 {
253 	ssize_t rval;
254 
255 	rval = recvmsg(sockfd, msg, flags);
256 
257 	if (rval == -1) {
258 		tst_brkm(TBROK | TERRNO, NULL,
259 			 "%s:%d: recvmsg(%d, %p, %d) failed",
260 			 file, lineno, sockfd, msg, flags);
261 	}
262 
263 	if (len && (size_t)rval != len) {
264 		tst_brkm(TBROK, NULL,
265 			 "%s:%d: recvmsg(%d, %p, %d) ret(%zd) != len(%zu)",
266 			 file, lineno, sockfd, msg, flags, rval, len);
267 	}
268 
269 	return rval;
270 
271 }
272 
safe_bind(const char * file,const int lineno,void (cleanup_fn)(void),int socket,const struct sockaddr * address,socklen_t address_len)273 int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void),
274 	      int socket, const struct sockaddr *address,
275 	      socklen_t address_len)
276 {
277 	int i;
278 	char buf[128];
279 
280 	for (i = 0; i < 120; i++) {
281 		if (!bind(socket, address, address_len))
282 			return 0;
283 
284 		if (errno != EADDRINUSE) {
285 			tst_brkm(TBROK | TERRNO, cleanup_fn,
286 				 "%s:%d: bind(%d, %s, %d) failed", file, lineno,
287 				 socket, tst_sock_addr(address, address_len,
288 						       buf, sizeof(buf)),
289 				 address_len);
290 			return -1;
291 		}
292 
293 		if ((i + 1) % 10 == 0) {
294 			tst_resm(TINFO, "address is in use, waited %3i sec",
295 				 i + 1);
296 		}
297 
298 		sleep(1);
299 	}
300 
301 	tst_brkm(TBROK | TERRNO, cleanup_fn,
302 		 "%s:%d: Failed to bind(%d, %s, %d) after 120 retries", file,
303 		 lineno, socket,
304 		 tst_sock_addr(address, address_len, buf, sizeof(buf)),
305 		 address_len);
306 	return -1;
307 }
308 
safe_listen(const char * file,const int lineno,void (cleanup_fn)(void),int socket,int backlog)309 int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void),
310 		int socket, int backlog)
311 {
312 	int rval;
313 
314 	rval = listen(socket, backlog);
315 
316 	if (rval < 0) {
317 		tst_brkm(TBROK | TERRNO, cleanup_fn,
318 			 "%s:%d: listen(%d, %d) failed", file, lineno, socket,
319 			 backlog);
320 	}
321 
322 	return rval;
323 }
324 
safe_accept(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,struct sockaddr * addr,socklen_t * addrlen)325 int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void),
326 		int sockfd, struct sockaddr *addr, socklen_t *addrlen)
327 {
328 	int rval;
329 
330 	rval = accept(sockfd, addr, addrlen);
331 
332 	if (rval < 0) {
333 		tst_brkm(TBROK | TERRNO, cleanup_fn,
334 			"%s:%d: accept(%d, %p, %d) failed", file, lineno,
335 			sockfd, addr, *addrlen);
336 	}
337 
338 	return rval;
339 }
340 
safe_connect(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,const struct sockaddr * addr,socklen_t addrlen)341 int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void),
342 		 int sockfd, const struct sockaddr *addr, socklen_t addrlen)
343 {
344 	int rval;
345 	char buf[128];
346 
347 	rval = connect(sockfd, addr, addrlen);
348 
349 	if (rval < 0) {
350 		tst_brkm(TBROK | TERRNO, cleanup_fn,
351 			 "%s:%d: connect(%d, %s, %d) failed", file, lineno,
352 			 sockfd, tst_sock_addr(addr, addrlen, buf,
353 					       sizeof(buf)), addrlen);
354 	}
355 
356 	return rval;
357 }
358 
safe_getsockname(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,struct sockaddr * addr,socklen_t * addrlen)359 int safe_getsockname(const char *file, const int lineno,
360 		     void (cleanup_fn)(void), int sockfd, struct sockaddr *addr,
361 		     socklen_t *addrlen)
362 {
363 	int rval;
364 	char buf[128];
365 
366 	rval = getsockname(sockfd, addr, addrlen);
367 
368 	if (rval < 0) {
369 		tst_brkm(TBROK | TERRNO, cleanup_fn,
370 			 "%s:%d: getsockname(%d, %s, %d) failed", file, lineno,
371 			 sockfd, tst_sock_addr(addr, *addrlen, buf,
372 					       sizeof(buf)), *addrlen);
373 	}
374 
375 	return rval;
376 }
377 
safe_gethostname(const char * file,const int lineno,char * name,size_t size)378 int safe_gethostname(const char *file, const int lineno,
379 		     char *name, size_t size)
380 {
381 	int rval = gethostname(name, size);
382 
383 	if (rval < 0) {
384 		tst_brkm(TBROK | TERRNO, NULL,
385 			 "%s:%d: gethostname(%p, %zu) failed",
386 			 file, lineno, name, size);
387 	}
388 
389 	return rval;
390 }
391 
392 /*
393  * @return port in network byte order.
394  */
tst_get_unused_port(const char * file,const int lineno,void (cleanup_fn)(void),unsigned short family,int type)395 unsigned short tst_get_unused_port(const char *file, const int lineno,
396 	      void (cleanup_fn)(void), unsigned short family, int type)
397 {
398 	int sock;
399 	socklen_t slen;
400 	struct sockaddr_storage _addr;
401 	struct sockaddr *addr = (struct sockaddr *)&_addr;
402 	struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
403 	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
404 
405 	switch (family) {
406 	case AF_INET:
407 		addr4->sin_family = AF_INET;
408 		addr4->sin_port = 0;
409 		addr4->sin_addr.s_addr = INADDR_ANY;
410 		slen = sizeof(*addr4);
411 		break;
412 
413 	case AF_INET6:
414 		addr6->sin6_family = AF_INET6;
415 		addr6->sin6_port = 0;
416 		addr6->sin6_addr = in6addr_any;
417 		slen = sizeof(*addr6);
418 		break;
419 
420 	default:
421 		tst_brkm(TBROK, cleanup_fn,
422 			"%s:%d: unknown family", file, lineno);
423 		return -1;
424 	}
425 
426 	sock = socket(addr->sa_family, type, 0);
427 	if (sock < 0) {
428 		tst_brkm(TBROK | TERRNO, cleanup_fn,
429 			 "%s:%d: socket failed", file, lineno);
430 		return -1;
431 	}
432 
433 	if (bind(sock, addr, slen) < 0) {
434 		tst_brkm(TBROK | TERRNO, cleanup_fn,
435 			 "%s:%d: bind failed", file, lineno);
436 		return -1;
437 	}
438 
439 	if (getsockname(sock, addr, &slen) == -1) {
440 		tst_brkm(TBROK | TERRNO, cleanup_fn,
441 			 "%s:%d: getsockname failed", file, lineno);
442 		return -1;
443 	}
444 
445 	if (close(sock) == -1) {
446 		tst_brkm(TBROK | TERRNO, cleanup_fn,
447 			 "%s:%d: close failed", file, lineno);
448 		return -1;
449 	}
450 
451 	switch (family) {
452 	case AF_INET:
453 		return addr4->sin_port;
454 	case AF_INET6:
455 		return addr6->sin6_port;
456 	default:
457 		return -1;
458 	}
459 }
460