diff --git a/Documentation/About/Limitations.md b/Documentation/About/Limitations.md index b42138149..afeaf9aec 100644 --- a/Documentation/About/Limitations.md +++ b/Documentation/About/Limitations.md @@ -20,13 +20,6 @@ different backend authentication module is not supported. ### Limitations in the MySQL authenticator (MySQLAuth) -* MariaDB MaxScale supports authentication that uses wildcard matching in -hostnames in the `mysql.user` table of the backend database. For IP address -entries either `%` or `_`-wildcards are accepted, they should not be mixed in -the same entry. For text addresses both wildcards can be mixed. - -* Wildcards in text-form hostnames are not supported. - * MySQL old style passwords are not supported. MySQL versions 4.1 and newer use a new authentication protocol which does not support pre-4.1 style passwords. diff --git a/Documentation/Release-Notes/MaxScale-2.1.1-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.1.1-Release-Notes.md index 39d65b1a6..423752daa 100644 --- a/Documentation/Release-Notes/MaxScale-2.1.1-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.1.1-Release-Notes.md @@ -74,6 +74,7 @@ NOTE This feature was available already in _2.1.0_. [Here is a list of bugs fixed since the release of MaxScale 2.1.0.](https://jira.mariadb.org/issues/?jql=project%20%3D%20MXS%20AND%20issuetype%20%3D%20Bug%20AND%20resolution%20in%20(Fixed%2C%20Done)%20AND%20fixVersion%20%3D%202.1.1%20AND%20fixVersion%20NOT%20IN%20(2.1.0)) +* [MXS-1178](https://jira.mariadb.org/browse/MXS-1178) master_accept_reads doesn't work with detect_replication_lag * [MXS-1165](https://jira.mariadb.org/browse/MXS-1165) MaxInfo eat too much memory when getting list of session and client. * [MXS-1143](https://jira.mariadb.org/browse/MXS-1143) Add support for new MariaDB 10.2 flags * [MXS-1130](https://jira.mariadb.org/browse/MXS-1130) Unexpected length encoding 'ff' encountered diff --git a/Documentation/Release-Notes/MaxScale-2.1.2-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.1.2-Release-Notes.md new file mode 100644 index 000000000..b3712049d --- /dev/null +++ b/Documentation/Release-Notes/MaxScale-2.1.2-Release-Notes.md @@ -0,0 +1,52 @@ +# MariaDB MaxScale 2.1.2 Release Notes + +Release 2.1.2 is a Beta release. + +This document describes the changes in release 2.1.2, when compared to +release [2.1.1](MaxScale-2.1.1-Release-Notes.md). + +If you are upgrading from release 2.0, please also read the following +release notes: +[2.1.1](./MaxScale-2.1.1-Release-Notes.md) +[2.1.0](./MaxScale-2.1.0-Release-Notes.md) + +For any problems you encounter, please consider submitting a bug +report at [Jira](https://jira.mariadb.org). + +## Changed Features + +### Improved Wildcard Matching + +The MySQLAuth module now supports all types of wildcards for both IP addresses +as well as hostnames. + +## New Features + +### IPv6 Support + +MaxScale now supports IPv6 connections on both the client and backend side as +well as being able to listen on IPv6 addresses. + +## Bug fixes + +[Here is a list of bugs fixed since the release of MaxScale 2.1.1.](https://jira.mariadb.org/issues/?jql=project%20%3D%20MXS%20AND%20issuetype%20%3D%20Bug%20AND%20resolution%20in%20(Fixed%2C%20Done)%20AND%20fixVersion%20%3D%202.1.2%20AND%20fixVersion%20NOT%20IN%20(2.1.1)) + +## Known Issues and Limitations + +There are some limitations and known issues within this version of MaxScale. +For more information, please refer to the [Limitations](../About/Limitations.md) document. + +## Packaging + +RPM and Debian packages are provided for the Linux distributions supported +by MariaDB Enterprise. + +Packages can be downloaded [here](https://mariadb.com/resources/downloads). + +## Source Code + +The source code of MaxScale is tagged at GitHub with a tag, which is identical +with the version of MaxScale. For instance, the tag of version X.Y.Z of MaxScale +is X.Y.Z. Further, *master* always refers to the latest released non-beta version. + +The source code is available [here](https://github.com/mariadb-corporation/MaxScale). diff --git a/include/maxscale/dcb.h b/include/maxscale/dcb.h index 7171e3457..b7c80e487 100644 --- a/include/maxscale/dcb.h +++ b/include/maxscale/dcb.h @@ -195,7 +195,7 @@ typedef struct dcb int flags; /**< DCB flags */ char *remote; /**< Address of remote end */ char *user; /**< User name for connection */ - struct sockaddr_in ipv4; /**< remote end IPv4 address */ + struct sockaddr_storage ip; /**< remote IPv4/IPv6 address */ char *protoname; /**< Name of the protocol */ void *protocol; /**< The protocol specific state */ size_t protocol_packet_length; /**< How long the protocol specific packet is */ @@ -236,7 +236,7 @@ typedef struct dcb } DCB; #define DCB_INIT {.dcb_chk_top = CHK_NUM_DCB, \ - .evq = DCBEVENTQ_INIT, .ipv4 = {0}, .func = {0}, .authfunc = {0}, \ + .evq = DCBEVENTQ_INIT, .ip = {0}, .func = {0}, .authfunc = {0}, \ .stats = {0}, .memdata = DCBMM_INIT, \ .fd = DCBFD_CLOSED, .stats = DCBSTATS_INIT, .ssl_state = SSL_HANDSHAKE_UNKNOWN, \ .state = DCB_STATE_ALLOC, .dcb_chk_tail = CHK_NUM_DCB, \ @@ -339,6 +339,14 @@ void dcb_process_idle_sessions(int thr); */ bool dcb_foreach(bool (*func)(DCB *, void *), void *data); +/** + * @brief Return the port number this DCB is connected to + * + * @param dcb DCB to inspect + * @return Port number the DCB is connected to or -1 if information is not available + */ +int dcb_get_port(const DCB *dcb); + /** * DCB flags values */ diff --git a/include/maxscale/protocol/mysql.h b/include/maxscale/protocol/mysql.h index 14f959add..e0d43b322 100644 --- a/include/maxscale/protocol/mysql.h +++ b/include/maxscale/protocol/mysql.h @@ -407,7 +407,7 @@ bool protocol_get_response_status (MySQLProtocol* p, int* npackets, ssize_t* nby void protocol_set_response_status (MySQLProtocol* p, int npackets, ssize_t nbytes); void protocol_archive_srv_command(MySQLProtocol* p); -char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db, int); +char* create_auth_fail_str(char *username, char *hostaddr, bool password, char *db, int); void init_response_status ( GWBUF* buf, diff --git a/include/maxscale/session.h b/include/maxscale/session.h index a85b9292a..92d38002a 100644 --- a/include/maxscale/session.h +++ b/include/maxscale/session.h @@ -324,6 +324,17 @@ static inline bool session_set_autocommit(MXS_SESSION* ses, bool autocommit) */ MXS_SESSION* session_get_by_id(int id); +/** + * @brief Close a session + * + * Calling this function will start the session shutdown process. The shutdown + * closes all related backend DCBs by calling the closeSession entry point + * of the router session. + * + * @param session The session to close + */ +void session_close(MXS_SESSION *session); + /** * @brief Release a session reference * diff --git a/include/maxscale/utils.h b/include/maxscale/utils.h index 9b9d65070..6f34e47aa 100644 --- a/include/maxscale/utils.h +++ b/include/maxscale/utils.h @@ -35,13 +35,58 @@ MXS_BEGIN_DECLS */ #define MXS_PTR(a, b) (((uint8_t*)(a)) + (b)) +/** The type of the socket */ +enum mxs_socket_type +{ + MXS_SOCKET_LISTENER, /**< */ + MXS_SOCKET_NETWORK, +}; + bool utils_init(); /*< Call this first before using any other function */ void utils_end(); -int setnonblocking(int fd); -int parse_bindconfig(const char *, struct sockaddr_in *); -int setipaddress(struct in_addr *, char *); +/** + * @brief Create a network socket and a socket configuration + * + * This helper function can be used to open both listener socket and network + * connection sockets. For listener sockets, the @c host and @c port parameters + * tell where the socket will bind to. For network sockets, the parameters tell + * where the connection is created. + * + * After calling this function, the only thing that needs to be done is to + * give @c addr and the return value of this function as the parameters to + * either bind() (for listeners) or connect() (for outbound network connections). + * + * @param type Type of the socket, either MXS_SOCKET_LISTENER for a listener + * socket or MXS_SOCKET_NETWORK for a network connection socket + * @param addr Pointer to a struct sockaddr_storage where the socket + * configuration is stored + * @param host The target host for which the socket is created + * @param port The target port on the host + * + * @return The opened socket or -1 on failure + */ +int open_network_socket(enum mxs_socket_type type, struct sockaddr_storage *addr, + const char *host, uint16_t port); +/** + * @brief Create a UNIX domain socket + * + * This opens and prepares a UNIX domain socket for use. The @c addr parameter + * can be given to the bind() function to bind the socket. + * + * @param type Type of the socket, either MXS_SOCKET_LISTENER for a listener + * socket or MXS_SOCKET_NETWORK for a network connection socket + * @param addr Pointer to a struct sockaddr_un where the socket configuration + * is stored + * @param path Path to the socket + * + * @return The opened socket or -1 on failure + */ +int open_unix_socket(enum mxs_socket_type type, struct sockaddr_un *addr, + const char *path); + +int setnonblocking(int fd); char *gw_strend(register const char *s); static char gw_randomchar(); int gw_generate_random_str(char *output, int len); diff --git a/server/core/config.c b/server/core/config.c index c339caf57..9913f2958 100644 --- a/server/core/config.c +++ b/server/core/config.c @@ -83,7 +83,6 @@ typedef struct duplicate_context static bool duplicate_context_init(DUPLICATE_CONTEXT* context); static void duplicate_context_finish(DUPLICATE_CONTEXT* context); -extern int setipaddress(struct in_addr *, char *); static bool process_config_context(CONFIG_CONTEXT *); static bool process_config_update(CONFIG_CONTEXT *); static char *config_get_value(MXS_CONFIG_PARAMETER *, const char *); @@ -3401,16 +3400,14 @@ bool config_param_is_valid(const MXS_MODULE_PARAM *params, const char *key, break; case MXS_MODULE_PARAM_SERVICE: - if ((context && config_contains_type(context, value, "service")) || - service_find(value)) + if (context && config_contains_type(context, value, "service")) { valid = true; } break; case MXS_MODULE_PARAM_SERVER: - if ((context && config_contains_type(context, value, "server")) || - server_find_by_unique_name(value)) + if (context && config_contains_type(context, value, "server")) { valid = true; } diff --git a/server/core/dcb.c b/server/core/dcb.c index 0df6e38be..dfb745f2e 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -152,8 +152,8 @@ static int gw_write(DCB *dcb, GWBUF *writeq, bool *stop_writing); static int gw_write_SSL(DCB *dcb, GWBUF *writeq, bool *stop_writing); static int dcb_log_errors_SSL (DCB *dcb, const char *called_by, int ret); static int dcb_accept_one_connection(DCB *listener, struct sockaddr *client_conn); -static int dcb_listen_create_socket_inet(const char *config_bind); -static int dcb_listen_create_socket_unix(const char *config_bind); +static int dcb_listen_create_socket_inet(const char *host, uint16_t port); +static int dcb_listen_create_socket_unix(const char *path); static int dcb_set_socket_option(int sockfd, int level, int optname, void *optval, socklen_t optlen); static void dcb_add_to_all_list(DCB *dcb); static DCB *dcb_find_free(); @@ -2711,25 +2711,30 @@ dcb_accept(DCB *listener) if (client_conn.ss_family == AF_UNIX) { // client address + // Should this be `localhost` like it is in the MariaDB server? client_dcb->remote = MXS_STRDUP_A("localhost_from_socket"); - // set localhost IP for user authentication - (client_dcb->ipv4).sin_addr.s_addr = 0x0100007F; } else { - /* client IPv4 in raw data*/ - memcpy(&client_dcb->ipv4, - (struct sockaddr_in *)&client_conn, - sizeof(struct sockaddr_in)); - /* client IPv4 in string representation */ - client_dcb->remote = (char *)MXS_CALLOC(INET_ADDRSTRLEN + 1, sizeof(char)); + /* client IP in raw data*/ + memcpy(&client_dcb->ip, &client_conn, sizeof(client_conn)); + /* client IP in string representation */ + client_dcb->remote = (char *)MXS_CALLOC(INET6_ADDRSTRLEN + 1, sizeof(char)); - if (client_dcb->remote != NULL) + if (client_dcb->remote) { - inet_ntop(AF_INET, - &(client_dcb->ipv4).sin_addr, - client_dcb->remote, - INET_ADDRSTRLEN); + void *ptr; + if (client_dcb->ip.ss_family == AF_INET) + { + ptr = &((struct sockaddr_in*)&client_dcb->ip)->sin_addr; + } + else + { + ptr = &((struct sockaddr_in6*)&client_dcb->ip)->sin6_addr; + } + + inet_ntop(client_dcb->ip.ss_family, ptr, + client_dcb->remote, INET6_ADDRSTRLEN); } } memcpy(&client_dcb->func, protocol_funcs, sizeof(MXS_PROTOCOL)); @@ -2884,22 +2889,38 @@ dcb_accept_one_connection(DCB *listener, struct sockaddr *client_conn) * @param protocol_name Name of protocol that is listening * @return 0 if new listener created successfully, otherwise -1 */ -int -dcb_listen(DCB *listener, const char *config, const char *protocol_name) +int dcb_listen(DCB *listener, const char *config, const char *protocol_name) { - int listener_socket; + char host[strlen(config) + 1]; + strcpy(host, config); + char *port_str = strrchr(host, '|'); + uint16_t port = 0; - listener->fd = -1; - if (strchr(config, '/')) + if (port_str) { - listener_socket = dcb_listen_create_socket_unix(config); + *port_str++ = 0; + port = atoi(port_str); + } + + int listener_socket = -1; + + if (strchr(host, '/')) + { + listener_socket = dcb_listen_create_socket_unix(host); + } + else if (port > 0) + { + listener_socket = dcb_listen_create_socket_inet(host, port); } else { - listener_socket = dcb_listen_create_socket_inet(config); + // We don't have a socket path or a network port + ss_dassert(false); } + if (listener_socket < 0) { + ss_dassert(listener_socket == -1); return -1; } @@ -2912,17 +2933,13 @@ dcb_listen(DCB *listener, const char *config, const char *protocol_name) */ if (listen(listener_socket, INT_MAX) != 0) { - char errbuf[MXS_STRERROR_BUFLEN]; MXS_ERROR("Failed to start listening on '%s' with protocol '%s': %d, %s", - config, - protocol_name, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); + config, protocol_name, errno, mxs_strerror(errno)); close(listener_socket); return -1; } - MXS_NOTICE("Listening connections at %s with protocol %s", config, protocol_name); + MXS_NOTICE("Listening for connections at %s with protocol %s", config, protocol_name); // assign listener_socket to dcb listener->fd = listener_socket; @@ -2938,151 +2955,41 @@ dcb_listen(DCB *listener, const char *config, const char *protocol_name) } /** - * @brief Create a listening socket, TCP + * @brief Create a network listener socket * - * Parse the configuration provided and if valid create a socket. - * Set options, set non-blocking and bind to the socket. - * - * @param config_bind The configuration information - * @return socket if successful, -1 otherwise + * @param host The network address to listen on + * @param port The port to listen on + * @return The opened socket or -1 on error */ -static int -dcb_listen_create_socket_inet(const char *config_bind) +static int dcb_listen_create_socket_inet(const char *host, uint16_t port) { - int listener_socket; - struct sockaddr_in server_address; - int one = 1; - - memset(&server_address, 0, sizeof(server_address)); - if (!parse_bindconfig(config_bind, &server_address)) - { - MXS_ERROR("Error in parse_bindconfig for [%s]", config_bind); - return -1; - } - - /** Create the TCP socket */ - if ((listener_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Can't create socket: %i, %s", - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - return -1; - } - - // socket options - if (dcb_set_socket_option(listener_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) != 0 || - dcb_set_socket_option(listener_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one)) != 0) - { - return -1; - } - - // set NONBLOCKING mode - if (setnonblocking(listener_socket) != 0) - { - MXS_ERROR("Failed to set socket to non-blocking mode."); - close(listener_socket); - return -1; - } - - if (bind(listener_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to bind on '%s': %i, %s", - config_bind, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - close(listener_socket); - return -1; - } - return listener_socket; + struct sockaddr_storage server_address = {}; + return open_network_socket(MXS_SOCKET_LISTENER, &server_address, host, port); } /** - * @brief Create a listening socket, Unix + * @brief Create a Unix domain socket * - * Parse the configuration provided and if valid create a socket. - * Set options, set non-blocking and bind to the socket. - * - * @param config_bind The configuration information - * @return socket if successful, -1 otherwise + * @param path The socket path + * @return The opened socket or -1 on error */ -static int -dcb_listen_create_socket_unix(const char *config_bind) +static int dcb_listen_create_socket_unix(const char *path) { - int listener_socket; - struct sockaddr_un local_addr; - int one = 1; - - char *tmp = strrchr(config_bind, ':'); - if (tmp) + if (unlink(path) == -1 && errno != ENOENT) { - *tmp = '\0'; - } - - if (strlen(config_bind) > sizeof(local_addr.sun_path) - 1) - { - MXS_ERROR("The path %s specified for the UNIX domain socket is too long. " - "The maximum length is %lu.", config_bind, sizeof(local_addr.sun_path) - 1); - return -1; - } - - // UNIX socket create - if ((listener_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Can't create UNIX socket: %i, %s", - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - return -1; - } - - // socket options - if (dcb_set_socket_option(listener_socket, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) != 0) - { - return -1; - } - - // set NONBLOCKING mode - if (setnonblocking(listener_socket) != 0) - { - MXS_ERROR("Failed to set socket to non-blocking mode."); - close(listener_socket); - return -1; - } - - memset(&local_addr, 0, sizeof(local_addr)); - local_addr.sun_family = AF_UNIX; - strcpy(local_addr.sun_path, config_bind); - - if ((-1 == unlink(config_bind)) && (errno != ENOENT)) - { - char errbuf[MXS_STRERROR_BUFLEN]; MXS_ERROR("Failed to unlink Unix Socket %s: %d %s", - config_bind, errno, strerror_r(errno, errbuf, sizeof(errbuf))); + path, errno, mxs_strerror(errno)); } - /* Bind the socket to the Unix domain socket */ - if (bind(listener_socket, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) + struct sockaddr_un local_addr; + int listener_socket = open_unix_socket(MXS_SOCKET_LISTENER, &local_addr, path); + + if (listener_socket >= 0 && chmod(path, 0777) < 0) { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to bind to UNIX Domain socket '%s': %i, %s", - config_bind, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - close(listener_socket); - return -1; + MXS_ERROR("Failed to change permissions on UNIX Domain socket '%s': %d, %s", + path, errno, mxs_strerror(errno)); } - /* set permission for all users */ - if (chmod(config_bind, 0777) < 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to change permissions on UNIX Domain socket '%s': %i, %s", - config_bind, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - } return listener_socket; } @@ -3303,3 +3210,25 @@ bool dcb_foreach(bool(*func)(DCB *, void *), void *data) return more; } + +int dcb_get_port(const DCB *dcb) +{ + int rval = -1; + + if (dcb->ip.ss_family == AF_INET) + { + struct sockaddr_in* ip = (struct sockaddr_in*)&dcb->ip; + rval = ntohs(ip->sin_port); + } + else if (dcb->ip.ss_family == AF_INET6) + { + struct sockaddr_in6* ip = (struct sockaddr_in6*)&dcb->ip; + rval = ntohs(ip->sin6_port); + } + else + { + ss_dassert(dcb->ip.ss_family == AF_UNIX); + } + + return rval; +} diff --git a/server/core/monitor.c b/server/core/monitor.c index 1b3b8341d..e885a1275 100644 --- a/server/core/monitor.c +++ b/server/core/monitor.c @@ -998,10 +998,13 @@ bool mon_status_changed(MXS_MONITOR_SERVERS* mon_srv) unsigned int new_status = mon_srv->server->status & all_server_bits; /** - * The state has changed if the relevant state bits are not the same and - * the server is not going into maintenance or coming out of it + * The state has changed if the relevant state bits are not the same, + * the server is either running, stopping or starting and the server is + * not going into maintenance or coming out of it */ - if (old_status != new_status && ((old_status | new_status) & SERVER_MAINT) == 0) + if (old_status != new_status && + ((old_status | new_status) & SERVER_MAINT) == 0 && + ((old_status | new_status) & SERVER_RUNNING) == SERVER_RUNNING) { rval = true; } diff --git a/server/core/service.c b/server/core/service.c index df6b2d168..ac2948582 100644 --- a/server/core/service.c +++ b/server/core/service.c @@ -307,11 +307,11 @@ serviceStartPort(SERVICE *service, SERV_LISTENER *port) if (port->address) { - sprintf(config_bind, "%s:%d", port->address, port->port); + sprintf(config_bind, "%s|%d", port->address, port->port); } else { - sprintf(config_bind, "0.0.0.0:%d", port->port); + sprintf(config_bind, "0.0.0.0|%d", port->port); } /** Load the authentication users before before starting the listener */ diff --git a/server/core/session.c b/server/core/session.c index fff7f9832..d286f2507 100644 --- a/server/core/session.c +++ b/server/core/session.c @@ -303,6 +303,23 @@ session_simple_free(MXS_SESSION *session, DCB *dcb) session_final_free(session); } +void session_close(MXS_SESSION *session) +{ + if (!session->ses_is_child && session->router_session) + { + if (session->state != SESSION_STATE_STOPPING) + { + session->state = SESSION_STATE_STOPPING; + } + + MXS_ROUTER_OBJECT* router = session->service->router; + void* router_instance = session->service->router_instance; + + /** Close router session and all its connections */ + router->closeSession(router_instance, session->router_session); + } +} + /** * Deallocate the specified session * diff --git a/server/core/utils.c b/server/core/utils.c index 400e50cbd..4ad3556ff 100644 --- a/server/core/utils.c +++ b/server/core/utils.c @@ -37,12 +37,14 @@ #include #include #include - +#include +#include #include #include #include #include +#include #include #include #include @@ -889,150 +891,151 @@ void utils_end() SPINLOCK tmplock = SPINLOCK_INIT; -/* - * Set IP address in socket structure in_addr - * - * @param a Pointer to a struct in_addr into which the address is written - * @param p The hostname to lookup - * @return 1 on success, 0 on failure - */ -int -setipaddress(struct in_addr *a, char *p) +static bool configure_network_socket(int so) { -#ifdef __USE_POSIX - struct addrinfo *ai = NULL, hint; - int rc; - struct sockaddr_in *res_addr; - memset(&hint, 0, sizeof (hint)); + int sndbufsize = MXS_BACKEND_SO_SNDBUF; + int rcvbufsize = MXS_BACKEND_SO_RCVBUF; + int one = 1; - hint.ai_socktype = SOCK_STREAM; - - /* - * This is for the listening socket, matching INADDR_ANY only for now. - * For future specific addresses bind, a dedicated routine woulbd be better - */ - - if (strcmp(p, "0.0.0.0") == 0) + if (setsockopt(so, SOL_SOCKET, SO_SNDBUF, &sndbufsize, sizeof(sndbufsize)) != 0 || + setsockopt(so, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, sizeof(rcvbufsize)) != 0 || + setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0) { - hint.ai_flags = AI_PASSIVE; - hint.ai_family = AF_UNSPEC; - if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0) - { - MXS_ERROR("Failed to obtain address for host %s, %s", - p, - gai_strerror(rc)); - - return 0; - } - } - else - { - hint.ai_flags = AI_CANONNAME; - hint.ai_family = AF_INET; - - if ((rc = getaddrinfo(p, NULL, &hint, &ai)) != 0) - { - MXS_ERROR("Failed to obtain address for host %s, %s", - p, - gai_strerror(rc)); - - return 0; - } + MXS_ERROR("Failed to set socket option: %d, %s.", errno, mxs_strerror(errno)); + return false; } - /* take the first one */ - if (ai != NULL) - { - res_addr = (struct sockaddr_in *)(ai->ai_addr); - memcpy(a, &res_addr->sin_addr, sizeof(struct in_addr)); - - freeaddrinfo(ai); - - return 1; - } -#else - struct hostent *h; - - spinlock_acquire(&tmplock); - h = gethostbyname(p); - spinlock_release(&tmplock); - - if (h == NULL) - { - if ((a->s_addr = inet_addr(p)) == -1) - { - MXS_ERROR("gethostbyname failed for [%s]", p); - - return 0; - } - } - else - { - /* take the first one */ - memcpy(a, h->h_addr, h->h_length); - - return 1; - } -#endif - return 0; + return setnonblocking(so) == 0; } - -/** - * Parse the bind config data. This is passed in a string as address:port. - * - * The address may be either a . separated IP address or a hostname to - * lookup. The address 0.0.0.0 is the wildcard address for SOCKADR_ANY. - * The ':' and port are required. - * - * @param config The bind address and port separated by a ':' - * @param addr The sockaddr_in in which the data is written - * @return 0 on failure - */ -int -parse_bindconfig(const char *config, struct sockaddr_in *addr) +static bool configure_listener_socket(int so) { - char buf[strlen(config) + 1]; - strcpy(buf, config); + int one = 1; - char *port = strrchr(buf, ':'); - short pnum; - if (port) + if (setsockopt(so, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0 || + setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0) { - *port = 0; - port++; - pnum = atoi(port); + MXS_ERROR("Failed to set socket option: %d, %s.", errno, mxs_strerror(errno)); + return false; + } + + return setnonblocking(so) == 0; +} + +static void set_port(struct sockaddr_storage *addr, uint16_t port) +{ + if (addr->ss_family == AF_INET) + { + struct sockaddr_in *ip = (struct sockaddr_in*)addr; + ip->sin_port = htons(port); + } + else if (addr->ss_family == AF_INET6) + { + struct sockaddr_in6 *ip = (struct sockaddr_in6*)addr; + ip->sin6_port = htons(port); } else { - return 0; + MXS_ERROR("Unknown address family: %d", (int)addr->ss_family); + ss_dassert(false); + } +} + +int open_network_socket(enum mxs_socket_type type, struct sockaddr_storage *addr, const char *host, uint16_t port) +{ + ss_dassert(type == MXS_SOCKET_NETWORK || type == MXS_SOCKET_LISTENER); +#ifdef __USE_POSIX + struct addrinfo *ai = NULL, hint = {}; + int so, rc; + hint.ai_socktype = SOCK_STREAM; + hint.ai_family = AF_UNSPEC; + hint.ai_flags = AI_ALL; + + if ((rc = getaddrinfo(host, NULL, &hint, &ai)) != 0) + { + MXS_ERROR("Failed to obtain address for host %s: %s", host, gai_strerror(rc)); + return -1; } - if (!strcmp(buf, "0.0.0.0")) + /* Take the first one */ + if (ai) { - addr->sin_addr.s_addr = htonl(INADDR_ANY); - } - else - { - if (!inet_aton(buf, &addr->sin_addr)) + if ((so = socket(ai->ai_family, SOCK_STREAM, 0)) == -1) { - struct hostent *hp = gethostbyname(buf); + MXS_ERROR("Socket creation failed: %d, %s.", errno, mxs_strerror(errno)); + } + else + { + memcpy(addr, ai->ai_addr, ai->ai_addrlen); + set_port(addr, port); - if (hp) + if ((type == MXS_SOCKET_NETWORK && !configure_network_socket(so)) || + (type == MXS_SOCKET_LISTENER && !configure_listener_socket(so))) { - bcopy(hp->h_addr, &(addr->sin_addr.s_addr), hp->h_length); + close(so); + so = -1; } - else + else if (type == MXS_SOCKET_LISTENER && bind(so, (struct sockaddr*)addr, sizeof(*addr)) < 0) { - MXS_ERROR("Failed to lookup host '%s'.", buf); - return 0; + MXS_ERROR("Failed to bind on '%s:%u': %d, %s", + host, port, errno, mxs_strerror(errno)); + close(so); + so = -1; } } + + freeaddrinfo(ai); + } + +#else +#error Only the POSIX networking interface is supported +#endif + + return so; +} + +static bool configure_unix_socket(int so) +{ + int one = 1; + + if (setsockopt(so, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) + { + MXS_ERROR("Failed to set socket option: %d, %s.", errno, mxs_strerror(errno)); + return false; + } + + return setnonblocking(so) == 0; +} + +int open_unix_socket(enum mxs_socket_type type, struct sockaddr_un *addr, const char *path) +{ + int fd = -1; + + if (strlen(path) > sizeof(addr->sun_path) - 1) + { + MXS_ERROR("The path %s specified for the UNIX domain socket is too long. " + "The maximum length is %lu.", path, sizeof(addr->sun_path) - 1); + } + else if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + MXS_ERROR("Can't create UNIX socket: %d, %s", errno, mxs_strerror(errno)); + } + else if (configure_unix_socket(fd)) + { + addr->sun_family = AF_UNIX; + strcpy(addr->sun_path, path); + + /* Bind the socket to the Unix domain socket */ + if (type == MXS_SOCKET_LISTENER && bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) + { + MXS_ERROR("Failed to bind to UNIX Domain socket '%s': %d, %s", + path, errno, mxs_strerror(errno)); + close(fd); + fd = -1; + } } - addr->sin_family = AF_INET; - addr->sin_port = htons(pnum); - return 1; + return fd; } /** diff --git a/server/modules/authenticator/MySQLAuth/dbusers.c b/server/modules/authenticator/MySQLAuth/dbusers.c index b8f505809..4ed39d91b 100644 --- a/server/modules/authenticator/MySQLAuth/dbusers.c +++ b/server/modules/authenticator/MySQLAuth/dbusers.c @@ -53,7 +53,7 @@ static int get_users(SERV_LISTENER *listener); static MYSQL *gw_mysql_init(void); static int gw_mysql_set_timeouts(MYSQL* handle); static char *mysql_format_user_entry(void *data); -static bool get_hostname(const char *ip_address, char *client_hostname); +static bool get_hostname(DCB *dcb, char *client_hostname, size_t size); static char* get_new_users_query(const char *server_version, bool include_root) { @@ -208,7 +208,8 @@ int validate_mysql_user(sqlite3 *handle, DCB *dcb, MYSQL_session *session, * as a last resort so we avoid the high cost of the DNS lookup. */ char client_hostname[MYSQL_HOST_MAXLEN]; - get_hostname(dcb->remote, client_hostname); + get_hostname(dcb, client_hostname, sizeof(client_hostname) - 1); + sprintf(sql, mysqlauth_validate_user_query, session->user, client_hostname, client_hostname, session->db, session->db); @@ -237,12 +238,6 @@ int validate_mysql_user(sqlite3 *handle, DCB *dcb, MYSQL_session *session, rval = MXS_AUTH_FAILED_DB; } } - else if (session->auth_token_len) - { - /** If authentication fails, this will trigger the right - * error message with `Using password : YES` */ - session->client_sha1[0] = '_'; - } } return rval; @@ -269,6 +264,69 @@ static bool delete_mysql_users(sqlite3 *handle) return rval; } +/** + * If the hostname is of form a.b.c.d/e.f.g.h where e-h is 255 or 0, replace + * the zeros in the first part with '%' and remove the second part. This does + * not yet support netmasks completely, but should be sufficient for most + * situations. In case of error, the hostname may end in an invalid state, which + * will cause an error later on. + * + * @param host The hostname, which is modified in-place. If merging is unsuccessful, + * it may end up garbled. + */ +static void merge_netmask(char *host) +{ + char *delimiter_loc = strchr(host, '/'); + if (delimiter_loc == NULL) + { + return; // Nothing to do + } + /* If anything goes wrong, we put the '/' back in to ensure the hostname + * cannot be used. + */ + *delimiter_loc = '\0'; + + char *ip_token_loc = host; + char *mask_token_loc = delimiter_loc + 1; // This is at minimum a \0 + + while (ip_token_loc && mask_token_loc) + { + if (strncmp(mask_token_loc, "255", 3) == 0) + { + // Skip + } + else if (*mask_token_loc == '0' && *ip_token_loc == '0') + { + *ip_token_loc = '%'; + } + else + { + /* Any other combination is considered invalid. This may leave the + * hostname in a partially modified state. + * TODO: handle more cases + */ + *delimiter_loc = '/'; + MXS_ERROR("Unrecognized IP-bytes in host/mask-combination. " + "Merge incomplete: %s", host); + return; + } + + ip_token_loc = strchr(ip_token_loc, '.'); + mask_token_loc = strchr(mask_token_loc, '.'); + if (ip_token_loc && mask_token_loc) + { + ip_token_loc++; + mask_token_loc++; + } + } + if (ip_token_loc || mask_token_loc) + { + *delimiter_loc = '/'; + MXS_ERROR("Unequal number of IP-bytes in host/mask-combination. " + "Merge incomplete: %s", host); + } +} + void add_mysql_user(sqlite3 *handle, const char *user, const char *host, const char *db, bool anydb, const char *pw) { @@ -611,30 +669,27 @@ bool check_service_permissions(SERVICE* service) * * @return True if the hostname query was successful */ -static bool get_hostname(const char *ip_address, char *client_hostname) +static bool get_hostname(DCB *dcb, char *client_hostname, size_t size) { - /* Looks like the parameters are valid. First, convert the client IP string - * to binary form. This is somewhat silly, since just a while ago we had the - * binary address but had to zero it. dbusers.c should be refactored to fix this. - */ - struct sockaddr_in bin_address; - bin_address.sin_family = AF_INET; - if (inet_pton(bin_address.sin_family, ip_address, &(bin_address.sin_addr)) != 1) + struct addrinfo *ai = NULL, hint = {}; + hint.ai_flags = AI_ALL; + int rc; + + if ((rc = getaddrinfo(dcb->remote, NULL, &hint, &ai)) != 0) { - MXS_ERROR("Could not convert to binary ip-address: '%s'.", ip_address); + MXS_ERROR("Failed to obtain address for host %s, %s", + dcb->remote, gai_strerror(rc)); return false; } /* Try to lookup the domain name of the given IP-address. This is a slow * i/o-operation, which will stall the entire thread. TODO: cache results - * if this feature is used often. - */ - MXS_DEBUG("Resolving '%s'", ip_address); - int lookup_result = getnameinfo((struct sockaddr*)&bin_address, - sizeof(struct sockaddr_in), - client_hostname, sizeof(client_hostname), + * if this feature is used often. */ + int lookup_result = getnameinfo(ai->ai_addr, ai->ai_addrlen, + client_hostname, size, NULL, 0, // No need for the port NI_NAMEREQD); // Text address only + freeaddrinfo(ai); if (lookup_result != 0) { @@ -646,7 +701,7 @@ static bool get_hostname(const char *ip_address, char *client_hostname) MXS_DEBUG("IP-lookup success, hostname is: '%s'", client_hostname); } - return false; + return lookup_result == 0; } void start_sqlite_transaction(sqlite3 *handle) @@ -695,8 +750,6 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server, SERVICE *service, SERV { start_sqlite_transaction(instance->handle); - /** Delete the old users */ - delete_mysql_users(instance->handle); MYSQL_ROW row; while ((row = mysql_fetch_row(result))) @@ -706,6 +759,11 @@ int get_users_from_server(MYSQL *con, SERVER_REF *server, SERVICE *service, SERV strip_escape_chars(row[2]); } + if (strchr(row[1], '/')) + { + merge_netmask(row[1]); + } + add_mysql_user(instance->handle, row[0], row[1], row[2], row[3] && strcmp(row[3], "Y") == 0, row[4]); users++; @@ -786,6 +844,10 @@ static int get_users(SERV_LISTENER *listener) return -1; } + /** Delete the old users */ + MYSQL_AUTH *instance = (MYSQL_AUTH*)listener->auth_instance; + delete_mysql_users(instance->handle); + SERVER_REF *server = service->dbref; int total_users = -1; diff --git a/server/modules/authenticator/MySQLAuth/mysql_auth.c b/server/modules/authenticator/MySQLAuth/mysql_auth.c index a29487419..62793d167 100644 --- a/server/modules/authenticator/MySQLAuth/mysql_auth.c +++ b/server/modules/authenticator/MySQLAuth/mysql_auth.c @@ -106,18 +106,19 @@ MXS_MODULE* MXS_CREATE_MODULE() return &info; } -static void get_database_path(SERV_LISTENER *port, char *dest) +static void get_database_path(SERV_LISTENER *port, char *dest, size_t size) { MYSQL_AUTH *instance = port->auth_instance; SERVICE *service = port->service; + ss_dassert(size - sizeof(DBUSERS_FILE) - 1 >= 0); if (instance->cache_dir) { - snprintf(dest, sizeof(dest) - sizeof(DBUSERS_FILE) - 1, "%s/", instance->cache_dir); + snprintf(dest, size, "%s/", instance->cache_dir); } else { - sprintf(dest, "%s/%s/%s/%s/", get_cachedir(), service->name, port->name, DBUSERS_DIR); + snprintf(dest, size, "%s/%s/%s/%s/", get_cachedir(), service->name, port->name, DBUSERS_DIR); } if (mxs_mkdir_all(dest, S_IRWXU)) @@ -254,6 +255,30 @@ static void mysql_auth_destroy(void *data) } } +static bool is_localhost_address(struct sockaddr_storage *addr) +{ + bool rval = false; + + if (addr->ss_family == AF_INET) + { + struct sockaddr_in *ip = (struct sockaddr_in*)addr; + if (ip->sin_addr.s_addr == INADDR_LOOPBACK) + { + rval = true; + } + } + else if (addr->ss_family == AF_INET6) + { + struct sockaddr_in6 *ip = (struct sockaddr_in6*)addr; + if (memcmp(&ip->sin6_addr, &in6addr_loopback, sizeof(ip->sin6_addr)) == 0) + { + rval = true; + } + } + + return rval; +} + /** * @brief Authenticates a MySQL user who is a client to MaxScale. * @@ -325,13 +350,13 @@ mysql_auth_authenticate(DCB *dcb) else if (dcb->service->log_auth_warnings) { MXS_WARNING("%s: login attempt for user '%s'@%s:%d, authentication failed.", - dcb->service->name, client_data->user, dcb->remote, ntohs(dcb->ipv4.sin_port)); - if (dcb->ipv4.sin_addr.s_addr == 0x0100007F && + dcb->service->name, client_data->user, dcb->remote, dcb_get_port(dcb)); + + if (is_localhost_address(&dcb->ip) && !dcb->service->localhost_match_wildcard_host) { - MXS_NOTICE("If you have a wildcard grant that covers" - " this address, try adding " - "'localhost_match_wildcard_host=true' for " + MXS_NOTICE("If you have a wildcard grant that covers this address, " + "try adding 'localhost_match_wildcard_host=true' for " "service '%s'. ", dcb->service->name); } } @@ -374,7 +399,7 @@ mysql_auth_set_protocol_data(DCB *dcb, GWBUF *buf) if (auth_ses->handle == NULL) { char path[PATH_MAX]; - get_database_path(dcb->listener, path); + get_database_path(dcb->listener, path, sizeof(path)); if (!open_client_database(path, &auth_ses->handle)) { @@ -591,7 +616,7 @@ static int mysql_auth_load_users(SERV_LISTENER *port) if (instance->handle == NULL) { char path[PATH_MAX]; - get_database_path(port, path); + get_database_path(port, path, sizeof(path)); if (!open_instance_database(path, &instance->handle)) { return MXS_AUTH_LOADUSERS_FATAL; diff --git a/server/modules/filter/namedserverfilter/namedserverfilter.cc b/server/modules/filter/namedserverfilter/namedserverfilter.cc index 7f32371cf..02e0a3d69 100644 --- a/server/modules/filter/namedserverfilter/namedserverfilter.cc +++ b/server/modules/filter/namedserverfilter/namedserverfilter.cc @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -52,7 +53,7 @@ struct RegexHintSess_t; typedef struct source_host { - const char *address; + char *address; struct sockaddr_in ipv4; int netmask; } REGEXHINT_SOURCE_HOST; @@ -75,7 +76,7 @@ private: volatile unsigned int m_total_diverted; volatile unsigned int m_total_undiverted; - int check_source_host(const char *remote, const struct sockaddr_in *ipv4); + int check_source_host(const char *remote, const struct sockaddr_storage *ip); public: RegexHintInst(string match, string server, string user, REGEXHINT_SOURCE_HOST* source, @@ -135,6 +136,10 @@ RegexHintInst::RegexHintInst(string match, string server, string user, RegexHintInst::~RegexHintInst() { pcre2_code_free(m_regex); + if (m_source) + { + MXS_FREE(m_source->address); + } MXS_FREE(m_source); } @@ -158,7 +163,7 @@ RegexHintSess_t* RegexHintInst::newSession(MXS_SESSION *session) (remote = session_get_remote(session)) != NULL) { my_session->active = - this->check_source_host(remote, &session->client_dcb->ipv4); + this->check_source_host(remote, &session->client_dcb->ip); } /* Check client user against 'user' option */ @@ -253,12 +258,12 @@ void RegexHintInst::diagnostic(RegexHintSess_t* my_session, DCB *dcb) * @param ipv4 The client IPv4 struct * @return 1 for match, 0 otherwise */ -int RegexHintInst::check_source_host(const char *remote, const struct sockaddr_in *ipv4) +int RegexHintInst::check_source_host(const char *remote, const struct sockaddr_storage *ip) { int ret = 0; struct sockaddr_in check_ipv4; - memcpy(&check_ipv4, ipv4, sizeof(check_ipv4)); + memcpy(&check_ipv4, ip, sizeof(check_ipv4)); switch (m_source->netmask) { @@ -552,28 +557,26 @@ static bool validate_ip_address(const char *host) */ static REGEXHINT_SOURCE_HOST *set_source_address(const char *input_host) { + ss_dassert(input_host); int netmask = 32; int bytes = 0; - struct sockaddr_in serv_addr; REGEXHINT_SOURCE_HOST *source_host = (REGEXHINT_SOURCE_HOST*)MXS_CALLOC(1, sizeof(REGEXHINT_SOURCE_HOST)); - if (!input_host || !source_host) + if (!source_host) { return NULL; } if (!validate_ip_address(input_host)) { - MXS_WARNING("The given 'source' parameter source=%s" - " is not a valid IP address: it will not be used.", - input_host); - - source_host->address = NULL; - return source_host; + MXS_WARNING("The given 'source' parameter '%s'" + " is not a valid IPv4 address.", input_host); + MXS_FREE(source_host); + return NULL; } - source_host->address = input_host; + source_host->address = MXS_STRDUP_A(input_host); /* If no wildcards don't check it, set netmask to 32 and return */ if (!strchr(input_host, '%')) @@ -610,9 +613,15 @@ static REGEXHINT_SOURCE_HOST *set_source_address(const char *input_host) *out = '\0'; source_host->netmask = netmask; + struct addrinfo *ai = NULL, hint = {}; + hint.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED; + int rc = getaddrinfo(input_host, NULL, &hint, &ai); + /* fill IPv4 data struct */ - if (setipaddress(&source_host->ipv4.sin_addr, format_host) && strlen(format_host)) + if (rc == 0) { + ss_dassert(ai->ai_family == AF_INET); + memcpy(&source_host->ipv4, ai->ai_addr, ai->ai_addrlen); /* if netmask < 32 there are % wildcards */ if (source_host->netmask < 32) @@ -621,16 +630,16 @@ static REGEXHINT_SOURCE_HOST *set_source_address(const char *input_host) source_host->ipv4.sin_addr.s_addr &= 0x00FFFFFF; } - MXS_INFO("Input %s is valid with netmask %d\n", - source_host->address, - source_host->netmask); + MXS_INFO("Input %s is valid with netmask %d", source_host->address, source_host->netmask); + freeaddrinfo(ai); } else { - MXS_WARNING("Found invalid IP address for parameter 'source=%s'," - " it will not be used.", - input_host); - source_host->address = NULL; + MXS_WARNING("Found invalid IP address for parameter 'source=%s': %s", + input_host, gai_strerror(rc)); + MXS_FREE(source_host->address); + MXS_FREE(source_host); + return NULL; } return (REGEXHINT_SOURCE_HOST *)source_host; diff --git a/server/modules/filter/tee/tee.c b/server/modules/filter/tee/tee.c index 768c6b88a..da8a961da 100644 --- a/server/modules/filter/tee/tee.c +++ b/server/modules/filter/tee/tee.c @@ -536,22 +536,9 @@ closeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session) if ((bsession = my_session->branch_session) != NULL) { CHK_SESSION(bsession); - - if (bsession->state != SESSION_STATE_STOPPING) - { - bsession->state = SESSION_STATE_STOPPING; - } - router = bsession->service->router; - router_instance = bsession->service->router_instance; - rsession = bsession->router_session; - - /** Close router session and all its connections */ - router->closeSession(router_instance, rsession); + bsession->ses_is_child = false; + session_close(bsession); } - /* No need to free the session, this is done as - * a side effect of closing the client DCB of the - * session. - */ if (my_session->waiting[PARENT]) { diff --git a/server/modules/monitor/mysqlmon/mysql_mon.c b/server/modules/monitor/mysqlmon/mysql_mon.c index 4e429be09..e4e5f26b3 100644 --- a/server/modules/monitor/mysqlmon/mysql_mon.c +++ b/server/modules/monitor/mysqlmon/mysql_mon.c @@ -1777,8 +1777,11 @@ static MXS_MONITOR_SERVERS *get_replication_tree(MXS_MONITOR *mon, int num_serve master->server->unique_name); ss_dassert(info); - /** Only set the Master status if read_only is disabled */ - monitor_set_pending_status(master, info->read_only ? SERVER_SLAVE : SERVER_MASTER); + if (SERVER_IS_RUNNING(master->server)) + { + /** Only set the Master status if read_only is disabled */ + monitor_set_pending_status(master, info->read_only ? SERVER_SLAVE : SERVER_MASTER); + } handle->master = master; } diff --git a/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c b/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c index f2414859a..3c32f4958 100644 --- a/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c +++ b/server/modules/protocol/MySQL/MySQLBackend/mysql_backend.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -271,88 +270,20 @@ return_fd: * backend server. In failure, fd == -1 and socket is closed. * */ -static int -gw_do_connect_to_backend(char *host, int port, int *fd) +static int gw_do_connect_to_backend(char *host, int port, int *fd) { - struct sockaddr_in serv_addr; - int rv; - int so = 0; - int bufsize; + struct sockaddr_storage serv_addr = {}; + int rv = -1; - memset(&serv_addr, 0, sizeof serv_addr); - serv_addr.sin_family = (int)AF_INET; - so = socket((int)AF_INET, (int)SOCK_STREAM, 0); - - if (so < 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Establishing connection to backend server " - "%s:%d failed.\n\t\t Socket creation failed " - "due %d, %s.", - host, - port, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - rv = -1; - goto return_rv; - } /* prepare for connect */ - setipaddress(&serv_addr.sin_addr, host); - serv_addr.sin_port = htons(port); - bufsize = MXS_BACKEND_SO_SNDBUF; + int so = open_network_socket(MXS_SOCKET_NETWORK, &serv_addr, host, port); - if (setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) != 0) + if (so == -1) { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to set socket options " - "%s:%d failed.\n\t\t Socket configuration failed " - "due %d, %s.", - host, - port, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - rv = -1; - /** Close socket */ - close_socket(so); - goto return_rv; - } - bufsize = MXS_BACKEND_SO_RCVBUF; - - if (setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) != 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to set socket options " - "%s:%d failed.\n\t\t Socket configuration failed " - "due %d, %s.", - host, - port, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - rv = -1; - /** Close socket */ - close_socket(so); - goto return_rv; + MXS_ERROR("Establishing connection to backend server %s:%d failed.", host, port); + return rv; } - int one = 1; - if (setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to set socket options " - "%s:%d failed.\n\t\t Socket configuration failed " - "due %d, %s.", - host, - port, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - rv = -1; - /** Close socket */ - close_socket(so); - goto return_rv; - } - - /* set socket to as non-blocking here */ - setnonblocking(so); rv = connect(so, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); if (rv != 0) @@ -363,24 +294,17 @@ gw_do_connect_to_backend(char *host, int port, int *fd) } else { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to connect backend server %s:%d, " - "due %d, %s.", - host, - port, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - /** Close socket */ - close_socket(so); - goto return_rv; + MXS_ERROR("Failed to connect backend server %s:%d due to: %d, %s.", + host, port, errno, mxs_strerror(errno)); + close(so); + return rv; } } + *fd = so; MXS_DEBUG("%lu [gw_do_connect_to_backend] Connected to backend server " - "%s:%d, fd %d.", - pthread_self(), host, port, so); + "%s:%d, fd %d.", pthread_self(), host, port, so); -return_rv: return rv; } @@ -1188,46 +1112,31 @@ static int gw_backend_hangup(DCB *dcb) */ static int gw_backend_close(DCB *dcb) { - MXS_SESSION* session; - GWBUF* quitbuf; - CHK_DCB(dcb); - session = dcb->session; - - MXS_DEBUG("%lu [gw_backend_close]", pthread_self()); - - quitbuf = mysql_create_com_quit(NULL, 0); - gwbuf_set_type(quitbuf, GWBUF_TYPE_MYSQL); + ss_dassert(dcb->session); /** Send COM_QUIT to the backend being closed */ + GWBUF* quitbuf = mysql_create_com_quit(NULL, 0); + gwbuf_set_type(quitbuf, GWBUF_TYPE_MYSQL); mysql_send_com_quit(dcb, 0, quitbuf); + /** Free protocol data */ mysql_protocol_done(dcb); - if (session) - { - CHK_SESSION(session); - /** - * The lock is needed only to protect the read of session->state and - * session->client_dcb values. Client's state may change by other thread - * but client's close and adding client's DCB to zombies list is executed - * only if client's DCB's state does _not_ change in parallel. - */ + MXS_SESSION* session = dcb->session; + CHK_SESSION(session); - /** - * If session->state is STOPPING, start closing client session. - * Otherwise only this backend connection is closed. - */ - if (session->state == SESSION_STATE_STOPPING && - session->client_dcb != NULL) - { - if (session->client_dcb->state == DCB_STATE_POLLING) - { - /** Close client DCB */ - dcb_close(session->client_dcb); - } - } + /** + * If session state is SESSION_STATE_STOPPING, start closing client session. + * Otherwise only this backend connection is closed. + */ + if (session->client_dcb && + session->state == SESSION_STATE_STOPPING && + session->client_dcb->state == DCB_STATE_POLLING) + { + dcb_close(session->client_dcb); } + return 1; } @@ -1446,7 +1355,7 @@ static int gw_change_user(DCB *backend, message = create_auth_fail_str(username, backend->session->client_dcb->remote, password_set, - "", + false, auth_ret); if (message == NULL) { @@ -1683,21 +1592,6 @@ static bool sescmd_response_complete(DCB* dcb) return succp; } -static void inline -close_socket(int sock) -{ - /*< Close newly created socket. */ - if (close(sock) != 0) - { - char errbuf[MXS_STRERROR_BUFLEN]; - MXS_ERROR("Failed to close socket %d due %d, %s.", - sock, - errno, - strerror_r(errno, errbuf, sizeof(errbuf))); - } - -} - /** * Create COM_CHANGE_USER packet and store it to GWBUF * diff --git a/server/modules/protocol/MySQL/MySQLClient/mysql_client.c b/server/modules/protocol/MySQL/MySQLClient/mysql_client.c index a9aaff2ab..2fcb715bb 100644 --- a/server/modules/protocol/MySQL/MySQLClient/mysql_client.c +++ b/server/modules/protocol/MySQL/MySQLClient/mysql_client.c @@ -83,7 +83,6 @@ static void mysql_client_auth_error_handling(DCB *dcb, int auth_val, int packet_ static int gw_read_do_authentication(DCB *dcb, GWBUF *read_buffer, int nbytes_read); static int gw_read_normal_data(DCB *dcb, GWBUF *read_buffer, int nbytes_read); static int gw_read_finish_processing(DCB *dcb, GWBUF *read_buffer, uint64_t capabilities); -extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db, int); static bool ensure_complete_packet(DCB *dcb, GWBUF **read_buffer, int nbytes_read); static void gw_process_one_new_client(DCB *client_dcb); @@ -1047,86 +1046,67 @@ mysql_client_auth_error_handling(DCB *dcb, int auth_val, int packet_number) { int message_len; char *fail_str = NULL; + MYSQL_session *session = (MYSQL_session*)dcb->data; switch (auth_val) { case MXS_AUTH_NO_SESSION: - MXS_DEBUG("%lu [gw_read_client_event] session " - "creation failed. fd %d, " - "state = MYSQL_AUTH_NO_SESSION.", - pthread_self(), - dcb->fd); + MXS_DEBUG("%lu [gw_read_client_event] session creation failed. fd %d, " + "state = MYSQL_AUTH_NO_SESSION.", pthread_self(), dcb->fd); /** Send ERR 1045 to client */ - mysql_send_auth_error(dcb, - packet_number, - 0, - "failed to create new session"); + mysql_send_auth_error(dcb, packet_number, 0, "failed to create new session"); break; + case MXS_AUTH_FAILED_DB: - MXS_DEBUG("%lu [gw_read_client_event] database " - "specified was not valid. fd %d, " - "state = MYSQL_FAILED_AUTH_DB.", - pthread_self(), - dcb->fd); + MXS_DEBUG("%lu [gw_read_client_event] database specified was not valid. fd %d, " + "state = MYSQL_FAILED_AUTH_DB.", pthread_self(), dcb->fd); /** Send error 1049 to client */ message_len = 25 + MYSQL_DATABASE_MAXLEN; fail_str = MXS_CALLOC(1, message_len + 1); MXS_ABORT_IF_NULL(fail_str); - snprintf(fail_str, message_len, "Unknown database '%s'", - (char*)((MYSQL_session *)dcb->data)->db); + snprintf(fail_str, message_len, "Unknown database '%s'", session->db); modutil_send_mysql_err_packet(dcb, packet_number, 0, 1049, "42000", fail_str); break; + case MXS_AUTH_FAILED_SSL: MXS_DEBUG("%lu [gw_read_client_event] client is " "not SSL capable for SSL listener. fd %d, " - "state = MYSQL_FAILED_AUTH_SSL.", - pthread_self(), - dcb->fd); + "state = MYSQL_FAILED_AUTH_SSL.", pthread_self(), dcb->fd); /** Send ERR 1045 to client */ - mysql_send_auth_error(dcb, - packet_number, - 0, - "Access without SSL denied"); + mysql_send_auth_error(dcb, packet_number, 0, "Access without SSL denied"); break; + case MXS_AUTH_SSL_INCOMPLETE: MXS_DEBUG("%lu [gw_read_client_event] unable to " "complete SSL authentication. fd %d, " - "state = MYSQL_AUTH_SSL_INCOMPLETE.", - pthread_self(), - dcb->fd); + "state = MYSQL_AUTH_SSL_INCOMPLETE.", pthread_self(), dcb->fd); /** Send ERR 1045 to client */ - mysql_send_auth_error(dcb, - packet_number, - 0, + mysql_send_auth_error(dcb, packet_number, 0, "failed to complete SSL authentication"); break; + case MXS_AUTH_FAILED: MXS_DEBUG("%lu [gw_read_client_event] authentication failed. fd %d, " - "state = MYSQL_FAILED_AUTH.", - pthread_self(), - dcb->fd); + "state = MYSQL_FAILED_AUTH.", pthread_self(), dcb->fd); /** Send error 1045 to client */ - fail_str = create_auth_fail_str((char *)((MYSQL_session *)dcb->data)->user, - dcb->remote, - (char*)((MYSQL_session *)dcb->data)->client_sha1, - (char*)((MYSQL_session *)dcb->data)->db, auth_val); + fail_str = create_auth_fail_str(session->user, dcb->remote, + session->auth_token_len > 0, + session->db, auth_val); modutil_send_mysql_err_packet(dcb, packet_number, 0, 1045, "28000", fail_str); break; + default: MXS_DEBUG("%lu [gw_read_client_event] authentication failed. fd %d, " - "state unrecognized.", - pthread_self(), - dcb->fd); + "state unrecognized.", pthread_self(), dcb->fd); /** Send error 1045 to client */ - fail_str = create_auth_fail_str((char *)((MYSQL_session *)dcb->data)->user, - dcb->remote, - (char*)((MYSQL_session *)dcb->data)->client_sha1, - (char*)((MYSQL_session *)dcb->data)->db, auth_val); + fail_str = create_auth_fail_str(session->user, dcb->remote, + session->auth_token_len > 0, + session->db, auth_val); modutil_send_mysql_err_packet(dcb, packet_number, 0, 1045, "28000", fail_str); } MXS_FREE(fail_str); @@ -1347,52 +1327,12 @@ retblock: return 1; } -static int -gw_client_close(DCB *dcb) +static int gw_client_close(DCB *dcb) { - MXS_SESSION* session; - MXS_ROUTER_OBJECT* router; - void* router_instance; -#if defined(SS_DEBUG) - MySQLProtocol* protocol = (MySQLProtocol *)dcb->protocol; - - if (dcb->state == DCB_STATE_POLLING || - dcb->state == DCB_STATE_NOPOLLING || - dcb->state == DCB_STATE_ZOMBIE) - { - if (!DCB_IS_CLONE(dcb)) - { - CHK_PROTOCOL(protocol); - } - } -#endif - MXS_DEBUG("%lu [gw_client_close]", pthread_self()); + CHK_DCB(dcb); + ss_dassert(dcb->protocol); mysql_protocol_done(dcb); - session = dcb->session; - /** - * session may be NULL if session_alloc failed. - * In that case, router session wasn't created. - */ - if (session != NULL && SESSION_STATE_DUMMY != session->state) - { - CHK_SESSION(session); - - if (session->state != SESSION_STATE_STOPPING) - { - session->state = SESSION_STATE_STOPPING; - } - router_instance = session->service->router_instance; - router = session->service->router; - /** - * If router session is being created concurrently router - * session might be NULL and it shouldn't be closed. - */ - if (session->router_session != NULL) - { - /** Close router session and all its connections */ - router->closeSession(router_instance, session->router_session); - } - } + session_close(dcb->session); return 1; } diff --git a/server/modules/protocol/MySQL/mysql_common.c b/server/modules/protocol/MySQL/mysql_common.c index 8103ff9aa..a2db80fd4 100644 --- a/server/modules/protocol/MySQL/mysql_common.c +++ b/server/modules/protocol/MySQL/mysql_common.c @@ -925,16 +925,17 @@ char* create_auth_failed_msg(GWBUF*readbuf, /** * Create a message error string to send via MySQL ERR packet. * - * @param username the MySQL user - * @param hostaddr the client IP - * @param sha1 authentication scramble data - * @param db the MySQL db to connect to + * @param username The MySQL user + * @param hostaddr The client IP + * @param password If client provided a password + * @param db The default database the client requested + * @param errcode Authentication error code * * @return Pointer to the allocated string or NULL on failure */ char *create_auth_fail_str(char *username, char *hostaddr, - char *sha1, + bool password, char *db, int errcode) { @@ -974,7 +975,7 @@ char *create_auth_fail_str(char *username, if (db_len > 0) { - sprintf(errstr, ferrstr, username, hostaddr, (*sha1 == '\0' ? "NO" : "YES"), db); + sprintf(errstr, ferrstr, username, hostaddr, password ? "YES": "NO", db); } else if (errcode == MXS_AUTH_FAILED_SSL) { @@ -982,7 +983,7 @@ char *create_auth_fail_str(char *username, } else { - sprintf(errstr, ferrstr, username, hostaddr, (*sha1 == '\0' ? "NO" : "YES")); + sprintf(errstr, ferrstr, username, hostaddr, password ? "YES" : "NO"); } retblock: diff --git a/server/modules/routing/avrorouter/avro.c b/server/modules/routing/avrorouter/avro.c index 86ba44c52..dad64c4ee 100644 --- a/server/modules/routing/avrorouter/avro.c +++ b/server/modules/routing/avrorouter/avro.c @@ -904,7 +904,7 @@ diagnostics(MXS_ROUTER *router, DCB *dcb) dcb_printf(dcb, "\t\tClient UUID: %s\n", session->uuid); dcb_printf(dcb, "\t\tClient_host_port: %s:%d\n", - session->dcb->remote, ntohs((session->dcb->ipv4).sin_port)); + session->dcb->remote, dcb_get_port(session->dcb)); dcb_printf(dcb, "\t\tUsername: %s\n", session->dcb->user); dcb_printf(dcb, "\t\tClient DCB: %p\n", session->dcb); dcb_printf(dcb, "\t\tClient protocol: %s\n", diff --git a/server/modules/routing/binlogrouter/blr.c b/server/modules/routing/binlogrouter/blr.c index 550137af1..cfa5cc735 100644 --- a/server/modules/routing/binlogrouter/blr.c +++ b/server/modules/routing/binlogrouter/blr.c @@ -1173,7 +1173,7 @@ closeSession(MXS_ROUTER *instance, MXS_ROUTER_SESSION *router_session) MXS_NOTICE("%s: Slave %s:%d, server id %d, disconnected after %ld seconds. " "%d SQL commands, %d events sent (%lu bytes), binlog '%s', " "last position %lu", - router->service->name, slave->dcb->remote, ntohs((slave->dcb->ipv4).sin_port), + router->service->name, slave->dcb->remote, dcb_get_port(slave->dcb), slave->serverid, time(0) - slave->connect_time, slave->stats.n_queries, @@ -1581,7 +1581,7 @@ diagnostics(MXS_ROUTER *router, DCB *dcb) } dcb_printf(dcb, "\t\tSlave_host_port: %s:%d\n", - session->dcb->remote, ntohs((session->dcb->ipv4).sin_port)); + session->dcb->remote, dcb_get_port(session->dcb)); dcb_printf(dcb, "\t\tUsername: %s\n", session->dcb->user); diff --git a/server/modules/routing/binlogrouter/blr.h b/server/modules/routing/binlogrouter/blr.h index 7427fae10..4f360ca02 100644 --- a/server/modules/routing/binlogrouter/blr.h +++ b/server/modules/routing/binlogrouter/blr.h @@ -736,14 +736,15 @@ typedef struct binlog_pos_fix #define BLRM_SERVER_VARS 0x0016 #define BLRM_BINLOG_VARS 0x0017 #define BLRM_LOWER_CASE_TABLES 0x0018 -#define BLRM_REGISTER 0x0019 -#define BLRM_CHECK_SEMISYNC 0x001A -#define BLRM_REQUEST_SEMISYNC 0x001B -#define BLRM_REQUEST_BINLOGDUMP 0x001C -#define BLRM_BINLOGDUMP 0x001D -#define BLRM_SLAVE_STOPPED 0x001E +#define BLRM_REGISTER_READY 0x0019 +#define BLRM_REGISTER 0x001A +#define BLRM_CHECK_SEMISYNC 0x001B +#define BLRM_REQUEST_SEMISYNC 0x001C +#define BLRM_REQUEST_BINLOGDUMP 0x001D +#define BLRM_BINLOGDUMP 0x001E +#define BLRM_SLAVE_STOPPED 0x001F -#define BLRM_MAXSTATE 0x001E +#define BLRM_MAXSTATE 0x001F static char *blrm_states[] = { @@ -772,6 +773,7 @@ static char *blrm_states[] = "Query server variables", "Query binlog variables", "Query @@lower_case_table_names", + "Ready to Register", "Register slave", "Semi-Sync Support retrivial", "Request Semi-Sync Replication", diff --git a/server/modules/routing/binlogrouter/blr_master.c b/server/modules/routing/binlogrouter/blr_master.c index 9cd007995..bb63ae0bb 100644 --- a/server/modules/routing/binlogrouter/blr_master.c +++ b/server/modules/routing/binlogrouter/blr_master.c @@ -714,43 +714,80 @@ blr_master_response(ROUTER_INSTANCE *router, GWBUF *buf) router->saved_master.map = buf; blr_cache_response(router, "map", buf); - // Query for Server Variables - buf = blr_make_query(router->master, MYSQL_CONNECTOR_SERVER_VARS_QUERY); - router->master_state = BLRM_SERVER_VARS; - router->master->func.write(router->master, buf); - break; + if (router->maxwell_compat) + { + // Query for Server Variables + buf = blr_make_query(router->master, MYSQL_CONNECTOR_SERVER_VARS_QUERY); + router->master_state = BLRM_SERVER_VARS; + router->master->func.write(router->master, buf); + break; + } + else + { + // Continue: ready for the registration, nothing to write/read + router->master_state = BLRM_REGISTER_READY; + } case BLRM_SERVER_VARS: - if (router->saved_master.server_vars) + /** + * This branch could be reached as fallthrough from BLRM_MAP + * with new state BLRM_REGISTER_READY + * Go ahead if maxwell_compat is not set + */ + if (router->maxwell_compat) { - GWBUF_CONSUME_ALL(router->saved_master.server_vars); - } - router->saved_master.server_vars = buf; - blr_cache_response(router, "server_vars", buf); + if (router->saved_master.server_vars) + { + GWBUF_CONSUME_ALL(router->saved_master.server_vars); + } + router->saved_master.server_vars = buf; + blr_cache_response(router, "server_vars", buf); - buf = blr_make_query(router->master, "SELECT IF(@@global.log_bin, 'ON', 'OFF'), @@global.binlog_format, @@global.binlog_row_image"); - router->master_state = BLRM_BINLOG_VARS; - router->master->func.write(router->master, buf); - break; + buf = blr_make_query(router->master, + "SELECT IF(@@global.log_bin, 'ON', 'OFF'), " + "@@global.binlog_format, @@global.binlog_row_image"); + router->master_state = BLRM_BINLOG_VARS; + router->master->func.write(router->master, buf); + break; + } case BLRM_BINLOG_VARS: - if (router->saved_master.binlog_vars) + /** + * This branch could be reached as fallthrough from BLRM_MAP + * with new state BLRM_REGISTER_READY. + * Go ahead if maxwell_compat is not set + */ + if (router->maxwell_compat) { - GWBUF_CONSUME_ALL(router->saved_master.binlog_vars); - } - router->saved_master.binlog_vars = buf; - blr_cache_response(router, "binlog_vars", buf); + if (router->saved_master.binlog_vars) + { + GWBUF_CONSUME_ALL(router->saved_master.binlog_vars); + } + router->saved_master.binlog_vars = buf; + blr_cache_response(router, "binlog_vars", buf); - buf = blr_make_query(router->master, "select @@lower_case_table_names"); - router->master_state = BLRM_LOWER_CASE_TABLES; - router->master->func.write(router->master, buf); - break; + buf = blr_make_query(router->master, "select @@lower_case_table_names"); + router->master_state = BLRM_LOWER_CASE_TABLES; + router->master->func.write(router->master, buf); + break; + } case BLRM_LOWER_CASE_TABLES: - if (router->saved_master.lower_case_tables) + /** + * This branch could be reached as fallthrough from BLRM_MAP + * with new state BLRM_REGISTER_READY. + * Go ahead if maxwell_compat is not set + */ + if (router->maxwell_compat) { - GWBUF_CONSUME_ALL(router->saved_master.lower_case_tables); + if (router->saved_master.lower_case_tables) + { + GWBUF_CONSUME_ALL(router->saved_master.lower_case_tables); + } + router->saved_master.lower_case_tables = buf; + blr_cache_response(router, "lower_case_tables", buf); + router->master_state = BLRM_REGISTER_READY; + // Continue: ready for the registration, nothing to write/read } - router->saved_master.lower_case_tables = buf; - blr_cache_response(router, "lower_case_tables", buf); - + case BLRM_REGISTER_READY: + // Prepare registration buf = blr_make_registration(router); router->master_state = BLRM_REGISTER; router->master->func.write(router->master, buf); @@ -2448,7 +2485,7 @@ bool blr_send_event(blr_thread_role_t role, "the event has already been sent by thread %lu in the role of %s. " "%u bytes buffered for writing in DCB %p. %lu events received from master.", slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, binlog_name, binlog_pos, @@ -2511,7 +2548,7 @@ bool blr_send_event(blr_thread_role_t role, { MXS_ERROR("Failed to send an event of %u bytes to slave at %s:%d.", hdr->event_size, slave->dcb->remote, - ntohs(slave->dcb->ipv4.sin_port)); + dcb_get_port(slave->dcb)); } return rval; } diff --git a/server/modules/routing/binlogrouter/blr_slave.c b/server/modules/routing/binlogrouter/blr_slave.c index 72437ad5e..ab77d9d3a 100644 --- a/server/modules/routing/binlogrouter/blr_slave.c +++ b/server/modules/routing/binlogrouter/blr_slave.c @@ -2262,7 +2262,7 @@ blr_slave_binlog_dump(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue "Latest safe position %lu, end of binlog file %lu", router->service->name, slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, (unsigned long)slave->binlog_pos, @@ -2382,7 +2382,7 @@ blr_slave_binlog_dump(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue MXS_NOTICE("%s: Slave %s:%d, server id %d requested binlog file %s from position %lu", router->service->name, slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, (unsigned long)slave->binlog_pos); @@ -2546,7 +2546,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) } MXS_ERROR("Slave %s:%i, server-id %d, binlog '%s': blr_slave_catchup " "failed to open binlog file", - slave->dcb->remote, ntohs((slave->dcb->ipv4).sin_port), slave->serverid, + slave->dcb->remote, dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile); slave->cstate &= ~CS_BUSY; @@ -2675,7 +2675,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) MXS_ERROR("Slave %s:%i, server-id %d, binlog '%s': blr_slave_catchup " "failed to open binlog file in rotate event", slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile); @@ -2719,7 +2719,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) MXS_WARNING("Slave %s:%i, server-id %d, binlog '%s, position %u: " "Slave-thread could not send event to slave, closing connection.", slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, binlog_name, binlog_pos); @@ -2754,7 +2754,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) MXS_ERROR("%s Slave %s:%i, server-id %d, binlog '%s', %s", router->service->name, slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, read_errmsg); @@ -2765,7 +2765,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) MXS_ERROR("%s Slave %s:%i, server-id %d, binlog '%s', %s", router->service->name, slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, read_errmsg); @@ -2787,7 +2787,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) MXS_ERROR("%s Slave %s:%i, server-id %d, binlog '%s', %s", router->service->name, slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, read_errmsg); @@ -2822,7 +2822,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) "current committed transaction event being sent: %lu, %s", router->service->name, slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, slave->stats.n_events - events_before, @@ -2897,7 +2897,7 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large) "previous failure of the master.", router->service->name, slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, (unsigned long)slave->binlog_pos, router->binlog_name, router->binlog_position); @@ -3142,7 +3142,7 @@ blr_slave_read_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave) { MXS_ERROR("Slave %s:%i, server-id %d, binlog '%s', blr_read_binlog failure: %s", slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, err_msg); @@ -6104,7 +6104,7 @@ blr_slave_read_ste(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, uint32_t fde_en { MXS_ERROR("Slave %s:%i, server-id %d, binlog '%s', blr_read_binlog failure: %s", slave->dcb->remote, - ntohs((slave->dcb->ipv4).sin_port), + dcb_get_port(slave->dcb), slave->serverid, slave->binlogfile, err_msg); diff --git a/server/modules/routing/readconnroute/readconnroute.c b/server/modules/routing/readconnroute/readconnroute.c index a1564c18f..0b3f0f4fb 100644 --- a/server/modules/routing/readconnroute/readconnroute.c +++ b/server/modules/routing/readconnroute/readconnroute.c @@ -102,7 +102,6 @@ static uint64_t getCapabilities(MXS_ROUTER* instance); static bool rses_begin_locked_router_action(ROUTER_CLIENT_SES* rses); static void rses_end_locked_router_action(ROUTER_CLIENT_SES* rses); static SERVER_REF *get_root_master(SERVER_REF *servers); -static int handle_state_switch(DCB* dcb, DCB_REASON reason, void * routersession); /** * The module entry point routine. It is this routine that @@ -810,49 +809,3 @@ static SERVER_REF *get_root_master(SERVER_REF *servers) } return master_host; } - -static int handle_state_switch(DCB* dcb, DCB_REASON reason, void * routersession) -{ - ss_dassert(dcb != NULL); - MXS_SESSION* session = dcb->session; - ROUTER_CLIENT_SES* rses = (ROUTER_CLIENT_SES*) routersession; - SERVICE* service = session->service; - MXS_ROUTER* router = (MXS_ROUTER *) service->router; - - if (NULL == dcb->session->router_session && DCB_REASON_ERROR != reason) - { - /* - * We cannot handle a DCB that does not have a router session, - * except in the case where error processing is invoked. - */ - return 0; - } - switch (reason) - { - case DCB_REASON_CLOSE: - dcb->func.close(dcb); - break; - case DCB_REASON_DRAINED: - /** Do we need to do anything? */ - break; - case DCB_REASON_HIGH_WATER: - /** Do we need to do anything? */ - break; - case DCB_REASON_LOW_WATER: - /** Do we need to do anything? */ - break; - case DCB_REASON_ERROR: - dcb->func.error(dcb); - break; - case DCB_REASON_HUP: - dcb->func.hangup(dcb); - break; - case DCB_REASON_NOT_RESPONDING: - dcb->func.hangup(dcb); - break; - default: - break; - } - - return 0; -}