tftp: prevent it from hanging if ack packets get lost
send ACK reply for duplicate data packets in case our ack response got lost. make sure packets are in sequence and ignore out of oder packets (except the ones we'v already acked).
This commit is contained in:
parent
9d182f906d
commit
9a06f93b71
3 changed files with 38 additions and 32 deletions
|
@ -249,16 +249,21 @@ read(void *f, void *data, int len)
|
|||
switch(nhgets(t->pkt)){
|
||||
case Tftp_DATA:
|
||||
seq = nhgets(t->pkt+2);
|
||||
if(seq <= t->seq){
|
||||
putc('@');
|
||||
if(seq > t->seq){
|
||||
putc('?');
|
||||
continue;
|
||||
}
|
||||
hnputs(t->pkt, Tftp_ACK);
|
||||
while(udpwrite(t->dip, t->gip, t->sport, t->dport, 4, t->pkt))
|
||||
putc('!');
|
||||
t->seq = seq;
|
||||
if(seq < t->seq){
|
||||
putc('@');
|
||||
continue;
|
||||
}
|
||||
t->seq = seq+1;
|
||||
n -= 4;
|
||||
t->rp = t->pkt + 4;
|
||||
t->ep = t->pkt + n;
|
||||
t->ep = t->rp + n;
|
||||
t->eof = n < Segsize;
|
||||
break;
|
||||
case Tftp_ERROR:
|
||||
|
@ -300,7 +305,7 @@ tftpopen(Tftp *t, char *path, IP4 sip, IP4 dip, IP4 gip)
|
|||
t->sport = xport++;
|
||||
t->dport = 0;
|
||||
t->rp = t->ep = 0;
|
||||
t->seq = -1;
|
||||
t->seq = 1;
|
||||
t->eof = 0;
|
||||
t->nul = 0;
|
||||
if(r = udpopen(t->sip))
|
||||
|
|
|
@ -340,9 +340,6 @@ options(int fd, char *buf, int bufsz, char *file, ushort oper, char *p, int dlen
|
|||
if (nopts == 0)
|
||||
return 0; /* no options actually seen */
|
||||
|
||||
if (bp + 3 >= ep)
|
||||
return -1;
|
||||
|
||||
if (write(fd, buf, bp - buf) < bp - buf) {
|
||||
syslog(dbg, flog, "tftpd network write error on oack to %s: %r",
|
||||
raddr);
|
||||
|
|
|
@ -147,7 +147,7 @@ filereq(uchar *buf, char *path)
|
|||
static void
|
||||
download(void *aux)
|
||||
{
|
||||
int fd, cfd, last, block, n, ndata;
|
||||
int fd, cfd, last, block, seq, n, ndata;
|
||||
char *err, adir[40];
|
||||
uchar *data;
|
||||
Channel *c;
|
||||
|
@ -197,6 +197,7 @@ download(void *aux)
|
|||
|
||||
notify(catch);
|
||||
|
||||
seq = 1;
|
||||
last = 0;
|
||||
while(!last){
|
||||
alarm(5000);
|
||||
|
@ -218,12 +219,24 @@ download(void *aux)
|
|||
if(n < 4)
|
||||
continue;
|
||||
block = nhgets(msg.buf+2);
|
||||
if((n -= 4) > 0){
|
||||
if(block > seq)
|
||||
continue;
|
||||
hnputs(msg.buf, Tftp_ACK);
|
||||
if(write(fd, &msg, sizeof(Udphdr) + 4) < 0){
|
||||
err = "send acknowledge: %r";
|
||||
goto out;
|
||||
}
|
||||
if(block < seq)
|
||||
continue;
|
||||
seq = block+1;
|
||||
n -= 4;
|
||||
if(n < Segsize)
|
||||
last = 1;
|
||||
data = erealloc9p(data, ndata + n);
|
||||
memcpy(data + ndata, msg.buf+4, n);
|
||||
ndata += n;
|
||||
|
||||
rloop: /* hanlde read request while downloading */
|
||||
rloop: /* hanlde read request while downloading */
|
||||
if((r != nil) && (r->ifcall.type == Tread) && (r->ifcall.offset < ndata)){
|
||||
readbuf(r, data, ndata);
|
||||
respond(r, nil);
|
||||
|
@ -237,15 +250,6 @@ rloop: /* hanlde read request while downloading */
|
|||
}
|
||||
goto rloop;
|
||||
}
|
||||
}
|
||||
if(n < Segsize)
|
||||
last = 1;
|
||||
hnputs(msg.buf, Tftp_ACK);
|
||||
hnputs(msg.buf+2, block);
|
||||
if(write(fd, &msg, sizeof(Udphdr) + 4) < 0){
|
||||
err = "send acknowledge: %r";
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue