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