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.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