Merge branch 'master' into socket
authorFredrik Tolf <fredrik@dolda2000.com>
Fri, 17 Oct 2008 23:11:09 +0000 (01:11 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Fri, 17 Oct 2008 23:11:09 +0000 (01:11 +0200)
Conflicts:

daemon/net.c

17 files changed:
.gitignore
clients/gtk2/mainwnd.desc
clients/tty/dcsh.c
configure.in
contrib/debian-init.d-doldacond [new file with mode: 0755]
daemon/Makefile.am
daemon/auth.c
daemon/client.c
daemon/fnet-dc.c
daemon/main.c
daemon/net.c
daemon/reqstat.c
daemon/sysevents.h
daemon/ui.c
doc/TODO
doc/man/doldacond.conf.5.in
lib/uilib.c

index cb9c624..54891e3 100644 (file)
@@ -7,6 +7,7 @@ Makefile.in
 .libs
 *.gtk
 *.gtkh
+TAGS
 
 /m4
 /configure
index 9bb2220..f1022a8 100644 (file)
@@ -140,24 +140,24 @@ end
                                        $mlbl label: "_List of downloads:" mwidget: downloads
                                        :sw fill: TRUE expand: TRUE
                                                :treeview name: downloads var: y sig(key-press-event): cb_main_trlist_keypress sig(popup-menu): cb_main_trpopup sig(button-release-event): cb_main_trpopup
-                                                       :tvcol title: "User Name"
+                                                       :tvcol title: "User Name" resizable: TRUE
                                                                $pixbufrend stock_id: 8
                                                                $textrend text: 4
                                                        end
-                                                       $tvcol title: "File Name" text: 5
-                                                       :tvcol title: "Size"
+                                                       $tvcol title: "File Name" text: 5 resizable: TRUE
+                                                       :tvcol title: "Size" resizable: TRUE
                                                                $textrend func: transnicebytefunc funcdata: "GINT_TO_POINTER(6)"
                                                        end
-                                                       :tvcol title: "Position"
+                                                       :tvcol title: "Position" resizable: TRUE
                                                                $progrend func: progressfunc funcdata: "GINT_TO_POINTER((6 << 8) | 7)" expand: TRUE
                                                        end
-                                                       :tvcol title: "Speed"
+                                                       :tvcol title: "Speed" resizable: TRUE
                                                                $textrend func: transspeedinfo
                                                        end
-                                                       :tvcol title: "Error"
+                                                       :tvcol title: "Error" resizable: TRUE
                                                                $textrend func: transerrorinfo
                                                        end
-                                                       $tvcol title: "Hash" text: 12
+                                                       $tvcol title: "Hash"  resizable: TRUE text: 12
                                                end
                                        end
                                end
index 835aa8b..60904b9 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <errno.h>
 #include <locale.h>
+#include <stdint.h>
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -91,20 +92,24 @@ int cmd_lsdl(int argc, wchar_t **argv)
 {
     struct dc_response *resp;
     struct dc_intresp *ires;
+    wchar_t *file, *p;
     
     resp = dc_gettaggedrespsync(dc_queuecmd(NULL, NULL, L"lstrans", NULL));
     if(resp->code == 200) {
        if(interactive) {
-           printf("ID      S USER            FILE\n");
-           printf("------- - --------------- ----------------------------------------------------\n");
+           printf("ID      S USER       PROGRESS      FILE\n");
+           printf("------- - ---------- ------------- -------------------------------------------\n");
        }
        while((ires = dc_interpret(resp)) != NULL) {
            if(ires->argv[1].val.num == DC_TRNSD_DOWN) {
+               file = ires->argv[5].val.str;
+               if((p = wcsrchr(file, L'/')) != NULL)
+                   file = p + 1;
                if(interactive) {
-                   wcslimit(ires->argv[4].val.str, 15);
-                   wcslimitr(ires->argv[5].val.str, 52);
+                   wcslimit(ires->argv[4].val.str, 10);
+                   wcslimit(file, 43);
                }
-               printf("%-7i %c %-15ls %ls\n", ires->argv[0].val.num, "SHED"[ires->argv[2].val.num], ires->argv[4].val.str, ires->argv[5].val.str);
+               printf("%-7i %c %-10ls %'-13ji %ls\n", ires->argv[0].val.num, "SHED"[ires->argv[2].val.num], ires->argv[4].val.str, (intmax_t)ires->argv[7].val.lnum, file);
            }
            dc_freeires(ires);
        }
index 49c7ea4..effe65b 100644 (file)
@@ -1,5 +1,5 @@
 AC_INIT(daemon/main.c)
-AM_INIT_AUTOMAKE([doldaconnect], [1.2])
+AM_INIT_AUTOMAKE([doldaconnect], [1.3])
 AM_CONFIG_HEADER(config.h)
 
 DOLDA_AC_GROUP([Checking build chain])
@@ -83,6 +83,21 @@ if test "$HAS_LIBNOTIFY" = yes; then
        AC_DEFINE(HAVE_NOTIFY)
 fi
 
+# libattr check
+AH_TEMPLATE(HAVE_XATTR, [define to compile support for extended attributes])
+AC_ARG_WITH(xattr, [  --with-xattr            Enable XATTR support])
+DOLDA_PKG([HAS_XATTR], [test "$with_xattr" = no && HAS_XATTR=no],
+                      [AC_CHECK_LIB(attr, getxattr, [:], [HAS_XATTR=no])],
+                      [DOLDA_CHECK_HEADER(attr/xattr.h, [], [HAS_XATTR=no])],
+                      [XATTR_LIBS=-lattr])
+if test "$with_xattr" = yes -a "$HAS_XATTR" = no; then
+       AC_MSG_ERROR([*** cannot find xattr support on this system])
+fi
+if test "$HAS_XATTR" = yes; then
+       AC_DEFINE(HAVE_XATTR)
+fi
+AC_SUBST(XATTR_LIBS)
+
 # libpanelapplet check
 DOLDA_PKG([HAS_LIBPANELAPPLET], [PKG_CHECK_MODULES(PANELAPPLET, libpanelapplet-2.0, [], [HAS_LIBPANELAPPLET=no])])
 
diff --git a/contrib/debian-init.d-doldacond b/contrib/debian-init.d-doldacond
new file mode 100755 (executable)
index 0000000..1492f94
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+PATH=/usr/local/bin:/usr/local/sbin:$PATH
+# Protect auto-files against sudo invocations of the init script
+HOME=/root
+# If you use PAM authentication with pam_krb5 and Kerberos
+# authentication simultaneously, uncomment the following line to
+# avoid segfaults in libcom_err:
+#LD_PRELOAD=/usr/lib/libkrb4.so; export LD_PRELOAD
+
+. /lib/lsb/init-functions
+
+start() {
+    LANG=en_US.UTF-8
+    export LANG
+    log_begin_msg "Starting Dolda Connect daemon..."
+    log_progress_msg lists
+    rm -f /tmp/dc-filelist-*
+    log_progress_msg daemon
+    start-stop-daemon -S -p /var/run/doldacond.pid -qx /usr/local/bin/doldacond -- -s -p /var/run/doldacond.pid
+    log_end_msg $?
+}
+
+stop() {
+    log_begin_msg "Stopping Dolda Connect daemon..."
+    start-stop-daemon -K -p /var/run/doldacond.pid -qx /usr/local/bin/doldacond
+    log_end_msg $?
+}
+
+reload() {
+    log_begin_msg "Reloading Dolda Connect daemon..."
+    start-stop-daemon -K -p /var/run/doldacond.pid -qx /usr/local/bin/doldacond -s HUP
+    log_end_msg $?
+}
+
+case "$1" in
+    start)
+       start
+       ;;
+    stop)
+       stop
+       ;;
+    reload)
+       reload
+       ;;
+    restart)
+       stop
+       start
+       ;;
+esac
+
+exit 0
index 532b4da..a80ad94 100644 (file)
@@ -32,5 +32,5 @@ endif
 
 EXTRA_DIST=emacs-local
 doldacond_LDADD=$(top_srcdir)/common/libcommon.a \
