From ec12a85981246cd2d76b7095b54c403d680ba3ca Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Thu, 1 Aug 2013 18:19:41 +0200
Subject: [PATCH] CURLINFO_XFER_STATE: export the state of a transfer

---
 docs/libcurl/curl_easy_getinfo.3 | 35 +++++++++++++++++++++++-
 include/curl/curl.h              | 19 ++++++++++++-
 lib/multi.c                      | 59 ++++++++++++++++++++++++++++++++++++++++
 lib/multiif.h                    |  2 ++
 4 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index 62d8ae4..bc2e07a 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -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
@@ -249,6 +249,39 @@ retrieve this info before closing the active connection.
 Pass a pointer to a long to receive the most recently received CSeq from the
 server. If your application encounters a \fICURLE_RTSP_CSEQ_ERROR\fP then you
 may wish to troubleshoot and/or fix the CSeq mismatch by peeking at this value.
+.IP CURLINFO_XFER_STATE
+Pass a pointer to a long to receive the current state of the transfer of the
+given easy handle.
+
+The currently available states are:
+.RS
+.IP "CURLXFER_INIT (0)"
+Nothing really happened yet
+.IP "CURLXFER_NAMERES (1)"
+Name resolving
+.IP "CURLXFER_CONNECT (2)"
+TCP (or similar) connect
+.IP "CURLXFER_PROTOCONNECT (3)"
+Protocol specific connect
+.IP "CURLXFER_PROXYCONNECT (4)"
+HTTP proxy CONNECT procedure
+.IP "CURLXFER_WAITDO (5)"
+Waiting to issue request
+.IP "CURLXFER_DO (6)"
+Issuing request
+.IP "CURLXFER_TRANSFER (7)"
+Transfer
+.IP "CURLXFER_TOOFAST (8)"
+Switched to due to rate limiting, basically a variation of CURLXFER_TRANSFER.
+.IP "CURLXFER_DONE (9)"
+Transfer complete
+.RE
+
+Not all transfers will use all states. States may not be changed to in a
+numerical order. In some cases a transfer can go back to a previously already
+visited state. We may introduce new states in the future
+
+(Added in 7.33.0)
 .SH TIMES
 .nf
 An overview of the six time values available from curl_easy_getinfo()
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 41c0881..f02446d 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1961,6 +1961,22 @@ struct curl_certinfo {
                                    format "name: value" */
 };
 
+/* The XFER_STATE option returns state about the particular transfer. Not all
+   transfers will use all states. States may not be changed to in a numerical
+   order. In some cases a transfer can go back to a previously already visited
+   state. We may introduce new states in the future. */
+#define CURLXFER_INIT         0 /* nothing really happened yet */
+#define CURLXFER_NAMERES      1 /* name resolving */
+#define CURLXFER_CONNECT      2 /* TCP (or similar) connect */
+#define CURLXFER_PROTOCONNECT 3 /* protocol specific connect oriented ops */
+#define CURLXFER_PROXYCONNECT 4 /* proxy CONNECT procedure */
+#define CURLXFER_WAITDO       5 /* waiting to issue request */
+#define CURLXFER_DO           6 /* issuing request */
+#define CURLXFER_TRANSFER     7 /* transfer */
+#define CURLXFER_TOOFAST      8 /* toggled transfer due to rate limiting,
+                                   basically a variation of *TRANSFER */
+#define CURLXFER_DONE         9 /* transfer complete */
+
 #define CURLINFO_STRING   0x100000
 #define CURLINFO_LONG     0x200000
 #define CURLINFO_DOUBLE   0x300000
@@ -2012,9 +2028,10 @@ typedef enum {
   CURLINFO_PRIMARY_PORT     = CURLINFO_LONG   + 40,
   CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
   CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
+  CURLINFO_XFER_STATE       = CURLINFO_LONG   + 43,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 42
+  CURLINFO_LASTONE          = 43
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
diff --git a/lib/multi.c b/lib/multi.c
index 774e808..7a79bd8 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -2732,3 +2732,62 @@ void Curl_multi_dump(const struct Curl_multi *multi_handle)
   }
 }
 #endif
+
+/*
+ * Return the external version of the internal state for this
+ * connection/handle.
+ *
+ * The external version is part of the fixed API and must never change even if
+ * new states MAY be introduced if absolutely necessary.
+ */
+CURLcode Curl_multi_easy_state(struct SessionHandle *data, long *valuep)
+{
+  long ext_state = CURLXFER_INIT;
+  if(data && data->multi) {
+    switch(data->mstate) {
+    case CURLM_STATE_INIT:
+      break;
+    case CURLM_STATE_CONNECT_PEND:
+    case CURLM_STATE_CONNECT:
+    case CURLM_STATE_WAITCONNECT:
+      ext_state = CURLXFER_CONNECT;
+      break;
+    case CURLM_STATE_WAITRESOLVE:
+      ext_state = CURLXFER_NAMERES;
+      break;
+    case CURLM_STATE_WAITPROXYCONNECT:
+      ext_state = CURLXFER_PROXYCONNECT;
+      break;
+    case CURLM_STATE_PROTOCONNECT:
+      ext_state = CURLXFER_PROTOCONNECT;
+      break;
+    case CURLM_STATE_WAITDO:
+      ext_state = CURLXFER_WAITDO;
+      break;
+    case CURLM_STATE_DO:
+    case CURLM_STATE_DOING:
+    case CURLM_STATE_DO_MORE:
+    case CURLM_STATE_DO_DONE:
+      ext_state = CURLXFER_DO;
+      break;
+    case CURLM_STATE_WAITPERFORM:
+    case CURLM_STATE_PERFORM:
+      ext_state = CURLXFER_TRANSFER;
+      break;
+    case CURLM_STATE_TOOFAST:
+      ext_state = CURLXFER_TOOFAST;
+      break;
+    case CURLM_STATE_DONE:
+    case CURLM_STATE_COMPLETED:
+    case CURLM_STATE_MSGSENT:
+    case CURLM_STATE_LAST:
+      ext_state = CURLXFER_DONE;
+      break;
+    }
+    if(valuep)
+      *valuep = ext_state;
+  }
+  else
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return CURLE_OK;
+}
diff --git a/lib/multiif.h b/lib/multiif.h
index d1b0e2f..fcdd15d 100644
--- a/lib/multiif.h
+++ b/lib/multiif.h
@@ -95,4 +95,6 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
 
 void Curl_multi_closed(struct connectdata *conn, curl_socket_t s);
 
+CURLcode Curl_multi_easy_state(struct SessionHandle *data, long *valuep);
+
 #endif /* HEADER_CURL_MULTIIF_H */
-- 
1.8.4.rc0

