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

Reply via email to