diff options
author | rodrigc <rodrigc@FreeBSD.org> | 2011-06-15 22:04:14 +0000 |
---|---|---|
committer | rodrigc <rodrigc@FreeBSD.org> | 2011-06-15 22:04:14 +0000 |
commit | d05f25ce84fa1850102baa6610eb2566f980b41c (patch) | |
tree | d41262e650e3b747d1002a20b5e51982e6dd84d8 /lib/libstand/tftp.c | |
parent | 5d1632301aa97755dbc6e9325ffa2722ea8c7ea7 (diff) | |
download | FreeBSD-src-d05f25ce84fa1850102baa6610eb2566f980b41c.zip FreeBSD-src-d05f25ce84fa1850102baa6610eb2566f980b41c.tar.gz |
Added sendrecv_tftp function instead of sendrecv for use by tftp.
In sendrecv_tftp:
* Upon receving an unexpected block of data or error, resend the ACK
immediately instead of waiting till the expiry of receive data timeout
to resend the ACK.
* change the receive timeout value between retries to be 2xMINTMO.
Obtained from: Juniper Networks
Fixed by: Santhanakrishnan Balraj <sbalraj at juniper dot net>
Diffstat (limited to 'lib/libstand/tftp.c')
-rw-r--r-- | lib/libstand/tftp.c | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/lib/libstand/tftp.c b/lib/libstand/tftp.c index 29590fc..5cb8762 100644 --- a/lib/libstand/tftp.c +++ b/lib/libstand/tftp.c @@ -66,6 +66,7 @@ static int tftp_read(struct open_file *f, void *buf, size_t size, size_t *resid) static int tftp_write(struct open_file *f, void *buf, size_t size, size_t *resid); static off_t tftp_seek(struct open_file *f, off_t offset, int where); static int tftp_stat(struct open_file *f, struct stat *sb); +static ssize_t sendrecv_tftp(d, sproc, sbuf, ssize, rproc, rbuf, rsize); struct fs_ops tftp_fsops = { "tftp", @@ -191,7 +192,7 @@ tftp_makereq(struct tftp_handle *h) h->iodesc->destport = htons(IPPORT_TFTP); h->iodesc->xid = 1; /* expected block */ - res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, + res = sendrecv_tftp(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, recvtftp, t, sizeof(*t) + RSPACE); if (res == -1) @@ -226,7 +227,7 @@ tftp_getnextblock(struct tftp_handle *h) h->iodesc->xid = h->currblock + 1; /* expected block */ - res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, + res = sendrecv_tftp(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t, recvtftp, t, sizeof(*t) + RSPACE); if (res == -1) /* 0 is OK! */ @@ -404,3 +405,55 @@ tftp_seek(struct open_file *f, off_t offset, int where) } return (tftpfile->off); } + +static ssize_t +sendrecv_tftp(d, sproc, sbuf, ssize, rproc, rbuf, rsize) + struct iodesc *d; + ssize_t (*sproc)(struct iodesc *, void *, size_t); + void *sbuf; + size_t ssize; + ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t); + void *rbuf; + size_t rsize; +{ + ssize_t cc; + time_t t, t1, tleft; + +#ifdef TFTP_DEBUG + if (debug) + printf("sendrecv: called\n"); +#endif + + tleft = MINTMO; + t = t1 = getsecs(); + for (;;) { + if ((getsecs() - t) > MAXTMO) { + errno = ETIMEDOUT; + return -1; + } + + cc = (*sproc)(d, sbuf, ssize); + if (cc != -1 && cc < ssize) + panic("sendrecv: short write! (%zd < %zu)", + cc, ssize); + + if (cc == -1) { + /* Error on transmit; wait before retrying */ + while ((getsecs() - t1) < tleft); + continue; + } + + /* Try to get a packet and process it. */ + cc = (*rproc)(d, rbuf, rsize, tleft); + /* Return on data, EOF or real error. */ + if (cc != -1 || errno != 0) + return (cc); + + /* Timed out or didn't get the packet we're waiting for */ + tleft += MINTMO; + if (tleft > (2 * MINTMO)) { + tleft = (2 * MINTMO); + } + t1 = getsecs(); + } +} |