1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2010, 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 "setup.h"
24
25#include <curl/curl.h>
26
27#include "urldata.h"
28#include "getinfo.h"
29
30#include <stdio.h>
31#include <string.h>
32#include <stdarg.h>
33#include <stdlib.h>
34#include "curl_memory.h"
35#include "sslgen.h"
36#include "connect.h" /* Curl_getconnectinfo() */
37#include "progress.h"
38
39/* Make this the last #include */
40#include "memdebug.h"
41
42/*
43 * This is supposed to be called in the beginning of a perform() session
44 * and should reset all session-info variables
45 */
46CURLcode Curl_initinfo(struct SessionHandle *data)
47{
48  struct Progress *pro = &data->progress;
49  struct PureInfo *info =&data->info;
50
51  pro->t_nslookup = 0;
52  pro->t_connect = 0;
53  pro->t_pretransfer = 0;
54  pro->t_starttransfer = 0;
55  pro->timespent = 0;
56  pro->t_redirect = 0;
57
58  info->httpcode = 0;
59  info->httpversion=0;
60  info->filetime=-1; /* -1 is an illegal time and thus means unknown */
61
62  if(info->contenttype)
63    free(info->contenttype);
64  info->contenttype = NULL;
65
66  info->header_size = 0;
67  info->request_size = 0;
68  info->numconnects = 0;
69
70  info->conn_primary_ip[0] = '\0';
71  info->conn_local_ip[0] = '\0';
72  info->conn_primary_port = 0;
73  info->conn_local_port = 0;
74
75  return CURLE_OK;
76}
77
78CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
79{
80  va_list arg;
81  long *param_longp=NULL;
82  double *param_doublep=NULL;
83  char **param_charp=NULL;
84  struct curl_slist **param_slistp=NULL;
85  int type;
86  curl_socket_t sockfd;
87
88  union {
89    struct curl_certinfo * to_certinfo;
90    struct curl_slist    * to_slist;
91  } ptr;
92
93  if(!data)
94    return CURLE_BAD_FUNCTION_ARGUMENT;
95
96  va_start(arg, info);
97
98  type = CURLINFO_TYPEMASK & (int)info;
99  switch(type) {
100  case CURLINFO_STRING:
101    param_charp = va_arg(arg, char **);
102    if(NULL == param_charp)
103      return CURLE_BAD_FUNCTION_ARGUMENT;
104    break;
105  case CURLINFO_LONG:
106    param_longp = va_arg(arg, long *);
107    if(NULL == param_longp)
108      return CURLE_BAD_FUNCTION_ARGUMENT;
109    break;
110  case CURLINFO_DOUBLE:
111    param_doublep = va_arg(arg, double *);
112    if(NULL == param_doublep)
113      return CURLE_BAD_FUNCTION_ARGUMENT;
114    break;
115  case CURLINFO_SLIST:
116    param_slistp = va_arg(arg, struct curl_slist **);
117    if(NULL == param_slistp)
118      return CURLE_BAD_FUNCTION_ARGUMENT;
119    break;
120  default:
121    return CURLE_BAD_FUNCTION_ARGUMENT;
122  }
123
124  switch(info) {
125  case CURLINFO_EFFECTIVE_URL:
126    *param_charp = data->change.url?data->change.url:(char *)"";
127    break;
128  case CURLINFO_RESPONSE_CODE:
129    *param_longp = data->info.httpcode;
130    break;
131  case CURLINFO_HTTP_CONNECTCODE:
132    *param_longp = data->info.httpproxycode;
133    break;
134  case CURLINFO_FILETIME:
135    *param_longp = data->info.filetime;
136    break;
137  case CURLINFO_HEADER_SIZE:
138    *param_longp = data->info.header_size;
139    break;
140  case CURLINFO_REQUEST_SIZE:
141    *param_longp = data->info.request_size;
142    break;
143  case CURLINFO_TOTAL_TIME:
144    *param_doublep = data->progress.timespent;
145    break;
146  case CURLINFO_NAMELOOKUP_TIME:
147    *param_doublep = data->progress.t_nslookup;
148    break;
149  case CURLINFO_CONNECT_TIME:
150    *param_doublep = data->progress.t_connect;
151    break;
152  case CURLINFO_APPCONNECT_TIME:
153    *param_doublep = data->progress.t_appconnect;
154    break;
155  case CURLINFO_PRETRANSFER_TIME:
156    *param_doublep =  data->progress.t_pretransfer;
157    break;
158  case CURLINFO_STARTTRANSFER_TIME:
159    *param_doublep = data->progress.t_starttransfer;
160    break;
161  case CURLINFO_SIZE_UPLOAD:
162    *param_doublep =  (double)data->progress.uploaded;
163    break;
164  case CURLINFO_SIZE_DOWNLOAD:
165    *param_doublep = (double)data->progress.downloaded;
166    break;
167  case CURLINFO_SPEED_DOWNLOAD:
168    *param_doublep =  (double)data->progress.dlspeed;
169    break;
170  case CURLINFO_SPEED_UPLOAD:
171    *param_doublep = (double)data->progress.ulspeed;
172    break;
173  case CURLINFO_SSL_VERIFYRESULT:
174    *param_longp = data->set.ssl.certverifyresult;
175    break;
176  case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
177    *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
178      (double)data->progress.size_dl:-1;
179    break;
180  case CURLINFO_CONTENT_LENGTH_UPLOAD:
181    *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
182      (double)data->progress.size_ul:-1;
183    break;
184  case CURLINFO_REDIRECT_TIME:
185    *param_doublep =  data->progress.t_redirect;
186    break;
187  case CURLINFO_REDIRECT_COUNT:
188    *param_longp = data->set.followlocation;
189    break;
190  case CURLINFO_CONTENT_TYPE:
191    *param_charp = data->info.contenttype;
192    break;
193  case CURLINFO_PRIVATE:
194    *param_charp = (char *) data->set.private_data;
195    break;
196  case CURLINFO_HTTPAUTH_AVAIL:
197    *param_longp = data->info.httpauthavail;
198    break;
199  case CURLINFO_PROXYAUTH_AVAIL:
200    *param_longp = data->info.proxyauthavail;
201    break;
202  case CURLINFO_OS_ERRNO:
203    *param_longp = data->state.os_errno;
204    break;
205  case CURLINFO_NUM_CONNECTS:
206    *param_longp = data->info.numconnects;
207    break;
208  case CURLINFO_SSL_ENGINES:
209    *param_slistp = Curl_ssl_engines_list(data);
210    break;
211  case CURLINFO_COOKIELIST:
212    *param_slistp = Curl_cookie_list(data);
213    break;
214  case CURLINFO_FTP_ENTRY_PATH:
215    /* Return the entrypath string from the most recent connection.
216       This pointer was copied from the connectdata structure by FTP.
217       The actual string may be free()ed by subsequent libcurl calls so
218       it must be copied to a safer area before the next libcurl call.
219       Callers must never free it themselves. */
220    *param_charp = data->state.most_recent_ftp_entrypath;
221    break;
222  case CURLINFO_LASTSOCKET:
223    sockfd = Curl_getconnectinfo(data, NULL);
224
225    /* note: this is not a good conversion for systems with 64 bit sockets and
226       32 bit longs */
227    if(sockfd != CURL_SOCKET_BAD)
228      *param_longp = (long)sockfd;
229    else
230      /* this interface is documented to return -1 in case of badness, which
231         may not be the same as the CURL_SOCKET_BAD value */
232      *param_longp = -1;
233    break;
234  case CURLINFO_REDIRECT_URL:
235    /* Return the URL this request would have been redirected to if that
236       option had been enabled! */
237    *param_charp = data->info.wouldredirect;
238    break;
239  case CURLINFO_PRIMARY_IP:
240    /* Return the ip address of the most recent (primary) connection */
241    *param_charp = data->info.conn_primary_ip;
242    break;
243  case CURLINFO_PRIMARY_PORT:
244    /* Return the (remote) port of the most recent (primary) connection */
245    *param_longp = data->info.conn_primary_port;
246    break;
247  case CURLINFO_LOCAL_IP:
248    /* Return the source/local ip address of the most recent (primary)
249       connection */
250    *param_charp = data->info.conn_local_ip;
251    break;
252  case CURLINFO_LOCAL_PORT:
253    /* Return the local port of the most recent (primary) connection */
254    *param_longp = data->info.conn_local_port;
255    break;
256  case CURLINFO_CERTINFO:
257    /* Return the a pointer to the certinfo struct. Not really an slist
258       pointer but we can pretend it is here */
259    ptr.to_certinfo = &data->info.certs;
260    *param_slistp = ptr.to_slist;
261    break;
262  case CURLINFO_CONDITION_UNMET:
263    /* return if the condition prevented the document to get transferred */
264    *param_longp = data->info.timecond;
265    break;
266  case CURLINFO_RTSP_SESSION_ID:
267    *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
268    break;
269  case CURLINFO_RTSP_CLIENT_CSEQ:
270    *param_longp = data->state.rtsp_next_client_CSeq;
271    break;
272  case CURLINFO_RTSP_SERVER_CSEQ:
273    *param_longp = data->state.rtsp_next_server_CSeq;
274    break;
275  case CURLINFO_RTSP_CSEQ_RECV:
276    *param_longp = data->state.rtsp_CSeq_recv;
277    break;
278
279  default:
280    return CURLE_BAD_FUNCTION_ARGUMENT;
281  }
282  return CURLE_OK;
283}
284