Serialize created listeners to disk
The created listeners are now stored to disk like created servers are. This allows them to be used even after a restart. Currently, the listeners cannot be deleted and need to be manually removed.
This commit is contained in:
parent
dd63253261
commit
e31afa28e4
@ -49,6 +49,7 @@ typedef struct servlistener
|
||||
unsigned short port; /**< Port to listen on */
|
||||
char *address; /**< Address to listen with */
|
||||
char *authenticator; /**< Name of authenticator */
|
||||
char *auth_options; /**< Authenticator options */
|
||||
void *auth_instance; /**< Authenticator instance created in GWAUTHENTICATOR::initialize() */
|
||||
SSL_LISTENER *ssl; /**< Structure of SSL data or NULL */
|
||||
struct dcb *listener; /**< The DCB for the listener */
|
||||
@ -59,6 +60,18 @@ typedef struct servlistener
|
||||
struct servlistener *next; /**< Next service protocol */
|
||||
} SERV_LISTENER;
|
||||
|
||||
/**
|
||||
* @brief Serialize a listener to a file
|
||||
*
|
||||
* This converts @c listener into an INI format file. This allows created listeners
|
||||
* to be persisted to disk. This will replace any existing files with the same
|
||||
* name.
|
||||
*
|
||||
* @param listener Listener to serialize
|
||||
* @return True if the serialization of the listener was successful, false if it fails
|
||||
*/
|
||||
bool listener_serialize(const SERV_LISTENER *listener);
|
||||
|
||||
SERV_LISTENER* listener_alloc(struct service* service, const char* name, const char *protocol,
|
||||
const char *address, unsigned short port, const char *authenticator,
|
||||
const char* auth_options, SSL_LISTENER *ssl);
|
||||
|
@ -192,9 +192,9 @@ extern SERVICE *service_alloc(const char *, const char *);
|
||||
extern int service_free(SERVICE *);
|
||||
extern SERVICE *service_find(const char *);
|
||||
extern int service_isvalid(SERVICE *);
|
||||
extern bool serviceAddProtocol(SERVICE *service, const char *name, const char *protocol,
|
||||
const char *address, unsigned short port, const char *authenticator,
|
||||
const char *options, SSL_LISTENER *ssl);
|
||||
extern SERV_LISTENER* serviceCreateListener(SERVICE *service, const char *name, const char *protocol,
|
||||
const char *address, unsigned short port, const char *authenticator,
|
||||
const char *options, SSL_LISTENER *ssl);
|
||||
extern int serviceHasProtocol(SERVICE *service, const char *protocol,
|
||||
const char* address, unsigned short port);
|
||||
extern void serviceAddBackend(SERVICE *, SERVER *);
|
||||
@ -204,7 +204,7 @@ extern void serviceAddRouterOption(SERVICE *, char *);
|
||||
extern void serviceClearRouterOptions(SERVICE *);
|
||||
extern int serviceStart(SERVICE *);
|
||||
extern int serviceStartAll();
|
||||
extern bool serviceListen(SERVICE *service, unsigned short port);
|
||||
extern bool serviceListen(SERVICE *service, SERV_LISTENER *port);
|
||||
extern int serviceStop(SERVICE *);
|
||||
extern int serviceRestart(SERVICE *);
|
||||
extern int serviceSetUser(SERVICE *, char *, char *);
|
||||
|
@ -3121,8 +3121,8 @@ int create_new_listener(CONFIG_CONTEXT *obj)
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceAddProtocol(service, obj->object, protocol, socket, 0,
|
||||
authenticator, authenticator_options, ssl_info);
|
||||
serviceCreateListener(service, obj->object, protocol, socket, 0,
|
||||
authenticator, authenticator_options, ssl_info);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3138,8 +3138,8 @@ int create_new_listener(CONFIG_CONTEXT *obj)
|
||||
}
|
||||
else
|
||||
{
|
||||
serviceAddProtocol(service, obj->object, protocol, address, atoi(port),
|
||||
authenticator, authenticator_options, ssl_info);
|
||||
serviceCreateListener(service, obj->object, protocol, address, atoi(port),
|
||||
authenticator, authenticator_options, ssl_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,9 +411,10 @@ bool runtime_create_listener(SERVICE *service, const char *name, const char *add
|
||||
if (rval)
|
||||
{
|
||||
const char *print_addr = addr ? addr : "0.0.0.0";
|
||||
SERV_LISTENER *listener = serviceCreateListener(service, name, proto, addr,
|
||||
u_port, auth, auth_opt, ssl);
|
||||
|
||||
if (serviceAddProtocol(service, name, proto, addr, u_port, auth, auth_opt, ssl) &&
|
||||
serviceListen(service, u_port))
|
||||
if (listener && listener_serialize(listener) && serviceListen(service, listener))
|
||||
{
|
||||
MXS_NOTICE("Listener '%s' at %s:%s for service '%s' created",
|
||||
name, print_addr, port, service->name);
|
||||
|
@ -30,13 +30,16 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <maxscale/listener.h>
|
||||
#include <maxscale/gwdirs.h>
|
||||
#include <maxscale/gw_ssl.h>
|
||||
#include <maxscale/gw_protocol.h>
|
||||
#include <maxscale/log_manager.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/users.h>
|
||||
#include <maxscale/modules.h>
|
||||
#include <maxscale/service.h>
|
||||
|
||||
static RSA *rsa_512 = NULL;
|
||||
static RSA *rsa_1024 = NULL;
|
||||
@ -69,6 +72,14 @@ listener_alloc(struct service* service, const char* name, const char *protocol,
|
||||
}
|
||||
}
|
||||
|
||||
char *my_auth_options = NULL;
|
||||
|
||||
if (auth_options && (my_auth_options = MXS_STRDUP(auth_options)) == NULL)
|
||||
{
|
||||
MXS_FREE(my_address);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *my_authenticator = NULL;
|
||||
|
||||
if (authenticator)
|
||||
@ -116,6 +127,7 @@ listener_alloc(struct service* service, const char* name, const char *protocol,
|
||||
proto->address = my_address;
|
||||
proto->port = port;
|
||||
proto->authenticator = my_authenticator;
|
||||
proto->auth_options = my_auth_options;
|
||||
proto->ssl = ssl;
|
||||
proto->users = NULL;
|
||||
proto->resources = NULL;
|
||||
@ -146,6 +158,8 @@ void listener_free(SERV_LISTENER* listener)
|
||||
|
||||
MXS_FREE(listener->address);
|
||||
MXS_FREE(listener->authenticator);
|
||||
MXS_FREE(listener->auth_options);
|
||||
MXS_FREE(listener->name);
|
||||
MXS_FREE(listener->protocol);
|
||||
MXS_FREE(listener);
|
||||
}
|
||||
@ -376,3 +390,132 @@ tmp_rsa_callback(SSL *s, int is_export, int keylength)
|
||||
}
|
||||
return(rsa_tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a listener configuration at the location pointed by @c filename
|
||||
*
|
||||
* @param listener Listener to serialize into a configuration
|
||||
* @param filename Filename where configuration is written
|
||||
* @return True on success, false on error
|
||||
*/
|
||||
static bool create_listener_config(const SERV_LISTENER *listener, const char *filename)
|
||||
{
|
||||
int file = open(filename, O_EXCL | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
|
||||
if (file == -1)
|
||||
{
|
||||
char errbuf[MXS_STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to open file '%s' when serializing listener '%s': %d, %s",
|
||||
filename, listener->name, errno, strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Check for return values on all of the dprintf calls
|
||||
dprintf(file, "[%s]\n", listener->name);
|
||||
dprintf(file, "type=listener\n");
|
||||
dprintf(file, "protocol=%s\n", listener->protocol);
|
||||
dprintf(file, "service=%s\n", listener->service->name);
|
||||
dprintf(file, "address=%s\n", listener->address);
|
||||
dprintf(file, "port=%u\n", listener->port);
|
||||
dprintf(file, "authenticator=%s\n", listener->authenticator);
|
||||
|
||||
if (listener->auth_options)
|
||||
{
|
||||
dprintf(file, "authenticator_options=%s\n", listener->auth_options);
|
||||
}
|
||||
|
||||
if (listener->ssl)
|
||||
{
|
||||
dprintf(file, "ssl=required\n");
|
||||
|
||||
if (listener->ssl->ssl_cert)
|
||||
{
|
||||
dprintf(file, "ssl_cert=%s\n", listener->ssl->ssl_cert);
|
||||
}
|
||||
|
||||
if (listener->ssl->ssl_key)
|
||||
{
|
||||
dprintf(file, "ssl_key=%s\n", listener->ssl->ssl_key);
|
||||
}
|
||||
|
||||
if (listener->ssl->ssl_ca_cert)
|
||||
{
|
||||
dprintf(file, "ssl_ca_cert=%s\n", listener->ssl->ssl_ca_cert);
|
||||
}
|
||||
if (listener->ssl->ssl_cert_verify_depth)
|
||||
{
|
||||
dprintf(file, "ssl_cert_verify_depth=%d\n", listener->ssl->ssl_cert_verify_depth);
|
||||
}
|
||||
|
||||
const char *version = NULL;
|
||||
|
||||
switch (listener->ssl->ssl_method_type)
|
||||
{
|
||||
case SERVICE_TLS10:
|
||||
version = "TLSV10";
|
||||
break;
|
||||
|
||||
#ifdef OPENSSL_1_0
|
||||
case SERVICE_TLS11:
|
||||
version = "TLSV11";
|
||||
break;
|
||||
|
||||
case SERVICE_TLS12:
|
||||
version = "TLSV12";
|
||||
break;
|
||||
#endif
|
||||
case SERVICE_SSL_TLS_MAX:
|
||||
version = "MAX";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (version)
|
||||
{
|
||||
dprintf(file, "ssl_version=%s\n", version);
|
||||
}
|
||||
}
|
||||
|
||||
close(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool listener_serialize(const SERV_LISTENER *listener)
|
||||
{
|
||||
bool rval = false;
|
||||
char filename[PATH_MAX];
|
||||
snprintf(filename, sizeof(filename), "%s/%s.cnf.tmp", get_config_persistdir(),
|
||||
listener->name);
|
||||
|
||||
if (unlink(filename) == -1 && errno != ENOENT)
|
||||
{
|
||||
char err[MXS_STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to remove temporary listener configuration at '%s': %d, %s",
|
||||
filename, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
else if (create_listener_config(listener, filename))
|
||||
{
|
||||
char final_filename[PATH_MAX];
|
||||
strcpy(final_filename, filename);
|
||||
|
||||
char *dot = strrchr(final_filename, '.');
|
||||
ss_dassert(dot);
|
||||
*dot = '\0';
|
||||
|
||||
if (rename(filename, final_filename) == 0)
|
||||
{
|
||||
rval = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
char err[MXS_STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to rename temporary listener configuration at '%s': %d, %s",
|
||||
filename, errno, strerror_r(errno, err, sizeof(err)));
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
@ -508,22 +508,9 @@ serviceStart(SERVICE *service)
|
||||
* @param service The service to start the listener for
|
||||
* @param port The port number
|
||||
*/
|
||||
bool serviceListen(SERVICE *service, unsigned short port)
|
||||
bool serviceListen(SERVICE *service, SERV_LISTENER *port)
|
||||
{
|
||||
bool rval = false;
|
||||
for (SERV_LISTENER *ptr = service->ports; ptr; ptr = ptr->next)
|
||||
{
|
||||
if (ptr->port == port)
|
||||
{
|
||||
if (serviceStartPort(service, ptr))
|
||||
{
|
||||
rval = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
return serviceStartPort(service, port);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -678,7 +665,7 @@ service_free(SERVICE *service)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a protocol/port pair to the service
|
||||
* Create a listener for the service
|
||||
*
|
||||
* @param service The service
|
||||
* @param protocol The name of the protocol module
|
||||
@ -686,13 +673,13 @@ service_free(SERVICE *service)
|
||||
* @param port The port to listen on
|
||||
* @param authenticator Name of the authenticator to be used
|
||||
* @param ssl SSL configuration
|
||||
* @return TRUE if the protocol/port could be added
|
||||
*
|
||||
* @return Created listener or NULL on error
|
||||
*/
|
||||
bool serviceAddProtocol(SERVICE *service, const char *name, const char *protocol,
|
||||
SERV_LISTENER* serviceCreateListener(SERVICE *service, const char *name, const char *protocol,
|
||||
const char *address, unsigned short port, const char *authenticator,
|
||||
const char *options, SSL_LISTENER *ssl)
|
||||
{
|
||||
bool rval = false;
|
||||
SERV_LISTENER *proto = listener_alloc(service, name, protocol, address,
|
||||
port, authenticator, options, ssl);
|
||||
|
||||
@ -702,10 +689,9 @@ bool serviceAddProtocol(SERVICE *service, const char *name, const char *protocol
|
||||
proto->next = service->ports;
|
||||
service->ports = proto;
|
||||
spinlock_release(&service->spin);
|
||||
rval = true;
|
||||
}
|
||||
|
||||
return rval;
|
||||
return proto;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,8 +69,8 @@ test1()
|
||||
ss_info_dassert(0 == strcmp("MyService", service_get_name(service)), "Service must have given name");
|
||||
ss_dfprintf(stderr, "\t..done\nAdding protocol testprotocol.");
|
||||
set_libdir(MXS_STRDUP_A("../../modules/authenticator/MySQLAuth/"));
|
||||
ss_info_dassert(0 != serviceAddProtocol(service, "TestProtocol", "testprotocol",
|
||||
"localhost", 9876, "MySQLAuth", NULL, NULL),
|
||||
ss_info_dassert(serviceCreateListener(service, "TestProtocol", "testprotocol",
|
||||
"localhost", 9876, "MySQLAuth", NULL, NULL),
|
||||
"Add Protocol should succeed");
|
||||
ss_info_dassert(0 != serviceHasProtocol(service, "testprotocol", "localhost", 9876),
|
||||
"Service should have new protocol as requested");
|
||||
|
Loading…
x
Reference in New Issue
Block a user