From 6468191d64827a2d1481c091ec499874583c834e Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 13 May 2015 15:33:27 +0300 Subject: [PATCH] director: Cleanup for director socket type configuration. It's now possible to use any type of a socket for inet listeners by specifying the name for the listener. The available types are: auth (default), userdb, ring (= director<->director connection), admin/doveadm. This change should be backwards compatible with previous configuration. This setting also deprecates director_doveadm_port setting. --- src/director/main.c | 167 ++++++++++++++++++++++++++++++-------------- 1 file changed, 116 insertions(+), 51 deletions(-) diff --git a/src/director/main.c b/src/director/main.c index 208748184e..29392eeccd 100644 --- a/src/director/main.c +++ b/src/director/main.c @@ -26,9 +26,18 @@ #define AUTH_SOCKET_PATH "auth-login" #define AUTH_USERDB_SOCKET_PATH "auth-userdb" +enum director_socket_type { + DIRECTOR_SOCKET_TYPE_UNKNOWN = 0, + DIRECTOR_SOCKET_TYPE_AUTH, + DIRECTOR_SOCKET_TYPE_USERDB, + DIRECTOR_SOCKET_TYPE_RING, + DIRECTOR_SOCKET_TYPE_DOVEADM +}; + static struct director *director; static struct notify_connection *notify_conn; static struct timeout *to_proctitle_refresh; +static ARRAY(enum director_socket_type) listener_socket_types; static void director_refresh_proctitle_timeout(void *context ATTR_UNUSED) { @@ -51,6 +60,84 @@ static void director_refresh_proctitle_timeout(void *context ATTR_UNUSED) process_title_set(str_c(str)); } +static enum director_socket_type +director_socket_type_get_from_name(const char *path) +{ + const char *name, *suffix; + + name = strrchr(path, '/'); + if (name == NULL) + name = path; + else + name++; + + suffix = strrchr(name, '-'); + if (suffix == NULL) + suffix = name; + else + suffix++; + + if (strcmp(suffix, "auth") == 0) + return DIRECTOR_SOCKET_TYPE_AUTH; + else if (strcmp(suffix, "userdb") == 0) + return DIRECTOR_SOCKET_TYPE_USERDB; + else if (strcmp(suffix, "ring") == 0) + return DIRECTOR_SOCKET_TYPE_RING; + else if (strcmp(suffix, "admin") == 0 || + strcmp(suffix, "doveadm") == 0) + return DIRECTOR_SOCKET_TYPE_DOVEADM; + else + return DIRECTOR_SOCKET_TYPE_UNKNOWN; +} + +static enum director_socket_type +listener_get_socket_type_fallback(const struct director_settings *set, + int listen_fd) +{ + unsigned int local_port; + + if (net_getsockname(listen_fd, NULL, &local_port) == 0) { + /* TCP/IP connection */ + if (local_port == set->director_doveadm_port) + return DIRECTOR_SOCKET_TYPE_DOVEADM; + else + return DIRECTOR_SOCKET_TYPE_RING; + } + return DIRECTOR_SOCKET_TYPE_AUTH; +} + +static void listener_sockets_init(const struct director_settings *set, + struct ip_addr *listen_ip_r, + unsigned int *listen_port_r) +{ + const char *name; + unsigned int i, socket_count, port; + struct ip_addr ip; + enum director_socket_type type; + + *listen_port_r = 0; + + i_array_init(&listener_socket_types, 8); + socket_count = master_service_get_socket_count(master_service); + for (i = 0; i < socket_count; i++) { + int listen_fd = MASTER_LISTEN_FD_FIRST + i; + + name = master_service_get_socket_name(master_service, listen_fd); + type = director_socket_type_get_from_name(name); + if (type == DIRECTOR_SOCKET_TYPE_UNKNOWN) { + /* mainly for backwards compatibility */ + type = listener_get_socket_type_fallback(set, listen_fd); + } + if (type == DIRECTOR_SOCKET_TYPE_RING && *listen_port_r == 0 && + net_getsockname(listen_fd, &ip, &port) == 0 && port > 0) { + i_warning("listen port = %d", port); + *listen_ip_r = ip; + *listen_port_r = port; + } + array_idx_set(&listener_socket_types, listen_fd, &type); + } +} + static int director_client_connected(int fd, const struct ip_addr *ip) { struct director_host *host; @@ -70,8 +157,7 @@ static void client_connected(struct master_service_connection *conn) { struct auth_connection *auth; const char *socket_path; - struct ip_addr ip; - unsigned int local_port, len; + const enum director_socket_type *typep; bool userdb; if (conn->fifo) { @@ -84,58 +170,36 @@ static void client_connected(struct master_service_connection *conn) return; } - if (net_getpeername(conn->fd, &ip, NULL) == 0 && - net_getsockname(conn->fd, NULL, &local_port) == 0 && - (IPADDR_IS_V4(&ip) || IPADDR_IS_V6(&ip))) { - /* TCP/IP connection */ - if (local_port == director->set->director_doveadm_port) { - master_service_client_connection_accept(conn); - (void)doveadm_connection_init(director, conn->fd); - } else { - if (director_client_connected(conn->fd, &ip) == 0) - master_service_client_connection_accept(conn); + typep = array_idx(&listener_socket_types, conn->listen_fd); + switch (*typep) { + case DIRECTOR_SOCKET_TYPE_UNKNOWN: + i_unreached(); + case DIRECTOR_SOCKET_TYPE_AUTH: + case DIRECTOR_SOCKET_TYPE_USERDB: + /* a) userdb connection, probably for lmtp proxy + b) login connection + Both of them are handled exactly the same, except for which + auth socket they connect to. */ + userdb = *typep == DIRECTOR_SOCKET_TYPE_USERDB; + socket_path = userdb ? AUTH_USERDB_SOCKET_PATH : + AUTH_SOCKET_PATH; + auth = auth_connection_init(socket_path); + if (auth_connection_connect(auth) < 0) { + auth_connection_deinit(&auth); + break; } - return; - } - - len = strlen(conn->name); - if (len > 6 && strcmp(conn->name + len - 6, "-admin") == 0) { - /* doveadm connection */ - master_service_client_connection_accept(conn); - (void)doveadm_connection_init(director, conn->fd); - return; - } - - /* a) userdb connection, probably for lmtp proxy - b) login connection - Both of them are handled exactly the same, except for which - auth socket they connect to. */ - userdb = len > 7 && strcmp(conn->name + len - 7, "-userdb") == 0; - socket_path = userdb ? AUTH_USERDB_SOCKET_PATH : AUTH_SOCKET_PATH; - auth = auth_connection_init(socket_path); - if (auth_connection_connect(auth) == 0) { master_service_client_connection_accept(conn); (void)login_connection_init(director, conn->fd, auth, userdb); - } else { - auth_connection_deinit(&auth); - } -} - -static unsigned int -find_inet_listener_port(struct ip_addr *ip_r, - const struct director_settings *set) -{ - unsigned int i, socket_count, port; - - socket_count = master_service_get_socket_count(master_service); - for (i = 0; i < socket_count; i++) { - int fd = MASTER_LISTEN_FD_FIRST + i; - - if (net_getsockname(fd, ip_r, &port) == 0 && port > 0 && - port != set->director_doveadm_port) - return port; + break; + case DIRECTOR_SOCKET_TYPE_RING: + if (director_client_connected(conn->fd, &conn->remote_ip) == 0) + master_service_client_connection_accept(conn); + break; + case DIRECTOR_SOCKET_TYPE_DOVEADM: + master_service_client_connection_accept(conn); + (void)doveadm_connection_init(director, conn->fd); + break; } - return 0; } static void director_state_changed(struct director *dir) @@ -177,7 +241,7 @@ static void main_preinit(void) } set = master_service_settings_get_others(master_service)[0]; - listen_port = find_inet_listener_port(&listen_ip, set); + listener_sockets_init(set, &listen_ip, &listen_port); if (listen_port == 0 && *set->director_servers != '\0') { i_fatal("No inet_listeners defined for director service " "(for standalone keep director_servers empty)"); @@ -206,6 +270,7 @@ static void main_deinit(void) doveadm_connections_deinit(); login_connections_deinit(); auth_connections_deinit(); + array_free(&listener_socket_types); } int main(int argc, char *argv[]) -- 2.47.3