From 12383d48e624213114482f29af819ff77aef70fa Mon Sep 17 00:00:00 2001 From: fredrik Date: Wed, 11 Apr 2007 11:01:52 +0000 Subject: [PATCH] New dc_connect implementation git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/doldaconnect@887 959494ce-11ee-0310-bf91-de5d638817bd --- include/doldaconnect/uilib.h | 2 +- lib/guile/dolcon-guile.c | 21 ++-- lib/python/dolmod.c | 7 +- lib/uilib.c | 222 ++++++++++++++++++++++++++++--------------- 4 files changed, 162 insertions(+), 90 deletions(-) diff --git a/include/doldaconnect/uilib.h b/include/doldaconnect/uilib.h index ac717fb..9cfa4de 100644 --- a/include/doldaconnect/uilib.h +++ b/include/doldaconnect/uilib.h @@ -48,7 +48,7 @@ int dc_getstate(void); int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...); int dc_handleread(void); int dc_handlewrite(void); -int dc_connect(char *host, int port); +int dc_connect(char *host); struct dc_intresp *dc_interpret(struct dc_response *resp); void dc_freeires(struct dc_intresp *ires); const char *dc_gethostname(void); diff --git a/lib/guile/dolcon-guile.c b/lib/guile/dolcon-guile.c index 9e05753..7a0f3e2 100644 --- a/lib/guile/dolcon-guile.c +++ b/lib/guile/dolcon-guile.c @@ -24,21 +24,20 @@ struct scmcb static int fd = -1; static scm_bits_t resptype; -static SCM scm_dc_connect(SCM host, SCM port) +static SCM scm_dc_connect(SCM host) { - int cport; + char *chost; - SCM_ASSERT(SCM_STRINGP(host), host, SCM_ARG1, "dc-connect"); - if(port == SCM_UNDEFINED) + if(fd >= 0) + dc_disconnect(); + if(host == SCM_UNDEFINED) { - cport = -1; + chost = NULL; } else { - SCM_ASSERT(SCM_INUMP(port), port, SCM_ARG2, "dc-connect"); - cport = SCM_INUM(port); + SCM_ASSERT(SCM_STRINGP(host), host, SCM_ARG1, "dc-connect"); + chost = SCM_STRING_CHARS(host); } - if(fd >= 0) - dc_disconnect(); - if((fd = dc_connect(SCM_STRING_CHARS(host), cport)) < 0) + if((fd = dc_connect(chost)) < 0) scm_syserror("dc-connect"); return(SCM_MAKINUM(fd)); } @@ -322,7 +321,7 @@ static int resp_print(SCM respsmob, SCM port, scm_print_state *pstate) void init_guiledc(void) { - scm_c_define_gsubr("dc-connect", 1, 1, 0, scm_dc_connect); + scm_c_define_gsubr("dc-connect", 0, 1, 0, scm_dc_connect); scm_c_define_gsubr("dc-disconnect", 0, 0, 0, scm_dc_disconnect); scm_c_define_gsubr("dc-connected", 0, 0, 0, scm_dc_connected); scm_c_define_gsubr("dc-select", 0, 1, 0, scm_dc_select); diff --git a/lib/python/dolmod.c b/lib/python/dolmod.c index adf07a2..eb2c405 100644 --- a/lib/python/dolmod.c +++ b/lib/python/dolmod.c @@ -134,14 +134,13 @@ static struct respobj *makeresp(struct dc_response *resp) static PyObject *mod_connect(PyObject *self, PyObject *args) { char *host; - int port; - port = -1; - if(!PyArg_ParseTuple(args, "s|i", &host, &port)) + host = NULL; + if(!PyArg_ParseTuple(args, "|s", &host)) return(NULL); if(fd >= 0) dc_disconnect(); - if((fd = dc_connect(host, port)) < 0) { + if((fd = dc_connect(host)) < 0) { PyErr_SetFromErrno(PyExc_OSError); return(NULL); } diff --git a/lib/uilib.c b/lib/uilib.c index 26958a7..034c823 100644 --- a/lib/uilib.c +++ b/lib/uilib.c @@ -38,9 +38,11 @@ #include #include #include +#include #include #include #include +#include #ifdef HAVE_RESOLVER #include #include @@ -96,7 +98,6 @@ static iconv_t ichandle; static int resetreader = 1; static char *dchostname = NULL; static struct addrinfo *hostlist = NULL, *curhost = NULL; -static int servport; static struct dc_response *makeresp(void) { @@ -502,10 +503,7 @@ int dc_handleread(void) if(ret) { int newfd; - struct sockaddr_storage addr; - struct sockaddr_in *ipv4; - struct sockaddr_in6 *ipv6; - + for(curhost = curhost->ai_next; curhost != NULL; curhost = curhost->ai_next) { if((newfd = socket(curhost->ai_family, curhost->ai_socktype, curhost->ai_protocol)) < 0) @@ -518,20 +516,7 @@ int dc_handleread(void) dup2(newfd, fd); close(newfd); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - memcpy(&addr, curhost->ai_addr, curhost->ai_addrlen); - if(addr.ss_family == AF_INET) - { - ipv4 = (struct sockaddr_in *)&addr; - ipv4->sin_port = htons(servport); - } -#ifdef HAVE_IPV6 - if(addr.ss_family == AF_INET6) - { - ipv6 = (struct sockaddr_in6 *)&addr; - ipv6->sin6_port = htons(servport); - } -#endif - if(connect(fd, (struct sockaddr *)&addr, curhost->ai_addrlen)) + if(connect(fd, (struct sockaddr *)curhost->ai_addr, curhost->ai_addrlen)) { if(errno == EINPROGRESS) return(0); @@ -546,6 +531,8 @@ int dc_handleread(void) return(-1); } } + if(curhost->ai_canonname != NULL) + dchostname = sstrdup(curhost->ai_canonname); state = 1; resetreader = 1; break; @@ -952,75 +939,165 @@ static int getsrvrr(char *name, char **host, int *port) } #endif -int dc_connect(char *host, int port) +static struct addrinfo *gaicat(struct addrinfo *l1, struct addrinfo *l2) { - struct addrinfo hint; - struct sockaddr_storage addr; - struct sockaddr_in *ipv4; -#ifdef HAVE_IPV6 - struct sockaddr_in6 *ipv6; -#endif - struct qcmd *qcmd; - char *newhost; - int getsrv, freehost; - int errnobak; + struct addrinfo *p; + + if(l1 == NULL) + return(l2); + for(p = l1; p->ai_next != NULL; p = p->ai_next); + p->ai_next = l2; + return(l1); +} + +/* This isn't actually correct, in any sense of the word. It only + * works on systems whose getaddrinfo implementation saves the + * sockaddr in the same malloc block as the struct addrinfo. Those + * systems include at least FreeBSD and glibc-based systems, though, + * so it should not be any immediate threat, and it allows me to not + * implement a getaddrinfo wrapper. It can always be changed, should + * the need arise. */ +static struct addrinfo *unixgai(int type, char *path) +{ + void *buf; + struct addrinfo *ai; + struct sockaddr_un *un; + + buf = smalloc(sizeof(*ai) + sizeof(*un)); + memset(buf, 0, sizeof(*ai) + sizeof(*un)); + ai = (struct addrinfo *)buf; + un = (struct sockaddr_un *)(buf + sizeof(*ai)); + ai->ai_flags = 0; + ai->ai_family = AF_UNIX; + ai->ai_socktype = type; + ai->ai_protocol = 0; + ai->ai_addrlen = sizeof(*un); + ai->ai_addr = (struct sockaddr *)un; + ai->ai_canonname = NULL; + ai->ai_next = NULL; + un->sun_family = PF_UNIX; + strncpy(un->sun_path, path, sizeof(un->sun_path) - 1); + return(ai); +} + +static struct addrinfo *resolvtcp(char *name, int port) +{ + struct addrinfo hint, *ret; + char tmp[32]; - if(fd >= 0) - dc_disconnect(); - state = -1; - freehost = 0; - if(port < 0) - { - port = 1500; - getsrv = 1; - } else { - getsrv = 0; - } memset(&hint, 0, sizeof(hint)); hint.ai_socktype = SOCK_STREAM; - if(getsrv) + hint.ai_flags = AI_NUMERICSERV | AI_CANONNAME; + snprintf(tmp, sizeof(tmp), "%i", port); + if(!getaddrinfo(name, tmp, &hint, &ret)) + return(ret); + return(NULL); +} + +static struct addrinfo *resolvsrv(char *name) +{ + struct addrinfo *ret; + char *realname; + int port; + + if(getsrvrr(name, &realname, &port)) + return(NULL); + ret = resolvtcp(realname, port); + free(realname); + return(ret); +} + +static struct addrinfo *resolvhost(char *host) +{ + char *p, *hp; + struct addrinfo *ret; + int port; + + if(strchr(host, '/')) + return(unixgai(SOCK_STREAM, host)); + if((strchr(host, ':') == NULL) && ((ret = resolvsrv(host)) != NULL)) + return(ret); + ret = NULL; + if((*host == '[') && ((p = strchr(host, ']')) != NULL)) { - if(!getsrvrr(host, &newhost, &port)) - { - host = newhost; - freehost = 1; + hp = memcpy(smalloc(p - host), host + 1, (p - host) - 1); + hp[(p - host) - 1] = 0; + if(strchr(hp, ':') != NULL) { + port = 0; + if(*(++p) == ':') + port = atoi(p + 1); + if(port == 0) + port = 1500; + ret = resolvtcp(hp, port); } + free(hp); + } + if(ret != NULL) + return(ret); + hp = sstrdup(host); + port = 0; + if((p = strrchr(hp, ':')) != NULL) { + *(p++) = 0; + port = atoi(p); + } + if(port == 0) + port = 1500; + ret = resolvtcp(hp, port); + free(hp); + if(ret != NULL) + return(ret); + return(NULL); +} + +static struct addrinfo *defaulthost(void) +{ + struct addrinfo *ret; + struct passwd *pwd; + char *tmp; + char dn[1024]; + + if(((tmp = getenv("DCSERVER")) != NULL) && *tmp) + return(resolvhost(tmp)); + ret = NULL; + if((getuid() != 0) && ((pwd = getpwuid(getuid())) != NULL)) + { + tmp = sprintf2("/tmp/doldacond-%s", pwd->pw_name); + ret = gaicat(ret, unixgai(SOCK_STREAM, tmp)); + free(tmp); } - servport = port; + ret = gaicat(ret, unixgai(SOCK_STREAM, "/var/run/doldacond.sock")); + ret = gaicat(ret, resolvtcp("localhost", 1500)); + if(!getdomainname(dn, sizeof(dn)) && *dn && strcmp(dn, "(none)")) + ret = gaicat(ret, resolvsrv(dn)); + return(ret); +} + +int dc_connect(char *host) +{ + struct qcmd *qcmd; + int errnobak; + + if(fd >= 0) + dc_disconnect(); + state = -1; if(hostlist != NULL) freeaddrinfo(hostlist); - if(getaddrinfo(host, NULL, &hint, &hostlist)) - { - errno = ENONET; - if(freehost) - free(host); + if(!host || !*host) + hostlist = defaulthost(); + else + hostlist = resolvhost(host); + if(hostlist == NULL) return(-1); - } for(curhost = hostlist; curhost != NULL; curhost = curhost->ai_next) { if((fd = socket(curhost->ai_family, curhost->ai_socktype, curhost->ai_protocol)) < 0) { errnobak = errno; - if(freehost) - free(host); errno = errnobak; return(-1); } fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - memcpy(&addr, curhost->ai_addr, curhost->ai_addrlen); - if(addr.ss_family == AF_INET) - { - ipv4 = (struct sockaddr_in *)&addr; - ipv4->sin_port = htons(port); - } -#ifdef HAVE_IPV6 - if(addr.ss_family == AF_INET6) - { - ipv6 = (struct sockaddr_in6 *)&addr; - ipv6->sin6_port = htons(port); - } -#endif - if(connect(fd, (struct sockaddr *)&addr, curhost->ai_addrlen)) + if(connect(fd, (struct sockaddr *)curhost->ai_addr, curhost->ai_addrlen)) { if(errno == EINPROGRESS) { @@ -1030,17 +1107,14 @@ int dc_connect(char *host, int port) close(fd); fd = -1; } else { + if(curhost->ai_canonname != NULL) + dchostname = sstrdup(curhost->ai_canonname); state = 1; break; } } qcmd = makeqcmd(NULL); resetreader = 1; - if(dchostname != NULL) - free(dchostname); - dchostname = sstrdup(host); - if(freehost) - free(host); return(fd); } -- 2.11.0