Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/libbb/xconnect.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 4  Line 4 
4   *   *
5   * Connect to host at port using address resolution from getaddrinfo   * Connect to host at port using address resolution from getaddrinfo
6   *   *
7     * Licensed under GPLv2, see file LICENSE in this tarball for details.
8   */   */
9    
10    #include <sys/socket.h> /* netinet/in.h needs it */
11  #include <netinet/in.h>  #include <netinet/in.h>
12  #include <net/if.h>  #include <net/if.h>
13    #include <sys/un.h>
14  #include "libbb.h"  #include "libbb.h"
15    
16  void FAST_FUNC setsockopt_reuseaddr(int fd)  void FAST_FUNC setsockopt_reuseaddr(int fd)
# Line 22  int FAST_FUNC setsockopt_bindtodevice(in Line 25  int FAST_FUNC setsockopt_bindtodevice(in
25  {  {
26   int r;   int r;
27   struct ifreq ifr;   struct ifreq ifr;
28   strncpy(ifr.ifr_name, iface, IFNAMSIZ);   strncpy_IFNAMSIZ(ifr.ifr_name, iface);
29   /* Actually, ifr_name is at offset 0, and in practice   /* NB: passing (iface, strlen(iface) + 1) does not work!
30     * (maybe it works on _some_ kernels, but not on 2.6.26)
31     * Actually, ifr_name is at offset 0, and in practice
32   * just giving char[IFNAMSIZ] instead of struct ifreq works too.   * just giving char[IFNAMSIZ] instead of struct ifreq works too.
33   * But just in case it's not true on some obscure arch... */   * But just in case it's not true on some obscure arch... */
34   r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));   r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
# Line 32  int FAST_FUNC setsockopt_bindtodevice(in Line 37  int FAST_FUNC setsockopt_bindtodevice(in
37   return r;   return r;
38  }  }
39    
40    len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd)
41    {
42     len_and_sockaddr lsa;
43     len_and_sockaddr *lsa_ptr;
44    
45     lsa.len = LSA_SIZEOF_SA;
46     if (getsockname(fd, &lsa.u.sa, &lsa.len) != 0)
47     return NULL;
48    
49     lsa_ptr = xzalloc(LSA_LEN_SIZE + lsa.len);
50     if (lsa.len > LSA_SIZEOF_SA) { /* rarely (if ever) happens */
51     lsa_ptr->len = lsa.len;
52     getsockname(fd, &lsa_ptr->u.sa, &lsa_ptr->len);
53     } else {
54     memcpy(lsa_ptr, &lsa, LSA_LEN_SIZE + lsa.len);
55     }
56     return lsa_ptr;
57    }
58    
59  void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)  void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
60  {  {
# Line 40  void FAST_FUNC xconnect(int s, const str Line 63  void FAST_FUNC xconnect(int s, const str
63   close(s);   close(s);
64   if (s_addr->sa_family == AF_INET)   if (s_addr->sa_family == AF_INET)
65   bb_perror_msg_and_die("%s (%s)",   bb_perror_msg_and_die("%s (%s)",
66   "cannot connect to remote host",   "can't connect to remote host",
67   inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));   inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
68   bb_perror_msg_and_die("cannot connect to remote host");   bb_perror_msg_and_die("can't connect to remote host");
69   }   }
70  }  }
71    
72  /* Return port number for a service.  /* Return port number for a service.
73   * If "port" is a number use it as the port.   * If "port" is a number use it as the port.
74   * If "port" is a name it is looked up in /etc/services, if it isnt found return   * If "port" is a name it is looked up in /etc/services,
75   * default_port */   * if it isnt found return default_port
76     */
77  unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port)  unsigned FAST_FUNC bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
78  {  {
79   unsigned port_nr = default_port;   unsigned port_nr = default_port;
# Line 134  void FAST_FUNC set_nport(len_and_sockadd Line 158  void FAST_FUNC set_nport(len_and_sockadd
158   * port: if neither of above specifies port # */   * port: if neither of above specifies port # */
159  static len_and_sockaddr* str2sockaddr(  static len_and_sockaddr* str2sockaddr(
160   const char *host, int port,   const char *host, int port,
161  USE_FEATURE_IPV6(sa_family_t af,)  IF_FEATURE_IPV6(sa_family_t af,)
162   int ai_flags)   int ai_flags)
163  {  {
164    IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;)
165   int rc;   int rc;
166   len_and_sockaddr *r = NULL;   len_and_sockaddr *r;
167   struct addrinfo *result = NULL;   struct addrinfo *result = NULL;
168   struct addrinfo *used_res;   struct addrinfo *used_res;
169   const char *org_host = host; /* only for error msg */   const char *org_host = host; /* only for error msg */
170   const char *cp;   const char *cp;
171   struct addrinfo hint;   struct addrinfo hint;
172    
173     if (ENABLE_FEATURE_UNIX_LOCAL && strncmp(host, "local:", 6) == 0) {
174     struct sockaddr_un *sun;
175    
176     r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
177     r->len = sizeof(struct sockaddr_un);
178     r->u.sa.sa_family = AF_UNIX;
179     sun = (struct sockaddr_un *)&r->u.sa;
180     safe_strncpy(sun->sun_path, host + 6, sizeof(sun->sun_path));
181     return r;
182     }
183    
184     r = NULL;
185    
186   /* Ugly parsing of host:addr */   /* Ugly parsing of host:addr */
187   if (ENABLE_FEATURE_IPV6 && host[0] == '[') {   if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
188   /* Even uglier parsing of [xx]:nn */   /* Even uglier parsing of [xx]:nn */
189   host++;   host++;
190   cp = strchr(host, ']');   cp = strchr(host, ']');
191   if (!cp || cp[1] != ':') { /* Malformed: must have [xx]:nn */   if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
192     /* Malformed: must be [xx]:nn or [xx] */
193   bb_error_msg("bad address '%s'", org_host);   bb_error_msg("bad address '%s'", org_host);
194   if (ai_flags & DIE_ON_ERROR)   if (ai_flags & DIE_ON_ERROR)
195   xfunc_die();   xfunc_die();
# Line 165  USE_FEATURE_IPV6(sa_family_t af,) Line 204  USE_FEATURE_IPV6(sa_family_t af,)
204   }   }
205   if (cp) { /* points to ":" or "]:" */   if (cp) { /* points to ":" or "]:" */
206   int sz = cp - host + 1;   int sz = cp - host + 1;
207    
208   host = safe_strncpy(alloca(sz), host, sz);   host = safe_strncpy(alloca(sz), host, sz);
209   if (ENABLE_FEATURE_IPV6 && *cp != ':')   if (ENABLE_FEATURE_IPV6 && *cp != ':') {
210   cp++; /* skip ']' */   cp++; /* skip ']' */
211     if (*cp == '\0') /* [xx] without port */
212     goto skip;
213     }
214   cp++; /* skip ':' */   cp++; /* skip ':' */
215   port = bb_strtou(cp, NULL, 10);   port = bb_strtou(cp, NULL, 10);
216   if (errno || (unsigned)port > 0xffff) {   if (errno || (unsigned)port > 0xffff) {
# Line 176  USE_FEATURE_IPV6(sa_family_t af,) Line 219  USE_FEATURE_IPV6(sa_family_t af,)
219   xfunc_die();   xfunc_die();
220   return NULL;   return NULL;
221   }   }
222     skip: ;
223   }   }
224    
225     /* Next two if blocks allow to skip getaddrinfo()
226     * in case host name is a numeric IP(v6) address.
227     * getaddrinfo() initializes DNS resolution machinery,
228     * scans network config and such - tens of syscalls.
229     */
230     /* If we were not asked specifically for IPv6,
231     * check whether this is a numeric IPv4 */
232     IF_FEATURE_IPV6(if(af != AF_INET6)) {
233     struct in_addr in4;
234     if (inet_aton(host, &in4) != 0) {
235     r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in));
236     r->len = sizeof(struct sockaddr_in);
237     r->u.sa.sa_family = AF_INET;
238     r->u.sin.sin_addr = in4;
239     goto set_port;
240     }
241     }
242    #if ENABLE_FEATURE_IPV6
243     /* If we were not asked specifically for IPv4,
244     * check whether this is a numeric IPv6 */
245     if (af != AF_INET) {
246     struct in6_addr in6;
247     if (inet_pton(AF_INET6, host, &in6) > 0) {
248     r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in6));
249     r->len = sizeof(struct sockaddr_in6);
250     r->u.sa.sa_family = AF_INET6;
251     r->u.sin6.sin6_addr = in6;
252     goto set_port;
253     }
254     }
255    #endif
256    
257   memset(&hint, 0 , sizeof(hint));   memset(&hint, 0 , sizeof(hint));
 #if !ENABLE_FEATURE_IPV6  
  hint.ai_family = AF_INET; /* do not try to find IPv6 */  
 #else  
