diff --git a/include/maxscale/config_runtime.h b/include/maxscale/config_runtime.h index cc29f775c..8384ebbb9 100644 --- a/include/maxscale/config_runtime.h +++ b/include/maxscale/config_runtime.h @@ -118,3 +118,29 @@ bool runtime_enable_server_ssl(SERVER *server, const char *key, const char *cert * @return True if @c key was one of the supported parameters */ bool runtime_alter_monitor(MONITOR *monitor, char *key, char *value); + +/** + * @brief Create a new listener for a service + * + * This function adds a new listener to a service and starts it. + * + * @param service Service where the listener is added + * @param name Name of the listener + * @param addr Listening address, NULL for default of 0.0.0.0 + * @param port Listening port, NULL for default of 3306 + * @param proto Listener protocol, NULL for default of "MySQLClient" + * @param auth Listener authenticator, NULL for protocol default authenticator + * @param auth_opt Options for the authenticator, NULL for no options + * @param ssl_key SSL key, NULL for no key + * @param ssl_cert SSL cert, NULL for no cert + * @param ssl_ca SSL CA cert, NULL for no CA cert + * @param ssl_version SSL version, NULL for default of "MAX" + * @param ssl_depth SSL cert verification depth, NULL for default + * + * @return True if the listener was successfully created and started + */ +bool runtime_create_listener(SERVICE *service, const char *name, const char *addr, + const char *port, const char *proto, const char *auth, + const char *auth_opt, const char *ssl_key, + const char *ssl_cert, const char *ssl_ca, + const char *ssl_version, const char *ssl_depth); diff --git a/include/maxscale/service.h b/include/maxscale/service.h index e4c23a67a..73c282142 100644 --- a/include/maxscale/service.h +++ b/include/maxscale/service.h @@ -204,7 +204,7 @@ extern void serviceAddRouterOption(SERVICE *, char *); extern void serviceClearRouterOptions(SERVICE *); extern int serviceStart(SERVICE *); extern int serviceStartAll(); -extern void serviceStartProtocol(SERVICE *, char *, int); +extern bool serviceListen(SERVICE *service, unsigned short port); extern int serviceStop(SERVICE *); extern int serviceRestart(SERVICE *); extern int serviceSetUser(SERVICE *, char *, char *); diff --git a/server/core/config.c b/server/core/config.c index 3e62de294..65d22e9af 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -98,7 +98,7 @@ bool config_has_duplicate_sections(const char* config, DUPLICATE_CONTEXT* contex int create_new_service(CONFIG_CONTEXT *obj); int create_new_server(CONFIG_CONTEXT *obj); int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* monitorhash); -int create_new_listener(CONFIG_CONTEXT *obj, bool startnow); +int create_new_listener(CONFIG_CONTEXT *obj); int create_new_filter(CONFIG_CONTEXT *obj); int configure_new_service(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj); @@ -815,7 +815,7 @@ process_config_context(CONFIG_CONTEXT *context) } else if (!strcmp(type, "listener")) { - error_count += create_new_listener(obj, false); + error_count += create_new_listener(obj); } else if (!strcmp(type, "monitor")) { @@ -3094,7 +3094,7 @@ int create_new_monitor(CONFIG_CONTEXT *context, CONFIG_CONTEXT *obj, HASHTABLE* * @param startnow If true, start the listener now * @return Number of errors */ -int create_new_listener(CONFIG_CONTEXT *obj, bool startnow) +int create_new_listener(CONFIG_CONTEXT *obj) { int error_count = 0; char *service_name = config_get_value(obj->parameters, "service"); @@ -3123,10 +3123,6 @@ int create_new_listener(CONFIG_CONTEXT *obj, bool startnow) { serviceAddProtocol(service, obj->object, protocol, socket, 0, authenticator, authenticator_options, ssl_info); - if (startnow) - { - serviceStartProtocol(service, protocol, 0); - } } } @@ -3144,10 +3140,6 @@ int create_new_listener(CONFIG_CONTEXT *obj, bool startnow) { serviceAddProtocol(service, obj->object, protocol, address, atoi(port), authenticator, authenticator_options, ssl_info); - if (startnow) - { - serviceStartProtocol(service, protocol, atoi(port)); - } } } diff --git a/server/core/config_runtime.c b/server/core/config_runtime.c index 5858a13b6..84740391a 100644 --- a/server/core/config_runtime.c +++ b/server/core/config_runtime.c @@ -11,6 +11,7 @@ * Public License. */ +#include #include #include #include @@ -190,17 +191,16 @@ bool runtime_destroy_server(SERVER *server) return rval; } -bool runtime_enable_server_ssl(SERVER *server, const char *key, const char *cert, - const char *ca, const char *version, const char *depth) +static SSL_LISTENER* create_ssl(const char *name, const char *key, const char *cert, + const char *ca, const char *version, const char *depth) { - spinlock_acquire(&crt_lock); - bool rval = false; + SSL_LISTENER *rval = NULL; + CONFIG_CONTEXT *obj = config_context_create(name); - if (key && cert && ca) + if (obj) { - CONFIG_CONTEXT *obj = config_context_create(server->unique_name); - - if (obj && config_add_param(obj, "ssl_key", key) && + if (config_add_param(obj, "ssl", "required") && + config_add_param(obj, "ssl_key", key) && config_add_param(obj, "ssl_cert", cert) && config_add_param(obj, "ssl_ca_cert", ca) && (!version || config_add_param(obj, "ssl_version", version)) && @@ -211,27 +211,44 @@ bool runtime_enable_server_ssl(SERVER *server, const char *key, const char *cert if (err == 0 && ssl && listener_init_SSL(ssl) == 0) { - /** TODO: Properly discard old SSL configurations - * - * This could cause the loss of a pointer if two update - * operations are done at the same time.*/ - ssl->next = server->server_ssl; - - /** Sync to prevent reads on partially initialized server_ssl */ - atomic_synchronize(); - - server->server_ssl = ssl; - if (server_serialize(server)) - { - rval = true; - } + rval = ssl; } } config_context_free(obj); } - spinlock_release(&crt_lock); + return rval; +} + +bool runtime_enable_server_ssl(SERVER *server, const char *key, const char *cert, + const char *ca, const char *version, const char *depth) +{ + bool rval = false; + + if (key && cert && ca) + { + spinlock_acquire(&crt_lock); + SSL_LISTENER *ssl = create_ssl(server->unique_name, key, cert, ca, version, depth); + + if (ssl) + { + /** TODO: Properly discard old SSL configurations.This could cause the + * loss of a pointer if two update operations are done at the same time.*/ + ssl->next = server->server_ssl; + + /** Sync to prevent reads on partially initialized server_ssl */ + atomic_synchronize(); + server->server_ssl = ssl; + + if (server_serialize(server)) + { + rval = true; + } + } + spinlock_release(&crt_lock); + } + return rval; } @@ -341,3 +358,73 @@ bool runtime_alter_monitor(MONITOR *monitor, char *key, char *value) spinlock_release(&crt_lock); return valid; } + +bool runtime_create_listener(SERVICE *service, const char *name, const char *addr, + const char *port, const char *proto, const char *auth, + const char *auth_opt, const char *ssl_key, + const char *ssl_cert, const char *ssl_ca, + const char *ssl_version, const char *ssl_depth) +{ + SSL_LISTENER *ssl = NULL; + bool rval = true; + + if (addr == NULL || strcasecmp(addr, "default") == 0) + { + addr = "0.0.0.0"; + } + if (port == NULL || strcasecmp(port, "default") == 0) + { + port = "3306"; + } + if (proto == NULL || strcasecmp(proto, "default") == 0) + { + proto = "MySQLClient"; + } + + if (auth && strcasecmp(auth, "default") == 0) + { + /** Set auth to NULL so the protocol default authenticator is used */ + auth = NULL; + } + + if (auth_opt && strcasecmp(auth_opt, "default") == 0) + { + /** Don't pass options to the authenticator */ + auth_opt = NULL; + } + + unsigned short u_port = atoi(port); + + if (ssl_key && ssl_cert && ssl_ca) + { + ssl = create_ssl(name, ssl_key, ssl_cert, ssl_ca, ssl_version, ssl_depth); + + if (ssl == NULL) + { + MXS_ERROR("SSL initialization for listener '%s' failed.", name); + rval = false; + } + } + + spinlock_acquire(&crt_lock); + + if (rval) + { + const char *print_addr = addr ? addr : "0.0.0.0"; + + if (serviceAddProtocol(service, name, proto, addr, u_port, auth, auth_opt, ssl) && + serviceListen(service, u_port)) + { + MXS_NOTICE("Listener '%s' at %s:%s for service '%s' created", + name, print_addr, port, service->name); + } + else + { + MXS_ERROR("Failed to start listener '%s' at %s:%s.", name, print_addr, port); + rval = false; + } + } + + spinlock_release(&crt_lock); + return rval; +} diff --git a/server/core/service.c b/server/core/service.c index a9a673f8f..2c04f8e54 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -506,25 +506,25 @@ serviceStart(SERVICE *service) * Start an individual listener * * @param service The service to start the listener for - * @param protocol The name of the protocol * @param port The port number */ -void -serviceStartProtocol(SERVICE *service, char *protocol, int port) +bool serviceListen(SERVICE *service, unsigned short port) { - SERV_LISTENER *ptr; - - ptr = service->ports; - while (ptr) + bool rval = false; + for (SERV_LISTENER *ptr = service->ports; ptr; ptr = ptr->next) { - if (strcmp(ptr->protocol, protocol) == 0 && ptr->port == port) + if (ptr->port == port) { - serviceStartPort(service, ptr); + if (serviceStartPort(service, ptr)) + { + rval = true; + } + break; } - ptr = ptr->next; } -} + return rval; +} /** * Start all the services