.libs
*.gtk
*.gtkh
+TAGS
/m4
/configure
$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
#include <string.h>
#include <errno.h>
#include <locale.h>
+#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
{
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);
}
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])
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])])
--- /dev/null
+#!/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
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
{
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);
}
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;
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");
} 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)
new->pid = pid;
new->callback = func;
new->data = data;
- new->finished = 0;
new->prev = NULL;
new->next = children;
if(children != NULL)
static void handler(int signum)
{
- pid_t pid;
- int status;
- struct child *child;
FILE *dumpfile;
extern int numfnetnodes, numtransfers, numdcpeers;
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");
}
}
+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;
int delay, immsyslog;
struct module *mod;
struct timer *timer;
- struct child *child;
double now;
now = ntime();
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
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();
* 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). */
* 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}
};
{
int buf;
struct ufd *ufd;
+ int dscp2tos;
ufd = getskufd(sk);
if(ufd->type != UFD_SOCK) {
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);
#include "module.h"
#include "log.h"
+#ifdef HAVE_XATTR
+#include <attr/xattr.h>
+#endif
+
struct trdata {
size_t startpos;
};
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)
/** 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}
};
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);
for(pp = cargv; *pp; pp++)
free(*pp);
free(cargv);
+ free(filtercmd);
data->fcmdsk = wrapsock(pipe);
data->fcmdpid = pid;
if(data->fcmdbuf != NULL)
Code cleanups:
* Clean up local variables in the library.
-
-Other: See output of "grep -r XXX ."
+ * See output of "grep -r XXX ."
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
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
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, ...)
{
{
if((ichandle = iconv_open("wchar_t", "utf-8")) == (iconv_t)-1)
return(-1);
- dc_srv_local = sstrdup("");
initcmds();
return(0);
}