main.c revision 09060303d565e15d54e42b4ef722f9d3c26f5336
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2014 Dovecot authors, see the included COPYING file */
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "lib.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "ioloop.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "array.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "restrict-access.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "master-interface.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "master-service.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "master-service-settings.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "auth-connection.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "doveadm-connection.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "login-connection.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "notify-connection.h"
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi#include "director.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "director-host.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "director-connection.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "director-request.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include "mail-host.h"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include <stdio.h>
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#include <unistd.h>
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#define AUTH_SOCKET_PATH "auth-login"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody#define AUTH_USERDB_SOCKET_PATH "auth-userdb"
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmodystatic struct director *director;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmodystatic struct notify_connection *notify_conn;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmodystatic int director_client_connected(int fd, const struct ip_addr *ip)
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody{
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody struct director_host *host;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody host = director_host_lookup_ip(director, ip);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (host == NULL || host->removed) {
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody i_warning("Connection from %s: Server not listed in "
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi "director_servers, dropping", net_ip2addr(ip));
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody return -1;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody }
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody (void)director_connection_init_in(director, fd, ip);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody return 0;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody}
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmodystatic void client_connected(struct master_service_connection *conn)
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody{
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody struct auth_connection *auth;
62461eb609e1d852e027cf4e07d30d51288678a2Aki Tuomi const char *socket_path;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody struct ip_addr ip;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody unsigned int local_port, len;
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi bool userdb;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (conn->fifo) {
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (notify_conn != NULL) {
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody i_error("Received another proxy-notify connection");
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody return;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody }
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody master_service_client_connection_accept(conn);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody notify_conn = notify_connection_init(director, conn->fd);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody return;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody }
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (net_getpeername(conn->fd, &ip, NULL) == 0 &&
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody net_getsockname(conn->fd, NULL, &local_port) == 0 &&
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody (IPADDR_IS_V4(&ip) || IPADDR_IS_V6(&ip))) {
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody /* TCP/IP connection */
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody if (local_port == director->set->director_doveadm_port) {
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody master_service_client_connection_accept(conn);
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody (void)doveadm_connection_init(director, conn->fd);
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody } else {
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody if (director_client_connected(conn->fd, &ip) == 0)
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody master_service_client_connection_accept(conn);
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody }
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi return;
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody }
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody len = strlen(conn->name);
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi if (len > 6 && strcmp(conn->name + len - 6, "-admin") == 0) {
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody /* doveadm connection */
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody master_service_client_connection_accept(conn);
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody (void)doveadm_connection_init(director, conn->fd);
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody return;
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody }
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody /* a) userdb connection, probably for lmtp proxy
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody b) login connection
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody Both of them are handled exactly the same, except for which
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody auth socket they connect to. */
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody userdb = len > 7 && strcmp(conn->name + len - 7, "-userdb") == 0;
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody socket_path = userdb ? AUTH_USERDB_SOCKET_PATH : AUTH_SOCKET_PATH;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody auth = auth_connection_init(socket_path);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (auth_connection_connect(auth) == 0) {
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody master_service_client_connection_accept(conn);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody (void)login_connection_init(director, conn->fd, auth, userdb);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody } else {
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody auth_connection_deinit(&auth);
e2588872c1fe79642589b805aaab9fbb6750771bTimo Sirainen }
618262376e4a087f2047e627baf008884a4085b9Timo Sirainen}
96f75b44a4950bf20273656e71e2686a508d0bd1Timo Sirainen
618262376e4a087f2047e627baf008884a4085b9Timo Sirainenstatic unsigned int
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmodyfind_inet_listener_port(struct ip_addr *ip_r,
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody const struct director_settings *set)
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi{
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody unsigned int i, socket_count, port;
98c59517ebce19556221065e9231f007bbdd0038Timo Sirainen
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody socket_count = master_service_get_socket_count(master_service);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody for (i = 0; i < socket_count; i++) {
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi int fd = MASTER_LISTEN_FD_FIRST + i;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (net_getsockname(fd, ip_r, &port) == 0 && port > 0 &&
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody port != set->director_doveadm_port)
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody return port;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody }
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody return 0;
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody}
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmodystatic void director_state_changed(struct director *dir)
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody{
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody struct director_request *const *requestp;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody ARRAY(struct director_request *) new_requests;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody bool ret;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (!dir->ring_synced || !mail_hosts_have_usable(dir->mail_hosts))
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody return;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
3c5ee51327f075dc13cdacf46135f7f0abbdaafeTimo Sirainen /* if there are any pending client requests, finish them now */
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody t_array_init(&new_requests, 8);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody array_foreach(&dir->pending_requests, requestp) {
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody ret = director_request_continue(*requestp);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (!ret) {
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody /* a) request for a user being killed
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody b) user is weak */
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody array_append(&new_requests, requestp, 1);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody }
62461eb609e1d852e027cf4e07d30d51288678a2Aki Tuomi }
62461eb609e1d852e027cf4e07d30d51288678a2Aki Tuomi array_clear(&dir->pending_requests);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody array_append_array(&dir->pending_requests, &new_requests);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody if (dir->to_request != NULL && array_count(&new_requests) == 0)
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody timeout_remove(&dir->to_request);
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody}
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmodystatic void main_preinit(void)
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody{
f9a1f7b6034d692cbd24c1895061b3834f486501Phil Carmody const struct director_settings *set;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody struct ip_addr listen_ip;
992a1726a41b42fa47204565ff17f7c635fcb421Phil Carmody unsigned int listen_port;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
957d34edbe3599fbb4e7c0bcf3785bd7fd4862c4Timo Sirainen set = master_service_settings_get_others(master_service)[0];
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
03e0be24656823c795dfadccf68bbeeefa6fb772Phil Carmody listen_port = find_inet_listener_port(&listen_ip, set);
e2588872c1fe79642589b805aaab9fbb6750771bTimo Sirainen if (listen_port == 0 && *set->director_servers != '\0') {
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody i_fatal("No inet_listeners defined for director service "
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody "(for standalone keep director_servers empty)");
e2588872c1fe79642589b805aaab9fbb6750771bTimo Sirainen }
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director = director_init(set, &listen_ip, listen_port,
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director_state_changed);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director_host_add_from_string(director, set->director_servers);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director_find_self(director);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody if (mail_hosts_parse_and_add(director->mail_hosts,
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody set->director_mail_servers) < 0)
f4a820824229d5b25736fe3a2794e4767d8b2cfaPhil Carmody i_fatal("Invalid value for director_mail_servers setting");
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director->orig_config_hosts = mail_hosts_dup(director->mail_hosts);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody restrict_access_by_env(NULL, FALSE);
211c638d81d382517d196ad47565e0d85012c927klemens restrict_access_allow_coredumps(TRUE);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody}
3c5ee51327f075dc13cdacf46135f7f0abbdaafeTimo Sirainen
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmodystatic void main_deinit(void)
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody{
e2588872c1fe79642589b805aaab9fbb6750771bTimo Sirainen if (notify_conn != NULL)
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody notify_connection_deinit(&notify_conn);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director_deinit(&director);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody doveadm_connections_deinit();
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody login_connections_deinit();
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody auth_connections_deinit();
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody}
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmodyint main(int argc, char *argv[])
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody{
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi const struct setting_parser_info *set_roots[] = {
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi &director_setting_parser_info,
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody NULL
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody };
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody const enum master_service_flags service_flags =
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody MASTER_SERVICE_FLAG_NO_IDLE_DIE |
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody MASTER_SERVICE_FLAG_UPDATE_PROCTITLE;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody unsigned int test_port = 0;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody const char *error;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody bool debug = FALSE;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody int c;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody master_service = master_service_init("director", service_flags,
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody &argc, &argv, "Dt:");
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi while ((c = master_getopt(master_service)) > 0) {
ba1a5db879b08d2fefcb42160af67853cdfe7687Timo Sirainen switch (c) {
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi case 'D':
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody debug = TRUE;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody break;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody case 't':
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody if (str_to_uint(optarg, &test_port) < 0)
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi i_fatal("-t: Not a number: %s", optarg);
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi break;
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi default:
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody return FATAL_DEFAULT;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody }
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody }
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody if (master_service_settings_read_simple(master_service, set_roots,
ba1a5db879b08d2fefcb42160af67853cdfe7687Timo Sirainen &error) < 0)
3c5ee51327f075dc13cdacf46135f7f0abbdaafeTimo Sirainen i_fatal("Error reading configuration: %s", error);
e2588872c1fe79642589b805aaab9fbb6750771bTimo Sirainen
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody master_service_init_log(master_service, "director: ");
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody main_preinit();
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director->test_port = test_port;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director_debug = debug;
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody director_connect(director);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody if (director->test_port != 0) {
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody /* we're testing, possibly writing to same log file.
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody make it clear which director we are. */
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody master_service_init_log(master_service,
ba1a5db879b08d2fefcb42160af67853cdfe7687Timo Sirainen t_strdup_printf("director(%s): ",
3c5ee51327f075dc13cdacf46135f7f0abbdaafeTimo Sirainen net_ip2addr(&director->self_ip)));
e2588872c1fe79642589b805aaab9fbb6750771bTimo Sirainen }
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody master_service_init_finish(master_service);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody master_service_run(master_service, client_connected);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody main_deinit();
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody master_service_deinit(&master_service);
ee2298ffa2c91fa156ba5ba05d45576a99d3f9adPhil Carmody return 0;
03e0be24656823c795dfadccf68bbeeefa6fb772Phil Carmody}
03e0be24656823c795dfadccf68bbeeefa6fb772Phil Carmody