Hello all, I have recently created PR [0], which has been merged and I backported this patch to our latest apr-util version in Fedora.
Now I have been trying to come up with some test. I created simple C file where I'm trying to query memcached: int main(int argc, char **argv) { apr_pool_t *pglobal; apr_status_t rv; char *mcversion; char *errstr = malloc(1024); apr_app_initialize(NULL, NULL, NULL); if (apr_pool_create(&pglobal, NULL)){ fprintf(stderr, "could not create global pool"); return 1; } if (argc != 3){ fprintf(stderr, "Usage: ./connconnectipv6 HOST PORT\n"); return 2; } apr_memcache_server_t *ms; rv = apr_memcache_server_create(pglobal, argv[1], atoi(argv[2]), 0, 2, 2, 60, &ms); if (rv != APR_SUCCESS){. fprintf(stderr, "Errno: %d - %s\n", errno, apr_strerror(errno, errstr, 1024)); return 3; } rv = apr_memcache_version(ms, pglobal, &mcversion); if (rv != APR_SUCCESS){. fprintf(stderr, "Errno: %d - %s\n", errno, apr_strerror(errno, errstr, 1024)); return 5; } fprintf(stdout, "memcached version: %s\n", mcversion); apr_pool_destroy(pglobal); free(errstr); return 0; } In old apr-util version without patch[0] , I'm getting output as expected: # ./memcachecon 127.0.0.1 11211 memcached version: 1.6.21 # echo $? 0 # ./memcachecon ::1 11211 Errno: 0 - Success # echo $? 5 But with new apr-util containing patch[0], I'm getting weird behavior: # ./memcachecon 127.0.0.1 11211 Errno: 22 - Invalid argument # echo $? 5 # ./memcachecon ::1 11211 memcached version: 1.6.21 # echo $? 0 I don't know why, but somehow I'm getting errcode 22 in mc_conn_construct function allegedly returned by conn_connect, but when I debug it in gdb it shows me that conn_connect returns 0. Also it looks like apr_socketaddr_info_get finished successfully. I'm really puzzled here. Do you have any idea, what am I doing wrong? Also adding output from gdb: (gdb) run 127.0.0.1 11211 Starting program: /tmp/tmp.ntb0HNhuvT/memcachecon 127.0.0.1 11211 [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Breakpoint 2, apr_sockaddr_info_get (sa=sa@entry=0x7fffffffd9f0, hostname=0x40b490 "127.0.0.1", family=0, port=11211, flags=flags@entry=0, p=0x40d3f8) at network_io/unix/sockaddr.c:639 639 { (gdb) list 634 635 APR_DECLARE(apr_status_t) apr_sockaddr_info_get(apr_sockaddr_t **sa, 636 const char *hostname, 637 apr_int32_t family, apr_port_t port, 638 apr_int32_t flags, apr_pool_t *p) 639 { 640 apr_int32_t masked; 641 *sa = NULL; 642 643 if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { (gdb) 644 if (!hostname || 645 family != APR_UNSPEC || 646 masked == (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK)) { 647 return APR_EINVAL; 648 } 649 #if !APR_HAVE_IPV6 650 if (flags & APR_IPV6_ADDR_OK) { 651 return APR_ENOTIMPL; 652 } 653 #endif (gdb) 654 } 655 if (family == APR_UNSPEC && hostname && *hostname == '/') { 656 family = APR_UNIX; 657 } 658 if (family == APR_UNIX) { 659 #if APR_HAVE_SOCKADDR_UN 660 if (hostname && *hostname == '/') { 661 *sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); 662 (*sa)->pool = p; 663 apr_cpystrn((*sa)->sa.unx.sun_path, hostname, (gdb) 664 sizeof((*sa)->sa.unx.sun_path)); 665 (*sa)->hostname = apr_pstrdup(p, hostname); 666 (*sa)->family = APR_UNIX; 667 (*sa)->sa.unx.sun_family = APR_UNIX; 668 (*sa)->salen = sizeof(struct sockaddr_un); 669 (*sa)->addr_str_len = sizeof((*sa)->sa.unx.sun_path); 670 (*sa)->ipaddr_ptr = &((*sa)->sa.unx.sun_path); 671 (*sa)->ipaddr_len = (*sa)->addr_str_len; 672 673 return APR_SUCCESS; (gdb) 674 } 675 else 676 #endif 677 { 678 *sa = NULL; 679 return APR_ENOTIMPL; 680 } 681 } 682 #if !APR_HAVE_IPV6 683 /* What may happen is that APR is not IPv6-enabled, but we're still (gdb) 684 * going to call getaddrinfo(), so we have to tell the OS we only 685 * want IPv4 addresses back since we won't know what to do with 686 * IPv6 addresses. 687 */ 688 if (family == APR_UNSPEC) { 689 family = APR_INET; 690 } 691 #endif 692 693 return find_addresses(sa, hostname, family, port, flags, p); (gdb) 694 } 695 696 APR_DECLARE(apr_status_t) apr_sockaddr_info_copy(apr_sockaddr_t **dst, 697 const apr_sockaddr_t *src, 698 apr_pool_t *p) 699 { 700 apr_sockaddr_t *d; 701 const apr_sockaddr_t *s; 702 703 for (*dst = d = NULL, s = src; s; s = s->next) { (gdb) 704 if (!d) { 705 *dst = d = apr_pmemdup(p, s, sizeof *s); 706 } 707 else { 708 d = d->next = apr_pmemdup(p, s, sizeof *s); 709 } 710 if (s->hostname) { 711 if (s == src || s->hostname != src->hostname) { 712 d->hostname = apr_pstrdup(p, s->hostname); 713 } (gdb) n 641 *sa = NULL; (gdb) 643 if ((masked = flags & (APR_IPV4_ADDR_OK | APR_IPV6_ADDR_OK))) { (gdb) 655 if (family == APR_UNSPEC && hostname && *hostname == '/') { (gdb) 693 return find_addresses(sa, hostname, family, port, flags, p); (gdb) call_resolver.constprop.0 (sa=sa@entry=0x7fffffffd9f0, hostname=0x40b490 "127.0.0.1", family=0, port=11211, p=0x40d3f8, flags=<optimized out>) at network_io/unix/sockaddr.c:337 337 static apr_status_t call_resolver(apr_sockaddr_t **sa, (gdb) 347 memset(&hints, 0, sizeof(hints)); (gdb) 337 static apr_status_t call_resolver(apr_sockaddr_t **sa, (gdb) 347 memset(&hints, 0, sizeof(hints)); (gdb) 337 static apr_status_t call_resolver(apr_sockaddr_t **sa, (gdb) 347 memset(&hints, 0, sizeof(hints)); (gdb) 348 hints.ai_family = family; (gdb) 349 hints.ai_socktype = SOCK_STREAM; (gdb) 347 memset(&hints, 0, sizeof(hints)); (gdb) 351 if (family == APR_UNSPEC) { (gdb) 355 hints.ai_flags = AI_ADDRCONFIG; (gdb) 368 if(hostname == NULL) { (gdb) 397 error = getaddrinfo(hostname, servname, &hints, &ai_list); (gdb) 345 char *servname = NULL; (gdb) 397 error = getaddrinfo(hostname, servname, &hints, &ai_list); (gdb) 416 || error == EAI_ADDRFAMILY (gdb) 414 if ((family == APR_UNSPEC) && (error == EAI_BADFLAGS (gdb) 423 if (error) { (gdb) 446 ai = ai_list; (gdb) 447 while (ai) { /* while more addresses to report */ (gdb) 445 prev_sa = NULL; (gdb) 454 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) { (gdb) 462 new_sa = apr_pcalloc(p, sizeof(apr_sockaddr_t)); (gdb) 464 new_sa->pool = p; (gdb) 465 memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen); (gdb) 466 apr_sockaddr_vars_set(new_sa, ai->ai_family, port); (gdb) 468 if (!prev_sa) { /* first element in new list */ (gdb) 469 if (hostname) { (gdb) 470 new_sa->hostname = apr_pstrdup(p, hostname); (gdb) 472 *sa = new_sa; (gdb) 480 ai = ai->ai_next; (gdb) 447 while (ai) { /* while more addresses to report */ (gdb) 482 freeaddrinfo(ai_list); (gdb) 484 if (prev_sa == NULL) { (gdb) 493 } (gdb) conn_connect (conn=0x40d470) at memcache/apr_memcache.c:299 299 if (rv != APR_SUCCESS) { (gdb) p rv $1 = 0 (gdb) l 294 #else 295 apr_int32_t family = APR_UNSPEC; 296 #endif 297 298 rv = apr_sockaddr_info_get(&sa, conn->ms->host, family, conn->ms->port, 0, conn->p); 299 if (rv != APR_SUCCESS) { 300 return rv; 301 } 302 303 rv = apr_socket_timeout_set(conn->sock, 1 * APR_USEC_PER_SEC); (gdb) 304 if (rv != APR_SUCCESS) { 305 return rv; 306 } 307 308 rv = apr_socket_connect(conn->sock, sa); 309 if (rv != APR_SUCCESS) { 310 return rv; 311 } 312 313 rv = apr_socket_timeout_set(conn->sock, -1); (gdb) 314 if (rv != APR_SUCCESS) { 315 return rv; 316 } 317 318 return rv; 319 } 320 321 322 static apr_status_t 323 mc_conn_construct(void **conn_, void *params, apr_pool_t *pool) (gdb) bt #0 conn_connect (conn=0x40d470) at memcache/apr_memcache.c:299 #1 mc_conn_construct (conn_=0x40b638, params=0x40b460, pool=<optimized out>) at memcache/apr_memcache.c:363 #2 0x00007ffff7cff75d in create_resource (ret_res=<synthetic pointer>, reslist=0x40b4f0) at misc/apr_reslist.c:123 #3 apr_reslist_acquire (reslist=0x40b4f0, resource=resource@entry=0x7fffffffda78) at misc/apr_reslist.c:395 #4 0x00007ffff7d060fc in ms_find_conn (ms=<optimized out>, ms=<optimized out>, conn=0x7fffffffda78) at memcache/apr_memcache.c:232 #5 apr_memcache_version (ms=0x40b460, p=0x4093d8, baton=0x7fffffffdb08) at memcache/apr_memcache.c:1063 #6 0x000000000040129e in main (argc=3, argv=0x7fffffffdc38) at /mnt/tests/CoreOS/apr-util/memcache/bz2063562-memcache-conn-connect-allow-ipv6/connconnectipv6.c:39 (gdb) n mc_conn_construct (conn_=0x40b638, params=0x40b460, pool=<optimized out>) at memcache/apr_memcache.c:363 363 rv = conn_connect(conn); (gdb) p rv $2 = <optimized out> (gdb) list 358 359 conn->buffer = apr_palloc(conn->p, BUFFER_SIZE + 1); 360 conn->blen = 0; 361 conn->ms = ms; 362 363 rv = conn_connect(conn); 364 if (rv != APR_SUCCESS) { 365 apr_pool_destroy(np); 366 } 367 else { (gdb) 368 *conn_ = conn; 369 } 370 371 return rv; 372 } 373 374 #if APR_HAS_THREADS 375 static apr_status_t 376 mc_conn_destruct(void *conn_, void *params, apr_pool_t *pool) 377 { (gdb) n 365 apr_pool_destroy(np); (gdb) p rv $3 = 22 (gdb) [0] https://github.com/apache/apr-util/commit/fb3feebd617f6aa904d9132618649f24821bd67f Best, Lubos Uhliarik