Allocate dc_srv_local in the .data segment rather than on the heap.
[doldaconnect.git] / lib / uilib.c
index 356e41e..a299395 100644 (file)
@@ -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 <fredrik@dolda2000.com>
  *  
  *  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 <netdb.h>
 #include <sys/poll.h>
 #include <pwd.h>
+#include <stdint.h>
 #ifdef HAVE_RESOLVER
 #include <arpa/nameser.h>
 #include <resolv.h>
@@ -58,6 +59,7 @@
 #define RESP_STR 1
 #define RESP_INT 2
 #define RESP_FLOAT 3
+#define RESP_LNUM 4
 
 struct respclass
 {
@@ -102,8 +104,66 @@ struct {
     int family;
     int sentcreds;
 } servinfo;
-char *dc_srv_local;
+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;
@@ -155,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++;
@@ -259,7 +321,6 @@ int dc_init(void)
 {
     if((ichandle = iconv_open("wchar_t", "utf-8")) == (iconv_t)-1)
        return(-1);
-    dc_srv_local = sstrdup("");
     initcmds();
     return(0);
 }
@@ -417,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);
@@ -427,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;
@@ -440,6 +505,7 @@ int dc_queuecmd(int (*callback)(struct dc_response *), void *data, ...)
                } else {
                    if(buf != NULL)
                        free(buf);
+                   errno = EINVAL;
                    return(-1);
                }
            } else {
@@ -520,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)
@@ -533,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;
                }
@@ -762,6 +831,7 @@ int dc_handleread(void)
     return(0);
 }
 
+#if UNIX_AUTH_STYLE == 1
 static void mkcreds(struct msghdr *msg)
 {
     struct ucred *ucred;
@@ -780,6 +850,7 @@ static void mkcreds(struct msghdr *msg)
     ucred->gid = getgid();
     msg->msg_controllen = cmsg->cmsg_len;
 }
+#endif
 
 int dc_handlewrite(void)
 {
@@ -798,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)
            {
@@ -1051,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);
@@ -1121,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)"))
@@ -1152,6 +1228,7 @@ static int dc_connectai(struct addrinfo *hosts, struct qcmd **cnctcmd)
            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)
@@ -1159,6 +1236,7 @@ static int dc_connectai(struct addrinfo *hosts, struct qcmd **cnctcmd)
                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 {
@@ -1188,12 +1266,16 @@ static int dc_connect2(char *host, struct qcmd **cnctcmd)
     struct qcmd *qcmd;
     int ret;
     
-    if(host == dc_srv_local)
+    if(host == dc_srv_local) {
+       message(4, "connect start: Unix\n");
        ai = getlocalai();
-    else if(!host || !*host)
+    } 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);
     ret = dc_connectai(ai, &qcmd);
@@ -1238,6 +1320,7 @@ int dc_connectsync2(char *host, int rev)
     {
        dc_freeresp(resp);
        dc_disconnect();
+       errno = EPROTONOSUPPORT;
        return(-1);
     }
     dc_freeresp(resp);
@@ -1295,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++;