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)
{
state = 3;
else if(*args != ' ')
state = 1;
+ else
+ args++;
break;
case 1:
if((*args == ' ') || (*args == 0))
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);
int minsize, maxsize;
int dotth;
size_t buflen;
- int termnum, satisfied, skipcheck;
+ int termnum, satisfied, matches, skipcheck, proper;
int level, tersat[32];
wchar_t *terms[32], *lname;
char hashtth[24];
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;
termnum = 0;
p2 = p;
done = 0;
+ proper = 0;
while(!done)
{
if((*p2 == 0) || (*p2 == '$'))
} else {
if((terms[termnum] = icmbstowcs(p, hub->charset)) != NULL) {
wcslower(terms[termnum]);
+ if(wcslen(terms[termnum]) > 1)
+ proper = 1;
termnum++;
}
}
}
p2++;
}
+ if(!proper)
+ goto out;
node = shareroot->child;
level = 0;
for(i = 0; i < termnum; i++)
tersat[i] = -1;
satisfied = 0;
+ matches = 0;
while(1)
{
skipcheck = 0;
qstrf(dsk, "%s%s\005%ji%s%s%s", prefix, buf, (intmax_t)node->size, infix, hub->nativename, postfix);
}
free(buf);
+ if(++matches >= 20)
+ break;
}
}
if((!skipcheck && (satisfied == termnum)) || (node->child == NULL))
{
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;
if(peer->direction == TRNSD_DOWN)
requestfile(peer);
} else {
- if(peer->wcsname == NULL)
+ if((peer->wcsname == NULL) || (peer->transfer != NULL))
{
peer->close = 1;
return;
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)
{
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 */
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);
- }
+ 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;
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"));