backend.c 4.05 KB
Newer Older
Ondřej Kuzník's avatar
Ondřej Kuzník committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
 * Copyright 1998-2020 The OpenLDAP Foundation.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */

#include "portable.h"

#include <ac/socket.h>
#include <ac/errno.h>
#include <ac/string.h>
#include <ac/time.h>
#include <ac/unistd.h>

#include <event2/event.h>
#include <event2/dns.h>

#include "lutil.h"
#include "slap.h"

static void
upstream_name_cb( int result, struct evutil_addrinfo *res, void *arg )
{
    Backend *b = arg;
    Connection *c;
    ber_socket_t s;
    int rc;

    if ( result || !res ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "name resolution failed for backend '%s': %s\n",
                b->b_bindconf.sb_uri.bv_val, evutil_gai_strerror( result ) );
        return;
    }

    s = socket( res->ai_family, SOCK_STREAM, 0 );
    if ( s == AC_SOCKET_INVALID ) {
        return;
    }

    rc = ber_pvt_socket_set_nonblock( s, 1 );
    if ( rc ) {
        evutil_closesocket( s );
        return;
    }

    if ( res->ai_family == PF_INET ) {
        struct sockaddr_in *ai = (struct sockaddr_in *)res->ai_addr;
        ai->sin_port = htons( b->b_port );
        rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen );
    } else {
        struct sockaddr_in6 *ai = (struct sockaddr_in6 *)res->ai_addr;
        ai->sin6_port = htons( b->b_port );
        rc = connect( s, (struct sockaddr *)ai, res->ai_addrlen );
    }
    if ( rc && errno != EINPROGRESS && errno != EWOULDBLOCK ) {
        Debug( LDAP_DEBUG_ANY, "upstream_name_cb: "
                "failed to connect to server '%s'\n",
                b->b_bindconf.sb_uri.bv_val );
        evutil_closesocket( s );
        return;
    }

    c = upstream_init( s, b );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
74
    ldap_pvt_thread_mutex_lock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
75
    b->b_conns = c;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
76
    ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
77
78
79
80
81
82
83
84
85
86
}

Connection *
backend_select( Operation *op )
{
    Backend *b;

    LDAP_STAILQ_FOREACH ( b, &backend, b_next ) {
        Connection *c;

Ondřej Kuzník's avatar
Ondřej Kuzník committed
87
        ldap_pvt_thread_mutex_lock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
88
        c = b->b_conns;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
89
        ldap_pvt_thread_mutex_lock( &c->c_io_mutex );
90
        if ( c->c_state == SLAP_C_READY && !c->c_pendingber ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
91
            ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
92
93
            return b->b_conns;
        }
Ondřej Kuzník's avatar
Ondřej Kuzník committed
94
        ldap_pvt_thread_mutex_unlock( &c->c_io_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
95
        ldap_pvt_thread_mutex_unlock( &b->b_mutex );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
96
97
98
99
100
101
    }

    return NULL;
}

void *
102
backend_connect( void *ctx, void *arg )
Ondřej Kuzník's avatar
Ondřej Kuzník committed
103
104
{
    struct evutil_addrinfo hints = {};
105
    Backend *b = arg;
Ondřej Kuzník's avatar
Ondřej Kuzník committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

#ifdef LDAP_PF_LOCAL
    if ( b->b_proto == LDAP_PROTO_IPC ) {
        struct sockaddr_un addr;
        ber_socket_t s = socket( PF_LOCAL, SOCK_STREAM, 0 );
        int rc;

        if ( s == AC_SOCKET_INVALID ) {
            return (void *)-1;
        }

        rc = ber_pvt_socket_set_nonblock( s, 1 );
        if ( rc ) {
            evutil_closesocket( s );
            return (void *)-1;
        }

        if ( strlen( b->b_host ) > ( sizeof(addr.sun_path) - 1 ) ) {
            evutil_closesocket( s );
            return (void *)-1;
        }
        memset( &addr, '\0', sizeof(addr) );
        addr.sun_family = AF_LOCAL;
        strcpy( addr.sun_path, b->b_host );

        rc = connect(
                s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un) );
        if ( rc && errno != EINPROGRESS && errno != EWOULDBLOCK ) {
            evutil_closesocket( s );
            return (void *)-1;
        }

        b->b_conns = upstream_init( s, b );
        return NULL;
    }
#endif /* LDAP_PF_LOCAL */

    hints.ai_family = AF_UNSPEC;
    hints.ai_flags = EVUTIL_AI_CANONNAME;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    evdns_getaddrinfo( dnsbase, b->b_host, NULL, &hints, upstream_name_cb, b );
    return NULL;
}