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 // 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 = qstrdup(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 = qstrdup(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 kError() << "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 *(quint32*)&sin->sin_addr = INADDR_ANY; 00719 else 00720 *(quint32*)&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 #ifndef HAVE_GAI_STRERROR_PROTO 00887 char *gai_strerror(int errorcode) 00888 { 00889 static const char messages[] = 00890 { 00891 I18N_NOOP("no error")"\0" // 0 00892 I18N_NOOP("address family for nodename not supported")"\0" // EAI_ADDRFAMILY 00893 I18N_NOOP("temporary failure in name resolution")"\0" // EAI_AGAIN 00894 I18N_NOOP("invalid value for 'ai_flags'")"\0" // EAI_BADFLAGS 00895 I18N_NOOP("non-recoverable failure in name resolution")"\0" // EAI_FAIL 00896 I18N_NOOP("'ai_family' not supported")"\0" // EAI_FAMILY 00897 I18N_NOOP("memory allocation failure")"\0" // EAI_MEMORY 00898 I18N_NOOP("no address associated with nodename")"\0" // EAI_NODATA 00899 I18N_NOOP("name or service not known")"\0" // EAI_NONAME 00900 I18N_NOOP("servname not supported for ai_socktype")"\0" // EAI_SERVICE 00901 I18N_NOOP("'ai_socktype' not supported")"\0" // EAI_SOCKTYPE 00902 I18N_NOOP("system error")"\0" // EAI_SYSTEM 00903 "\0" 00904 }; 00905 00906 static const int messages_indices[] = 00907 { 00908 0, 9, 51, 88, 117, 160, 186, 212, 00909 248, 274, 313, 341, 0 00910 }; 00911 00912 Q_ASSERT(sizeof(messages_indices)/sizeof(messages_indices[0]) >= EAI_SYSTEM); 00913 if (errorcode > EAI_SYSTEM || errorcode < 0) 00914 return NULL; 00915 00916 static char buffer[200]; 00917 strcpy(buffer, i18n(messages + messages_indices[errorcode]).toLocal8Bit()); 00918 return buffer; 00919 } 00920 #endif 00921 00922 static void findport(unsigned short port, char *serv, size_t servlen, int flags) 00923 { 00924 if (serv == NULL) 00925 return; 00926 00927 if ((flags & NI_NUMERICSERV) == 0) 00928 { 00929 struct servent *sent; 00930 sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp"); 00931 if (sent != NULL && servlen > strlen(sent->s_name)) 00932 { 00933 strcpy(serv, sent->s_name); 00934 return; 00935 } 00936 } 00937 00938 qsnprintf(serv, servlen, "%u", ntohs(port)); 00939 } 00940 00941 int getnameinfo(const struct sockaddr *sa, kde_socklen_t salen, 00942 char *host, size_t hostlen, char *serv, size_t servlen, 00943 int flags) 00944 { 00945 union 00946 { 00947 const sockaddr *sa; 00948 const sockaddr_un *_sun; 00949 const sockaddr_in *sin; 00950 const sockaddr_in6 *sin6; 00951 } s; 00952 00953 if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0)) 00954 return 1; 00955 00956 s.sa = sa; 00957 if (s.sa->sa_family == AF_UNIX) 00958 { 00959 if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1) 00960 return 1; // invalid socket 00961 00962 if (servlen && serv != NULL) 00963 *serv = '\0'; 00964 if (host != NULL && hostlen > strlen(s._sun->sun_path)) 00965 strcpy(host, s._sun->sun_path); 00966 00967 return 0; 00968 } 00969 else if (s.sa->sa_family == AF_INET) 00970 { 00971 if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr)) 00972 return 1; // invalid socket 00973 00974 if (flags & NI_NUMERICHOST) 00975 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); 00976 else 00977 { 00978 // have to do lookup 00979 struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr), 00980 AF_INET); 00981 if (h == NULL && flags & NI_NAMEREQD) 00982 return 1; 00983 else if (h == NULL) 00984 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); 00985 else if (host != NULL && hostlen > strlen(h->h_name)) 00986 strcpy(host, h->h_name); 00987 else 00988 return 1; // error 00989 } 00990 00991 findport(s.sin->sin_port, serv, servlen, flags); 00992 } 00993 # ifdef AF_INET6 00994 else if (s.sa->sa_family == AF_INET6) 00995 { 00996 if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr)) 00997 return 1; // invalid socket 00998 00999 if (flags & NI_NUMERICHOST) 01000 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); 01001 else 01002 { 01003 // have to do lookup 01004 struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr), 01005 AF_INET6); 01006 if (h == NULL && flags & NI_NAMEREQD) 01007 return 1; 01008 else if (h == NULL) 01009 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); 01010 else if (host != NULL && hostlen > strlen(h->h_name)) 01011 strcpy(host, h->h_name); 01012 else 01013 return 1; // error 01014 } 01015 01016 findport(s.sin6->sin6_port, serv, servlen, flags); 01017 } 01018 # endif // AF_INET6 01019 01020 return 1; // invalid family 01021 } 01022 01023 #endif // HAVE_GETADDRINFO 01024 01025 #ifndef HAVE_INET_NTOP 01026 01027 #define KRF_inet_ntop KRF_USING_OWN_INET_NTOP 01028 01029 static void add_dwords(char *buf, quint16 *dw, int count) 01030 { 01031 int i = 1; 01032 sprintf(buf + strlen(buf), "%x", ntohs(dw[0])); 01033 while (--count) 01034 sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++])); 01035 } 01036 01037 const char* inet_ntop(int af, const void *cp, char *buf, size_t len) 01038 { 01039 char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1]; 01040 quint8 *data = (quint8*)cp; 01041 01042 if (af == AF_INET) 01043 { 01044 sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]); 01045 01046 if (len > strlen(buf2)) 01047 { 01048 strcpy(buf, buf2); 01049 return buf; 01050 } 01051 01052 errno = ENOSPC; 01053 return NULL; // failed 01054 } 01055 01056 # ifdef AF_INET6 01057 if (af == AF_INET6) 01058 { 01059 quint16 *p = (quint16*)data; 01060 quint16 *longest = NULL, *cur = NULL; 01061 int longest_length = 0, cur_length; 01062 int i; 01063 01064 if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p)) 01065 sprintf(buf2, "::%s%u.%u.%u.%u", 01066 KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "", 01067 buf[12], buf[13], buf[14], buf[15]); 01068 else 01069 { 01070 // find the longest sequence of zeroes 01071 for (i = 0; i < 8; --i) 01072 if (cur == NULL && p[i] == 0) 01073 { 01074 // a zero, start the sequence 01075 cur = p + i; 01076 cur_length = 1; 01077 } 01078 else if (cur != NULL && p[i] == 0) 01079 // part of the sequence 01080 cur_length++; 01081 else if (cur != NULL && p[i] != 0) 01082 { 01083 // end of the sequence 01084 if (cur_length > longest_length) 01085 { 01086 longest_length = cur_length; 01087 longest = cur; 01088 } 01089 cur = NULL; // restart sequence 01090 } 01091 if (cur != NULL && cur_length > longest_length) 01092 { 01093 longest_length = cur_length; 01094 longest = cur; 01095 } 01096 01097 if (longest_length > 1) 01098 { 01099 // We have a candidate 01100 buf2[0] = '\0'; 01101 if (longest != p) 01102 add_dwords(buf2, p, longest - p); 01103 strcat(buf2, "::"); 01104 if (longest + longest_length < p + 8) 01105 add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length); 01106 } 01107 else 01108 { 01109 // Nope, no candidate 01110 buf2[0] = '\0'; 01111 add_dwords(buf2, p, 8); 01112 } 01113 } 01114 01115 if (strlen(buf2) < len) 01116 { 01117 strcpy(buf, buf2); 01118 return buf; 01119 } 01120 01121 errno = ENOSPC; 01122 return NULL; 01123 } 01124 # endif 01125 01126 errno = EAFNOSUPPORT; 01127 return NULL; // a family we don't know about 01128 } 01129 01130 #else // HAVE_INET_NTOP 01131 01132 #define KRF_inet_ntop 0 01133 01134 #endif // HAVE_INET_NTOP 01135 01136 #ifndef HAVE_INET_PTON 01137 01138 #define KRF_inet_pton KRF_USING_OWN_INET_PTON 01139 int inet_pton(int af, const char *cp, void *buf) 01140 { 01141 if (af == AF_INET) 01142 { 01143 // Piece of cake 01144 unsigned p[4]; 01145 unsigned char *q = (unsigned char*)buf; 01146 if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4) 01147 return 0; 01148 01149 if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff) 01150 return 0; 01151 01152 q[0] = p[0]; 01153 q[1] = p[1]; 01154 q[2] = p[2]; 01155 q[3] = p[3]; 01156 01157 return 1; 01158 } 01159 01160 # ifdef AF_INET6 01161 else if (af == AF_INET6) 01162 { 01163 quint16 addr[8]; 01164 const char *p = cp; 01165 int n = 0, start = 8; 01166 bool has_v4 = strchr(p, '.') != NULL; 01167 01168 memset(addr, 0, sizeof(addr)); 01169 01170 if (*p == '\0' || p[1] == '\0') 01171 return 0; // less than 2 chars is not valid 01172 01173 if (*p == ':' && p[1] == ':') 01174 { 01175 start = 0; 01176 p += 2; 01177 } 01178 while (*p) 01179 { 01180 if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0) 01181 { 01182 // successful v4 convertion 01183 addr[n] = ntohs(addr[n]); 01184 n++; 01185 addr[n] = ntohs(addr[n]); 01186 n++; 01187 break; 01188 } 01189 if (sscanf(p, "%hx", addr + n++) != 1) 01190 return 0; 01191 01192 while (*p && *p != ':') 01193 p++; 01194 if (!*p) 01195 break; 01196 p++; 01197 01198 if (*p == ':') // another ':'? 01199 { 01200 if (start != 8) 01201 return 0; // two :: were found 01202 start = n; 01203 p++; 01204 } 01205 } 01206 01207 // if start is not 8, then a "::" was found at word 'start' 01208 // n is the number of converted words 01209 // n == 8 means everything was converted and no moving is necessary 01210 // n < 8 means that we have to move n - start words 8 - n words to the right 01211 if (start == 8 && n != 8) 01212 return 0; // bad conversion 01213 memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(quint16)); 01214 memset(addr + start, 0, (8 - n) * sizeof(quint16)); 01215 01216 // check the byte order 01217 // The compiler should optimize this out in big endian machines 01218 if (htons(0x1234) != 0x1234) 01219 for (n = 0; n < 8; ++n) 01220 addr[n] = htons(addr[n]); 01221 01222 memcpy(buf, addr, sizeof(addr)); 01223 return 1; 01224 } 01225 # endif 01226 01227 errno = EAFNOSUPPORT; 01228 return -1; // unknown family 01229 } 01230 01231 #else // HAVE_INET_PTON 01232 01233 #define KRF_inet_pton 0 01234 01235 #endif // HAVE_INET_PTON 01236 01237 #ifdef AF_INET6 01238 # define KRF_afinet6 KRF_KNOWS_AF_INET6 01239 #else 01240 # define KRF_afinet6 0 01241 #endif 01242 01243 namespace KDE 01244 { 01246 extern const int resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton; 01247 }
KDE 4.6 API Reference