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
23char *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
84int 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
100int 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
134int 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
150int 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
168int 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