diff options
author | 2012-07-10 07:25:37 +0000 | |
---|---|---|
committer | 2012-07-10 07:25:37 +0000 | |
commit | 6ac42c1a8db079920fd713f3ada641c5d3084471 (patch) | |
tree | dfa486981d90acee3f9e0123003cf8cec2b9f5af | |
parent | libexec/tftpd handled the case where we'd get an ack for the previous (diff) | |
download | wireguard-openbsd-6ac42c1a8db079920fd713f3ada641c5d3084471.tar.xz wireguard-openbsd-6ac42c1a8db079920fd713f3ada641c5d3084471.zip |
fix the last outstanding functionality difference i could find between
libexec and usr.sbin tftpd.
libexec waitied around after finishing a wrq in case our ack for the last
write from a client got lost. this does the same dance, or an arguably
better version of it compared to libexec tftpd.
-rw-r--r-- | usr.sbin/tftpd/tftpd.c | 66 |
1 files changed, 64 insertions, 2 deletions
diff --git a/usr.sbin/tftpd/tftpd.c b/usr.sbin/tftpd/tftpd.c index 70a82bba83e..c4ecf2eaaf8 100644 --- a/usr.sbin/tftpd/tftpd.c +++ b/usr.sbin/tftpd/tftpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tftpd.c,v 1.6 2012/07/10 07:21:34 dlg Exp $ */ +/* $OpenBSD: tftpd.c,v 1.7 2012/07/10 07:25:37 dlg Exp $ */ /* * Copyright (c) 2012 David Gwynne <dlg@uq.edu.au> @@ -163,6 +163,7 @@ void tftpd_events(void); void tftpd_recv(int, short, void *); int retry(struct tftp_client *); int tftp_flush(struct tftp_client *); +void tftp_end(struct tftp_client *); void tftp(struct tftp_client *, struct tftphdr *, size_t); void tftp_open(struct tftp_client *, const char *); @@ -181,6 +182,7 @@ int tftp_wrq_ack_packet(struct tftp_client *); void tftp_rrq_ack(int, short, void *); void tftp_wrq_ack(struct tftp_client *client); void tftp_wrq(int, short, void *); +void tftp_wrq_end(int, short, void *); int parse_options(struct tftp_client *, char *, size_t, struct opt_client *); @@ -1272,7 +1274,10 @@ tftp_wrq(int fd, short events, void *arg) if (n < client->packet_size) { tftp_wrq_ack_packet(client); - goto done; + event_set(&client->sev, client->sock, EV_READ, + tftp_wrq_end, client); + event_add(&client->sev, &client->tv); + return; } tftp_wrq_ack(client); @@ -1285,6 +1290,63 @@ done: client_free(client); } +void +tftp_wrq_end(int fd, short events, void *arg) +{ + char wbuf[SEGSIZE_MAX + 4]; + struct tftp_client *client = arg; + struct tftphdr *dp; + ssize_t n; + + if (events & EV_TIMEOUT) { + /* this was the last packet, we can clean up */ + goto done; + } + + n = recv(fd, wbuf, client->packet_size, 0); + if (n == -1) { + switch (errno) { + case EINTR: + case EAGAIN: + goto retry; + + default: + lwarn("tftp_wrq_end recv"); + goto done; + } + } + + if (n < 4) + goto done; + + dp = (struct tftphdr *)wbuf; + dp->th_opcode = ntohs((u_short)dp->th_opcode); + dp->th_block = ntohs((u_short)dp->th_block); + + switch (dp->th_opcode) { + case ERROR: + goto done; + case DATA: + break; + default: + goto retry; + } + + if (dp->th_block != client->block) + goto done; + +retry: + if (retry(client) == -1) { + lwarn("%s", getip(&client->ss)); + goto done; + } + return; +done: + client_free(client); + return; +} + + /* * Send a nak packet (error message). * Error code passed in is one of the |