From 78e9fa58f820522a6282a9180749f36214ea539e 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 | 33 ++++++++++++++++++++++
 include/curl/curl.h              | 20 +++++++++++++-
 lib/multi.c                      | 59 ++++++++++++++++++++++++++++++++++++++++
 lib/multiif.h                    |  2 ++
 4 files changed, 113 insertions(+), 1 deletion(-)

diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index 8d000c0..4c6b26d 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -261,6 +261,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 aafaeed..d93e4b8 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, 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
@@ -2007,6 +2007,22 @@ struct curl_tlssessioninfo {
   void *internals;
 };
 
+/* 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
@@ -2059,6 +2075,8 @@ typedef enum {
   CURLINFO_LOCAL_IP         = CURLINFO_STRING + 41,
   CURLINFO_LOCAL_PORT       = CURLINFO_LONG   + 42,
   CURLINFO_TLS_SESSION      = CURLINFO_SLIST  + 43,
+  CURLINFO_XFER_STATE       = CURLINFO_LONG   + 44,
+
   /* Fill in new entries below here! */
 
   CURLINFO_LASTONE          = 43
diff --git a/lib/multi.c b/lib/multi.c
index b3b5716..4e95a07 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -2735,3 +2735,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 1cbd310..286c0f1 100644
--- a/lib/multiif.h
+++ b/lib/multiif.h
@@ -93,4 +93,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.9.rc1

