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