Re: Issues with apr_memcache_server_create

Lubos Uhliarik <[email protected]>
Newsgroups gmane.comp.apache.apr.devel
Message-ID <CAMJdYBz+6dr7vpA2M-nE16vEcf0NTvEhbNp12-X1ift_ekbJJA@mail.gmail.com>
Hello again,

I think this is a regression, since now it will refuse all IPv4
connections. I filed a new PR on github [0].

[0] https://github.com/apache/apr/pull/44

Best,
Lubos Uhliarik

On Fri, Jun 23, 2023 at 1:04 PM Lubos Uhliarik <[email protected]> wrote:

> 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
>


-- 

Luboš Uhliarik

Senior Software Engineer | Infrastructure Services

[email protected]

BRQ-TPBC

*irc (luhliari at): #brno, #infrastructure-services, #core-services*
<https://www.redhat.com/>
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.