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