258   hint.ai_family = af;   hint.ai_family = af;
 #endif  
259   /* Needed. Or else we will get each address thrice (or more)   /* Needed. Or else we will get each address thrice (or more)
260   * for each possible socket type (tcp,udp,raw...): */   * for each possible socket type (tcp,udp,raw...): */
261   hint.ai_socktype = SOCK_STREAM;   hint.ai_socktype = SOCK_STREAM;
# Line 207  USE_FEATURE_IPV6(sa_family_t af,) Line 279  USE_FEATURE_IPV6(sa_family_t af,)
279   }   }
280   }   }
281  #endif  #endif
282   r = xmalloc(offsetof(len_and_sockaddr, u.sa) + used_res->ai_addrlen);   r = xmalloc(LSA_LEN_SIZE + used_res->ai_addrlen);
283   r->len = used_res->ai_addrlen;   r->len = used_res->ai_addrlen;
284   memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);   memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
285    
286     set_port:
287   set_nport(r, htons(port));   set_nport(r, htons(port));
288   ret:   ret:
289   freeaddrinfo(result);   freeaddrinfo(result);
# Line 247  len_and_sockaddr* FAST_FUNC xdotted2sock Line 321  len_and_sockaddr* FAST_FUNC xdotted2sock
321  }  }
322    
323  #undef xsocket_type  #undef xsocket_type
324  int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type)  int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type)
325  {  {
326   SKIP_FEATURE_IPV6(enum { family = AF_INET };)   IF_NOT_FEATURE_IPV6(enum { family = AF_INET };)
327   len_and_sockaddr *lsa;   len_and_sockaddr *lsa;
328   int fd;   int fd;
329   int len;   int len;
# Line 272  int FAST_FUNC xsocket_type(len_and_socka Line 346  int FAST_FUNC xsocket_type(len_and_socka
346   len = sizeof(struct sockaddr_in6);   len = sizeof(struct sockaddr_in6);
347   }   }
348  #endif  #endif
349   lsa = xzalloc(offsetof(len_and_sockaddr, u.sa) + len);   lsa = xzalloc(LSA_LEN_SIZE + len);
350   lsa->len = len;   lsa->len = len;
351   lsa->u.sa.sa_family = family;   lsa->u.sa.sa_family = family;
352   *lsap = lsa;   *lsap = lsa;
# Line 281  int FAST_FUNC xsocket_type(len_and_socka Line 355  int FAST_FUNC xsocket_type(len_and_socka
355    
356  int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap)  int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap)
357  {  {
358   return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);   return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
359  }  }
360    
361  static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)  static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
# Line 294  static int create_and_bind_or_die(const Line 368  static int create_and_bind_or_die(const
368   /* user specified bind addr dictates family */   /* user specified bind addr dictates family */
369   fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);   fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
370   } else {   } else {
371   fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);   fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type);
372   set_nport(lsa, htons(port));   set_nport(lsa, htons(port));
373   }   }
374   setsockopt_reuseaddr(fd);   setsockopt_reuseaddr(fd);
# Line 344  static char* FAST_FUNC sockaddr2str(cons Line 418  static char* FAST_FUNC sockaddr2str(cons
418   int rc;   int rc;
419   socklen_t salen;   socklen_t salen;
420    
421     if (ENABLE_FEATURE_UNIX_LOCAL && sa->sa_family == AF_UNIX) {
422     struct sockaddr_un *sun = (struct sockaddr_un *)sa;
423     return xasprintf("local:%.*s",
424     (int) sizeof(sun->sun_path),
425     sun->sun_path);
426     }
427    
428   salen = LSA_SIZEOF_SA;   salen = LSA_SIZEOF_SA;
429  #if ENABLE_FEATURE_IPV6  #if ENABLE_FEATURE_IPV6
430   if (sa->sa_family == AF_INET)   if (sa->sa_family == AF_INET)

Legend:
Removed from v.983  
changed lines
  Added in v.984