Fwd: Issues with apr_memcache_server_create

Lubos Uhliarik <[email protected]>
Newsgroups gmane.comp.apache.apr.devel
Message-ID <CAMJdYBy5iZgcutPzmh3=k37tmxx3dR1jwp3SxJrtfA+CGT+FjA@mail.gmail.com>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.