Changeset: 5e0b7910d31e for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/5e0b7910d31e Added Files: clients/mapilib/connect.c clients/mapilib/mapi_intern.h Modified Files: clients/mapilib/CMakeLists.txt clients/mapilib/mapi.c clients/mapilib/mapi.h Branch: monetdburl Log Message:
Extract mapi_reconnect() into its own compilation unit diffs (truncated from 1620 to 300 lines): diff --git a/clients/mapilib/CMakeLists.txt b/clients/mapilib/CMakeLists.txt --- a/clients/mapilib/CMakeLists.txt +++ b/clients/mapilib/CMakeLists.txt @@ -19,6 +19,8 @@ add_library(mapi target_sources(mapi PRIVATE mapi.c + connect.c + mapi_intern.h PUBLIC $<BUILD_INTERFACE:$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/mapi.h> $<BUILD_INTERFACE:$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/mapi_querytype.h> diff --git a/clients/mapilib/connect.c b/clients/mapilib/connect.c new file mode 100644 --- /dev/null +++ b/clients/mapilib/connect.c @@ -0,0 +1,815 @@ + + +#include "monetdb_config.h" +#include "stream.h" /* include before mapi.h */ +#include "stream_socket.h" +#include "mapi.h" +#include "mapi_prompt.h" +#include "mcrypt.h" +#include "matomic.h" +#include "mstring.h" + +#include "mapi_intern.h" + +/* (Re-)establish a connection with the server. */ +MapiMsg +mapi_reconnectx(Mapi mid) +{ + SOCKET s = INVALID_SOCKET; + char errbuf[8096]; + char buf[BLOCK]; + size_t len; + MapiHdl hdl; + + if (mid->connected) + close_connection(mid); + else if (mid->uri == NULL) { + /* continue work started by mapi_mapi */ + + /* connection searching strategy: + * 0) if host and port are given, resort to those + * 1) if no dbname given, make TCP connection + * (merovingian will complain regardless, so it is + * more likely an mserver is meant to be directly + * addressed) + * a) resort to default (hardwired) port 50000, + * unless port given, then + * b) resort to port given + * 2) a dbname is given + * a) if a port is given, open unix socket for that + * port, resort to TCP connection if not found + * b) no port given, start looking for a matching + * merovingian, by searching through socket + * files, attempting connect to given dbname + * I) try available sockets that have a matching + * owner with the current user + * II) try other sockets + * III) resort to TCP connection on hardwired + * port (localhost:50000) + */ + + char *host; + int port; + + host = mid->hostname; + port = mid->port; + + if (host != NULL && port != 0) { + /* case 0), just do what the user told us */ +#ifdef HAVE_SYS_UN_H + if (*host == '/') { + /* don't stat or anything, the + * mapi_reconnect will return the + * error if it doesn't exist, falling + * back to TCP with a hostname like + * '/var/sockets' won't work anyway */ + snprintf(buf, sizeof(buf), + "%s/.s.monetdb.%d", host, port); + host = buf; + } +#endif + } else if (mid->database == NULL) { + /* case 1) */ + if (port == 0) + port = MAPI_PORT; /* case 1a), hardwired default */ + if (host == NULL) + host = "localhost"; + } else { + /* case 2), database name is given */ + if (port != 0) { + /* case 2a), if unix socket found, use + * it, otherwise TCP */ +#ifdef HAVE_SYS_UN_H + struct stat st; + snprintf(buf, sizeof(buf), + "/tmp/.s.monetdb.%d", port); + if (stat(buf, &st) != -1 && + S_ISSOCK(st.st_mode)) + host = buf; + else +#endif + host = "localhost"; + } else if (host != NULL) { +#ifdef HAVE_SYS_UN_H + if (*host == '/') { + /* see comment above for why + * we don't stat */ + snprintf(buf, sizeof(buf), + "%s/.s.monetdb.%d", host, MAPI_PORT); + host = buf; + } +#endif + port = MAPI_PORT; + } else { + /* case 2b), no host, no port, but a + * dbname, search for meros */ +#ifdef HAVE_SYS_UN_H + DIR *d; + struct dirent *e; + struct stat st; + struct { + int port; + uid_t owner; + } socks[24]; + int i = 0; + int len; + uid_t me = getuid(); + + d = opendir("/tmp"); + if (d != NULL) { + while ((e = readdir(d)) != NULL) { + if (strncmp(e->d_name, ".s.monetdb.", 11) != 0) + continue; + if (snprintf(buf, sizeof(buf), "/tmp/%s", e->d_name) >= (int) sizeof(buf)) + continue; /* ignore long name */ + if (stat(buf, &st) != -1 && + S_ISSOCK(st.st_mode)) { + socks[i].owner = st.st_uid; + socks[i++].port = atoi(e->d_name + 11); + } + if (i == NELEM(socks)) + break; + } + closedir(d); + len = i; + /* case 2bI) first those with + * a matching owner */ + for (i = 0; i < len; i++) { + if (socks[i].port != 0 && + socks[i].owner == me) { + /* try this server for the database */ + snprintf(buf, sizeof(buf), "/tmp/.s.monetdb.%d", socks[i].port); + if (mid->hostname) + free(mid->hostname); + mid->hostname = strdup(buf); + mid->port = socks[i].port; + set_uri(mid); + if (mapi_reconnect(mid) == MOK) + return MOK; + mapi_clrError(mid); + socks[i].port = 0; /* don't need to try again */ + } + } + /* case 2bII) the other sockets */ + for (i = 0; i < len; i++) { + if (socks[i].port != 0) { + /* try this server for the database */ + snprintf(buf, sizeof(buf), "/tmp/.s.monetdb.%d", socks[i].port); + if (mid->hostname) + free(mid->hostname); + mid->hostname = strdup(buf); + mid->port = socks[i].port; + set_uri(mid); + if (mapi_reconnect(mid) == MOK) + return MOK; + mapi_clrError(mid); + } + } + } +#endif + /* case 2bIII) resort to TCP + * connection on hardwired port */ + host = "localhost"; + port = MAPI_PORT; + } + } + if (host != mid->hostname) { + if (mid->hostname) + free(mid->hostname); + mid->hostname = strdup(host); + } + mid->port = port; + set_uri(mid); + } + +#ifdef HAVE_SYS_UN_H + if (mid->hostname && mid->hostname[0] == '/') { + struct msghdr msg; + struct iovec vec; + struct sockaddr_un userver; + + if (strlen(mid->hostname) >= sizeof(userver.sun_path)) { + return mapi_setError(mid, "path name too long", __func__, MERROR); + } + + if ((s = socket(PF_UNIX, SOCK_STREAM +#ifdef SOCK_CLOEXEC + | SOCK_CLOEXEC +#endif + , 0)) == INVALID_SOCKET) { + snprintf(errbuf, sizeof(errbuf), + "opening socket failed: %s", +#ifdef _MSC_VER + wsaerror(WSAGetLastError()) +#else + strerror(errno) +#endif + ); + return mapi_setError(mid, errbuf, __func__, MERROR); + } +#if !defined(SOCK_CLOEXEC) && defined(HAVE_FCNTL) + (void) fcntl(s, F_SETFD, FD_CLOEXEC); +#endif + userver = (struct sockaddr_un) { + .sun_family = AF_UNIX, + }; + strcpy_len(userver.sun_path, mid->hostname, sizeof(userver.sun_path)); + + if (connect(s, (struct sockaddr *) &userver, sizeof(struct sockaddr_un)) == SOCKET_ERROR) { + snprintf(errbuf, sizeof(errbuf), + "initiating connection on socket failed: %s", +#ifdef _MSC_VER + wsaerror(WSAGetLastError()) +#else + strerror(errno) +#endif + ); + closesocket(s); + return mapi_setError(mid, errbuf, __func__, MERROR); + } + + /* send first byte, nothing special to happen */ + msg.msg_name = NULL; + msg.msg_namelen = 0; + buf[0] = '0'; /* normal */ + vec.iov_base = buf; + vec.iov_len = 1; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + if (sendmsg(s, &msg, 0) < 0) { + snprintf(errbuf, sizeof(errbuf), "could not send initial byte: %s", +#ifdef _MSC_VER + wsaerror(WSAGetLastError()) +#else + strerror(errno) +#endif + ); + closesocket(s); + return mapi_setError(mid, errbuf, __func__, MERROR); + } + } else +#endif + { + struct addrinfo hints, *res, *rp; + char port[32]; + int ret; + + if (mid->hostname == NULL) + mid->hostname = strdup("localhost"); + snprintf(port, sizeof(port), "%d", mid->port & 0xFFFF); + + hints = (struct addrinfo) { + .ai_family = AF_UNSPEC, + .ai_socktype = SOCK_STREAM, + .ai_protocol = IPPROTO_TCP, + }; + ret = getaddrinfo(mid->hostname, port, &hints, &res); + if (ret) { + snprintf(errbuf, sizeof(errbuf), "getaddrinfo failed: %s", gai_strerror(ret)); + return mapi_setError(mid, errbuf, __func__, MERROR); + } + errbuf[0] = 0; + for (rp = res; rp; rp = rp->ai_next) { + s = socket(rp->ai_family, rp->ai_socktype +#ifdef SOCK_CLOEXEC + | SOCK_CLOEXEC +#endif + , rp->ai_protocol); + if (s != INVALID_SOCKET) { +#if !defined(SOCK_CLOEXEC) && defined(HAVE_FCNTL) _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org