1014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch/***************************************************************************
2014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *                                  _   _ ____  _
3014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *  Project                     ___| | | |  _ \| |
4014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *                             / __| | | | |_) | |
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *                            | (__| |_| |  _ <| |___
6014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *                             \___|\___/|_| \_\_____|
7014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *
8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
9342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch *
101b268ca467c924004286c97bac133db489cf43d0Ben Murdoch * This software is licensed as described in the file COPYING, which
11014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * you should have received as part of this distribution. The terms
12014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * are also available at https://curl.haxx.se/docs/copyright.html.
13014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *
14014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * copies of the Software, and permit persons to whom the Software is
16014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * furnished to do so, under the terms of the COPYING file.
17014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *
18014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch * KIND, either express or implied.
20014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch *
21014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ***************************************************************************/
22014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
23342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch#include "curl_setup.h"
2421efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch
2521efce637eb329c94f1323b6a2334a1c977e1a9dBen Murdoch#include <curl/curl.h>
26014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
27014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "urldata.h"
28014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "getinfo.h"
29014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
30014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "vtls/vtls.h"
311b268ca467c924004286c97bac133db489cf43d0Ben Murdoch#include "connect.h" /* Curl_getconnectinfo() */
32014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "progress.h"
33014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
34014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch/* The last #include files should be: */
35014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "curl_memory.h"
36014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "memdebug.h"
37014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
38/*
39 * This is supposed to be called in the beginning of a perform() session
40 * and should reset all session-info variables
41 */
42CURLcode Curl_initinfo(struct Curl_easy *data)
43{
44  struct Progress *pro = &data->progress;
45  struct PureInfo *info = &data->info;
46
47  pro->t_nslookup = 0;
48  pro->t_connect = 0;
49  pro->t_appconnect = 0;
50  pro->t_pretransfer = 0;
51  pro->t_starttransfer = 0;
52  pro->timespent = 0;
53  pro->t_redirect = 0;
54
55  info->httpcode = 0;
56  info->httpproxycode = 0;
57  info->httpversion = 0;
58  info->filetime = -1; /* -1 is an illegal time and thus means unknown */
59  info->timecond = FALSE;
60
61  free(info->contenttype);
62  info->contenttype = NULL;
63
64  info->header_size = 0;
65  info->request_size = 0;
66  info->numconnects = 0;
67
68  info->conn_primary_ip[0] = '\0';
69  info->conn_local_ip[0] = '\0';
70  info->conn_primary_port = 0;
71  info->conn_local_port = 0;
72
73  return CURLE_OK;
74}
75
76static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
77                             char **param_charp)
78{
79  switch(info) {
80  case CURLINFO_EFFECTIVE_URL:
81    *param_charp = data->change.url?data->change.url:(char *)"";
82    break;
83  case CURLINFO_CONTENT_TYPE:
84    *param_charp = data->info.contenttype;
85    break;
86  case CURLINFO_PRIVATE:
87    *param_charp = (char *) data->set.private_data;
88    break;
89  case CURLINFO_FTP_ENTRY_PATH:
90    /* Return the entrypath string from the most recent connection.
91       This pointer was copied from the connectdata structure by FTP.
92       The actual string may be free()ed by subsequent libcurl calls so
93       it must be copied to a safer area before the next libcurl call.
94       Callers must never free it themselves. */
95    *param_charp = data->state.most_recent_ftp_entrypath;
96    break;
97  case CURLINFO_REDIRECT_URL:
98    /* Return the URL this request would have been redirected to if that
99       option had been enabled! */
100    *param_charp = data->info.wouldredirect;
101    break;
102  case CURLINFO_PRIMARY_IP:
103    /* Return the ip address of the most recent (primary) connection */
104    *param_charp = data->info.conn_primary_ip;
105    break;
106  case CURLINFO_LOCAL_IP:
107    /* Return the source/local ip address of the most recent (primary)
108       connection */
109    *param_charp = data->info.conn_local_ip;
110    break;
111  case CURLINFO_RTSP_SESSION_ID:
112    *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
113    break;
114
115  default:
116    return CURLE_UNKNOWN_OPTION;
117  }
118
119  return CURLE_OK;
120}
121
122static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
123                             long *param_longp)
124{
125  curl_socket_t sockfd;
126
127  union {
128    unsigned long *to_ulong;
129    long          *to_long;
130  } lptr;
131
132  switch(info) {
133  case CURLINFO_RESPONSE_CODE:
134    *param_longp = data->info.httpcode;
135    break;
136  case CURLINFO_HTTP_CONNECTCODE:
137    *param_longp = data->info.httpproxycode;
138    break;
139  case CURLINFO_FILETIME:
140    *param_longp = data->info.filetime;
141    break;
142  case CURLINFO_HEADER_SIZE:
143    *param_longp = data->info.header_size;
144    break;
145  case CURLINFO_REQUEST_SIZE:
146    *param_longp = data->info.request_size;
147    break;
148  case CURLINFO_SSL_VERIFYRESULT:
149    *param_longp = data->set.ssl.certverifyresult;
150    break;
151  case CURLINFO_REDIRECT_COUNT:
152    *param_longp = data->set.followlocation;
153    break;
154  case CURLINFO_HTTPAUTH_AVAIL:
155    lptr.to_long = param_longp;
156    *lptr.to_ulong = data->info.httpauthavail;
157    break;
158  case CURLINFO_PROXYAUTH_AVAIL:
159    lptr.to_long = param_longp;
160    *lptr.to_ulong = data->info.proxyauthavail;
161    break;
162  case CURLINFO_OS_ERRNO:
163    *param_longp = data->state.os_errno;
164    break;
165  case CURLINFO_NUM_CONNECTS:
166    *param_longp = data->info.numconnects;
167    break;
168  case CURLINFO_LASTSOCKET:
169    sockfd = Curl_getconnectinfo(data, NULL);
170
171    /* note: this is not a good conversion for systems with 64 bit sockets and
172       32 bit longs */
173    if(sockfd != CURL_SOCKET_BAD)
174      *param_longp = (long)sockfd;
175    else
176      /* this interface is documented to return -1 in case of badness, which
177         may not be the same as the CURL_SOCKET_BAD value */
178      *param_longp = -1;
179    break;
180  case CURLINFO_PRIMARY_PORT:
181    /* Return the (remote) port of the most recent (primary) connection */
182    *param_longp = data->info.conn_primary_port;
183    break;
184  case CURLINFO_LOCAL_PORT:
185    /* Return the local port of the most recent (primary) connection */
186    *param_longp = data->info.conn_local_port;
187    break;
188  case CURLINFO_CONDITION_UNMET:
189    /* return if the condition prevented the document to get transferred */
190    *param_longp = data->info.timecond ? 1L : 0L;
191    break;
192  case CURLINFO_RTSP_CLIENT_CSEQ:
193    *param_longp = data->state.rtsp_next_client_CSeq;
194    break;
195  case CURLINFO_RTSP_SERVER_CSEQ:
196    *param_longp = data->state.rtsp_next_server_CSeq;
197    break;
198  case CURLINFO_RTSP_CSEQ_RECV:
199    *param_longp = data->state.rtsp_CSeq_recv;
200    break;
201  case CURLINFO_HTTP_VERSION:
202    switch (data->info.httpversion) {
203    case 10:
204      *param_longp = CURL_HTTP_VERSION_1_0;
205      break;
206    case 11:
207      *param_longp = CURL_HTTP_VERSION_1_1;
208      break;
209    case 20:
210      *param_longp = CURL_HTTP_VERSION_2_0;
211      break;
212    default:
213      *param_longp = CURL_HTTP_VERSION_NONE;
214      break;
215    }
216    break;
217
218  default:
219    return CURLE_UNKNOWN_OPTION;
220  }
221
222  return CURLE_OK;
223}
224
225static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
226                               double *param_doublep)
227{
228  switch(info) {
229  case CURLINFO_TOTAL_TIME:
230    *param_doublep = data->progress.timespent;
231    break;
232  case CURLINFO_NAMELOOKUP_TIME:
233    *param_doublep = data->progress.t_nslookup;
234    break;
235  case CURLINFO_CONNECT_TIME:
236    *param_doublep = data->progress.t_connect;
237    break;
238  case CURLINFO_APPCONNECT_TIME:
239    *param_doublep = data->progress.t_appconnect;
240    break;
241  case CURLINFO_PRETRANSFER_TIME:
242    *param_doublep =  data->progress.t_pretransfer;
243    break;
244  case CURLINFO_STARTTRANSFER_TIME:
245    *param_doublep = data->progress.t_starttransfer;
246    break;
247  case CURLINFO_SIZE_UPLOAD:
248    *param_doublep =  (double)data->progress.uploaded;
249    break;
250  case CURLINFO_SIZE_DOWNLOAD:
251    *param_doublep = (double)data->progress.downloaded;
252    break;
253  case CURLINFO_SPEED_DOWNLOAD:
254    *param_doublep =  (double)data->progress.dlspeed;
255    break;
256  case CURLINFO_SPEED_UPLOAD:
257    *param_doublep = (double)data->progress.ulspeed;
258    break;
259  case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
260    *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
261      (double)data->progress.size_dl:-1;
262    break;
263  case CURLINFO_CONTENT_LENGTH_UPLOAD:
264    *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
265      (double)data->progress.size_ul:-1;
266    break;
267  case CURLINFO_REDIRECT_TIME:
268    *param_doublep =  data->progress.t_redirect;
269    break;
270
271  default:
272    return CURLE_UNKNOWN_OPTION;
273  }
274
275  return CURLE_OK;
276}
277
278static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
279                              struct curl_slist **param_slistp)
280{
281  union {
282    struct curl_certinfo *to_certinfo;
283    struct curl_slist    *to_slist;
284  } ptr;
285
286  switch(info) {
287  case CURLINFO_SSL_ENGINES:
288    *param_slistp = Curl_ssl_engines_list(data);
289    break;
290  case CURLINFO_COOKIELIST:
291    *param_slistp = Curl_cookie_list(data);
292    break;
293  case CURLINFO_CERTINFO:
294    /* Return the a pointer to the certinfo struct. Not really an slist
295       pointer but we can pretend it is here */
296    ptr.to_certinfo = &data->info.certs;
297    *param_slistp = ptr.to_slist;
298    break;
299  case CURLINFO_TLS_SESSION:
300  case CURLINFO_TLS_SSL_PTR:
301    {
302      struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
303                                          param_slistp;
304      struct curl_tlssessioninfo *tsi = &data->tsi;
305      struct connectdata *conn = data->easy_conn;
306
307      *tsip = tsi;
308      tsi->backend = Curl_ssl_backend();
309      tsi->internals = NULL;
310
311      if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
312        unsigned int i;
313        for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
314          if(conn->ssl[i].use) {
315#if defined(USE_AXTLS)
316            tsi->internals = (void *)conn->ssl[i].ssl;
317#elif defined(USE_CYASSL)
318            tsi->internals = (void *)conn->ssl[i].handle;
319#elif defined(USE_DARWINSSL)
320            tsi->internals = (void *)conn->ssl[i].ssl_ctx;
321#elif defined(USE_GNUTLS)
322            tsi->internals = (void *)conn->ssl[i].session;
323#elif defined(USE_GSKIT)
324            tsi->internals = (void *)conn->ssl[i].handle;
325#elif defined(USE_MBEDTLS)
326            tsi->internals = (void *)&conn->ssl[i].ssl;
327#elif defined(USE_NSS)
328            tsi->internals = (void *)conn->ssl[i].handle;
329#elif defined(USE_OPENSSL)
330            /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
331            tsi->internals = ((info == CURLINFO_TLS_SESSION) ?
332                              (void *)conn->ssl[i].ctx :
333                              (void *)conn->ssl[i].handle);
334#elif defined(USE_POLARSSL)
335            tsi->internals = (void *)&conn->ssl[i].ssl;
336#elif defined(USE_SCHANNEL)
337            tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle;
338#elif defined(USE_SSL)
339#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR"
340#endif
341            break;
342          }
343        }
344      }
345    }
346    break;
347  default:
348    return CURLE_UNKNOWN_OPTION;
349  }
350
351  return CURLE_OK;
352}
353
354static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
355                               curl_socket_t *param_socketp)
356{
357  switch(info) {
358  case CURLINFO_ACTIVESOCKET:
359    *param_socketp = Curl_getconnectinfo(data, NULL);
360    break;
361  default:
362    return CURLE_UNKNOWN_OPTION;
363  }
364
365  return CURLE_OK;
366}
367
368CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
369{
370  va_list arg;
371  long *param_longp = NULL;
372  double *param_doublep = NULL;
373  char **param_charp = NULL;
374  struct curl_slist **param_slistp = NULL;
375  curl_socket_t *param_socketp = NULL;
376  int type;
377  CURLcode result = CURLE_UNKNOWN_OPTION;
378
379  if(!data)
380    return result;
381
382  va_start(arg, info);
383
384  type = CURLINFO_TYPEMASK & (int)info;
385  switch(type) {
386  case CURLINFO_STRING:
387    param_charp = va_arg(arg, char **);
388    if(param_charp)
389      result = getinfo_char(data, info, param_charp);
390    break;
391  case CURLINFO_LONG:
392    param_longp = va_arg(arg, long *);
393    if(param_longp)
394      result = getinfo_long(data, info, param_longp);
395    break;
396  case CURLINFO_DOUBLE:
397    param_doublep = va_arg(arg, double *);
398    if(param_doublep)
399      result = getinfo_double(data, info, param_doublep);
400    break;
401  case CURLINFO_SLIST:
402    param_slistp = va_arg(arg, struct curl_slist **);
403    if(param_slistp)
404      result = getinfo_slist(data, info, param_slistp);
405    break;
406  case CURLINFO_SOCKET:
407    param_socketp = va_arg(arg, curl_socket_t *);
408    if(param_socketp)
409      result = getinfo_socket(data, info, param_socketp);
410    break;
411  default:
412    break;
413  }
414
415  va_end(arg);
416
417  return result;
418}
419