netsupp.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# netsupp.cpp

    00001 /*
    00002  *  This file is part of the KDE libraries
    00003  *  Copyright (C) 2000,2001 Thiago Macieira <thiagom@mail.com>
    00004  *
    00005  *  $Id: netsupp.cpp,v 1.33.2.1 2002/12/10 16:43:58 lunakl Exp $
    00006  *
    00007  *  This library is free software; you can redistribute it and/or
    00008  *  modify it under the terms of the GNU Library General Public
    00009  *  License as published by the Free Software Foundation; either
    00010  *  version 2 of the License, or (at your option) any later version.
    00011  *
    00012  *  This library is distributed in the hope that it will be useful,
    00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00015  *  Library General Public License for more details.
    00016  *
    00017  *  You should have received a copy of the GNU Library General Public License
    00018  *  along with this library; see the file COPYING.LIB.  If not, write to
    00019  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00020  *  Boston, MA 02111-1307, USA.
    00021  **/
    00022
    00023 #include <sys/types.h>
    00024 #include <sys/socket.h>
    00025 #include <sys/un.h>
    00026 #include <netinet/in.h>
    00027 #include <stdlib.h>
    00028 #include <stdio.h>
    00029 #include <errno.h>
    00030 #include <unistd.h>
    00031 #include <arpa/inet.h>
    00032
    00033 #include <qglobal.h>
    00034
    00035 // This is so that, if addrinfo is defined, it doesn't clobber our definition
    00036 // It might be defined in the few cases in which we are replacing the system's
    00037 // broken getaddrinfo
    00038 #include <netdb.h>
    00039
    00040 #include "config.h"
    00041 #include "kdebug.h"
    00042 #include "klocale.h"
    00043
    00044 #ifndef IN6_IS_ADDR_V4MAPPED
    00045 #define NEED_IN6_TESTS
    00046 #endif
    00047 #undef CLOBBER_IN6
    00048 #include "netsupp.h"
    00049
    00050 #if defined(__hpux) || defined(_HPUX_SOURCE)
    00051 extern int h_errno;
    00052 #endif
    00053
    00054 #if !defined(kde_sockaddr_in6)
    00055 /*
    00056  * kde_sockaddr_in6 might have got defined even though we #undef'ed
    00057  * CLOBBER_IN6. This happens when we are compiling under --enable-final.
    00058  * However, in that case, if it was defined, that's because ksockaddr.cpp
    00059  * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6
    00060  * exists and is our kde_sockaddr_in6
    00061  */
    00062 # define sockaddr_in6   kde_sockaddr_in6
    00063 # define in6_addr       kde_in6_addr
    00064 #endif
    00065
    00066 #ifdef offsetof
    00067 #undef offsetof
    00068 #endif
    00069 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    00070
    00071 /*
    00072  * These constants tell the flags in KDE::resolverFlags
    00073  * The user could (but shouldn't) test the variable to know what kind of
    00074  * resolution is supported
    00075  */
    00076 #define KRF_KNOWS_AF_INET6              0x01    /* if present, the code knows about AF_INET6 */
    00077 #define KRF_USING_OWN_GETADDRINFO       0x02    /* if present, we are using our own getaddrinfo */
    00078 #define KRF_USING_OWN_INET_NTOP         0x04    /* if present, we are using our own inet_ntop */
    00079 #define KRF_USING_OWN_INET_PTON         0x08    /* if present, we are using our own inet_pton */
    00080 #define KRF_CAN_RESOLVE_UNIX            0x100   /* if present, the resolver can resolve Unix sockets */
    00081 #define KRF_CAN_RESOLVE_IPV4            0x200   /* if present, the resolver can resolve to IPv4 */
    00082 #define KRF_CAN_RESOLVE_IPV6            0x400   /* if present, the resolver can resolve to IPv6 */
    00083
    00084
    00085 static void dofreeaddrinfo(struct addrinfo *ai)
    00086 {
    00087   while (ai)
    00088     {
    00089       struct addrinfo *ai2 = ai;
    00090       if (ai->ai_canonname != NULL)
    00091         free(ai->ai_canonname);
    00092
    00093       if (ai->ai_addr != NULL)
    00094         free(ai->ai_addr);
    00095
    00096       ai = ai->ai_next;
    00097       free(ai2);
    00098     }
    00099 }
    00100
    00101 void kde_freeaddrinfo(struct kde_addrinfo *ai)
    00102 {
    00103   if (ai->origin == KAI_LOCALUNIX)
    00104     {
    00105       struct addrinfo *p, *last = NULL;
    00106       /* We've added one AF_UNIX socket in here, to the
    00107        * tail of the linked list. We have to find it */
    00108       for (p = ai->data; p; p = p->ai_next)
    00109         {
    00110           if (p->ai_family == AF_UNIX)
    00111             {
    00112               if (last)
    00113                 {
    00114                   last->ai_next = NULL;
    00115                   freeaddrinfo(ai->data);
    00116                 }
    00117               dofreeaddrinfo(p);
    00118               break;
    00119             }
    00120           last = p;
    00121         }
    00122     }
    00123   else
    00124     freeaddrinfo(ai->data);
    00125
    00126   free(ai);
    00127 }
    00128
    00129 static struct addrinfo*
    00130 make_unix(const char *name, const char *serv)
    00131 {
    00132   const char *buf;
    00133   struct addrinfo *p;
    00134   struct sockaddr_un *_sun;
    00135   int len;
    00136
    00137   p = (addrinfo*)malloc(sizeof(*p));
    00138   if (p == NULL)
    00139     return NULL;
    00140   memset(p, 0, sizeof(*p));
    00141
    00142   if (name != NULL)
    00143     buf = name;
    00144   else
    00145     buf = serv;
    00146
    00147   // Calculate length of the binary representation
    00148   len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1;
    00149   if (*buf != '/')
    00150     len += 5;                   // strlen("/tmp/");
    00151
    00152   _sun = (sockaddr_un*)malloc(len);
    00153   if (_sun == NULL)
    00154     {
    00155       // Oops
    00156       free(p);
    00157       return NULL;
    00158     }
    00159
    00160   _sun->sun_family = AF_UNIX;
    00161 # ifdef HAVE_SOCKADDR_SA_LEN
    00162   _sun->sun_len = len;
    00163 # endif
    00164   if (*buf == '/')
    00165     *_sun->sun_path = '\0';     // empty it
    00166   else
    00167     strcpy(_sun->sun_path, "/tmp/");
    00168   strcat(_sun->sun_path, buf);
    00169
    00170   // Set the addrinfo
    00171   p->ai_family = AF_UNIX;
    00172   p->ai_addrlen = len;
    00173   p->ai_addr = (sockaddr*)_sun;
    00174   p->ai_canonname = strdup(buf);
    00175
    00176   return p;
    00177 }
    00178
    00179 // Ugh. I hate #ifdefs
    00180 // Anyways, here's what this does:
    00181 // KDE_IPV6_LOOKUP_MODE != 1, this function doesn't exist
    00182 // AF_INET6 not defined, we say there is no IPv6 stack
    00183 // otherwise, we try to create a socket.
    00184 // returns: 1 for IPv6 stack available, 2 for not available
    00185 #if KDE_IPV6_LOOKUP_MODE == 1
    00186 static int check_ipv6_stack()
    00187 {
    00188 # ifndef AF_INET6
    00189   return 2;                     // how can we check?
    00190 # else
    00191   int fd = ::socket(AF_INET6, SOCK_STREAM, 0);
    00192   if (fd == -1)
    00193      return 2;
    00194
    00195   ::close(fd);
    00196   return 1;
    00197 # endif
    00198 }
    00199 #endif
    00200
    00201
    00202 /*
    00203  * Reason for using this function: kde_getaddrinfo
    00204  *
    00205  * I decided to add this wrapper function for getaddrinfo
    00206  * and have this be called by KExtendedSocket instead of
    00207  * the real getaddrinfo so that we can make sure that the
    00208  * behaviour is the desired one.
    00209  *
    00210  * Currently, the only "undesired" behaviour is getaddrinfo
    00211  * not returning PF_UNIX sockets in some implementations.
    00212  *
    00213  * getaddrinfo and family are defined in POSIX 1003.1g
    00214  * (Protocol Independent Interfaces) and in RFC 2553
    00215  * (Basic Socket Interface for IPv6). Whereas the RFC is ambiguosly
    00216  * vague whether this family of functions should return Internet
    00217  * sockets only or not, the name of the POSIX draft says
    00218  * otherwise: it should be independent of protocol.
    00219  *
    00220  * So, my interpretation is that they should return every
    00221  * kind of socket available and known and that's how I
    00222  * designed KExtendedSocket on top of it.
    00223  *
    00224  * That's why there's this wrapper, to make sure PF_UNIX
    00225  * sockets are returned when expected.
    00226  */
    00227
    00228 int kde_getaddrinfo(const char *name, const char *service,
    00229                     const struct addrinfo* hint,
    00230                     struct kde_addrinfo** result)
    00231 {
    00232   struct kde_addrinfo* res;
    00233   struct addrinfo* p;
    00234   int err = EAI_SERVICE;
    00235 #if KDE_IPV6_LOOKUP_MODE == 1
    00236   // mode 1: do a check on whether we have an IPv6 stack
    00237   static int ipv6_stack = 0;    // 0: unknown, 1: yes, 2: no
    00238 #endif
    00239
    00240   // allocate memory for results
    00241   res = (kde_addrinfo*)malloc(sizeof(*res));
    00242   if (res == NULL)
    00243     return EAI_MEMORY;
    00244   res->data = NULL;
    00245   res->origin = KAI_SYSTEM;     // at first, it'll be only system data
    00246
    00247   struct addrinfo* last = NULL;
    00248
    00249   // Skip the getaddrinfo call and the ipv6 check for a UNIX socket.
    00250   if (hint && (hint->ai_family == PF_UNIX))
    00251   {
    00252      if (service == NULL || *service == '\0')
    00253        goto out;                // can't be Unix if no service was requested
    00254
    00255      // Unix sockets must be localhost
    00256      // That is, either name is NULL or, if it's not, it must be empty,
    00257      // "*" or "localhost"
    00258      if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') ||
    00259                 strcmp("localhost", name) == 0))
    00260        goto out;                // isn't localhost
    00261
    00262      goto do_unix;
    00263   }
    00264
    00265 #if KDE_IPV6_LOOKUP_MODE != 0
    00266 # if KDE_IPV6_LOOKUP_MODE == 1
    00267   // mode 1: do a check on whether we have an IPv6 stack
    00268   if (ipv6_stack == 0)
    00269     ipv6_stack = check_ipv6_stack();
    00270
    00271   if (ipv6_stack == 2)
    00272     {
    00273 # endif
    00274       // here we have modes 1 and 2 (no lookups)
    00275       // this is shared code
    00276       struct addrinfo our_hint;
    00277       if (hint != NULL)
    00278         {
    00279           memcpy(&our_hint, hint, sizeof(our_hint));
    00280           if (our_hint.ai_family == AF_UNSPEC)
    00281             our_hint.ai_family = AF_INET;
    00282         }
    00283       else
    00284         {
    00285           memset(&our_hint, 0, sizeof(our_hint));
    00286           our_hint.ai_family = AF_INET;
    00287         }
    00288
    00289       // do the actual resolution
    00290       err = getaddrinfo(name, service, &our_hint, &res->data);
    00291 # if KDE_IPV6_LOOKUP_MODE == 1
    00292     }
    00293   else
    00294 # endif
    00295 #endif
    00296 #if KDE_IPV6_LOOKUP_MODE != 2
    00297       // do the IPV6 resolution
    00298       err = getaddrinfo(name, service, hint, &res->data);
    00299 #endif
    00300
    00301   // Now we have to check whether the user could want a Unix socket
    00302
    00303   if (service == NULL || *service == '\0')
    00304     goto out;                   // can't be Unix if no service was requested
    00305
    00306   // Unix sockets must be localhost
    00307   // That is, either name is NULL or, if it's not, it must be empty,
    00308   // "*" or "localhost"
    00309   if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') ||
    00310                         strcmp("localhost", name) == 0))
    00311     goto out;                   // isn't localhost
    00312
    00313   // Unix sockets can only be returned if the user asked for a PF_UNSPEC
    00314   // or PF_UNIX socket type or gave us a NULL hint
    00315   if (hint != NULL && (hint->ai_family != PF_UNSPEC && hint->ai_family != PF_UNIX))
    00316     goto out;                   // user doesn't want Unix
    00317
    00318   // If we got here, then it means that the user might be expecting Unix
    00319   // sockets. The user wants a local socket, with a non-null service and
    00320   // has told us that they accept PF_UNIX sockets
    00321   // Check whether the system implementation returned Unix
    00322   if (err == 0)
    00323     for (p = res->data; p; p = p->ai_next)
    00324       {
    00325         last = p;                       // we have to find out which one is last anyways
    00326         if (p->ai_family == AF_UNIX)
    00327           // there is an Unix node
    00328           goto out;
    00329       }
    00330
    00331  do_unix:
    00332   // So, give the user a PF_UNIX socket
    00333   p = make_unix(NULL, service);
    00334   if (p == NULL)
    00335     {
    00336       err = EAI_MEMORY;
    00337       goto out;
    00338     }
    00339   if (hint != NULL)
    00340     p->ai_socktype = hint->ai_socktype;
    00341   if (p->ai_socktype == 0)
    00342     p->ai_socktype = SOCK_STREAM; // default
    00343
    00344   if (last)
    00345     last->ai_next = p;
    00346   else
    00347     res->data = p;
    00348   res->origin = KAI_LOCALUNIX;
    00349   *result = res;
    00350   return 0;
    00351
    00352  out:
    00353   // Normal exit of the function
    00354   if (err == 0)
    00355     *result = res;
    00356   else
    00357     {
    00358       if (res->data != NULL)
    00359         freeaddrinfo(res->data);
    00360       free(res);
    00361     }
    00362   return err;
    00363 }
    00364
    00365 #if defined(HAVE_GETADDRINFO) && !defined(HAVE_BROKEN_GETADDRINFO)
    00366
    00367 #define KRF_getaddrinfo         0
    00368 #define KRF_resolver            0
    00369
    00370 #else  // !defined(HAVE_GETADDRINFO) || defined(HAVE_BROKEN_GETADDRINFO)
    00371
    00372 #define KRF_getaddrinfo                 KRF_USING_OWN_GETADDRINFO
    00373 #define KRF_resolver                    KRF_CAN_RESOLVE_UNIX | KRF_CAN_RESOLVE_IPV4
    00374
    00375 /*
    00376  * No getaddrinfo() in this system.
    00377  * We shall provide our own
    00378  */
    00379
    00383 static int inet_lookup(const char *name, int portnum, int protonum,
    00384                        struct addrinfo *p, const struct addrinfo *hint,
    00385                        struct addrinfo** result)
    00386 {
    00387   struct addrinfo *q;
    00388   struct hostent *h;
    00389   struct sockaddr **psa = NULL;
    00390   int len;
    00391
    00392   // TODO
    00393   // Currently, this never resolves IPv6 (need gethostbyname2, etc.)
    00394 # ifdef AF_INET6
    00395   if (hint->ai_family == AF_INET6)
    00396     {
    00397       if (p != NULL)
    00398         {
    00399           *result = p;
    00400           return 0;
    00401         }
    00402       return EAI_FAIL;
    00403     }
    00404 # endif
    00405
    00406   q = (addrinfo*)malloc(sizeof(*q));
    00407   if (q == NULL)
    00408     {
    00409       freeaddrinfo(p);
    00410       return EAI_MEMORY;
    00411     }
    00412
    00413   h = gethostbyname(name);
    00414   if (h == NULL)
    00415     {
    00416       if (p != NULL)
    00417         {
    00418           // There already is a suitable result
    00419           *result = p;
    00420           return 0;
    00421         }
    00422
    00423       switch (h_errno)
    00424         {
    00425         case HOST_NOT_FOUND:
    00426           return EAI_NONAME;
    00427         case TRY_AGAIN:
    00428           return EAI_AGAIN;
    00429         case NO_RECOVERY:
    00430           return EAI_FAIL;
    00431         case NO_ADDRESS:
    00432           return EAI_NODATA;
    00433         default:
    00434           // EH!?
    00435           return EAI_FAIL;
    00436         }
    00437     }
    00438
    00439   // convert the hostent to addrinfo
    00440   if (h->h_addrtype == AF_INET && (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC))
    00441     len = sizeof(struct sockaddr_in);
    00442 # ifdef AF_INET6
    00443   else if (h->h_addrtype == AF_INET6 && (hint->ai_family == AF_INET6 ||
    00444                                          hint->ai_family == AF_UNSPEC))
    00445     len = sizeof(struct sockaddr_in6);
    00446 # endif
    00447   else
    00448     {
    00449       // We don't know what to do with these addresses
    00450       // Or gethostbyname returned information we don't want
    00451       if (p != NULL)
    00452         {
    00453           *result = p;
    00454           return 0;
    00455         }
    00456       return EAI_NODATA;
    00457     }
    00458
    00459   q->ai_flags = 0;
    00460   q->ai_family = h->h_addrtype;
    00461   q->ai_socktype = hint->ai_socktype;
    00462   q->ai_protocol = protonum;
    00463   q->ai_addrlen = len;
    00464
    00465   q->ai_addr = (sockaddr*)malloc(len);
    00466   if (q->ai_addr == NULL)
    00467     {
    00468       free(q);
    00469       freeaddrinfo(p);
    00470       return EAI_MEMORY;
    00471     }
    00472   if (h->h_addrtype == AF_INET)
    00473     {
    00474       struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr;
    00475       sin->sin_family = AF_INET;
    00476 # ifdef HAVE_SOCKADDR_SA_LEN
    00477       sin->sin_len = sizeof(*sin);
    00478 # endif
    00479       sin->sin_port = portnum;
    00480       memcpy(&sin->sin_addr, h->h_addr, h->h_length);
    00481     }
    00482 # ifdef AF_INET6
    00483   else if (h->h_addrtype == AF_INET6)
    00484     {
    00485       struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr;
    00486       sin6->sin6_family = AF_INET6;
    00487 #  ifdef HAVE_SOCKADDR_SA_LEN
    00488       sin6->sin6_len = sizeof(*sin6);
    00489 #  endif
    00490       sin6->sin6_port = portnum;
    00491       sin6->sin6_flowinfo = 0;
    00492       memcpy(&sin6->sin6_addr, h->h_addr, h->h_length);
    00493       sin6->sin6_scope_id = 0;
    00494     }
    00495 # endif
    00496
    00497   if (hint->ai_flags & AI_CANONNAME)
    00498     q->ai_canonname = strdup(h->h_name);
    00499   else
    00500     q->ai_canonname = NULL;
    00501
    00502   q->ai_next = p;
    00503   p = q;
    00504
    00505   // cycle through the rest of the hosts;
    00506   for (psa = (sockaddr**)h->h_addr_list + 1; *psa; psa++)
    00507     {
    00508       q = (addrinfo*)malloc(sizeof(*q));
    00509       if (q == NULL)
    00510         {
    00511           freeaddrinfo(p);
    00512           return EAI_MEMORY;
    00513         }
    00514       memcpy(q, p, sizeof(*q));
    00515
    00516       q->ai_addr = (sockaddr*)malloc(h->h_length);
    00517       if (q->ai_addr == NULL)
    00518         {
    00519           freeaddrinfo(p);
    00520           free(q);
    00521           return EAI_MEMORY;
    00522         }
    00523       if (h->h_addrtype == AF_INET)
    00524         {
    00525           struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr;
    00526           sin->sin_family = AF_INET;
    00527 # ifdef HAVE_SOCKADDR_SA_LEN
    00528           sin->sin_len = sizeof(*sin);
    00529 # endif
    00530           sin->sin_port = portnum;
    00531           memcpy(&sin->sin_addr, *psa, h->h_length);
    00532         }
    00533 # ifdef AF_INET6
    00534       else if (h->h_addrtype == AF_INET6)
    00535         {
    00536           struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr;
    00537           sin6->sin6_family = AF_INET6;
    00538 #  ifdef HAVE_SOCKADDR_SA_LEN
    00539           sin6->sin6_len = sizeof(*sin6);
    00540 #  endif
    00541           sin6->sin6_port = portnum;
    00542           sin6->sin6_flowinfo = 0;
    00543           memcpy(&sin6->sin6_addr, *psa, h->h_length);
    00544           sin6->sin6_scope_id = 0;
    00545         }
    00546 # endif
    00547
    00548       if (q->ai_canonname != NULL)
    00549         q->ai_canonname = strdup(q->ai_canonname);
    00550
    00551       q->ai_next = p;
    00552       p = q;
    00553     }
    00554
    00555   *result = p;
    00556   return 0;                     // Whew! Success!
    00557 }
    00558
    00559 static int make_inet(const char *name, int portnum, int protonum, struct addrinfo *p,
    00560                      const struct addrinfo *hint, struct addrinfo** result)
    00561 {
    00562   struct addrinfo *q;
    00563
    00564   do
    00565     {
    00566       // This 'do' is here just so that we can 'break' out of it
    00567
    00568       if (name != NULL)
    00569         {
    00570           // first, try to use inet_pton before resolving
    00571           // it will catch IP addresses given without having to go to lookup
    00572           struct sockaddr_in *sin;
    00573           struct in_addr in;
    00574 # ifdef AF_INET6
    00575           struct sockaddr_in6 *sin6;
    00576           struct in6_addr in6;
    00577
    00578           if (hint->ai_family == AF_INET6 || (hint->ai_family == AF_UNSPEC &&
    00579                                               strchr(name, ':') != NULL))
    00580             {
    00581               // yes, this is IPv6
    00582               if (inet_pton(AF_INET6, name, &in6) != 1)
    00583                 {
    00584                   if (hint->ai_flags & AI_NUMERICHOST)
    00585                     {
    00586                       freeaddrinfo(p);
    00587                       return EAI_FAIL;
    00588                     }
    00589                   break;        // not a numeric host
    00590                 }
    00591
    00592               sin6 = (sockaddr_in6*)malloc(sizeof(*sin6));
    00593               if (sin6 == NULL)
    00594                 {
    00595                   freeaddrinfo(p);
    00596                   return EAI_MEMORY;
    00597                 }
    00598               memcpy(&sin6->sin6_addr, &in6, sizeof(in6));
    00599
    00600               if (strchr(name, '%') != NULL)
    00601                 {
    00602                   errno = 0;
    00603                   sin6->sin6_scope_id = strtoul(strchr(name, '%') + 1, NULL, 10);
    00604                   if (errno != 0)
    00605                     sin6->sin6_scope_id = 0; // no interface
    00606                 }
    00607
    00608               q = (addrinfo*)malloc(sizeof(*q));
    00609               if (q == NULL)
    00610                 {
    00611                   freeaddrinfo(p);
    00612                   free(sin6);
    00613                   return EAI_MEMORY;
    00614                 }
    00615
    00616               sin6->sin6_family = AF_INET6;
    00617 #  ifdef HAVE_SOCKADDR_SA_LEN
    00618               sin6->sin6_len = sizeof(*sin6);
    00619 #  endif
    00620               sin6->sin6_port = portnum;
    00621               sin6->sin6_flowinfo = 0;
    00622
    00623               q->ai_flags = 0;
    00624               q->ai_family = AF_INET6;
    00625               q->ai_socktype = hint->ai_socktype;
    00626               q->ai_protocol = protonum;
    00627               q->ai_addrlen = sizeof(*sin6);
    00628               q->ai_canonname = NULL;
    00629               q->ai_addr = (sockaddr*)sin6;
    00630               q->ai_next = p;
    00631
    00632               *result = q;
    00633               return 0;         // success!
    00634             }
    00635 # endif // AF_INET6
    00636
    00637           if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)
    00638             {
    00639               // This has to be IPv4
    00640               if (inet_pton(AF_INET, name, &in) != 1)
    00641                 {
    00642                   if (hint->ai_flags & AI_NUMERICHOST)
    00643                     {
    00644                       freeaddrinfo(p);
    00645                       return EAI_FAIL;  // invalid, I guess
    00646                     }
    00647                   break;        // not a numeric host, do lookup
    00648                 }
    00649
    00650               sin = (sockaddr_in*)malloc(sizeof(*sin));
    00651               if (sin == NULL)
    00652                 {
    00653                   freeaddrinfo(p);
    00654                   return EAI_MEMORY;
    00655                 }
    00656
    00657               q = (addrinfo*)malloc(sizeof(*q));
    00658               if (q == NULL)
    00659                 {
    00660                   freeaddrinfo(p);
    00661                   free(sin);
    00662                   return EAI_MEMORY;
    00663                 }
    00664
    00665               sin->sin_family = AF_INET;
    00666 # ifdef HAVE_SOCKADDR_SA_LEN
    00667               sin->sin_len = sizeof(*sin);
    00668 # endif
    00669               sin->sin_port = portnum;
    00670               sin->sin_addr = in;
    00671
    00672               q->ai_flags = 0;
    00673               q->ai_family = AF_INET;
    00674               q->ai_socktype = hint->ai_socktype;
    00675               q->ai_protocol = protonum;
    00676               q->ai_addrlen = sizeof(*sin);
    00677               q->ai_canonname = NULL;
    00678               q->ai_addr = (sockaddr*)sin;
    00679               q->ai_next = p;
    00680               *result = q;
    00681               return 0;
    00682             }
    00683
    00684           // Eh, what!?
    00685           // One of the two above has to have matched
    00686           kdError() << "I wasn't supposed to get here!";
    00687         }
    00688     } while (false);
    00689
    00690   // This means localhost
    00691   if (name == NULL)
    00692     {
    00693       struct sockaddr_in *sin = (sockaddr_in*)malloc(sizeof(*sin));
    00694 # ifdef AF_INET6
    00695       struct sockaddr_in6 *sin6;
    00696 # endif
    00697
    00698       if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)
    00699         {
    00700           if (sin == NULL)
    00701             {
    00702               free(sin);
    00703               freeaddrinfo(p);
    00704               return EAI_MEMORY;
    00705             }
    00706
    00707           // Do IPv4 first
    00708           q = (addrinfo*)malloc(sizeof(*q));
    00709           if (q == NULL)
    00710             {
    00711               free(sin);
    00712               freeaddrinfo(p);
    00713               return EAI_MEMORY;
    00714             }
    00715
    00716           sin->sin_family = AF_INET;
    00717 # ifdef HAVE_SOCKADDR_SA_LEN
    00718           sin->sin_len = sizeof(*sin);
    00719 # endif
    00720           sin->sin_port = portnum;
    00721           if (hint->ai_flags & AI_PASSIVE)
    00722             *(Q_UINT32*)&sin->sin_addr = INADDR_ANY;
    00723           else
    00724             *(Q_UINT32*)&sin->sin_addr = htonl(INADDR_LOOPBACK);
    00725           q->ai_flags = 0;
    00726           q->ai_family = AF_INET;
    00727           q->ai_socktype = hint->ai_socktype;
    00728           q->ai_protocol = protonum;
    00729           q->ai_addrlen = sizeof(*sin);
    00730           q->ai_canonname = NULL;
    00731           q->ai_addr = (sockaddr*)sin;
    00732           q->ai_next = p;
    00733           p = q;
    00734         }
    00735
    00736 # ifdef AF_INET6
    00737       // Try now IPv6
    00738
    00739       if (hint->ai_family == AF_INET6 || hint->ai_family == AF_UNSPEC)
    00740         {
    00741           sin6 = (sockaddr_in6*)malloc(sizeof(*sin6));
    00742           q = (addrinfo*)malloc(sizeof(*q));
    00743           if (q == NULL || sin6 == NULL)
    00744             {
    00745               free(sin6);
    00746               free(q);
    00747               freeaddrinfo(p);
    00748               return EAI_MEMORY;
    00749             }
    00750
    00751           sin6->sin6_family = AF_INET6;
    00752 #  ifdef HAVE_SOCKADDR_SA_LEN
    00753           sin6->sin6_len = sizeof(*sin6);
    00754 #  endif
    00755           sin6->sin6_port = portnum;
    00756           sin6->sin6_flowinfo = 0;
    00757           sin6->sin6_scope_id = 0;
    00758
    00759       // We don't want to use in6addr_loopback and in6addr_any
    00760           memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr));
    00761           if ((hint->ai_flags & AI_PASSIVE) == 0)
    00762             ((char*)&sin6->sin6_addr)[15] = 1;
    00763
    00764           q->ai_flags = 0;
    00765           q->ai_family = AF_INET6;
    00766           q->ai_socktype = hint->ai_socktype;
    00767           q->ai_protocol = protonum;
    00768           q->ai_addrlen = sizeof(*sin6);
    00769           q->ai_canonname = NULL;
    00770           q->ai_addr = (sockaddr*)sin6;
    00771           q->ai_next = p;
    00772           p = q;
    00773         }
    00774
    00775 # endif // AF_INET6
    00776
    00777       *result = p;
    00778       return 0;                 // success!
    00779     }
    00780
    00781   return inet_lookup(name, portnum, protonum, p, hint, result);
    00782 }
    00783
    00784
    00785 int getaddrinfo(const char *name, const char *serv,
    00786                 const struct addrinfo* hint,
    00787                 struct addrinfo** result)
    00788 {
    00789   unsigned short portnum;       // remember to store in network byte order
    00790   int protonum = IPPROTO_TCP;
    00791   const char *proto = "tcp";
    00792   struct addrinfo *p = NULL;
    00793
    00794   // Sanity checks:
    00795   if (hint == NULL || result == NULL)
    00796     return EAI_BADFLAGS;
    00797   if (hint->ai_family != AF_UNSPEC && hint->ai_family != AF_UNIX &&
    00798       hint->ai_family != AF_INET
    00799 # ifdef AF_INET6
    00800       && hint->ai_family != AF_INET6
    00801 # endif
    00802       )
    00803     return EAI_FAMILY;
    00804   if (hint->ai_socktype != 0 && hint->ai_socktype != SOCK_STREAM &&
    00805       hint->ai_socktype != SOCK_DGRAM)
    00806     return EAI_SOCKTYPE;
    00807
    00808   // Treat hostname of "*" as NULL, which means localhost
    00809   if (name != NULL && ((*name == '*' && name[1] == '\0') || *name == '\0'))
    00810     name = NULL;
    00811   // Treat service of "*" as NULL, which I guess means no port (0)
    00812   if (serv != NULL && ((*serv == '*' && serv[1] == '\0') || *serv == '\0'))
    00813     serv = NULL;
    00814
    00815   if (name == NULL && serv == NULL) // what the hell do you want?
    00816     return EAI_NONAME;
    00817
    00818   // This is just to make it easier
    00819   if (name != NULL && strcmp(name, "localhost") == 0)
    00820      name = NULL;
    00821
    00822   // First, check for a Unix socket
    00823   // family must be either AF_UNIX or AF_UNSPEC
    00824   // either of name or serv must be set, the other must be NULL or empty
    00825   if (hint->ai_family == AF_UNIX || hint->ai_family == AF_UNSPEC)
    00826     {
    00827       if (name != NULL && serv != NULL)
    00828         {
    00829           // This is not allowed
    00830           if (hint->ai_family == AF_UNIX)
    00831             return EAI_BADFLAGS;
    00832         }
    00833       else
    00834         {
    00835           p = make_unix(name, serv);
    00836           if (p == NULL)
    00837             return EAI_MEMORY;
    00838
    00839           p->ai_socktype = hint->ai_socktype;
    00840           // If the name/service started with a slash, then this *IS*
    00841           // only a Unix socket. Return.
    00842           if (hint->ai_family == AF_UNIX || ((name != NULL && *name == '/') ||
    00843                                               (serv != NULL && *serv == '/')))
    00844             {
    00845               *result = p;
    00846               return 0;         // successful lookup
    00847             }
    00848         }
    00849     }
    00850
    00851   // Lookup the service name, if required
    00852   if (serv != NULL)
    00853     {
    00854       char *tail;
    00855       struct servent *sent;
    00856
    00857       portnum = htons((unsigned)strtoul(serv, &tail, 10));
    00858       if (*tail != '\0')
    00859         {
    00860           // not a number. We have to do the lookup
    00861           if (hint->ai_socktype == SOCK_DGRAM)
    00862             {
    00863               proto = "udp";
    00864               protonum = IPPROTO_UDP;
    00865             }
    00866
    00867           sent = getservbyname(serv, proto);
    00868           if (sent == NULL)     // no service?
    00869             {
    00870               if (p == NULL)
    00871                 return EAI_NONAME;
    00872               else
    00873                 return 0;       // a Unix socket available
    00874             }
    00875
    00876           portnum = sent->s_port;
    00877         }
    00878     }
    00879   else
    00880     portnum = 0;                // no port number
    00881
    00882   return make_inet(name, portnum, protonum, p, hint, result);
    00883 }
    00884
    00885 void freeaddrinfo(struct addrinfo *p)
    00886 {
    00887   dofreeaddrinfo(p);
    00888 }
    00889
    00890 char *gai_strerror(int errorcode)
    00891 {
    00892   static const char * const messages[] =
    00893   {
    00894     I18N_NOOP("no error"),      // 0
    00895     I18N_NOOP("address family for nodename not supported"), // EAI_ADDRFAMILY
    00896     I18N_NOOP("temporary failure in name resolution"),  // EAI_AGAIN
    00897     I18N_NOOP("invalid value for 'ai_flags'"),  // EAI_BADFLAGS
    00898     I18N_NOOP("non-recoverable failure in name resolution"), // EAI_FAIL
    00899     I18N_NOOP("'ai_family' not supported"),     // EAI_FAMILY
    00900     I18N_NOOP("memory allocation failure"),     // EAI_MEMORY
    00901     I18N_NOOP("no address associated with nodename"),   // EAI_NODATA
    00902     I18N_NOOP("name or service not known"),     // EAI_NONAME
    00903     I18N_NOOP("servname not supported for ai_socktype"), // EAI_SERVICE
    00904     I18N_NOOP("'ai_socktype' not supported"),   // EAI_SOCKTYPE
    00905     I18N_NOOP("system error")                   // EAI_SYSTEM
    00906   };
    00907
    00908   if (errorcode > EAI_SYSTEM || errorcode < 0)
    00909     return NULL;
    00910
    00911   static char buffer[200];
    00912   strcpy(buffer, i18n(messages[errorcode]).local8Bit());
    00913   return buffer;
    00914 }
    00915
    00916 static void findport(unsigned short port, char *serv, size_t servlen, int flags)
    00917 {
    00918   if (serv == NULL)
    00919     return;
    00920
    00921   if ((flags & NI_NUMERICSERV) == 0)
    00922     {
    00923       struct servent *sent;
    00924       sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp");
    00925       if (sent != NULL && servlen > strlen(sent->s_name))
    00926         {
    00927           strcpy(serv, sent->s_name);
    00928           return;
    00929         }
    00930     }
    00931
    00932   snprintf(serv, servlen, "%u", ntohs(port));
    00933 }
    00934
    00935 int getnameinfo(const struct sockaddr *sa, ksocklen_t salen,
    00936                 char *host, size_t hostlen, char *serv, size_t servlen,
    00937                 int flags)
    00938 {
    00939   union
    00940     {
    00941       const sockaddr *sa;
    00942       const sockaddr_un *_sun;
    00943       const sockaddr_in *sin;
    00944       const sockaddr_in6 *sin6;
    00945   } s;
    00946
    00947   if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0))
    00948     return 1;
    00949
    00950   s.sa = sa;
    00951   if (s.sa->sa_family == AF_UNIX)
    00952     {
    00953       if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1)
    00954         return 1;               // invalid socket
    00955
    00956       if (servlen && serv != NULL)
    00957         *serv = '\0';
    00958       if (host != NULL && hostlen > strlen(s._sun->sun_path))
    00959         strcpy(host, s._sun->sun_path);
    00960
    00961       return 0;
    00962     }
    00963   else if (s.sa->sa_family == AF_INET)
    00964     {
    00965       if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr))
    00966         return 1;               // invalid socket
    00967
    00968       if (flags & NI_NUMERICHOST)
    00969         inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
    00970       else
    00971         {
    00972           // have to do lookup
    00973           struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
    00974                                             AF_INET);
    00975           if (h == NULL && flags & NI_NAMEREQD)
    00976             return 1;
    00977           else if (h == NULL)
    00978             inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen);
    00979           else if (host != NULL && hostlen > strlen(h->h_name))
    00980             strcpy(host, h->h_name);
    00981           else
    00982             return 1;           // error
    00983         }
    00984
    00985       findport(s.sin->sin_port, serv, servlen, flags);
    00986     }
    00987 # ifdef AF_INET6
    00988   else if (s.sa->sa_family == AF_INET6)
    00989     {
    00990       if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr))
    00991         return 1;               // invalid socket
    00992
    00993       if (flags & NI_NUMERICHOST)
    00994         inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
    00995       else
    00996         {
    00997           // have to do lookup
    00998           struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr),
    00999                                             AF_INET6);
    01000           if (h == NULL && flags & NI_NAMEREQD)
    01001             return 1;
    01002           else if (h == NULL)
    01003             inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen);
    01004           else if (host != NULL && hostlen > strlen(h->h_name))
    01005             strcpy(host, h->h_name);
    01006           else
    01007             return 1;           // error
    01008         }
    01009
    01010       findport(s.sin6->sin6_port, serv, servlen, flags);
    01011     }
    01012 # endif // AF_INET6
    01013
    01014   return 1;                     // invalid family
    01015 }
    01016
    01017 #endif // HAVE_GETADDRINFO
    01018
    01019 #ifndef HAVE_INET_NTOP
    01020
    01021 #define KRF_inet_ntop   KRF_USING_OWN_INET_NTOP
    01022
    01023 static void add_dwords(char *buf, Q_UINT16 *dw, int count)
    01024 {
    01025   int i = 1;
    01026   sprintf(buf + strlen(buf), "%x", ntohs(dw[0]));
    01027   while (--count)
    01028     sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++]));
    01029 }
    01030
    01031 const char* inet_ntop(int af, const void *cp, char *buf, size_t len)
    01032 {
    01033   char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1];
    01034   Q_UINT8 *data = (Q_UINT8*)cp;
    01035
    01036   if (af == AF_INET)
    01037     {
    01038       sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]);
    01039
    01040       if (len > strlen(buf2))
    01041         {
    01042           strcpy(buf, buf2);
    01043           return buf;
    01044         }
    01045
    01046       errno = ENOSPC;
    01047       return NULL;              // failed
    01048     }
    01049
    01050 # ifdef AF_INET6
    01051   if (af == AF_INET6)
    01052     {
    01053       Q_UINT16 *p = (Q_UINT16*)data;
    01054       Q_UINT16 *longest = NULL, *cur = NULL;
    01055       int longest_length = 0, cur_length;
    01056       int i;
    01057
    01058       if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p))
    01059         sprintf(buf2, "::%s%u.%u.%u.%u",
    01060                 KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "",
    01061                 buf[12], buf[13], buf[14], buf[15]);
    01062       else
    01063         {
    01064           // find the longest sequence of zeroes
    01065           for (i = 0; i < 8; i++)
    01066             if (cur == NULL && p[i] == 0)
    01067               {
    01068                 // a zero, start the sequence
    01069                 cur = p + i;
    01070                 cur_length = 1;
    01071               }
    01072             else if (cur != NULL && p[i] == 0)
    01073               // part of the sequence
    01074               cur_length++;
    01075             else if (cur != NULL && p[i] != 0)
    01076               {
    01077                 // end of the sequence
    01078                 if (cur_length > longest_length)
    01079                   {
    01080                     longest_length = cur_length;
    01081                     longest = cur;
    01082                   }
    01083                 cur = NULL;             // restart sequence
    01084               }
    01085           if (cur != NULL && cur_length > longest_length)
    01086             {
    01087               longest_length = cur_length;
    01088               longest = cur;
    01089             }
    01090
    01091           if (longest_length > 1)
    01092             {
    01093               // We have a candidate
    01094               buf2[0] = '\0';
    01095               if (longest != p)
    01096                 add_dwords(buf2, p, longest - p);
    01097               strcat(buf2, "::");
    01098               if (longest + longest_length < p + 8)
    01099                 add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length);
    01100             }
    01101           else
    01102             {
    01103               // Nope, no candidate
    01104               buf2[0] = '\0';
    01105               add_dwords(buf2, p, 8);
    01106             }
    01107         }
    01108
    01109       if (strlen(buf2) < len)
    01110         {
    01111           strcpy(buf, buf2);
    01112           return buf;
    01113         }
    01114
    01115       errno = ENOSPC;
    01116       return NULL;
    01117     }
    01118 # endif
    01119
    01120   errno = EAFNOSUPPORT;
    01121   return NULL;                  // a family we don't know about
    01122 }
    01123
    01124 #else   // HAVE_INET_NTOP
    01125
    01126 #define KRF_inet_ntop           0
    01127
    01128 #endif  // HAVE_INET_NTOP
    01129
    01130 #ifndef HAVE_INET_PTON
    01131
    01132 #define KRF_inet_pton           KRF_USING_OWN_INET_PTON
    01133 int inet_pton(int af, const char *cp, void *buf)
    01134 {
    01135   if (af == AF_INET)
    01136     {
    01137       // Piece of cake
    01138       unsigned p[4];
    01139       unsigned char *q = (unsigned char*)buf;
    01140       if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4)
    01141         return 0;
    01142
    01143       if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff)
    01144         return 0;
    01145
    01146       q[0] = p[0];
    01147       q[1] = p[1];
    01148       q[2] = p[2];
    01149       q[3] = p[3];
    01150
    01151       return 1;
    01152     }
    01153
    01154 # ifdef AF_INET6
    01155   else if (af == AF_INET6)
    01156     {
    01157       Q_UINT16 addr[8];
    01158       const char *p = cp;
    01159       int n = 0, start = 8;
    01160       bool has_v4 = strchr(p, '.') != NULL;
    01161
    01162       memset(addr, 0, sizeof(addr));
    01163
    01164       if (*p == '\0' || p[1] == '\0')
    01165         return 0;               // less than 2 chars is not valid
    01166
    01167       if (*p == ':' && p[1] == ':')
    01168         {
    01169           start = 0;
    01170           p += 2;
    01171         }
    01172       while (*p)
    01173         {
    01174           if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0)
    01175             {
    01176               // successfull v4 convertion
    01177               addr[n] = ntohs(addr[n]);
    01178               n++;
    01179               addr[n] = ntohs(addr[n]);
    01180               n++;
    01181               break;
    01182             }
    01183           if (sscanf(p, "%hx", addr + n++) != 1)
    01184             return 0;
    01185
    01186           while (*p && *p != ':')
    01187             p++;
    01188           if (!*p)
    01189             break;
    01190           p++;
    01191
    01192           if (*p == ':')        // another ':'?
    01193             {
    01194               if (start != 8)
    01195                 return 0;       // two :: were found
    01196               start = n;
    01197               p++;
    01198             }
    01199         }
    01200
    01201       // if start is not 8, then a "::" was found at word 'start'
    01202       // n is the number of converted words
    01203       // n == 8 means everything was converted and no moving is necessary
    01204       // n < 8 means that we have to move n - start words 8 - n words to the right
    01205       if (start == 8 && n != 8)
    01206         return 0;               // bad conversion
    01207       memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(Q_UINT16));
    01208       memset(addr + start, 0, (8 - n) * sizeof(Q_UINT16));
    01209
    01210       // check the byte order
    01211       // The compiler should optimise this out in big endian machines
    01212       if (htons(0x1234) != 0x1234)
    01213         for (n = 0; n < 8; n++)
    01214           addr[n] = htons(addr[n]);
    01215
    01216       memcpy(buf, addr, sizeof(addr));
    01217       return 1;
    01218     }
    01219 # endif
    01220
    01221   errno = EAFNOSUPPORT;
    01222   return -1;                    // unknown family
    01223 }
    01224
    01225 #else  // HAVE_INET_PTON
    01226
    01227 #define KRF_inet_pton           0
    01228
    01229 #endif // HAVE_INET_PTON
    01230
    01231 #ifdef AF_INET6
    01232 # define KRF_afinet6    KRF_KNOWS_AF_INET6
    01233 #else
    01234 # define KRF_afinet6    0
    01235 #endif
    01236
    01237 namespace KDE
    01238 {
    01239   extern const int resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton;
    01240 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:47:00 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001