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

Reply via email to