1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at http://curl.haxx.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #include <curl/curl.h>
26 
27 #include "urldata.h"
28 #include "getinfo.h"
29 
30 #include "vtls/vtls.h"
31 #include "connect.h" /* Curl_getconnectinfo() */
32 #include "progress.h"
33 
34 /* The last #include files should be: */
35 #include "curl_memory.h"
36 #include "memdebug.h"
37 
38 /*
39  * This is supposed to be called in the beginning of a perform() session
40  * and should reset all session-info variables
41  */
Curl_initinfo(struct SessionHandle * data)42 CURLcode Curl_initinfo(struct SessionHandle *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 
getinfo_char(struct SessionHandle * data,CURLINFO info,char ** param_charp)76 static CURLcode getinfo_char(struct SessionHandle *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_BAD_FUNCTION_ARGUMENT;
117   }
118 
119   return CURLE_OK;
120 }
121 
getinfo_long(struct SessionHandle * data,CURLINFO info,long * param_longp)122 static CURLcode getinfo_long(struct SessionHandle *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 
202   default:
203     return CURLE_BAD_FUNCTION_ARGUMENT;
204   }
205 
206   return CURLE_OK;
207 }
208 
getinfo_double(struct SessionHandle * data,CURLINFO info,double * param_doublep)209 static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info,
210                                double *param_doublep)
211 {
212   switch(info) {
213   case CURLINFO_TOTAL_TIME:
214     *param_doublep = data->progress.timespent;
215     break;
216   case CURLINFO_NAMELOOKUP_TIME:
217     *param_doublep = data->progress.t_nslookup;
218     break;
219   case CURLINFO_CONNECT_TIME:
220     *param_doublep = data->progress.t_connect;
221     break;
222   case CURLINFO_APPCONNECT_TIME:
223     *param_doublep = data->progress.t_appconnect;
224     break;
225   case CURLINFO_PRETRANSFER_TIME:
226     *param_doublep =  data->progress.t_pretransfer;
227     break;
228   case CURLINFO_STARTTRANSFER_TIME:
229     *param_doublep = data->progress.t_starttransfer;
230     break;
231   case CURLINFO_SIZE_UPLOAD:
232     *param_doublep =  (double)data->progress.uploaded;
233     break;
234   case CURLINFO_SIZE_DOWNLOAD:
235     *param_doublep = (double)data->progress.downloaded;
236     break;
237   case CURLINFO_SPEED_DOWNLOAD:
238     *param_doublep =  (double)data->progress.dlspeed;
239     break;
240   case CURLINFO_SPEED_UPLOAD:
241     *param_doublep = (double)data->progress.ulspeed;
242     break;
243   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
244     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
245       (double)data->progress.size_dl:-1;
246     break;
247   case CURLINFO_CONTENT_LENGTH_UPLOAD:
248     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
249       (double)data->progress.size_ul:-1;
250     break;
251   case CURLINFO_REDIRECT_TIME:
252     *param_doublep =  data->progress.t_redirect;
253     break;
254 
255   default:
256     return CURLE_BAD_FUNCTION_ARGUMENT;
257   }
258 
259   return CURLE_OK;
260 }
261 
getinfo_slist(struct SessionHandle * data,CURLINFO info,struct curl_slist ** param_slistp)262 static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info,
263                               struct curl_slist **param_slistp)
264 {
265   union {
266     struct curl_certinfo *to_certinfo;
267     struct curl_slist    *to_slist;
268   } ptr;
269 
270   switch(info) {
271   case CURLINFO_SSL_ENGINES:
272     *param_slistp = Curl_ssl_engines_list(data);
273     break;
274   case CURLINFO_COOKIELIST:
275     *param_slistp = Curl_cookie_list(data);
276     break;
277   case CURLINFO_CERTINFO:
278     /* Return the a pointer to the certinfo struct. Not really an slist
279        pointer but we can pretend it is here */
280     ptr.to_certinfo = &data->info.certs;
281     *param_slistp = ptr.to_slist;
282     break;
283   case CURLINFO_TLS_SESSION:
284     {
285       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
286                                           param_slistp;
287       struct curl_tlssessioninfo *tsi = &data->tsi;
288       struct connectdata *conn = data->easy_conn;
289       unsigned int sockindex = 0;
290       void *internals = NULL;
291 
292       *tsip = tsi;
293       tsi->backend = CURLSSLBACKEND_NONE;
294       tsi->internals = NULL;
295 
296       if(!conn)
297         break;
298 
299       /* Find the active ("in use") SSL connection, if any */
300       while((sockindex < sizeof(conn->ssl) / sizeof(conn->ssl[0])) &&
301             (!conn->ssl[sockindex].use))
302         sockindex++;
303 
304       if(sockindex == sizeof(conn->ssl) / sizeof(conn->ssl[0]))
305         break; /* no SSL session found */
306 
307       /* Return the TLS session information from the relevant backend */
308 #ifdef USE_OPENSSL
309       internals = conn->ssl[sockindex].ctx;
310 #endif
311 #ifdef USE_GNUTLS
312       internals = conn->ssl[sockindex].session;
313 #endif
314 #ifdef USE_NSS
315       internals = conn->ssl[sockindex].handle;
316 #endif
317 #ifdef USE_GSKIT
318       internals = conn->ssl[sockindex].handle;
319 #endif
320       if(internals) {
321         tsi->backend = Curl_ssl_backend();
322         tsi->internals = internals;
323       }
324       /* NOTE: For other SSL backends, it is not immediately clear what data
325          to return from 'struct ssl_connect_data'; thus, for now we keep the
326          backend as CURLSSLBACKEND_NONE in those cases, which should be
327          interpreted as "not supported" */
328     }
329     break;
330   default:
331     return CURLE_BAD_FUNCTION_ARGUMENT;
332   }
333 
334   return CURLE_OK;
335 }
336 
Curl_getinfo(struct SessionHandle * data,CURLINFO info,...)337 CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
338 {
339   va_list arg;
340   long *param_longp = NULL;
341   double *param_doublep = NULL;
342   char **param_charp = NULL;
343   struct curl_slist **param_slistp = NULL;
344   int type;
345   /* default return code is to error out! */
346   CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
347 
348   if(!data)
349     return result;
350 
351   va_start(arg, info);
352 
353   type = CURLINFO_TYPEMASK & (int)info;
354   switch(type) {
355   case CURLINFO_STRING:
356     param_charp = va_arg(arg, char **);
357     if(param_charp)
358       result = getinfo_char(data, info, param_charp);
359     break;
360   case CURLINFO_LONG:
361     param_longp = va_arg(arg, long *);
362     if(param_longp)
363       result = getinfo_long(data, info, param_longp);
364     break;
365   case CURLINFO_DOUBLE:
366     param_doublep = va_arg(arg, double *);
367     if(param_doublep)
368       result = getinfo_double(data, info, param_doublep);
369     break;
370   case CURLINFO_SLIST:
371     param_slistp = va_arg(arg, struct curl_slist **);
372     if(param_slistp)
373       result = getinfo_slist(data, info, param_slistp);
374     break;
375   default:
376     break;
377   }
378 
379   va_end(arg);
380 
381   return result;
382 }
383