1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "str.h"
5 #include "ioloop.h"
6 #include "istream.h"
7 #include "istream-unix.h"
8 #include "ostream.h"
9 #include "ostream-unix.h"
10 #include "iostream.h"
11 #include "net.h"
12 #include "strescape.h"
13 #include "llist.h"
14 #include "time-util.h"
15 #include "connection.h"
16
17 #include <unistd.h>
18 #include <libgen.h>
19
connection_handshake_ready(struct connection * conn)20 static void connection_handshake_ready(struct connection *conn)
21 {
22 conn->handshake_received = TRUE;
23 if (conn->v.handshake_ready != NULL)
24 conn->v.handshake_ready(conn);
25 }
26
connection_closed(struct connection * conn,enum connection_disconnect_reason reason)27 static void connection_closed(struct connection *conn,
28 enum connection_disconnect_reason reason)
29 {
30 conn->disconnect_reason = reason;
31 conn->v.destroy(conn);
32 }
33
connection_idle_timeout(struct connection * conn)34 static void connection_idle_timeout(struct connection *conn)
35 {
36 connection_closed(conn, CONNECTION_DISCONNECT_IDLE_TIMEOUT);
37 }
38
connection_connect_timeout(struct connection * conn)39 static void connection_connect_timeout(struct connection *conn)
40 {
41 connection_closed(conn, CONNECTION_DISCONNECT_CONNECT_TIMEOUT);
42 }
43
connection_input_default(struct connection * conn)44 void connection_input_default(struct connection *conn)
45 {
46 const char *line;
47 struct istream *input;
48 struct ostream *output;
49 int ret = 0;
50
51 if (!conn->handshake_received &&
52 conn->v.handshake != NULL) {
53 if ((ret = conn->v.handshake(conn)) < 0) {
54 connection_closed(
55 conn, CONNECTION_DISCONNECT_HANDSHAKE_FAILED);
56 return;
57 } else if (ret == 0) {
58 return;
59 } else {
60 connection_handshake_ready(conn);
61 }
62 }
63
64 switch (connection_input_read(conn)) {
65 case -1:
66 return;
67 case 0: /* allow calling this function for buffered input */
68 case 1:
69 break;
70 default:
71 i_unreached();
72 }
73
74 input = conn->input;
75 output = conn->output;
76 i_stream_ref(input);
77 if (output != NULL) {
78 o_stream_ref(output);
79 o_stream_cork(output);
80 }
81 while (!input->closed && (line = i_stream_next_line(input)) != NULL) {
82 T_BEGIN {
83 if (!conn->handshake_received &&
84 conn->v.handshake_line != NULL) {
85 ret = conn->v.handshake_line(conn, line);
86 if (ret > 0)
87 connection_handshake_ready(conn);
88 else if (ret == 0)
89 /* continue reading */
90 ret = 1;
91 else
92 conn->disconnect_reason =
93 CONNECTION_DISCONNECT_HANDSHAKE_FAILED;
94 } else {
95 ret = conn->v.input_line(conn, line);
96 }
97 } T_END;
98 if (ret <= 0)
99 break;
100 }
101 if (output != NULL) {
102 o_stream_uncork(output);
103 o_stream_unref(&output);
104 }
105 if (ret < 0 && !input->closed) {
106 enum connection_disconnect_reason reason =
107 conn->disconnect_reason;
108 if (reason == CONNECTION_DISCONNECT_NOT)
109 reason = CONNECTION_DISCONNECT_DEINIT;
110 connection_closed(conn, reason);
111 }
112 i_stream_unref(&input);
113 }
114
connection_verify_version(struct connection * conn,const char * service_name,unsigned int major_version,unsigned int minor_version)115 int connection_verify_version(struct connection *conn,
116 const char *service_name,
117 unsigned int major_version,
118 unsigned int minor_version)
119 {
120 i_assert(!conn->version_received);
121
122 if (strcmp(service_name, conn->list->set.service_name_in) != 0) {
123 e_error(conn->event, "Connected to wrong socket type. "
124 "We want '%s', but received '%s'",
125 conn->list->set.service_name_in, service_name);
126 return -1;
127 }
128
129 if (major_version != conn->list->set.major_version) {
130 e_error(conn->event, "Socket supports major version %u, "
131 "but we support only %u (mixed old and new binaries?)",
132 major_version, conn->list->set.major_version);
133 return -1;
134 }
135
136 conn->minor_version = minor_version;
137 conn->version_received = TRUE;
138 return 0;
139 }
140
connection_handshake_args_default(struct connection * conn,const char * const * args)141 int connection_handshake_args_default(struct connection *conn,
142 const char *const *args)
143 {
144 unsigned int major_version, minor_version;
145
146 if (conn->version_received)
147 return 1;
148
149 /* VERSION <tab> service_name <tab> major version <tab> minor version */
150 if (str_array_length(args) != 4 ||
151 strcmp(args[0], "VERSION") != 0 ||
152 str_to_uint(args[2], &major_version) < 0 ||
153 str_to_uint(args[3], &minor_version) < 0) {
154 e_error(conn->event, "didn't reply with a valid VERSION line: %s",
155 t_strarray_join(args, "\t"));
156 return -1;
157 }
158
159 if (connection_verify_version(conn, args[1],
160 major_version, minor_version) < 0)
161 return -1;
162 return 1;
163 }
164
connection_input_line_default(struct connection * conn,const char * line)165 int connection_input_line_default(struct connection *conn, const char *line)
166 {
167 const char *const *args;
168
169 args = t_strsplit_tabescaped(line);
170 if (args[0] == NULL && !conn->list->set.allow_empty_args_input) {
171 e_error(conn->event, "Unexpectedly received empty line");
172 return -1;
173 }
174
175 if (!conn->handshake_received &&
176 (conn->v.handshake_args != connection_handshake_args_default ||
177 conn->list->set.major_version != 0)) {
178 int ret;
179 if ((ret = conn->v.handshake_args(conn, args)) == 0)
180 ret = 1; /* continue reading */
181 else if (ret > 0)
182 connection_handshake_ready(conn);
183 else {
184 conn->disconnect_reason =
185 CONNECTION_DISCONNECT_HANDSHAKE_FAILED;
186 }
187 return ret;
188 } else if (!conn->handshake_received) {
189 /* we don't do handshakes */
190 connection_handshake_ready(conn);
191 }
192
193 /* version must be handled though, by something */
194 i_assert(conn->version_received);
195
196 return conn->v.input_args(conn, args);
197 }
198
connection_input_halt(struct connection * conn)199 void connection_input_halt(struct connection *conn)
200 {
201 io_remove(&conn->io);
202 timeout_remove(&conn->to);
203 }
204
205 static void
connection_input_resume_full(struct connection * conn,bool set_io_pending)206 connection_input_resume_full(struct connection *conn, bool set_io_pending)
207 {
208 i_assert(!conn->disconnected);
209
210 if (conn->io != NULL) {
211 /* do nothing */
212 } else if (conn->input != NULL) {
213 conn->io = io_add_istream_to(conn->ioloop, conn->input,
214 *conn->v.input, conn);
215 if (set_io_pending)
216 io_set_pending(conn->io);
217 } else if (conn->fd_in != -1) {
218 conn->io = io_add_to(conn->ioloop, conn->fd_in, IO_READ,
219 *conn->v.input, conn);
220 if (set_io_pending)
221 io_set_pending(conn->io);
222 }
223 if (conn->input_idle_timeout_secs != 0 && conn->to == NULL) {
224 conn->to = timeout_add_to(conn->ioloop,
225 conn->input_idle_timeout_secs*1000,
226 *conn->v.idle_timeout, conn);
227 }
228 }
229
connection_input_resume(struct connection * conn)230 void connection_input_resume(struct connection *conn)
231 {
232 connection_input_resume_full(conn, TRUE);
233 }
234
235 static void
connection_update_property_label(struct connection * conn)236 connection_update_property_label(struct connection *conn)
237 {
238 const char *label;
239
240 if (conn->remote_ip.family == 0) {
241 if (conn->remote_uid == (uid_t)-1)
242 label = NULL;
243 else if (conn->remote_pid != (pid_t)-1) {
244 label = t_strdup_printf("pid=%ld,uid=%ld",
245 (long)conn->remote_pid,
246 (long)conn->remote_uid);
247 } else {
248 label = t_strdup_printf("uid=%ld",
249 (long)conn->remote_uid);
250 }
251 } else if (conn->remote_ip.family == AF_INET6) {
252 label = t_strdup_printf("[%s]:%u",
253 net_ip2addr(&conn->remote_ip),
254 conn->remote_port);
255 } else {
256 label = t_strdup_printf("%s:%u",
257 net_ip2addr(&conn->remote_ip),
258 conn->remote_port);
259 }
260
261 i_free(conn->property_label);
262 conn->property_label = i_strdup(label);
263 }
264
265 static void
connection_update_label(struct connection * conn)266 connection_update_label(struct connection *conn)
267 {
268 bool unix_socket = conn->unix_socket ||
269 (conn->remote_ip.family == 0 && conn->remote_uid != (uid_t)-1);
270 string_t *label;
271
272 label = t_str_new(64);
273 if (conn->base_name != NULL)
274 str_append(label, conn->base_name);
275 if (conn->property_label != NULL) {
276 if (str_len(label) == 0)
277 str_append(label, conn->property_label);
278 else {
279 str_append(label, " (");
280 str_append(label, conn->property_label);
281 str_append(label, ")");
282 }
283 }
284 if (str_len(label) == 0) {
285 if (conn->fd_in >= 0 &&
286 (conn->fd_in == conn->fd_out || conn->fd_out < 0))
287 str_printfa(label, "fd=%d", conn->fd_in);
288 else if (conn->fd_in < 0 && conn->fd_out >= 0)
289 str_printfa(label, "fd=%d", conn->fd_out);
290 else if (conn->fd_in >= 0 && conn->fd_out >= 0) {
291 str_printfa(label, "fd_in=%d,fd_out=%d",
292 conn->fd_in, conn->fd_out);
293 }
294 }
295 if (unix_socket && str_len(label) > 0)
296 str_insert(label, 0, "unix:");
297 if (conn->list->set.log_connection_id) {
298 if (str_len(label) > 0)
299 str_append_c(label, ' ');
300 str_printfa(label, "[%u]", conn->id);
301 }
302
303 i_free(conn->label);
304 conn->label = i_strdup(str_c(label));
305 }
306
307 static const char *
connection_create_stream_name(struct connection * conn,int fd)308 connection_create_stream_name(struct connection *conn, int fd)
309 {
310 string_t *name;
311
312 name = t_str_new(64);
313 str_append(name, "(conn");
314 if (conn->unix_socket ||
315 (conn->remote_ip.family == 0 && conn->remote_uid != (uid_t)-1))
316 str_append(name, ":unix");
317 if (conn->base_name != NULL) {
318 str_append_c(name, ':');
319 str_append(name, conn->base_name);
320 } else if (conn->property_label != NULL) {
321 str_append_c(name, ':');
322 str_append(name, conn->property_label);
323 } else if (fd >= 0) {
324 str_printfa(name, ":fd=%d", fd);
325 }
326 if (conn->list->set.log_connection_id) {
327 if (str_len(name) == 5)
328 str_append_c(name, ':');
329 else
330 str_append_c(name, ',');
331 str_printfa(name, "id=%u", conn->id);
332 }
333 str_append_c(name, ')');
334
335 return str_c(name);
336 }
337
connection_update_stream_names(struct connection * conn)338 static void connection_update_stream_names(struct connection *conn)
339 {
340 if (conn->input != NULL) {
341 i_stream_set_name(
342 conn->input,
343 connection_create_stream_name(conn, conn->fd_in));
344 }
345 if (conn->output != NULL) {
346 o_stream_set_name(
347 conn->output,
348 connection_create_stream_name(conn, conn->fd_out));
349 }
350 }
351
connection_update_event(struct connection * conn)352 void connection_update_event(struct connection *conn)
353 {
354 string_t *prefix;
355
356 prefix = t_str_new(64);
357 str_append(prefix, "conn");
358 if (strlen(conn->label) > 0) {
359 str_append_c(prefix, ' ');
360 str_append(prefix, conn->label);
361 }
362 str_append(prefix, ": ");
363 event_set_append_log_prefix(conn->event, str_c(prefix));
364
365 if (conn->local_ip.family > 0) {
366 event_add_str(conn->event, conn->list->set.client ?
367 "source_ip" : "local_ip",
368 net_ip2addr(&conn->local_ip));
369 }
370
371 if (conn->remote_ip.family > 0) {
372 event_add_str(conn->event, conn->list->set.client ?
373 "dest_ip" : "remote_ip",
374 net_ip2addr(&conn->remote_ip));
375 }
376 if (conn->remote_port > 0) {
377 event_add_int(conn->event, conn->list->set.client ?
378 "dest_port" : "remote_port",
379 conn->remote_port);
380 }
381
382 if (conn->remote_pid != (pid_t)-1)
383 event_add_int(conn->event, "remote_pid", conn->remote_pid);
384 if (conn->remote_uid != (uid_t)-1)
385 event_add_int(conn->event, "remote_uid", conn->remote_uid);
386 }
387
388 static void
connection_update_properties(struct connection * conn)389 connection_update_properties(struct connection *conn)
390 {
391 int fd = (conn->fd_in < 0 ? conn->fd_out : conn->fd_in);
392 struct net_unix_cred cred;
393
394 if (conn->remote_ip.family != 0) {
395 /* remote IP was already set */
396 } else if (conn->unix_peer_checked) {
397 /* already checked */
398 } else if (fd < 0) {
399 /* not connected yet - wait */
400 } else {
401 if (net_getpeername(fd, &conn->remote_ip,
402 &conn->remote_port) == 0) {
403 /* either TCP or UNIX socket connection */
404 errno = 0;
405 }
406
407 if (conn->remote_ip.family != 0) {
408 /* TCP connection */
409 i_assert(conn->remote_port != 0);
410 } else if (errno == ENOTSOCK) {
411 /* getpeername() already found out this can't be a UNIX
412 socket connection */
413 } else if (net_getunixcred(fd, &cred) == 0) {
414 conn->remote_pid = cred.pid;
415 conn->remote_uid = cred.uid;
416 }
417 conn->unix_peer_checked = TRUE;
418 }
419
420 connection_update_property_label(conn);
421 connection_update_label(conn);
422 connection_update_stream_names(conn);
423 connection_update_event(conn);
424
425 conn->name = (conn->base_name != NULL ?
426 conn->base_name : conn->property_label);
427 }
428
connection_init_streams(struct connection * conn)429 static void connection_init_streams(struct connection *conn)
430 {
431 const struct connection_settings *set = &conn->list->set;
432
433 i_assert(conn->io == NULL);
434 i_assert(conn->input == NULL);
435 i_assert(conn->output == NULL);
436 i_assert(conn->to == NULL);
437
438 conn->handshake_received = FALSE;
439 conn->version_received = set->major_version == 0;
440
441 if (set->input_max_size != 0) {
442 if (conn->unix_socket)
443 conn->input = i_stream_create_unix(conn->fd_in,
444 set->input_max_size);
445 else
446 conn->input = i_stream_create_fd(conn->fd_in,
447 set->input_max_size);
448 i_stream_switch_ioloop_to(conn->input, conn->ioloop);
449 }
450 if (set->output_max_size != 0) {
451 if (conn->unix_socket)
452 conn->output = o_stream_create_unix(conn->fd_out,
453 set->output_max_size);
454 else
455 conn->output = o_stream_create_fd(conn->fd_out,
456 set->output_max_size);
457 o_stream_set_no_error_handling(conn->output, TRUE);
458 o_stream_set_finish_via_child(conn->output, FALSE);
459 o_stream_switch_ioloop_to(conn->output, conn->ioloop);
460 }
461 connection_update_stream_names(conn);
462
463 conn->disconnected = FALSE;
464 i_assert(conn->to == NULL);
465 connection_input_resume_full(conn, FALSE);
466 i_assert(conn->to != NULL || conn->input_idle_timeout_secs == 0);
467 if (set->major_version != 0 && !set->dont_send_version) {
468 e_debug(conn->event, "Sending version handshake");
469 o_stream_nsend_str(conn->output, t_strdup_printf(
470 "VERSION\t%s\t%u\t%u\n", set->service_name_out,
471 set->major_version, set->minor_version));
472 }
473 }
474
connection_streams_changed(struct connection * conn)475 void connection_streams_changed(struct connection *conn)
476 {
477 const struct connection_settings *set = &conn->list->set;
478
479 if (set->input_max_size != 0 && conn->io != NULL) {
480 connection_input_halt(conn);
481 connection_input_resume(conn);
482 }
483 }
484
connection_client_connected(struct connection * conn,bool success)485 static void connection_client_connected(struct connection *conn, bool success)
486 {
487 i_assert(conn->list->set.client);
488
489 connection_update_properties(conn);
490
491 conn->connect_finished = ioloop_timeval;
492
493 struct event_passthrough *e = event_create_passthrough(conn->event)->
494 set_name("server_connection_connected");
495 if (success) {
496 e_debug(e->event(), "Client connected (fd=%d)",
497 conn->fd_in);
498 } else {
499 e_debug(e->event(), "Client connection failed (fd=%d)",
500 conn->fd_in);
501 }
502
503 if (success)
504 connection_init_streams(conn);
505 if (conn->v.client_connected != NULL)
506 conn->v.client_connected(conn, success);
507 if (!success) {
508 connection_closed(conn, CONNECTION_DISCONNECT_CONN_CLOSED);
509 }
510 }
511
512 static void
connection_init_full(struct connection_list * list,struct connection * conn,const char * name,int fd_in,int fd_out)513 connection_init_full(struct connection_list *list, struct connection *conn,
514 const char *name, int fd_in, int fd_out)
515 {
516 if (conn->id == 0) {
517 if (list->id_counter == 0)
518 list->id_counter++;
519 conn->id = list->id_counter++;
520 }
521
522 conn->ioloop = current_ioloop;
523 conn->fd_in = fd_in;
524 conn->fd_out = fd_out;
525 conn->disconnected = TRUE;
526 conn->remote_uid = (uid_t)-1;
527 conn->remote_pid = (pid_t)-1;
528
529 i_free(conn->base_name);
530 conn->base_name = i_strdup(name);
531
532 if (list->set.input_idle_timeout_secs != 0 &&
533 conn->input_idle_timeout_secs == 0) {
534 conn->input_idle_timeout_secs =
535 list->set.input_idle_timeout_secs;
536 }
537
538 if (conn->event == NULL)
539 conn->event = event_create(conn->event_parent);
540 if (list->set.debug)
541 event_set_forced_debug(conn->event, TRUE);
542
543 if (conn->list != NULL) {
544 i_assert(conn->list == list);
545 } else {
546 conn->list = list;
547 DLLIST_PREPEND(&list->connections, conn);
548 list->connections_count++;
549 }
550
551 connection_update_properties(conn);
552 connection_set_default_handlers(conn);
553 }
554
connection_init(struct connection_list * list,struct connection * conn,const char * name)555 void connection_init(struct connection_list *list, struct connection *conn,
556 const char *name)
557 {
558 connection_init_full(list, conn, name, -1, -1);
559 }
560
connection_init_server(struct connection_list * list,struct connection * conn,const char * name,int fd_in,int fd_out)561 void connection_init_server(struct connection_list *list,
562 struct connection *conn, const char *name,
563 int fd_in, int fd_out)
564 {
565 i_assert(!list->set.client);
566
567 connection_init_full(list, conn, name, fd_in, fd_out);
568
569 struct event_passthrough *e = event_create_passthrough(conn->event)->
570 set_name("client_connection_connected");
571 /* fd_out differs from fd_in only for stdin/stdout. Keep the logging
572 output nice and clean by logging only the fd_in. If it's 0, it'll
573 also be obvious that fd_out=1. */
574 e_debug(e->event(), "Server accepted connection (fd=%d)", fd_in);
575
576 connection_init_streams(conn);
577 }
578
connection_init_server_ip(struct connection_list * list,struct connection * conn,const char * name,int fd_in,int fd_out,const struct ip_addr * remote_ip,in_port_t remote_port)579 void connection_init_server_ip(struct connection_list *list,
580 struct connection *conn, const char *name,
581 int fd_in, int fd_out,
582 const struct ip_addr *remote_ip,
583 in_port_t remote_port)
584 {
585 if (remote_ip != NULL && remote_ip->family != 0)
586 conn->remote_ip = *remote_ip;
587 if (remote_port != 0)
588 conn->remote_port = remote_port;
589
590 connection_init_server(list, conn, name, fd_in, fd_out);
591 }
592
connection_init_client_fd(struct connection_list * list,struct connection * conn,const char * name,int fd_in,int fd_out)593 void connection_init_client_fd(struct connection_list *list,
594 struct connection *conn, const char *name,
595 int fd_in, int fd_out)
596 {
597 i_assert(list->set.client);
598
599 connection_init_full(list, conn, name, fd_in, fd_out);
600
601 struct event_passthrough *e = event_create_passthrough(conn->event)->
602 set_name("server_connection_connected");
603 /* fd_out differs from fd_in only for stdin/stdout. Keep the logging
604 output nice and clean by logging only the fd_in. If it's 0, it'll
605 also be obvious that fd_out=1. */
606 e_debug(e->event(), "Client connected (fd=%d)", fd_in);
607
608 connection_client_connected(conn, TRUE);
609 }
610
connection_init_client_ip_from(struct connection_list * list,struct connection * conn,const char * hostname,const struct ip_addr * ip,in_port_t port,const struct ip_addr * my_ip)611 void connection_init_client_ip_from(struct connection_list *list,
612 struct connection *conn,
613 const char *hostname,
614 const struct ip_addr *ip, in_port_t port,
615 const struct ip_addr *my_ip)
616 {
617 const char *name = NULL;
618
619 if (hostname != NULL)
620 name = t_strdup_printf("%s:%u", hostname, port);
621
622 i_assert(list->set.client);
623
624 conn->remote_ip = *ip;
625 conn->remote_port = port;
626
627 if (my_ip != NULL)
628 conn->local_ip = *my_ip;
629 else
630 i_zero(&conn->local_ip);
631
632 connection_init(list, conn, name);
633 if (hostname != NULL)
634 event_add_str(conn->event, "dest_host", hostname);
635 connection_update_event(conn);
636 }
637
connection_init_client_ip(struct connection_list * list,struct connection * conn,const char * hostname,const struct ip_addr * ip,in_port_t port)638 void connection_init_client_ip(struct connection_list *list,
639 struct connection *conn, const char *hostname,
640 const struct ip_addr *ip, in_port_t port)
641 {
642 connection_init_client_ip_from(list, conn, hostname, ip, port, NULL);
643 }
644
connection_init_client_unix(struct connection_list * list,struct connection * conn,const char * path)645 void connection_init_client_unix(struct connection_list *list,
646 struct connection *conn, const char *path)
647 {
648 i_assert(list->set.client);
649
650 conn->unix_socket = TRUE;
651
652 connection_init(list, conn, path);
653 event_add_str(conn->event, "socket_path", path);
654 }
655
connection_init_from_streams(struct connection_list * list,struct connection * conn,const char * name,struct istream * input,struct ostream * output)656 void connection_init_from_streams(struct connection_list *list,
657 struct connection *conn, const char *name,
658 struct istream *input, struct ostream *output)
659 {
660 connection_init_full(list, conn, name,
661 i_stream_get_fd(input), o_stream_get_fd(output));
662
663 i_assert(conn->fd_in >= 0);
664 i_assert(conn->fd_out >= 0);
665 i_assert(conn->io == NULL);
666 i_assert(conn->input == NULL);
667 i_assert(conn->output == NULL);
668 i_assert(conn->to == NULL);
669
670 conn->input = input;
671 i_stream_ref(conn->input);
672
673 conn->output = output;
674 o_stream_ref(conn->output);
675 o_stream_set_no_error_handling(conn->output, TRUE);
676
677 connection_update_stream_names(conn);
678
679 conn->disconnected = FALSE;
680 connection_input_resume_full(conn, FALSE);
681
682 if (conn->v.client_connected != NULL)
683 conn->v.client_connected(conn, TRUE);
684 }
685
connection_socket_connected(struct connection * conn)686 static void connection_socket_connected(struct connection *conn)
687 {
688 io_remove(&conn->io);
689 timeout_remove(&conn->to);
690
691 errno = net_geterror(conn->fd_in);
692 connection_client_connected(conn, errno == 0);
693 }
694
connection_client_connect(struct connection * conn)695 int connection_client_connect(struct connection *conn)
696 {
697 const struct connection_settings *set = &conn->list->set;
698 int fd;
699
700 i_assert(conn->list->set.client);
701 i_assert(conn->fd_in == -1);
702
703 e_debug(conn->event, "Connecting");
704
705 if (conn->remote_port != 0) {
706 fd = net_connect_ip(&conn->remote_ip, conn->remote_port,
707 (conn->local_ip.family != 0 ?
708 &conn->local_ip : NULL));
709 } else if (conn->list->set.unix_client_connect_msecs == 0) {
710 fd = net_connect_unix(conn->base_name);
711 } else {
712 fd = net_connect_unix_with_retries(
713 conn->base_name,
714 conn->list->set.unix_client_connect_msecs);
715 }
716 if (fd == -1)
717 return -1;
718 conn->fd_in = conn->fd_out = fd;
719 conn->connect_started = ioloop_timeval;
720 conn->disconnected = FALSE;
721
722 if (conn->remote_port != 0 ||
723 conn->list->set.delayed_unix_client_connected_callback) {
724 connection_update_properties(conn);
725 conn->io = io_add_to(conn->ioloop, conn->fd_out, IO_WRITE,
726 connection_socket_connected, conn);
727 e_debug(conn->event,
728 "Waiting for connect (fd=%d) to finish for max %u msecs",
729 fd, set->client_connect_timeout_msecs);
730 if (set->client_connect_timeout_msecs != 0) {
731 conn->to = timeout_add_to(conn->ioloop,
732 set->client_connect_timeout_msecs,
733 *conn->v.connect_timeout, conn);
734 }
735 } else {
736 connection_client_connected(conn, TRUE);
737 }
738 return 0;
739 }
740
connection_update_counters(struct connection * conn)741 static void connection_update_counters(struct connection *conn)
742 {
743 if (conn->input != NULL)
744 event_add_int(conn->event, "bytes_in", conn->input->v_offset);
745 if (conn->output != NULL)
746 event_add_int(conn->event, "bytes_out", conn->output->offset);
747 }
748
connection_disconnect(struct connection * conn)749 void connection_disconnect(struct connection *conn)
750 {
751 if (conn->disconnected)
752 return;
753 connection_update_counters(conn);
754 /* client connects to a Server, and Server gets connection from Client
755 */
756 const char *ename = conn->list->set.client ?
757 "server_connection_disconnected" :
758 "client_connection_disconnected";
759
760 struct event_passthrough *e = event_create_passthrough(conn->event)->
761 set_name(ename)->
762 add_str("reason", connection_disconnect_reason(conn));
763 e_debug(e->event(), "Disconnected: %s (fd=%d)",
764 connection_disconnect_reason(conn), conn->fd_in);
765
766 conn->last_input = 0;
767 i_zero(&conn->last_input_tv);
768 timeout_remove(&conn->to);
769 io_remove(&conn->io);
770 i_stream_close(conn->input);
771 i_stream_destroy(&conn->input);
772 o_stream_close(conn->output);
773 o_stream_destroy(&conn->output);
774 fd_close_maybe_stdio(&conn->fd_in, &conn->fd_out);
775 conn->disconnected = TRUE;
776 }
777
connection_deinit(struct connection * conn)778 void connection_deinit(struct connection *conn)
779 {
780 i_assert(conn->list->connections_count > 0);
781
782 conn->list->connections_count--;
783 DLLIST_REMOVE(&conn->list->connections, conn);
784
785 connection_disconnect(conn);
786 i_free(conn->base_name);
787 i_free(conn->label);
788 i_free(conn->property_label);
789 event_unref(&conn->event);
790 conn->list = NULL;
791 }
792
connection_input_read(struct connection * conn)793 int connection_input_read(struct connection *conn)
794 {
795 conn->last_input = ioloop_time;
796 conn->last_input_tv = ioloop_timeval;
797 if (conn->to != NULL)
798 timeout_reset(conn->to);
799
800 switch (i_stream_read(conn->input)) {
801 case -2:
802 /* buffer full */
803 switch (conn->list->set.input_full_behavior) {
804 case CONNECTION_BEHAVIOR_DESTROY:
805 connection_closed(conn,
806 CONNECTION_DISCONNECT_BUFFER_FULL);
807 return -1;
808 case CONNECTION_BEHAVIOR_ALLOW:
809 return -2;
810 }
811 i_unreached();
812 case -1:
813 /* disconnected */
814 connection_closed(conn, CONNECTION_DISCONNECT_CONN_CLOSED);
815 return -1;
816 case 0:
817 /* nothing new read */
818 return 0;
819 default:
820 /* something was read */
821 return 1;
822 }
823 }
824
connection_disconnect_reason(struct connection * conn)825 const char *connection_disconnect_reason(struct connection *conn)
826 {
827 switch (conn->disconnect_reason) {
828 case CONNECTION_DISCONNECT_DEINIT:
829 return "Deinitializing";
830 case CONNECTION_DISCONNECT_CONNECT_TIMEOUT: {
831 unsigned int msecs =
832 conn->list->set.client_connect_timeout_msecs;
833 return t_strdup_printf("connect() timed out in %u.%03u secs",
834 msecs/1000, msecs%1000);
835 }
836 case CONNECTION_DISCONNECT_IDLE_TIMEOUT:
837 return "Idle timeout";
838 case CONNECTION_DISCONNECT_CONN_CLOSED:
839 if (conn->input == NULL)
840 return t_strdup_printf("connect() failed: %m");
841 /* fall through */
842 case CONNECTION_DISCONNECT_NOT:
843 case CONNECTION_DISCONNECT_BUFFER_FULL:
844 return io_stream_get_disconnect_reason(conn->input, conn->output);
845 case CONNECTION_DISCONNECT_HANDSHAKE_FAILED:
846 return "Handshake failed";
847 }
848 i_unreached();
849 }
850
connection_input_timeout_reason(struct connection * conn)851 const char *connection_input_timeout_reason(struct connection *conn)
852 {
853 if (conn->last_input_tv.tv_sec != 0) {
854 int diff = timeval_diff_msecs(&ioloop_timeval,
855 &conn->last_input_tv);
856 return t_strdup_printf("No input for %u.%03u secs",
857 diff/1000, diff%1000);
858 } else if (conn->connect_finished.tv_sec != 0) {
859 int diff = timeval_diff_msecs(&ioloop_timeval,
860 &conn->connect_finished);
861 return t_strdup_printf(
862 "No input since connected %u.%03u secs ago",
863 diff/1000, diff%1000);
864 } else {
865 int diff = timeval_diff_msecs(&ioloop_timeval,
866 &conn->connect_started);
867 return t_strdup_printf("connect() timed out after %u.%03u secs",
868 diff/1000, diff%1000);
869 }
870 }
871
connection_set_handlers(struct connection * conn,const struct connection_vfuncs * vfuncs)872 void connection_set_handlers(struct connection *conn,
873 const struct connection_vfuncs *vfuncs)
874 {
875 connection_input_halt(conn);
876 i_assert(vfuncs->destroy != NULL);
877 conn->v = *vfuncs;
878 if (conn->v.input == NULL)
879 conn->v.input = connection_input_default;
880 if (conn->v.input_line == NULL)
881 conn->v.input_line = connection_input_line_default;
882 if (conn->v.handshake_args == NULL)
883 conn->v.handshake_args = connection_handshake_args_default;
884 if (conn->v.idle_timeout == NULL)
885 conn->v.idle_timeout = connection_idle_timeout;
886 if (conn->v.connect_timeout == NULL)
887 conn->v.connect_timeout = connection_connect_timeout;
888 if (!conn->disconnected)
889 connection_input_resume_full(conn, FALSE);
890 }
891
connection_set_default_handlers(struct connection * conn)892 void connection_set_default_handlers(struct connection *conn)
893 {
894 connection_set_handlers(conn, &conn->list->v);
895 }
896
connection_switch_ioloop_to(struct connection * conn,struct ioloop * ioloop)897 void connection_switch_ioloop_to(struct connection *conn,
898 struct ioloop *ioloop)
899 {
900 conn->ioloop = ioloop;
901 if (conn->io != NULL)
902 conn->io = io_loop_move_io_to(ioloop, &conn->io);
903 if (conn->to != NULL)
904 conn->to = io_loop_move_timeout_to(ioloop, &conn->to);
905 if (conn->input != NULL)
906 i_stream_switch_ioloop_to(conn->input, ioloop);
907 if (conn->output != NULL)
908 o_stream_switch_ioloop_to(conn->output, ioloop);
909 }
910
connection_switch_ioloop(struct connection * conn)911 void connection_switch_ioloop(struct connection *conn)
912 {
913 connection_switch_ioloop_to(conn, current_ioloop);
914 }
915
916 struct connection_list *
connection_list_init(const struct connection_settings * set,const struct connection_vfuncs * vfuncs)917 connection_list_init(const struct connection_settings *set,
918 const struct connection_vfuncs *vfuncs)
919 {
920 struct connection_list *list;
921
922 i_assert(vfuncs->input != NULL ||
923 set->input_full_behavior != CONNECTION_BEHAVIOR_ALLOW);
924 i_assert(set->major_version == 0 ||
925 (set->service_name_in != NULL &&
926 set->service_name_out != NULL &&
927 set->output_max_size != 0));
928
929 list = i_new(struct connection_list, 1);
930 list->set = *set;
931 list->v = *vfuncs;
932
933 return list;
934 }
935
connection_list_deinit(struct connection_list ** _list)936 void connection_list_deinit(struct connection_list **_list)
937 {
938 struct connection_list *list = *_list;
939 struct connection *conn;
940
941 *_list = NULL;
942
943 while (list->connections != NULL) {
944 conn = list->connections;
945 connection_closed(conn, CONNECTION_DISCONNECT_DEINIT);
946 i_assert(conn != list->connections);
947 }
948 i_free(list);
949 }
950