kdecore Library API Documentation

netsupp.cpp

00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (C) 2000,2001 Thiago Macieira <thiagom@mail.com> 00004 * 00005 * $Id: netsupp.cpp,v 1.39.2.1 2004/04/21 12:20:25 waba Exp $ 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Library General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public License 00018 * along with this library; see the file COPYING.LIB. If not, write to 00019 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00020 * Boston, MA 02111-1307, USA. 00021 **/ 00022 00023 #include <sys/types.h> 00024 #include <sys/socket.h> 00025 #include <sys/un.h> 00026 #include <netinet/in.h> 00027 #include <stdlib.h> 00028 #include <stdio.h> 00029 #include <errno.h> 00030 #include <unistd.h> 00031 #include <arpa/inet.h> 00032 00033 #include <qglobal.h> 00034 00035 // This is so that, if addrinfo is defined, it doesn't clobber our definition 00036 // It might be defined in the few cases in which we are replacing the system's 00037 // broken getaddrinfo 00038 #include <netdb.h> 00039 00040 #include "config.h" 00041 #include "kdebug.h" 00042 #include "klocale.h" 00043 00044 #ifndef IN6_IS_ADDR_V4MAPPED 00045 #define NEED_IN6_TESTS 00046 #endif 00047 #undef CLOBBER_IN6 00048 #include "netsupp.h" 00049 00050 #if defined(__hpux) || defined(_HPUX_SOURCE) 00051 extern int h_errno; 00052 #endif 00053 00054 #if !defined(kde_sockaddr_in6) 00055 /* 00056 * kde_sockaddr_in6 might have got defined even though we #undef'ed 00057 * CLOBBER_IN6. This happens when we are compiling under --enable-final. 00058 * However, in that case, if it was defined, that's because ksockaddr.cpp 00059 * had it defined because sockaddr_in6 didn't exist, and so sockaddr_in6 00060 * exists and is our kde_sockaddr_in6 00061 */ 00062 # define sockaddr_in6 kde_sockaddr_in6 00063 # define in6_addr kde_in6_addr 00064 #endif 00065 00066 #ifdef offsetof 00067 #undef offsetof 00068 #endif 00069 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 00070 00071 /* 00072 * These constants tell the flags in KDE::resolverFlags 00073 * The user could (but shouldn't) test the variable to know what kind of 00074 * resolution is supported 00075 */ 00076 #define KRF_KNOWS_AF_INET6 0x01 /* if present, the code knows about AF_INET6 */ 00077 #define KRF_USING_OWN_GETADDRINFO 0x02 /* if present, we are using our own getaddrinfo */ 00078 #define KRF_USING_OWN_INET_NTOP 0x04 /* if present, we are using our own inet_ntop */ 00079 #define KRF_USING_OWN_INET_PTON 0x08 /* if present, we are using our own inet_pton */ 00080 #define KRF_CAN_RESOLVE_UNIX 0x100 /* if present, the resolver can resolve Unix sockets */ 00081 #define KRF_CAN_RESOLVE_IPV4 0x200 /* if present, the resolver can resolve to IPv4 */ 00082 #define KRF_CAN_RESOLVE_IPV6 0x400 /* if present, the resolver can resolve to IPv6 */ 00083 00084 00085 static void dofreeaddrinfo(struct addrinfo *ai) 00086 { 00087 while (ai) 00088 { 00089 struct addrinfo *ai2 = ai; 00090 if (ai->ai_canonname != NULL) 00091 free(ai->ai_canonname); 00092 00093 if (ai->ai_addr != NULL) 00094 free(ai->ai_addr); 00095 00096 ai = ai->ai_next; 00097 free(ai2); 00098 } 00099 } 00100 00101 void kde_freeaddrinfo(struct kde_addrinfo *ai) 00102 { 00103 if (ai->origin == KAI_LOCALUNIX) 00104 { 00105 struct addrinfo *p, *last = NULL; 00106 /* We've added one AF_UNIX socket in here, to the 00107 * tail of the linked list. We have to find it */ 00108 for (p = ai->data; p; p = p->ai_next) 00109 { 00110 if (p->ai_family == AF_UNIX) 00111 { 00112 if (last) 00113 { 00114 last->ai_next = NULL; 00115 freeaddrinfo(ai->data); 00116 } 00117 dofreeaddrinfo(p); 00118 break; 00119 } 00120 last = p; 00121 } 00122 } 00123 else 00124 freeaddrinfo(ai->data); 00125 00126 free(ai); 00127 } 00128 00129 static struct addrinfo* 00130 make_unix(const char *name, const char *serv) 00131 { 00132 const char *buf; 00133 struct addrinfo *p; 00134 struct sockaddr_un *_sun; 00135 int len; 00136 00137 p = (addrinfo*)malloc(sizeof(*p)); 00138 if (p == NULL) 00139 return NULL; 00140 memset(p, 0, sizeof(*p)); 00141 00142 if (name != NULL) 00143 buf = name; 00144 else 00145 buf = serv; 00146 00147 // Calculate length of the binary representation 00148 len = strlen(buf) + offsetof(struct sockaddr_un, sun_path) + 1; 00149 if (*buf != '/') 00150 len += 5; // strlen("/tmp/"); 00151 00152 _sun = (sockaddr_un*)malloc(len); 00153 if (_sun == NULL) 00154 { 00155 // Oops 00156 free(p); 00157 return NULL; 00158 } 00159 00160 _sun->sun_family = AF_UNIX; 00161 # ifdef HAVE_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 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 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 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 KDE_IPV6_LOOKUP_MODE != 2 00299 // do the IPV6 resolution 00300 err = getaddrinfo(name, service, hint, &res->data); 00301 #endif 00302 00303 // Now we have to check whether the user could want a Unix socket 00304 00305 if (service == NULL || *service == '\0') 00306 goto out; // can't be Unix if no service was requested 00307 00308 // Unix sockets must be localhost 00309 // That is, either name is NULL or, if it's not, it must be empty, 00310 // "*" or "localhost" 00311 if (name != NULL && !(name[0] == '\0' || (name[0] == '*' && name[1] == '\0') || 00312 strcmp("localhost", name) == 0)) 00313 goto out; // isn't localhost 00314 00315 // Unix sockets can only be returned if the user asked for a PF_UNSPEC 00316 // or PF_UNIX socket type or gave us a NULL hint 00317 if (hint != NULL && (hint->ai_family != PF_UNSPEC && hint->ai_family != PF_UNIX)) 00318 goto out; // user doesn't want Unix 00319 00320 // If we got here, then it means that the user might be expecting Unix 00321 // sockets. The user wants a local socket, with a non-null service and 00322 // has told us that they accept PF_UNIX sockets 00323 // Check whether the system implementation returned Unix 00324 if (err == 0) 00325 for (p = res->data; p; p = p->ai_next) 00326 { 00327 last = p; // we have to find out which one is last anyways 00328 if (p->ai_family == AF_UNIX) 00329 // there is an Unix node 00330 goto out; 00331 } 00332 00333 do_unix: 00334 // So, give the user a PF_UNIX socket 00335 p = make_unix(NULL, service); 00336 if (p == NULL) 00337 { 00338 err = EAI_MEMORY; 00339 goto out; 00340 } 00341 if (hint != NULL) 00342 p->ai_socktype = hint->ai_socktype; 00343 if (p->ai_socktype == 0) 00344 p->ai_socktype = SOCK_STREAM; // default 00345 00346 if (last) 00347 last->ai_next = p; 00348 else 00349 res->data = p; 00350 res->origin = KAI_LOCALUNIX; 00351 *result = res; 00352 return 0; 00353 00354 out: 00355 // Normal exit of the function 00356 if (err == 0) 00357 *result = res; 00358 else 00359 { 00360 if (res->data != NULL) 00361 freeaddrinfo(res->data); 00362 free(res); 00363 } 00364 return err; 00365 } 00366 00367 #if defined(HAVE_GETADDRINFO) && !defined(HAVE_BROKEN_GETADDRINFO) 00368 00369 #define KRF_getaddrinfo 0 00370 #define KRF_resolver 0 00371 00372 #else // !defined(HAVE_GETADDRINFO) || defined(HAVE_BROKEN_GETADDRINFO) 00373 00374 #define KRF_getaddrinfo KRF_USING_OWN_GETADDRINFO 00375 #define KRF_resolver KRF_CAN_RESOLVE_UNIX | KRF_CAN_RESOLVE_IPV4 00376 00377 /* 00378 * No getaddrinfo() in this system. 00379 * We shall provide our own 00380 */ 00381 00385 static int inet_lookup(const char *name, int portnum, int protonum, 00386 struct addrinfo *p, const struct addrinfo *hint, 00387 struct addrinfo** result) 00388 { 00389 struct addrinfo *q; 00390 struct hostent *h; 00391 struct sockaddr **psa = NULL; 00392 int len; 00393 00394 // TODO 00395 // Currently, this never resolves IPv6 (need gethostbyname2, etc.) 00396 # ifdef AF_INET6 00397 if (hint->ai_family == AF_INET6) 00398 { 00399 if (p != NULL) 00400 { 00401 *result = p; 00402 return 0; 00403 } 00404 return EAI_FAIL; 00405 } 00406 # endif 00407 00408 q = (addrinfo*)malloc(sizeof(*q)); 00409 if (q == NULL) 00410 { 00411 freeaddrinfo(p); 00412 return EAI_MEMORY; 00413 } 00414 00415 h = gethostbyname(name); 00416 if (h == NULL) 00417 { 00418 if (p != NULL) 00419 { 00420 // There already is a suitable result 00421 *result = p; 00422 return 0; 00423 } 00424 00425 switch (h_errno) 00426 { 00427 case HOST_NOT_FOUND: 00428 return EAI_NONAME; 00429 case TRY_AGAIN: 00430 return EAI_AGAIN; 00431 case NO_RECOVERY: 00432 return EAI_FAIL; 00433 case NO_ADDRESS: 00434 return EAI_NODATA; 00435 default: 00436 // EH!? 00437 return EAI_FAIL; 00438 } 00439 } 00440 00441 // convert the hostent to addrinfo 00442 if (h->h_addrtype == AF_INET && (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC)) 00443 len = sizeof(struct sockaddr_in); 00444 # ifdef AF_INET6 00445 else if (h->h_addrtype == AF_INET6 && (hint->ai_family == AF_INET6 || 00446 hint->ai_family == AF_UNSPEC)) 00447 len = sizeof(struct sockaddr_in6); 00448 # endif 00449 else 00450 { 00451 // We don't know what to do with these addresses 00452 // Or gethostbyname returned information we don't want 00453 if (p != NULL) 00454 { 00455 *result = p; 00456 return 0; 00457 } 00458 return EAI_NODATA; 00459 } 00460 00461 q->ai_flags = 0; 00462 q->ai_family = h->h_addrtype; 00463 q->ai_socktype = hint->ai_socktype; 00464 q->ai_protocol = protonum; 00465 q->ai_addrlen = len; 00466 00467 q->ai_addr = (sockaddr*)malloc(len); 00468 if (q->ai_addr == NULL) 00469 { 00470 free(q); 00471 freeaddrinfo(p); 00472 return EAI_MEMORY; 00473 } 00474 if (h->h_addrtype == AF_INET) 00475 { 00476 struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr; 00477 sin->sin_family = AF_INET; 00478 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00479 sin->sin_len = sizeof(*sin); 00480 # endif 00481 sin->sin_port = portnum; 00482 memcpy(&sin->sin_addr, h->h_addr, h->h_length); 00483 } 00484 # ifdef AF_INET6 00485 else if (h->h_addrtype == AF_INET6) 00486 { 00487 struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr; 00488 sin6->sin6_family = AF_INET6; 00489 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00490 sin6->sin6_len = sizeof(*sin6); 00491 # endif 00492 sin6->sin6_port = portnum; 00493 sin6->sin6_flowinfo = 0; 00494 memcpy(&sin6->sin6_addr, h->h_addr, h->h_length); 00495 sin6->sin6_scope_id = 0; 00496 } 00497 # endif 00498 00499 if (hint->ai_flags & AI_CANONNAME) 00500 q->ai_canonname = strdup(h->h_name); 00501 else 00502 q->ai_canonname = NULL; 00503 00504 q->ai_next = p; 00505 p = q; 00506 00507 // cycle through the rest of the hosts; 00508 for (psa = (sockaddr**)h->h_addr_list + 1; *psa; psa++) 00509 { 00510 q = (addrinfo*)malloc(sizeof(*q)); 00511 if (q == NULL) 00512 { 00513 freeaddrinfo(p); 00514 return EAI_MEMORY; 00515 } 00516 memcpy(q, p, sizeof(*q)); 00517 00518 q->ai_addr = (sockaddr*)malloc(h->h_length); 00519 if (q->ai_addr == NULL) 00520 { 00521 freeaddrinfo(p); 00522 free(q); 00523 return EAI_MEMORY; 00524 } 00525 if (h->h_addrtype == AF_INET) 00526 { 00527 struct sockaddr_in *sin = (sockaddr_in*)q->ai_addr; 00528 sin->sin_family = AF_INET; 00529 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00530 sin->sin_len = sizeof(*sin); 00531 # endif 00532 sin->sin_port = portnum; 00533 memcpy(&sin->sin_addr, *psa, h->h_length); 00534 } 00535 # ifdef AF_INET6 00536 else if (h->h_addrtype == AF_INET6) 00537 { 00538 struct sockaddr_in6 *sin6 = (sockaddr_in6*)q->ai_addr; 00539 sin6->sin6_family = AF_INET6; 00540 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00541 sin6->sin6_len = sizeof(*sin6); 00542 # endif 00543 sin6->sin6_port = portnum; 00544 sin6->sin6_flowinfo = 0; 00545 memcpy(&sin6->sin6_addr, *psa, h->h_length); 00546 sin6->sin6_scope_id = 0; 00547 } 00548 # endif 00549 00550 if (q->ai_canonname != NULL) 00551 q->ai_canonname = strdup(q->ai_canonname); 00552 00553 q->ai_next = p; 00554 p = q; 00555 } 00556 00557 *result = p; 00558 return 0; // Whew! Success! 00559 } 00560 00561 static int make_inet(const char *name, int portnum, int protonum, struct addrinfo *p, 00562 const struct addrinfo *hint, struct addrinfo** result) 00563 { 00564 struct addrinfo *q; 00565 00566 do 00567 { 00568 // This 'do' is here just so that we can 'break' out of it 00569 00570 if (name != NULL) 00571 { 00572 // first, try to use inet_pton before resolving 00573 // it will catch IP addresses given without having to go to lookup 00574 struct sockaddr_in *sin; 00575 struct in_addr in; 00576 # ifdef AF_INET6 00577 struct sockaddr_in6 *sin6; 00578 struct in6_addr in6; 00579 00580 if (hint->ai_family == AF_INET6 || (hint->ai_family == AF_UNSPEC && 00581 strchr(name, ':') != NULL)) 00582 { 00583 // yes, this is IPv6 00584 if (inet_pton(AF_INET6, name, &in6) != 1) 00585 { 00586 if (hint->ai_flags & AI_NUMERICHOST) 00587 { 00588 freeaddrinfo(p); 00589 return EAI_FAIL; 00590 } 00591 break; // not a numeric host 00592 } 00593 00594 sin6 = (sockaddr_in6*)malloc(sizeof(*sin6)); 00595 if (sin6 == NULL) 00596 { 00597 freeaddrinfo(p); 00598 return EAI_MEMORY; 00599 } 00600 memcpy(&sin6->sin6_addr, &in6, sizeof(in6)); 00601 00602 if (strchr(name, '%') != NULL) 00603 { 00604 errno = 0; 00605 sin6->sin6_scope_id = strtoul(strchr(name, '%') + 1, NULL, 10); 00606 if (errno != 0) 00607 sin6->sin6_scope_id = 0; // no interface 00608 } 00609 00610 q = (addrinfo*)malloc(sizeof(*q)); 00611 if (q == NULL) 00612 { 00613 freeaddrinfo(p); 00614 free(sin6); 00615 return EAI_MEMORY; 00616 } 00617 00618 sin6->sin6_family = AF_INET6; 00619 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00620 sin6->sin6_len = sizeof(*sin6); 00621 # endif 00622 sin6->sin6_port = portnum; 00623 sin6->sin6_flowinfo = 0; 00624 00625 q->ai_flags = 0; 00626 q->ai_family = AF_INET6; 00627 q->ai_socktype = hint->ai_socktype; 00628 q->ai_protocol = protonum; 00629 q->ai_addrlen = sizeof(*sin6); 00630 q->ai_canonname = NULL; 00631 q->ai_addr = (sockaddr*)sin6; 00632 q->ai_next = p; 00633 00634 *result = q; 00635 return 0; // success! 00636 } 00637 # endif // AF_INET6 00638 00639 if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC) 00640 { 00641 // This has to be IPv4 00642 if (inet_pton(AF_INET, name, &in) != 1) 00643 { 00644 if (hint->ai_flags & AI_NUMERICHOST) 00645 { 00646 freeaddrinfo(p); 00647 return EAI_FAIL; // invalid, I guess 00648 } 00649 break; // not a numeric host, do lookup 00650 } 00651 00652 sin = (sockaddr_in*)malloc(sizeof(*sin)); 00653 if (sin == NULL) 00654 { 00655 freeaddrinfo(p); 00656 return EAI_MEMORY; 00657 } 00658 00659 q = (addrinfo*)malloc(sizeof(*q)); 00660 if (q == NULL) 00661 { 00662 freeaddrinfo(p); 00663 free(sin); 00664 return EAI_MEMORY; 00665 } 00666 00667 sin->sin_family = AF_INET; 00668 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00669 sin->sin_len = sizeof(*sin); 00670 # endif 00671 sin->sin_port = portnum; 00672 sin->sin_addr = in; 00673 00674 q->ai_flags = 0; 00675 q->ai_family = AF_INET; 00676 q->ai_socktype = hint->ai_socktype; 00677 q->ai_protocol = protonum; 00678 q->ai_addrlen = sizeof(*sin); 00679 q->ai_canonname = NULL; 00680 q->ai_addr = (sockaddr*)sin; 00681 q->ai_next = p; 00682 *result = q; 00683 return 0; 00684 } 00685 00686 // Eh, what!? 00687 // One of the two above has to have matched 00688 kdError() << "I wasn't supposed to get here!"; 00689 } 00690 } while (false); 00691 00692 // This means localhost 00693 if (name == NULL) 00694 { 00695 struct sockaddr_in *sin = (sockaddr_in*)malloc(sizeof(*sin)); 00696 # ifdef AF_INET6 00697 struct sockaddr_in6 *sin6; 00698 # endif 00699 00700 if (hint->ai_family == AF_INET || hint->ai_family == AF_UNSPEC) 00701 { 00702 if (sin == NULL) 00703 { 00704 free(sin); 00705 freeaddrinfo(p); 00706 return EAI_MEMORY; 00707 } 00708 00709 // Do IPv4 first 00710 q = (addrinfo*)malloc(sizeof(*q)); 00711 if (q == NULL) 00712 { 00713 free(sin); 00714 freeaddrinfo(p); 00715 return EAI_MEMORY; 00716 } 00717 00718 sin->sin_family = AF_INET; 00719 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00720 sin->sin_len = sizeof(*sin); 00721 # endif 00722 sin->sin_port = portnum; 00723 if (hint->ai_flags & AI_PASSIVE) 00724 *(Q_UINT32*)&sin->sin_addr = INADDR_ANY; 00725 else 00726 *(Q_UINT32*)&sin->sin_addr = htonl(INADDR_LOOPBACK); 00727 q->ai_flags = 0; 00728 q->ai_family = AF_INET; 00729 q->ai_socktype = hint->ai_socktype; 00730 q->ai_protocol = protonum; 00731 q->ai_addrlen = sizeof(*sin); 00732 q->ai_canonname = NULL; 00733 q->ai_addr = (sockaddr*)sin; 00734 q->ai_next = p; 00735 p = q; 00736 } 00737 00738 # ifdef AF_INET6 00739 // Try now IPv6 00740 00741 if (hint->ai_family == AF_INET6 || hint->ai_family == AF_UNSPEC) 00742 { 00743 sin6 = (sockaddr_in6*)malloc(sizeof(*sin6)); 00744 q = (addrinfo*)malloc(sizeof(*q)); 00745 if (q == NULL || sin6 == NULL) 00746 { 00747 free(sin6); 00748 free(q); 00749 freeaddrinfo(p); 00750 return EAI_MEMORY; 00751 } 00752 00753 sin6->sin6_family = AF_INET6; 00754 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00755 sin6->sin6_len = sizeof(*sin6); 00756 # endif 00757 sin6->sin6_port = portnum; 00758 sin6->sin6_flowinfo = 0; 00759 sin6->sin6_scope_id = 0; 00760 00761 // We don't want to use in6addr_loopback and in6addr_any 00762 memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); 00763 if ((hint->ai_flags & AI_PASSIVE) == 0) 00764 ((char*)&sin6->sin6_addr)[15] = 1; 00765 00766 q->ai_flags = 0; 00767 q->ai_family = AF_INET6; 00768 q->ai_socktype = hint->ai_socktype; 00769 q->ai_protocol = protonum; 00770 q->ai_addrlen = sizeof(*sin6); 00771 q->ai_canonname = NULL; 00772 q->ai_addr = (sockaddr*)sin6; 00773 q->ai_next = p; 00774 p = q; 00775 } 00776 00777 # endif // AF_INET6 00778 00779 *result = p; 00780 return 0; // success! 00781 } 00782 00783 return inet_lookup(name, portnum, protonum, p, hint, result); 00784 } 00785 00786 00787 int getaddrinfo(const char *name, const char *serv, 00788 const struct addrinfo* hint, 00789 struct addrinfo** result) 00790 { 00791 unsigned short portnum; // remember to store in network byte order 00792 int protonum = IPPROTO_TCP; 00793 const char *proto = "tcp"; 00794 struct addrinfo *p = NULL; 00795 00796 // Sanity checks: 00797 if (hint == NULL || result == NULL) 00798 return EAI_BADFLAGS; 00799 if (hint->ai_family != AF_UNSPEC && hint->ai_family != AF_UNIX && 00800 hint->ai_family != AF_INET 00801 # ifdef AF_INET6 00802 && hint->ai_family != AF_INET6 00803 # endif 00804 ) 00805 return EAI_FAMILY; 00806 if (hint->ai_socktype != 0 && hint->ai_socktype != SOCK_STREAM && 00807 hint->ai_socktype != SOCK_DGRAM) 00808 return EAI_SOCKTYPE; 00809 00810 // Treat hostname of "*" as NULL, which means localhost 00811 if (name != NULL && ((*name == '*' && name[1] == '\0') || *name == '\0')) 00812 name = NULL; 00813 // Treat service of "*" as NULL, which I guess means no port (0) 00814 if (serv != NULL && ((*serv == '*' && serv[1] == '\0') || *serv == '\0')) 00815 serv = NULL; 00816 00817 if (name == NULL && serv == NULL) // what the hell do you want? 00818 return EAI_NONAME; 00819 00820 // This is just to make it easier 00821 if (name != NULL && strcmp(name, "localhost") == 0) 00822 name = NULL; 00823 00824 // First, check for a Unix socket 00825 // family must be either AF_UNIX or AF_UNSPEC 00826 // either of name or serv must be set, the other must be NULL or empty 00827 if (hint->ai_family == AF_UNIX || hint->ai_family == AF_UNSPEC) 00828 { 00829 if (name != NULL && serv != NULL) 00830 { 00831 // This is not allowed 00832 if (hint->ai_family == AF_UNIX) 00833 return EAI_BADFLAGS; 00834 } 00835 else 00836 { 00837 p = make_unix(name, serv); 00838 if (p == NULL) 00839 return EAI_MEMORY; 00840 00841 p->ai_socktype = hint->ai_socktype; 00842 // If the name/service started with a slash, then this *IS* 00843 // only a Unix socket. Return. 00844 if (hint->ai_family == AF_UNIX || ((name != NULL && *name == '/') || 00845 (serv != NULL && *serv == '/'))) 00846 { 00847 *result = p; 00848 return 0; // successful lookup 00849 } 00850 } 00851 } 00852 00853 // Lookup the service name, if required 00854 if (serv != NULL) 00855 { 00856 char *tail; 00857 struct servent *sent; 00858 00859 portnum = htons((unsigned)strtoul(serv, &tail, 10)); 00860 if (*tail != '\0') 00861 { 00862 // not a number. We have to do the lookup 00863 if (hint->ai_socktype == SOCK_DGRAM) 00864 { 00865 proto = "udp"; 00866 protonum = IPPROTO_UDP; 00867 } 00868 00869 sent = getservbyname(serv, proto); 00870 if (sent == NULL) // no service? 00871 { 00872 if (p == NULL) 00873 return EAI_NONAME; 00874 else 00875 return 0; // a Unix socket available 00876 } 00877 00878 portnum = sent->s_port; 00879 } 00880 } 00881 else 00882 portnum = 0; // no port number 00883 00884 return make_inet(name, portnum, protonum, p, hint, result); 00885 } 00886 00887 void freeaddrinfo(struct addrinfo *p) 00888 { 00889 dofreeaddrinfo(p); 00890 } 00891 00892 char *gai_strerror(int errorcode) 00893 { 00894 static const char * const messages[] = 00895 { 00896 I18N_NOOP("no error"), // 0 00897 I18N_NOOP("address family for nodename not supported"), // EAI_ADDRFAMILY 00898 I18N_NOOP("temporary failure in name resolution"), // EAI_AGAIN 00899 I18N_NOOP("invalid value for 'ai_flags'"), // EAI_BADFLAGS 00900 I18N_NOOP("non-recoverable failure in name resolution"), // EAI_FAIL 00901 I18N_NOOP("'ai_family' not supported"), // EAI_FAMILY 00902 I18N_NOOP("memory allocation failure"), // EAI_MEMORY 00903 I18N_NOOP("no address associated with nodename"), // EAI_NODATA 00904 I18N_NOOP("name or service not known"), // EAI_NONAME 00905 I18N_NOOP("servname not supported for ai_socktype"), // EAI_SERVICE 00906 I18N_NOOP("'ai_socktype' not supported"), // EAI_SOCKTYPE 00907 I18N_NOOP("system error") // EAI_SYSTEM 00908 }; 00909 00910 if (errorcode > EAI_SYSTEM || errorcode < 0) 00911 return NULL; 00912 00913 static char buffer[200]; 00914 strcpy(buffer, i18n(messages[errorcode]).local8Bit()); 00915 return buffer; 00916 } 00917 00918 static void findport(unsigned short port, char *serv, size_t servlen, int flags) 00919 { 00920 if (serv == NULL) 00921 return; 00922 00923 if ((flags & NI_NUMERICSERV) == 0) 00924 { 00925 struct servent *sent; 00926 sent = getservbyport(ntohs(port), flags & NI_DGRAM ? "udp" : "tcp"); 00927 if (sent != NULL && servlen > strlen(sent->s_name)) 00928 { 00929 strcpy(serv, sent->s_name); 00930 return; 00931 } 00932 } 00933 00934 snprintf(serv, servlen, "%u", ntohs(port)); 00935 } 00936 00937 int getnameinfo(const struct sockaddr *sa, ksocklen_t salen, 00938 char *host, size_t hostlen, char *serv, size_t servlen, 00939 int flags) 00940 { 00941 union 00942 { 00943 const sockaddr *sa; 00944 const sockaddr_un *_sun; 00945 const sockaddr_in *sin; 00946 const sockaddr_in6 *sin6; 00947 } s; 00948 00949 if ((host == NULL || hostlen == 0) && (serv == NULL || servlen == 0)) 00950 return 1; 00951 00952 s.sa = sa; 00953 if (s.sa->sa_family == AF_UNIX) 00954 { 00955 if (salen < offsetof(struct sockaddr_un, sun_path) + strlen(s._sun->sun_path) + 1) 00956 return 1; // invalid socket 00957 00958 if (servlen && serv != NULL) 00959 *serv = '\0'; 00960 if (host != NULL && hostlen > strlen(s._sun->sun_path)) 00961 strcpy(host, s._sun->sun_path); 00962 00963 return 0; 00964 } 00965 else if (s.sa->sa_family == AF_INET) 00966 { 00967 if (salen < offsetof(struct sockaddr_in, sin_addr) + sizeof(s.sin->sin_addr)) 00968 return 1; // invalid socket 00969 00970 if (flags & NI_NUMERICHOST) 00971 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); 00972 else 00973 { 00974 // have to do lookup 00975 struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr), 00976 AF_INET); 00977 if (h == NULL && flags & NI_NAMEREQD) 00978 return 1; 00979 else if (h == NULL) 00980 inet_ntop(AF_INET, &s.sin->sin_addr, host, hostlen); 00981 else if (host != NULL && hostlen > strlen(h->h_name)) 00982 strcpy(host, h->h_name); 00983 else 00984 return 1; // error 00985 } 00986 00987 findport(s.sin->sin_port, serv, servlen, flags); 00988 } 00989 # ifdef AF_INET6 00990 else if (s.sa->sa_family == AF_INET6) 00991 { 00992 if (salen < offsetof(struct sockaddr_in6, sin6_addr) + sizeof(s.sin6->sin6_addr)) 00993 return 1; // invalid socket 00994 00995 if (flags & NI_NUMERICHOST) 00996 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); 00997 else 00998 { 00999 // have to do lookup 01000 struct hostent *h = gethostbyaddr((const char*)&s.sin->sin_addr, sizeof(s.sin->sin_addr), 01001 AF_INET6); 01002 if (h == NULL && flags & NI_NAMEREQD) 01003 return 1; 01004 else if (h == NULL) 01005 inet_ntop(AF_INET6, &s.sin6->sin6_addr, host, hostlen); 01006 else if (host != NULL && hostlen > strlen(h->h_name)) 01007 strcpy(host, h->h_name); 01008 else 01009 return 1; // error 01010 } 01011 01012 findport(s.sin6->sin6_port, serv, servlen, flags); 01013 } 01014 # endif // AF_INET6 01015 01016 return 1; // invalid family 01017 } 01018 01019 #endif // HAVE_GETADDRINFO 01020 01021 #ifndef HAVE_INET_NTOP 01022 01023 #define KRF_inet_ntop KRF_USING_OWN_INET_NTOP 01024 01025 static void add_dwords(char *buf, Q_UINT16 *dw, int count) 01026 { 01027 int i = 1; 01028 sprintf(buf + strlen(buf), "%x", ntohs(dw[0])); 01029 while (--count) 01030 sprintf(buf + strlen(buf), ":%x", ntohs(dw[i++])); 01031 } 01032 01033 const char* inet_ntop(int af, const void *cp, char *buf, size_t len) 01034 { 01035 char buf2[sizeof "1234:5678:9abc:def0:1234:5678:255.255.255.255" + 1]; 01036 Q_UINT8 *data = (Q_UINT8*)cp; 01037 01038 if (af == AF_INET) 01039 { 01040 sprintf(buf2, "%u.%u.%u.%u", data[0], data[1], data[2], data[3]); 01041 01042 if (len > strlen(buf2)) 01043 { 01044 strcpy(buf, buf2); 01045 return buf; 01046 } 01047 01048 errno = ENOSPC; 01049 return NULL; // failed 01050 } 01051 01052 # ifdef AF_INET6 01053 if (af == AF_INET6) 01054 { 01055 Q_UINT16 *p = (Q_UINT16*)data; 01056 Q_UINT16 *longest = NULL, *cur = NULL; 01057 int longest_length = 0, cur_length; 01058 int i; 01059 01060 if (KDE_IN6_IS_ADDR_V4MAPPED(p) || KDE_IN6_IS_ADDR_V4COMPAT(p)) 01061 sprintf(buf2, "::%s%u.%u.%u.%u", 01062 KDE_IN6_IS_ADDR_V4MAPPED(p) ? "ffff:" : "", 01063 buf[12], buf[13], buf[14], buf[15]); 01064 else 01065 { 01066 // find the longest sequence of zeroes 01067 for (i = 0; i < 8; i++) 01068 if (cur == NULL && p[i] == 0) 01069 { 01070 // a zero, start the sequence 01071 cur = p + i; 01072 cur_length = 1; 01073 } 01074 else if (cur != NULL && p[i] == 0) 01075 // part of the sequence 01076 cur_length++; 01077 else if (cur != NULL && p[i] != 0) 01078 { 01079 // end of the sequence 01080 if (cur_length > longest_length) 01081 { 01082 longest_length = cur_length; 01083 longest = cur; 01084 } 01085 cur = NULL; // restart sequence 01086 } 01087 if (cur != NULL && cur_length > longest_length) 01088 { 01089 longest_length = cur_length; 01090 longest = cur; 01091 } 01092 01093 if (longest_length > 1) 01094 { 01095 // We have a candidate 01096 buf2[0] = '\0'; 01097 if (longest != p) 01098 add_dwords(buf2, p, longest - p); 01099 strcat(buf2, "::"); 01100 if (longest + longest_length < p + 8) 01101 add_dwords(buf2, longest + longest_length, 8 - (longest - p) - longest_length); 01102 } 01103 else 01104 { 01105 // Nope, no candidate 01106 buf2[0] = '\0'; 01107 add_dwords(buf2, p, 8); 01108 } 01109 } 01110 01111 if (strlen(buf2) < len) 01112 { 01113 strcpy(buf, buf2); 01114 return buf; 01115 } 01116 01117 errno = ENOSPC; 01118 return NULL; 01119 } 01120 # endif 01121 01122 errno = EAFNOSUPPORT; 01123 return NULL; // a family we don't know about 01124 } 01125 01126 #else // HAVE_INET_NTOP 01127 01128 #define KRF_inet_ntop 0 01129 01130 #endif // HAVE_INET_NTOP 01131 01132 #ifndef HAVE_INET_PTON 01133 01134 #define KRF_inet_pton KRF_USING_OWN_INET_PTON 01135 int inet_pton(int af, const char *cp, void *buf) 01136 { 01137 if (af == AF_INET) 01138 { 01139 // Piece of cake 01140 unsigned p[4]; 01141 unsigned char *q = (unsigned char*)buf; 01142 if (sscanf(cp, "%u.%u.%u.%u", p, p + 1, p + 2, p + 3) != 4) 01143 return 0; 01144 01145 if (p[0] > 0xff || p[1] > 0xff || p[2] > 0xff || p[3] > 0xff) 01146 return 0; 01147 01148 q[0] = p[0]; 01149 q[1] = p[1]; 01150 q[2] = p[2]; 01151 q[3] = p[3]; 01152 01153 return 1; 01154 } 01155 01156 # ifdef AF_INET6 01157 else if (af == AF_INET6) 01158 { 01159 Q_UINT16 addr[8]; 01160 const char *p = cp; 01161 int n = 0, start = 8; 01162 bool has_v4 = strchr(p, '.') != NULL; 01163 01164 memset(addr, 0, sizeof(addr)); 01165 01166 if (*p == '\0' || p[1] == '\0') 01167 return 0; // less than 2 chars is not valid 01168 01169 if (*p == ':' && p[1] == ':') 01170 { 01171 start = 0; 01172 p += 2; 01173 } 01174 while (*p) 01175 { 01176 if (has_v4 && inet_pton(AF_INET, p, addr + n) != 0) 01177 { 01178 // successful v4 convertion 01179 addr[n] = ntohs(addr[n]); 01180 n++; 01181 addr[n] = ntohs(addr[n]); 01182 n++; 01183 break; 01184 } 01185 if (sscanf(p, "%hx", addr + n++) != 1) 01186 return 0; 01187 01188 while (*p && *p != ':') 01189 p++; 01190 if (!*p) 01191 break; 01192 p++; 01193 01194 if (*p == ':') // another ':'? 01195 { 01196 if (start != 8) 01197 return 0; // two :: were found 01198 start = n; 01199 p++; 01200 } 01201 } 01202 01203 // if start is not 8, then a "::" was found at word 'start' 01204 // n is the number of converted words 01205 // n == 8 means everything was converted and no moving is necessary 01206 // n < 8 means that we have to move n - start words 8 - n words to the right 01207 if (start == 8 && n != 8) 01208 return 0; // bad conversion 01209 memmove(addr + start + (8 - n), addr + start, (n - start) * sizeof(Q_UINT16)); 01210 memset(addr + start, 0, (8 - n) * sizeof(Q_UINT16)); 01211 01212 // check the byte order 01213 // The compiler should optimise this out in big endian machines 01214 if (htons(0x1234) != 0x1234) 01215 for (n = 0; n < 8; n++) 01216 addr[n] = htons(addr[n]); 01217 01218 memcpy(buf, addr, sizeof(addr)); 01219 return 1; 01220 } 01221 # endif 01222 01223 errno = EAFNOSUPPORT; 01224 return -1; // unknown family 01225 } 01226 01227 #else // HAVE_INET_PTON 01228 01229 #define KRF_inet_pton 0 01230 01231 #endif // HAVE_INET_PTON 01232 01233 #ifdef AF_INET6 01234 # define KRF_afinet6 KRF_KNOWS_AF_INET6 01235 #else 01236 # define KRF_afinet6 0 01237 #endif 01238 01239 namespace KDE 01240 { 01242 extern const int resolverFlags = KRF_getaddrinfo | KRF_resolver | KRF_afinet6 | KRF_inet_ntop | KRF_inet_pton; 01243 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:48:28 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003