-               @KRB5_LIBS@ -lbz2 -lz -lgdbm @PAM_LIBS@ @KEYUTILS_LIBS@
+               @KRB5_LIBS@ -lbz2 -lz -lgdbm @PAM_LIBS@ @KEYUTILS_LIBS@ @XATTR_LIBS@
 doldacond_CPPFLAGS=-I$(top_srcdir)/include -DDAEMON @KRB5_CFLAGS@ -D_ISOC99_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
index 470c985..d8c7a35 100644 (file)
@@ -80,10 +80,10 @@ void authputhandle(struct authhandle *auth)
 {
     if(--auth->refcount)
        return;
-    if(auth->text != NULL)
-       free(auth->text);
     if(auth->mechdata != NULL)
        auth->mech->release(auth);
+    if(auth->text != NULL)
+       free(auth->text);
     free(auth);
 }
 
index 46766e9..e493a88 100644 (file)
@@ -294,8 +294,10 @@ static void readhashcache(void)
     if((stream = fopen(hcname, "r")) == NULL)
     {
        flog(LOG_WARNING, "could not open hash cache %s: %s", hcname, strerror(errno));
+       free(hcname);
        return;
     }
+    free(hcname);
     while(hashcache != NULL)
        freehashcache(hashcache);
     line = 0;
