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