Gopher using Curl_write; test suite (4 tests)
authorCameron Kaiser <ckaiser@floodgap.com>
Mon, 23 Aug 2010 21:30:59 +0000 (14:30 -0700)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 25 Aug 2010 12:21:25 +0000 (14:21 +0200)
lib/gopher.c
tests/data/Makefile.am
tests/data/test1200 [new file with mode: 0644]
tests/data/test1201 [new file with mode: 0644]
tests/data/test1202 [new file with mode: 0644]
tests/data/test1203 [new file with mode: 0644]
tests/ftp.pm
tests/ftpserver.pl
tests/runtests.pl
tests/serverhelp.pm

index d1ca440..2fab6da 100644 (file)
@@ -121,8 +121,8 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
 
   curl_off_t *bytecount = &data->req.bytecount;
   char *path = data->state.path;
-
   char *sel;
+  ssize_t amount, k;
 
   *done = TRUE; /* unconditionally */
 
@@ -149,12 +149,29 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
       return CURLE_OUT_OF_MEMORY;
   }
 
-  result = Curl_sendf(sockfd, conn, "%s\r\n", sel);
-
-  if(result) {
+  /* We use Curl_write instead of Curl_sendf to make sure the entire buffer
+     is sent, which could be sizeable with long selectors. */
+  k = strlen(sel);
+  for(;;) {
+    result = Curl_write(conn, sockfd, sel, k, &amount);
+    if (CURLE_OK == result) { /* Which may not have written it all! */
+      k -= amount;
+      sel += amount;
+      if (k < 1)
+        break; /* but it did write it all */
+    } else {
+      failf(data, "Failed sending Gopher request");
+      return result;
+    }
+  }
+  /* We can use Curl_sendf to send the terminal \r\n relatively safely and
+     save allocing another string/doing another _write loop. */
+  result = Curl_sendf(sockfd, conn, "\r\n");
+  if (result != CURLE_OK) {
     failf(data, "Failed sending Gopher request");
     return result;
   }
+
   Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
                       -1, NULL); /* no upload */
   return CURLE_OK;
index a31b356..89df9d0 100644 (file)
@@ -19,55 +19,56 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46         \
  test505 test74 test75 test76 test77 test78 test147 test148 test506 test79 \
  test80 test81 test82 test83 test84 test85 test86 test87 test507 test149   \
  test88 test89 test90 test508 test91 test92 test203 test93 test94 test95   \
- test510 test97 test98 test99 test150 test151 test152 test153     \
- test154 test155 test156 test157 test158 test159 test511 test160 test161   \
- test162 test163 test164 test512 test165 test166 test167 test168 test169   \
- test170 test171 test172 test204 test205 test173 test174 test175 test176   \
- test177 test513 test514 test178 test179 test180 test181 test182 test183   \
- test184 test185 test186 test187 test188 test189 test191 test192 test193   \
- test194 test195 test196 test197 test198 test515 test516 test517 test518   \
- test210 test211 test212 test220 test221 test222 test223 test224 test206   \
- test207 test208 test209 test213 test240 test241 test242 test519 test214   \
- test215 test216 test217 test218 test199 test225 test226 test227 test228   \
- test229 test233 test234 test235 test236 test520 test237 test238 test239   \
- test243 test245 test246 test247 test248 test249 test250 test251 test252   \
- test253 test254 test255 test521 test522 test523 test256 test257 test258   \
- test259 test260 test261 test262 test263 test264 test265 test266 test267   \
- test268 test269 test270 test271 test272 test273 test274 test275 test524   \
- test525 test276 test277 test526 test527 test528 test530 DISABLED test278  \
- test279 test531 test280 test529 test532 test533 test534 test535 test281   \
- test537 test282 test283 test284 test538 test285 test286 test307 test308   \
- test287 test400 test288 test600 test601 test602 test603 test401 test402   \
- test290 test291 test292 test293 test403 test404 test405 test604 test605   \
- test606 test607 test608 test609 test294 test295 test296 test297 test298   \
- test610 test611 test612 test406 test407 test408 test409 test613 test614   \
- test700 test701 test702 test704 test705 test703 test706 test707 test350   \
- test351 test352 test353 test289 test540 test354 test231 test1000 test1001 \
+ test510 test97 test98 test99 test150 test151 test152 test153 test154     \
+ test155 test156 test157 test158 test159 test511 test160 test161 test162   \
+ test163 test164 test512 test165 test166 test167 test168 test169 test170   \
+ test171 test172 test204 test205 test173 test174 test175 test176 test177   \
+ test513 test514 test178 test179 test180 test181 test182 test183 test184   \
+ test185 test186 test187 test188 test189 test191 test192 test193 test194   \
+ test195 test196 test197 test198 test515 test516 test517 test518 test210   \
+ test211 test212 test220 test221 test222 test223 test224 test206 test207   \
+ test208 test209 test213 test240 test241 test242 test519 test214 test215   \
+ test216 test217 test218 test199 test225 test226 test227 test228 test229   \
+ test233 test234 test235 test236 test520 test237 test238 test239 test243   \
+ test245 test246 test247 test248 test249 test250 test251 test252 test253   \
+ test254 test255 test521 test522 test523 test256 test257 test258 test259   \
+ test260 test261 test262 test263 test264 test265 test266 test267 test268   \
+ test269 test270 test271 test272 test273 test274 test275 test524 test525   \
+ test276 test277 test526 test527 test528 test530 DISABLED test278 test279  \
+ test531 test280 test529 test532 test533 test534 test535 test281 test537   \
+ test282 test283 test284 test538 test285 test286 test307 test308 test287   \
+ test400 test288 test600 test601 test602 test603 test401 test402 test290   \
+ test291 test292 test293 test403 test404 test405 test604 test605 test606   \
+ test607 test608 test609 test294 test295 test296 test297 test298 test610   \
+ test611 test612 test406 test407 test408 test409 test613 test614 test700   \
+ test701 test702 test704 test705 test703 test706 test707 test350 test351   \
+ test352 test353 test289 test540 test354 test231 test1000 test1001        \
  test1002 test1003 test1004 test1005 test1006 test615 test1007 test541    \
  test1010 test1011 test1012 test542 test543 test536 test1008 test1009     \
  test2000 test2001 test2002 test2003 test35 test544 test545 test2004      \
  test546 test1013 test1014 test1015 test547 test548 test549 test550       \
