always-multi: always use non-blocking internals
authorDaniel Stenberg <daniel@haxx.se>
Thu, 17 Jan 2013 11:59:23 +0000 (12:59 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 17 Jan 2013 18:40:35 +0000 (19:40 +0100)
Remove internal separated behavior of the easy vs multi intercace.
curl_easy_perform() is now using the multi interface itself.

Several minor multi interface quirks and bugs have been fixed in the
process.

Much help with debugging this has been provided by: Yang Tse

54 files changed:
docs/TODO
lib/Makefile.inc
lib/conncache.c
lib/conncache.h
lib/connect.c
lib/easy.c
lib/ftp.c
lib/http.c
lib/http_proxy.c
lib/imap.c
lib/multi.c
lib/multihandle.h [new file with mode: 0644]
lib/openldap.c
lib/pop3.c
lib/smtp.c
lib/ssh.c
lib/ssluse.c
lib/tftp.c
lib/transfer.c
lib/url.c
lib/urldata.h
tests/Makefile.am
tests/data/test1208
tests/data/test1349
tests/data/test1350
tests/data/test1351
tests/data/test1352
tests/data/test1353
tests/data/test1354
tests/data/test1357
tests/data/test1358
tests/data/test1359
tests/data/test1360
tests/data/test1361
tests/data/test1362
tests/data/test1379
tests/data/test1380
tests/data/test1381
tests/data/test1382
tests/data/test1383
tests/data/test1384
tests/data/test1387
tests/data/test1388
tests/data/test1389
tests/data/test1390
tests/data/test1391
tests/data/test1392
tests/data/test1407
tests/data/test506
tests/data/test808
tests/data/test813
tests/libtest/lib537.c
tests/runtests.pl
tests/valgrind.supp [new file with mode: 0644]

index cfbac2f3b1fa7e3eaecf0968f06d4475da5aaed8..470612d30070242ddd29c35078cef9895fa3319a 100644 (file)
--- a/docs/TODO
+++ b/docs/TODO
@@ -21,8 +21,7 @@
 
  2. libcurl - multi interface
  2.1 More non-blocking
- 2.2 Remove easy interface internally
- 2.4 Fix HTTP Pipelining for PUT
+ 2.2 Fix HTTP Pipelining for PUT
 
  3. Documentation
  3.1  More and better
  - The "DONE" operation (post transfer protocol-specific actions) for the
    protocols SFTP, SMTP, FTP. Fixing Curl_done() for this is a worthy task.
 
-2.2 Remove easy interface internally
-
- Make curl_easy_perform() a wrapper-function that simply creates a multi
- handle, adds the easy handle to it, runs curl_multi_perform() until the
- transfer is done, then detach the easy handle, destroy the multi handle and
- return the easy handle's return code. This will thus make everything
- internally use and assume the multi interface. The select()-loop should use
- curl_multi_socket().
-
-2.4 Fix HTTP Pipelining for PUT
+2.2 Fix HTTP Pipelining for PUT
 
  HTTP Pipelining can be a way to greatly enhance performance for multiple
  serial requests and currently libcurl only supports that for HEAD and GET
index b116b3932fe2acb2ff7626dfcd8b768bd52c5b5f..e970edd90eac127cd441aa8a47e3d6f14939f20d 100644 (file)
@@ -43,4 +43,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h     \
   gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h        \
   curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h       \
   curl_sasl.h curl_schannel.h curl_multibyte.h curl_darwinssl.h        \
-  hostcheck.h bundles.h conncache.h curl_setup_once.h
+  hostcheck.h bundles.h conncache.h curl_setup_once.h multihandle.h
index 165a26fb4fd42e292eb0b57dfa41b163156de55d..530cdc2ec3f4183429e8d76c2dfe73515e8d951a 100644 (file)
@@ -6,7 +6,7 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
- * Copyright (C) 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -47,7 +47,7 @@ static void free_bundle_hash_entry(void *freethis)
   Curl_bundle_destroy(b);
 }
 
-struct conncache *Curl_conncache_init(conncachetype type)
+struct conncache *Curl_conncache_init(void)
 {
   struct conncache *connc;
 
@@ -63,9 +63,6 @@ struct conncache *Curl_conncache_init(conncachetype type)
     return NULL;
   }
 
-  connc->type = type;
-  connc->num_connections = 0;
-
   return connc;
 }
 
index 03b129d4e9a072e006a6a5f15f8e0a490e133787..fad17d8f7a76d44c4830460a5f526dbd1fa76bfa 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
+ * Copyright (C) 2012, 2013, Linus Nielsen Feltzing, <linus@haxx.se>
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  *
  ***************************************************************************/
 
-typedef enum {
-  CONNCACHE_PRIVATE, /* used for an easy handle alone */
-  CONNCACHE_MULTI    /* shared within a multi handle */
-} conncachetype;
-
 struct conncache {
   struct curl_hash *hash;
-  conncachetype type;
   size_t num_connections;
 };
 
-struct conncache *Curl_conncache_init(conncachetype type);
+struct conncache *Curl_conncache_init(void);
 
 void Curl_conncache_destroy(struct conncache *connc);
 
index acaf3b485ba0ee2e6b4b28a87ca61316c8980e8e..c411a0eb5ff2f80ebd7b094c5bab6a65eda2bf66 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -74,6 +74,8 @@
 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
 #include "progress.h"
 #include "warnless.h"
+#include "conncache.h"
+#include "multihandle.h"
 
 /* The last #include file should be: */
 #include "memdebug.h"