@@ -369,8 +371,10 @@ static void writehashcache(int now)
     if((stream = fopen(hcname, "w")) == NULL)
     {
        flog(LOG_WARNING, "could not write hash cache %s: %s", hcname, strerror(errno));
+       free(hcname);
        return;
     }
+    free(hcname);
     fprintf(stream, "# Dolda Connect hash cache file\n");
     fprintf(stream, "# Generated automatically, do not edit\n");
     fprintf(stream, "# Format: DEVICE INODE MTIME [HASH...]\n");
index 708215a..828e6d0 100644 (file)
@@ -2117,6 +2117,7 @@ static void cmd_adcget(struct socket *sk, struct dcpeer *peer, char *cmd, char *
     } else if(fd >= 0) {
        if((wbuf = adc2path(argv[1])) != NULL)
            transfersetpath(peer->transfer, wbuf);
+       free(wbuf);
        peer->transfer->flags.b.minislot = 1;
     }
     if(fd < 0)
index 58d1c6c..463d8be 100644 (file)
@@ -91,7 +91,6 @@ void childcallback(pid_t pid, void (*func)(pid_t, int, void *), void *data)
     new->pid = pid;
     new->callback = func;
     new->data = data;
-    new->finished = 0;
     new->prev = NULL;
     new->next = children;
     if(children != NULL)
@@ -139,9 +138,6 @@ static void terminate(void)
 
 static void handler(int signum)
 {
-    pid_t pid;
-    int status;
-    struct child *child;
     FILE *dumpfile;
     extern int numfnetnodes, numtransfers, numdcpeers;
     
@@ -155,18 +151,7 @@ static void handler(int signum)
        running = 0;
        break;
     case SIGCHLD:
-       while((pid = waitpid(-1, &status, WNOHANG)) > 0)
-       {
-           for(child = children; child != NULL; child = child->next)
-           {
-               if(child->pid == pid)
-               {
-                   child->finished = 1;
-                   child->status = status;
-               }
-           }
-           childrendone = 1;
-       }
+       childrendone = 1;
        break;
     case SIGUSR1:
        flog(LOG_NOTICE, "forking and dumping core upon SIGUSR1");
@@ -185,6 +170,32 @@ static void handler(int signum)
     }
 }
 
+static void checkchildren(void)
+{
+    pid_t pid;
+    int status;
+    struct child *child;
+
+    while((pid = waitpid(-1, &status, WNOHANG)) > 0)
+    {
+       for(child = children; child != NULL; child = child->next)
+       {
+           if(child->pid == pid)
+           {
+               child->callback(pid, status, child->data);
+               if(child == children)
+                   children = child->next;
+               if(child->prev != NULL)
+                   child->prev->next = child->next;
+               if(child->next != NULL)
+                   child->next->prev = child->prev;
+               free(child);
+               break;
+           }
+       }
+    }
+}
+
 pid_t forksess(uid_t user, struct authhandle *auth, void (*ccbfunc)(pid_t, int, void *), void *data, ...)
 {
     int i, o;
@@ -383,7 +394,6 @@ int main(int argc, char **argv)
     int delay, immsyslog;
     struct module *mod;
     struct timer *timer;
-    struct child *child;
     double now;
     
     now = ntime();
@@ -534,11 +544,10 @@ int main(int argc, char **argv)
                    delay = (int)((timer->at - now) * 1000.0);
            }
        }
+       /* Of course, there's a race condition here that should be
+        * solved with pselect, but it doesn't matter a lot. */
        if(childrendone)
-       {
            delay = 0;
-           childrendone = 0;
-       }
        pollsocks(delay);
        now = ntime();
        do
@@ -558,24 +567,11 @@ int main(int argc, char **argv)
                break;
            }
        } while(timer != NULL);
-       do
+       if(childrendone)
        {
-           for(child = children; child != NULL; child = child->next)
-           {
-               if(child->finished)
-               {
-                   child->callback(child->pid, child->status, child->data);
-                   if(child == children)
-                       children = child->next;
-                   if(child->prev != NULL)
-                       child->prev->next = child->next;
-                   if(child->next != NULL)
-                       child->next->prev = child->prev;
-                   free(child);
-                   break;
-               }
-           }
-       } while(child != NULL);
+           childrendone = 0;
+           checkchildren();
+       }
     }
     flog(LOG_INFO, "terminating...");
     terminate();
