X-Git-Url: http://dolda2000.com/gitweb/?p=doldaconnect.git;a=blobdiff_plain;f=lib%2Fuilib.c;h=a2993956d6dfece156fae3fc44a7c6f942dc98dc;hp=f7a6b28554c2e11c4ea86168b4c3835b97ae2a84;hb=ae93c710feb83661705620d14e9712f7b3a7879b;hpb=8affe2ff5a4c2125128d9a9510aa67b29c0c0b18 diff --git a/lib/uilib.c b/lib/uilib.c index f7a6b28..a299395 100644 --- a/lib/uilib.c +++ b/lib/uilib.c @@ -1,6 +1,6 @@ /* * Dolda Connect - Modular multiuser Direct Connect-style client - * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com) + * Copyright (C) 2004 Fredrik Tolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef HAVE_RESOLVER #include #include @@ -58,6 +59,7 @@ #define RESP_STR 1 #define RESP_INT 2 #define RESP_FLOAT 3 +#define RESP_LNUM 4 struct respclass { @@ -102,7 +104,66 @@ struct { int family; int sentcreds; } servinfo; +char dc_srv_local_addr; +char *dc_srv_local = &dc_srv_local_addr; +static void message(int bits, char *format, ...) +{ + static int hb = -1; + char *v; + va_list args; + + if(hb == -1) + { + hb = 0; + if((v = getenv("LIBDCUI_MSG")) != NULL) + hb = strtol(v, NULL, 0) & 65535; + } + if(hb & bits) + { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + } +} + +static char *formataddress(struct sockaddr *arg, socklen_t arglen) +{ + struct sockaddr_in *ipv4; +#ifdef HAVE_IPV6 + struct sockaddr_in6 *ipv6; +#endif + static char *ret = NULL; + char buf[1024]; + + if(ret != NULL) + free(ret); + ret = NULL; + switch(arg->sa_family) + { + case AF_UNIX: + ret = sprintf2("Unix socket (%s)", ((struct sockaddr_un *)arg)->sun_path); + break; + case AF_INET: + ipv4 = (struct sockaddr_in *)arg; + if(inet_ntop(AF_INET, &ipv4->sin_addr, buf, sizeof(buf)) == NULL) + return(NULL); + ret = sprintf2("%s:%i", buf, (int)ntohs(ipv4->sin_port)); + break; +#ifdef HAVE_IPV6 + case AF_INET6: + ipv6 = (struct sockaddr_in6 *)arg; + if(inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf)) == NULL) + return(NULL); + ret = sprintf2("[%s]:%i", buf, (int)ntohs(ipv6->sin6_port)); + break; +#endif + default: + errno = EPFNOSUPPORT; + break; + } + return(ret); +} static struct dc_response *makeresp(void) { struct dc_response *new; @@ -154,8 +215,10 @@ static struct qcmd *makeqcmd(wchar_t *name) if((cmd->name != NULL) && !wcscmp(cmd->name, name)) break; } - if(cmd == NULL) + if(cmd == NULL) { + errno = ENOSYS; /* Bleh */ return(NULL); + } } new = smalloc(sizeof(*new)); new->tag = tag++; @@ -415,6 +478,9 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...) { freepart = 1; part = swprintf2(L"%i", va_arg(al, int)); + } else if(!wcscmp(tpart, L"li")) { + freepart = 1; + part = swprintf2(L"%ji", (intmax_t)va_arg(al, dc_lnum_t)); } else if(!wcscmp(tpart, L"s")) { freepart = 1; part = icmbstowcs(sarg = va_arg(al, char *), NULL); @@ -425,6 +491,7 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...) return(-1); } } else if(!wcscmp(tpart, L"ls")) { + freepart = 0; part = va_arg(al, wchar_t *); } else if(!wcscmp(tpart, L"ll")) { freepart = 1; @@ -438,6 +505,7 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...) } else { if(buf != NULL) free(buf); + errno = EINVAL; return(-1); } } else { @@ -518,7 +586,8 @@ int dc_handleread(void) if(ret) { int newfd; - + + message(2, "could not connect to %s: %s\n", formataddress(curhost->ai_addr, curhost->ai_addrlen), strerror(ret)); for(curhost = curhost->ai_next; curhost != NULL; curhost = curhost->ai_next) { if((newfd = socket(curhost->ai_family, curhost->ai_socktype, curhost->ai_protocol)) < 0) @@ -531,10 +600,12 @@ int dc_handleread(void) dup2(newfd, fd); close(newfd); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); + message(4, "connecting to %s\n", formataddress(curhost->ai_addr, curhost->ai_addrlen)); if(connect(fd, (struct sockaddr *)curhost->ai_addr, curhost->ai_addrlen)) { if(errno == EINPROGRESS) return(0); + message(2, "could not connect to %s: %s\n", formataddress(curhost->ai_addr, curhost->ai_addrlen), strerror(ret)); } else { break; } @@ -760,6 +831,7 @@ int dc_handleread(void) return(0); } +#if UNIX_AUTH_STYLE == 1 static void mkcreds(struct msghdr *msg) { struct ucred *ucred; @@ -778,6 +850,7 @@ static void mkcreds(struct msghdr *msg) ucred->gid = getgid(); msg->msg_controllen = cmsg->cmsg_len; } +#endif int dc_handlewrite(void) { @@ -796,11 +869,13 @@ int dc_handlewrite(void) msg.msg_iovlen = 1; bufvec.iov_base = queue->buf; bufvec.iov_len = queue->buflen; +#if UNIX_AUTH_STYLE == 1 if((servinfo.family == PF_UNIX) && !servinfo.sentcreds) { mkcreds(&msg); servinfo.sentcreds = 1; } +#endif ret = sendmsg(fd, &msg, MSG_NOSIGNAL | MSG_DONTWAIT); if(ret < 0) { @@ -1049,6 +1124,7 @@ static struct addrinfo *resolvsrv(char *name) if(getsrvrr(name, &realname, &port)) return(NULL); + message(4, "SRV RR resolved: %s -> %s\n", name, realname); ret = resolvtcp(realname, port); free(realname); return(ret); @@ -1119,8 +1195,10 @@ static struct addrinfo *defaulthost(void) char *tmp; char dn[1024]; - if(((tmp = getenv("DCSERVER")) != NULL) && *tmp) + if(((tmp = getenv("DCSERVER")) != NULL) && *tmp) { + message(4, "using DCSERVER: %s\n", tmp); return(resolvhost(tmp)); + } ret = getlocalai(); ret = gaicat(ret, resolvtcp("localhost", 1500)); if(!getdomainname(dn, sizeof(dn)) && *dn && strcmp(dn, "(none)")) @@ -1128,7 +1206,7 @@ static struct addrinfo *defaulthost(void) return(ret); } -static int dc_connectai(struct addrinfo *hosts) +static int dc_connectai(struct addrinfo *hosts, struct qcmd **cnctcmd) { struct qcmd *qcmd; int errnobak; @@ -1144,10 +1222,13 @@ static int dc_connectai(struct addrinfo *hosts) if((fd = socket(curhost->ai_family, curhost->ai_socktype, curhost->ai_protocol)) < 0) { errnobak = errno; + freeaddrinfo(hostlist); + hostlist = NULL; errno = errnobak; return(-1); } fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); + message(4, "connecting to %s\n", formataddress(curhost->ai_addr, curhost->ai_addrlen)); if(connect(fd, (struct sockaddr *)curhost->ai_addr, curhost->ai_addrlen)) { if(errno == EINPROGRESS) @@ -1155,6 +1236,7 @@ static int dc_connectai(struct addrinfo *hosts) state = 0; break; } + message(2, "could not connect to %s: %s\n", formataddress(curhost->ai_addr, curhost->ai_addrlen), strerror(errno)); close(fd); fd = -1; } else { @@ -1165,35 +1247,83 @@ static int dc_connectai(struct addrinfo *hosts) break; } } - qcmd = makeqcmd(NULL); - resetreader = 1; + if(state != -1) + { + qcmd = makeqcmd(NULL); + if(cnctcmd != NULL) + *cnctcmd = qcmd; + resetreader = 1; + } else { + free(hostlist); + hostlist = NULL; + } return(fd); } -int dc_connect(char *host) +static int dc_connect2(char *host, struct qcmd **cnctcmd) { struct addrinfo *ai; + struct qcmd *qcmd; int ret; - if(!host || !*host) + if(host == dc_srv_local) { + message(4, "connect start: Unix\n"); + ai = getlocalai(); + } else if(!host || !*host) { + message(4, "connect start: default\n"); ai = defaulthost(); - else + } else { + message(4, "connect start: host %s\n", host); ai = resolvhost(host); + } if(ai == NULL) return(-1); - if((ret = dc_connectai(ai)) != 0) - freeaddrinfo(ai); + ret = dc_connectai(ai, &qcmd); + if((ret >= 0) && (cnctcmd != NULL)) + *cnctcmd = qcmd; return(ret); } -int dc_connectlocal(void) +int dc_connect(char *host) +{ + return(dc_connect2(host, NULL)); +} + +int dc_connectsync(char *host, struct dc_response **respbuf) +{ + int ret; + struct qcmd *cc; + struct dc_response *resp; + + if((ret = dc_connect2(host, &cc)) < 0) + return(-1); + resp = dc_gettaggedrespsync(cc->tag); + if(resp == NULL) { + dc_disconnect(); + return(-1); + } + if(respbuf == NULL) + dc_freeresp(resp); + else + *respbuf = resp; + return(ret); +} + +int dc_connectsync2(char *host, int rev) { - struct addrinfo *ai; int ret; + struct dc_response *resp; - ai = getlocalai(); - if((ret = dc_connectai(ai)) != 0) - freeaddrinfo(ai); + if((ret = dc_connectsync(host, &resp)) < 0) + return(-1); + if(dc_checkprotocol(resp, rev)) + { + dc_freeresp(resp); + dc_disconnect(); + errno = EPROTONOSUPPORT; + return(-1); + } + dc_freeresp(resp); return(ret); } @@ -1248,6 +1378,12 @@ struct dc_intresp *dc_interpret(struct dc_response *resp) iresp->argv[iresp->argc].type = cls->wordt[i]; iresp->argc++; break; + case RESP_LNUM: + sizebuf(&(iresp->argv), &args, iresp->argc + 1, sizeof(*(iresp->argv)), 1); + iresp->argv[iresp->argc].val.lnum = wcstoll(resp->rlines[resp->curline].argv[i + 1], NULL, 0); + iresp->argv[iresp->argc].type = cls->wordt[i]; + iresp->argc++; + break; } } resp->curline++; @@ -1278,7 +1414,7 @@ int dc_checkprotocol(struct dc_response *resp, int revision) if((ires = dc_interpret(resp)) == NULL) return(-1); low = ires->argv[0].val.num; - high = ires->argv[0].val.num; + high = ires->argv[1].val.num; dc_freeires(ires); if((revision < low) || (revision > high)) return(-1); @@ -1289,3 +1425,8 @@ const char *dc_gethostname(void) { return(servinfo.hostname); } + +int dc_getfd(void) +{ + return(fd); +}