~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to src/auth/auth-worker-server.c

  • Committer: Package Import Robot
  • Author(s): Jaldhar H. Vyas
  • Date: 2013-09-09 00:57:32 UTC
  • mfrom: (1.13.11)
  • mto: (4.8.5 experimental) (1.16.1)
  • mto: This revision was merged to the branch mainline in revision 97.
  • Revision ID: package-import@ubuntu.com-20130909005732-dn1eell8srqbhh0e
Tags: upstream-2.2.5
ImportĀ upstreamĀ versionĀ 2.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2005-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "auth-common.h"
4
4
#include "ioloop.h"
5
5
#include "array.h"
6
6
#include "aqueue.h"
7
 
#include "network.h"
 
7
#include "net.h"
8
8
#include "istream.h"
9
9
#include "ostream.h"
10
10
#include "hex-binary.h"
19
19
 
20
20
#define AUTH_WORKER_LOOKUP_TIMEOUT_SECS 60
21
21
#define AUTH_WORKER_MAX_IDLE_SECS (60*5)
 
22
#define AUTH_WORKER_ABORT_SECS 60
22
23
#define AUTH_WORKER_DELAY_WARN_SECS 3
23
24
#define AUTH_WORKER_DELAY_WARN_MIN_INTERVAL_SECS 300
24
25
 
25
26
struct auth_worker_request {
26
27
        unsigned int id;
27
28
        time_t created;
28
 
        const char *data_str;
 
29
        const char *data;
29
30
        auth_worker_callback_t *callback;
30
31
        void *context;
31
32
};
46
47
        unsigned int shutdown:1;
47
48
};
48
49
 
49
 
static ARRAY_DEFINE(connections, struct auth_worker_connection *) = ARRAY_INIT;
 
50
static ARRAY(struct auth_worker_connection *) connections = ARRAY_INIT;
50
51
static unsigned int idle_count = 0, auth_workers_with_errors = 0;
51
 
static ARRAY_DEFINE(worker_request_array, struct auth_worker_request *);
 
52
static ARRAY(struct auth_worker_request *) worker_request_array;
52
53
static struct aqueue *worker_request_queue;
53
54
static time_t auth_worker_last_warn;
54
55
static unsigned int auth_workers_throttle_count;
57
58
 
58
59
static void worker_input(struct auth_worker_connection *conn);
59
60
static void auth_worker_destroy(struct auth_worker_connection **conn,
60
 
                                const char *reason, bool restart);
 
61
                                const char *reason, bool restart) ATTR_NULL(2);
61
62
 
62
63
static void auth_worker_idle_timeout(struct auth_worker_connection *conn)
63
64
{
76
77
        auth_worker_destroy(&conn, "Lookup timed out", TRUE);
77
78
}
78
79
 
79
 
