• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

netsupp.cpp

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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal