1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel (at) 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.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 */ 42 CURLcode 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 76 static 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 122 static 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 225 static 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 278 static 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 354 static 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 368 CURLcode 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