diff --git a/include/maxscale/utils.h b/include/maxscale/utils.h index cf22d1382..6f34e47aa 100644 --- a/include/maxscale/utils.h +++ b/include/maxscale/utils.h @@ -69,6 +69,23 @@ void utils_end(); 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(); diff --git a/server/core/dcb.c b/server/core/dcb.c index 94342526f..dfb745f2e 100644 --- a/server/core/dcb.c +++ b/server/core/dcb.c @@ -2964,20 +2964,7 @@ int dcb_listen(DCB *listener, const char *config, const char *protocol_name) static int dcb_listen_create_socket_inet(const char *host, uint16_t port) { struct sockaddr_storage server_address = {}; - int listener_socket = open_network_socket(MXS_SOCKET_LISTENER, &server_address, host, port); - - if (listener_socket != -1) - { - if (bind(listener_socket, (struct sockaddr*)&server_address, sizeof(server_address)) < 0) - { - MXS_ERROR("Failed to bind on '%s:%u': %d, %s", - host, port, errno, mxs_strerror(errno)); - close(listener_socket); - listener_socket = -1; - } - } - - return listener_socket; + return open_network_socket(MXS_SOCKET_LISTENER, &server_address, host, port); } /** @@ -2988,59 +2975,16 @@ static int dcb_listen_create_socket_inet(const char *host, uint16_t port) */ static int dcb_listen_create_socket_unix(const char *path) { - int listener_socket; - struct sockaddr_un local_addr; - int one = 1; - - if (strlen(path) > 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.", path, sizeof(local_addr.sun_path) - 1); - return -1; - } - - // UNIX socket create - if ((listener_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - { - MXS_ERROR("Can't create UNIX socket: %d, %s", errno, mxs_strerror(errno)); - 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, path); - - if ((-1 == unlink(path)) && (errno != ENOENT)) + if (unlink(path) == -1 && errno != ENOENT) { MXS_ERROR("Failed to unlink Unix Socket %s: %d %s", 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) - { - MXS_ERROR("Failed to bind to UNIX Domain socket '%s': %d, %s", - path, errno, mxs_strerror(errno)); - close(listener_socket); - return -1; - } + struct sockaddr_un local_addr; + int listener_socket = open_unix_socket(MXS_SOCKET_LISTENER, &local_addr, path); - /* set permission for all users */ - if (chmod(path, 0777) < 0) + if (listener_socket >= 0 && chmod(path, 0777) < 0) { MXS_ERROR("Failed to change permissions on UNIX Domain socket '%s': %d, %s", path, errno, mxs_strerror(errno)); diff --git a/server/core/utils.c b/server/core/utils.c index 3814b8128..4ad3556ff 100644 --- a/server/core/utils.c +++ b/server/core/utils.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -974,6 +975,13 @@ int open_network_socket(enum mxs_socket_type type, struct sockaddr_storage *addr close(so); so = -1; } + else if (type == MXS_SOCKET_LISTENER && bind(so, (struct sockaddr*)addr, sizeof(*addr)) < 0) + { + MXS_ERROR("Failed to bind on '%s:%u': %d, %s", + host, port, errno, mxs_strerror(errno)); + close(so); + so = -1; + } } freeaddrinfo(ai); @@ -986,6 +994,50 @@ int open_network_socket(enum mxs_socket_type type, struct sockaddr_storage *addr 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; + } + } + + return fd; +} + /** * Return the number of processors available. * @return Number of processors or 1 if the required definition of _SC_NPROCESSORS_CONF