@@ -980,8 +982,7 @@ singleipconnect(struct connectdata *conn,
 
   /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
      connect(). We can be sure of this since connect() cannot return 1. */
-  if((WAITCONN_TIMEOUT == rc) &&
-     (data->state.used_interface == Curl_if_multi)) {
+  if(WAITCONN_TIMEOUT == rc) {
     /* Timeout when running the multi interface */
     *sockp = sockfd;
     return CURLE_OK;
@@ -1072,9 +1073,8 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
 
     /* start connecting to the IP curr_addr points to */
     res = singleipconnect(conn, curr_addr,
-                          /* don't hang when doing multi */
-                          (data->state.used_interface == Curl_if_multi)?0:
-                          conn->timeoutms_per_addr, &sockfd, connected);
+                          0, /* don't hang when doing multi */
+                          &sockfd, connected);
     if(res)
       return res;
 
@@ -1112,6 +1112,21 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   return CURLE_OK;
 }
 
+struct connfind {
+  struct connectdata *tofind;
+  bool found;
+};
+
+static int conn_is_conn(struct connectdata *conn, void *param)
+{
+  struct connfind *f = (struct connfind *)param;
+  if(conn == f->tofind) {
+    f->found = TRUE;
+    return 1;
+  }
+  return 0;
+}
+
 /*
  * Used to extract socket and connectdata struct for the most recent
  * transfer on the given SessionHandle.
@@ -1125,8 +1140,21 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
 
   DEBUGASSERT(data);
 
-  if(data->state.lastconnect) {
+  /* this only works for an easy handle that has been used for
+     curl_easy_perform()! */
+  if(data->state.lastconnect && data->multi_easy) {
     struct connectdata *c = data->state.lastconnect;
+    struct connfind find;
+    find.tofind = data->state.lastconnect;
+    find.found = FALSE;
+
+    Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
+
+    if(!find.found) {
+      data->state.lastconnect = NULL;
+      return CURL_SOCKET_BAD;
+    }
+
     if(connp)
       /* only store this if the caller cares for it */
       *connp = c;
index 700fb327be4e6cb3c89660fbec2973b65476c2e2..2f4b48b802f78c637470a1ce13716b3cf1e4acf6 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -385,40 +385,46 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
   return ret;
 }
 
-#ifdef CURL_MULTIEASY
-/***************************************************************************
- * This function is still only for testing purposes. It makes a great way
- * to run the full test suite on the multi interface instead of the easy one.
- ***************************************************************************
- *
- * The *new* curl_easy_perform() is the external interface that performs a
- * transfer previously setup.
+/*
+ * curl_easy_perform() is the external interface that performs a blocking
+ * transfer as previously setup.
  *
- * Wrapper-function that: creates a multi handle, adds the easy handle to it,
+ * CONCEPT: This function creates a multi handle, adds the easy handle to it,
  * runs curl_multi_perform() until the transfer is done, then detaches the
  * easy handle, destroys the multi handle and returns the easy handle's return
- * code. This will make everything internally use and assume multi interface.
+ * code.
+ *
+ * REALITY: it can't just create and destroy the multi handle that easily. It
+ * needs to keep it around since if this easy handle is used again by this
+ * function, the same multi handle must be re-used so that the same pools and
+ * caches can be used.
  */
 CURLcode curl_easy_perform(CURL *easy)
 {
   CURLM *multi;
   CURLMcode mcode;
   CURLcode code = CURLE_OK;
-  int still_running;
-  struct timeval timeout;
-  int rc;
   CURLMsg *msg;
-  fd_set fdread;
-  fd_set fdwrite;
-  fd_set fdexcep;
-  int maxfd;
+  bool done = FALSE;
+  int rc;
+  struct SessionHandle *data = easy;
 
   if(!easy)
     return CURLE_BAD_FUNCTION_ARGUMENT;
 
-  multi = curl_multi_init();
-  if(!multi)
-    return CURLE_OUT_OF_MEMORY;
+  if(data->multi) {
+    failf(data, "easy handled already used in multi handle");
+    return CURLE_FAILED_INIT;
+  }
+
+  if(data->multi_easy)
+    multi = data->multi_easy;
+  else {
+    multi = curl_multi_init();
+    if(!multi)
+      return CURLE_OUT_OF_MEMORY;
+    data->multi_easy = multi;
+  }
 
   mcode = curl_multi_add_handle(multi, easy);
   if(mcode) {
@@ -429,108 +435,33 @@ CURLcode curl_easy_perform(CURL *easy)
       return CURLE_FAILED_INIT;
   }
 
-  /* we start some action by calling perform right away */
-
-  do {
-    while(CURLM_CALL_MULTI_PERFORM ==
-          curl_multi_perform(multi, &still_running));
-
-    if(!still_running)
-      break;
-
-    FD_ZERO(&fdread);
-    FD_ZERO(&fdwrite);
-    FD_ZERO(&fdexcep);
-
-    /* timeout once per second */
-    timeout.tv_sec = 1;
-    timeout.tv_usec = 0;
-
-    /* Old deprecated style: get file descriptors from the transfers */
-    curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
-    rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
-
-    /* The way is to extract the sockets and wait for them without using
-       select. This whole alternative version should probably rather use the
-       curl_multi_socket() approach. */
-
-    if(rc == -1)
-      /* select error */
-      break;
-
-    /* timeout or data to send/receive => loop! */
-  } while(still_running);
-
-  msg = curl_multi_info_read(multi, &rc);
-  if(msg)
-    code = msg->data.result;
-
-  mcode = curl_multi_remove_handle(multi, easy);
-  /* what to do if it fails? */
-
-  mcode = curl_multi_cleanup(multi);
-  /* what to do if it fails? */
-
-  return code;
-}
-#else
-/*
- * curl_easy_perform() is the external interface that performs a transfer
- * previously setup.
- */
-CURLcode curl_easy_perform(CURL *curl)
-{
-  struct SessionHandle *data = (struct SessionHandle *)curl;
-
-  if(!data)
-    return CURLE_BAD_FUNCTION_ARGUMENT;
+  /* assign this after curl_multi_add_handle() since that function checks for
+     it and rejects this handle otherwise */
+  data->multi = multi;
 
-  if(! (data->share && data->share->hostcache)) {
-    /* this handle is not using a shared dns cache */
+  while(!done && !mcode) {
+    int still_running;
 
-    if(data->set.global_dns_cache &&
-       (data->dns.hostcachetype != HCACHE_GLOBAL)) {
-      /* global dns cache was requested but still isn't */
-      struct curl_hash *ptr;
+    mcode = curl_multi_wait(multi, NULL, 0, 1000, NULL);
 
-      if(data->dns.hostcachetype == HCACHE_PRIVATE) {
-        /* if the current cache is private, kill it first */
-        Curl_hash_destroy(data->dns.hostcache);
-        data->dns.hostcachetype = HCACHE_NONE;
-        data->dns.hostcache = NULL;
-      }
+    if(mcode == CURLM_OK)
+      mcode = curl_multi_perform(multi, &still_running);
 
-      ptr = Curl_global_host_cache_init();
-      if(ptr) {
-        /* only do this if the global cache init works */
-        data->dns.hostcache = ptr;
-        data->dns.hostcachetype = HCACHE_GLOBAL;
+    /* only read 'still_running' if curl_multi_perform() return OK */
+    if((mcode == CURLM_OK) && !still_running) {
+      msg = curl_multi_info_read(multi, &rc);
+      if(msg) {
+        code = msg->data.result;
+        done = TRUE;
       }
     }
-
-    if(!data->dns.hostcache) {
-      data->dns.hostcachetype = HCACHE_PRIVATE;
-      data->dns.hostcache = Curl_mk_dnscache();
-
-      if(!data->dns.hostcache)
-        /* While we possibly could survive and do good without a host cache,
-           the fact that creating it failed indicates that things are truly
-           screwed up and we should bail out! */
-        return CURLE_OUT_OF_MEMORY;
-    }
-
   }
 
-  if(!data->state.conn_cache) {
-    /* Oops, no connection cache, create one */
-    data->state.conn_cache = Curl_conncache_init(CONNCACHE_PRIVATE);
-    if(!data->state.conn_cache)
-      return CURLE_OUT_OF_MEMORY;
-  }
+  mcode = curl_multi_remove_handle(multi, easy);
 
-  return Curl_perform(data);
+  /* The multi handle is kept alive, owned by the easy handle */
+  return code;
 }
-#endif
 
 /*
  * curl_easy_cleanup() is the external interface to cleaning/freeing the given
@@ -553,10 +484,6 @@ void Curl_easy_addmulti(struct SessionHandle *data,
                         void *multi)
 {
   data->multi = multi;
-  if(multi == NULL)
-    /* the association is cleared, mark the easy handle as not used by an
-       interface */
-    data->state.used_interface = Curl_if_none;
 }
 
 void Curl_easy_initHandleData(struct SessionHandle *data)
index 352f12f44c5ab2defe05620290612e92b256c3d0..469b8874969e4810e5564e0b5aecf415ab74f071 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
 #endif
 
 /* Local API functions */
-static void state(struct connectdata *conn,
-                  ftpstate newstate);
+#ifndef DEBUGBUILD
+static void _state(struct connectdata *conn,
+                   ftpstate newstate);
+#define state(x,y) _state(x,y)
+#else
+static void _state(struct connectdata *conn,
+                   ftpstate newstate,
+                   int lineno);
+#define state(x,y) _state(x,y,__LINE__)
+#endif
+
 static CURLcode ftp_sendquote(struct connectdata *conn,
                               struct curl_slist *quote);
 static CURLcode ftp_quit(struct connectdata *conn);
@@ -149,6 +158,8 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
                              struct pingpong *pp,
                              int *ftpcode,
                              size_t *size);
+static CURLcode ftp_dophase_done(struct connectdata *conn,
+                                 bool connected);
 
 /* easy-to-use macro: */
 #define FTPSENDF(x,y,z)    if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
@@ -411,7 +422,7 @@ static long ftp_timeleft_accept(struct SessionHandle *data)
  * connection for a negative response regarding a failure in connecting
  *
  */
-static CURLcode ReceivedServerConnect(struct connectdata* conn, bool* received)
+static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
 {
   struct SessionHandle *data = conn->data;
   curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
@@ -514,8 +525,8 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
   else {
     /* FTP download: */
     Curl_setup_transfer(conn, SECONDARYSOCKET,
-        conn->proto.ftpc.retr_size_saved, FALSE,
-        ftp->bytecountp, -1, NULL); /* no upload here */
+                        conn->proto.ftpc.retr_size_saved, FALSE,
+                        ftp->bytecountp, -1, NULL); /* no upload here */
   }
 
   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
@@ -528,18 +539,15 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
  *
  * AllowServerConnect()
  *
- * When we've issue the PORT command, we have told the server to connect
- * to us. This function
- *   - will sit and wait here until the server has connected for easy interface
- *   - will check whether data connection is established if so it is accepted
- *   for multi interface
+ * When we've issue the PORT command, we have told the server to connect to
+ * us. This function checks whether data connection is established if so it is
+ * accepted.
  *
  */
 static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
 {
   struct SessionHandle *data = conn->data;
   long timeout_ms;
-  long interval_ms;
   CURLcode ret = CURLE_OK;
 
   *connected = FALSE;
@@ -548,50 +556,34 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
   /* Save the time we start accepting server connect */
   Curl_pgrsTime(data, TIMER_STARTACCEPT);
 
-  for(;;) {
-    timeout_ms = ftp_timeleft_accept(data);
-    if(timeout_ms < 0) {
-      /* if a timeout was already reached, bail out */
-      failf(data, "Accept timeout occurred while waiting server connect");
-      return CURLE_FTP_ACCEPT_TIMEOUT;
-    }
+  timeout_ms = ftp_timeleft_accept(data);
+  if(timeout_ms < 0) {
+    /* if a timeout was already reached, bail out */
+    failf(data, "Accept timeout occurred while waiting server connect");
+    return CURLE_FTP_ACCEPT_TIMEOUT;
+  }
+
+  /* see if the connection request is already here */
+  ret = ReceivedServerConnect(conn, connected);
+  if(ret)
+    return ret;
 
-    /* see if the connection request is already here */
-    ret = ReceivedServerConnect(conn, connected);
+  if(*connected) {
+    ret = AcceptServerConnect(conn);
     if(ret)
       return ret;
 
-    if(*connected) {
-      ret = AcceptServerConnect(conn);
-      if(ret)
-        return ret;
-
-      ret = InitiateTransfer(conn);
-      if(ret)
-        return ret;
-
-      break; /* connection is accepted, break the loop */
-    }
-    else {
-      if(data->state.used_interface == Curl_if_easy) {
-        interval_ms = 1000;
-        if(timeout_ms < interval_ms)
-          interval_ms = timeout_ms;
-
-        /* sleep for 1 second and then continue */
-        Curl_socket_ready(CURL_SOCKET_BAD, CURL_SOCKET_BAD, interval_ms);
-      }
-      else {
-        /* Add timeout to multi handle and break out of the loop */
-        if(ret == CURLE_OK && *connected == FALSE) {
-          if(data->set.accepttimeout > 0)
-            Curl_expire(data, data->set.accepttimeout);
-          else
-            Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
-        }
-
-        break; /* connection was not accepted immediately */
-      }
+    ret = InitiateTransfer(conn);
+    if(ret)
+      return ret;
+  }
+  else {
+    /* Add timeout to multi handle and break out of the loop */
+    if(ret == CURLE_OK && *connected == FALSE) {
+      if(data->set.accepttimeout > 0)
+        Curl_expire(data, data->set.accepttimeout);
+      else
+        Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
     }
   }
 
@@ -787,8 +779,12 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
 }
 
 /* This is the ONLY way to change FTP state! */
-static void state(struct connectdata *conn,
-                  ftpstate newstate)
+static void _state(struct connectdata *conn,
+                   ftpstate newstate
+#ifdef DEBUGBUILD
+                   , int lineno
+#endif
+  )
 {
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* for debug purposes */
@@ -833,8 +829,8 @@ static void state(struct connectdata *conn,
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   if(ftpc->state != newstate)
-    infof(conn->data, "FTP %p state change from %s to %s\n",
-          ftpc, names[ftpc->state], names[newstate]);
+    infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
+          ftpc, lineno, names[ftpc->state], names[newstate]);
 #endif
   ftpc->state = newstate;
 }
@@ -2071,10 +2067,19 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
 
     if(result)
       return result;
+
+    if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
+      /* the CONNECT procedure is not complete, the tunnel is not yet up */
+      state(conn, FTP_STOP); /* this phase is completed */
+      conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
+
+      return result;
+    }
   }
 
   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
 
+  conn->bits.do_more = TRUE;
   state(conn, FTP_STOP); /* this phase is completed */
 
   return result;
@@ -2108,6 +2113,7 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn,
   else {
     infof(data, "Connect data stream actively\n");
     state(conn, FTP_STOP); /* end of DO phase */
+    result = ftp_dophase_done(conn, FALSE);
   }
 
   return result;
@@ -3206,7 +3212,6 @@ static CURLcode ftp_connect(struct connectdata *conn,
 {
   CURLcode result;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
-  struct SessionHandle *data=conn->data;
   struct pingpong *pp = &ftpc->pp;
 
   *done = FALSE; /* default to not done yet */
@@ -3240,13 +3245,7 @@ static CURLcode ftp_connect(struct connectdata *conn,
      response */
   state(conn, FTP_WAIT220);
 
-  if(data->state.used_interface == Curl_if_multi)
-    result = ftp_multi_statemach(conn, done);
-  else {
-    result = ftp_easy_statemach(conn);
-    if(!result)
-      *done = TRUE;
-  }
+  result = ftp_multi_statemach(conn, done);
 
   return result;
 }
@@ -3681,6 +3680,14 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
 
   /* if the second connection isn't done yet, wait for it */
   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
+    if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
+      /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
+         aren't used so we blank their arguments. TODO: make this nicer */
+      result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
+
+      return result;
+    }
+
     result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
 
     /* Ready to do more? */
@@ -3691,9 +3698,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
       return result;
   }
 
-  if((data->state.used_interface == Curl_if_multi) &&
-     ftpc->state) {
-    /* multi interface and already in a state so skip the intial commands.
+  if(ftpc->state) {
+    /* already in a state so skip the intial commands.
        They are only done to kickstart the do_more state */
     result = ftp_multi_statemach(conn, complete);
 
@@ -3701,6 +3707,12 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
        immediately */
     if(result || (ftpc->wait_data_conn != TRUE))
       return result;
+
+    if(ftpc->wait_data_conn)
+      /* if we reach the end of the FTP state machine here, *complete will be
+         TRUE but so is ftpc->wait_data_conn, which says we need to wait for
+         the data connection and therefore we're not actually complete */
+      *complete = FALSE;
   }
 
   if(ftp->transfer <= FTPTRANSFER_INFO) {
@@ -3729,6 +3741,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
       result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
       if(result)
         return result;
+
+      result = ftp_multi_statemach(conn, complete);
     }
     else {
       /* download */
@@ -3755,14 +3769,10 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
         if(result)
           return result;
       }
-    }
-    if(data->state.used_interface == Curl_if_multi) {
-      result = ftp_multi_statemach(conn, complete);
 
-      return result;
+      result = ftp_multi_statemach(conn, complete);
     }
-    else
-      result = ftp_easy_statemach(conn);
+    return result;
   }
 
   if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