- test551 test552 test1016 test1017 test1018 test1019 test1020 test553      \
- test1021 test1022 test1023 test309 test616 test617 test618 test619        \
+ test551 test552 test1016 test1017 test1018 test1019 test1020 test553     \
+ test1021 test1022 test1023 test309 test616 test617 test618 test619       \
  test620 test621 test622 test623 test624 test625 test626 test627 test554   \
- test1024 test1025 test555 test1026 test1027 test1028 test1029 test1030    \
+ test1024 test1025 test555 test1026 test1027 test1028 test1029 test1030           \
  test556 test557 test1031 test628 test629 test630 test631 test632 test1032 \
- test1033 test539 test1034 test1035 test1036 test1037 test1038 test1039    \
+ test1033 test539 test1034 test1035 test1036 test1037 test1038 test1039           \
  test1040 test1041 test1042 test1043 test1044 test1045 test1046 test1047   \
  test1048 test1049 test1050 test1051 test1052 test1053 test1054 test1055   \
  test1056 test1057 test1058 test1059 test1060 test1061 test1062 test1063   \
  test1064 test1065 test1066 test1067 test1068 test1069 test1070 test1071   \
  test1072 test1073 test1074 test1075 test1076 test1077 test1078 test1079   \
- test1080 test1081 test1082 test1083 test1084 test1085 test633 test634     \
- test635 test636 test637 test558 test559 test1086 test1087 test1088        \
- test574 test575 test576 test577 test1113 test1114 \
- test1089 test1090 test1091 test1092 test1093 test1094 test1095 test1096   \
- test1097 test560 test561 test1098 test1099 test562 test563 test1100       \
- test564 test1101 test1102 test1103 test1104 test299 test310 test311       \
- test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
- test1107 test1108 test1109 test1110 test1111 test1112 test129 test567     \
- test568 test569 test570 test571 test572 test804 test805 test806 test807 \
- test573 test313 test1115 test578 test579 test1116
+ test1080 test1081 test1082 test1083 test1084 test1085 test633 test634    \
+ test635 test636 test637 test558 test559 test1086 test1087 test1088       \
+ test574 test575 test576 test577 test1113 test1114 test1089 test1090      \
+ test1091 test1092 test1093 test1094 test1095 test1096 test1097 test560           \
+ test561 test1098 test1099 test562 test563 test1100 test564 test1101      \
+ test1102 test1103 test1104 test299 test310 test311 test312 test1105      \
+ test565 test800 test1106 test801 test566 test802 test803 test1107        \
+ test1108 test1109 test1110 test1111 test1112 test129 test567 test568     \
+ test569 test570 test571 test572 test804 test805 test806 test807 test573   \
+ test313 test1115 test578 test579 test1116 test1200 test1201 test1202     \
+ test1203
 
 filecheck:
        @mkdir test-place; \
