Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/libbb/xconnect.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/libbb/xconnect.c
r821 r1770 7 7 */ 8 8 9 #include <unistd.h>10 #include <string.h>11 #include <stdlib.h>12 #include <sys/types.h>13 #include <sys/socket.h>14 #include <errno.h>15 #include <netdb.h>16 #include <sys/socket.h>17 9 #include <netinet/in.h> 18 #include <arpa/inet.h>19 10 #include "libbb.h" 20 11 21 /* Return network byte ordered port number for a service. 12 void setsockopt_reuseaddr(int fd) 13 { 14 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)); 15 } 16 int setsockopt_broadcast(int fd) 17 { 18 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1)); 19 } 20 21 void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) 22 { 23 if (connect(s, s_addr, addrlen) < 0) { 24 if (ENABLE_FEATURE_CLEAN_UP) 25 close(s); 26 if (s_addr->sa_family == AF_INET) 27 bb_perror_msg_and_die("%s (%s)", 28 "cannot connect to remote host", 29 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr)); 30 bb_perror_msg_and_die("cannot connect to remote host"); 31 } 32 } 33 34 /* Return port number for a service. 22 35 * If "port" is a number use it as the port. 23 36 * If "port" is a name it is looked up in /etc/services, if it isnt found return 24 * default_port 25 */ 26 unsigned short bb_lookup_port(const char *port, const char *protocol, unsigned short default_port) 27 { 28 unsigned short port_nr = htons(default_port); 37 * default_port */ 38 unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port) 39 { 40 unsigned port_nr = default_port; 29 41 if (port) { 30 char *endptr;31 42 int old_errno; 32 long port_long;33 43 34 44 /* Since this is a lib function, we're not allowed to reset errno to 0. 35 45 * Doing so could break an app that is deferring checking of errno. */ 36 46 old_errno = errno; 37 errno = 0; 38 port_long = strtol(port, &endptr, 10); 39 if (errno != 0 || *endptr!='\0' || endptr==port || port_long < 0 || port_long > 65535) { 47 port_nr = bb_strtou(port, NULL, 10); 48 if (errno || port_nr > 65535) { 40 49 struct servent *tserv = getservbyname(port, protocol); 41 if (tserv) { 42 port_nr = tserv->s_port; 43 } 44 } else { 45 port_nr = htons(port_long); 50 port_nr = default_port; 51 if (tserv) 52 port_nr = ntohs(tserv->s_port); 46 53 } 47 54 errno = old_errno; 48 55 } 49 return port_nr; 50 } 51 56 return (uint16_t)port_nr; 57 } 58 59 60 /* "Old" networking API - only IPv4 */ 61 62 /* 52 63 void bb_lookup_host(struct sockaddr_in *s_in, const char *host) 53 64 { … … 60 71 } 61 72 62 int xconnect(struct sockaddr_in *s_addr) 63 { 64 int s = bb_xsocket(AF_INET, SOCK_STREAM, 0); 65 if (connect(s, (struct sockaddr *)s_addr, sizeof(struct sockaddr_in)) < 0) 66 { 67 if (ENABLE_FEATURE_CLEAN_UP) close(s); 68 bb_perror_msg_and_die("Unable to connect to remote host (%s)", 69 inet_ntoa(s_addr->sin_addr)); 70 } 73 74 int xconnect_tcp_v4(struct sockaddr_in *s_addr) 75 { 76 int s = xsocket(AF_INET, SOCK_STREAM, 0); 77 xconnect(s, (struct sockaddr*) s_addr, sizeof(*s_addr)); 71 78 return s; 72 79 } 80 */ 81 82 /* "New" networking API */ 83 84 85 int get_nport(const struct sockaddr *sa) 86 { 87 #if ENABLE_FEATURE_IPV6 88 if (sa->sa_family == AF_INET6) { 89 return ((struct sockaddr_in6*)sa)->sin6_port; 90 } 91 #endif 92 if (sa->sa_family == AF_INET) { 93 return ((struct sockaddr_in*)sa)->sin_port; 94 } 95 /* What? UNIX socket? IPX?? :) */ 96 return -1; 97 } 98 99 void set_nport(len_and_sockaddr *lsa, unsigned port) 100 { 101 #if ENABLE_FEATURE_IPV6 102 if (lsa->sa.sa_family == AF_INET6) { 103 lsa->sin6.sin6_port = port; 104 return; 105 } 106 #endif 107 if (lsa->sa.sa_family == AF_INET) { 108 lsa->sin.sin_port = port; 109 return; 110 } 111 /* What? UNIX socket? IPX?? :) */ 112 } 113 114 /* We hijack this constant to mean something else */ 115 /* It doesn't hurt because we will remove this bit anyway */ 116 #define DIE_ON_ERROR AI_CANONNAME 117 118 /* host: "1.2.3.4[:port]", "www.google.com[:port]" 119 * port: if neither of above specifies port # */ 120 static len_and_sockaddr* str2sockaddr( 121 const char *host, int port, 122 USE_FEATURE_IPV6(sa_family_t af,) 123 int ai_flags) 124 { 125 int rc; 126 len_and_sockaddr *r = NULL; 127 struct addrinfo *result = NULL; 128 const char *org_host = host; /* only for error msg */ 129 const char *cp; 130 struct addrinfo hint; 131 132 /* Ugly parsing of host:addr */ 133 if (ENABLE_FEATURE_IPV6 && host[0] == '[') { 134 host++; 135 cp = strchr(host, ']'); 136 if (!cp || cp[1] != ':') /* Malformed: must have [xx]:nn */ 137 bb_error_msg_and_die("bad address '%s'", org_host); 138 //return r; /* return NULL */ 139 } else { 140 cp = strrchr(host, ':'); 141 if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) { 142 /* There is more than one ':' (e.g. "::1") */ 143 cp = NULL; /* it's not a port spec */ 144 } 145 } 146 if (cp) { 147 int sz = cp - host + 1; 148 host = safe_strncpy(alloca(sz), host, sz); 149 if (ENABLE_FEATURE_IPV6 && *cp != ':') 150 cp++; /* skip ']' */ 151 cp++; /* skip ':' */ 152 port = xatou16(cp); 153 } 154 155 memset(&hint, 0 , sizeof(hint)); 156 #if !ENABLE_FEATURE_IPV6 157 hint.ai_family = AF_INET; /* do not try to find IPv6 */ 158 #else 159 hint.ai_family = af; 160 #endif 161 /* Needed. Or else we will get each address thrice (or more) 162 * for each possible socket type (tcp,udp,raw...): */ 163 hint.ai_socktype = SOCK_STREAM; 164 hint.ai_flags = ai_flags & ~DIE_ON_ERROR; 165 rc = getaddrinfo(host, NULL, &hint, &result); 166 if (rc || !result) { 167 bb_error_msg("bad address '%s'", org_host); 168 if (ai_flags & DIE_ON_ERROR) 169 xfunc_die(); 170 goto ret; 171 } 172 r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen); 173 r->len = result->ai_addrlen; 174 memcpy(&r->sa, result->ai_addr, result->ai_addrlen); 175 set_nport(r, htons(port)); 176 ret: 177 freeaddrinfo(result); 178 return r; 179 } 180 #if !ENABLE_FEATURE_IPV6 181 #define str2sockaddr(host, port, af, ai_flags) str2sockaddr(host, port, ai_flags) 182 #endif 183 184 #if ENABLE_FEATURE_IPV6 185 len_and_sockaddr* host_and_af2sockaddr(const char *host, int port, sa_family_t af) 186 { 187 return str2sockaddr(host, port, af, 0); 188 } 189 190 len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t af) 191 { 192 return str2sockaddr(host, port, af, DIE_ON_ERROR); 193 } 194 #endif 195 196 len_and_sockaddr* host2sockaddr(const char *host, int port) 197 { 198 return str2sockaddr(host, port, AF_UNSPEC, 0); 199 } 200 201 len_and_sockaddr* xhost2sockaddr(const char *host, int port) 202 { 203 return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR); 204 } 205 206 len_and_sockaddr* xdotted2sockaddr(const char *host, int port) 207 { 208 return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); 209 } 210 211 int xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type) 212 { 213 SKIP_FEATURE_IPV6(enum { family = AF_INET };) 214 len_and_sockaddr *lsa; 215 int fd; 216 int len; 217 218 #if ENABLE_FEATURE_IPV6 219 if (family == AF_UNSPEC) { 220 fd = socket(AF_INET6, sock_type, 0); 221 if (fd >= 0) { 222 family = AF_INET6; 223 goto done; 224 } 225 family = AF_INET; 226 } 227 #endif 228 fd = xsocket(family, sock_type, 0); 229 len = sizeof(struct sockaddr_in); 230 #if ENABLE_FEATURE_IPV6 231 if (family == AF_INET6) { 232 done: 233 len = sizeof(struct sockaddr_in6); 234 } 235 #endif 236 lsa = xzalloc(offsetof(len_and_sockaddr, sa) + len); 237 lsa->len = len; 238 lsa->sa.sa_family = family; 239 *lsap = lsa; 240 return fd; 241 } 242 243 int xsocket_stream(len_and_sockaddr **lsap) 244 { 245 return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM); 246 } 247 248 static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) 249 { 250 int fd; 251 len_and_sockaddr *lsa; 252 253 if (bindaddr && bindaddr[0]) { 254 lsa = xdotted2sockaddr(bindaddr, port); 255 /* user specified bind addr dictates family */ 256 fd = xsocket(lsa->sa.sa_family, sock_type, 0); 257 } else { 258 fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type); 259 set_nport(lsa, htons(port)); 260 } 261 setsockopt_reuseaddr(fd); 262 xbind(fd, &lsa->sa, lsa->len); 263 free(lsa); 264 return fd; 265 } 266 267 int create_and_bind_stream_or_die(const char *bindaddr, int port) 268 { 269 return create_and_bind_or_die(bindaddr, port, SOCK_STREAM); 270 } 271 272 int create_and_bind_dgram_or_die(const char *bindaddr, int port) 273 { 274 return create_and_bind_or_die(bindaddr, port, SOCK_DGRAM); 275 } 276 277 278 int create_and_connect_stream_or_die(const char *peer, int port) 279 { 280 int fd; 281 len_and_sockaddr *lsa; 282 283 lsa = xhost2sockaddr(peer, port); 284 fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0); 285 setsockopt_reuseaddr(fd); 286 xconnect(fd, &lsa->sa, lsa->len); 287 free(lsa); 288 return fd; 289 } 290 291 int xconnect_stream(const len_and_sockaddr *lsa) 292 { 293 int fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0); 294 xconnect(fd, &lsa->sa, lsa->len); 295 return fd; 296 } 297 298 /* We hijack this constant to mean something else */ 299 /* It doesn't hurt because we will add this bit anyway */ 300 #define IGNORE_PORT NI_NUMERICSERV 301 static char* sockaddr2str(const struct sockaddr *sa, int flags) 302 { 303 char host[128]; 304 char serv[16]; 305 int rc; 306 socklen_t salen; 307 308 salen = LSA_SIZEOF_SA; 309 #if ENABLE_FEATURE_IPV6 310 if (sa->sa_family == AF_INET) 311 salen = sizeof(struct sockaddr_in); 312 if (sa->sa_family == AF_INET6) 313 salen = sizeof(struct sockaddr_in6); 314 #endif 315 rc = getnameinfo(sa, salen, 316 host, sizeof(host), 317 /* can do ((flags & IGNORE_PORT) ? NULL : serv) but why bother? */ 318 serv, sizeof(serv), 319 /* do not resolve port# into service _name_ */ 320 flags | NI_NUMERICSERV 321 ); 322 if (rc) 323 return NULL; 324 if (flags & IGNORE_PORT) 325 return xstrdup(host); 326 #if ENABLE_FEATURE_IPV6 327 if (sa->sa_family == AF_INET6) { 328 if (strchr(host, ':')) /* heh, it's not a resolved hostname */ 329 return xasprintf("[%s]:%s", host, serv); 330 /*return xasprintf("%s:%s", host, serv);*/ 331 /* - fall through instead */ 332 } 333 #endif 334 /* For now we don't support anything else, so it has to be INET */ 335 /*if (sa->sa_family == AF_INET)*/ 336 return xasprintf("%s:%s", host, serv); 337 /*return xstrdup(host);*/ 338 } 339 340 char* xmalloc_sockaddr2host(const struct sockaddr *sa) 341 { 342 return sockaddr2str(sa, 0); 343 } 344 345 char* xmalloc_sockaddr2host_noport(const struct sockaddr *sa) 346 { 347 return sockaddr2str(sa, IGNORE_PORT); 348 } 349 350 char* xmalloc_sockaddr2hostonly_noport(const struct sockaddr *sa) 351 { 352 return sockaddr2str(sa, NI_NAMEREQD | IGNORE_PORT); 353 } 354 char* xmalloc_sockaddr2dotted(const struct sockaddr *sa) 355 { 356 return sockaddr2str(sa, NI_NUMERICHOST); 357 } 358 359 char* xmalloc_sockaddr2dotted_noport(const struct sockaddr *sa) 360 { 361 return sockaddr2str(sa, NI_NUMERICHOST | IGNORE_PORT); 362 }
Note:
See TracChangeset
for help on using the changeset viewer.