net.c

00001 /* 
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l.
00003  */
00004 
00005 #include <stdlib.h>
00006 #include <stdio.h>
00007 #include <errno.h>
00008 #include <unistd.h>
00009 #include <string.h>
00010 #include <strings.h>
00011 
00012 #include <toolbox/carpal.h>
00013 #include <toolbox/net.h>
00014 #include <toolbox/misc.h>
00015 
00016 #ifndef HAVE_GETADDRINFO
00017 /* Duplicate addrinfo layout in case struct addrinfo and related
00018  * methods were not available on the platform. */
00019 struct u_addrinfo_s
00020 {
00021     int ai_flags;       /* not used */
00022     int ai_family;      /* AF_INET, AF_INET6, AF_UNIX */
00023     int ai_socktype;    /* SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET */
00024     int ai_protocol;    /* (ai_family == AF_UNIX) => 0, otherwise one of:
00025                            IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP */
00026     char *ai_canonname;
00027     u_socklen_t ai_addrlen;
00028     struct sockaddr *ai_addr;
00029     struct u_addrinfo_s *ai_next;
00030 };
00031 #endif  /* !HAVE_GETADDRINFO */
00032 
00033 /* how u_net uri are represented */
00034 struct u_net_addr_s
00035 {
00036     int opts;   /* OR'd U_NET_OPT's */
00037     u_net_mode_t mode;  /* one of U_NET_SSOCK or U_NET_CSOCK */
00038     u_addrinfo_t *addr; /* list of available addresses */
00039     u_addrinfo_t *cur;  /* reference to the current working address */
00040 };
00041 
00042 /* private stuff */ 
00043 static int na_new (u_net_mode_t mode, u_net_addr_t **pa);
00044 static void ai_free (u_addrinfo_t *ai);
00045 #ifndef NO_SCTP
00046 static int sctp_enable_events (int s, int opts);
00047 #endif  /* !NO_SCTP */
00048 static int bind_reuse_addr (int s);
00049 
00050 /* low level resolvers */
00051 static int do_resolv (
00052         int rf (const char *, const char *, const char *, u_addrinfo_t *ai), 
00053         const char *host, const char *port, const char *path, int family, 
00054         int type, int proto, u_addrinfo_t **pai);
00055 #ifndef NO_UNIXSOCK
00056 /* this is needed here because getaddrinfo() don't understand AF_UNIX */
00057 static int resolv_sun (const char *dummy1, const char *dummy2, const char *path,
00058         u_addrinfo_t *ai); 
00059 #endif  /* !NO_UNIXSOCK */
00060 static int ai_resolv (const char *host, const char *port, const char *path,
00061         int family, int type, int proto, int passive, u_addrinfo_t **pai);
00062 
00063 #ifndef HAVE_GETADDRINFO
00064 static int resolv_sin (const char *host, const char *port, const char *dummy, 
00065         u_addrinfo_t *ai); 
00066 #ifndef NO_IPV6
00067 static int resolv_sin6 (const char *host, const char *port, const char *dummy,
00068         u_addrinfo_t *ai);
00069 #endif  /* !NO_IPV6 */
00070 static int resolv_port (const char *s_port, uint16_t *pin_port);
00071 #endif  /* !HAVE_GETADDRINFO */
00072 
00073 /* socket creation horses */
00074 static int do_sock (
00075         int f(struct sockaddr *, u_socklen_t, int, int, int, int, int, 
00076             struct timeval *),
00077         struct u_net_addr_s *a, int backlog, u_addrinfo_t **pai, 
00078         struct timeval *timeout);
00079 static int do_csock (struct sockaddr *sad, u_socklen_t sad_len, int domain, 
00080         int type, int protocol, int opts, int dummy,
00081         struct timeval *timeout);
00082 static int do_ssock (struct sockaddr *sad, u_socklen_t sad_len, int domain, 
00083         int type, int protocol, int opts, int backlog,
00084         struct timeval *dummy);
00085 
00086 /* URI scheme mapper */
00087 struct u_net_scheme_map_s
00088 {
00089     int addr_family;    /* one of AF_... */
00090     int sock_type;      /* one of SOCK_... */
00091     int proto;          /* one of IPPROTO_... */
00092 };
00093 typedef struct u_net_scheme_map_s u_net_scheme_map_t;
00094 
00095 static int scheme_mapper (const char *scheme, u_net_scheme_map_t *map);
00096 static int uri2addr (u_uri_t *u, u_net_scheme_map_t *m, u_net_addr_t *a);
00097 static inline int update_timeout (struct timeval *timeout, 
00098         struct timeval *tstart);
00099 
00228 int u_net_uri2addr (const char *uri, u_net_mode_t mode, u_net_addr_t **pa)
00229 {
00230     const char *s;
00231     u_uri_t *u = NULL;
00232     u_net_scheme_map_t smap;
00233     u_net_addr_t *a = NULL;
00234 
00235     dbg_return_if (uri == NULL, ~0);
00236     dbg_return_if (pa == NULL, ~0);
00237 
00238     /* decode address and map the uri scheme to a suitable set of socket 
00239      * creation parameters */
00240     dbg_err_if (u_uri_crumble(uri, U_URI_OPT_NONE, &u));
00241     dbg_err_if ((s = u_uri_get_scheme(u)) == NULL);
00242     dbg_err_ifm (scheme_mapper(s, &smap), "unsupported URI scheme: %s", s);
00243 
00244     /* create the address container */
00245     dbg_err_sif (na_new(mode, &a));
00246 
00247     /* create the internal representation */
00248     dbg_err_if (uri2addr(u, &smap, a));
00249 
00250     u_uri_free(u);
00251 
00252     *pa = a;
00253 
00254     return 0;
00255 err:
00256     if (u)
00257         u_uri_free(u);
00258     if (a)
00259         u_net_addr_free(a);
00260     return ~0;
00261 }
00262 
00278 int u_net_sd_by_addr_ex (u_net_addr_t *a, struct timeval *timeout)
00279 {
00280     dbg_return_if (a == NULL, ~1);
00281 
00282     switch (a->mode)
00283     {
00284         case U_NET_SSOCK:
00285             return do_sock(do_ssock, a, U_NET_BACKLOG, &a->cur, timeout);
00286         case U_NET_CSOCK:
00287             return do_sock(do_csock, a, 0, &a->cur, timeout);
00288         default:
00289             dbg_return_ifm (1, -1, "unknown socket mode %d", a->mode);
00290     }
00291 }
00292 
00296 int u_net_sd_by_addr (u_net_addr_t *a)
00297 {
00298     return u_net_sd_by_addr_ex(a, NULL);
00299 }
00300 
00312 int u_net_sd_ex (const char *uri, u_net_mode_t mode, int opts, 
00313         struct timeval *timeout)
00314 {
00315     int s = -1;
00316     u_net_addr_t *a = NULL;
00317 
00318     /* 'mode' check is done by u_net_uri2addr() */
00319     dbg_return_if (uri == NULL, -1);
00320 
00321     /* decode address (u_net_addr_t validation is done later by 
00322      * u_net_sd_by_addr() */
00323     dbg_err_if (u_net_uri2addr(uri, mode, &a));
00324 
00325     /* add options if any */
00326     u_net_addr_set_opts(a, opts);
00327 
00328     /* do the real job */
00329     s = u_net_sd_by_addr_ex(a, timeout);
00330 
00331     /* dispose the (one-shot) address */
00332     u_net_addr_free(a);
00333 
00334     return s;
00335 err:
00336     if (s != -1)
00337         (void) close(s);
00338     if (a)
00339         u_net_addr_free(a);
00340 
00341     return -1;
00342 }
00343 
00347 int u_net_sd (const char *uri, u_net_mode_t mode, int opts)
00348 {
00349     return u_net_sd_ex(uri, mode, opts, NULL);
00350 }
00351  
00361 int u_net_addr_can_accept (u_net_addr_t *a)
00362 {
00363     dbg_return_if (a == NULL, 0);
00364     dbg_return_if (a->cur == NULL, 0);
00365 
00366     switch (a->cur->ai_socktype)
00367     {
00368         case SOCK_STREAM:
00369         case SOCK_SEQPACKET:
00370             return (a->mode == U_NET_SSOCK) ? 1 : 0;
00371         default:
00372             return 0;
00373     }
00374 }
00375 
00388 void u_net_addr_set_opts (u_net_addr_t *a, int opts)
00389 {
00390     dbg_return_if (a == NULL, );
00391     a->opts = opts;
00392     return;
00393 }
00394 
00408 void u_net_addr_add_opts (u_net_addr_t *a, int opts)
00409 {
00410     dbg_return_if (a == NULL, );
00411     a->opts |= opts;
00412     return;
00413 }
00414 
00425 void u_net_addr_free (u_net_addr_t *a)
00426 {
00427     dbg_return_if (a == NULL, );
00428 
00429     /* release the inner blob */
00430     ai_free(a->addr);
00431 
00432     /* release the wrapping container */
00433     u_free(a);
00434     return;
00435 }
00436 
00438 int u_accept (int sd, struct sockaddr *addr, u_socklen_t *addrlen)
00439 {
00440     int ad;
00441 
00442 again:
00443     if ((ad = accept(sd, addr, addrlen)) == -1 && (errno == EINTR))
00444         goto again; /* interrupted */
00445 
00446 #ifdef U_NET_TRACE
00447     u_dbg("accept(%d, %p, %d) = %d", sd, addr, addrlen, ad); 
00448 #endif
00449 
00450     /* in case of error log errno, otherwise fall through */
00451     dbg_err_sif (ad == -1);
00452 err:
00453     return ad;
00454 }
00455 
00457 int u_socket (int domain, int type, int protocol)
00458 {
00459     int s = socket(domain, type, protocol);
00460 
00461 #ifdef U_NET_TRACE
00462     u_dbg("socket(%d, %d, %d) = %d", domain, type, protocol, s); 
00463 #endif
00464 
00465     /* in case of error log errno, otherwise fall through */
00466     dbg_err_sif (s == -1);
00467 err:
00468     return s;
00469 }
00470 
00472 int u_connect (int sd, const struct sockaddr *addr, u_socklen_t addrlen)
00473 {
00474     return u_connect_ex(sd, addr, addrlen, NULL);
00475 }
00476 
00496 int u_connect_ex (int sd, const struct sockaddr *addr, u_socklen_t addrlen,
00497         struct timeval *timeout)
00498 {
00499     int rc;
00500     u_socklen_t rc_len = sizeof rc;
00501     struct timeval tstart, tcopy, *ptcopy = timeout ? &tcopy : NULL;
00502     fd_set writefds;
00503 
00504     dbg_return_if (sd < 0, -1);
00505     dbg_return_if (addr == NULL, -1);
00506     dbg_return_if (addrlen == 0, -1);
00507 
00508     if (timeout)
00509     {
00510         dbg_err_if (u_net_set_nonblocking(sd));
00511         dbg_err_sif (gettimeofday(&tstart, NULL) == -1);
00512     }
00513    
00514     /* Open Group Base Specifications:
00515      *  "If connect() is interrupted by a signal that is caught while blocked 
00516      *   waiting to establish a connection, connect() shall fail and set 
00517      *   connect() to [EINTR], but the connection request shall not be aborted, 
00518      *   and the connection shall be established asynchronously." 
00519      * That's why we can't just simply 'goto again' here when errno==EINTR,
00520      * instead a rather convoluted select() based machinery must be put in
00521      * place.  Anyway, since the timeout'ed version shares the same code layout
00522      * we can kill two birds with one stone... */
00523     nop_return_if ((rc = connect(sd, addr, addrlen)) == 0, 0);
00524     dbg_err_sif (errno != EINTR && errno != EINPROGRESS);
00525 
00526     /* "When the connection has been established asynchronously, select() and 
00527      *  poll() shall indicate that the file descriptor for the socket is ready 
00528      *  for writing." */
00529     FD_ZERO(&writefds);
00530     FD_SET(sd, &writefds);
00531 
00532     for (;;)
00533     {
00534         /* On Linux, select() also modifies timeout if the call is 
00535          * interrupted by a signal handler (i.e., the EINTR error return).
00536          * We have to take care of this non-POSIX Linux feature by making a 
00537          * copy of the original timeout value, so that, on EINTR, it can be 
00538          * correctly re-computed by update_timeout(). */
00539         if (timeout)
00540             tcopy = *timeout;
00541 
00542         /* Try repeatedly to select the socket descriptor for a write 
00543          * condition to happen. */
00544         if ((rc = select(sd + 1, NULL, &writefds, NULL, ptcopy)) > 0)
00545             break;
00546 
00547         /* Timeout: jump to err. */
00548         if (rc == 0)
00549         {
00550             errno = ETIMEDOUT;
00551             dbg_err("connection timeouted on socket %d", sd);
00552         }
00553 
00554         /* Unless interrupted by a cought signal (in which case select() is
00555          * re-entered), bail out. */
00556         dbg_err_sif (rc == -1 && errno != EINTR);
00557 
00558         /* When interrupted, recalculate timeout value. */
00559         if (timeout)
00560         {
00561             dbg_err_if (update_timeout(timeout, &tstart));
00562 
00563             /* Handle corner case. */
00564             if (timeout->tv_sec < 0)
00565             {
00566                 errno = ETIMEDOUT;
00567                 dbg_err("negative timeout on socket %d.", sd);
00568             }
00569         }
00570     }
00571 
00572     /* Ok, if we reached here we're almost done, just peek at SO_ERROR to
00573      * check if there is any pending error on the socket. */
00574     dbg_err_sif (u_getsockopt(sd, SOL_SOCKET, SO_ERROR, &rc, &rc_len) == -1);
00575     if (rc)
00576     {
00577         errno = rc;
00578         warn_err("error detected on socket %d: %s", sd, strerror(errno));
00579     }
00580 
00581     if (timeout)
00582         (void) u_net_unset_nonblocking(sd);
00583 
00584     return 0;
00585 err:
00586     if (timeout)
00587         (void) u_net_unset_nonblocking(sd);
00588 
00589     return (errno == ETIMEDOUT) ? -2 : -1;
00590 }
00591 
00593 int u_bind (int sd, const struct sockaddr *addr, u_socklen_t addrlen)
00594 {
00595     int rc = bind(sd, addr, addrlen);
00596 
00597 #ifdef U_NET_TRACE
00598     u_dbg("bind(%d, %p, %d) = %d", sd, addr, addrlen, rc); 
00599 #endif
00600 
00601     /* in case of error log errno, otherwise fall through */
00602     dbg_err_sif (rc == -1);
00603 err:
00604     return rc;
00605 }
00606 
00608 int u_listen (int sd, int backlog)
00609 {
00610     int rc = listen(sd, backlog);
00611 
00612 #ifdef U_NET_TRACE
00613     u_dbg("listen(%d, %d) = %d", sd, backlog, rc); 
00614 #endif
00615 
00616     /* in case of error log errno, otherwise fall through */
00617     dbg_err_sif (rc == -1);
00618 err:
00619     return rc;
00620 }
00621 
00623 int u_setsockopt (int sd, int lev, int name, const void *val, u_socklen_t len)
00624 {
00625 #ifdef HAVE_SETSOCKOPT
00626     int rc = setsockopt(sd, lev, name, val, len);
00627 
00628 #ifdef U_NET_TRACE
00629     u_dbg("setsockopt(%d, %d, %d, %p, %d) = %d", sd, lev, name, val, len, rc);
00630 #endif
00631 
00632     dbg_err_sif (rc == -1);
00633 err:
00634     return rc;
00635 #else
00636     u_unused_args(sd, lev, name, val, len);
00637     u_info("setsockopt not implemented on this platform");
00638     return -1;
00639 #endif  /* HAVE_SETSOCKOPT */
00640 }
00641 
00643 int u_getsockopt (int sd, int lev, int name, void *val, u_socklen_t *len)
00644 {
00645 #ifdef HAVE_GETSOCKOPT
00646     int rc = getsockopt(sd, lev, name, val, len);
00647 
00648 #ifdef U_NET_TRACE
00649     u_dbg("getsockopt(%d, %d, %d, %p, %p) = %d", sd, lev, name, val, len, rc);
00650 #endif
00651 
00652     dbg_err_sif (rc == -1);
00653 err:
00654     return rc;
00655 #else
00656     u_unused_args(sd, lev, name, val, len);
00657     u_info("getsockopt not implemented on this platform");
00658     return -1;
00659 #endif  /* HAVE_GETSOCKOPT */
00660 }
00661 
00670 int u_net_set_nonblocking (int s)
00671 {
00672 #ifdef HAVE_FCNTL
00673     int flags;
00674 
00675     dbg_err_sif ((flags = fcntl(s, F_GETFL, 0)) == -1);
00676     flags |= O_NONBLOCK;
00677     dbg_err_sif (fcntl(s, F_SETFL, flags) == -1);
00678 #else   /* !HAVE_FCNTL */
00679     warn_err("missing fcntl(2): can't set socket %d as non blocking", s);
00680 #endif  /* HAVE_FCNTL */
00681 
00682     return 0;
00683 err:
00684     return ~0;
00685 }
00686  int u_net_unset_nonblocking (int s)
00695 {
00696 #ifdef HAVE_FCNTL
00697     int flags;
00698 
00699     dbg_err_sif ((flags = fcntl(s, F_GETFL, 0)) == -1);
00700     flags &= ~O_NONBLOCK;
00701     dbg_err_sif (fcntl(s, F_SETFL, flags) == -1);
00702 #else   /* !HAVE_FCNTL */
00703     warn_err("missing fcntl(2): can't reset non-blocking bit on socket %d", s);
00704 #endif  /* HAVE_FCNTL */
00705 
00706     return 0;
00707 err:
00708     return ~0;
00709 }
00710 
00719 int u_net_nagle_off (int s)
00720 {
00721 #if defined(HAVE_TCP_NODELAY) && !defined(__minix)
00722     int y = 1;
00723 
00724     dbg_return_if (s < 0, ~0);
00725 
00726     dbg_err_if (u_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &y, sizeof y) == -1);
00727 
00728     return 0;
00729 err:
00730     return ~0;
00731 #else   /* !HAVE_TCP_NODELAY || __minix */
00732     u_unused_args(s);
00733     u_dbg("TCP_NODELAY not supported on this platform");
00734     return 0;
00735 #endif  /* HAVE_TCP_NODELAY && !__minix */
00736 }
00737 
00739 const char *u_inet_ntop (int af, const void *src, char *dst, u_socklen_t len)
00740 {
00741     const unsigned char *p = (const unsigned char *) src;
00742 
00743     if (af == AF_INET)
00744     {
00745         char s[U_INET_ADDRSTRLEN];
00746 
00747         dbg_if (u_snprintf(s, sizeof s, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]));
00748 
00749         if (u_strlcpy(dst, s, len))
00750         {
00751             errno = ENOSPC;
00752             return NULL; 
00753         }
00754         
00755         return dst;
00756     }
00757 #ifndef NO_IPV6
00758     if (af == AF_INET6)
00759         return inet_ntop(af, src, dst, len);
00760 #endif  /* !NO_IPV6 */
00761 
00762     errno = EAFNOSUPPORT;
00763     return NULL;
00764 }
00765 
00767 const char *u_sa_ntop (const struct sockaddr *sa, char *d, size_t dlen)
00768 {
00769     char a[256];    /* should be big enough for UNIX sock pathnames */
00770 
00771     dbg_err_if (sa == NULL);
00772     dbg_err_if (d == NULL);
00773     dbg_err_if (dlen == 0);
00774 
00775     switch (sa->sa_family)
00776     {
00777         case AF_INET: 
00778         {
00779             const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
00780             dbg_err_if (!u_inet_ntop(AF_INET, &s4->sin_addr, a, sizeof a));
00781             dbg_if (u_snprintf(d, dlen, "%s:%d", a, ntohs(s4->sin_port)));
00782             break;
00783         }
00784 #ifndef NO_IPV6
00785         case AF_INET6: 
00786         {
00787             const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
00788             dbg_err_if (!u_inet_ntop(AF_INET6, &s6->sin6_addr, a, sizeof a));
00789             dbg_if (u_snprintf(d, dlen, "[%s]:%d", a, ntohs(s6->sin6_port)));
00790             break;
00791         }
00792 #endif  /* !NO_IPV6 */
00793 #ifndef NO_UNIXSOCK
00794         case AF_UNIX:
00795         {
00796             const struct sockaddr_un *su = (const struct sockaddr_un *) sa;
00797             dbg_if (u_strlcpy(d, su->sun_path, dlen));
00798             break;
00799         }
00800 #endif  /* !NO_UNIXSOCK */
00801         default:
00802             dbg_err("unhandled socket type");
00803     }
00804 
00805     return d;
00806 err:
00807     return "(sockaddr conversion failed)";
00808 }
00809 
00814 /* - 'wf' is one of do_ssock() or do_csock() 
00815  * - if 'psa' is not NULL it will receive the connected/bound sockaddr back */
00816 static int do_sock (
00817         int wf (struct sockaddr *, u_socklen_t, int, int, int, int, int,
00818             struct timeval *), 
00819         struct u_net_addr_s *a, int backlog, u_addrinfo_t **pai,
00820         struct timeval *timeout)
00821 {
00822     int sock_type, sd = -1;
00823     u_addrinfo_t *ap;
00824     char h[1024];
00825 
00826     dbg_return_if ((ap = a->addr) == NULL, ~0);
00827 
00828     for ( ; ap != NULL; ap = ap->ai_next)
00829     {
00830 #ifndef NO_SCTP
00831         /* override .ai_socktype for SCTP one-to-many sockets with 
00832          * SOCK_SEQPACKET.  the default is SOCK_STREAM, see scheme_mapper() 
00833          * in sctp[46] branches */ 
00834         sock_type = (ap->ai_protocol == IPPROTO_SCTP && 
00835                 (a->opts & U_NET_OPT_SCTP_ONE_TO_MANY)) ? 
00836             SOCK_SEQPACKET : ap->ai_socktype;
00837 #else
00838         sock_type = ap->ai_socktype;
00839 #endif  /* !NO_SCTP */
00840 
00841         if ((sd = wf(ap->ai_addr, ap->ai_addrlen, ap->ai_family, sock_type, 
00842                     ap->ai_protocol, a->opts, backlog, timeout)) >= 0)
00843         {
00844             /* TODO call getsockname to catch the real connected/bound address 
00845              * to feed 'pai' */
00846 
00847             u_info("%s %s", (wf == do_ssock) ? "bind succeeded for" 
00848                     : "connect succeeded to", (ap->ai_family == AF_UNIX) 
00849                     ? ap->ai_canonname : u_sa_ntop(ap->ai_addr, h, sizeof h));
00850 
00851             /* if caller has supplied a valid 'pai', copy out the pointer 
00852              * to the addrinfo that has fullfilled the connection request */
00853             if (pai)
00854                 *pai = ap;
00855 
00856             break;
00857         }
00858     }
00859 
00860     if (sd == -1)
00861     {
00862         u_addrinfo_t *wai = a->addr;
00863 
00864         u_info("could not %s %s", (wf == do_ssock) ? "bind" : "connect to", 
00865                 (wai->ai_family == AF_UNIX) ? wai->ai_canonname 
00866                 : u_sa_ntop(wai->ai_addr, h, sizeof h));
00867     }
00868 
00869     return sd;
00870 }
00871 
00872 static int do_csock (struct sockaddr *sad, u_socklen_t sad_len, int domain, 
00873         int type, int protocol, int opts, int dummy, struct timeval *timeout)
00874 {
00875     int s = -1;
00876 #ifdef HAVE_SO_BROADCAST
00877     int bc = 1;
00878 #endif  /* HAVE_SO_BROADCAST */
00879 
00880     u_unused_args(dummy);
00881 
00882     dbg_return_if (sad == NULL, -1);
00883 
00884     dbg_err_sif ((s = u_socket(domain, type, protocol)) == -1);
00885 
00886     if ((type == SOCK_DGRAM) && (opts & U_NET_OPT_DGRAM_BROADCAST))
00887     {
00888 #ifdef HAVE_SO_BROADCAST
00889         dbg_err_sif (u_setsockopt(s, SOL_SOCKET, SO_BROADCAST, 
00890                     &bc, sizeof bc) == -1);
00891 #else
00892         u_warn("SO_BROADCAST is not defined on this platform");
00893 #endif  /* HAVE_SO_BROADCAST */
00894     }
00895 
00896 #ifndef NO_SCTP
00897     if (opts & U_NET_OPT_SCTP_ONE_TO_MANY)
00898         dbg_err_sif (sctp_enable_events(s, opts));
00899 #endif  /* NO_SCTP */
00900 
00901     /* NOTE that by default UDP and SCTP sockets (not only TCP and UNIX) are 
00902      * connected.  For UDP this has a couple of important implications:
00903      * 1) the caller must use u{,_net}_write for I/O instead of sendto 
00904      * 2) async errors are returned to the process. */
00905     if (!(opts & U_NET_OPT_DONT_CONNECT))
00906         dbg_err_sif (u_connect_ex(s, sad, sad_len, timeout) < 0);
00907 
00908     return s;
00909 err:
00910     U_CLOSE(s);
00911     return -1;
00912 }
00913 
00914 static int do_ssock (struct sockaddr *sad, u_socklen_t sad_len, int domain, 
00915         int type, int protocol, int opts, int backlog, struct timeval *dummy)
00916 {
00917     int s = -1;
00918 
00919     dbg_return_if (sad == NULL, -1);
00920     u_unused_args(dummy);
00921 
00922     dbg_err_sif ((s = u_socket(domain, type, protocol)) == -1);
00923     
00924     /* 
00925      * by default address reuse is in place for all server sockets except 
00926      * AF_UNIX, unless the caller has set the U_NET_OPT_DONT_REUSE_ADDR option 
00927      */ 
00928     if (domain != AF_UNIX && !(opts & U_NET_OPT_DONT_REUSE_ADDR))
00929         dbg_err_if (bind_reuse_addr(s));
00930 
00931 #ifndef NO_SCTP
00932     if (opts & U_NET_OPT_SCTP_ONE_TO_MANY)
00933         dbg_err_sif (sctp_enable_events(s, opts));
00934 #endif
00935 
00936     dbg_err_sif (u_bind(s, (struct sockaddr *) sad, sad_len) == -1);
00937 
00938     /* only stream and seqpacket sockets enter the LISTEN state */
00939     if (type == SOCK_STREAM || type == SOCK_SEQPACKET)
00940         dbg_err_sif (u_listen(s, backlog) == -1);
00941 
00942     return s;
00943 err:
00944     U_CLOSE(s);
00945     return -1;
00946 }
00947 
00948 /* change the rules used in validating addresses supplied in a bind(2) call 
00949  * so that reuse of local addresses is allowed */
00950 static int bind_reuse_addr (int s)
00951 {
00952     int y = 1;
00953 
00954     dbg_return_if (s < 0, -1);
00955 
00956     dbg_err_if (u_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &y, sizeof y) == -1);
00957 
00958     return 0;
00959 err:
00960     return ~0;
00961 }
00962 
00963 #ifndef NO_SCTP
00964 /* change server/client notification settings for one-to-many SCTP sockets */
00965 static int sctp_enable_events (int s, int o)
00966 {
00967     struct sctp_event_subscribe e;
00968 
00969     e.sctp_data_io_event = 
00970         (o & U_NET_OPT_SCTP_DATA_IO_EVENT) ? 1 : 0;
00971 
00972     e.sctp_association_event = 
00973         (o & U_NET_OPT_SCTP_ASSOCIATION_EVENT) ? 1 : 0;
00974 
00975     e.sctp_address_event = 
00976         (o & U_NET_OPT_SCTP_ADDRESS_EVENT) ? 1 : 0;
00977 
00978     e.sctp_send_failure_event = 
00979         (o & U_NET_OPT_SCTP_SEND_FAILURE_EVENT) ? 1 : 0;
00980 
00981     e.sctp_peer_error_event = 
00982         (o & U_NET_OPT_SCTP_PEER_ERROR_EVENT) ? 1 : 0;
00983     
00984     e.sctp_shutdown_event = 
00985         (o & U_NET_OPT_SCTP_SHUTDOWN_EVENT) ? 1 : 0;
00986     
00987     e.sctp_partial_delivery_event = 
00988         (o & U_NET_OPT_SCTP_PARTIAL_DELIVERY_EVENT) ? 1 : 0;
00989     
00990     e.sctp_adaptation_layer_event = 
00991         (o & U_NET_OPT_SCTP_ADAPTATION_LAYER_EVENT) ? 1 : 0;
00992     
00993     e.sctp_authentication_event = 
00994         (o & U_NET_OPT_SCTP_AUTHENTICATION_EVENT) ? 1 : 0;
00995 
00996     dbg_err_if (u_setsockopt(s, IPPROTO_SCTP, SCTP_EVENTS, &e, sizeof e) == -1);
00997 
00998     return 0;
00999 err:
01000     return ~0;
01001 }
01002 #endif  /* !NO_SCTP */
01003 
01004 static int scheme_mapper (const char *scheme, u_net_scheme_map_t *map)
01005 {
01006     dbg_return_if (scheme == NULL, ~0);
01007     dbg_return_if (map == NULL, ~0);
01008 
01009     if (!strcasecmp(scheme, "tcp4") || !strcasecmp(scheme, "tcp"))
01010     {
01011         map->addr_family = AF_INET;
01012         map->sock_type = SOCK_STREAM;
01013         map->proto  = IPPROTO_TCP;
01014     }
01015     else if (!strcasecmp(scheme, "udp4") || !strcasecmp(scheme, "udp"))
01016     {
01017         map->addr_family = AF_INET;
01018         map->sock_type = SOCK_DGRAM;
01019         map->proto  = IPPROTO_UDP;
01020     }
01021 #ifndef NO_SCTP
01022     else if (!strcasecmp(scheme, "sctp4") || !strcasecmp(scheme, "sctp"))
01023     {
01024         map->addr_family = AF_INET;
01025         /* default to STREAM, will be set to SEQPACKET in case 
01026          * U_NET_OPT_SCTP_ONE_TO_MANY is set */
01027         map->sock_type = SOCK_STREAM;
01028         map->proto  = IPPROTO_SCTP;
01029     }
01030 #endif  /* !NO_SCTP */
01031 #ifndef NO_UNIXSOCK
01032     else if (!strcasecmp(scheme, "unix"))
01033     {
01034         map->addr_family = AF_UNIX;
01035         map->sock_type = SOCK_STREAM;   /* default to STREAM sockets */
01036         map->proto  = 0;
01037     }
01038 #endif  /* !NO_UNIXSOCK */
01039 #ifndef NO_IPV6
01040     else if (!strcasecmp(scheme, "tcp6"))
01041     {
01042         map->addr_family = AF_INET6;
01043         map->sock_type = SOCK_STREAM;
01044         map->proto  = IPPROTO_TCP;
01045     }
01046     else if (!strcasecmp(scheme, "udp6"))
01047     {
01048         map->addr_family = AF_INET6;
01049         map->sock_type = SOCK_DGRAM;
01050         map->proto  = IPPROTO_UDP;
01051     }
01052 #ifndef NO_SCTP
01053     else if (!strcasecmp(scheme, "sctp6"))
01054     {
01055         map->addr_family = AF_INET6;
01056         /* default to STREAM, will be set to SEQPACKET in case 
01057          * U_NET_OPT_SCTP_ONE_TO_MANY is set */
01058         map->sock_type = SOCK_STREAM;
01059         map->proto  = IPPROTO_SCTP;
01060     }
01061 #endif  /* !NO_SCTP */
01062 #endif  /* !NO_IPV6 */
01063     else
01064         return ~0;
01065 
01066     return 0;
01067 }
01068 
01069 /* just malloc enough room for the address container and zero-out everything
01070  * but the 'mode' attribute */
01071 static int na_new (u_net_mode_t mode, u_net_addr_t **pa)
01072 {
01073     u_net_addr_t *a = NULL;
01074 
01075     dbg_return_if (pa == NULL, ~0);
01076     dbg_return_if (!U_NET_IS_MODE(mode), ~0);
01077 
01078     dbg_err_sif ((a = u_zalloc(sizeof(u_net_addr_t))) == NULL);
01079 
01080     a->mode = mode;
01081     a->opts = 0;
01082     a->addr = NULL;
01083     a->cur = NULL;
01084 
01085     *pa = a;
01086 
01087     return 0;
01088 err:
01089     if (a) 
01090         u_net_addr_free(a);
01091     return ~0;
01092 }
01093 
01094 /* basically an ai_resolv() wrapper using u_net objects */
01095 static int uri2addr (u_uri_t *u, u_net_scheme_map_t *m, u_net_addr_t *a)
01096 {
01097     dbg_return_if (u == NULL, ~0);
01098     dbg_return_if (m == NULL, ~0);
01099     dbg_return_if (a == NULL, ~0);
01100 
01101     return ai_resolv(u_uri_get_host(u), u_uri_get_port(u), u_uri_get_path(u), 
01102             m->addr_family, m->sock_type, m->proto, 
01103             (a->mode == U_NET_SSOCK) ? 1 : 0, &a->addr);
01104 }
01105 
01106 /* 'rf' is one of: resolv_sin, resolv_sun or resolv_sin6 */ 
01107 static int do_resolv (
01108         int rf (const char *, const char *, const char *, u_addrinfo_t *ai), 
01109         const char *host, const char *port, const char *path, int family, 
01110         int type, int proto, u_addrinfo_t **pai)
01111 {
01112     u_addrinfo_t *ai = NULL;
01113 
01114     /* 'port' can be NULL when family == AF_UNIX */
01115     dbg_return_if (rf == NULL, ~0);
01116     dbg_return_if (pai == NULL, ~0);
01117 
01118     dbg_err_sif ((ai = u_zalloc(sizeof *ai)) == NULL);
01119 
01120     /* set header flags */
01121     ai->ai_flags = 0;           /* unused */
01122     ai->ai_family = family;
01123     ai->ai_socktype = type;
01124     ai->ai_protocol = proto;
01125 
01126     /* call the resolver (they can possibly change some attribute setting) */
01127     dbg_err_if (rf(host, port, path, ai));
01128 
01129     *pai = ai;
01130 
01131     return 0;
01132 err:
01133     if (ai)
01134         ai_free(ai);
01135     return ~0;
01136 }
01137 
01138 #ifndef NO_UNIXSOCK
01139 static int resolv_sun (const char *dummy1, const char *dummy2, 
01140         const char *path, u_addrinfo_t *ai)
01141 {
01142     char *cname = NULL;
01143     /* This variable used to be called 'sun'.  Unfortunately, we can't call
01144      * it like this on OpenSolaris, because their C preprocessor sets the 
01145      * symbol 'sun' to the numeric constant '1' :) */
01146     struct sockaddr_un *sunix = NULL;
01147 
01148     u_unused_args(dummy1, dummy2);
01149 
01150     dbg_return_if (path == NULL, ~0);
01151     dbg_return_if (ai == NULL, ~0);
01152 
01153     dbg_err_sif ((sunix = u_zalloc(sizeof *sunix)) == NULL);
01154 
01155     sunix->sun_family = AF_UNIX;
01156     dbg_err_ifm (u_strlcpy(sunix->sun_path, path, sizeof sunix->sun_path), 
01157             "%s too long", path);
01158 
01159     ai->ai_protocol = 0;    /* override previous setting if any */
01160     ai->ai_addr = (struct sockaddr *) sunix;
01161     ai->ai_addrlen = sizeof *sunix;
01162     ai->ai_next = NULL;
01163 
01164     /* set cname to what was provided as 'path' by the caller */
01165     dbg_err_sif ((cname = u_strdup(path)) == NULL);
01166     ai->ai_canonname = cname;
01167 
01168     return 0;
01169 err:
01170     U_FREE(sunix);
01171     U_FREE(cname);
01172     return ~0;
01173 }
01174 #endif  /* !NO_UNIXSOCK */
01175 
01176 static void ai_free (u_addrinfo_t *ai)
01177 {
01178     nop_return_if (ai == NULL, );
01179 
01180 #ifdef HAVE_GETADDRINFO
01181     if (ai->ai_family == AF_UNIX)
01182     {
01183 #endif
01184         /* UNIX addresses have been created "manually", i.e. not by means 
01185          * of getaddrinfo()  */
01186         U_FREE(ai->ai_addr);
01187         U_FREE(ai->ai_canonname);
01188         u_free(ai);
01189 #ifdef HAVE_GETADDRINFO
01190     }
01191     else
01192         freeaddrinfo(ai); 
01193 #endif
01194 
01195     return;
01196 }
01197 
01198 #ifdef HAVE_GETADDRINFO
01199 static int ai_resolv (const char *host, const char *port, const char *path,
01200         int family, int type, int proto, int passive, u_addrinfo_t **pai)
01201 {
01202     int e;
01203     const char *hostname, *servname;
01204     struct addrinfo hints, *ai = NULL;
01205 
01206     /* 'host', 'port' and 'path' check depend on 'family' */
01207     dbg_return_if (pai == NULL, ~0);
01208 
01209     /* early intercept UNIX sock creation requests and dispatch it straight 
01210      * to resolv_sun() */
01211     if (family == AF_UNIX)
01212     {
01213         return do_resolv(resolv_sun, NULL, NULL, path, family, type, 
01214                 proto, pai);
01215     }
01216 
01217     dbg_return_if (host == NULL, ~0);
01218     dbg_return_if (port == NULL, ~0);
01219 
01220     /* 
01221      * Handle '*' for both host and port.
01222      */
01223     hostname = !strcmp(host, "*") ? NULL : host;
01224     servname = !strcmp(port, "*") ? NULL : port;
01225 
01226     memset(&hints, 0, sizeof hints);
01227 
01228     hints.ai_flags = passive ? AI_PASSIVE : 0;
01229     hints.ai_flags |= hostname ? AI_CANONNAME : 0;
01230 
01231     hints.ai_family = family;
01232     hints.ai_socktype = type;
01233     hints.ai_protocol = proto;
01234 
01235     switch ((e = getaddrinfo(hostname, servname, &hints, &ai)))
01236     {
01237         case 0:             /* ok */
01238             break;
01239         case EAI_SYSTEM:    /* system error returned in errno */
01240             dbg_err_sifm (1, "getaddrinfo failed");
01241         default:            /* gai specific error */
01242             dbg_err_ifm (1, "getaddrinfo failed: %s", gai_strerror(e));
01243     }
01244 
01245     *pai = ai;
01246 
01247     return 0;
01248 err:
01249     if (ai)
01250         ai_free(ai);
01251     return ~0;
01252 }
01253 
01254 #else   /* !HAVE_GETADDRINFO */
01255 
01256 static int ai_resolv (const char *host, const char *port, const char *path, 
01257         int family, int type, int proto, int passive, u_addrinfo_t **pai)
01258 {
01259     u_unused_args(passive);
01260 
01261     /* dispatch is based on address family type */
01262     switch (family)
01263     {
01264         case AF_INET:
01265             return do_resolv(resolv_sin, host, port, NULL, family, type, 
01266                     proto, pai);
01267 #ifndef NO_UNIXSOCK
01268         case AF_UNIX:
01269             return do_resolv(resolv_sun, NULL, NULL, path, family, type,
01270                     proto, pai);
01271 #endif  /* !NO_UNIXSOCK */
01272 #ifndef NO_IPV6
01273         case AF_INET6:
01274             return do_resolv(resolv_sin6, host, port, NULL, family, type, 
01275                     proto, pai);
01276 #endif  /* !NO_IPV6 */
01277         default:
01278             dbg_return_ifm (1, ~0, "address family not supported");
01279     }
01280 }
01281 
01282 static int resolv_sin (const char *host, const char *port, 
01283         const char *dummy, u_addrinfo_t *ai)
01284 {
01285     in_addr_t saddr;
01286     char *cname = NULL;
01287     struct hostent *hp = NULL;
01288     struct sockaddr_in *sin = NULL;
01289 
01290     u_unused_args(dummy);
01291 
01292     dbg_return_if (ai == NULL, ~0);
01293     dbg_return_if (host == NULL, ~0);
01294     dbg_return_if (port == NULL, ~0);
01295 
01296     dbg_err_sif ((sin = u_zalloc(sizeof *sin)) == NULL);
01297 
01298     sin->sin_family = AF_INET;
01299     dbg_err_if (resolv_port(port, &sin->sin_port));
01300 
01301     /* '*' is the wildcard address */
01302     if (!strcmp(host, "*"))
01303         sin->sin_addr.s_addr = htonl(INADDR_ANY);
01304     else
01305     {
01306         if (strspn(host, "0123456789.") != strlen(host)) /* !ipv4 dotted */
01307         {
01308             dbg_err_ifm ((hp = gethostbyname(host)) == NULL, 
01309                     "%s: %d", host, h_errno);
01310             dbg_err_if (hp->h_addrtype != AF_INET);
01311             memcpy(&sin->sin_addr.s_addr, hp->h_addr, sizeof(in_addr_t));
01312         }
01313         else if ((saddr = inet_addr(host)) != INADDR_NONE)
01314             sin->sin_addr.s_addr = saddr;
01315         else
01316             dbg_err("invalid host name: \'%s\'", host);
01317     }
01318 
01319     ai->ai_addr = (struct sockaddr *) sin;
01320     ai->ai_addrlen = sizeof *sin;
01321     ai->ai_next = NULL;
01322 
01323     /* set cname to what was provided as 'host' by the caller */
01324     dbg_err_sif ((cname = u_strdup(host)) == NULL);
01325     ai->ai_canonname = cname;
01326 
01327     return 0;
01328 err:
01329     U_FREE(sin);
01330     U_FREE(cname);
01331     return ~0;
01332 }
01333 
01334 #ifndef NO_IPV6
01335 static int resolv_sin6 (const char *host, const char *port, 
01336         const char *dummy, u_addrinfo_t *ai)
01337 {
01338     char *cname = NULL;
01339     struct hostent *hp = NULL;
01340     struct sockaddr_in6 *sin6 = NULL;
01341 
01342     u_unused_args(dummy);
01343 
01344     dbg_return_if (ai == NULL, ~0);
01345     dbg_return_if (host == NULL, ~0);
01346     dbg_return_if (port == NULL, ~0);
01347 
01348     dbg_err_sif ((sin6 = u_zalloc(sizeof *sin6)) == NULL);
01349 
01350 #ifdef SIN6_LEN
01351     /* the SIN6_LEN constant must be defined if the system supports the
01352      * length member for IPv6 socket address structure */
01353     sin6->sin6_len = sizeof *sin6;
01354 #endif
01355     sin6->sin6_family = AF_INET6;
01356     dbg_err_if (resolv_port(port, &sin6->sin6_port));
01357     sin6->sin6_flowinfo = 0;
01358 
01359     /* '*' is the wildcard address */
01360     if (!strcmp(host, "*"))
01361         sin6->sin6_addr = in6addr_any;
01362     else
01363     {
01364         /* try DNS for an AAAA record of 'host' */
01365         if (!strchr(host, ':'))
01366         {
01367             /* XXX gethostbyname2(3) is deprecated by POSIX, anyway if we 
01368              * XXX reached here is because our platform is not that POSIX, 
01369              * XXX i.e. IPv6 is implemented but addrinfo is not available. */
01370             dbg_err_ifm ((hp = gethostbyname2(host, AF_INET6)) == NULL, 
01371                     "%s: %d", host, h_errno);
01372             dbg_err_if (hp->h_addrtype != AF_INET6);
01373             dbg_err_if (hp->h_length != sizeof(struct in6_addr));
01374             memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length);
01375         }
01376         else /* convert numeric address */
01377         {
01378             switch (inet_pton(AF_INET6, host, &sin6->sin6_addr))
01379             {
01380                 case -1:
01381                     dbg_strerror(errno); 
01382                     /* log errno and fall through */
01383                 case 0:
01384                     dbg_err("invalid IPv6 host name: \'%s\'", host);
01385                     /* log hostname and jump to err: */
01386                 default:
01387                     break;
01388             }
01389         }
01390     }
01391 
01392     ai->ai_addr = (struct sockaddr *) sin6;
01393     ai->ai_addrlen = sizeof *sin6;
01394     ai->ai_next = NULL;
01395 
01396     /* set cname to what was provided as 'host' by the caller */
01397     dbg_err_sif ((cname = u_strdup(host)) == NULL);
01398     ai->ai_canonname = cname;
01399 
01400     return 0;
01401 err:
01402     U_FREE(sin6);
01403     U_FREE(cname);
01404     return ~0;
01405 }
01406 #endif  /* !NO_IPV6 */
01407 
01408 /* given a port string (both numeric and service), return a port in network 
01409  * format ready to be used in struct sockaddr_in{,6} */
01410 static int resolv_port (const char *s_port, uint16_t *pin_port)
01411 {
01412     int i_port;
01413     struct servent *se;
01414 
01415     dbg_return_if (s_port == NULL, ~0);
01416     dbg_return_if (pin_port == NULL, ~0);
01417 
01418     /* handle wildcard as ephemeral */
01419     if (!strcmp(s_port, "*"))
01420     {
01421         *pin_port = (uint16_t) 0; 
01422     }
01423     else if (strspn(s_port, "0123456789") == strlen(s_port)) /* numeric */
01424     {
01425         dbg_err_if (u_atoi(s_port, &i_port));
01426         dbg_err_ifm (i_port < 0 || i_port > 65535, "%s out of range", s_port);
01427         *pin_port = htons((uint16_t) i_port);
01428     }
01429     else    /* service name (don't mind about protocol) */
01430     {
01431         dbg_err_if ((se = getservbyname(s_port, NULL)) == NULL);
01432         *pin_port = (uint16_t) se->s_port;
01433     }
01434 
01435     return 0;
01436 err:
01437     return ~0;
01438 }
01439 #endif  /* HAVE_GETADDRINFO */
01440 
01441 static inline int update_timeout (struct timeval *timeout, 
01442         struct timeval *tstart)
01443 {
01444     struct timeval now, telapsed;
01445 
01446     dbg_return_if (timeout == NULL, ~0);
01447     dbg_return_if (tstart == NULL, ~0);
01448 
01449     dbg_err_sif (gettimeofday(&now, NULL) == -1);
01450 
01451     /* Time elapsed since last interrupt or first call to select(). */
01452     u_timersub(&now, tstart, &telapsed);
01453 
01454     /* Update timeout value by subtracting the elapsed interval. */
01455     u_timersub(timeout, &telapsed, timeout);
01456 
01457     /* Assign new tstart value. */
01458     *tstart = now;
01459 
01460     return 0;
01461 err:
01462     return ~0;
01463 }

←Products
© 2005-2012 - KoanLogic S.r.l. - All rights reserved