char *name;
void (*handler)(struct socket *sk, void *data, char *cmd, char *args);
int stop;
+ int limit;
};
struct qcommand
char *string;
};
+struct qcmdqueue
+{
+ struct qcommand *f, *l;
+ int size;
+};
+
struct dchub
{
struct socket *sk;
char *inbuf;
size_t inbufdata, inbufsize;
- struct qcommand *queue;
+ struct qcmdqueue queue;
int extended, dcppemu;
char *charset;
char *nativename;
struct fnetnode *fn;
char *inbuf;
size_t inbufdata, inbufsize;
- size_t curread, totalsize;
+ off_t curread, totalsize;
int freeing;
struct timer *timeout;
- struct qcommand *queue;
+ struct qcmdqueue queue;
struct transfer *transfer;
int state;
int ptclose; /* Close after transfer is complete */
return(key);
}
-static char *pathnmdc2adc(char *path)
+static wchar_t *nmdc2path(char *nmdc, char *charset)
{
- char *ret;
- size_t retsize, retdata;
+ wchar_t *ret, *p;
- if(!strcmp(path, "files.xml") || !strcmp(path, "files.xml.bz2") || !strcmp(path, "MyList.DcLst"))
- return(sstrdup(path));
- ret = NULL;
- retsize = retdata = 0;
- addtobuf(ret, '/');
- for(; *path; path++)
- {
- if(*path == '\\')
- addtobuf(ret, '/');
- else
- addtobuf(ret, *path);
+ if((ret = icmbstowcs(nmdc, charset)) == NULL)
+ return(NULL);
+ for(p = ret; *p != L'\0'; p++) {
+ if(*p == L'\\')
+ *p = L'/';
}
- addtobuf(ret, 0);
return(ret);
}
+static char *path2nmdc(wchar_t *path, char *charset)
+{
+ char *ret, *p;
+
+ if((ret = icwcstombs(path, charset)) == NULL)
+ return(NULL);
+ for(p = ret; *p; p++) {
+ if(*p == '/')
+ *p = '\\';
+ }
+ return(ret);
+}
+
+static wchar_t *adc2path(char *adc)
+{
+ return(icmbstowcs(adc, "UTF-8"));
+}
+
+static char *path2adc(wchar_t *path)
+{
+ return(icwcstombs(path, "UTF-8"));
+}
+
static int isdchash(struct hash *hash)
{
if(wcscmp(hash->algo, L"TTH"))
return(ep);
}
-static struct qcommand *newqcmd(struct qcommand **queue, char *string)
+static struct qcommand *newqcmd(struct qcmdqueue *queue, char *string)
{
struct qcommand *new;
- while(*queue != NULL)
- queue = &(*queue)->next;
new = smalloc(sizeof(*new));
new->string = sstrdup(string);
- new->next = *queue;
- *queue = new;
+ new->next = NULL;
+ if(queue->l == NULL)
+ queue->f = new;
+ else
+ queue->l->next = new;
+ queue->l = new;
+ queue->size++;
return(new);
}
-static struct qcommand *ulqcmd(struct qcommand **queue)
+static struct qcommand *ulqcmd(struct qcmdqueue *queue)
{
struct qcommand *qcmd;
- if((qcmd = *queue) == NULL)
+ if((qcmd = queue->f) == NULL)
return(NULL);
- *queue = qcmd->next;
+ if((queue->f = qcmd->next) == NULL)
+ queue->l = NULL;
+ queue->size--;
return(qcmd);
}
free(buf);
}
-static void sendadcf(struct socket *sk, char *arg, ...)
+#if defined(__GNUC__)
+static void __attribute__ ((format (printf, 2, 3))) sendadcf(struct socket *sk, char *arg, ...)
+#else
+static void sendadcf(struct socket *sk, char *arg, ...)
+#endif
{
char *buf;
va_list args;
ret = sprintf2("TTH/%.39s", buf);
free(buf);
} else {
- if((buf = icwcstombs(peer->transfer->path, "UTF-8")) == NULL)
- return(NULL);
- ret = pathnmdc2adc(buf);
- free(buf);
+ ret = path2adc(peer->transfer->path);
}
return(ret);
}
flog(LOG_WARNING, "filter returned no position for \"resume\" on transfer %i", transfer->id);
freedcpeer(peer);
} else {
- transfer->curpos = wcstol(arg, NULL, 10);
+ transfer->curpos = wcstoll(arg, NULL, 10);
peer->hascurpos = 1;
requestfile(peer);
}
if(peer->transfer->size == -1)
{
/* Use DCCHARSET for $Get paths until further researched... */
- if((buf = icswcstombs(peer->transfer->path, DCCHARSET, NULL)) == NULL)
+ if((buf = path2nmdc(peer->transfer->path, DCCHARSET)) == NULL)
{
transferseterror(peer->transfer, TRNSE_NOTFOUND);
freedcpeer(peer);
* cmd_filelength when it detects that the sizes
* don't match. */
qstrf(peer->sk, "$Get %s$1|", buf);
+ free(buf);
return;
}
if((peer->transfer->hash == NULL) && !peer->notthl)
}
sendadc(peer->sk, buf);
free(buf);
- sendadcf(peer->sk, "%i", peer->transfer->curpos);
- sendadcf(peer->sk, "%i", peer->transfer->size - peer->transfer->curpos);
+ sendadcf(peer->sk, "%ji", (intmax_t)peer->transfer->curpos);
+ sendadcf(peer->sk, "%ji", (intmax_t)(peer->transfer->size - peer->transfer->curpos));
qstr(peer->sk, "|");
} else if(supports(peer, "xmlbzlist")) {
- if((buf = icswcstombs(peer->transfer->path, "UTF-8", NULL)) == NULL)
+ if((buf = path2nmdc(peer->transfer->path, "UTF-8")) == NULL)
{
transferseterror(peer->transfer, TRNSE_NOTFOUND);
freedcpeer(peer);
return;
}
- qstrf(peer->sk, "$UGetBlock %zi %zi %s|", peer->transfer->curpos, peer->transfer->size - peer->transfer->curpos, buf);
+ qstrf(peer->sk, "$UGetBlock %ji %ji %s|", (intmax_t)peer->transfer->curpos, (intmax_t)(peer->transfer->size - peer->transfer->curpos), buf);
+ free(buf);
} else {
/* Use DCCHARSET for $Get paths until further researched... */
- if((buf = icswcstombs(peer->transfer->path, DCCHARSET, NULL)) == NULL)
+ if((buf = path2nmdc(peer->transfer->path, DCCHARSET)) == NULL)
{
transferseterror(peer->transfer, TRNSE_NOTFOUND);
freedcpeer(peer);
return;
}
- qstrf(peer->sk, "$Get %s$%zi|", buf, peer->transfer->curpos + 1);
+ qstrf(peer->sk, "$Get %s$%ji|", buf, (intmax_t)peer->transfer->curpos + 1);
+ free(buf);
}
}
struct dchub *hub;
char *p;
wchar_t *buf;
- struct fnetpeer *peer, *npeer;
+ struct fnetpeer *peer;
hub = fn->data;
- for(peer = fn->peers; peer != NULL; peer = peer->next)
+ for(peer = btreeiter(fn->peers); peer != NULL; peer = btreeiter(NULL))
peer->flags.b.delete = 1;
while((p = strstr(args, "$$")) != NULL)
{
}
args = p + 2;
}
- for(peer = fn->peers; peer != NULL; peer = npeer)
- {
- npeer = peer->next;
- if(peer->flags.b.delete)
- fnetdelpeer(peer);
- }
+ fnetpeerdm(fn);
hubhandleaction(sk, fn, cmd, args);
}
struct fnetpeer *peer;
hub = fn->data;
- for(peer = fn->peers; peer != NULL; peer = peer->next)
+ for(peer = btreeiter(fn->peers); peer != NULL; peer = btreeiter(NULL))
peer->flags.b.op = 0;
while((p = strstr(args, "$$")) != NULL)
{
if(node->f.b.hastth)
{
buf2 = base32encode(node->hashtth, 24);
- qstrf(dsk, "%s%s\005%zi%sTTH:%.39s%s", prefix, buf, node->size, infix, buf2, postfix);
+ qstrf(dsk, "%s%s\005%ji%sTTH:%.39s%s", prefix, buf, (intmax_t)node->size, infix, buf2, postfix);
free(buf2);
} else {
- qstrf(dsk, "%s%s\005%zi%s%s%s", prefix, buf, node->size, infix, hub->nativename, postfix);
+ qstrf(dsk, "%s%s\005%ji%s%s%s", prefix, buf, (intmax_t)node->size, infix, hub->nativename, postfix);
}
free(buf);
}
struct dchub *hub;
char *p, *p2, *buf;
char *nick, *filename, *hubname;
- int size, slots;
+ off_t size;
+ int slots;
size_t buflen;
struct srchres *sr;
wchar_t *wnick, *wfile;
if((p2 = strchr(p, ' ')) == NULL)
return;
*p2 = 0;
- size = atoi(p);
+ size = strtoll(p, NULL, 10);
p = p2 + 1;
if((p2 = strchr(p, '/')) == NULL)
return;
if((wnick = icmbstowcs(nick, hub->charset)) == NULL)
return;
/* Use DCCHARSET in $Get paths until further researched... */
- if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL)
+ if((wfile = nmdc2path(filename, DCCHARSET)) == NULL)
{
free(wnick);
return;
static void cmd_filelength(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
{
- int size;
+ off_t size;
struct transfer *transfer;
if(peer->transfer == NULL)
freedcpeer(peer);
return;
}
- size = atoi(args);
+ size = strtoll(args, NULL, 10);
if(peer->transfer->size != size)
{
transfersetsize(peer->transfer, size);
static void cmd_get(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
{
- int offset;
+ off_t offset;
char *p, *buf;
wchar_t *buf2;
struct sharecache *node;
return;
}
*(p++) = 0;
- if((offset = (atoi(p) - 1)) < 0)
+ if((offset = (strtoll(p, NULL, 10) - 1)) < 0)
{
freedcpeer(peer);
return;
freedcpeer(peer);
return;
} else if(fd >= 0) {
- if((buf2 = icsmbstowcs(args, DCCHARSET, NULL)) != NULL)
+ if((buf2 = nmdc2path(args, DCCHARSET)) != NULL) {
transfersetpath(peer->transfer, buf2);
+ free(buf2);
+ }
peer->transfer->flags.b.minislot = 1;
}
if(fd < 0)
lesk = wrapsock(fd);
transferprepul(peer->transfer, sb.st_size, offset, -1, lesk);
putsock(lesk);
- qstrf(sk, "$FileLength %zi|", peer->transfer->size);
+ qstrf(sk, "$FileLength %ji|", (intmax_t)peer->transfer->size);
}
static void cmd_send(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
{
int fd;
char *p, *p2;
- int start, numbytes;
+ off_t start, numbytes;
char *charset, *buf;
wchar_t *buf2;
struct sharecache *node;
return;
}
*(p2++) = 0;
- start = atoi(p);
+ start = strtoll(p, NULL, 10);
p = p2;
if((p2 = strchr(p, ' ')) == NULL)
{
return;
}
*(p2++) = 0;
- numbytes = atoi(p);
+ numbytes = strtoll(p, NULL, 10);
p = p2;
if(!strcmp(cmd, "$UGetBlock") || !strcmp(cmd, "$UGetZBlock"))
charset = "UTF-8";
qstr(sk, "$Error Could not send file list|");
return;
} else if(fd >= 0) {
- if((buf2 = icsmbstowcs(args, charset, NULL)) != NULL)
+ if((buf2 = nmdc2path(args, charset)) != NULL) {
transfersetpath(peer->transfer, buf2);
+ free(buf2);
+ }
peer->transfer->flags.b.minislot = 1;
}
if(fd < 0)
lesk = wrapsock(fd);
transferprepul(peer->transfer, sb.st_size, start, start + numbytes, lesk);
putsock(lesk);
- qstrf(sk, "$Sending %i|", numbytes);
+ qstrf(sk, "$Sending %ji|", (intmax_t)numbytes);
startul(peer);
}
{
int i;
char **argv, *buf;
- int start, numbytes;
+ off_t start, numbytes;
struct sharecache *node;
struct stat sb;
struct socket *lesk;
freedcpeer(peer);
goto out;
}
- start = atoi(argv[2]);
- numbytes = atoi(argv[3]);
+ start = strtoll(argv[2], NULL, 10);
+ numbytes = strtoll(argv[3], NULL, 10);
node = NULL;
fd = -1;
if(((fd = openfilelist(argv[1])) < 0) && (errno != 0))
qstr(sk, "$Error Could not send file list|");
goto out;
} else if(fd >= 0) {
- if((wbuf = icsmbstowcs(argv[1], "UTF-8", NULL)) != NULL)
+ if((wbuf = adc2path(argv[1])) != NULL)
transfersetpath(peer->transfer, wbuf);
peer->transfer->flags.b.minislot = 1;
}
qstr(sk, "$ADCSND");
sendadc(sk, "file");
sendadc(sk, argv[1]);
- sendadcf(sk, "%i", start);
- sendadcf(sk, "%i", numbytes);
+ sendadcf(sk, "%ji", (intmax_t)start);
+ sendadcf(sk, "%ji", (intmax_t)numbytes);
if(peer->compress == CPRS_ZLIB)
sendadc(sk, "ZL1");
qstr(sk, "|");
static void cmd_adcsnd(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
{
char **argv;
- int start, numbytes;
+ off_t start, numbytes;
if(peer->transfer == NULL)
{
freedcpeer(peer);
goto out;
}
- start = atoi(argv[2]);
- numbytes = atoi(argv[3]);
+ start = strtoll(argv[2], NULL, 10);
+ numbytes = strtoll(argv[3], NULL, 10);
if(!strcmp(argv[0], "tthl"))
{
if((start != 0) || (numbytes % 24 != 0))
static void cmd_sending(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
{
- int numbytes;
+ off_t numbytes;
if(peer->transfer == NULL)
{
freedcpeer(peer);
return;
}
- numbytes = atoi(args);
+ numbytes = strtoll(args, NULL, 10);
if(peer->transfer->size - peer->transfer->curpos != numbytes)
{
transfersetsize(peer->transfer, peer->transfer->curpos + numbytes);
{"$OpList", cc(cmd_oplist)},
{"$MyINFO", cc(cmd_myinfo)},
{"$ForceMove", cc(cmd_forcemove)},
- {"$Search", cc(cmd_search)},
- {"$MultiSearch", cc(cmd_search)},
- {"$ConnectToMe", cc(cmd_connecttome)},
- {"$RevConnectToMe", cc(cmd_revconnecttome)},
+ {"$Search", cc(cmd_search), .limit = 100},
+ {"$MultiSearch", cc(cmd_search), .limit = 50},
+ {"$ConnectToMe", cc(cmd_connecttome), .limit = 200},
+ {"$RevConnectToMe", cc(cmd_revconnecttome), .limit = 500},
{"$GetNetInfo", cc(cmd_getnetinfo)},
{"$To:", cc(cmd_to)},
{"$SR", cc(cmd_sr)},
{"$GetZBlock", cc(cmd_getblock)},
{"$UGetZBlock", cc(cmd_getblock)},
{"$ADCGET", cc(cmd_adcget)},
- {"$ADCSND", cc(cmd_adcsnd), 1},
- {"$Sending", cc(cmd_sending), 1},
+ {"$ADCSND", cc(cmd_adcsnd), .stop = 1},
+ {"$Sending", cc(cmd_sending), .stop = 1},
{NULL, NULL}
};
#undef cc
size_t buflen, hashlen;
char *nick, *filename, *hubname;
struct sockaddr_in hubaddr;
- int size, slots;
+ off_t size;
+ int slots;
struct fnetnode *fn, *myfn;
struct dchub *hub;
struct srchres *sr;
return;
}
*p2 = 0;
- size = atoi(p);
+ size = strtoll(p, NULL, 10);
p = p2 + 1;
if((p2 = strchr(p, '/')) == NULL)
{
*p2 = 0;
hubaddr.sin_port = htons(atoi(p));
/* Use DCCHARSET in $Get paths until further researched... */
- if((wfile = icmbstowcs(filename, DCCHARSET)) == NULL)
+ if((wfile = nmdc2path(filename, DCCHARSET)) == NULL)
{
free(buf);
return;
static void hubread(struct socket *sk, struct fnetnode *fn)
{
struct dchub *hub;
+ struct command *cmd;
char *newbuf;
- size_t datalen;
+ size_t datalen, cnlen;
char *p;
hub = (struct dchub *)fn->data;
while((datalen > 0) && ((p = memchr(p, '|', datalen)) != NULL))
{
*(p++) = 0;
- newqcmd(&hub->queue, hub->inbuf);
+ for(cmd = hubcmds; cmd->handler != NULL; cmd++)
+ {
+ cnlen = strlen(cmd->name);
+ if(!strncmp(hub->inbuf, cmd->name, cnlen) && ((hub->inbuf[cnlen] == ' ') || (hub->inbuf[cnlen] == 0)))
+ break;
+ }
+ if((cmd->limit == 0) || (hub->queue.size < cmd->limit))
+ newqcmd(&hub->queue, hub->inbuf);
memmove(hub->inbuf, p, hub->inbufdata -= p - hub->inbuf);
datalen = hub->inbufdata;
p = hub->inbuf;
}
+ if(hub->queue.size > 1000)
+ sk->ignread = 1;
}
static void huberr(struct socket *sk, int err, struct fnetnode *fn)
static void peerread(struct socket *sk, struct dcpeer *peer)
{
char *newbuf, *p;
- size_t datalen;
+ size_t datalen, cnlen;
struct command *cmd;
if((newbuf = sockgetinbuf(sk, &datalen)) == NULL)
while((peer->inbufdata > 0) && (p = memchr(peer->inbuf, '|', peer->inbufdata)) != NULL)
{
*(p++) = 0;
- newqcmd(&peer->queue, peer->inbuf);
for(cmd = peercmds; cmd->handler != NULL; cmd++)
{
- if(!memcmp(peer->inbuf, cmd->name, strlen(cmd->name)) && ((peer->inbuf[strlen(cmd->name)] == ' ') || (peer->inbuf[strlen(cmd->name)] == '|')))
+ cnlen = strlen(cmd->name);
+ if(!strncmp(peer->inbuf, cmd->name, cnlen) && ((peer->inbuf[cnlen] == ' ') || (peer->inbuf[cnlen] == 0)))
break;
}
+ if((cmd->limit == 0) || (peer->queue.size < cmd->limit))
+ newqcmd(&peer->queue, peer->inbuf);
memmove(peer->inbuf, p, peer->inbufdata -= p - peer->inbuf);
if(cmd->stop)
{
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(node->f.b.type == FILE_REG)
{
addtobuf(buf, '|');
- sprintf(numbuf, "%zi", node->size);
+ sprintf(numbuf, "%ji", (intmax_t)node->size);
bufcat(buf, numbuf, strlen(numbuf));
}
addtobuf(buf, 13);
lev++;
continue;
} else {
- fprintf(fs, "<File Name=\"%s\" Size=\"%zi\"", namebuf, node->size);
+ fprintf(fs, "<File Name=\"%s\" Size=\"%ji\"", namebuf, (intmax_t)node->size);
if(node->f.b.hastth)
{
hashbuf = base32encode(node->hashtth, 24);
struct dchub *hub;
struct dcpeer *peer, *nextpeer;
struct qcommand *qcmd;
- int ret;
+ int ret, quota;
ret = 0;
+ quota = 20;
for(fn = fnetnodes; fn != NULL; fn = nextfn)
{
nextfn = fn->next;
if(fn->data == NULL)
continue;
hub = (struct dchub *)fn->data;
- if((qcmd = ulqcmd(&hub->queue)) != NULL)
+ while((quota > 0) && ((qcmd = ulqcmd(&hub->queue)) != NULL))
{
if(*qcmd->string == '$')
{
}
freeqcmd(qcmd);
ret = 1;
- break;
+ quota--;
}
+ if(hub->queue.size < 1000)
+ hub->sk->ignread = 0;
+ if(quota < 1)
+ break;
}
+ quota = 20;
for(peer = peers; peer != NULL; peer = nextpeer)
{
nextpeer = peer->next;
- if((qcmd = ulqcmd(&peer->queue)) != NULL)
+ while((quota > 0) && ((qcmd = ulqcmd(&peer->queue)) != NULL))
{
if(peer->timeout != NULL)
canceltimer(peer->timeout);
dispatchcommand(qcmd, peercmds, peer->sk, peer);
freeqcmd(qcmd);
ret = 1;
- break;
+ quota--;
}
+ if((peer->queue.size < 50) && (peer->inbufdata < 500000))
+ peer->sk->ignread = 0;
+ if(quota < 1)
+ break;
}
return(ret);
}