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

# netsupp.cpp

    00001 /*
    00002  *  This file is part of the KDE libraries
    00003  *  Copyright (C) 2000,2001 Thiago Macieira <thiago.macieira@kdemail.net>
    00004  *
    00005  *  This library is free software; you can redistribute it and/or
    00006  *  modify it under the terms of the GNU Library General Public
    00007  *  License as published by the Free Software Foundation; either
    00008  *  version 2 of the License, or (at your option) any later version.
    00009  *
    00010  *  This library is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00013  *  Library General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU Library General Public License
    00016  *  along with this library; see the file COPYING.LIB.  If not, write to
    00017  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00018  *  Boston, MA 02111-1307, USA.
    00019  **/
    00020
    00021 #include <sys/types.h>
    00022 #include <sys/socket.h>
    00023 #include <sys/un.h>
    00024 #include <netinet/in.h>
    00025 #include <stdlib.h>
    00026 #include <stdio.h>
    00027 #include <errno.h>
    00028 #include <unistd.h>
    00029 #include <arpa/inet.h>
    00030
    00031 #include <qglobal.h>
    00032
    00033 // This is so that, if addrinfo is defined, it doesn't clobber our definition
    00034 // It might be defined in the few cases in which we are replacing the system's
    00035 // broken getaddrinfo
    00036 #include <netdb.h>
    00037
    00038 #include "config.h"
    00039 #include "kdebug.h"
    00040 #include "klocale.h"
    00041
    00042 #ifndef IN6_IS_ADDR_V4MAPPED
    00043 #define NEED_IN6_TESTS
    00044 #endif
    00045 #undef CLOBBER_IN6
    00046 #include "netsupp.h"
    00047
    00048 #if defined(__hpux) || defined(_HPUX_SOURCE)
    00049 extern int h_errno;
    00050 #endif
    00051
    00052 #if !defined(kde_sockaddr_in6)
    00053 /*
    00054  * kde_sockaddr_in6 might have got defined even though we #undef'ed
    00055  * CLOBBER_IN6. This happens when we are compiling under --enable-final.
    00056  * However, in that case, if it was defined, that's because ksockaddr.cpp
    00057  * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6
    00058  * exists and is our kde_sockaddr_in6
    00059  */
    00060 # define sockaddr_in6   kde_sockaddr_in6
    00061 # define in6_addr   kde_in6_addr
    00062 #endif
    00063
    00064 #ifdef offsetof
    00065 #undef offsetof
    00066 #endif
    00067 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    00068
    00069 /*
    00070  * These constants tell the flags in KDE::resolverFlags
    00071  * The user could (but shouldn't) test the variable to know what kind of
    00072  * resolution is supported
    00073  */
    00074 #define KRF_KNOWS_AF_INET6      0x01    /* if present, the code knows about AF_INET6 */
    00075 #define KRF_USING_OWN_GETADDRINFO   0x02    /* if present, we are using our own getaddrinfo */
    00076 #define KRF_USING_OWN_INET_NTOP     0x04    /* if present, we are using our own inet_ntop */
    00077 #define KRF_USING_OWN_INET_PTON     0x08    /* if present, we are using our own inet_pton */
    00078 #define KRF_CAN_RESOLVE_UNIX        0x100   /* if present, the resolver can resolve Unix sockets */
    00079 #define KRF_CAN_RESOLVE_IPV4        0x200   /* if present, the resolver can resolve to IPv4 */
    00080 #define KRF_CAN_RESOLVE_IPV6        0x400   /* if present, the resolver can resolve to IPv6 */
    00081
    00082
    00083 static void dofreeaddrinfo(struct addrinfo *ai)
    00084 {
    00085   while (ai)
    00086     {
    00087       struct addrinfo *ai2 = ai;
    00088       if (ai->ai_canonname != NULL)
    00089     free(ai->ai_canonname);
    00090
    00091       if (ai->ai_addr != NULL)
    00092     free(ai->ai_addr);
    00093
    00094       ai = ai->ai_next;
    00095       free(ai2);
    00096     }
    00097 }
    00098
    00099 void kde_freeaddrinfo(struct kde_addrinfo *ai)
    00100 {
    00101   if (ai->origin == KAI_LOCALUNIX)
    00102     {
    00103       struct addrinfo *p, *last = NULL;
    00104       /* We've added one AF_UNIX socket in here, to the
    00105        * tail of the linked list. We have to find it */
    00106       for (p = ai->data; p; p = p->ai_next)
    00107     {
    00108       if (p->ai_family == AF_UNIX)
    00109         {
    00110           if (last)
    00111         {
    00112           last->ai_next = NULL;
    00113           freeaddrinfo(ai->data);
    00114         }
    00115           dofreeaddrinfo(p);
    00116           break;
    00117         }
    00118       last = p;
    00119     }
    00120     }
    00121   else
    00122     freeaddrinfo(ai->data);
    00123
    00124   free(ai);
    00125 }
    00126
    00127 static struct addrinfo*
    00128 make_unix(const char *name, const char *serv)
    00129 {
    00130   const char *buf;
    00131   struct addrinfo *p;
    00132   struct sockaddr_un *_sun;
    00133   int len;
    00134
    00135   p = (addrinfo*)malloc(sizeof(*p));
    00136   if (p == NULL)
    00137     return NULL;
    00138   memset(p, 0, sizeof(*p));
    00139
    00140   if (name != NULL)
    00141     buf = name;
    00142   else
    00143     buf = serv;
    00144
    00145   // Calculate length of the binary representation
    00146   len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1;
    00147   if (*buf != '/')
    00148     len += 5;           // strlen("/tmp/");
    00149
    00150   _sun = (sockaddr_un*)malloc(len);
    00151   if (_sun == NULL)
    00152     {
    00153       // Oops
    00154       free(p);
    00155       return NULL;
    00156     }
    00157
    00158   _sun->sun_family = AF_UNIX;
    00159 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
    00160   _sun->sun_len = len;
    00161 # endif
    00162   if (*buf == '/')
    00163     *_sun->sun_path = '\0'; // empty it
    00164   else
    00165     strcpy(_sun->sun_path, "/tmp/");
    00166   strcat(_sun->sun_path, buf);
    00167
    00168   // Set the addrinfo
    00169   p->ai_family = AF_UNIX;
    00170   p->ai_addrlen = len;
    00171   p->ai_addr = (sockaddr*)_sun;
    00172   p->ai_canonname = strdup(buf);
    00173
    00174   return p;
    00175 }
    00176
    00177 // Ugh. I hate #ifdefs
    00178 // Anyways, here's what this does:
    00179 // KDE_IPV6_LOOKUP_MODE != 1, this function doesn't exist
    00180 // AF_INET6 not defined, we say there is no IPv6 stack
    00181 // otherwise, we try to create a socket.
    00182 // returns: 1 for IPv6 stack available, 2 for not available
    00183 #if defined(KDE_IPV6_LOOKUP_MODE) && KDE_IPV6_LOOKUP_MODE == 1
    00184 static int check_ipv6_stack()
    00185 {
    00186 # ifndef AF_INET6
    00187   return 2;         // how can we check?
    00188 # else
    00189   if (getenv("KDE_NO_IPV6"))
    00190      return 2;
    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  * behavior is the desired one.
    00209  *
    00210  * Currently, the only "undesired" behavior 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 defined(KDE_IPV6_LOOKUP_MODE) && 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 defined(KDE_IPV6_LOOKUP_MODE) && 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 defined(KDE_IPV6_LOOKUP_MODE) && 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_STRUCT_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_STRUCT_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_STRUCT_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_STRUCT_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_STRUCT_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_STRUCT_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_STRUCT_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_STRUCT_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           // successful 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 {
    01240   extern KDE_EXPORT const int resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton;
    01241 }

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:12 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003