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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
|
/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "connection.h"
#include "imap-master-connection.h"
#define IMAP_MASTER_CONNECTION_TIMEOUT_MSECS 30000
struct imap_master_connection {
struct connection conn;
struct timeout *to;
imap_master_connection_send_callback_t *send_callback;
imap_master_connection_read_callback_t *read_callback;
void *context;
};
static struct connection_list *master_clients;
static void imap_master_connection_timeout(struct imap_master_connection *conn)
{
e_error(conn->conn.event,
"Timeout communicating with %s (version %sreceived)",
conn->conn.name, conn->conn.version_received ? "" : "not ");
imap_master_connection_deinit(&conn);
}
int imap_master_connection_init(const char *path,
imap_master_connection_send_callback_t *send_callback,
imap_master_connection_read_callback_t *read_callback,
void *context,
struct imap_master_connection **conn_r,
const char **error_r)
{
struct imap_master_connection *conn;
conn = i_new(struct imap_master_connection, 1);
conn->send_callback = send_callback;
conn->read_callback = read_callback;
conn->context = context;
connection_init_client_unix(master_clients, &conn->conn, path);
if (connection_client_connect(&conn->conn) < 0) {
int ret = errno == EAGAIN ? 0 : -1;
*error_r = t_strdup_printf(
"net_connect_unix(%s) failed: %m", path);
connection_deinit(&conn->conn);
i_free(conn);
return ret;
}
conn->to = timeout_add(IMAP_MASTER_CONNECTION_TIMEOUT_MSECS,
imap_master_connection_timeout, conn);
*conn_r = conn;
return 1;
}
static void
imap_master_read_callback(struct imap_master_connection **_conn,
const char *line)
{
struct imap_master_connection *conn = *_conn;
imap_master_connection_read_callback_t *read_callback =
conn->read_callback;
*_conn = NULL;
conn->read_callback = NULL;
read_callback(conn->context, line);
/* connection is destroyed now */
}
void imap_master_connection_deinit(struct imap_master_connection **_conn)
{
imap_master_read_callback(_conn, t_strdup_printf(
"-%s", connection_disconnect_reason(&(*_conn)->conn)));
}
void imap_master_connection_free(struct imap_master_connection **_conn)
{
struct imap_master_connection *conn = *_conn;
*_conn = NULL;
timeout_remove(&conn->to);
connection_deinit(&conn->conn);
i_free(conn);
}
static void imap_master_client_destroy(struct connection *_conn)
{
struct imap_master_connection *conn =
(struct imap_master_connection *)_conn;
imap_master_connection_deinit(&conn);
}
static int
imap_master_client_input_line(struct connection *_conn, const char *line)
{
struct imap_master_connection *conn =
(struct imap_master_connection *)_conn;
if (!_conn->version_received) {
if (connection_input_line_default(_conn, line) < 0)
return -1;
conn->send_callback(conn->context, _conn->output);
return 1;
} else {
imap_master_read_callback(&conn, line);
/* we're finished now with this connection - disconnect it */
return -1;
}
}
static struct connection_settings client_set = {
.service_name_in = "imap-master",
.service_name_out = "imap-master",
.major_version = 1,
.minor_version = 0,
.input_max_size = SIZE_MAX,
.output_max_size = SIZE_MAX,
.client = TRUE
};
static const struct connection_vfuncs client_vfuncs = {
.destroy = imap_master_client_destroy,
.input_line = imap_master_client_input_line
};
void imap_master_connections_init(void)
{
master_clients = connection_list_init(&client_set, &client_vfuncs);
}
void imap_master_connections_deinit(void)
{
connection_list_deinit(&master_clients);
}
|