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

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.9.5 API Reference

Skip menu "kdelibs-4.9.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal