aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtests/ftpserver.pl53
-rw-r--r--tests/server/sockfilt.c119
2 files changed, 146 insertions, 26 deletions
diff --git a/tests/ftpserver.pl b/tests/ftpserver.pl
index dd8de2ec4..d0be36f15 100755
--- a/tests/ftpserver.pl
+++ b/tests/ftpserver.pl
@@ -670,6 +670,51 @@ sub protocolsetup {
}
}
+# Perform the disconnecgt handshake with sockfilt on the secondary connection
+# (the only connection we actively disconnect).
+# This involves waiting for the disconnect acknowledgmeent after the DISC
+# command, while throwing away anything else that might come in before
+# that.
+sub disc_handshake {
+ print DWRITE "DISC\n";
+ my $line;
+ my $nr;
+ while (5 == ($nr = sysread DREAD, $line, 5)) {
+ if($line eq "DATA\n") {
+ # Must read the data bytes to stay in sync
+ my $i;
+ sysread DREAD, $i, 5;
+
+ my $size = 0;
+ if($i =~ /^([0-9a-fA-F]{4})\n/) {
+ $size = hex($1);
+ }
+
+ read_datasockf(\$line, $size);
+
+ logmsg "> Throwing away $size bytes on closed connection\n";
+ }
+ elsif($line eq "DISC\n") {
+ logmsg "Fancy that; client wants to DISC, too\n";
+ printf DWRITE "ACKD\n";
+ }
+ elsif($line eq "ACKD\n") {
+ # Got the ack we were waiting for
+ last;
+ }
+ else {
+ logmsg "Ignoring: $line";
+ # sockfilt should not be sending us any other commands
+ }
+ }
+ if(!defined($nr)) {
+ logmsg "Error: pipe read error ($!) while waiting for ACKD";
+ }
+ elsif($nr <= 0) {
+ logmsg "Error: pipe EOF while waiting for ACKD";
+ }
+}
+
sub close_dataconn {
my ($closed)=@_; # non-zero if already disconnected
@@ -680,9 +725,7 @@ sub close_dataconn {
if(!$closed) {
if($datapid > 0) {
logmsg "Server disconnects $datasockf_mode DATA connection\n";
- print DWRITE "DISC\n";
- my $i;
- sysread DREAD, $i, 5;
+ disc_handshake();
logmsg "Server disconnected $datasockf_mode DATA connection\n";
}
else {
@@ -940,6 +983,7 @@ sub DATA_smtp {
elsif($line eq "DISC\n") {
# disconnect!
$disc=1;
+ printf SFWRITE "ACKD\n";
last;
}
else {
@@ -1286,6 +1330,7 @@ sub APPEND_imap {
}
elsif($line eq "DISC\n") {
logmsg "Unexpected disconnect!\n";
+ printf SFWRITE "ACKD\n";
last;
}
else {
@@ -2405,6 +2450,7 @@ sub STOR_ftp {
elsif($line eq "DISC\n") {
# disconnect!
$disc=1;
+ printf DWRITE "ACKD\n";
last;
}
else {
@@ -3156,6 +3202,7 @@ while(1) {
logmsg "MAIN sockfilt said $i";
if($i =~ /^DISC/) {
# disconnect
+ printf SFWRITE "ACKD\n";
last;
}
next;
diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c
index 473b651f7..7e342e330 100644
--- a/tests/server/sockfilt.c
+++ b/tests/server/sockfilt.c
@@ -130,6 +130,10 @@
#define DEFAULT_LOGFILE "log/sockfilt.log"
#endif
+/* buffer is this excessively large only to be able to support things like
+ test 1003 which tests exceedingly large server response lines */
+#define BUFFER_SIZE 17010
+
const char *serverlogfile = DEFAULT_LOGFILE;
static bool verbose = FALSE;
@@ -386,6 +390,36 @@ static void lograw(unsigned char *buffer, ssize_t len)
logmsg("'%s'", data);
}
+/*
+ * handle the DATA command
+ * maxlen is the available space in buffer (input)
+ * *buffer_len is the amount of data in the buffer (output)
+ */
+static bool read_data_block(unsigned char *buffer, ssize_t maxlen,
+ ssize_t *buffer_len)
+{
+ if(!read_stdin(buffer, 5))
+ return FALSE;
+
+ buffer[5] = '\0';
+
+ *buffer_len = (ssize_t)strtol((char *)buffer, NULL, 16);
+ if(*buffer_len > maxlen) {
+ logmsg("ERROR: Buffer size (%zd bytes) too small for data size "
+ "(%zd bytes)", maxlen, *buffer_len);
+ return FALSE;
+ }
+ logmsg("> %zd bytes data, server => client", *buffer_len);
+
+ if(!read_stdin(buffer, *buffer_len))
+ return FALSE;
+
+ lograw(buffer, *buffer_len);
+
+ return TRUE;
+}
+
+
#ifdef USE_WINSOCK
/*
* WinSock select() does not support standard file descriptors,
@@ -857,6 +891,63 @@ static int select_ws(int nfds, fd_set *readfds, fd_set *writefds,
#define select(a,b,c,d,e) select_ws(a,b,c,d,e)
#endif /* USE_WINSOCK */
+
+/* Perform the disconnect handshake with sockfilt
+ * This involves waiting for the disconnect acknowledgmeent after the DISC
+ * command, while throwing away anything else that might come in before
+ * that.
+ */
+static bool disc_handshake(void)
+{
+ if(!write_stdout("DISC\n", 5))
+ return FALSE;
+
+ do {
+ unsigned char buffer[BUFFER_SIZE];
+ ssize_t buffer_len;
+ if(!read_stdin(buffer, 5))
+ return FALSE;
+ logmsg("Received %c%c%c%c (on stdin)",
+ buffer[0], buffer[1], buffer[2], buffer[3]);
+
+ if(!memcmp("ACKD", buffer, 4)) {
+ /* got the ack we were waiting for */
+ break;
+ }
+ else if(!memcmp("DISC", buffer, 4)) {
+ logmsg("Crikey! Client also wants to disconnect");
+ if(!write_stdout("ACKD\n", 5))
+ return FALSE;
+ }
+ else if(!memcmp("DATA", buffer, 4)) {
+ /* We must read more data to stay in sync */
+ if(!read_data_block(buffer, sizeof(buffer), &buffer_len))
+ return FALSE;
+
+ logmsg("Throwing again %zd data bytes", buffer_len);
+
+ }
+ else if(!memcmp("QUIT", buffer, 4)) {
+ /* just die */
+ logmsg("quits");
+ return FALSE;
+ }
+ else {
+ logmsg("Error: unexpected message; aborting");
+ /*
+ * The only other messages that could occur here are PING and PORT,
+ * and both of them occur at the start of a test when nothing should be
+ * trying to DISC. Therefore, we should not ever get here, but if we
+ * do, it's probably due to some kind of unclean shutdown situation so
+ * us shutting down is what we probably ought to be doing, anyway.
+ */
+ return FALSE;
+ }
+
+ } while(TRUE);
+ return TRUE;
+}
+
/*
sockfdp is a pointer to an established stream or CURL_SOCKET_BAD
@@ -876,9 +967,7 @@ static bool juggle(curl_socket_t *sockfdp,
ssize_t rc;
int error = 0;
- /* 'buffer' is this excessively large only to be able to support things like
- test 1003 which tests exceedingly large server response lines */
- unsigned char buffer[17010];
+ unsigned char buffer[BUFFER_SIZE];
char data[16];
if(got_exit_signal) {
@@ -1025,28 +1114,12 @@ static bool juggle(curl_socket_t *sockfdp,
}
else if(!memcmp("DATA", buffer, 4)) {
/* data IN => data OUT */
-
- if(!read_stdin(buffer, 5))
- return FALSE;
-
- buffer[5] = '\0';
-
- buffer_len = (ssize_t)strtol((char *)buffer, NULL, 16);
- if(buffer_len > (ssize_t)sizeof(buffer)) {
- logmsg("ERROR: Buffer size (%zu bytes) too small for data size "
- "(%zd bytes)", sizeof(buffer), buffer_len);
- return FALSE;
- }
- logmsg("> %zd bytes data, server => client", buffer_len);
-
- if(!read_stdin(buffer, buffer_len))
+ if(!read_data_block(buffer, sizeof(buffer), &buffer_len))
return FALSE;
- lograw(buffer, buffer_len);
-
if(*mode == PASSIVE_LISTEN) {
logmsg("*** We are disconnected!");
- if(!write_stdout("DISC\n", 5))
+ if(!disc_handshake())
return FALSE;
}
else {
@@ -1060,7 +1133,7 @@ static bool juggle(curl_socket_t *sockfdp,
}
else if(!memcmp("DISC", buffer, 4)) {
/* disconnect! */
- if(!write_stdout("DISC\n", 5))
+ if(!write_stdout("ACKD\n", 5))
return FALSE;
if(sockfd != CURL_SOCKET_BAD) {
logmsg("====> Client forcibly disconnected");
@@ -1115,7 +1188,7 @@ static bool juggle(curl_socket_t *sockfdp,
if(nread_socket <= 0) {
logmsg("====> Client disconnect");
- if(!write_stdout("DISC\n", 5))
+ if(!disc_handshake())
return FALSE;
sclose(sockfd);
*sockfdp = CURL_SOCKET_BAD;