kdecore Library API Documentation

netsupp.cpp

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