@@ -3805,7 +3815,6 @@ CURLcode ftp_perform(struct connectdata *conn,
     ftp->transfer = FTPTRANSFER_INFO;
   }
 
-
   *dophase_done = FALSE; /* not done yet */
 
   /* start the first command in the DO phase */
@@ -3814,16 +3823,12 @@ CURLcode ftp_perform(struct connectdata *conn,
     return result;
 
   /* run the state-machine */
-  if(conn->data->state.used_interface == Curl_if_multi)
-    result = ftp_multi_statemach(conn, dophase_done);
-  else {
-    result = ftp_easy_statemach(conn);
-    *dophase_done = TRUE; /* with the easy interface we are done here */
-  }
+  result = ftp_multi_statemach(conn, dophase_done);
+
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(conn->data, "DO phase is complete1\n"));
 
   return result;
 }
@@ -4476,7 +4481,7 @@ static CURLcode ftp_doing(struct connectdata *conn,
   else if(*dophase_done) {
     result = ftp_dophase_done(conn, FALSE /* not connected */);
 
-    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+    DEBUGF(infof(conn->data, "DO phase is complete2\n"));
   }
   return result;
 }
@@ -4521,6 +4526,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
       return CURLE_OK;
 
     result = ftp_dophase_done(conn, connected);
+
     if(result)
       return result;
   }
index 21f7c21e6e1661a5f1f11dc64f4b0f0e3725388c..daaafe317e340e2975fbe2031a4d66fb4c9c4cb1 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -1295,22 +1295,16 @@ Curl_compareheader(const char *headerline, /* line to check */
  */
 CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
 {
-  struct SessionHandle *data;
   CURLcode result;
 
-  data=conn->data;
-
   /* We default to persistent connections. We set this already in this connect
      function to make the re-use checks properly be able to check this bit. */
   conn->bits.close = FALSE;
 
-  if(data->state.used_interface == Curl_if_multi) {
-    /* when the multi interface is used, the CONNECT procedure might not have
-       been completed */
-    result = Curl_proxy_connect(conn);
-    if(result)
-      return result;
-  }
+  /* the CONNECT procedure might not have been completed */
+  result = Curl_proxy_connect(conn);
+  if(result)
+    return result;
 
   if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
     /* nothing else to do except wait right now - we're not done here. */
@@ -1318,22 +1312,12 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
 
   if(conn->given->flags & PROTOPT_SSL) {
     /* perform SSL initialization */
-    if(data->state.used_interface == Curl_if_multi) {
-      result = https_connecting(conn, done);
-      if(result)
-        return result;
-    }
-    else {
-      /* BLOCKING */
-      result = Curl_ssl_connect(conn, FIRSTSOCKET);
-      if(result)
-        return result;
-      *done = TRUE;
-    }
+    result = https_connecting(conn, done);
+    if(result)
+      return result;
   }
-  else {
+  else
     *done = TRUE;
-  }
 
   return CURLE_OK;
 }
index ada89576e170ef7fb70e1ed8f935bd4133a55b41..ed0fe95037bc78079d446ea79fbafab3f9960483 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -87,13 +87,6 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
  * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
  * function will issue the necessary commands to get a seamless tunnel through
  * this proxy. After that, the socket can be used just as a normal socket.
- *
- * This badly needs to be rewritten. CONNECT should be sent and dealt with
- * like any ordinary HTTP request, and not specially crafted like this. This
- * function only remains here like this for now since the rewrite is a bit too
- * much work to do at the moment.
- *
- * This function is BLOCKING which is nasty for all multi interface using apps.
  */
 
 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
@@ -244,19 +237,13 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
       return CURLE_RECV_ERROR;
     }
 
-    /* if we're in multi-mode and we would block, return instead for a retry */
-    if(Curl_if_multi == data->state.used_interface) {
-      if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
-        /* return so we'll be called again polling-style */
-        return CURLE_OK;
-      else {
-        DEBUGF(infof(data,
-                     "Multi mode finished polling for response from "
-                     "proxy CONNECT\n"));
-      }
-    }
+    if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
+      /* return so we'll be called again polling-style */
+      return CURLE_OK;
     else {
-      DEBUGF(infof(data, "Easy mode waiting response from proxy CONNECT\n"));
+      DEBUGF(infof(data,
+                   "Multi mode finished polling for response from "
+                   "proxy CONNECT\n"));
     }
 
     /* at this point, either:
@@ -572,6 +559,12 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
     if(closeConnection && data->req.newurl)
       conn->bits.proxy_connect_closed = TRUE;
 
+    if(data->req.newurl) {
+      /* this won't be used anymore for the CONNECT so free it now */
+      free(data->req.newurl);
+      data->req.newurl = NULL;
+    }
+
     /* to back to init state */
     conn->tunnel_state[sockindex] = TUNNEL_INIT;
 
index a53f2e9d243126f0b81bfab752464e9a61640976..c7198d0b1435a08cc4f60ef19b7460304cb947f3 100644 (file)
@@ -633,19 +633,9 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
       result = imap_state_capability(conn);
   }
   else {
-    if(data->state.used_interface == Curl_if_multi) {
-      state(conn, IMAP_UPGRADETLS);
-      result = imap_state_upgrade_tls(conn);
-    }
-    else {
-      result = Curl_ssl_connect(conn, FIRSTSOCKET);
-      if(CURLE_OK == result) {
-        imap_to_imaps(conn);
-        result = imap_state_capability(conn);
-      }
-    }
+    state(conn, IMAP_UPGRADETLS);
+    return imap_state_upgrade_tls(conn);
   }
-
   return result;
 }
 
@@ -1358,7 +1348,6 @@ static CURLcode imap_connect(struct connectdata *conn,
 {
   CURLcode result;
   struct imap_conn *imapc = &conn->proto.imapc;
-  struct SessionHandle *data=conn->data;
   struct pingpong *pp = &imapc->pp;
 
   *done = FALSE; /* default to not done yet */
@@ -1379,17 +1368,7 @@ static CURLcode imap_connect(struct connectdata *conn,
   pp->endofresp = imap_endofresp;
   pp->conn = conn;
 
-  if((conn->handler->flags & PROTOPT_SSL) &&
-     data->state.used_interface != Curl_if_multi) {
-    /* IMAPS is simply imap with SSL for the control channel */
-    /* so perform the SSL initialization for this socket */
-    result = Curl_ssl_connect(conn, FIRSTSOCKET);
-    if(result)
-      return result;
-  }
-
-  /* Initialise the response reader stuff */
-  Curl_pp_init(pp);
+  Curl_pp_init(pp); /* init generic pingpong data */
 
   /* Start off waiting for the server greeting response */
   state(conn, IMAP_SERVERGREET);
@@ -1397,13 +1376,7 @@ static CURLcode imap_connect(struct connectdata *conn,
   /* Start off with an id of '*' */
   imapc->idstr = "*";
 
-  if(data->state.used_interface == Curl_if_multi)
-    result = imap_multi_statemach(conn, done);
-  else {
-    result = imap_easy_statemach(conn);
-    if(!result)
-      *done = TRUE;
-  }
+  result = imap_multi_statemach(conn, done);
 
   return result;
 }
@@ -1473,13 +1446,9 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
   if(result)
     return result;
 
-  /* Run the state-machine */
-  if(conn->data->state.used_interface == Curl_if_multi)
-    result = imap_multi_statemach(conn, dophase_done);
-  else {
-    result = imap_easy_statemach(conn);
-    *dophase_done = TRUE; /* with the easy interface we are done here */
-  }
+  /* run the state-machine */
+  result = imap_multi_statemach(conn, dophase_done);
+
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
index de1fc7d6ead8a49f9842a8c6f5d784fb6f66eab9..fa0afb9f83ab3ad3984d1cf9668947198b9de4d3 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -39,6 +39,7 @@
 #include "speedcheck.h"
 #include "conncache.h"
 #include "bundles.h"
+#include "multihandle.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
 #define CURL_SOCKET_HASH_TABLE_SIZE 911
 #endif
 
-struct Curl_message {
-  /* the 'CURLMsg' is the part that is visible to the external user */
-  struct CURLMsg extmsg;
-};
-
-/* NOTE: if you add a state here, add the name to the statename[] array as
-   well!
-*/
-typedef enum {
-  CURLM_STATE_INIT,        /* 0 - start in this state */
-  CURLM_STATE_CONNECT,     /* 1 - resolve/connect has been sent off */
-  CURLM_STATE_WAITRESOLVE, /* 2 - awaiting the resolve to finalize */
-  CURLM_STATE_WAITCONNECT, /* 3 - awaiting the connect to finalize */
-  CURLM_STATE_WAITPROXYCONNECT, /* 4 - awaiting proxy CONNECT to finalize */
-  CURLM_STATE_PROTOCONNECT, /* 5 - completing the protocol-specific connect
-                               phase */
-  CURLM_STATE_WAITDO,      /* 6 - wait for our turn to send the request */
-  CURLM_STATE_DO,          /* 7 - start send off the request (part 1) */
-  CURLM_STATE_DOING,       /* 8 - sending off the request (part 1) */
-  CURLM_STATE_DO_MORE,     /* 9 - send off the request (part 2) */
-  CURLM_STATE_DO_DONE,     /* 10 - done sending off request */
-  CURLM_STATE_WAITPERFORM, /* 11 - wait for our turn to read the response */
-  CURLM_STATE_PERFORM,     /* 12 - transfer data */
-  CURLM_STATE_TOOFAST,     /* 13 - wait because limit-rate exceeded */
-  CURLM_STATE_DONE,        /* 14 - post data transfer operation */
-  CURLM_STATE_COMPLETED,   /* 15 - operation complete */
-  CURLM_STATE_MSGSENT,     /* 16 - the operation complete message is sent */
-  CURLM_STATE_LAST         /* 17 - not a true state, never use this */
-} CURLMstate;
-
-/* we support N sockets per easy handle. Set the corresponding bit to what
-   action we should wait for */
-#define MAX_SOCKSPEREASYHANDLE 5
-#define GETSOCK_READABLE (0x00ff)
-#define GETSOCK_WRITABLE (0xff00)
-
-struct Curl_one_easy {
-  /* first, two fields for the linked list of these */
-  struct Curl_one_easy *next;
-  struct Curl_one_easy *prev;
-
-  struct SessionHandle *easy_handle; /* the easy handle for this unit */
-  struct connectdata *easy_conn;     /* the "unit's" connection */
-
-  CURLMstate state;  /* the handle's state */
-  CURLcode result;   /* previous result */
-
-  struct Curl_message msg; /* A single posted message. */
-
-  /* Array with the plain socket numbers this handle takes care of, in no
-     particular order. Note that all sockets are added to the sockhash, where
-     the state etc are also kept. This array is mostly used to detect when a
-     socket is to be removed from the hash. See singlesocket(). */
-  curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
-  int numsocks;
-};
 
 #define CURL_MULTI_HANDLE 0x000bab1e
 
@@ -120,57 +65,6 @@ struct Curl_one_easy {
 #define GOOD_EASY_HANDLE(x) \
   ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
 
-/* This is the struct known as CURLM on the outside */
-struct Curl_multi {
-  /* First a simple identifier to easier detect if a user mix up
-     this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
-  long type;
-
-  /* We have a doubly-linked circular list with easy handles */
-  struct Curl_one_easy easy;
-
-  int num_easy; /* amount of entries in the linked list above. */
-  int num_alive; /* amount of easy handles that are added but have not yet
-                    reached COMPLETE state */
-
-  struct curl_llist *msglist; /* a list of messages from completed transfers */
-
-  /* callback function and user data pointer for the *socket() API */
-  curl_socket_callback socket_cb;
-  void *socket_userp;
-
-  /* Hostname cache */
-  struct curl_hash *hostcache;
-
-  /* timetree points to the splay-tree of time nodes to figure out expire
-     times of all currently set timers */
-  struct Curl_tree *timetree;
-
-  /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
-     the pluralis form, there can be more than one easy handle waiting on the
-     same actual socket) */
-  struct curl_hash *sockhash;
-
-  /* Whether pipelining is enabled for this multi handle */
-  bool pipelining_enabled;
-
-  /* Shared connection cache (bundles)*/
-  struct conncache *conn_cache;
-
-  /* This handle will be used for closing the cached connections in
-     curl_multi_cleanup() */
-  struct SessionHandle *closure_handle;
-
-  long maxconnects; /* if >0, a fixed limit of the maximum number of entries
-                       we're allowed to grow the connection cache to */
-
-  /* timer callback and user data pointer for the *socket() API */
-  curl_multi_timer_callback timer_cb;
-  void *timer_userp;
-  struct timeval timer_lastcall; /* the fixed time for the timeout for the
-                                    previous callback */
-};
-
 static void singlesocket(struct Curl_multi *multi,
                          struct Curl_one_easy *easy);
 static int update_timer(struct Curl_multi *multi);
@@ -213,7 +107,11 @@ static const char * const statename[]={
 static void multi_freetimeout(void *a, void *b);
 
 /* always use this function to change state, to make debugging easier */
-static void multistate(struct Curl_one_easy *easy, CURLMstate state)
+static void mstate(struct Curl_one_easy *easy, CURLMstate state
+#ifdef DEBUGBUILD
+                   , int lineno
+#endif
+)
 {
 #ifdef DEBUGBUILD
   long connection_id = -5000;
@@ -233,9 +131,9 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
       connection_id = easy->easy_conn->connection_id;
 
     infof(easy->easy_handle,
-          "STATE: %s => %s handle %p; (connection #%ld) \n",
+          "STATE: %s => %s handle %p; line %d (connection #%ld) \n",
           statename[oldstate], statename[easy->state],
-          (char *)easy, connection_id);
+          (char *)easy, lineno, connection_id);
   }
 #endif
   if(state == CURLM_STATE_COMPLETED)
@@ -243,6 +141,12 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
     easy->easy_handle->multi->num_alive--;
 }
 
+#ifndef DEBUGBUILD
+#define multistate(x,y) mstate(x,y)
+#else
+#define multistate(x,y) mstate(x,y, __LINE__)
+#endif
+
 /*
  * We add one of these structs to the sockhash for a particular socket
  */
@@ -396,7 +300,7 @@ CURLM *curl_multi_init(void)
   if(!multi->sockhash)
     goto error;
 
-  multi->conn_cache = Curl_conncache_init(CONNCACHE_MULTI);
+  multi->conn_cache = Curl_conncache_init();
   if(!multi->conn_cache)
     goto error;
 
@@ -516,29 +420,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
   easy->easy_handle->multi_pos =  easy;
 
   /* for multi interface connections, we share DNS cache automatically if the
-     easy handle's one is currently private. */
-  if(easy->easy_handle->dns.hostcache &&
-     (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
-    Curl_hash_destroy(easy->easy_handle->dns.hostcache);
-    easy->easy_handle->dns.hostcache = NULL;
-    easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
-  }
-
+     easy handle's one is currently not set. */
   if(!easy->easy_handle->dns.hostcache ||
      (easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
     easy->easy_handle->dns.hostcache = multi->hostcache;
     easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
   }
 
-  /* On a multi stack the connection cache, owned by the multi handle,
-     is shared between all easy handles within the multi handle.
-     Therefore we free the private connection cache if there is one */
-  if(easy->easy_handle->state.conn_cache &&
-     easy->easy_handle->state.conn_cache->type == CONNCACHE_PRIVATE) {
-    Curl_conncache_destroy(easy->easy_handle->state.conn_cache);
-  }
-
-  /* Point now to this multi's connection cache */
+  /* Point to the multi's connection cache */
   easy->easy_handle->state.conn_cache = multi->conn_cache;
 
   /* This adds the new entry at the 'end' of the doubly-linked circular
@@ -666,18 +555,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
     }
 
     if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
-      if(multi->num_easy == 1) {
-        if(easy_owns_conn) {
-          Curl_resolver_cancel(easy->easy_conn);
-          if(easy->easy_conn->dns_entry) {
-            Curl_resolv_unlock(easy->easy_handle, easy->easy_conn->dns_entry);
-            easy->easy_conn->dns_entry = NULL;
-          }
-        }
-        Curl_hostcache_destroy(easy->easy_handle);
-        multi->hostcache = NULL;
-      }
-      /* clear out the usage of the shared DNS cache */
+      /* stop using the multi handle's DNS cache */
       easy->easy_handle->dns.hostcache = NULL;
       easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
     }
@@ -700,12 +578,9 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
         Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn);
     }
 
-    if(easy->easy_handle->state.conn_cache->type == CONNCACHE_MULTI) {
-      /* if this was using the shared connection cache we clear the pointer
-         to that since we're not part of that handle anymore */
-      easy->easy_handle->state.conn_cache = NULL;
-      easy->easy_handle->state.lastconnect = NULL;
-    }
+    /* as this was using a shared connection cache we clear the pointer
+       to that since we're not part of that multi handle anymore */
+    easy->easy_handle->state.conn_cache = NULL;
 
     /* change state without using multistate(), only to make singlesocket() do
        what we want */
@@ -1025,7 +900,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
   bool connected;
   bool async;
   bool protocol_connect = FALSE;
-  bool dophase_done;
+  bool dophase_done = FALSE;
   bool done = FALSE;
   CURLMcode result = CURLM_OK;
   struct SingleRequest *k;
@@ -1120,8 +995,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         /* after init, go CONNECT */
         multistate(easy, CURLM_STATE_CONNECT);
         result = CURLM_CALL_MULTI_PERFORM;
-
-        data->state.used_interface = Curl_if_multi;
       }
       break;
 
@@ -1577,9 +1450,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         if(!ret)
           retry = (newurl)?TRUE:FALSE;
 
