~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/replication/replicator/doveadm-connection.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
 
#include "ioloop.h"
5
 
#include "network.h"
6
 
#include "istream.h"
 
4
#include "connection.h"
7
5
#include "ostream.h"
8
6
#include "str.h"
9
7
#include "strescape.h"
 
8
#include "wildcard-match.h"
 
9
#include "master-service.h"
 
10
#include "replicator-queue.h"
10
11
#include "doveadm-connection.h"
11
12
 
12
13
#include <unistd.h>
13
14
 
14
 
#define DOVEADM_FAIL_TIMEOUT_MSECS (1000*5)
15
 
#define DOVEADM_HANDSHAKE "VERSION\tdoveadm-server\t1\t0\n"
16
 
#define MAX_INBUF_SIZE 1024
 
15
#define REPLICATOR_DOVEADM_MAJOR_VERSION 1
 
16
#define REPLICATOR_DOVEADM_MINOR_VERSION 0
17
17
 
18
18
struct doveadm_connection {
19
 
        char *path;
20
 
        int fd;
21
 
        struct io *io;
22
 
        struct istream *input;
23
 
        struct ostream *output;
24
 
        struct timeout *to;
25
 
 
26
 
        doveadm_callback_t *callback;
27
 
        void *context;
28
 
 
29
 
        time_t last_connect_failure;
30
 
        unsigned int handshaked:1;
31
 
        unsigned int end_of_print:1;
 
19
        struct connection conn;
 
20
        struct replicator_queue *queue;
32
21
};
33
 
 
34
 
struct doveadm_connection *doveadm_connection_init(const char *path)
35
 
{
36
 
        struct doveadm_connection *conn;
37
 
 
38
 
        conn = i_new(struct doveadm_connection, 1);
39
 
        conn->path = i_strdup(path);
40
 
        conn->fd = -1;
41
 
        return conn;
42
 
}
43
 
 
44
 
static void doveadm_callback(struct doveadm_connection *conn,
45
 
                             enum doveadm_reply reply)
46
 
{
47
 
        doveadm_callback_t *callback = conn->callback;
48
 
        void *context = conn->context;
49
 
 
50
 
        if (conn->to != NULL)
51
 
                timeout_remove(&conn->to);
52
 
 
53
 
        conn->callback = NULL;
54
 
        conn->context = NULL;
55
 
        callback(reply, context);
56
 
}
57
 
 
58
 
static void doveadm_disconnect(struct doveadm_connection *conn)
59
 
{
60
 
        if (conn->fd == -1)
61
 
                return;
62
 
 
63
 
        io_remove(&conn->io);
64
 
        o_stream_destroy(&conn->output);
65
 
        i_stream_destroy(&conn->input);
66
 
        if (close(conn->fd) < 0)
67
 
                i_error("close(doveadm) failed: %m");
68
 
        conn->fd = -1;
69
 
 
70
 
        if (conn->callback != NULL)
71
 
                doveadm_callback(conn, DOVEADM_REPLY_FAIL);
72
 
}
73
 
 
74
 
void doveadm_connection_deinit(struct doveadm_connection **_conn)
75
 
{
76
 
        struct doveadm_connection *conn = *_conn;
77
 
 
78
 
        *_conn = NULL;
79
 
 
80
 
        doveadm_disconnect(conn);
81
 
        i_free(conn->path);
82
 
        i_free(conn);
83
 
}
84
 
 
85
 
static int doveadm_input_line(struct doveadm_connection *conn, const char *line)
86
 
