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 
safe_socket(const char * file,const int lineno,void (cleanup_fn)(void),int domain,int type,int protocol)84 int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void),
85 		int domain, int type, int protocol)
86 {
87 	int rval;
88 
89 	rval = socket(domain, type, protocol);
90 
91 	if (rval < 0) {
92 		tst_brkm(TBROK | TERRNO, cleanup_fn,
93 			 "%s:%d: socket(%d, %d, %d) failed", file, lineno,
94 			 domain, type, protocol);
95 	}
96 
97 	return rval;
98 }
99 
safe_bind(const char * file,const int lineno,void (cleanup_fn)(void),int socket,const struct sockaddr * address,socklen_t address_len)100 int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void),
101 	      int socket, const struct sockaddr *address,
102 	      socklen_t address_len)
103 {
104 	int i;
105 	char buf[128];
106 
107 	for (i = 0; i < 120; i++) {
108 		if (!bind(socket, address, address_len))
109 			return 0;
110 
111 		if (errno != EADDRINUSE) {
112 			tst_brkm(TBROK | TERRNO, cleanup_fn,
113 				 "%s:%d: bind(%d, %s, %d) failed", file, lineno,
114 				 socket, tst_sock_addr(address, address_len,
115 						       buf, sizeof(buf)),
116 				 address_len);
117 		}
118 
119 		if ((i + 1) % 10 == 0) {
120 			tst_resm(TINFO, "address is in use, waited %3i sec",
121 				 i + 1);
122 		}
123 
124 		sleep(1);
125 	}
126 
127 	tst_brkm(TBROK | TERRNO, cleanup_fn,
128 		 "%s:%d: Failed to bind(%d, %s, %d) after 120 retries", file,
129 		 lineno, socket,
130 		 tst_sock_addr(address, address_len, buf, sizeof(buf)),
131 		 address_len);
132 }
133 
safe_listen(const char * file,const int lineno,void (cleanup_fn)(void),int socket,int backlog)134 int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void),
135 		int socket, int backlog)
136 {
137 	int rval;
138 
139 	rval = listen(socket, backlog);
140 
141 	if (rval < 0) {
142 		tst_brkm(TBROK | TERRNO, cleanup_fn,
143 			 "%s:%d: listen(%d, %d) failed", file, lineno, socket,
144 			 backlog);
145 	}
146 
147 	return rval;
148 }
149 
safe_connect(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,const struct sockaddr * addr,socklen_t addrlen)150 int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void),
151 		 int sockfd, const struct sockaddr *addr, socklen_t addrlen)
152 {
153 	int rval;
154 	char buf[128];
155 
156 	rval = connect(sockfd, addr, addrlen);
157 
158 	if (rval < 0) {
159 		tst_brkm(TBROK | TERRNO, cleanup_fn,
160 			 "%s:%d: connect(%d, %s, %d) failed", file, lineno,
161 			 sockfd, tst_sock_addr(addr, addrlen, buf,
162 					       sizeof(buf)), addrlen);
163 	}
164 
165 	return rval;
166 }
167 
safe_getsockname(const char * file,const int lineno,void (cleanup_fn)(void),int sockfd,struct sockaddr * addr,socklen_t * addrlen)168 int safe_getsockname(const char *file, const int lineno,
169 		     void (cleanup_fn)(void), int sockfd, struct sockaddr *addr,
170 		     socklen_t *addrlen)
171 {
172 	int rval;
173 	char buf[128];
174 
175 	rval = getsockname(sockfd, addr, addrlen);
176 
177 	if (rval < 0) {
178 		tst_brkm(TBROK | TERRNO, cleanup_fn,
179 			 "%s:%d: getsockname(%d, %s, %d) failed", file, lineno,
180 			 sockfd, tst_sock_addr(addr, *addrlen, buf,
181 					       sizeof(buf)), *addrlen);
182 	}
183 
184 	return rval;
185 }
186