#include <bzlib.h>
#include <zlib.h>
#include <sys/stat.h>
+#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
* considering it was developed without i18n support under Windows */
#define DCCHARSET "windows-1252"
-#ifdef DCPP_MASQUERADE
-/*
- * I honestly don't want to pretend being a client that I'm not, but
- * there are so many hubs that simply do not accept any clients
- * outside their whitelists, for no obvious reasons, so I feel that I
- * am left with little choice. Anyhow, as long as I actually support
- * all the features that my faked DC++ version does, there should be
- * very little harm done.
- */
-#define DCIDTAG "++"
-#define DCIDTAGV "0.674"
-#define DCIDFULL "DC++ 0.674"
-#else
-#define DCIDTAG "Dolda"
-#define DCIDTAGV VERSION
-#define DCIDFULL "DoldaConnect " VERSION
-#endif
-
#define PEER_CMD 0
#define PEER_STOP 1
#define PEER_TRNS 2
struct timer *timeout;
struct qcmdqueue queue;
struct transfer *transfer;
+ struct socket *trpipe;
int state;
int ptclose; /* Close after transfer is complete */
int accepted; /* If false, we connected, otherwise, we accepted */
};
static struct fnet dcnet;
-static struct transferiface dctransfer;
static struct socket *udpsock = NULL;
-static struct socket *tcpsock = NULL;
+static struct lport *tcpsock = NULL;
static struct dcpeer *peers = NULL;
int numdcpeers = 0;
static struct dcexppeer *expected = NULL;
static char *xmlbz2listname = NULL;
static struct timer *listwritetimer = NULL;
+static struct socket *mktrpipe(struct dcpeer *peer);
static void peerconnect(struct socket *sk, int err, struct fnetnode *fn);
static void freedcpeer(struct dcpeer *peer);
static void transread(struct socket *sk, struct dcpeer *peer);
static void updatexmlbz2list(void);
static void requestfile(struct dcpeer *peer);
static void updatelists(int now);
+static int trdestroycb(struct transfer *transfer, struct dcpeer *peer);
static int reservedchar(unsigned char c)
{
peer->close = 1;
return;
}
- CBREG(peer->transfer, trans_filterout, (int (*)(struct transfer *, wchar_t *, wchar_t *, void *))trresumecb, NULL, peer);
return;
}
if(supports(peer, "adcget"))
struct dchub *hub;
hub = fn->data;
- if(hub->nativename == NULL)
+ if(hub->nativename != NULL)
free(hub->nativename);
hub->nativename = sstrdup(args);
buf = icmbstowcs(args, hub->charset);
size_t buflen;
int termnum, satisfied, skipcheck;
int level, tersat[32];
- wchar_t *terms[32];
+ wchar_t *terms[32], *lname;
char hashtth[24];
hub = fn->data;
goto out;
prefix = sprintf2("$SR %s ", hub->nativenick);
infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots"));
- postfix = sprintf2(" (%s)\005%s|", formataddress(hub->sk->remote, hub->sk->remotelen), args + 4);
+ postfix = sprintf2(" (%s)\005%s|", formatsockpeer(hub->sk), args + 4);
dsk = sk;
getsock(dsk);
} else {
addr.sin_port = htons(atoi(p2));
prefix = sprintf2("$SR %s ", hub->nativenick);
infix = sprintf2(" %i/%i\005", slotsleft(), confgetint("transfer", "slots"));
- postfix = sprintf2(" (%s)|", formataddress(hub->sk->remote, hub->sk->remotelen));
- netdgramconn(dsk = netdupsock(udpsock), (struct sockaddr *)&addr, sizeof(addr));
+ postfix = sprintf2(" (%s)|", formatsockpeer(hub->sk));
+ dsk = netdgramconn(udpsock, (struct sockaddr *)&addr, sizeof(addr));
}
minsize = maxsize = -1;
memcpy(hashtth, buf, 24);
free(buf);
} else {
- if((terms[termnum] = icmbstowcs(p, hub->charset)) != NULL)
+ if((terms[termnum] = icmbstowcs(p, hub->charset)) != NULL) {
+ wcslower(terms[termnum]);
termnum++;
+ }
}
}
p = p2 + 1;
}
if(!skipcheck)
{
+ lname = wcslower(swcsdup(node->name));
for(i = 0; i < termnum; i++)
{
if(tersat[i] >= 0)
continue;
- if(wcsexists(node->name, terms[i]))
+ if(wcsstr(lname, terms[i]))
{
tersat[i] = level;
satisfied++;
break;
}
}
+ free(lname);
}
if(!skipcheck && (satisfied == termnum))
{
{
char *p;
struct dchub *hub;
- struct socket *newsk;
struct sockaddr_in addr;
hub = fn->data;
addr.sin_port = htons(atoi(p));
if(!inet_aton(args, &addr.sin_addr))
return;
- newsk = netcsconn((struct sockaddr *)&addr, sizeof(addr), (void (*)(struct socket *, int, void *))peerconnect, fn);
+ putsock(netcsconn((struct sockaddr *)&addr, sizeof(addr), (void (*)(struct socket *, int, void *))peerconnect, fn));
getfnetnode(fn);
hubhandleaction(sk, fn, cmd, args);
}
if(tcpsock == NULL)
return;
- if(sockgetremotename2(tcpsock, sk, &addr, &addrlen) < 0)
+ if(lstgetremotename2(tcpsock, sk, &addr, &addrlen) < 0)
return;
if(addr->sa_family == AF_INET)
qstrf(sk, "$ConnectToMe %s %s|", nick, formataddress(addr, addrlen));
}
}
+static void peerattach(struct dcpeer *peer, struct transfer *transfer)
+{
+ peer->transfer = transfer;
+ CBREG(peer->transfer, trans_filterout, (int (*)(struct transfer *, wchar_t *, wchar_t *, void *))trresumecb, NULL, peer);
+ CBREG(peer->transfer, trans_destroy, (int (*)(struct transfer *, void *))trdestroycb, NULL, peer);
+}
+
static void cmd_direction(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
{
char *p;
peer->close = 1;
return;
}
- transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer);
+ transfer = newupload(peer->fn, &dcnet, peer->wcsname, (peer->trpipe = mktrpipe(peer))->back);
} else {
if((transfer = finddownload(peer->wcsname)) == NULL)
{
peer->close = 1;
return;
}
- transferattach(transfer, &dctransfer, peer);
+ transferattach(transfer, (peer->trpipe = mktrpipe(peer))->back);
transfersetstate(transfer, TRNS_HS);
}
transfersetnick(transfer, peer->wcsname);
- peer->transfer = transfer;
+ peerattach(peer, transfer);
if(peer->extended)
sendsupports(peer);
qstrf(sk, "$Direction %s %i|", (peer->direction == TRNSD_UP)?"Upload":"Download", rand() % 10000);
return;
}
peer->direction = TRNSD_UP;
- transfer = newupload(peer->fn, &dcnet, peer->wcsname, &dctransfer, peer);
+ transfer = newupload(peer->fn, &dcnet, peer->wcsname, (peer->trpipe = mktrpipe(peer))->back);
} else {
peer->direction = TRNSD_DOWN;
- transferattach(transfer, &dctransfer, peer);
+ transferattach(transfer, (peer->trpipe = mktrpipe(peer))->back);
transfersetstate(transfer, TRNS_HS);
}
transfersetnick(transfer, peer->wcsname);
- peer->transfer = transfer;
+ peerattach(peer, transfer);
qstrf(sk, "$Direction %s %i|", (peer->direction == TRNSD_UP)?"Upload":"Download", rand() % 10000);
qstrf(sk, "$Key %s|", key);
free(key);
peer->state = PEER_TRNS;
transferstartul(peer->transfer, peer->sk);
peer->sk->writecb = (void (*)(struct socket *, void *))transwrite;
+ transwrite(peer->sk, peer);
}
static void cmd_filelength(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
} 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)
{
sockpushdata(sk, peer->inbuf, peer->inbufdata);
peer->inbufdata = 0;
- transread(sk, peer);
}
} else {
/* We certainly didn't request this...*/
{
sockpushdata(sk, peer->inbuf, peer->inbufdata);
peer->inbufdata = 0;
- transread(sk, peer);
}
}
return(0);
}
-static void findsizelimit(struct sexpr *sexpr, int *min, int *max)
+static void findsizelimit(struct sexpr *sexpr, off_t *min, off_t *max)
{
- int minl, maxl, minr, maxr, retmin, retmax;
+ off_t minl, maxl, minr, maxr, retmin, retmax;
switch(sexpr->op)
{
}
case SOP_SIZELT:
retmin = 0;
- retmax = sexpr->d.n - 1;
+ retmax = sexpr->d.sz - 1;
break;
case SOP_SIZEEQ:
- retmin = sexpr->d.n;
- retmax = sexpr->d.n;
+ retmin = sexpr->d.sz;
+ retmax = sexpr->d.sz;
break;
case SOP_SIZEGT:
- retmin = sexpr->d.n + 1;
+ retmin = sexpr->d.sz + 1;
retmax = -1;
break;
default:
size_t sstrsize, sstrdata;
struct sockaddr *name;
socklen_t namelen;
- int minsize, maxsize;
+ off_t minsize, maxsize;
struct hash *hash;
hub = fn->data;
if(minsize != 0)
{
sizebuf2(sstr, sstrdata + 32, 1);
- sstrdata += snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?F?%i?1?", minsize);
+ sstrdata += snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?F?%ji?1?", (intmax_t)minsize);
} else if(maxsize != -1) {
sizebuf2(sstr, sstrdata + 32, 1);
- sstrdata += snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?T?%i?1?", maxsize);
+ sstrdata += snprintf(sstr + sstrdata, sstrsize - sstrdata, "T?T?%ji?1?", (intmax_t)maxsize);
} else {
bufcat(sstr, "F?F?0?1?", 8);
}
};
#undef cc
-static void dctransdetach(struct transfer *transfer, struct dcpeer *peer)
-{
- CBUNREG(transfer, trans_filterout, peer);
- peer->transfer = NULL;
- peer->close = 1;
-}
-
static void dctransgotdata(struct transfer *transfer, struct dcpeer *peer)
{
int ret;
if((peer->state == PEER_TRNS) || (peer->state == PEER_SYNC))
{
- if(sockqueuesize(peer->sk) < 65536)
+ if(sockqueueleft(peer->sk) > 0)
{
- if((buf = transfergetdata(transfer, &bufsize)) != NULL)
+ if((buf = sockgetinbuf(peer->trpipe, &bufsize)) != NULL)
{
if(peer->compress == CPRS_NONE)
{
}
if(peer->ptclose)
{
- freedcpeer(peer);
+ peer->close = 1;
} else {
if(peer->timeout == NULL)
peer->timeout = timercallback(ntime() + 180, (void (*)(int, void *))peertimeout, peer);
}
}
-static void dctransendofdata(struct transfer *transfer, struct dcpeer *peer)
+static void peerdetach(struct dcpeer *peer)
{
- peer->state = PEER_SYNC;
- dctransgotdata(transfer, peer);
+ CBUNREG(peer->transfer, trans_filterout, peer);
+ CBUNREG(peer->transfer, trans_destroy, peer);
+ peer->trpipe->pnext = NULL;
+ closesock(peer->trpipe);
+ quitsock(peer->trpipe);
+ peer->trpipe = NULL;
+ peer->transfer = NULL;
}
-static void dcwantdata(struct transfer *transfer, struct dcpeer *peer)
+static int trdestroycb(struct transfer *transfer, struct dcpeer *peer)
{
- if(transferdatasize(transfer) < 65536)
- peer->sk->ignread = 0;
+ peerdetach(peer);
+ peer->close = 1;
+ return(0);
}
static void transread(struct socket *sk, struct dcpeer *peer)
{
void *buf;
size_t bufsize;
- struct transfer *transfer;
- if((buf = sockgetinbuf(sk, &bufsize)) == NULL)
+ if(peer->transfer == NULL) {
+ freedcpeer(peer);
return;
- if(peer->transfer == NULL)
+ }
+ if(sockqueueleft(peer->trpipe) < 0)
+ return;
+ if((buf = sockgetinbuf(sk, &bufsize)) != NULL)
{
+ if(peer->transfer == NULL)
+ {
+ free(buf);
+ freedcpeer(peer);
+ return;
+ }
+ sockqueue(peer->trpipe, buf, bufsize);
free(buf);
- freedcpeer(peer);
- return;
}
- transferputdata(peer->transfer, buf, bufsize);
- free(buf);
if(peer->transfer->curpos >= peer->transfer->size)
{
- transfer = peer->transfer;
- transferdetach(transfer);
- transferendofdata(transfer);
+ peerdetach(peer);
+ peer->close = 1;
return;
}
- if(transferdatasize(peer->transfer) > 65535)
- sk->ignread = 1;
}
static void transerr(struct socket *sk, int err, struct dcpeer *peer)
freedcpeer(peer);
return;
}
- transferdetach(transfer);
- transferendofdata(transfer);
+ peerdetach(peer);
+ peer->close = 1;
}
static void transwrite(struct socket *sk, struct dcpeer *peer)
return;
}
dctransgotdata(peer->transfer, peer);
+ sockread(peer->trpipe);
+}
+
+static void trpiperead(struct socket *sk, struct dcpeer *peer)
+{
+ dctransgotdata(peer->transfer, peer);
+}
+
+static void trpipewrite(struct socket *sk, struct dcpeer *peer)
+{
+ transread(peer->sk, peer);
+}
+
+static void trpipeerr(struct socket *sk, int errno, struct dcpeer *peer)
+{
+ peer->state = PEER_SYNC;
+ dctransgotdata(peer->transfer, peer);
+ peerdetach(peer);
+ if(peer->state != PEER_CMD)
+ peer->close = 1;
+}
+
+static struct socket *mktrpipe(struct dcpeer *peer)
+{
+ struct socket *sk;
+
+ sk = netsockpipe();
+ sk->pnext = peer->sk;
+ sk->data = peer;
+ sk->readcb = (void (*)(struct socket *, void *))trpiperead;
+ sk->writecb = (void (*)(struct socket *, void *))trpipewrite;
+ sk->errcb = (void (*)(struct socket *, int, void *))trpipeerr;
+ return(sk);
}
static void udpread(struct socket *sk, void *data)
size_t buflen, hashlen;
char *nick, *filename, *hubname;
struct sockaddr_in hubaddr;
+ struct sockaddr *addrbuf;
off_t size;
int slots;
struct fnetnode *fn, *myfn;
{
for(fn = fnetnodes; fn != NULL; fn = fn->next)
{
- if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL))
+ if((fn->fnet == &dcnet) && ((hub = fn->data) != NULL) && !sockpeeraddr(hub->sk, &addrbuf, NULL))
{
- if((hub->sk != NULL) && addreq(hub->sk->remote, (struct sockaddr *)&hubaddr))
+ if((hub->sk != NULL) && addreq(addrbuf, (struct sockaddr *)&hubaddr))
{
myfn = fn;
+ free(addrbuf);
break;
}
+ free(addrbuf);
}
}
}
char *p, *p2;
hub = (struct dchub *)fn->data;
+ if(hub->queue.size > 1000)
+ return;
if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
return;
if(hub->inbufdata > 500000) /* Discard possible malicious data */
free(newbuf);
p = hub->inbuf;
hub->inbufdata += datalen;
- while((datalen > 0) && ((p2 = memchr(p, '|', datalen)) != NULL))
+ while((p - hub->inbuf < hub->inbufdata) && ((p2 = memchr(p, '|', hub->inbufdata - (p - hub->inbuf))) != NULL))
{
*(p2++) = 0;
for(cmd = hubcmds; cmd->handler != NULL; cmd++)
}
if((cmd->limit == 0) || (hub->queue.size < cmd->limit))
newqcmd(&hub->queue, p);
- datalen -= p2 - p;
p = p2;
}
memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf);
- if(hub->queue.size > 1000)
- sk->ignread = 1;
}
static void huberr(struct socket *sk, int err, struct fnetnode *fn)
new = smalloc(sizeof(*new));
memset(new, 0, sizeof(*new));
- new->transfer = NULL;
getsock(sk);
new->sk = sk;
if(confgetint("dc", "dcppemu"))
if(peer->prev != NULL)
peer->prev->next = peer->next;
if(peer->transfer != NULL)
- {
- if(peer->transfer->dir == TRNSD_UP)
- peer->transfer->close = 1;
- if(peer->transfer->dir == TRNSD_DOWN)
- resettransfer(peer->transfer);
- transferdetach(peer->transfer);
- }
+ peerdetach(peer);
if(peer->timeout != NULL)
canceltimer(peer->timeout);
if(peer->sk->data == peer)
struct qcommand *qcmd;
hub = (struct dchub *)fn->data;
- putsock(hub->sk);
+ quitsock(hub->sk);
while((qcmd = ulqcmd(&hub->queue)) != NULL)
freeqcmd(qcmd);
if(hub->supports != NULL)
struct dchub *hub;
hub = (struct dchub *)fn->data;
- hub->sk->close = 1;
+ closesock(hub->sk);
}
-static struct transferiface dctransfer =
-{
- .detach = (void (*)(struct transfer *, void *))dctransdetach,
- .gotdata = (void (*)(struct transfer *, void *))dctransgotdata,
- .endofdata = (void (*)(struct transfer *, void *))dctransendofdata,
- .wantdata = (void (*)(struct transfer *, void *))dcwantdata
-};
-
static struct fnet dcnet =
{
.name = L"dc",
size_t datalen, cnlen;
struct command *cmd;
+ if(peer->state == PEER_CMD) {
+ if((peer->queue.size > 50) || (peer->inbufdata > 65536))
+ return;
+ } else if(peer->state == PEER_TTHL) {
+ } else {
+ return;
+ }
if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
return;
sizebuf2(peer->inbuf, peer->inbufdata + datalen, 1);
{
peer->state = PEER_STOP;
break;
- } else {
- if(peer->queue.size > 50)
- sk->ignread = 1;
}
}
} else if(peer->state == PEER_TTHL) {
handletthl(peer);
}
- if(peer->inbufdata > 500000)
- sk->ignread = 1;
}
static void peererror(struct socket *sk, int err, struct dcpeer *peer)
if(err != 0)
{
putfnetnode(fn);
- putsock(sk);
return;
}
hub = fn->data;
sk->errcb = (void (*)(struct socket *, int, void *))peererror;
sk->data = peer;
socksettos(sk, confgetint("fnet", "fnptos"));
- putsock(sk);
peer->timeout = timercallback(ntime() + 180, (void (*)(int, void *))peertimeout, peer);
sendmynick(peer);
sendpeerlock(peer);
}
-static void peeraccept(struct socket *sk, struct socket *newsk, void *data)
+static void peeraccept(struct lport *lp, struct socket *newsk, void *data)
{
struct dcpeer *peer;
char *buf, *buf2, numbuf[32];
size_t bufsize, bufdata;
int fd, ibuf;
+ FILE *out;
bufdata = 0;
buf = smalloc(bufsize = 65536);
free(hmlistname);
hmlistname = NULL;
} else {
+ out = fdopen(fd, "w");
/*
* I do not want to implement a good Huffman encoder, and it's not
* like Huffman encoding actually yields any impressive results
* for DC file lists anyway, so I'll just output a bogus
* tree. Implement a good encoder if you want to.
*/
- write(fd, "HE3\r\0", 5);
- write(fd, &bufdata, 4);
+ fwrite("HE3\r\0", 1, 5, out);
+ fwrite(&bufdata, 4, 1, out); /* XXX: Endian unsafe */
ibuf = 256;
- write(fd, &ibuf, 2);
+ fwrite(&ibuf, 2, 1, out);
ibuf = 8;
for(i = 0; i < 256; i++)
{
- write(fd, &i, 1);
- write(fd, &ibuf, 1);
+ fwrite(&i, 1, 1, out);
+ fwrite(&ibuf, 1, 1, out);
}
for(i = 0; i < 256; i++)
- write(fd, &i, 1);
+ fwrite(&i, 1, 1, out);
for(buf2 = buf; bufdata > 0;)
{
- if((ret = write(fd, buf2, bufdata)) < 0)
+ if((ret = fwrite(buf2, 1, bufdata, out)) < 0)
{
flog(LOG_WARNING, "could not write file list: %s", strerror(errno));
break;
bufdata -= ret;
buf2 += ret;
}
- close(fd);
+ fclose(out);
}
free(buf);
}
quota--;
}
if(hub->queue.size < 1000)
- hub->sk->ignread = 0;
+ hubread(hub->sk, fn);
if(quota < 1)
break;
}
quota--;
}
if((peer->queue.size < 50) && (peer->inbufdata < 500000))
- peer->sk->ignread = 0;
+ peerread(peer->sk, peer);
if(quota < 1)
break;
}
static int updatetcpport(struct configvar *var, void *uudata)
{
struct sockaddr_in addr;
- struct socket *newsock;
+ struct lport *newsock;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
if((newsock = netcslisten(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), peeraccept, NULL)) == NULL)
flog(LOG_INFO, "could not listen to a remote address, going into passive mode");
if(tcpsock != NULL)
- putsock(tcpsock);
+ closelport(tcpsock);
tcpsock = newsock;
return(0);
}
if(udpsock != NULL)
putsock(udpsock);
if(tcpsock != NULL)
- putsock(tcpsock);
+ closelport(tcpsock);
addr.sin_family = AF_INET;
memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
addr.sin_port = htons(confgetint("dc", "udpport"));