index d64e8c8..240855a 100644 (file)
@@ -66,8 +66,6 @@ static struct configvar myvars[] =
      * and net.visibleipv4 are unspecified the address of the hub
      * connection is used. */
     {CONF_VAR_STRING, "publicif", {.str = L""}},
-    /* Diffserv should be supported on IPv4, too, but I don't know the
-     * API to do that. */
     /** The Diffserv value to use on IPv6 connections when the
      * minimize cost TOS value is used (see the TOS VALUES
      * section). */
@@ -84,6 +82,12 @@ static struct configvar myvars[] =
      * minimize delay TOS value is used (see the TOS VALUES
      * section). */
     {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}},
+    /** If enabled, the IP TOS interface will be used to set Diffserv
+     * codepoints on IPv4 sockets, by shifting the DSCP value two bits
+     * to the left (remember, the DSCP field in the IPv4 header is
+     * defined as the 6 uppermost bits of the TOS field, the lower two
+     * being left for ECN). This may only work on Linux. */
+    {CONF_VAR_BOOL, "dscp-tos", {.num = 0}},
     {CONF_VAR_END}
 };
 
@@ -1155,6 +1159,7 @@ int socksettos(struct socket *sk, int tos)
 {
     int buf;
     struct ufd *ufd;
+    int dscp2tos;
     
     ufd = getskufd(sk);
     if(ufd->type != UFD_SOCK) {
@@ -1165,22 +1170,35 @@ int socksettos(struct socket *sk, int tos)
        return(0); /* Unix sockets are always perfect. :) */
     if(ufd->d.s.family == AF_INET)
     {
+       dscp2tos = confgetint("net", "dscp-tos");
        switch(tos)
        {
        case 0:
            buf = 0;
            break;
        case SOCK_TOS_MINCOST:
-           buf = 0x02;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-mincost") << 2;
+           else
+               buf = 0x02;
            break;
        case SOCK_TOS_MAXREL:
-           buf = 0x04;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-maxrel") << 2;
+           else
+               buf = 0x04;
            break;
        case SOCK_TOS_MAXTP:
-           buf = 0x08;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-maxtp") << 2;
+           else
+               buf = 0x08;
            break;
        case SOCK_TOS_MINDELAY:
-           buf = 0x10;
+           if(dscp2tos)
+               buf = confgetint("net", "diffserv-mindelay") << 2;
+           else
+               buf = 0x10;
            break;
        default:
            flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);
index cbe1c72..d3d849f 100644 (file)
 #include "module.h"
 #include "log.h"
 
+#ifdef HAVE_XATTR
+#include <attr/xattr.h>
+#endif
+
 struct trdata {
     size_t startpos;
 };
@@ -61,19 +65,60 @@ void filelog(char *format, ...)
     fclose(out);
 }
 
+#ifdef HAVE_XATTR
+void xainc(wchar_t *file, char *an, off_t inc)
+{
+    char buf[32];
+    ssize_t al;
+    off_t val;
+    char *fn;
+    
+    if((fn = icswcstombs(file, NULL, NULL)) == NULL) {
+       flog(LOG_WARNING, "could not convert filename %ls into local charset: %s", file, strerror(errno));
+       return;
+    }
+    if((al = getxattr(fn, an, buf, sizeof(buf) - 1)) < 0) {
+       if(errno != ENOATTR) {
+           flog(LOG_WARNING, "could not get xattr %s on %s: %s", an, fn, strerror(errno));
+           return;
+       }
+       val = 0;
+    } else {
+       buf[al] = 0;
+       val = strtoll(buf, NULL, 10);
+    }
+    val += inc;
+    al = snprintf(buf, sizeof(buf), "%ji", (intmax_t)val);
+    if(setxattr(fn, an, buf, al, 0) < 0)
+       flog(LOG_WARNING, "could not set xattr %s on %s: %s", an, fn, strerror(errno));
+}
+#endif
+
 void request(struct transfer *transfer, struct trdata *data)
 {
     filelog("request %ls", transfer->path);
+#ifdef HAVE_XATTR
+    if(confgetint("reqstat", "xa"))
+       xainc(transfer->path, "user.dc-req", 1);
+#endif
 }
 
 void start(struct transfer *transfer, struct trdata *data)
 {
     filelog("start %ls at %zi", transfer->path, data->startpos);
+#ifdef HAVE_XATTR
+    if(confgetint("reqstat", "xa"))
+       xainc(transfer->path, "user.dc-started", 1);
+#endif
 }
 
 void finish(struct transfer *transfer, struct trdata *data)
 {
     filelog("finish %ls at %zi, total %zi", transfer->path, transfer->curpos, transfer->curpos - data->startpos);
+#ifdef HAVE_XATTR
+    if(confgetint("reqstat", "xa"))
+       xainc(transfer->path, "user.dc-bytes", transfer->curpos - data->startpos);
+#endif
 }
 
 static int chattr(struct transfer *transfer, wchar_t *attrib, struct trdata *data)
@@ -140,6 +185,12 @@ static struct configvar myvars[] = {
     /** The name of a file to log upload request information to. If
      * unspecified, upload requests will not be logged. */
     {CONF_VAR_STRING, "file", {.str = L""}},
+    /** If set to true, upload statistics of files will be accumulated
+     * in counters stored in extends attributes (see attr(5)) on the
+     * files themselves. The data accumulated is the number of
+     * requests, the number of successfully started uploads and the
+     * number of uploaded bytes. */
+    {CONF_VAR_BOOL, "xa", {.num = 0}},
     {CONF_VAR_END}
 };
 
index 141fa6e..86cf69f 100644 (file)
@@ -40,8 +40,6 @@ struct child
     pid_t pid;
     void (*callback)(pid_t pid, int status, void *data);
     void *data;
-    int status;
-    volatile int finished;
 };
 
 void childcallback(pid_t pid, void (*func)(pid_t, int, void *), void *data);
index 0f6e701..3f65ea1 100644 (file)
@@ -1216,6 +1216,7 @@ static void cmd_filtercmd(struct socket *sk, struct uidata *data, int argc, wcha
     for(pp = cargv; *pp; pp++)
        free(*pp);
     free(cargv);
+    free(filtercmd);
     data->fcmdsk = wrapsock(pipe);
     data->fcmdpid = pid;
     if(data->fcmdbuf != NULL)
index 2f15a87..f194997 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -22,5 +22,4 @@ Documentation:
 
 Code cleanups:
  * Clean up local variables in the library.
-
-Other: See output of "grep -r XXX ."
+ * See output of "grep -r XXX ."
index 16c474c..3aa5903 100644 (file)
@@ -151,7 +151,8 @@ those routers. For IPv6 connections, which use Diffserv instead of the
 older IPv4 TOS values, the Diffserv values to use are specified by the
 \fBnet.diffserv-mincost\fP, \fBnet.diffserv-maxrel\fP,
 \fBnet.diffserv-maxtp\fP and \fBnet.diffserv-mindelay\fP configuration
-variables, as described above.
+variables, as described above. For a way to use DSCP in IPv4 as well,
+see the \fBnet.dscp-tos\fP option above.
 .SH FILES
 All file names specified in the configuration file, and the
 configuration file itself, are looked up by the daemon in a rather
@@ -191,8 +192,27 @@ file will be overwritten in place if found. If not found, it will be
 created in the home directory of the user running the daemon. If the
 home directory cannot be determined, the file will be created in /etc.
 .SH BUGS
-IPv4 should also be able to use Diffserv instead of TOS. I have simply
-not been able to find the API to set IPv4 Diffserv values.
+The TOS-related options have a number of interesting quirks:
+.TP
+1
+It is currently unclear to me whether Linux has an API to set IPv6
+DSCP values, so it is left unimplemented for now.
+.TP
+2
+I am rather sure that Linux lacks an API to set IPv4 DSCP
+values. However, it seems that it is possible to use the TOS API to
+set DSCP values, so it has been implemented as an option (see the
+\fBnet.dscp-tos\fP options above).
+.TP
+3
+Even though Linux lacks an explicit API to set the DSCP field in IPv4,
+the TOS API is "DSCP compliant" in the interesting way that it masks
+away the two least significant bits. Therefore, the minimum cost TOS
+value cannot currently be set on Linux.
+.TP
+4
+I have not examined how these issues compare to other operating
+systems, like FreeBSD.
 .SH AUTHOR
 Fredrik Tolf <fredrik@dolda2000.com>
 .SH SEE ALSO
index dfe414c..d07b9eb 100644 (file)
@@ -104,7 +104,8 @@ struct {
     int family;
     int sentcreds;
 } servinfo;
-char *dc_srv_local;
+/* char dc_srv_local_addr; */
+char *dc_srv_local = (void *)&dc_srv_local;
 
 static void message(int bits, char *format, ...)
 {
@@ -320,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);
 }