X-Git-Url: http://dolda2000.com/gitweb/?p=doldaconnect.git;a=blobdiff_plain;f=daemon%2Ftransfer.c;h=9c50ed102342e0b7c91739f5b4c4b5b8294f9c10;hp=0fea334ddb0c8feb7937d68c81a57f64b82d6b56;hb=1ce5968e27a19937a0e54f118d91e1a22438a0eb;hpb=5b193db06069c0d85b1f90f2df23a7091edc8999 diff --git a/daemon/transfer.c b/daemon/transfer.c index 0fea334..9c50ed1 100644 --- a/daemon/transfer.c +++ b/daemon/transfer.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 @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include @@ -80,6 +81,8 @@ void freetransfer(struct transfer *transfer) free(transfer->filterbuf); if(transfer->hash != NULL) freehash(transfer->hash); + if(transfer->exitstatus != NULL) + free(transfer->exitstatus); if(transfer->localend != NULL) { transfer->localend->readcb = NULL; @@ -123,22 +126,72 @@ struct transfer *newtransfer(void) return(new); } -void transferattach(struct transfer *transfer, struct transferiface *iface, void *data) +static void localread(struct socket *sk, struct transfer *transfer) { - if(transfer->iface != NULL) - transferdetach(transfer); - transfer->iface = iface; - transfer->ifacedata = data; + void *buf; + size_t blen; + + if((transfer->datapipe != NULL) && (sockqueueleft(transfer->datapipe) > 0)) { + buf = sockgetinbuf(sk, &blen); + sockqueue(transfer->datapipe, buf, blen); + } +} + +static void dataread(struct socket *sk, struct transfer *transfer) +{ + void *buf; + size_t blen; + + if((transfer->localend != NULL) && (sockqueueleft(transfer->localend) > 0)) { + buf = sockgetinbuf(sk, &blen); + sockqueue(transfer->localend, buf, blen); + } +} + +static void localwrite(struct socket *sk, struct transfer *transfer) +{ + if(transfer->datapipe != NULL) + dataread(transfer->datapipe, transfer); +} + +static void datawrite(struct socket *sk, struct transfer *transfer) +{ + if(transfer->localend != NULL) + localread(transfer->localend, transfer); +} + +static void localerr(struct socket *sk, int errno, struct transfer *transfer) +{ + if(transfer->datapipe != NULL) + closesock(transfer->datapipe); +} + +static void dataerr(struct socket *sk, int errno, struct transfer *transfer) +{ + if(transfer->localend != NULL) + closesock(transfer->localend); +} + +void transferattach(struct transfer *transfer, struct socket *dpipe) +{ + transferdetach(transfer); + getsock(transfer->datapipe = dpipe); + dpipe->readcb = (void (*)(struct socket *, void *))dataread; + dpipe->writecb = (void (*)(struct socket *, void *))datawrite; + dpipe->errcb = (void (*)(struct socket *, int, void *))dataerr; + dpipe->data = transfer; } void transferdetach(struct transfer *transfer) { - if(transfer->iface != NULL) - { - transfer->iface->detach(transfer, transfer->ifacedata); - transfer->iface = NULL; - transfer->ifacedata = NULL; + if(transfer->datapipe != NULL) { + transfer->datapipe->readcb = NULL; + transfer->datapipe->writecb = NULL; + transfer->datapipe->errcb = NULL; + closesock(transfer->datapipe); + putsock(transfer->datapipe); } + transfer->datapipe = NULL; } struct transfer *finddownload(wchar_t *peerid) @@ -147,13 +200,25 @@ struct transfer *finddownload(wchar_t *peerid) for(transfer = transfers; transfer != NULL; transfer = transfer->next) { - if((transfer->dir == TRNSD_DOWN) && (transfer->iface == NULL) && !wcscmp(peerid, transfer->peerid)) + if((transfer->dir == TRNSD_DOWN) && (transfer->datapipe == NULL) && !wcscmp(peerid, transfer->peerid)) + break; + } + return(transfer); +} + +struct transfer *hasupload(struct fnet *fnet, wchar_t *peerid) +{ + struct transfer *transfer; + + for(transfer = transfers; transfer != NULL; transfer = transfer->next) + { + if((transfer->dir == TRNSD_UP) && (transfer->fnet == fnet) && !wcscmp(transfer->peerid, peerid)) break; } return(transfer); } -struct transfer *newupload(struct fnetnode *fn, struct fnet *fnet, wchar_t *nickid, struct transferiface *iface, void *data) +struct transfer *newupload(struct fnetnode *fn, struct fnet *fnet, wchar_t *nickid, struct socket *dpipe) { struct transfer *transfer; @@ -167,7 +232,7 @@ struct transfer *newupload(struct fnetnode *fn, struct fnet *fnet, wchar_t *nick transfer->dir = TRNSD_UP; if(fn != NULL) getfnetnode(transfer->fn = fn); - transferattach(transfer, iface, data); + transferattach(transfer, dpipe); linktransfer(transfer); bumptransfer(transfer); return(transfer); @@ -187,8 +252,7 @@ void resettransfer(struct transfer *transfer) { if(transfer->dir == TRNSD_DOWN) { - if(transfer->iface != NULL) - transferdetach(transfer); + transferdetach(transfer); killfilter(transfer); transfersetstate(transfer, TRNS_WAITING); transfersetactivity(transfer, L"reset"); @@ -217,27 +281,7 @@ static void transexpire(int cancelled, struct transfer *transfer) transfer->timeout = 0; } -static void transferread(struct socket *sk, struct transfer *transfer) -{ - if(sockgetdatalen(sk) >= 65536) - sk->ignread = 1; - if((transfer->iface != NULL) && (transfer->iface->gotdata != NULL)) - transfer->iface->gotdata(transfer, transfer->ifacedata); -} - -static void transferwrite(struct socket *sk, struct transfer *transfer) -{ - if((transfer->iface != NULL) && (transfer->iface->wantdata != NULL)) - transfer->iface->wantdata(transfer, transfer->ifacedata); -} - -static void transfererr(struct socket *sk, int errno, struct transfer *transfer) -{ - if((transfer->iface != NULL) && (transfer->iface->endofdata != NULL)) - transfer->iface->endofdata(transfer, transfer->ifacedata); -} - -void transferputdata(struct transfer *transfer, void *buf, size_t size) +static void transferputdata(struct transfer *transfer, void *buf, size_t size) { time(&transfer->activity); sockqueue(transfer->localend, buf, size); @@ -246,7 +290,7 @@ void transferputdata(struct transfer *transfer, void *buf, size_t size) CBCHAINDOCB(transfer, trans_p, transfer); } -void transferendofdata(struct transfer *transfer) +static void transferendofdata(struct transfer *transfer) { if(transfer->curpos >= transfer->size) { @@ -261,25 +305,28 @@ void transferendofdata(struct transfer *transfer) } } -size_t transferdatasize(struct transfer *transfer) +static ssize_t transferdatasize(struct transfer *transfer) { - return(sockqueuesize(transfer->localend)); + return(sockqueueleft(transfer->localend)); } -void *transfergetdata(struct transfer *transfer, size_t *size) +static void *transfergetdata(struct transfer *transfer, size_t *size) { void *buf; if(transfer->localend == NULL) return(NULL); - transfer->localend->ignread = 0; time(&transfer->activity); if((buf = sockgetinbuf(transfer->localend, size)) == NULL) return(NULL); if((transfer->endpos >= 0) && (transfer->curpos + *size >= transfer->endpos)) { - *size = transfer->endpos - transfer->curpos; - buf = srealloc(buf, *size); + if((*size = transfer->endpos - transfer->curpos) == 0) { + free(buf); + buf = NULL; + } else { + buf = srealloc(buf, *size); + } } transfer->curpos += *size; bytesupload += *size; @@ -287,12 +334,11 @@ void *transfergetdata(struct transfer *transfer, size_t *size) return(buf); } -void transferprepul(struct transfer *transfer, size_t size, size_t start, size_t end, struct socket *lesk) +void transferprepul(struct transfer *transfer, off_t size, off_t start, off_t end, struct socket *lesk) { transfersetsize(transfer, size); transfer->curpos = start; transfer->endpos = end; - lesk->ignread = 1; transfersetlocalend(transfer, lesk); } @@ -307,7 +353,7 @@ void transferstartul(struct transfer *transfer, struct socket *sk) transfersetstate(transfer, TRNS_MAIN); socksettos(sk, confgetint("transfer", "ultos")); if(transfer->localend != NULL) - transfer->localend->ignread = 0; + localread(transfer->localend, transfer); } void transfersetlocalend(struct transfer *transfer, struct socket *sk) @@ -316,9 +362,9 @@ void transfersetlocalend(struct transfer *transfer, struct socket *sk) putsock(transfer->localend); getsock(transfer->localend = sk); sk->data = transfer; - sk->readcb = (void (*)(struct socket *, void *))transferread; - sk->writecb = (void (*)(struct socket *, void *))transferwrite; - sk->errcb = (void (*)(struct socket *, int, void *))transfererr; + sk->readcb = (void (*)(struct socket *, void *))localread; + sk->writecb = (void (*)(struct socket *, void *))localwrite; + sk->errcb = (void (*)(struct socket *, int, void *))localerr; } static int tryreq(struct transfer *transfer) @@ -443,7 +489,7 @@ void transfersetnick(struct transfer *transfer, wchar_t *newnick) CBCHAINDOCB(transfer, trans_ac, transfer, L"nick"); } -void transfersetsize(struct transfer *transfer, int newsize) +void transfersetsize(struct transfer *transfer, off_t newsize) { transfer->size = newsize; CBCHAINDOCB(transfer, trans_ac, transfer, L"size"); @@ -514,56 +560,15 @@ static void killfilter(struct transfer *transfer) transfer->filterbufsize = transfer->filterbufdata = 0; } -static char *findfilter(struct passwd *pwd) +static void handletranscmd(struct transfer *transfer, wchar_t *cmd, wchar_t *arg) { - char *path, *filtername; - - if((path = sprintf2("%s/.dcdl-filter", pwd->pw_dir)) != NULL) - { - if(!access(path, X_OK)) - return(path); - free(path); + if(!wcscmp(cmd, L"status")) { + if(arg == NULL) + arg = L""; + if(transfer->exitstatus != NULL) + free(transfer->exitstatus); + transfer->exitstatus = swcsdup(arg); } - if((filtername = icwcstombs(confgetstr("transfer", "filter"), NULL)) == NULL) - { - flog(LOG_WARNING, "could not convert filter name into local charset: %s", strerror(errno)); - } else { - if(strchr(filtername, '/') == NULL) - { - if((path = sprintf2("/etc/%s", filtername)) != NULL) - { - if(!access(path, X_OK)) - { - free(filtername); - return(path); - } - free(path); - } - if((path = sprintf2("/usr/etc/%s", filtername)) != NULL) - { - if(!access(path, X_OK)) - { - free(filtername); - return(path); - } - free(path); - } - if((path = sprintf2("/usr/local/etc/%s", filtername)) != NULL) - { - if(!access(path, X_OK)) - { - free(filtername); - return(path); - } - free(path); - } - } else { - if(!access(filtername, X_OK)) - return(filtername); - } - free(filtername); - } - return(NULL); } static void filterread(struct socket *sk, struct transfer *transfer) @@ -587,8 +592,9 @@ static void filterread(struct socket *sk, struct transfer *transfer) if(p2 != NULL) { if((arg = icmbstowcs(p2, NULL)) == NULL) - flog(LOG_WARNING, "filter sent a string which could not be converted into the local charset: %s: %s", transfer->filterbuf, strerror(errno)); + flog(LOG_WARNING, "filter sent a string which could not be converted into the local charset: %s: %s", p2, strerror(errno)); } + handletranscmd(transfer, cmd, arg); CBCHAINDOCB(transfer, trans_filterout, transfer, cmd, arg); if(arg != NULL) free(arg); @@ -603,6 +609,8 @@ static void filterread(struct socket *sk, struct transfer *transfer) static void filterexit(pid_t pid, int status, void *data) { struct transfer *transfer; + struct fnet *fnet; + wchar_t *peerid; for(transfer = transfers; transfer != NULL; transfer = transfer->next) { @@ -610,13 +618,14 @@ static void filterexit(pid_t pid, int status, void *data) { transfer->filter = -1; killfilter(transfer); + fnet = transfer->fnet; + peerid = swcsdup(transfer->peerid); if(WEXITSTATUS(status)) - { resettransfer(transfer); - } else { + else freetransfer(transfer); - } - trytransferbypeer(transfer->fnet, transfer->peerid); + trytransferbypeer(fnet, peerid); + free(peerid); break; } } @@ -624,7 +633,7 @@ static void filterexit(pid_t pid, int status, void *data) int forkfilter(struct transfer *transfer) { - char *filtername, *filename, *peerid, *buf; + char *filtername, *filename, *peerid, *buf, *p; wchar_t *wfilename; struct passwd *pwent; pid_t pid; @@ -635,9 +644,7 @@ int forkfilter(struct transfer *transfer) struct wcspair *ta; char *rec, *val; - wfilename = transfer->path; - if(transfer->fnet->filebasename != NULL) - wfilename = transfer->fnet->filebasename(wfilename); + wfilename = fnfilebasename(transfer->path); if(transfer->auth == NULL) { flog(LOG_WARNING, "tried to fork filter for transfer with NULL authhandle (tranfer %i)", transfer->id); @@ -650,7 +657,10 @@ int forkfilter(struct transfer *transfer) errno = EACCES; return(-1); } - if((filtername = findfilter(pwent)) == NULL) + filtername = findfile("dc-filter", pwent->pw_dir, 0); + if(filtername == NULL) + filtername = findfile(icswcstombs(confgetstr("transfer", "filter"), NULL, NULL), NULL, 0); + if(filtername == NULL) { flog(LOG_WARNING, "could not find filter for user %s", pwent->pw_name); errno = ENOENT; @@ -677,6 +687,12 @@ int forkfilter(struct transfer *transfer) peerid = sprintf2("utf8-%s", buf); free(buf); } + for(p = filename; *p; p++) { + if(*p == '/') + *p = '_'; + else if((p == filename) && (*p == '.')) + *p = '_'; + } if((pid = forksess(transfer->owner, transfer->auth, filterexit, NULL, FD_PIPE, 0, O_WRONLY, &inpipe, FD_PIPE, 1, O_RDONLY, &outpipe, FD_FILE, 2, O_RDWR, "/dev/null", FD_END)) < 0) { flog(LOG_WARNING, "could not fork session for filter for transfer %i: %s", transfer->id, strerror(errno)); @@ -686,7 +702,7 @@ int forkfilter(struct transfer *transfer) { argv = NULL; argvsize = argvdata = 0; - buf = sprintf2("%i", transfer->size); + buf = sprintf2("%ji", (intmax_t)transfer->size); addtobuf(argv, filtername); addtobuf(argv, filename); addtobuf(argv, buf); @@ -727,7 +743,7 @@ int forkfilter(struct transfer *transfer) * the fd, and thus it closes it. Until I can find out whyever the * kernel gives a POLLIN on the fd (if I can at all...), I'll just * set ignread on insock for now. */ - insock->ignread = 1; +/* sockblock(insock, 1); */ transfer->filter = pid; transfersetlocalend(transfer, insock); getsock(transfer->filterout = outsock); @@ -745,6 +761,7 @@ static int run(void) { struct transfer *transfer, *next; + /* for(transfer = transfers; transfer != NULL; transfer = transfer->next) { if((transfer->endpos >= 0) && (transfer->state == TRNS_MAIN) && (transfer->localend != NULL) && (transfer->localend->state == SOCK_EST) && (transfer->curpos >= transfer->endpos)) @@ -754,6 +771,7 @@ static int run(void) closesock(transfer->localend); } } + */ for(transfer = transfers; transfer != NULL; transfer = next) { next = transfer->next; @@ -769,10 +787,23 @@ static int run(void) static struct configvar myvars[] = { + /** The maximum number of simultaneously permitted uploads. A + * common hub rule is that you will need at least as many slots as + * the number of hubs to which you are connected. */ {CONF_VAR_INT, "slots", {.num = 3}}, + /** The TOS value to use for upload connections (see the TOS + * VALUES section). */ {CONF_VAR_INT, "ultos", {.num = SOCK_TOS_MAXTP}}, + /** The TOS value to use for download connections (see the TOS + * VALUES section). */ {CONF_VAR_INT, "dltos", {.num = SOCK_TOS_MAXTP}}, + /** The name of the filter script (see the FILES section for + * lookup information). */ {CONF_VAR_STRING, "filter", {.str = L"dc-filter"}}, + /** If true, only one upload is allowed per remote peer. This + * option is still experimental, so it is recommended to leave it + * off. */ + {CONF_VAR_BOOL, "ulquota", {.num = 0}}, {CONF_VAR_END} };