-        if(retry)
-          /* if we are to retry, set the result to OK */
+        if(retry) {
+          /* if we are to retry, set the result to OK and consider the
+             request as done */
           easy->result = CURLE_OK;
+          done = TRUE;
+        }
       }
 
       if(easy->result) {
@@ -1897,6 +1773,9 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
     /* Close all the connections in the connection cache */
     close_all_connections(multi);
 
+    multi->closure_handle->dns.hostcache = multi->hostcache;
+    Curl_hostcache_clean(multi->closure_handle);
+
     Curl_close(multi->closure_handle);
     multi->closure_handle = NULL;
 
diff --git a/lib/multihandle.h b/lib/multihandle.h
new file mode 100644 (file)
index 0000000..9418359
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef HEADER_CURL_MULTIHANDLE_H
+#define HEADER_CURL_MULTIHANDLE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+struct Curl_message {
+  /* the 'CURLMsg' is the part that is visible to the external user */
+  struct CURLMsg extmsg;
+};
+
+/* NOTE: if you add a state here, add the name to the statename[] array as
+   well!
+*/
+typedef enum {
+  CURLM_STATE_INIT,        /* 0 - start in this state */
+  CURLM_STATE_CONNECT,     /* 1 - resolve/connect has been sent off */
+  CURLM_STATE_WAITRESOLVE, /* 2 - awaiting the resolve to finalize */
+  CURLM_STATE_WAITCONNECT, /* 3 - awaiting the connect to finalize */
+  CURLM_STATE_WAITPROXYCONNECT, /* 4 - awaiting proxy CONNECT to finalize */
+  CURLM_STATE_PROTOCONNECT, /* 5 - completing the protocol-specific connect
+                               phase */
+  CURLM_STATE_WAITDO,      /* 6 - wait for our turn to send the request */
+  CURLM_STATE_DO,          /* 7 - start send off the request (part 1) */
+  CURLM_STATE_DOING,       /* 8 - sending off the request (part 1) */
+  CURLM_STATE_DO_MORE,     /* 9 - send off the request (part 2) */
+  CURLM_STATE_DO_DONE,     /* 10 - done sending off request */
+  CURLM_STATE_WAITPERFORM, /* 11 - wait for our turn to read the response */
+  CURLM_STATE_PERFORM,     /* 12 - transfer data */
+  CURLM_STATE_TOOFAST,     /* 13 - wait because limit-rate exceeded */
+  CURLM_STATE_DONE,        /* 14 - post data transfer operation */
+  CURLM_STATE_COMPLETED,   /* 15 - operation complete */
+  CURLM_STATE_MSGSENT,     /* 16 - the operation complete message is sent */
+  CURLM_STATE_LAST         /* 17 - not a true state, never use this */
+} CURLMstate;
+
+/* we support N sockets per easy handle. Set the corresponding bit to what
+   action we should wait for */
+#define MAX_SOCKSPEREASYHANDLE 5
+#define GETSOCK_READABLE (0x00ff)
+#define GETSOCK_WRITABLE (0xff00)
+
+struct Curl_one_easy {
+  /* first, two fields for the linked list of these */
+  struct Curl_one_easy *next;
+  struct Curl_one_easy *prev;
+
+  struct SessionHandle *easy_handle; /* the easy handle for this unit */
+  struct connectdata *easy_conn;     /* the "unit's" connection */
+
+  CURLMstate state;  /* the handle's state */
+  CURLcode result;   /* previous result */
+
+  struct Curl_message msg; /* A single posted message. */
+
+  /* Array with the plain socket numbers this handle takes care of, in no
+     particular order. Note that all sockets are added to the sockhash, where
+     the state etc are also kept. This array is mostly used to detect when a
+     socket is to be removed from the hash. See singlesocket(). */
+  curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+  int numsocks;
+};
+
+/* This is the struct known as CURLM on the outside */
+struct Curl_multi {
+  /* First a simple identifier to easier detect if a user mix up
+     this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
+  long type;
+
+  /* We have a doubly-linked circular list with easy handles */
+  struct Curl_one_easy easy;
+
+  int num_easy; /* amount of entries in the linked list above. */
+  int num_alive; /* amount of easy handles that are added but have not yet
+                    reached COMPLETE state */
+
+  struct curl_llist *msglist; /* a list of messages from completed transfers */
+
+  /* callback function and user data pointer for the *socket() API */
+  curl_socket_callback socket_cb;
+  void *socket_userp;
+
+  /* Hostname cache */
+  struct curl_hash *hostcache;
+
+  /* timetree points to the splay-tree of time nodes to figure out expire
+     times of all currently set timers */
+  struct Curl_tree *timetree;
+
+  /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
+     the pluralis form, there can be more than one easy handle waiting on the
+     same actual socket) */
+  struct curl_hash *sockhash;
+
+  /* Whether pipelining is enabled for this multi handle */
+  bool pipelining_enabled;
+
+  /* Shared connection cache (bundles)*/
+  struct conncache *conn_cache;
+
+  /* This handle will be used for closing the cached connections in
+     curl_multi_cleanup() */
+  struct SessionHandle *closure_handle;
+
+  long maxconnects; /* if >0, a fixed limit of the maximum number of entries
+                       we're allowed to grow the connection cache to */
+
+  /* timer callback and user data pointer for the *socket() API */
+  curl_multi_timer_callback timer_cb;
+  void *timer_userp;
+  struct timeval timer_lastcall; /* the fixed time for the timeout for the
+                                    previous callback */
+};
+
+#endif /* HEADER_CURL_MULTIHANDLE_H */
+
index 4c395fadc33014da48ea47c6c263f55343138497..cb3b4202058645324ae46b93024a4b33d8e55a7d 100644 (file)
@@ -6,7 +6,7 @@
  *                 \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
- * Copyright (C) 2011 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2011 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -192,6 +192,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
   struct SessionHandle *data=conn->data;
   int rc, proto = LDAP_VERSION3;
   char hosturl[1024], *ptr;
+  (void)done;
 
   strcpy(hosturl, "ldap");
   ptr = hosturl+4;
@@ -212,23 +213,12 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
 #ifdef USE_SSL
   if(conn->handler->flags & PROTOPT_SSL) {
     CURLcode res;
-    if(data->state.used_interface == Curl_if_easy) {
-      res = Curl_ssl_connect(conn, FIRSTSOCKET);
-      if(res)
-        return res;
-      li->ssldone = TRUE;
-    }
-    else {
-      res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
-      if(res)
-        return res;
-    }
+    res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
+    if(res)
+      return res;
   }
 #endif
 
-  if(data->state.used_interface == Curl_if_easy)
-    return ldap_connecting(conn, done);
-
   return CURLE_OK;
 }
 
@@ -262,10 +252,7 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
   }
 #endif
 
-  if(data->state.used_interface == Curl_if_easy)
-    tvp = NULL;    /* let ldap_result block indefinitely */
-  else
-    tvp = &tv;
+  tvp = &tv;
 
 retry:
   if(!li->didbind) {
index e8fd9c52c7dc064fd09e4179e02148f030180de2..b5ea7c23f09b2ebf24c12f9efc1a17e460aade87 100644 (file)
@@ -570,17 +570,8 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
       result = pop3_state_capa(conn);
   }
   else {
-    if(data->state.used_interface == Curl_if_multi) {
-      state(conn, POP3_UPGRADETLS);
-      result = pop3_state_upgrade_tls(conn);
-    }
-    else {
-      result = Curl_ssl_connect(conn, FIRSTSOCKET);
-      if(CURLE_OK == result) {
-        pop3_to_pop3s(conn);
-        result = pop3_state_capa(conn);
-      }
-    }
+    state(conn, POP3_UPGRADETLS);
+    result = pop3_state_upgrade_tls(conn);
   }
 
   return result;
@@ -1301,7 +1292,6 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
 {
   CURLcode result;
   struct pop3_conn *pop3c = &conn->proto.pop3c;
-  struct SessionHandle *data = conn->data;
   struct pingpong *pp = &pop3c->pp;
 
   *done = FALSE; /* default to not done yet */
@@ -1336,13 +1326,7 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
   /* Start off waiting for the server greeting response */
   state(conn, POP3_SERVERGREET);
 
-  if(data->state.used_interface == Curl_if_multi)
-    result = pop3_multi_statemach(conn, done);
-  else {
-    result = pop3_easy_statemach(conn);
-    if(!result)
-      *done = TRUE;
-  }
+  result = pop3_multi_statemach(conn, done);
 
   return result;
 }
@@ -1418,12 +1402,8 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
     return result;
 
   /* Run the state-machine */
-  if(conn->data->state.used_interface == Curl_if_multi)
-    result = pop3_multi_statemach(conn, dophase_done);
-  else {
-    result = pop3_easy_statemach(conn);
-    *dophase_done = TRUE; /* with the easy interface we are done here */
-  }
+  result = pop3_multi_statemach(conn, dophase_done);
+
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
index 2ad2ac691742e9497229e316893f80fbe6d14dc4..8de9af9c3e064e4aaee38a82009ebd9d961d12d8 100644 (file)
@@ -493,17 +493,8 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
       result = smtp_authenticate(conn);
   }
   else {
-    if(data->state.used_interface == Curl_if_multi) {
-      state(conn, SMTP_UPGRADETLS);
-      result = smtp_state_upgrade_tls(conn);
-    }
-    else {
-      result = Curl_ssl_connect(conn, FIRSTSOCKET);
-      if(CURLE_OK == result) {
-        smtp_to_smtps(conn);
-        result = smtp_state_ehlo(conn);
-      }
-    }
+    state(conn, SMTP_UPGRADETLS);
+    return smtp_state_upgrade_tls(conn);
   }
 
   return result;
@@ -1300,7 +1291,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
 {
   CURLcode result;
   struct smtp_conn *smtpc = &conn->proto.smtpc;
-  struct SessionHandle *data = conn->data;
   struct pingpong *pp = &smtpc->pp;
   const char *path = conn->data->state.path;
   char localhost[HOSTNAME_MAX + 1];
@@ -1323,15 +1313,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
   pp->endofresp = smtp_endofresp;
   pp->conn = conn;
 
-  if((conn->handler->protocol & CURLPROTO_SMTPS) &&
-      data->state.used_interface != Curl_if_multi) {
-    /* SMTPS is simply smtp with SSL for the control channel */
-    /* so perform the SSL initialization for this socket */
-    result = Curl_ssl_connect(conn, FIRSTSOCKET);
-    if(result)
-      return result;
-  }
-
   /* Initialise the response reader stuff */
   Curl_pp_init(pp);
 
@@ -1357,13 +1338,7 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
   /* Start off waiting for the server greeting response */
   state(conn, SMTP_SERVERGREET);
 
-  if(data->state.used_interface == Curl_if_multi)
-    result = smtp_multi_statemach(conn, done);
-  else {
-    result = smtp_easy_statemach(conn);
-    if(!result)
-      *done = TRUE;
-  }
+  result = smtp_multi_statemach(conn, done);
 
   return result;
 }
@@ -1470,13 +1445,9 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
   if(result)
     return result;
 
-  /* Run the state-machine */
-  if(conn->data->state.used_interface == Curl_if_multi)
-    result = smtp_multi_statemach(conn, dophase_done);
-  else {
-    result = smtp_easy_statemach(conn);
-    *dophase_done = TRUE; /* with the easy interface we are done here */
-  }
+  /* run the state-machine */
+  result = smtp_multi_statemach(conn, dophase_done);
+
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done)
index 8eb2e9fc9becb42771defde006cbe924122abc3b..0c7d36ecc94c55038e3ac5ad21116e2251e0f790 100644 (file)
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -2793,13 +2793,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
 
   state(conn, SSH_INIT);
 
-  if(data->state.used_interface == Curl_if_multi)
-    result = ssh_multi_statemach(conn, done);
-  else {
-    result = ssh_easy_statemach(conn, TRUE);
-    if(!result)
-      *done = TRUE;
-  }
+  result = ssh_multi_statemach(conn, done);
 
   return result;
 }
@@ -2828,13 +2822,8 @@ CURLcode scp_perform(struct connectdata *conn,
   state(conn, SSH_SCP_TRANS_INIT);
 
   /* run the state-machine */
-  if(conn->data->state.used_interface == Curl_if_multi) {
-    result = ssh_multi_statemach(conn, dophase_done);
-  }
-  else {
-    result = ssh_easy_statemach(conn, FALSE);
-    *dophase_done = TRUE; /* with the easy interface we are done here */
-  }
+  result = ssh_multi_statemach(conn, dophase_done);
+
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
@@ -3037,13 +3026,8 @@ CURLcode sftp_perform(struct connectdata *conn,
   state(conn, SSH_SFTP_QUOTE_INIT);
 
   /* run the state-machine */
-  if(conn->data->state.used_interface == Curl_if_multi) {
-    result = ssh_multi_statemach(conn, dophase_done);
-  }
-  else {
-    result = ssh_easy_statemach(conn, FALSE);
-    *dophase_done = TRUE; /* with the easy interface we are done here */
-  }
+  result = ssh_multi_statemach(conn, dophase_done);
+
   *connected = conn->bits.tcpconnect[FIRSTSOCKET];
 
   if(*dophase_done) {
index c4c465c2c76a3959ed7a2946fdee994e5eb12aff..4a0dba734d4cadd4b1e2e8fb17e2412434360372 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -1520,16 +1520,6 @@ ossl_connect_step1(struct connectdata *conn,
 
   SSL_CTX_set_options(connssl->ctx, ctx_options);
 
-#if 0
-  /*
-   * Not sure it's needed to tell SSL_connect() that socket is
-   * non-blocking. It doesn't seem to care, but just return with
-   * SSL_ERROR_WANT_x.
-   */
-  if(data->state.used_interface == Curl_if_multi)
-    SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL);
-#endif
-
   if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) {
     if(!cert_stuff(conn,
                    connssl->ctx,
index 282460bdaa5810d5048550f3decadf2a24de7b42..ef740b856986c99d21eee9c635a4d74d9c04fd40 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -1185,129 +1185,6 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
   return (long)(state->max_time - current);
 }
 
-
-/**********************************************************
- *
- * tftp_easy_statemach
- *
- * Handle easy request until completion
- *
- **********************************************************/
-static CURLcode tftp_easy_statemach(struct connectdata *conn)
-{
-  int                   rc;
-  int                   check_time = 0;
-  CURLcode              result = CURLE_OK;
-  struct SessionHandle  *data = conn->data;
-  tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
-  curl_socket_t         fd_read;
-  long                  timeout_ms;
-  struct SingleRequest  *k = &data->req;
-  struct timeval        transaction_start = Curl_tvnow();
-
-  k->start = transaction_start;
-  k->now = transaction_start;
-
-  /* Run the TFTP State Machine */
-  for(; (state->state != TFTP_STATE_FIN) && (result == CURLE_OK); ) {
-
-    timeout_ms = state->retry_time * 1000;
-
-    if(data->set.upload) {
-      if(data->set.max_send_speed &&
-          (data->progress.ulspeed > data->set.max_send_speed)) {
-        fd_read = CURL_SOCKET_BAD;
-        timeout_ms = Curl_sleep_time(data->set.max_send_speed,
-                                     data->progress.ulspeed, state->blksize);
-      }
-      else {
-        fd_read = state->sockfd;
-      }
-    }
-    else {
-      if(data->set.max_recv_speed &&
-         (data->progress.dlspeed > data->set.max_recv_speed)) {
-        fd_read = CURL_SOCKET_BAD;
-        timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
-                                     data->progress.dlspeed, state->blksize);
-      }
-      else
-        fd_read = state->sockfd;
-    }
-
-    if(data->set.timeout) {
-      timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start);
-      if(timeout_ms > state->retry_time * 1000)
-        timeout_ms = state->retry_time * 1000;
-      else if(timeout_ms < 0)
-        timeout_ms = 0;
-    }
-
-
-    /* Wait until ready to read or timeout occurs */
-    rc = Curl_socket_ready(fd_read, CURL_SOCKET_BAD, timeout_ms);
-
-    k->now = Curl_tvnow();
-
-    /* Force a progress callback if it's been too long */
-    if(Curl_tvdiff(k->now, k->start) >= data->set.timeout) {
-      if(Curl_pgrsUpdate(conn)) {
-        tftp_state_machine(state, TFTP_EVENT_ERROR);
-        return CURLE_ABORTED_BY_CALLBACK;
-      }
-      k->start = k->now;
-    }
-
-    if(rc == -1) {
-      /* bail out */
-      int error = SOCKERRNO;
-      failf(data, "%s", Curl_strerror(conn, error));
-      state->event = TFTP_EVENT_ERROR;
-    }
-    else {
-
-      if(rc==0) {
-        /* A timeout occurred, but our timeout is variable, so maybe
-           just continue? */
-        long rtms = state->retry_time * 1000;
-        if(Curl_tvdiff(k->now, transaction_start) > rtms) {
-          state->event = TFTP_EVENT_TIMEOUT;
-          /* Force a look at transfer timeouts */
-          check_time = 1;
-        }
-        else {
-          continue; /* skip state machine */
-        }
-      }
-      else {
-        result = tftp_receive_packet(conn);
-        if(result == CURLE_OK)
-          transaction_start = Curl_tvnow();
-
-        if(k->bytecountp)
-          *k->bytecountp = k->bytecount; /* read count */
-        if(k->writebytecountp)
-          *k->writebytecountp = k->writebytecount; /* write count */
-      }
-    }
-
-    if(check_time) {
-      tftp_state_timeout(conn, NULL);
-      check_time = 0;
-    }
-
-    if(result)
-      return(result);
-
-    result = tftp_state_machine(state, state->event);
-  }
-
-  /* Tell curl we're done */
-  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
-  return(result);
-}
-
 /**********************************************************
  *
  * tftp_multi_statemach
@@ -1404,12 +1281,7 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
   if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
     return(result);
 
-  if(conn->data->state.used_interface == Curl_if_multi)
-    tftp_multi_statemach(conn, dophase_done);
-  else {
-    result = tftp_easy_statemach(conn);
-    *dophase_done = TRUE; /* with the easy interface we are done here */
-  }
+  tftp_multi_statemach(conn, dophase_done);
 
   if(*dophase_done)
     DEBUGF(infof(conn->data, "DO phase is complete\n"));
index 6be43ea34d39fa2b2f8b3d52f68b2c3f1d1a6926..5e861f9fe34d82ee26495535aaa1bf12a2cf5774 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -2068,8 +2068,6 @@ static CURLcode Curl_do_perform(struct SessionHandle *data)
   char *newurl = NULL; /* possibly a new URL to follow to! */
   followtype follow = FOLLOW_NONE;
 
-  data->state.used_interface = Curl_if_easy;
-
   res = Curl_pretransfer(data);
   if(res)
     return res;
index 8e07a791eabc3f9ff7f5acd4686000e7c28f3148..80c8a997e39891d567a71d7d77bc8de62bf7e25b 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -131,7 +131,6 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
 #include "memdebug.h"
 
 /* Local static prototypes */
-static bool ConnectionKillOne(struct SessionHandle *data);
 static void conn_free(struct connectdata *conn);
 static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
 static CURLcode do_init(struct connectdata *conn);
@@ -255,15 +254,6 @@ static const struct Curl_handler Curl_handler_dummy = {
   PROTOPT_NONE                          /* flags */
 };
 
-static void close_connections(struct SessionHandle *data)
-{
-  /* Loop through all open connections and kill them one by one */
-  bool killed;
-  do {
-    killed = ConnectionKillOne(data);
-  } while(killed);
-}
-
 void Curl_freeset(struct SessionHandle * data)
 {
   /* Free all dynamic strings stored in the data->set substructure. */
@@ -386,6 +376,11 @@ CURLcode Curl_close(struct SessionHandle *data)
        and detach this handle from there. */
     curl_multi_remove_handle(data->multi, data);
 
+  if(data->multi_easy)
+    /* when curl_easy_perform() is used, it creates its own multi handle to
+       use and this is the one */
+    curl_multi_cleanup(data->multi_easy);
+
   /* Destroy the timeout list that is held in the easy handle. It is
      /normally/ done by curl_multi_remove_handle() but this is "just in
      case" */
@@ -398,19 +393,6 @@ CURLcode Curl_close(struct SessionHandle *data)
                       the multi handle, since that function uses the magic
                       field! */
 
-  if(data->state.conn_cache) {
-    if(data->state.conn_cache->type == CONNCACHE_PRIVATE) {
-      /* close all connections still alive that are in the private connection
-         cache, as we no longer have the pointer left to the shared one. */
-      close_connections(data);
-      Curl_conncache_destroy(data->state.conn_cache);
-      data->state.conn_cache = NULL;
-    }
-  }
-
-  if(data->dns.hostcachetype == HCACHE_PRIVATE)
-    Curl_hostcache_destroy(data);
-
   if(data->state.rangestringalloc)
     free(data->state.range);
 
@@ -2000,10 +1982,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
       data->share->dirty++;
 
       if(data->share->hostcache) {
-        /* use shared host cache, first free the private one if any */
-        if(data->dns.hostcachetype == HCACHE_PRIVATE)
-          Curl_hostcache_destroy(data);
-
+        /* use shared host cache */
         data->dns.hostcache = data->share->hostcache;
         data->dns.hostcachetype = HCACHE_SHARED;
       }
@@ -2982,69 +2961,6 @@ ConnectionExists(struct SessionHandle *data,
   return FALSE; /* no matching connecting exists */
 }
 
-/*
- * This function kills and removes an existing connection in the connection
- * cache. The connection that has been unused for the longest time.
- *
- * Returns FALSE if it can't find any unused connection to kill.
- */
-static bool
-ConnectionKillOne(struct SessionHandle *data)
-{
-  struct conncache *bc = data->state.conn_cache;
-  struct curl_hash_iterator iter;
-  struct curl_llist_element *curr;
-  struct curl_hash_element *he;
-  long highscore=-1;
-  long score;
-  struct timeval now;
-  struct connectdata *conn_candidate = NULL;
-  struct connectbundle *bundle;
-
-  now = Curl_tvnow();
-
-  Curl_hash_start_iterate(bc->hash, &iter);
-
-  he = Curl_hash_next_element(&iter);
-  while(he) {
-    struct connectdata *conn;
-
-    bundle = he->ptr;
-
-    curr = bundle->conn_list->head;
-    while(curr) {
-      conn = curr->ptr;
-
-      if(!conn->inuse) {
-        /* Set higher score for the age passed since the connection was used */
-        score = Curl_tvdiff(now, conn->now);
-
-        if(score > highscore) {
-          highscore = score;
-          conn_candidate = conn;
-        }
-      }
-      curr = curr->next;
-    }
-
-    he = Curl_hash_next_element(&iter);
-  }
-
-  if(conn_candidate) {
-    /* Set the connection's owner correctly */
-    conn_candidate->data = data;
-
-    bundle = conn_candidate->bundle;
-
-    /* the winner gets the honour of being disconnected */
-    (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
-
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
 /* this connection can now be marked 'idle' */
 static void
 ConnectionDone(struct connectdata *conn)
index 576872d70f84b311f2aa85a44baf339615eb48fc..7a275da5eef0ae4cdbd2061cbad52b0eb1026b8d 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -1147,15 +1147,15 @@ struct auth {
 };
 
 struct UrlState {
-  enum {
-    Curl_if_none,
-    Curl_if_easy,
-    Curl_if_multi
-  } used_interface;
 
   /* Points to the connection cache */
   struct conncache *conn_cache;
 
+  /* when curl_easy_perform() is called, the multi handle is "owned" by
+     the easy handle so curl_easy_cleanup() on such an easy handle will
+     also close the multi handle! */
+  bool multi_owned_by_easy;
+
   /* buffers to store authentication data in, as parsed from input options */
   struct timeval keeps_speed; /* for the progress meter really */
 
@@ -1588,7 +1588,6 @@ struct Names {
   struct curl_hash *hostcache;
   enum {
     HCACHE_NONE,    /* not pointing to anything */
-    HCACHE_PRIVATE, /* points to our own */
     HCACHE_GLOBAL,  /* points to the (shrug) global one */
     HCACHE_MULTI,   /* points to a shared one in the multi handle */
     HCACHE_SHARED   /* points to a shared one in a shared object */
@@ -1608,7 +1607,11 @@ struct Names {
 struct SessionHandle {
   struct Names dns;
   struct Curl_multi *multi;    /* if non-NULL, points to the multi handle
-                                  struct to which this "belongs" */
+                                  struct to which this "belongs" when used by
+                                  the multi interface */
+  struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle
+                                    struct to which this "belongs" when used
+                                    by the easy interface */
   struct Curl_one_easy *multi_pos; /* if non-NULL, points to its position
                                       in multi controlling structure to assist
                                       in removal. */
index 65a618ea622d995a4f117a3b39f9bba26f63f00d..7e55d96ab9e095bca9f4dcf57d1e3e342d2790da 100644 (file)
@@ -27,7 +27,7 @@ EXTRA_DIST = ftpserver.pl httpserver.pl secureserver.pl runtests.pl getpart.pm \
  FILEFORMAT README stunnel.pem memanalyze.pl testcurl.pl valgrind.pm ftp.pm   \
  sshserver.pl sshhelp.pm testcurl.1 runtests.1 $(HTMLPAGES) $(PDFPAGES) \
  serverhelp.pm tftpserver.pl rtspserver.pl directories.pm symbol-scan.pl \
- CMakeLists.txt mem-include-scan.pl
+ CMakeLists.txt mem-include-scan.pl valgrind.supp
 
 # we have two variables here to make sure DIST_SUBDIRS won't get 'unit'
 # added twice as then targets such as 'distclean' misbehave and try to
index a0d428b43e90b7f9598617c3c0109d9d95182e21..504f6c7bb3b832328eca98c2447b96937f211fd3 100644 (file)
@@ -36,6 +36,11 @@ FTP PORT download, no data conn and no transient negative reply
 <strippart>
 s/^EPRT \|1\|(.*)/EPRT \|1\|/
 </strippart>
+
+# This test doesn't send a QUIT because the main state machine in multi.c
+# triggers the timeout and sets the CURLE_OPERATION_TIMEDOUT error (28) for
+# which the FTP disconect code generically has to assume could mean the
+# control the connection and thus it cannot send any command.
 <protocol>
 USER anonymous\r
 PASS ftp@example.com\r
@@ -44,10 +49,9 @@ EPRT |1|
 TYPE I\r
 SIZE 1208\r
 RETR 1208\r
-QUIT\r
 </protocol>
 <errorcode>
-12
+28
 </errorcode>
 </verify>
 </testcase>
index c88eec9e054adf8811fc76d6d900b7f06c66f887..28576fe90c31cf54e547c5eb4dc7fbc52afc9b0f 100644 (file)
@@ -54,6 +54,8 @@ fooo
 mooo
 </file1>
 
+# The final "221 bye bye baby" response to QUIT will not be recorded
+# since that is not considered part of this particular transfer!
 <file2 name="log/heads1349">
 220-        _   _ ____  _     \r
 220-    ___| | | |  _ \| |    \r
@@ -69,7 +71,6 @@ mooo
 213 10\r
 150 Binary data connection for 1349 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 2142894840f784dbe2563d46b2be85d274aa2527..df12de59d2448f319f19ab1c3fdc63b8137fe466 100644 (file)
@@ -54,6 +54,8 @@ fooo
 mooo
 </file1>
 
+# The final "221 bye bye baby" response to QUIT will not be recorded
+# since that is not considered part of this particular transfer!
 <file2 name="log/stdout1350">
 220-        _   _ ____  _     \r
 220-    ___| | | |  _ \| |    \r
@@ -69,7 +71,6 @@ mooo
 213 10\r
 150 Binary data connection for 1350 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index fea442fc7fc231bde164c84b98f75b70814da9df..d81265e01c69d2b83af8d7b2ca74674fa2f923ca 100644 (file)
@@ -55,6 +55,8 @@ fooo
 mooo
 </file1>
 
+# The final "221 bye bye baby" response to QUIT will not be recorded
+# since that is not considered part of this particular transfer!
 <file2 name="log/heads1351">
 220-        _   _ ____  _     \r
 220-    ___| | | |  _ \| |    \r
@@ -70,7 +72,6 @@ mooo
 213 10\r
 150 Binary data connection for 1351 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index ca24d4911b270e1f5532ccec988756b6ac428c76..fa9d1ce7bdabb98405a0a5919676304e43d31899 100644 (file)
@@ -55,6 +55,8 @@ fooo
 mooo
 </file1>
 
+# The final "221 bye bye baby" response to QUIT will not be recorded
+# since that is not considered part of this particular transfer!
 <file2 name="log/stdout1352">
 220-        _   _ ____  _     \r
 220-    ___| | | |  _ \| |    \r
@@ -70,7 +72,6 @@ mooo
 213 10\r
 150 Binary data connection for 1352 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 015f60a418062610404c33ad47aa68bc73403a51..b2954b14daef16183c530ed22a6a37cf2c741a6a 100644 (file)
@@ -54,6 +54,8 @@ fooo
 mooo
 </file1>
 
+# The final "221 bye bye baby" response to QUIT will not be recorded
+# since that is not considered part of this particular transfer!
 <file2 name="log/heads1353">
 220-        _   _ ____  _     \r
 220-    ___| | | |  _ \| |    \r
@@ -69,7 +71,6 @@ mooo
 213 10\r
 150 Binary data connection for 1353 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index cf644294cbfcfb4e5061ffef7e67258abff4d565..aa54f2d07e700b1419e2fab62114e3b90ed6b1ea 100644 (file)
@@ -69,7 +69,6 @@ mooo
 213 10\r
 150 Binary data connection for 1354 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 4b539ec6d046b2b2e76027cadaf8d46076c8bf71..952572032b250a591237a029dacd8c59f7436d84 100644 (file)
@@ -87,7 +87,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1357 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 081b36f1d6d7d80a083a7096ed3c6ee384d0c1b8..24cc724ea06690642f86d592dde6396eee6be841 100644 (file)
@@ -87,7 +87,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1358 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index bb9747ae489e8235e08b53a77ffb379f9ab01235..96445bb4e844f96c1e9a4d6cbc79d919c9a7969c 100644 (file)
@@ -88,7 +88,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1359 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index d2cb33dfcb7d54cd3abcf386c0958f8b0af73cd7..abfbe8c682b5c183a4cbc6c0a9baf7b7c30b147f 100644 (file)
@@ -88,7 +88,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1360 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 8d3f1f53bbf2f1b61bb8ac7767b6f53cbd6e69bc..b97de16cd635c0e8fe5342de8ce4e2c47f04ab2b 100644 (file)
@@ -87,7 +87,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1361 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 5dc41811c4b1b7a7dd6959952a7bad515976a71a..0ea7461ea66d9ce89a588f20b488260fd1bc007e 100644 (file)
@@ -87,7 +87,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1362 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 26552c8fab7fb0dad4bb8f7f2c9d6dc7b31f7117..0fd06d5c541deabebd681c952aa9037322592211 100644 (file)
@@ -64,7 +64,6 @@ mooo
 213 10\r
 150 Binary data connection for 1379 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 060b4b0b8e228155043e2d190f5fe7ba87cdd5c5..ec7800d5d3741aa506daa9d70c7700081939aba5 100644 (file)
@@ -64,7 +64,6 @@ mooo
 213 10\r
 150 Binary data connection for 1380 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index c82ac745dd2c7f50b1d3e2d98f3dc479a6585277..8f3bc37f08c524e93b03d39e32e383c9b7cc6432 100644 (file)
@@ -65,7 +65,6 @@ mooo
 213 10\r
 150 Binary data connection for 1381 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 5e5513f3869aef15bc3bd6b956a6f684fae10b48..fbf5195f72838cd7fd36728fcc8b7929d0052881 100644 (file)
@@ -65,7 +65,6 @@ mooo
 213 10\r
 150 Binary data connection for 1382 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 2604faf9631acd0cc3775ec7b00fd6bc9ed9f052..0469e72e019e65264fb8543fec4e514ec2be4d56 100644 (file)
@@ -64,7 +64,6 @@ mooo
 213 10\r
 150 Binary data connection for 1383 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 289aa9bdbfc9b0f6500e5a9418a8ccbd479eccf8..2deeb7c4c6e4641a5cadb989a6b45d7e44506f13 100644 (file)
@@ -64,7 +64,6 @@ mooo
 213 10\r
 150 Binary data connection for 1384 () (10 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 6628b8963e5e664f1b6e8ae7e0e0affa879fa4c1..a2c5a4d6b056a98adc76f6fec630ba4dd9097fb1 100644 (file)
@@ -79,7 +79,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1387 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 478a2e9fa88836c0b3ea9592d4b73c76b9909060..b4662e654b87c47780c0d92c9a7c0d6ae78ad32a 100644 (file)
@@ -79,7 +79,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1388 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index 06b9c26b1bf1ca9f448343107bc56d4cead52a6c..c2ac3ad9d3044c11f104b24e0143a9a1fb876ff8 100644 (file)
@@ -80,7 +80,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1389 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index b5980369e63ba68fe164bc8406ccd14a1561232f..3cf86e775f2d106eaca1059af4031433fea4a32f 100644 (file)
@@ -80,7 +80,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1390 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index fa7d89a669544089929a05bde167ef8fd77a971f..913f25afe724f3903b99f1e0345ed6a97e99f220 100644 (file)
@@ -79,7 +79,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1391 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index c1e8346a28169a3c99b6034d8c37dcdb072a5a1e..b05fc317c6fb12864505a2d04fdf912cf47c1ab0 100644 (file)
@@ -79,7 +79,6 @@ MOOOO
 213 214\r
 150 Binary data connection for 1392 () (214 bytes).\r
 226 File transfer complete\r
-221 bye bye baby\r
 </file2>
 <stripfile2>
 s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
index a0c84057dd48136bfc69ace92d228e7748ab27a8..842778a7c214415739918aa982277f4845d51b21 100644 (file)
@@ -12,7 +12,7 @@ LIST
 # Server-side
 <reply>
 <servercmd>
-REPLY LIST +OK 1407 100
+REPLY LIST +OK 1407 100\r\n.
 </servercmd>
 </reply>
 
index c1a959a40afb734eec71f5091e1482f20f6274a9..a61e2fc00320054dfd1caae0d835e665ada59482 100644 (file)
@@ -101,66 +101,60 @@ run 1: set cookie 1, 2 and 3
 lock:   dns    [Pigs in space]: 14
 unlock: dns    [Pigs in space]: 15
 CLEANUP
-lock:   dns    [Pigs in space]: 16
-unlock: dns    [Pigs in space]: 17
-lock:   cookie [Pigs in space]: 18
-unlock: cookie [Pigs in space]: 19
-lock:   share  [Pigs in space]: 20
-unlock: share  [Pigs in space]: 21
+lock:   cookie [Pigs in space]: 16
+unlock: cookie [Pigs in space]: 17
+lock:   share  [Pigs in space]: 18
+unlock: share  [Pigs in space]: 19
 *** run 2
 CURLOPT_SHARE
-lock:   share  [Pigs in space]: 22
-unlock: share  [Pigs in space]: 23
+lock:   share  [Pigs in space]: 20
+unlock: share  [Pigs in space]: 21
 PERFORM
-lock:   dns    [Pigs in space]: 24
-unlock: dns    [Pigs in space]: 25
+lock:   dns    [Pigs in space]: 22
+unlock: dns    [Pigs in space]: 23
+lock:   cookie [Pigs in space]: 24
+unlock: cookie [Pigs in space]: 25
 lock:   cookie [Pigs in space]: 26
 unlock: cookie [Pigs in space]: 27
 lock:   cookie [Pigs in space]: 28
 unlock: cookie [Pigs in space]: 29
-lock:   cookie [Pigs in space]: 30
-unlock: cookie [Pigs in space]: 31
 run 2: set cookie 4 and 5
-lock:   dns    [Pigs in space]: 32
-unlock: dns    [Pigs in space]: 33
+lock:   dns    [Pigs in space]: 30
+unlock: dns    [Pigs in space]: 31
 CLEANUP
-lock:   dns    [Pigs in space]: 34
-unlock: dns    [Pigs in space]: 35
-lock:   cookie [Pigs in space]: 36
-unlock: cookie [Pigs in space]: 37
-lock:   share  [Pigs in space]: 38
-unlock: share  [Pigs in space]: 39
+lock:   cookie [Pigs in space]: 32
+unlock: cookie [Pigs in space]: 33
+lock:   share  [Pigs in space]: 34
+unlock: share  [Pigs in space]: 35
 *** run 3
 CURLOPT_SHARE
-lock:   share  [Pigs in space]: 40
-unlock: share  [Pigs in space]: 41
+lock:   share  [Pigs in space]: 36
+unlock: share  [Pigs in space]: 37
 CURLOPT_COOKIEJAR
 PERFORM
-lock:   dns    [Pigs in space]: 42
-unlock: dns    [Pigs in space]: 43
+lock:   dns    [Pigs in space]: 38
+unlock: dns    [Pigs in space]: 39
+lock:   cookie [Pigs in space]: 40
+unlock: cookie [Pigs in space]: 41
+lock:   cookie [Pigs in space]: 42
+unlock: cookie [Pigs in space]: 43
 lock:   cookie [Pigs in space]: 44
 unlock: cookie [Pigs in space]: 45
-lock:   cookie [Pigs in space]: 46
-unlock: cookie [Pigs in space]: 47
-lock:   cookie [Pigs in space]: 48
-unlock: cookie [Pigs in space]: 49
 run 3: overwrite cookie 1 and 4
-lock:   dns    [Pigs in space]: 50
-unlock: dns    [Pigs in space]: 51
+lock:   dns    [Pigs in space]: 46
+unlock: dns    [Pigs in space]: 47
 try SHARE_CLEANUP...
-lock:   share  [Pigs in space]: 52
-unlock: share  [Pigs in space]: 53
+lock:   share  [Pigs in space]: 48
+unlock: share  [Pigs in space]: 49
 SHARE_CLEANUP failed, correct
 CLEANUP
-lock:   dns    [Pigs in space]: 54
-unlock: dns    [Pigs in space]: 55
-lock:   cookie [Pigs in space]: 56
-unlock: cookie [Pigs in space]: 57
-lock:   share  [Pigs in space]: 58
-unlock: share  [Pigs in space]: 59
+lock:   cookie [Pigs in space]: 50
+unlock: cookie [Pigs in space]: 51
+lock:   share  [Pigs in space]: 52
+unlock: share  [Pigs in space]: 53
 SHARE_CLEANUP
-lock:   share  [Pigs in space]: 60
-unlock: share  [Pigs in space]: 61
+lock:   share  [Pigs in space]: 54
+unlock: share  [Pigs in space]: 55
 GLOBAL_CLEANUP
 </stdout>
 <stderr>
index 2c9c11cdd23d3e9a5e9ba6ebed8c93ed7dae7493..9027a5ab99159f4c835e45cf39b894e9940ed92e 100644 (file)
@@ -10,7 +10,8 @@ LIST
 # Server-side
 <reply>
 <servercmd>
-REPLY LIST +OK 808 100
+# include the '.\r\n' 3-byte trailer to end the transfer poperly!
+REPLY LIST +OK 808 100\r\n.
 </servercmd>
 </reply>
 
index 1447fa277b5fd522337e167b4bede3332844df36..fac4aa0ef70107b61fc21176d0765d15c7e358aa 100644 (file)
@@ -34,11 +34,13 @@ pop3://%HOSTIP:%POP3PORT/813 -u user:wrong
 <errorcode>
 67
 </errorcode>
+#
+# The multi interface considers a broken "DO" request as a prematurely broken
+# transfer and such a connection will not get a "QUIT"
 <protocol>
 CAPA\r
 USER user\r
 PASS wrong\r
-QUIT\r
 </protocol>
 </verify>
 </testcase>
index 24d2522353053969de7cf8c0d344f8efd04f2fd7..5da537995c99dbebd1e93a27af972b4d861100ee 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -41,7 +41,7 @@
 #error "this test requires FD_SETSIZE"
 #endif
 
-#define SAFETY_MARGIN (10)
+#define SAFETY_MARGIN (11)
 
 #if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
 #define DEV_NULL "NUL"
index f6c2016c4b9298a24c55dc35fc4a9fc7d4b8f407..c59d68fb7e8ac732842bb59176e2de336a9bf4df 100755 (executable)
@@ -6,7 +6,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
@@ -3084,6 +3084,7 @@ sub singletest {
             my $valgrindcmd = "$valgrind ";
             $valgrindcmd .= "$valgrind_tool " if($valgrind_tool);
             $valgrindcmd .= "--leak-check=yes ";
+            $valgrindcmd .= "--suppressions=valgrind.supp ";
             $valgrindcmd .= "--num-callers=16 ";
             $valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum";
             $CMDLINE = "$valgrindcmd $CMDLINE";
diff --git a/tests/valgrind.supp b/tests/valgrind.supp
new file mode 100644 (file)
index 0000000..6fb9ce8
--- /dev/null
@@ -0,0 +1,16 @@
+{
+   libidn-idna_to_ascii-error
+   Memcheck:Addr4
+   fun:idna_to_ascii_4z
+   fun:idna_to_ascii_8z
+   fun:idna_to_ascii_lz
+   fun:fix_hostname
+   fun:resolve_server
+   fun:create_conn
+   fun:Curl_connect
+   fun:multi_runsingle
+   fun:curl_multi_perform
+   fun:curl_easy_perform
+   fun:operate
+   fun:main
+}