Back to index

courier  0.68.2
mksocket.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2004-2009 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #include      "mksocket.h"
00007 
00008 #if HAVE_UNISTD_H
00009 #include      <unistd.h>
00010 #endif
00011 #if HAVE_FCNTL_H
00012 #include      <fcntl.h>
00013 #endif
00014 #include      <stdio.h>
00015 #include      <errno.h>
00016 #include      <string.h>
00017 #include      <stdlib.h>
00018 #include      "soxwrap.h"
00019 
00020 
00021 #define MKS_USEAFINET4 1
00022 #define MKS_ERROK 2
00023 
00024 #if    HAVE_SOXWRAP_IPV6
00025 typedef struct in6_addr     NET_ADDR;
00026 typedef struct sockaddr_in6 NET_SOCKADDR;
00027 typedef struct sockaddr_storage NET_NETADDR;
00028 #define NET_ADDRANY         in6addr_any
00029 #else
00030 typedef       struct in_addr       NET_ADDR;
00031 typedef struct sockaddr_in  NET_SOCKADDR;
00032 typedef struct sockaddr            NET_NETADDR;
00033 
00034 extern struct in_addr rfc1035_addr_any;
00035 #define NET_ADDRANY         rfc1035_addr_any
00036 #endif
00037 
00038 struct recycle_info {
00039        const struct sockaddr *sin;
00040        socklen_t sin_len;
00041        int found_socket;
00042 };
00043 
00044 /*
00045 ** If caller already has a socket listening on this address, recycle it.
00046 */
00047 
00048 static int try_recycle_socket(int fd, void *voidarg)
00049 {
00050        struct recycle_info *ri=(struct recycle_info *)voidarg;
00051 
00052        union {
00053               SOCKADDR_STORAGE ss;
00054               struct sockaddr_in sin;
00055 #if    HAVE_SOXWRAP_IPV6
00056               struct sockaddr_in6 sin6;
00057 #endif
00058        } sa;
00059 
00060        socklen_t salen=sizeof(sa);
00061 
00062        if (getsockname(fd, (struct sockaddr *)&sa, &salen) < 0)
00063               return 0;
00064 
00065        if (ri->sin->sa_family != sa.ss.SS_family)
00066               return 0;
00067 
00068        switch (ri->sin->sa_family) {
00069        case AF_INET:
00070               {
00071                      struct sockaddr_in ri_sin;
00072 
00073                      memcpy(&ri_sin, ri->sin, sizeof(ri_sin));
00074 
00075                      if (ri_sin.sin_addr.s_addr != sa.sin.sin_addr.s_addr
00076                          || ri_sin.sin_port != sa.sin.sin_port)
00077                             return 0;
00078               }
00079               break;
00080 
00081 #if    HAVE_SOXWRAP_IPV6
00082        case AF_INET6:
00083               {
00084                      struct sockaddr_in6 ri_sin;
00085 
00086                      memcpy(&ri_sin, ri->sin, sizeof(ri_sin));
00087 
00088                      if (memcmp(&ri_sin.sin6_addr, &sa.sin6.sin6_addr,
00089                                sizeof(sa.sin6.sin6_addr)) ||
00090                          ri_sin.sin6_port != sa.sin6.sin6_port)
00091                             return 0;
00092               }
00093               break;
00094 #endif
00095        default:
00096               return 0;
00097        }
00098        ri->found_socket=fd;
00099        return 1;
00100 }
00101 
00102 static int mksocket2(const char *ipaddrarg,      /* Host/IP address */
00103                    const char *servname,  /* Service/port */
00104                    int socktype,   /* SOCKS_STREAM */
00105                    int flags,
00106                    int (*recycle_fd_func)
00107                    ( int(*)(int, void *), void *, void *),
00108                    void *voidarg)
00109 {
00110        struct servent *servptr;
00111        int    port;
00112        int    fd;
00113        struct recycle_info ri;
00114        const struct sockaddr *sinaddr;
00115        int    sinaddrlen;
00116 
00117 #if    HAVE_SOXWRAP_IPV6
00118        struct sockaddr_in6  sin6;
00119 #endif
00120 
00121        struct sockaddr_in   sin4;
00122 
00123        int    af;
00124 
00125        servptr=getservbyname(servname, "tcp");
00126        if (servptr)
00127               port=servptr->s_port;
00128        else
00129        {
00130               port=atoi(servname);
00131               if (port <= 0 || port > 65535)
00132               {
00133                      fprintf(stderr, "Invalid port: %s\n", servname);
00134                      return (-1);
00135               }
00136               port=htons(port);
00137        }
00138 
00139        /* Create an IPv6 or an IPv4 socket */
00140 
00141 #if    HAVE_SOXWRAP_IPV6
00142        if (flags & MKS_USEAFINET4)
00143        {
00144               fd=sox_socket(PF_INET, socktype, 0);
00145               af=AF_INET;
00146        }
00147        else
00148 #endif
00149        {
00150 #if    HAVE_SOXWRAP_IPV6
00151 
00152               if ((fd=sox_socket(PF_INET6, socktype, 0)) >= 0)
00153                      af=AF_INET6;
00154               else
00155 #endif
00156               {
00157                      af=AF_INET;
00158                      fd=sox_socket(PF_INET, socktype, 0);
00159               }
00160        }
00161 
00162        if (fd < 0)
00163               return (-1);
00164 
00165        /* Figure out what to bind based on what socket we created */
00166 
00167        if (ipaddrarg && strcmp(ipaddrarg, "0"))
00168        {
00169 
00170 #if    HAVE_SOXWRAP_IPV6
00171               if (af == AF_INET6)
00172               {
00173                      memset(&sin6, 0, sizeof(sin6));
00174                      sin6.sin6_family=af;
00175                      if (inet_pton(af, ipaddrarg, &sin6.sin6_addr) <= 0)
00176                      {
00177                             errno=EINVAL;
00178                             close(fd);
00179                             return -1;
00180                      }
00181                      sin6.sin6_port=port;
00182 
00183                      sinaddr=(const struct sockaddr *)&sin6;
00184                      sinaddrlen=sizeof(sin6);
00185               }
00186               else
00187 #endif
00188                      if (af == AF_INET)
00189                      {
00190                             memset(&sin4, 0, sizeof(sin4));
00191                             sin4.sin_family=AF_INET;
00192                             if (inet_aton(ipaddrarg, &sin4.sin_addr) == 0)
00193                             {
00194                                    errno=EINVAL;
00195                                    close(fd);
00196                                    return -1;
00197                             }
00198                             sin4.sin_port=port;
00199                             sinaddr=(const struct sockaddr *)&sin4;
00200                             sinaddrlen=sizeof(sin4);
00201                      }
00202                      else
00203                      {
00204                             errno=EAFNOSUPPORT;
00205                             close(fd);
00206                             return (-1);
00207                      }
00208        }
00209        else   /* Bind default address */
00210        {
00211 #if    HAVE_SOXWRAP_IPV6
00212               if (af == AF_INET6)
00213               {
00214                      memset(&sin6, 0, sizeof(sin6));
00215                      sin6.sin6_family=AF_INET6;
00216                      sin6.sin6_addr=in6addr_any;
00217                      sin6.sin6_port=port;
00218                      sinaddr=(const struct sockaddr *)&sin6;
00219                      sinaddrlen=sizeof(sin6);
00220               }
00221               else
00222 #endif
00223                      if (af == AF_INET)
00224                      {
00225                             sin4.sin_family=AF_INET;
00226                             sin4.sin_addr.s_addr=INADDR_ANY;
00227                             sin4.sin_port=port;
00228                             sinaddr=(const struct sockaddr *)&sin4;
00229                             sinaddrlen=sizeof(sin4);
00230                      }
00231                      else
00232                      {
00233                             errno=EAFNOSUPPORT;
00234                             close(fd);
00235                             return (-1);
00236                      }
00237        }
00238 
00239        ri.found_socket= -1;
00240        ri.sin=sinaddr;
00241        ri.sin_len=sinaddrlen;
00242 
00243        if (recycle_fd_func &&
00244            (*recycle_fd_func)(&try_recycle_socket, &ri, voidarg) > 0 &&
00245            ri.found_socket >= 0)
00246        {
00247               close(fd);
00248               return dup(ri.found_socket);
00249        }
00250 
00251        {
00252               int dummy=1;
00253 
00254               setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
00255                         (const char *)&dummy, sizeof(dummy));
00256        }
00257 
00258        if (fcntl(fd, F_SETFD, FD_CLOEXEC))
00259        {
00260               close(fd);
00261               return (-1);
00262        }
00263 
00264        if (fcntl(fd, F_SETFL, O_NONBLOCK))
00265        {
00266               close(fd);
00267               return (-1);
00268        }
00269        {
00270               int dummy=1;
00271 
00272               setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
00273                         (const char *)&dummy, sizeof(dummy));
00274        }
00275 
00276        if (sox_bind(fd, sinaddr, sinaddrlen) < 0)
00277        {
00278               if (flags & MKS_ERROK)
00279               {
00280                      close(fd);
00281                      return (-2);
00282               }
00283               close(fd);
00284               return (-1);
00285        }
00286 
00287        if (sox_listen(fd,
00288 #ifdef SOMAXCONN
00289                      SOMAXCONN
00290 #else
00291                      5
00292 #endif
00293                      ))
00294        {
00295               if (flags && MKS_ERROK)
00296               {
00297                      close(fd);
00298                      return (-2);
00299               }
00300               close(fd);
00301               return (-1);
00302        }
00303        return (fd);
00304 }
00305 
00306 
00307 int mksocket(const char *address,
00308             const char *service,
00309             int socktype,
00310             int *fd1,
00311             int *fd2,
00312             int recycle_fd_func( int(*)(int, void *), void *, void *),
00313             void *voidarg)
00314 {
00315        int fd_flag=0;
00316 
00317        *fd1= -1;
00318        *fd2= -1;
00319 
00320        if (address && strcmp(address, "0"))
00321        {
00322 #if HAVE_INET_PTON
00323               SOCKADDR_STORAGE ina;
00324 
00325               if (inet_pton(AF_INET, address, &ina) > 0)
00326                      fd_flag=MKS_USEAFINET4;
00327 #else
00328               struct in_addr ina;
00329 
00330               if (inet_aton(address, &ina))
00331                      fd_flag=MKS_USEAFINET4;
00332 #endif
00333 
00334        }
00335 
00336 
00337        *fd1=mksocket2(address, service, socktype, fd_flag,
00338                      recycle_fd_func, voidarg);
00339 
00340        /* BSD requires both an IPv6 and an IPv4 socket */
00341 
00342 #if    HAVE_SOXWRAP_IPV6
00343 
00344        if (address == 0 || strcmp(address, "0") == 0)
00345        {
00346               int fd=mksocket2(address, service, socktype,
00347                              (MKS_USEAFINET4|MKS_ERROK),
00348                              recycle_fd_func, voidarg);
00349 
00350               if (fd < 0)
00351               {
00352                      if (fd != -2)
00353                      {
00354                             if (*fd1 >= 0)
00355                                    close(*fd1);
00356                             return -1;
00357                      }
00358               }
00359 
00360               *fd2=fd;
00361        }
00362 #endif
00363        if (*fd1 < 0 && *fd2 < 0)
00364               return -1;
00365 
00366        if (*fd1 < 0)
00367        {
00368               *fd1=*fd2;
00369               *fd2=-1;
00370        }
00371        return 0;
00372 }
00373 
00374 #if HAVE_SYS_POLL_H
00375 
00376 #else
00377 
00378 int poll(struct pollfd *pfd, unsigned int n, int timeout)
00379 {
00380        fd_set r, w, e;
00381        int maxfd=-1;
00382        unsigned int i;
00383        struct timeval tv;
00384        int cnt=0;
00385 
00386        FD_ZERO(&r);
00387        FD_ZERO(&w);
00388        FD_ZERO(&e);
00389 
00390        for (i=0; i<n; i++)
00391        {
00392               if (pfd[i].fd >= maxfd)
00393                      maxfd=pfd[i].fd;
00394 
00395               pfd[i].revents=0;
00396               if (pfd[i].events & (POLLIN|POLLPRI))
00397                      FD_SET(pfd[i].fd, &r);
00398               if (pfd[i].events & POLLOUT)
00399                      FD_SET(pfd[i].fd, &w);
00400               if (pfd[i].events & POLLPRI)
00401                      FD_SET(pfd[i].fd, &e);
00402        }
00403 
00404        tv.tv_sec=timeout/1000;
00405        tv.tv_usec=(timeout % 1000) * 1000;
00406 
00407        if (select(maxfd+1, &r, &w, &e, timeout < 0 ?NULL:&tv) < 0)
00408               return -1;
00409 
00410        for (i=0; i<n; i++)
00411        {
00412               if (FD_ISSET(pfd[i].fd, &r))
00413                      pfd[i].revents |= POLLIN;
00414               if (FD_ISSET(pfd[i].fd, &w))
00415                      pfd[i].revents |= POLLOUT;
00416               if (FD_ISSET(pfd[i].fd, &e))
00417                      pfd[i].revents |= POLLIN|POLLHUP;
00418 
00419               if (pfd[i].revents)
00420                      ++cnt;
00421        }
00422 
00423        return cnt;
00424 }
00425 
00426 #endif