{
87
 
        if (!conn->handshaked) {
88
 
                if (strcmp(line, "+") != 0) {
89
 
                        i_error("%s: Unexpected handshake: %s",
90
 
                                conn->path, line);
91
 
                        return -1;
 
22
static struct connection_list *doveadm_connections;
 
23
 
 
24
static int client_input_status_overview(struct doveadm_connection *client)
 
25
{
 
26
        struct replicator_queue_iter *iter;
 
27
        struct replicator_user *user;
 
28
        enum replication_priority priority;
 
29
        unsigned int pending_counts[REPLICATION_PRIORITY_SYNC+1];
 
30
        unsigned int user_count, next_secs, pending_failed_count;
 
31
        unsigned int pending_full_resync_count, waiting_failed_count;
 
32
        string_t *str = t_str_new(256);
 
33
 
 
34
        memset(pending_counts, 0, sizeof(pending_counts));
 
35
        pending_failed_count = 0; waiting_failed_count = 0;
 
36
        pending_full_resync_count = 0;
 
37
 
 
38
        user_count = 0;
 
39
        iter = replicator_queue_iter_init(client->queue);
 
40
        while ((user = replicator_queue_iter_next(iter)) != NULL) {
 
41
                if (user->priority != REPLICATION_PRIORITY_NONE)
 
42
                        pending_counts[user->priority]++;
 
43
                else if (replicator_queue_want_sync_now(client->queue,
 
44
                                                        user, &next_secs)) {
 
45
                        if (user->last_sync_failed)
 
46
                                pending_failed_count++;
 
47
                        else
 
48
                                pending_full_resync_count++;
 
49
                } else {
 
50
                        if (user->last_sync_failed)
 
51
                                waiting_failed_count++;
92
52
                }
93
 
                conn->handshaked = TRUE;
94
 
                return 0;
95
 
        }
96
 
        if (conn->callback == NULL) {
97
 
                i_error("%s: Unexpected input: %s", conn->path, line);
98
 
                return -1;
99
 
        }
100
 
        if (!conn->end_of_print) {
101
 
                if (line[0] == '\0')
102
 
                        conn->end_of_print = TRUE;
103
 
                return 0;
104
 
        }
105
 
        if (line[0] == '+')
106
 
                doveadm_callback(conn, DOVEADM_REPLY_OK);
107
 
        else if (line[0] == '-') {
108
 
                if (strcmp(line+1, "NOUSER") == 0)
109
 
                        doveadm_callback(conn, DOVEADM_REPLY_NOUSER);
110
 
                else
111
 
                        doveadm_callback(conn, DOVEADM_REPLY_FAIL);
112
 
        } else {
113
 
                i_error("%s: Invalid input: %s", conn->path, line);
114
 
                return -1;
115
 
        }
116
 
        conn->end_of_print = FALSE;
117
 
        /* FIXME: disconnect after each request for now.
118
 
           doveadm server's getopt() handling seems to break otherwise */
 
53
                user_count++;
 
54
        }
 
55
        replicator_queue_iter_deinit(&iter);
 
56
 
 
57
        for (priority = REPLICATION_PRIORITY_SYNC; priority > 0; priority--) {
 
58
                str_printfa(str, "Queued '%s' requests\t%u\n",
 
59
                            replicator_priority_to_str(priority),
 
60
                            pending_counts[priority]);
 
61
        }
 
62
        str_printfa(str, "Queued 'failed' requests\t%u\n",
 
63
                    pending_failed_count);
 
64
        str_printfa(str, "Queued 'full resync' requests\t%u\n",
 
65
                    pending_full_resync_count);
 
66
        str_printfa(str, "Waiting 'failed' requests\t%u\n",
 
67
                    waiting_failed_count);
 
68
        str_printfa(str, "Total number of known users\t%u\n", user_count);
 
69
        str_append_c(str, '\n');
 
70
        o_stream_send(client->conn.output, str_data(str), str_len(str));
 
71
        return 0;
 
72
}
 
73
 
 
74
static int
 
75
client_input_status(struct doveadm_connection *client, const char *const *args)
 
76
{
 
77
        struct replicator_queue_iter *iter;
 
78
        struct replicator_user *user;
 
79
        const char *mask = args[0];
 
80
        string_t *str = t_str_new(128);
 
81
 
 
82
        if (mask == NULL)
 
83
                return client_input_status_overview(client);
 
84
 
 
85
        iter = replicator_queue_iter_init(client->queue);
 
86
        while ((user = replicator_queue_iter_next(iter)) != NULL) {
 
87
                if (!wildcard_match(user->username, mask))
 
88
                        continue;
 
89
 
 
90
                str_truncate(str, 0);
 
91
                str_append_tabescaped(str, user->username);
 
92
                str_append_c(str, '\t');
 
93
                str_append(str, replicator_priority_to_str(user->priority));
 
94
                str_printfa(str, "\t%lld\t%lld\t%d\n",
 
95
                            (long long)user->last_fast_sync,
 
96
                            (long long)user->last_full_sync,
 
97
                            user->last_sync_failed);
 
98
                o_stream_send(client->conn.output, str_data(str), str_len(str));
 
99
        }
 
100
        replicator_queue_iter_deinit(&iter);
 
101
        o_stream_send(client->conn.output, "\n", 1);
 
102
        return 0;
 
103
}
 
104
 
 
105
static int
 
106
client_input_replicate(struct doveadm_connection *client, const char *const *args)
 
107
{
 
108
        struct replicator_queue_iter *iter;
 
109
        struct replicator_user *user;
 
110
        const char *usermask;
 
111
        enum replication_priority priority;
 
112
        unsigned int match_count;
 
113
 
 
114
        /* <priority> <username>|<mask> */
 
115
        if (str_array_length(args) != 2) {
 
116
                i_error("%s: REPLICATE: Invalid parameters", client->conn.name);
 
117
                return -1;
 
118
        }
 
119
        if (replication_priority_parse(args[0], &priority) < 0) {
 
120
                o_stream_send_str(client->conn.output, "-Invalid priority\n");
 
121
                return 0;
 
122
        }
 
123
        usermask = args[1];
 
124
        if (strchr(usermask, '*') == NULL && strchr(usermask, '?') == NULL) {
 
125
                replicator_queue_add(client->queue, usermask, priority);
 
126
                o_stream_send_str(client->conn.output, "+1\n");
 
127
                return 0;
 
128
        }
 
129
 
 
130
        match_count = 0;
 
131
        iter = replicator_queue_iter_init(client->queue);
 
132
        while ((user = replicator_queue_iter_next(iter)) != NULL) {
 
133
                if (!wildcard_match(user->username, usermask))
 
134
                        continue;
 
135
                replicator_queue_add(client->queue, user->username, priority);
 
136
                match_count++;
 
137
        }
 
138
        replicator_queue_iter_deinit(&iter);
 
139
        o_stream_send_str(client->conn.output,
 
140
                          t_strdup_printf("+%u\n", match_count));
 
141
        return 0;
 
142
}
 
143
 
 
144
static int
 
145
client_input_remove(struct doveadm_connection *client, const char *const *args)
 
146
{
 
147
        struct replicator_user *user;
 
148
 
 
149
        /* <username> */
 
150
        if (str_array_length(args) != 1) {
 
151
                i_error("%s: REMOVE: Invalid parameters", client->conn.name);
 
152
                return -1;
 
153
        }
 
154
        user = replicator_queue_lookup(client->queue, args[0]);
 
155
        if (user == NULL)
 
156
                o_stream_send_str(client->conn.output, "-User not found\n");
 
157
        else {
 
158
                replicator_queue_remove(client->queue, &user);
 
159
                o_stream_send_str(client->conn.output, "+\n");
 
160
        }
 
161
        return 0;
 
162
}
 
163
 
 
164
static int
 
165
client_input_notify(struct doveadm_connection *client, const char *const *args)
 
166
{
 
167
        struct replicator_user *user;
 
168
 
 
169
        /* <username> <flags> <state> */
 
170
        if (str_array_length(args) < 3) {
 
171
                i_error("%s: NOTIFY: Invalid parameters", client->conn.name);
 
172
                return -1;
 
173
        }
 
174
 
 
175
        user = replicator_queue_add(client->queue, args[0],
 
176
                                    REPLICATION_PRIORITY_NONE);
 
177
        if (args[1][0] == 'f')
 
178
                user->last_full_sync = ioloop_time;
 
179
        user->last_fast_sync = ioloop_time;
 
180
        user->last_update = ioloop_time;
 
181
 
 
182
        if (args[2][0] != '\0') {
 
183
                i_free(user->state);
 
184
                user->state = i_strdup(args[2]);
 
185
        }
 
186
        o_stream_send_str(client->conn.output, "+\n");
 
187
        return 0;
 
188
}
 
189
 
 
190
static int client_input_args(struct connection *conn, const char *const *args)
 
191
{
 
192
        struct doveadm_connection *client = (struct doveadm_connection *)conn;
 
193
        const char *cmd = args[0];
 
194
 
 
195
        if (cmd == NULL) {
 
196
                i_error("%s: Empty command", conn->name);
 
197
                return 0;
 
198
        }
 
199
        args++;
 
200
 
 
201
        if (strcmp(cmd, "STATUS") == 0)
 
202
                return client_input_status(client, args);
 
203
        else if (strcmp(cmd, "REPLICATE") == 0)
 
204
                return client_input_replicate(client, args);
 
205
        else if (strcmp(cmd, "REMOVE") == 0)
 
206
                return client_input_remove(client, args);
 
207
        else if (strcmp(cmd, "NOTIFY") == 0)
 
208
                return client_input_notify(client, args);
 
209
        i_error("%s: Unknown command: %s", conn->name, cmd);
119
210
        return -1;
120
211
}
121
212
 
122
 
static void doveadm_input(struct doveadm_connection *conn)
123
 
{
124
 
        const char *line;
125
 
 
126
 
        while ((line = i_stream_read_next_line(conn->input)) != NULL) {
127
 
                if (doveadm_input_line(conn, line) < 0) {
128
 
                        doveadm_disconnect(conn);
129
 
                        return;
130
 
                }
131
 
        }
132
 
        if (conn->input->eof)
133
 
                doveadm_disconnect(conn);
134
 
}
135
 
 
136
 
static int doveadm_connect(struct doveadm_connection *conn)
137
 
{
138
 
        if (conn->fd != -1)
139
 
                return 0;
140
 
 
141
 
        if (conn->last_connect_failure == ioloop_time)
142
 
                return -1;
143
 
 
144
 
        conn->fd = net_connect_unix(conn->path);
145
 
        if (conn->fd == -1) {
146
 
                i_error("net_connect_unix(%s) failed: %m", conn->path);
147
 
                conn->last_connect_failure = ioloop_time;
148
 
                return -1;
149
 
        }
150
 
        conn->last_connect_failure = 0;
151
 
        conn->io = io_add(conn->fd, IO_READ, doveadm_input, conn);
152
 
        conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE, FALSE);
153
 
        conn->output = o_stream_create_fd(conn->fd, (size_t)-1, FALSE);
154
 
        o_stream_send_str(conn->output, DOVEADM_HANDSHAKE);
155
 
        return 0;
156
 
}
157
 
 
158
 
static void doveadm_fail_timeout(struct doveadm_connection *conn)
159
 
{
160
 
        doveadm_callback(conn, DOVEADM_REPLY_FAIL);
161
 
}
162
 
 
163
 
void doveadm_connection_sync(struct doveadm_connection *conn,
164
 
                             const char *username, bool full,
165
 
                             doveadm_callback_t *callback, void *context)
166
 
{
167
 
        string_t *cmd;
168
 
 
169
 
        i_assert(callback != NULL);
170
 
        i_assert(!doveadm_connection_is_busy(conn));
171
 
 
172
 
        conn->callback = callback;
173
 
        conn->context = context;
174
 
 
175
 
        if (doveadm_connect(conn) < 0) {
176
 
                i_assert(conn->to == NULL);
177
 
                conn->to = timeout_add(DOVEADM_FAIL_TIMEOUT_MSECS,
178
 
                                       doveadm_fail_timeout, conn);
179
 
        } else {
180
 
                /* <flags> <username> <command> [<args>] */
181
 
                cmd = t_str_new(256);
182
 
                str_append_c(cmd, '\t');
183
 
                str_tabescape_write(cmd, username);
184
 
                str_append(cmd, "\tsync\t-d");
185
 
                if (full)
186
 
                        str_append(cmd, "\t-f");
187
 
                str_append_c(cmd, '\n');
188
 
                o_stream_send(conn->output, str_data(cmd), str_len(cmd));
189
 
        }
190
 
}
191
 
 
192
 
bool doveadm_connection_is_busy(struct doveadm_connection *conn)
193
 
{
194
 
        return conn->callback != NULL;
 
213
static void client_destroy(struct connection *conn)
 
214
{
 
215
        struct doveadm_connection *client = (struct doveadm_connection *)conn;
 
216
 
 
217
        connection_deinit(&client->conn);
 
218
        i_free(client);
 
219
 
 
220
        master_service_client_connection_destroyed(master_service);
 
221
}
 
222
 
 
223
void doveadm_connection_create(struct replicator_queue *queue, int fd)
 
224
{
 
225
        struct doveadm_connection *client;
 
226
 
 
227
        client = i_new(struct doveadm_connection, 1);
 
228
        client->queue = queue;
 
229
        connection_init_server(doveadm_connections, &client->conn,
 
230
                               "(doveadm client)", fd, fd);
 
231
}
 
232
 
 
233
static struct connection_settings doveadm_conn_set = {
 
234
        .service_name_in = "replicator-doveadm-client",
 
235
        .service_name_out = "replicator-doveadm-server",
 
236
        .major_version = REPLICATOR_DOVEADM_MAJOR_VERSION,
 
237
        .minor_version = REPLICATOR_DOVEADM_MINOR_VERSION,
 
238
 
 
239
        .input_max_size = (size_t)-1,
 
240
        .output_max_size = (size_t)-1,
 
241
        .client = FALSE
 
242
};
 
243
 
 
244
static const struct connection_vfuncs doveadm_conn_vfuncs = {
 
245
        .destroy = client_destroy,
 
246
        .input_args = client_input_args
 
247
};
 
248
 
 
249
void doveadm_connections_init(void)
 
250
{
 
251
        doveadm_connections = connection_list_init(&doveadm_conn_set,
 
252
                                                   &doveadm_conn_vfuncs);
 
253
}
 
254
 
 
255
void doveadm_connections_deinit(void)
 
256
{
 
257
        connection_list_deinit(&doveadm_connections);
195
258
}