kdecore Library API Documentation

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 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:14:48 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001