1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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 https://curl.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 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25 #include "curl_setup.h"
26
27 #include <curl/curl.h>
28
29 #include "urldata.h"
30 #include "getinfo.h"
31
32 #include "vtls/vtls.h"
33 #include "connect.h" /* Curl_getconnectinfo() */
34 #include "progress.h"
35
36 /* The last #include files should be: */
37 #include "curl_memory.h"
38 #include "memdebug.h"
39
40 /*
41 * Initialize statistical and informational data.
42 *
43 * This function is called in curl_easy_reset, curl_easy_duphandle and at the
44 * beginning of a perform session. It must reset the session-info variables,
45 * in particular all variables in struct PureInfo.
46 */
Curl_initinfo(struct Curl_easy * data)47 CURLcode Curl_initinfo(struct Curl_easy *data)
48 {
49 struct Progress *pro = &data->progress;
50 struct PureInfo *info = &data->info;
51
52 pro->t_nslookup = 0;
53 pro->t_connect = 0;
54 pro->t_appconnect = 0;
55 pro->t_pretransfer = 0;
56 pro->t_starttransfer = 0;
57 pro->timespent = 0;
58 pro->t_redirect = 0;
59 pro->is_t_startransfer_set = false;
60
61 info->httpcode = 0;
62 info->httpproxycode = 0;
63 info->httpversion = 0;
64 info->filetime = -1; /* -1 is an illegal time and thus means unknown */
65 info->timecond = FALSE;
66
67 info->header_size = 0;
68 info->request_size = 0;
69 info->proxyauthavail = 0;
70 info->httpauthavail = 0;
71 info->numconnects = 0;
72
73 free(info->contenttype);
74 info->contenttype = NULL;
75
76 free(info->wouldredirect);
77 info->wouldredirect = NULL;
78
79 info->primary.remote_ip[0] = '\0';
80 info->primary.local_ip[0] = '\0';
81 info->primary.remote_port = 0;
82 info->primary.local_port = 0;
83 info->retry_after = 0;
84
85 info->conn_scheme = 0;
86 info->conn_protocol = 0;
87
88 #ifdef USE_SSL
89 Curl_ssl_free_certinfo(data);
90 #endif
91 return CURLE_OK;
92 }
93
getinfo_pchar(struct Curl_easy * data,CURLINFO info,const char *** param_pcharp)94 static CURLcode getinfo_pchar(struct Curl_easy *data, CURLINFO info,
95 const char ***param_pcharp) {
96 switch (info) {
97 case CURLINFO_CIPHERS:
98 *param_pcharp = data->ciphers;
99 break;
100 default:
101 break;
102 }
103 return CURLE_OK;
104 }
105
getinfo_char(struct Curl_easy * data,CURLINFO info,const char ** param_charp)106 static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
107 const char **param_charp)
108 {
109 switch(info) {
110 case CURLINFO_LAST_RECV_SSL_ERROR:
111 *param_charp = data->last_ssl_recv_err;
112 break;
113 case CURLINFO_LAST_SEND_SSL_ERROR:
114 *param_charp = data->last_ssl_send_err;
115 break;
116 case CURLINFO_SSL_ERROR:
117 *param_charp = data->ssl_err;
118 break;
119 case CURLINFO_EFFECTIVE_URL:
120 *param_charp = data->state.url?data->state.url:(char *)"";
121 break;
122 case CURLINFO_EFFECTIVE_METHOD: {
123 const char *m = data->set.str[STRING_CUSTOMREQUEST];
124 if(!m) {
125 if(data->set.opt_no_body)
126 m = "HEAD";
127 #ifndef CURL_DISABLE_HTTP
128 else {
129 switch(data->state.httpreq) {
130 case HTTPREQ_POST:
131 case HTTPREQ_POST_FORM:
132 case HTTPREQ_POST_MIME:
133 m = "POST";
134 break;
135 case HTTPREQ_PUT:
136 m = "PUT";
137 break;
138 default: /* this should never happen */
139 case HTTPREQ_GET:
140 m = "GET";
141 break;
142 case HTTPREQ_HEAD:
143 m = "HEAD";
144 break;
145 }
146 }
147 #endif
148 }
149 *param_charp = m;
150 }
151 break;
152 case CURLINFO_CONTENT_TYPE:
153 *param_charp = data->info.contenttype;
154 break;
155 case CURLINFO_PRIVATE:
156 *param_charp = (char *) data->set.private_data;
157 break;
158 case CURLINFO_FTP_ENTRY_PATH:
159 /* Return the entrypath string from the most recent connection.
160 This pointer was copied from the connectdata structure by FTP.
161 The actual string may be free()ed by subsequent libcurl calls so
162 it must be copied to a safer area before the next libcurl call.
163 Callers must never free it themselves. */
164 *param_charp = data->state.most_recent_ftp_entrypath;
165 break;
166 case CURLINFO_REDIRECT_URL:
167 /* Return the URL this request would have been redirected to if that
168 option had been enabled! */
169 *param_charp = data->info.wouldredirect;
170 break;
171 case CURLINFO_REFERER:
172 /* Return the referrer header for this request, or NULL if unset */
173 *param_charp = data->state.referer;
174 break;
175 case CURLINFO_PRIMARY_IP:
176 /* Return the ip address of the most recent (primary) connection */
177 *param_charp = data->info.primary.remote_ip;
178 break;
179 case CURLINFO_LOCAL_IP:
180 /* Return the source/local ip address of the most recent (primary)
181 connection */
182 *param_charp = data->info.primary.local_ip;
183 break;
184 case CURLINFO_RTSP_SESSION_ID:
185 #ifndef CURL_DISABLE_RTSP
186 *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
187 #else
188 *param_charp = NULL;
189 #endif
190 break;
191 case CURLINFO_SCHEME:
192 *param_charp = data->info.conn_scheme;
193 break;
194 case CURLINFO_CAPATH:
195 #ifdef CURL_CA_PATH
196 *param_charp = CURL_CA_PATH;
197 #else
198 *param_charp = NULL;
199 #endif
200 break;
201 case CURLINFO_CAINFO:
202 #ifdef CURL_CA_BUNDLE
203 *param_charp = CURL_CA_BUNDLE;
204 #else
205 *param_charp = NULL;
206 #endif
207 break;
208 default:
209 return CURLE_UNKNOWN_OPTION;
210 }
211
212 return CURLE_OK;
213 }
214
getinfo_long(struct Curl_easy * data,CURLINFO info,long * param_longp)215 static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
216 long *param_longp)
217 {
218 curl_socket_t sockfd;
219
220 union {
221 unsigned long *to_ulong;
222 long *to_long;
223 } lptr;
224
225 #ifdef DEBUGBUILD
226 char *timestr = getenv("CURL_TIME");
227 if(timestr) {
228 unsigned long val = strtol(timestr, NULL, 10);
229 switch(info) {
230 case CURLINFO_LOCAL_PORT:
231 *param_longp = (long)val;
232 return CURLE_OK;
233 default:
234 break;
235 }
236 }
237 /* use another variable for this to allow different values */
238 timestr = getenv("CURL_DEBUG_SIZE");
239 if(timestr) {
240 unsigned long val = strtol(timestr, NULL, 10);
241 switch(info) {
242 case CURLINFO_HEADER_SIZE:
243 case CURLINFO_REQUEST_SIZE:
244 *param_longp = (long)val;
245 return CURLE_OK;
246 default:
247 break;
248 }
249 }
250 #endif
251
252 switch(info) {
253 case CURLINFO_TCP_CONNECT_ERRNO:
254 *param_longp = data->tcp_connect_errno;
255 break;
256 case CURLINFO_SSL_CONNECT_ERRNO:
257 *param_longp = data->ssl_connect_errno;
258 break;
259 case CURLINFO_LAST_POLLIN_TIME:
260 *param_longp = 1000 * data->last_pollin_time.tv_sec + data->last_pollin_time.tv_usec / 1000;
261 break;
262 case CURLINFO_LAST_OS_POLLIN_TIME:
263 *param_longp = 1000 * data->last_os_pollin_time.tv_sec + data->last_os_pollin_time.tv_usec / 1000;
264 break;
265 case CURLINFO_LAST_POLLOUT_TIME:
266 *param_longp = 1000 * data->last_pollout_time.tv_sec + data->last_pollout_time.tv_usec / 1000;
267 break;
268 case CURLINFO_LAST_OS_POLLOUT_TIME:
269 *param_longp = 1000 * data->last_os_pollout_time.tv_sec + data->last_os_pollout_time.tv_usec / 1000;
270 break;
271 case CURLINFO_LAST_SSL_RECV_SIZE:
272 *param_longp = data->last_ssl_recv_size;
273 break;
274 case CURLINFO_LAST_SSL_SEND_SIZE:
275 *param_longp = data->last_ssl_send_size;
276 break;
277 case CURLINFO_TOTAL_SSL_RECV_SIZE:
278 *param_longp = data->total_ssl_recv_size;
279 break;
280 case CURLINFO_TOTAL_SSL_SEND_SIZE:
281 *param_longp = data->total_ssl_send_size;
282 break;
283 case CURLINFO_LAST_RECV_ERRNO:
284 *param_longp = data->last_recv_errno;
285 break;
286 case CURLINFO_LAST_SEND_ERRNO:
287 *param_longp = data->last_send_errno;
288 break;
289 case CURLINFO_CIPHER_NUM:
290 *param_longp = data->cipher_num;
291 break;
292 case CURLINFO_MIN_TLS_VERSION:
293 *param_longp = data->min_tls_version;
294 break;
295 case CURLINFO_MAX_TLS_VERSION:
296 *param_longp = data->max_tls_version;
297 break;
298 case CURLINFO_RESPONSE_CODE:
299 *param_longp = data->info.httpcode;
300 break;
301 case CURLINFO_HTTP_CONNECTCODE:
302 *param_longp = data->info.httpproxycode;
303 break;
304 case CURLINFO_FILETIME:
305 if(data->info.filetime > LONG_MAX)
306 *param_longp = LONG_MAX;
307 else if(data->info.filetime < LONG_MIN)
308 *param_longp = LONG_MIN;
309 else
310 *param_longp = (long)data->info.filetime;
311 break;
312 case CURLINFO_HEADER_SIZE:
313 *param_longp = (long)data->info.header_size;
314 break;
315 case CURLINFO_REQUEST_SIZE:
316 *param_longp = (long)data->info.request_size;
317 break;
318 case CURLINFO_SSL_VERIFYRESULT:
319 *param_longp = data->set.ssl.certverifyresult;
320 break;
321 #ifndef CURL_DISABLE_PROXY
322 case CURLINFO_PROXY_SSL_VERIFYRESULT:
323 *param_longp = data->set.proxy_ssl.certverifyresult;
324 break;
325 #endif
326 case CURLINFO_REDIRECT_COUNT:
327 *param_longp = data->state.followlocation;
328 break;
329 case CURLINFO_HTTPAUTH_AVAIL:
330 lptr.to_long = param_longp;
331 *lptr.to_ulong = data->info.httpauthavail;
332 break;
333 case CURLINFO_PROXYAUTH_AVAIL:
334 lptr.to_long = param_longp;
335 *lptr.to_ulong = data->info.proxyauthavail;
336 break;
337 case CURLINFO_OS_ERRNO:
338 *param_longp = data->state.os_errno;
339 break;
340 case CURLINFO_NUM_CONNECTS:
341 *param_longp = data->info.numconnects;
342 break;
343 case CURLINFO_LASTSOCKET:
344 sockfd = Curl_getconnectinfo(data, NULL);
345
346 /* note: this is not a good conversion for systems with 64 bit sockets and
347 32 bit longs */
348 if(sockfd != CURL_SOCKET_BAD)
349 *param_longp = (long)sockfd;
350 else
351 /* this interface is documented to return -1 in case of badness, which
352 may not be the same as the CURL_SOCKET_BAD value */
353 *param_longp = -1;
354 break;
355 case CURLINFO_PRIMARY_PORT:
356 /* Return the (remote) port of the most recent (primary) connection */
357 *param_longp = data->info.primary.remote_port;
358 break;
359 case CURLINFO_LOCAL_PORT:
360 /* Return the local port of the most recent (primary) connection */
361 *param_longp = data->info.primary.local_port;
362 break;
363 case CURLINFO_PROXY_ERROR:
364 *param_longp = (long)data->info.pxcode;
365 break;
366 case CURLINFO_CONDITION_UNMET:
367 if(data->info.httpcode == 304)
368 *param_longp = 1L;
369 else
370 /* return if the condition prevented the document to get transferred */
371 *param_longp = data->info.timecond ? 1L : 0L;
372 break;
373 #ifndef CURL_DISABLE_RTSP
374 case CURLINFO_RTSP_CLIENT_CSEQ:
375 *param_longp = data->state.rtsp_next_client_CSeq;
376 break;
377 case CURLINFO_RTSP_SERVER_CSEQ:
378 *param_longp = data->state.rtsp_next_server_CSeq;
379 break;
380 case CURLINFO_RTSP_CSEQ_RECV:
381 *param_longp = data->state.rtsp_CSeq_recv;
382 break;
383 #endif
384 case CURLINFO_HTTP_VERSION:
385 switch(data->info.httpversion) {
386 case 10:
387 *param_longp = CURL_HTTP_VERSION_1_0;
388 break;
389 case 11:
390 *param_longp = CURL_HTTP_VERSION_1_1;
391 break;
392 case 20:
393 *param_longp = CURL_HTTP_VERSION_2_0;
394 break;
395 case 30:
396 *param_longp = CURL_HTTP_VERSION_3;
397 break;
398 default:
399 *param_longp = CURL_HTTP_VERSION_NONE;
400 break;
401 }
402 break;
403 case CURLINFO_PROTOCOL:
404 *param_longp = data->info.conn_protocol;
405 break;
406 case CURLINFO_USED_PROXY:
407 *param_longp =
408 #ifdef CURL_DISABLE_PROXY
409 0
410 #else
411 data->info.used_proxy
412 #endif
413 ;
414 break;
415 default:
416 return CURLE_UNKNOWN_OPTION;
417 }
418
419 return CURLE_OK;
420 }
421
422 #define DOUBLE_SECS(x) (double)(x)/1000000
423
getinfo_offt(struct Curl_easy * data,CURLINFO info,curl_off_t * param_offt)424 static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
425 curl_off_t *param_offt)
426 {
427 #ifdef DEBUGBUILD
428 char *timestr = getenv("CURL_TIME");
429 if(timestr) {
430 unsigned long val = strtol(timestr, NULL, 10);
431 switch(info) {
432 case CURLINFO_TOTAL_TIME_T:
433 case CURLINFO_NAMELOOKUP_TIME_T:
434 case CURLINFO_CONNECT_TIME_T:
435 case CURLINFO_APPCONNECT_TIME_T:
436 case CURLINFO_PRETRANSFER_TIME_T:
437 case CURLINFO_STARTTRANSFER_TIME_T:
438 case CURLINFO_REDIRECT_TIME_T:
439 case CURLINFO_SPEED_DOWNLOAD_T:
440 case CURLINFO_SPEED_UPLOAD_T:
441 *param_offt = (curl_off_t)val;
442 return CURLE_OK;
443 default:
444 break;
445 }
446 }
447 #endif
448 switch(info) {
449 case CURLINFO_FILETIME_T:
450 *param_offt = (curl_off_t)data->info.filetime;
451 break;
452 case CURLINFO_SIZE_UPLOAD_T:
453 *param_offt = data->progress.uploaded;
454 break;
455 case CURLINFO_SIZE_DOWNLOAD_T:
456 *param_offt = data->progress.downloaded;
457 break;
458 case CURLINFO_SPEED_DOWNLOAD_T:
459 *param_offt = data->progress.dlspeed;
460 break;
461 case CURLINFO_SPEED_UPLOAD_T:
462 *param_offt = data->progress.ulspeed;
463 break;
464 case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
465 *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
466 data->progress.size_dl:-1;
467 break;
468 case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
469 *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
470 data->progress.size_ul:-1;
471 break;
472 case CURLINFO_TOTAL_TIME_T:
473 *param_offt = data->progress.timespent;
474 break;
475 case CURLINFO_NAMELOOKUP_TIME_T:
476 *param_offt = data->progress.t_nslookup;
477 break;
478 case CURLINFO_CONNECT_TIME_T:
479 *param_offt = data->progress.t_connect;
480 break;
481 case CURLINFO_APPCONNECT_TIME_T:
482 *param_offt = data->progress.t_appconnect;
483 break;
484 case CURLINFO_PRETRANSFER_TIME_T:
485 *param_offt = data->progress.t_pretransfer;
486 break;
487 case CURLINFO_STARTTRANSFER_TIME_T:
488 *param_offt = data->progress.t_starttransfer;
489 break;
490 case CURLINFO_QUEUE_TIME_T:
491 *param_offt = data->progress.t_postqueue;
492 break;
493 case CURLINFO_REDIRECT_TIME_T:
494 *param_offt = data->progress.t_redirect;
495 break;
496 case CURLINFO_RETRY_AFTER:
497 *param_offt = data->info.retry_after;
498 break;
499 case CURLINFO_XFER_ID:
500 *param_offt = data->id;
501 break;
502 case CURLINFO_CONN_ID:
503 *param_offt = data->conn?
504 data->conn->connection_id : data->state.recent_conn_id;
505 break;
506 default:
507 return CURLE_UNKNOWN_OPTION;
508 }
509
510 return CURLE_OK;
511 }
512
getinfo_double(struct Curl_easy * data,CURLINFO info,double * param_doublep)513 static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
514 double *param_doublep)
515 {
516 #ifdef DEBUGBUILD
517 char *timestr = getenv("CURL_TIME");
518 if(timestr) {
519 unsigned long val = strtol(timestr, NULL, 10);
520 switch(info) {
521 case CURLINFO_TOTAL_TIME:
522 case CURLINFO_NAMELOOKUP_TIME:
523 case CURLINFO_CONNECT_TIME:
524 case CURLINFO_APPCONNECT_TIME:
525 case CURLINFO_PRETRANSFER_TIME:
526 case CURLINFO_STARTTRANSFER_TIME:
527 case CURLINFO_REDIRECT_TIME:
528 case CURLINFO_SPEED_DOWNLOAD:
529 case CURLINFO_SPEED_UPLOAD:
530 *param_doublep = (double)val;
531 return CURLE_OK;
532 default:
533 break;
534 }
535 }
536 #endif
537 switch(info) {
538 case CURLINFO_TOTAL_TIME:
539 *param_doublep = DOUBLE_SECS(data->progress.timespent);
540 break;
541 case CURLINFO_NAMELOOKUP_TIME:
542 *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
543 break;
544 case CURLINFO_CONNECT_TIME:
545 *param_doublep = DOUBLE_SECS(data->progress.t_connect);
546 break;
547 case CURLINFO_APPCONNECT_TIME:
548 *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
549 break;
550 case CURLINFO_PRETRANSFER_TIME:
551 *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
552 break;
553 case CURLINFO_STARTTRANSFER_TIME:
554 *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
555 break;
556 case CURLINFO_SIZE_UPLOAD:
557 *param_doublep = (double)data->progress.uploaded;
558 break;
559 case CURLINFO_SIZE_DOWNLOAD:
560 *param_doublep = (double)data->progress.downloaded;
561 break;
562 case CURLINFO_SPEED_DOWNLOAD:
563 *param_doublep = (double)data->progress.dlspeed;
564 break;
565 case CURLINFO_SPEED_UPLOAD:
566 *param_doublep = (double)data->progress.ulspeed;
567 break;
568 case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
569 *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
570 (double)data->progress.size_dl:-1;
571 break;
572 case CURLINFO_CONTENT_LENGTH_UPLOAD:
573 *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
574 (double)data->progress.size_ul:-1;
575 break;
576 case CURLINFO_REDIRECT_TIME:
577 *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
578 break;
579
580 default:
581 return CURLE_UNKNOWN_OPTION;
582 }
583
584 return CURLE_OK;
585 }
586
getinfo_slist(struct Curl_easy * data,CURLINFO info,struct curl_slist ** param_slistp)587 static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
588 struct curl_slist **param_slistp)
589 {
590 union {
591 struct curl_certinfo *to_certinfo;
592 struct curl_slist *to_slist;
593 } ptr;
594
595 switch(info) {
596 case CURLINFO_SSL_ENGINES:
597 *param_slistp = Curl_ssl_engines_list(data);
598 break;
599 case CURLINFO_COOKIELIST:
600 *param_slistp = Curl_cookie_list(data);
601 break;
602 case CURLINFO_CERTINFO:
603 /* Return the a pointer to the certinfo struct. Not really an slist
604 pointer but we can pretend it is here */
605 ptr.to_certinfo = &data->info.certs;
606 *param_slistp = ptr.to_slist;
607 break;
608 case CURLINFO_TLS_SESSION:
609 case CURLINFO_TLS_SSL_PTR:
610 {
611 struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
612 param_slistp;
613 struct curl_tlssessioninfo *tsi = &data->tsi;
614 #ifdef USE_SSL
615 struct connectdata *conn = data->conn;
616 #endif
617
618 *tsip = tsi;
619 tsi->backend = Curl_ssl_backend();
620 tsi->internals = NULL;
621
622 #ifdef USE_SSL
623 if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
624 tsi->internals = Curl_ssl_get_internals(data, FIRSTSOCKET, info, 0);
625 }
626 #endif
627 }
628 break;
629 default:
630 return CURLE_UNKNOWN_OPTION;
631 }
632
633 return CURLE_OK;
634 }
635
getinfo_socket(struct Curl_easy * data,CURLINFO info,curl_socket_t * param_socketp)636 static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
637 curl_socket_t *param_socketp)
638 {
639 switch(info) {
640 case CURLINFO_ACTIVESOCKET:
641 *param_socketp = Curl_getconnectinfo(data, NULL);
642 break;
643 default:
644 return CURLE_UNKNOWN_OPTION;
645 }
646
647 return CURLE_OK;
648 }
649
Curl_getinfo(struct Curl_easy * data,CURLINFO info,...)650 CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
651 {
652 va_list arg;
653 long *param_longp = NULL;
654 double *param_doublep = NULL;
655 curl_off_t *param_offt = NULL;
656 const char **param_charp = NULL;
657 const char ***param_pcharp = NULL;
658 struct curl_slist **param_slistp = NULL;
659 curl_socket_t *param_socketp = NULL;
660 int type;
661 CURLcode result = CURLE_UNKNOWN_OPTION;
662
663 if(!data)
664 return CURLE_BAD_FUNCTION_ARGUMENT;
665
666 va_start(arg, info);
667
668 type = CURLINFO_TYPEMASK & (int)info;
669 switch(type) {
670 case CURLINFO_P_STRING:
671 param_pcharp = va_arg(arg, const char ***);
672 if(param_pcharp)
673 result = getinfo_pchar(data, info, param_pcharp);
674 break;
675 case CURLINFO_STRING:
676 param_charp = va_arg(arg, const char **);
677 if(param_charp)
678 result = getinfo_char(data, info, param_charp);
679 break;
680 case CURLINFO_LONG:
681 param_longp = va_arg(arg, long *);
682 if(param_longp)
683 result = getinfo_long(data, info, param_longp);
684 break;
685 case CURLINFO_DOUBLE:
686 param_doublep = va_arg(arg, double *);
687 if(param_doublep)
688 result = getinfo_double(data, info, param_doublep);
689 break;
690 case CURLINFO_OFF_T:
691 param_offt = va_arg(arg, curl_off_t *);
692 if(param_offt)
693 result = getinfo_offt(data, info, param_offt);
694 break;
695 case CURLINFO_SLIST:
696 param_slistp = va_arg(arg, struct curl_slist **);
697 if(param_slistp)
698 result = getinfo_slist(data, info, param_slistp);
699 break;
700 case CURLINFO_SOCKET:
701 param_socketp = va_arg(arg, curl_socket_t *);
702 if(param_socketp)
703 result = getinfo_socket(data, info, param_socketp);
704 break;
705 default:
706 break;
707 }
708
709 va_end(arg);
710
711 return result;
712 }
713