+ address_list_release (pc_last_host_ip);
+ pc_last_host_ip = NULL;
+ }
+ DEBUGP (("Invalidating fd %d from further reuse.\n", pc_last_fd));
+}
+
+/* Register FD, which should be a TCP/IP connection to HOST:PORT, as
+ persistent. This will enable someone to use the same connection
+ later. In the context of HTTP, this must be called only AFTER the
+ response has been received and the server has promised that the
+ connection will remain alive.
+
+ If a previous connection was persistent, it is closed. */
+
+#ifdef HAVE_SSL
+static void
+register_persistent (const char *host, unsigned short port, int fd, SSL *ssl)
+{
+#else
+static void
+register_persistent (const char *host, unsigned short port, int fd)
+{
+#endif
+ if (pc_active_p)
+ {
+ if (pc_last_fd == fd)
+ {
+ /* The connection FD is already registered. Nothing to
+ do. */
+ return;
+ }
+ else
+ {
+ /* The old persistent connection is still active; let's
+ close it first. This situation arises whenever a
+ persistent connection exists, but we then connect to a
+ different host, and try to register a persistent
+ connection to that one. */
+#ifdef HAVE_SSL
+ /* The ssl disconnect has to take place before the closing
+ of pc_last_fd. */
+ if (pc_last_ssl)
+ shutdown_ssl(pc_last_ssl);
+#endif
+ CLOSE (pc_last_fd);
+ invalidate_persistent ();
+ }
+ }
+
+ assert (pc_last_host_ip == NULL);
+
+ /* This lookup_host cannot fail, because it has the results in the
+ cache. */
+ pc_last_host_ip = lookup_host (host, 1);
+ assert (pc_last_host_ip != NULL);
+
+ pc_last_port = port;
+ pc_last_fd = fd;
+ pc_active_p = 1;
+#ifdef HAVE_SSL
+ pc_last_ssl = ssl;
+ pc_active_ssl = ssl ? 1 : 0;
+#endif
+ DEBUGP (("Registered fd %d for persistent reuse.\n", fd));
+}
+
+#ifdef HAVE_SSL
+# define SHUTDOWN_SSL(ssl) do { \
+ if (ssl) \
+ shutdown_ssl (ssl); \
+} while (0)
+#else
+# define SHUTDOWN_SSL(ssl)
+#endif
+
+/* Return non-zero if a persistent connection is available for
+ connecting to HOST:PORT. */
+
+#ifdef HAVE_SSL
+static int
+persistent_available_p (const char *host, unsigned short port, int ssl)
+{
+#else
+static int
+persistent_available_p (const char *host, unsigned short port)
+{
+#endif
+ int success;
+ struct address_list *this_host_ip;
+
+ /* First, check whether a persistent connection is active at all. */
+ if (!pc_active_p)
+ return 0;
+ /* Second, check if the active connection pertains to the correct
+ (HOST, PORT) ordered pair. */
+ if (port != pc_last_port)
+ return 0;
+
+#ifdef HAVE_SSL
+ /* Second, a): check if current connection is (not) ssl, too. This
+ test is unlikely to fail because HTTP and HTTPS typicaly use
+ different ports. Yet it is possible, or so I [Christian
+ Fraenkel] have been told, to run HTTPS and HTTP simultaneus on
+ the same port. */
+ if (ssl != pc_active_ssl)
+ return 0;
+#endif /* HAVE_SSL */
+
+ this_host_ip = lookup_host (host, 1);
+ if (!this_host_ip)
+ return 0;
+
+ /* To equate the two host names for the purposes of persistent
+ connections, they need to share all the IP addresses in the
+ list. */
+ success = address_list_match_all (pc_last_host_ip, this_host_ip);
+ address_list_release (this_host_ip);
+ if (!success)
+ return 0;
+
+ /* Third: check whether the connection is still open. This is
+ important because most server implement a liberal (short) timeout
+ on persistent connections. Wget can of course always reconnect
+ if the connection doesn't work out, but it's nicer to know in
+ advance. This test is a logical followup of the first test, but
+ is "expensive" and therefore placed at the end of the list. */
+ if (!test_socket_open (pc_last_fd))
+ {
+ /* Oops, the socket is no longer open. Now that we know that,
+ let's invalidate the persistent connection before returning
+ 0. */
+ CLOSE (pc_last_fd);
+#ifdef HAVE_SSL
+ SHUTDOWN_SSL (pc_last_ssl);
+ pc_last_ssl = NULL;
+#endif
+ invalidate_persistent ();
+ return 0;