File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / getinfo.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    1: /***************************************************************************
    2:  *                                  _   _ ____  _
    3:  *  Project                     ___| | | |  _ \| |
    4:  *                             / __| | | | |_) | |
    5:  *                            | (__| |_| |  _ <| |___
    6:  *                             \___|\___/|_| \_\_____|
    7:  *
    8:  * Copyright (C) 1998 - 2020, 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.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:  * Initialize statistical and informational data.
   40:  *
   41:  * This function is called in curl_easy_reset, curl_easy_duphandle and at the
   42:  * beginning of a perform session. It must reset the session-info variables,
   43:  * in particular all variables in struct PureInfo.
   44:  */
   45: CURLcode Curl_initinfo(struct Curl_easy *data)
   46: {
   47:   struct Progress *pro = &data->progress;
   48:   struct PureInfo *info = &data->info;
   49: 
   50:   pro->t_nslookup = 0;
   51:   pro->t_connect = 0;
   52:   pro->t_appconnect = 0;
   53:   pro->t_pretransfer = 0;
   54:   pro->t_starttransfer = 0;
   55:   pro->timespent = 0;
   56:   pro->t_redirect = 0;
   57:   pro->is_t_startransfer_set = false;
   58: 
   59:   info->httpcode = 0;
   60:   info->httpproxycode = 0;
   61:   info->httpversion = 0;
   62:   info->filetime = -1; /* -1 is an illegal time and thus means unknown */
   63:   info->timecond = FALSE;
   64: 
   65:   info->header_size = 0;
   66:   info->request_size = 0;
   67:   info->proxyauthavail = 0;
   68:   info->httpauthavail = 0;
   69:   info->numconnects = 0;
   70: 
   71:   free(info->contenttype);
   72:   info->contenttype = NULL;
   73: 
   74:   free(info->wouldredirect);
   75:   info->wouldredirect = NULL;
   76: 
   77:   info->conn_primary_ip[0] = '\0';
   78:   info->conn_local_ip[0] = '\0';
   79:   info->conn_primary_port = 0;
   80:   info->conn_local_port = 0;
   81: 
   82:   info->conn_scheme = 0;
   83:   info->conn_protocol = 0;
   84: 
   85: #ifdef USE_SSL
   86:   Curl_ssl_free_certinfo(data);
   87: #endif
   88:   return CURLE_OK;
   89: }
   90: 
   91: static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
   92:                              const char **param_charp)
   93: {
   94:   switch(info) {
   95:   case CURLINFO_EFFECTIVE_URL:
   96:     *param_charp = data->change.url?data->change.url:(char *)"";
   97:     break;
   98:   case CURLINFO_CONTENT_TYPE:
   99:     *param_charp = data->info.contenttype;
  100:     break;
  101:   case CURLINFO_PRIVATE:
  102:     *param_charp = (char *) data->set.private_data;
  103:     break;
  104:   case CURLINFO_FTP_ENTRY_PATH:
  105:     /* Return the entrypath string from the most recent connection.
  106:        This pointer was copied from the connectdata structure by FTP.
  107:        The actual string may be free()ed by subsequent libcurl calls so
  108:        it must be copied to a safer area before the next libcurl call.
  109:        Callers must never free it themselves. */
  110:     *param_charp = data->state.most_recent_ftp_entrypath;
  111:     break;
  112:   case CURLINFO_REDIRECT_URL:
  113:     /* Return the URL this request would have been redirected to if that
  114:        option had been enabled! */
  115:     *param_charp = data->info.wouldredirect;
  116:     break;
  117:   case CURLINFO_PRIMARY_IP:
  118:     /* Return the ip address of the most recent (primary) connection */
  119:     *param_charp = data->info.conn_primary_ip;
  120:     break;
  121:   case CURLINFO_LOCAL_IP:
  122:     /* Return the source/local ip address of the most recent (primary)
  123:        connection */
  124:     *param_charp = data->info.conn_local_ip;
  125:     break;
  126:   case CURLINFO_RTSP_SESSION_ID:
  127:     *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
  128:     break;
  129:   case CURLINFO_SCHEME:
  130:     *param_charp = data->info.conn_scheme;
  131:     break;
  132: 
  133:   default:
  134:     return CURLE_UNKNOWN_OPTION;
  135:   }
  136: 
  137:   return CURLE_OK;
  138: }
  139: 
  140: static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
  141:                              long *param_longp)
  142: {
  143:   curl_socket_t sockfd;
  144: 
  145:   union {
  146:     unsigned long *to_ulong;
  147:     long          *to_long;
  148:   } lptr;
  149: 
  150: #ifdef DEBUGBUILD
  151:   char *timestr = getenv("CURL_TIME");
  152:   if(timestr) {
  153:     unsigned long val = strtol(timestr, NULL, 10);
  154:     switch(info) {
  155:     case CURLINFO_LOCAL_PORT:
  156:       *param_longp = (long)val;
  157:       return CURLE_OK;
  158:     default:
  159:       break;
  160:     }
  161:   }
  162:   /* use another variable for this to allow different values */
  163:   timestr = getenv("CURL_DEBUG_SIZE");
  164:   if(timestr) {
  165:     unsigned long val = strtol(timestr, NULL, 10);
  166:     switch(info) {
  167:     case CURLINFO_HEADER_SIZE:
  168:     case CURLINFO_REQUEST_SIZE:
  169:       *param_longp = (long)val;
  170:       return CURLE_OK;
  171:     default:
  172:       break;
  173:     }
  174:   }
  175: #endif
  176: 
  177:   switch(info) {
  178:   case CURLINFO_RESPONSE_CODE:
  179:     *param_longp = data->info.httpcode;
  180:     break;
  181:   case CURLINFO_HTTP_CONNECTCODE:
  182:     *param_longp = data->info.httpproxycode;
  183:     break;
  184:   case CURLINFO_FILETIME:
  185:     if(data->info.filetime > LONG_MAX)
  186:       *param_longp = LONG_MAX;
  187:     else if(data->info.filetime < LONG_MIN)
  188:       *param_longp = LONG_MIN;
  189:     else
  190:       *param_longp = (long)data->info.filetime;
  191:     break;
  192:   case CURLINFO_HEADER_SIZE:
  193:     *param_longp = (long)data->info.header_size;
  194:     break;
  195:   case CURLINFO_REQUEST_SIZE:
  196:     *param_longp = (long)data->info.request_size;
  197:     break;
  198:   case CURLINFO_SSL_VERIFYRESULT:
  199:     *param_longp = data->set.ssl.certverifyresult;
  200:     break;
  201:   case CURLINFO_PROXY_SSL_VERIFYRESULT:
  202:     *param_longp = data->set.proxy_ssl.certverifyresult;
  203:     break;
  204:   case CURLINFO_REDIRECT_COUNT:
  205:     *param_longp = data->set.followlocation;
  206:     break;
  207:   case CURLINFO_HTTPAUTH_AVAIL:
  208:     lptr.to_long = param_longp;
  209:     *lptr.to_ulong = data->info.httpauthavail;
  210:     break;
  211:   case CURLINFO_PROXYAUTH_AVAIL:
  212:     lptr.to_long = param_longp;
  213:     *lptr.to_ulong = data->info.proxyauthavail;
  214:     break;
  215:   case CURLINFO_OS_ERRNO:
  216:     *param_longp = data->state.os_errno;
  217:     break;
  218:   case CURLINFO_NUM_CONNECTS:
  219:     *param_longp = data->info.numconnects;
  220:     break;
  221:   case CURLINFO_LASTSOCKET:
  222:     sockfd = Curl_getconnectinfo(data, NULL);
  223: 
  224:     /* note: this is not a good conversion for systems with 64 bit sockets and
  225:        32 bit longs */
  226:     if(sockfd != CURL_SOCKET_BAD)
  227:       *param_longp = (long)sockfd;
  228:     else
  229:       /* this interface is documented to return -1 in case of badness, which
  230:          may not be the same as the CURL_SOCKET_BAD value */
  231:       *param_longp = -1;
  232:     break;
  233:   case CURLINFO_PRIMARY_PORT:
  234:     /* Return the (remote) port of the most recent (primary) connection */
  235:     *param_longp = data->info.conn_primary_port;
  236:     break;
  237:   case CURLINFO_LOCAL_PORT:
  238:     /* Return the local port of the most recent (primary) connection */
  239:     *param_longp = data->info.conn_local_port;
  240:     break;
  241:   case CURLINFO_CONDITION_UNMET:
  242:     if(data->info.httpcode == 304)
  243:       *param_longp = 1L;
  244:     else
  245:       /* return if the condition prevented the document to get transferred */
  246:       *param_longp = data->info.timecond ? 1L : 0L;
  247:     break;
  248:   case CURLINFO_RTSP_CLIENT_CSEQ:
  249:     *param_longp = data->state.rtsp_next_client_CSeq;
  250:     break;
  251:   case CURLINFO_RTSP_SERVER_CSEQ:
  252:     *param_longp = data->state.rtsp_next_server_CSeq;
  253:     break;
  254:   case CURLINFO_RTSP_CSEQ_RECV:
  255:     *param_longp = data->state.rtsp_CSeq_recv;
  256:     break;
  257:   case CURLINFO_HTTP_VERSION:
  258:     switch(data->info.httpversion) {
  259:     case 10:
  260:       *param_longp = CURL_HTTP_VERSION_1_0;
  261:       break;
  262:     case 11:
  263:       *param_longp = CURL_HTTP_VERSION_1_1;
  264:       break;
  265:     case 20:
  266:       *param_longp = CURL_HTTP_VERSION_2_0;
  267:       break;
  268:     case 30:
  269:       *param_longp = CURL_HTTP_VERSION_3;
  270:       break;
  271:     default:
  272:       *param_longp = CURL_HTTP_VERSION_NONE;
  273:       break;
  274:     }
  275:     break;
  276:   case CURLINFO_PROTOCOL:
  277:     *param_longp = data->info.conn_protocol;
  278:     break;
  279:   default:
  280:     return CURLE_UNKNOWN_OPTION;
  281:   }
  282: 
  283:   return CURLE_OK;
  284: }
  285: 
  286: #define DOUBLE_SECS(x) (double)(x)/1000000
  287: 
  288: static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
  289:                              curl_off_t *param_offt)
  290: {
  291: #ifdef DEBUGBUILD
  292:   char *timestr = getenv("CURL_TIME");
  293:   if(timestr) {
  294:     unsigned long val = strtol(timestr, NULL, 10);
  295:     switch(info) {
  296:     case CURLINFO_TOTAL_TIME_T:
  297:     case CURLINFO_NAMELOOKUP_TIME_T:
  298:     case CURLINFO_CONNECT_TIME_T:
  299:     case CURLINFO_APPCONNECT_TIME_T:
  300:     case CURLINFO_PRETRANSFER_TIME_T:
  301:     case CURLINFO_STARTTRANSFER_TIME_T:
  302:     case CURLINFO_REDIRECT_TIME_T:
  303:     case CURLINFO_SPEED_DOWNLOAD_T:
  304:     case CURLINFO_SPEED_UPLOAD_T:
  305:       *param_offt = (curl_off_t)val;
  306:       return CURLE_OK;
  307:     default:
  308:       break;
  309:     }
  310:   }
  311: #endif
  312:   switch(info) {
  313:   case CURLINFO_FILETIME_T:
  314:     *param_offt = (curl_off_t)data->info.filetime;
  315:     break;
  316:   case CURLINFO_SIZE_UPLOAD_T:
  317:     *param_offt = data->progress.uploaded;
  318:     break;
  319:   case CURLINFO_SIZE_DOWNLOAD_T:
  320:     *param_offt = data->progress.downloaded;
  321:     break;
  322:   case CURLINFO_SPEED_DOWNLOAD_T:
  323:     *param_offt =  data->progress.dlspeed;
  324:     break;
  325:   case CURLINFO_SPEED_UPLOAD_T:
  326:     *param_offt = data->progress.ulspeed;
  327:     break;
  328:   case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
  329:     *param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
  330:       data->progress.size_dl:-1;
  331:     break;
  332:   case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
  333:     *param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
  334:       data->progress.size_ul:-1;
  335:     break;
  336:    case CURLINFO_TOTAL_TIME_T:
  337:     *param_offt = data->progress.timespent;
  338:     break;
  339:   case CURLINFO_NAMELOOKUP_TIME_T:
  340:     *param_offt = data->progress.t_nslookup;
  341:     break;
  342:   case CURLINFO_CONNECT_TIME_T:
  343:     *param_offt = data->progress.t_connect;
  344:     break;
  345:   case CURLINFO_APPCONNECT_TIME_T:
  346:     *param_offt = data->progress.t_appconnect;
  347:     break;
  348:   case CURLINFO_PRETRANSFER_TIME_T:
  349:     *param_offt = data->progress.t_pretransfer;
  350:     break;
  351:   case CURLINFO_STARTTRANSFER_TIME_T:
  352:     *param_offt = data->progress.t_starttransfer;
  353:     break;
  354:   case CURLINFO_REDIRECT_TIME_T:
  355:     *param_offt = data->progress.t_redirect;
  356:     break;
  357:   case CURLINFO_RETRY_AFTER:
  358:     *param_offt = data->info.retry_after;
  359:     break;
  360:   default:
  361:     return CURLE_UNKNOWN_OPTION;
  362:   }
  363: 
  364:   return CURLE_OK;
  365: }
  366: 
  367: static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
  368:                                double *param_doublep)
  369: {
  370: #ifdef DEBUGBUILD
  371:   char *timestr = getenv("CURL_TIME");
  372:   if(timestr) {
  373:     unsigned long val = strtol(timestr, NULL, 10);
  374:     switch(info) {
  375:     case CURLINFO_TOTAL_TIME:
  376:     case CURLINFO_NAMELOOKUP_TIME:
  377:     case CURLINFO_CONNECT_TIME:
  378:     case CURLINFO_APPCONNECT_TIME:
  379:     case CURLINFO_PRETRANSFER_TIME:
  380:     case CURLINFO_STARTTRANSFER_TIME:
  381:     case CURLINFO_REDIRECT_TIME:
  382:     case CURLINFO_SPEED_DOWNLOAD:
  383:     case CURLINFO_SPEED_UPLOAD:
  384:       *param_doublep = (double)val;
  385:       return CURLE_OK;
  386:     default:
  387:       break;
  388:     }
  389:   }
  390: #endif
  391:   switch(info) {
  392:   case CURLINFO_TOTAL_TIME:
  393:     *param_doublep = DOUBLE_SECS(data->progress.timespent);
  394:     break;
  395:   case CURLINFO_NAMELOOKUP_TIME:
  396:     *param_doublep = DOUBLE_SECS(data->progress.t_nslookup);
  397:     break;
  398:   case CURLINFO_CONNECT_TIME:
  399:     *param_doublep = DOUBLE_SECS(data->progress.t_connect);
  400:     break;
  401:   case CURLINFO_APPCONNECT_TIME:
  402:     *param_doublep = DOUBLE_SECS(data->progress.t_appconnect);
  403:     break;
  404:   case CURLINFO_PRETRANSFER_TIME:
  405:     *param_doublep = DOUBLE_SECS(data->progress.t_pretransfer);
  406:     break;
  407:   case CURLINFO_STARTTRANSFER_TIME:
  408:     *param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
  409:     break;
  410:   case CURLINFO_SIZE_UPLOAD:
  411:     *param_doublep =  (double)data->progress.uploaded;
  412:     break;
  413:   case CURLINFO_SIZE_DOWNLOAD:
  414:     *param_doublep = (double)data->progress.downloaded;
  415:     break;
  416:   case CURLINFO_SPEED_DOWNLOAD:
  417:     *param_doublep =  (double)data->progress.dlspeed;
  418:     break;
  419:   case CURLINFO_SPEED_UPLOAD:
  420:     *param_doublep = (double)data->progress.ulspeed;
  421:     break;
  422:   case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
  423:     *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
  424:       (double)data->progress.size_dl:-1;
  425:     break;
  426:   case CURLINFO_CONTENT_LENGTH_UPLOAD:
  427:     *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
  428:       (double)data->progress.size_ul:-1;
  429:     break;
  430:   case CURLINFO_REDIRECT_TIME:
  431:     *param_doublep = DOUBLE_SECS(data->progress.t_redirect);
  432:     break;
  433: 
  434:   default:
  435:     return CURLE_UNKNOWN_OPTION;
  436:   }
  437: 
  438:   return CURLE_OK;
  439: }
  440: 
  441: static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
  442:                               struct curl_slist **param_slistp)
  443: {
  444:   union {
  445:     struct curl_certinfo *to_certinfo;
  446:     struct curl_slist    *to_slist;
  447:   } ptr;
  448: 
  449:   switch(info) {
  450:   case CURLINFO_SSL_ENGINES:
  451:     *param_slistp = Curl_ssl_engines_list(data);
  452:     break;
  453:   case CURLINFO_COOKIELIST:
  454:     *param_slistp = Curl_cookie_list(data);
  455:     break;
  456:   case CURLINFO_CERTINFO:
  457:     /* Return the a pointer to the certinfo struct. Not really an slist
  458:        pointer but we can pretend it is here */
  459:     ptr.to_certinfo = &data->info.certs;
  460:     *param_slistp = ptr.to_slist;
  461:     break;
  462:   case CURLINFO_TLS_SESSION:
  463:   case CURLINFO_TLS_SSL_PTR:
  464:     {
  465:       struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
  466:                                           param_slistp;
  467:       struct curl_tlssessioninfo *tsi = &data->tsi;
  468: #ifdef USE_SSL
  469:       struct connectdata *conn = data->conn;
  470: #endif
  471: 
  472:       *tsip = tsi;
  473:       tsi->backend = Curl_ssl_backend();
  474:       tsi->internals = NULL;
  475: 
  476: #ifdef USE_SSL
  477:       if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
  478:         unsigned int i;
  479:         for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
  480:           if(conn->ssl[i].use) {
  481:             tsi->internals = Curl_ssl->get_internals(&conn->ssl[i], info);
  482:             break;
  483:           }
  484:         }
  485:       }
  486: #endif
  487:     }
  488:     break;
  489:   default:
  490:     return CURLE_UNKNOWN_OPTION;
  491:   }
  492: 
  493:   return CURLE_OK;
  494: }
  495: 
  496: static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
  497:                                curl_socket_t *param_socketp)
  498: {
  499:   switch(info) {
  500:   case CURLINFO_ACTIVESOCKET:
  501:     *param_socketp = Curl_getconnectinfo(data, NULL);
  502:     break;
  503:   default:
  504:     return CURLE_UNKNOWN_OPTION;
  505:   }
  506: 
  507:   return CURLE_OK;
  508: }
  509: 
  510: CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
  511: {
  512:   va_list arg;
  513:   long *param_longp = NULL;
  514:   double *param_doublep = NULL;
  515:   curl_off_t *param_offt = NULL;
  516:   const char **param_charp = NULL;
  517:   struct curl_slist **param_slistp = NULL;
  518:   curl_socket_t *param_socketp = NULL;
  519:   int type;
  520:   CURLcode result = CURLE_UNKNOWN_OPTION;
  521: 
  522:   if(!data)
  523:     return result;
  524: 
  525:   va_start(arg, info);
  526: 
  527:   type = CURLINFO_TYPEMASK & (int)info;
  528:   switch(type) {
  529:   case CURLINFO_STRING:
  530:     param_charp = va_arg(arg, const char **);
  531:     if(param_charp)
  532:       result = getinfo_char(data, info, param_charp);
  533:     break;
  534:   case CURLINFO_LONG:
  535:     param_longp = va_arg(arg, long *);
  536:     if(param_longp)
  537:       result = getinfo_long(data, info, param_longp);
  538:     break;
  539:   case CURLINFO_DOUBLE:
  540:     param_doublep = va_arg(arg, double *);
  541:     if(param_doublep)
  542:       result = getinfo_double(data, info, param_doublep);
  543:     break;
  544:   case CURLINFO_OFF_T:
  545:     param_offt = va_arg(arg, curl_off_t *);
  546:     if(param_offt)
  547:       result = getinfo_offt(data, info, param_offt);
  548:     break;
  549:   case CURLINFO_SLIST:
  550:     param_slistp = va_arg(arg, struct curl_slist **);
  551:     if(param_slistp)
  552:       result = getinfo_slist(data, info, param_slistp);
  553:     break;
  554:   case CURLINFO_SOCKET:
  555:     param_socketp = va_arg(arg, curl_socket_t *);
  556:     if(param_socketp)
  557:       result = getinfo_socket(data, info, param_socketp);
  558:     break;
  559:   default:
  560:     break;
  561:   }
  562: 
  563:   va_end(arg);
  564: 
  565:   return result;
  566: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>