summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordlg <dlg@openbsd.org>2012-07-10 07:25:37 +0000
committerdlg <dlg@openbsd.org>2012-07-10 07:25:37 +0000
commit6ac42c1a8db079920fd713f3ada641c5d3084471 (patch)
treedfa486981d90acee3f9e0123003cf8cec2b9f5af
parentlibexec/tftpd handled the case where we'd get an ack for the previous (diff)
downloadwireguard-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.c66
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