static void auth_worker_request_send(struct auth_worker_connection *conn,
 
80
static bool auth_worker_request_send(struct auth_worker_connection *conn,
80
81
                                     struct auth_worker_request *request)
81
82
{
82
83
        struct const_iovec iov[3];
 
84
        unsigned int age_secs = ioloop_time - request->created;
83
85
 
84
 
        if (ioloop_time - request->created > AUTH_WORKER_DELAY_WARN_SECS &&
 
86
        if (age_secs >= AUTH_WORKER_ABORT_SECS) {
 
87
                i_error("Aborting auth request that was queued for %d secs, "
 
88
                        "%d left in queue",
 
89
                        age_secs, aqueue_count(worker_request_queue));
 
90
                request->callback(t_strdup_printf(
 
91
                        "FAIL\t%d", PASSDB_RESULT_INTERNAL_FAILURE),
 
92
                        request->context);
 
93
                return FALSE;
 
94
        }
 
95
        if (age_secs >= AUTH_WORKER_DELAY_WARN_SECS &&
85
96
            ioloop_time - auth_worker_last_warn >
86
97
            AUTH_WORKER_DELAY_WARN_MIN_INTERVAL_SECS) {
87
98
                auth_worker_last_warn = ioloop_time;
88
99
                i_warning("auth workers: Auth request was queued for %d "
89
100
                          "seconds, %d left in queue "
90
101
                          "(see auth_worker_max_count)",
91
 
                          (int)(ioloop_time - request->created),
92
 
                          aqueue_count(worker_request_queue));
 
102
                          age_secs, aqueue_count(worker_request_queue));
93
103
        }
94
104
 
95
105
        request->id = ++conn->id_counter;
96
106
 
97
107
        iov[0].iov_base = t_strdup_printf("%d\t", request->id);
98
108
        iov[0].iov_len = strlen(iov[0].iov_base);
99
 
        iov[1].iov_base = request->data_str;
100
 
        iov[1].iov_len = strlen(request->data_str);
 
109
        iov[1].iov_base = request->data;
 
110
        iov[1].iov_len = strlen(request->data);
101
111
        iov[2].iov_base = "\n";
102
112
        iov[2].iov_len = 1;
103
113
 
104
 
        o_stream_sendv(conn->output, iov, 3);
 
114
        o_stream_nsendv(conn->output, iov, 3);
105
115
 
106
116
        i_assert(conn->request == NULL);
107
117
        conn->request = request;
110
120
        conn->to = timeout_add(AUTH_WORKER_LOOKUP_TIMEOUT_SECS * 1000,
111
121
                               auth_worker_call_timeout, conn);
112
122
        idle_count--;
 
123
        return TRUE;
113
124
}
114
125
 
115
126
static void auth_worker_request_send_next(struct auth_worker_connection *conn)
116
127
{
117
128
        struct auth_worker_request *request, *const *requestp;
118
129
 
119
 
        if (aqueue_count(worker_request_queue) == 0)
120
 
                return;
 
130
        do {
 
131
                if (aqueue_count(worker_request_queue) == 0)
 
132
                        return;
121
133
 
122
 
        requestp = array_idx(&worker_request_array,
123
 
                             aqueue_idx(worker_request_queue, 0));
124
 
        request = *requestp;
125
 
        aqueue_delete_tail(worker_request_queue);
126
 
        auth_worker_request_send(conn, request);
 
134
                requestp = array_idx(&worker_request_array,
 
135
                                     aqueue_idx(worker_request_queue, 0));
 
136
                request = *requestp;
 
137
                aqueue_delete_tail(worker_request_queue);
 
138
        } while (!auth_worker_request_send(conn, request));
127
139
}
128
140
 
129
141
static void auth_worker_send_handshake(struct auth_worker_connection *conn)
145
157
        binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
146
158
        str_append_c(str, '\n');
147
159
 
148
 
        o_stream_send(conn->output, str_data(str), str_len(str));
 
160
        o_stream_nsend(conn->output, str_data(str), str_len(str));
149
161
}
150
162
 
151
163
static struct auth_worker_connection *auth_worker_create(void)
173
185
        conn->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
174
186
                                         FALSE);
175
187
        conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
 
188
        o_stream_set_no_error_handling(conn->output, TRUE);
176
189
        conn->io = io_add(fd, IO_READ, worker_input, conn);
177
190
        conn->to = timeout_add(AUTH_WORKER_MAX_IDLE_SECS * 1000,
178
191
                               auth_worker_idle_timeout, conn);
386
399
}
387
400
 
388
401
struct auth_worker_connection *
389
 
auth_worker_call(pool_t pool, struct auth_stream_reply *data,
 
402
auth_worker_call(pool_t pool, const char *data,
390
403
                 auth_worker_callback_t *callback, void *context)
391
404
{
392
405
        struct auth_worker_connection *conn;
394
407
 
395
408
        request = p_new(pool, struct auth_worker_request, 1);
396
409
        request->created = ioloop_time;
397
 
        request->data_str = p_strdup(pool, auth_stream_reply_export(data));
 
410
        request->data = p_strdup(pool, data);
398
411
        request->callback = callback;
399
412
        request->context = context;
400
413
 
409
422
                        conn = auth_worker_create();
410
423
                }
411
424
        }
412
 
        if (conn != NULL)
413
 
                auth_worker_request_send(conn, request);
414
 
        else {
 
425
        if (conn != NULL) {
 
426
                if (!auth_worker_request_send(conn, request))
 
427
                        i_unreached();
 
428
        } else {
415
429
                /* reached the limit, queue the request */
416
430
                aqueue_append(worker_request_queue, &request);
417
431
        }