diff --git a/tests/data/test1200 b/tests/data/test1200
new file mode 100644 (file)
index 0000000..c1f4971
--- /dev/null
@@ -0,0 +1,40 @@
+# Gopher directory fetch
+<testcase>
+<info>
+<keywords>
+GOPHER
+INDEX
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iMenu results          error.host      1
+0Selector      /bar    bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher
+</server>
+ <name>
+Gopher index
+ </name>
+ <command>
+gopher://%HOSTIP:%GOPHERPORT
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1201 b/tests/data/test1201
new file mode 100644 (file)
index 0000000..071e455
--- /dev/null
@@ -0,0 +1,40 @@
+# Gopher selector fetch
+<testcase>
+<info>
+<keywords>
+GOPHER
+SELECTOR
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iMenu results          error.host      1
+0Selector /selector/SELECTOR   /bar    bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher
+</server>
+ <name>
+Gopher selector
+ </name>
+ <command>
+gopher://%HOSTIP:%GOPHERPORT/1/selector/SELECTOR
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+/selector/SELECTOR
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1202 b/tests/data/test1202
new file mode 100644 (file)
index 0000000..2ab6fcb
--- /dev/null
@@ -0,0 +1,41 @@
+# Gopher query fetch
+<testcase>
+<info>
+<keywords>
+GOPHER
+QUERY
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iSearch results                error.host      1
+0Query query succeeded /foo    foo.bar.invalid 70
+0Selector /the/search/engine   /bar    bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher
+</server>
+ <name>
+Gopher query
+ </name>
+ <command>
+gopher://%HOSTIP:%GOPHERPORT/7/the/search/engine?query%20succeeded
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+/the/search/engine     query succeeded
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1203 b/tests/data/test1203
new file mode 100644 (file)
index 0000000..d49c3c8
--- /dev/null
@@ -0,0 +1,41 @@
+# Gopher IPv6 connectivity test
+<testcase>
+<info>
+<keywords>
+GOPHER-ipv6
+IPv6
+INDEX
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iMenu results          error.host      1
+0Selector      /bar    bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher-ipv6
+</server>
+ <name>
+Gopher IPv6 index
+ </name>
+ <command>
+-g "gopher://%HOSTIP:%GOPHER6PORT"
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+
+</protocol>
+</verify>
+</testcase>
index 6a46e76..535075a 100644 (file)
@@ -181,7 +181,7 @@ sub killsockfilters {
     my $pidfile;
     my $pid;
 
-    return if($proto !~ /^(ftp|imap|pop3|smtp)$/);
+    return if($proto !~ /^(ftp|imap|pop3|smtp|gopher)$/);
 
     die "unsupported sockfilter: $which"
         if($which && ($which !~ /^(main|data)$/));
index ed2a832..03d9334 100755 (executable)
@@ -29,6 +29,9 @@
 # protocol per invoke. You need to start mulitple servers to support multiple
 # protocols simultaneously.
 #
+# The gopher protocol test server also lives here, borrowing some of the
+# routines.
+#
 # It is meant to exercise curl, it is not meant to be a fully working
 # or even very standard compliant server.
 #
@@ -341,6 +344,7 @@ sub senddata {
 # for the given protocol. References to protocol command callbacks are
 # stored in 'commandfunc' hash, and text which will be returned to the
 # client before the command callback runs is stored in 'displaytext'.
+# Gopher is not handled here, however (it has a separate routine).
 #
 sub protocolsetup {
     my $proto = $_[0];
@@ -1294,7 +1298,7 @@ while(@ARGV) {
         }
     }
     elsif($ARGV[0] eq '--proto') {
-        if($ARGV[1] && ($ARGV[1] =~ /^(ftp|imap|pop3|smtp)$/)) {
+        if($ARGV[1] && ($ARGV[1] =~ /^(ftp|imap|pop3|smtp|gopher)$/)) {
             $proto = $1;
             shift @ARGV;
         }
@@ -1421,7 +1425,7 @@ while(1) {
 
     &customize(); # read test control instructions
 
-    sendcontrol @welcome;
+    sendcontrol @welcome unless ($proto eq 'gopher');
 
     #remove global variables from last connection
     if($ftplistparserstate) {
@@ -1474,7 +1478,39 @@ while(1) {
         my $FTPCMD;
         my $FTPARG;
         my $full=$_;
-        if($proto eq "imap") {
+
+        if($proto eq 'gopher') {
+          # Gopher protocol support lives right here and we handle it
+          # right here and now, since there will only ever be one selector
+          # and no other commands.
+
+          my $sel = $_;
+          my $query = '';
+          my @response = ();
+          ($sel, $query) = split(/\x09/, $_) if (/\x09/);
+
+          if($sel eq 'erifiedserver') {
+            # NOT verifiedserver, the first character is the item type in
+            # a Gopher URL!
+            push(@response, "iWE ROOLZ: $$\x09\x09error.host\x091\r\n");
+          }
+          if (length($query)) { # fake Veronica, gin up search results
+            push(@response, "iSearch results\x09\x09error.host\x091\r\n");
+            push(@response,
+                 "0Query $query\x09/foo\x09foo.bar.invalid\x0970\r\n");
+          } else { # fake selector, gin up a menu
+            push(@response, "iMenu results\x09\x09error.host\x091\r\n");
+          }
+          push(@response,
+               "0Selector $sel\x09/bar\x09bar.foo.invalid\x0970\r\n");
+          push(@response, ".\r\n");
+          sendcontrol @response;
+
+          # disconnect the client now, no command.
+          $FTPCMD = $FTPARG = '';
+          print SFWRITE "DISC\n";
+        }
+        elsif($proto eq "imap") {
             # IMAP is different with its identifier first on the command line
             unless (m/^([^ ]+) ([^ ]+) (.*)/ ||
                     m/^([^ ]+) ([^ ]+)/) {
@@ -1550,7 +1586,7 @@ while(1) {
             }
         }
 
-        if($check) {
+        if($check && $proto ne 'gopher') {
             logmsg "$FTPCMD wasn't handled!\n";
             sendcontrol "500 $FTPCMD is not dealt with!\r\n";
         }
index 06ff733..a3c402e 100755 (executable)
@@ -133,6 +133,8 @@ my $SMTPPORT; # SMTP
 my $SMTP6PORT; # SMTP IPv6 server port
 my $RTSPPORT; # RTSP
 my $RTSP6PORT; # RTSP IPv6 server port
+my $GOPHERPORT; # Gopher
+my $GOPHER6PORT; # Gopher IPv6 server port
 
 my $srcdir = $ENV{'srcdir'} || '.';
 my $CURL="../src/curl".exe_ext(); # what curl executable to run on the tests
@@ -193,6 +195,7 @@ my $has_idn;     # set if libcurl is built with IDN support
 my $http_ipv6;   # set if HTTP server has IPv6 support
 my $ftp_ipv6;    # set if FTP server has IPv6 support
 my $tftp_ipv6;   # set if TFTP server has IPv6 support
+my $gopher_ipv6; # set if Gopher server has IPv6 support
 my $has_ipv6;    # set if libcurl is built with IPv6 support
 my $has_libz;    # set if libcurl is built with libz support
 my $has_getrlimit;  # set if system has getrlimit()
@@ -329,7 +332,7 @@ sub init_serverpidfile_hash {
       }
     }
   }
-  for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp')) {
+  for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'gopher')) {
     for my $ipvnum ((4, 6)) {
       for my $idnum ((1, 2)) {
         my $serv = servername_id($proto, $ipvnum, $idnum);
@@ -988,7 +991,8 @@ my %protofunc = ('http' => \&verifyhttp,
                  'ftps' => \&verifyftp,
                  'tftp' => \&verifyftp,
                  'ssh' => \&verifyssh,
-                 'socks' => \&verifysocks);
+                 'socks' => \&verifysocks,
+                 'gopher' => \&verifyftp);
 
 sub verifyserver {
     my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
@@ -1180,7 +1184,7 @@ sub runhttpsserver {
 }
 
 #######################################################################
-# start the pingpong server (FTP, POP3, IMAP, SMTP)
+# start the pingpong server (FTP, POP3, IMAP, SMTP, GOPHER)
 #
 sub runpingpongserver {
     my ($proto, $id, $verbose, $ipv6) = @_;
@@ -1211,6 +1215,9 @@ sub runpingpongserver {
     elsif($proto eq "smtp") {
         $port = ($ipvnum==6) ? $SMTP6PORT : $SMTPPORT;
     }
+    elsif($proto eq "gopher") {
+        $port = ($ipvnum==6) ? $GOPHER6PORT : $GOPHERPORT;
+    }
     else {
         print STDERR "Unsupported protocol $proto!!\n";
         return 0;
@@ -1263,6 +1270,7 @@ sub runpingpongserver {
         $doesntrun{$pidfile} = 1;
         return (0,0);
     }
+
     $pid2 = $pid3;
 
     if($verbose) {
@@ -2039,7 +2047,9 @@ sub checksystem {
         @sws = `server/sockfilt --version`;
         if($sws[0] =~ /IPv6/) {
             # FTP server has ipv6 support!
+            # and since the Gopher server descends from it, we have it too!
             $ftp_ipv6 = 1;
+            $gopher_ipv6 = 1;
         }
     }
 
@@ -2098,6 +2108,10 @@ sub checksystem {
     if($tftp_ipv6) {
         logmsg sprintf("TFTP-IPv6/%d ", $TFTP6PORT);
     }
+    logmsg sprintf("\n*   GOPHER/%d ", $GOPHERPORT);
+    if($gopher_ipv6) {
+        logmsg sprintf("GOPHER-IPv6/%d", $GOPHERPORT);
+    }
     logmsg sprintf("\n*   SSH/%d ", $SSHPORT);
     logmsg sprintf("SOCKS/%d ", $SOCKSPORT);
     logmsg sprintf("POP3/%d ", $POP3PORT);
@@ -2147,6 +2161,8 @@ sub subVariables {
   $$thing =~ s/%CLIENT6IP/$CLIENT6IP/g;
   $$thing =~ s/%RTSPPORT/$RTSPPORT/g;
   $$thing =~ s/%RTSP6PORT/$RTSP6PORT/g;
+  $$thing =~ s/%GOPHERPORT/$GOPHERPORT/g;
+  $$thing =~ s/%GOPHER6PORT/$GOPHER6PORT/g;
 
   # The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be
   # used for time-out tests and that whould work on most hosts as these
@@ -3211,6 +3227,7 @@ sub startservers {
         if(($what eq "pop3") ||
            ($what eq "ftp") ||
            ($what eq "imap") ||
+           ($what eq "gopher") ||
            ($what eq "smtp")) {
             if(!$run{$what}) {
                 ($pid, $pid2) = runpingpongserver($what, "", $verbose);
@@ -3242,6 +3259,17 @@ sub startservers {
                 $run{'ftp-ipv6'}="$pid $pid2";
             }
         }
+        elsif($what eq "gopher-ipv6") {
+            if(!$run{'gopher-ipv6'}) {
+                ($pid, $pid2) = runpingpongserver("gopher","",$verbose,"ipv6");
+                if($pid <= 0) {
+                    return "failed starting GOPHER-IPv6 server";
+                }
+                logmsg sprintf("* pid gopher-ipv6 => %d %d\n", $pid,
+                       $pid2) if($verbose);
+                $run{'gopher-ipv6'}="$pid $pid2";
+            }
+        }
         elsif($what eq "http") {
             if(!$run{'http'}) {
                 ($pid, $pid2) = runhttpserver($verbose);
@@ -3821,6 +3849,8 @@ $SMTPPORT =  $base++;
 $SMTP6PORT = $base++;
 $RTSPPORT =  $base++;
 $RTSP6PORT = $base++;
+$GOPHERPORT =$base++;
+$GOPHER6PORT=$base++;
 
 #######################################################################
 # clear and create logging directory:
index 4b3b505..8429b40 100644 (file)
@@ -96,7 +96,7 @@ sub servername_str {
 
     $proto = uc($proto) if($proto);
     die "unsupported protocol: $proto" unless($proto &&
-        ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP))$/));
+        ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|GOPHER))$/));
 
     $ipver = (not $ipver) ? 'ipv4' : lc($ipver);
     die "unsupported IP version: $ipver" unless($ipver &&
@@ -148,7 +148,8 @@ sub server_pidfilename {
 sub server_logfilename {
     my ($logdir, $proto, $ipver, $idnum) = @_;
     my $trailer = '_server.log';
-    $trailer = '_stunnel.log' if(lc($proto) =~ /^(ftp|http|imap|pop3|smtp)s$/);
+    $trailer = '_stunnel.log' if(lc($proto) =~ /^(ftp|http|imap|pop3|smtp)s$/||
+                                 lc($proto) eq 'gopher');
     return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer";
 }
 
@@ -189,7 +190,7 @@ sub server_outputfilename {
 sub mainsockf_pidfilename {
     my ($proto, $ipver, $idnum) = @_;
     die "unsupported protocol: $proto" unless($proto &&
-        (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/));
+        ((lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/) || lc($proto) eq 'gopher'));
     my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.pid':'_sockfilt.pid';
     return '.'. servername_canon($proto, $ipver, $idnum) ."$trailer";
 }
@@ -201,7 +202,7 @@ sub mainsockf_pidfilename {
 sub mainsockf_logfilename {
     my ($logdir, $proto, $ipver, $idnum) = @_;
     die "unsupported protocol: $proto" unless($proto &&
-        (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/));
+        ((lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/) || lc($proto) eq 'gopher'));
     my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.log':'_sockfilt.log';
     return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer";
 }