Home | History | Annotate | Download | only in lib
      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 
     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 
     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 
    100 int safe_setsockopt(const char *file, const int lineno, int sockfd, int level,
    101 		    int optname, const void *optval, socklen_t optlen)
    102 {
    103 	int rval;
    104 
    105 	rval = setsockopt(sockfd, level, optname, optval, optlen);
    106 
    107 	if (rval) {
    108 		tst_brkm(TBROK | TERRNO, NULL,
    109 			 "%s:%d: setsockopt(%d, %d, %d, %p, %d) failed",
    110 			 file, lineno, sockfd, level, optname, optval, optlen);
    111 	}
    112 
    113 	return rval;
    114 }
    115 
    116 ssize_t safe_send(const char *file, const int lineno, char len_strict,
    117 		  int sockfd, const void *buf, size_t len, int flags)
    118 {
    119 	ssize_t rval;
    120 
    121 	rval = send(sockfd, buf, len, flags);
    122 
    123 	if (rval == -1 || (len_strict && (size_t)rval != len)) {
    124 		tst_brkm(TBROK | TERRNO, NULL,
    125 			 "%s:%d: send(%d, %p, %zu, %d) failed",
    126 			 file, lineno, sockfd, buf, len, flags);
    127 	}
    128 
    129 	return rval;
    130 }
    131 
    132 ssize_t safe_sendto(const char *file, const int lineno, char len_strict,
    133 		    int sockfd, const void *buf, size_t len, int flags,
    134 		    const struct sockaddr *dest_addr, socklen_t addrlen)
    135 {
    136 	ssize_t rval;
    137 	char res[128];
    138 
    139 	rval = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
    140 
    141 	if (rval == -1 || (len_strict && (size_t)rval != len)) {
    142 		tst_brkm(TBROK | TERRNO, NULL,
    143 			 "%s:%d: sendto(%d, %p, %zu, %d, %s, %d) failed",
    144 			 file, lineno, sockfd, buf, len, flags,
    145 			 tst_sock_addr(dest_addr, addrlen, res, sizeof(res)),
    146 			 addrlen);
    147 	}
    148 
    149 	return rval;
    150 }
    151 
    152 int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void),
    153 	      int socket, const struct sockaddr *address,
    154 	      socklen_t address_len)
    155 {
    156 	int i;
    157 	char buf[128];
    158 
    159 	for (i = 0; i < 120; i++) {
    160 		if (!bind(socket, address, address_len))
    161 			return 0;
    162 
    163 		if (errno != EADDRINUSE) {
    164 			tst_brkm(TBROK | TERRNO, cleanup_fn,
    165 				 "%s:%d: bind(%d, %s, %d) failed", file, lineno,
    166 				 socket, tst_sock_addr(address, address_len,
    167 						       buf, sizeof(buf)),
    168 				 address_len);
    169 			return -1;
    170 		}
    171 
    172 		if ((i + 1) % 10 == 0) {
    173 			tst_resm(TINFO, "address is in use, waited %3i sec",
    174 				 i + 1);
    175 		}
    176 
    177 		sleep(1);
    178 	}
    179 
    180 	tst_brkm(TBROK | TERRNO, cleanup_fn,
    181 		 "%s:%d: Failed to bind(%d, %s, %d) after 120 retries", file,
    182 		 lineno, socket,
    183 		 tst_sock_addr(address, address_len, buf, sizeof(buf)),
    184 		 address_len);
    185 	return -1;
    186 }
    187 
    188 int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void),
    189 		int socket, int backlog)
    190 {
    191 	int rval;
    192 
    193 	rval = listen(socket, backlog);
    194 
    195 	if (rval < 0) {
    196 		tst_brkm(TBROK | TERRNO, cleanup_fn,
    197 			 "%s:%d: listen(%d, %d) failed", file, lineno, socket,
    198 			 backlog);
    199 	}
    200 
    201 	return rval;
    202 }
    203 
    204 int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void),
    205 		 int sockfd, const struct sockaddr *addr, socklen_t addrlen)
    206 {
    207 	int rval;
    208 	char buf[128];
    209 
    210 	rval = connect(sockfd, addr, addrlen);
    211 
    212 	if (rval < 0) {
    213 		tst_brkm(TBROK | TERRNO, cleanup_fn,
    214 			 "%s:%d: connect(%d, %s, %d) failed", file, lineno,
    215 			 sockfd, tst_sock_addr(addr, addrlen, buf,
    216 					       sizeof(buf)), addrlen);
    217 	}
    218 
    219 	return rval;
    220 }
    221 
    222 int safe_getsockname(const char *file, const int lineno,
    223 		     void (cleanup_fn)(void), int sockfd, struct sockaddr *addr,
    224 		     socklen_t *addrlen)
    225 {
    226 	int rval;
    227 	char buf[128];
    228 
    229 	rval = getsockname(sockfd, addr, addrlen);
    230 
    231 	if (rval < 0) {
    232 		tst_brkm(TBROK | TERRNO, cleanup_fn,
    233 			 "%s:%d: getsockname(%d, %s, %d) failed", file, lineno,
    234 			 sockfd, tst_sock_addr(addr, *addrlen, buf,
    235 					       sizeof(buf)), *addrlen);
    236 	}
    237 
    238 	return rval;
    239 }
    240 
    241 int safe_gethostname(const char *file, const int lineno,
    242 		     char *name, size_t size)
    243 {
    244 	int rval = gethostname(name, size);
    245 
    246 	if (rval < 0) {
    247 		tst_brkm(TBROK | TERRNO, NULL,
    248 			 "%s:%d: gethostname(%p, %zu) failed",
    249 			 file, lineno, name, size);
    250 	}
    251 
    252 	return rval;
    253 }
    254