chkspeed.c
/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ /* <DESC> * Show transfer timing info after download completes. * </DESC> */ /* Example source code to show how the callback function can be used to * download data into a chunk of memory instead of storing it in a file. * After successful download we use curl_easy_getinfo() calls to get the * amount of downloaded bytes, the time used for the whole download, and * the average download speed. * On Linux you can create the download test files with: * dd if=/dev/urandom of=file_1M.bin bs=1M count=1 * */ #ifdef _MSC_VER #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS /* for ctime() */ #endif #endif #include <stdio.h> #include <stdlib.h> #include <time.h> #include <curl/curl.h> #define URL_BASE "http://speedtest.your.domain/" #define URL_1M URL_BASE "file_1M.bin" #define URL_2M URL_BASE "file_2M.bin" #define URL_5M URL_BASE "file_5M.bin" #define URL_10M URL_BASE "file_10M.bin" #define URL_20M URL_BASE "file_20M.bin" #define URL_50M URL_BASE "file_50M.bin" #define URL_100M URL_BASE "file_100M.bin" #define CHKSPEED_VERSION "1.0" static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *data) { /* we are not interested in the downloaded bytes itself, so we only return the size we would have saved ... */ (void)ptr; (void)data; return size * nmemb; } int main(int argc, const char *argv[]) { CURL *curl; CURLcode result; int prtall = 0, prtsep = 0, prttime = 0; const char *url = URL_1M; const char *appname = argv[0]; if(argc > 1) { /* parse input parameters */ for(argc--, argv++; *argv; argc--, argv++) { if(argv[0][0] == '-') { switch(argv[0][1]) { case 'h': case 'H': fprintf(stderr, "\rUsage: %s [-m=1|2|5|10|20|50|100] [-t] [-x] [url]\n", appname); return 1; case 'v': case 'V': fprintf(stderr, "\r%s %s - %s\n", appname, CHKSPEED_VERSION, curl_version()); return 1; case 'a': case 'A': prtall = 1; break; case 'x': case 'X': prtsep = 1; break; case 't': case 'T': prttime = 1; break; case 'm': case 'M': if(argv[0][2] == '=') { int m = atoi((*argv) + 3); switch(m) { case 1: url = URL_1M; break; case 2: url = URL_2M; break; case 5: url = URL_5M; break; case 10: url = URL_10M; break; case 20: url = URL_20M; break; case 50: url = URL_50M; break; case 100: url = URL_100M; break; default: fprintf(stderr, "\r%s: invalid parameter %s\n", appname, *argv + 3); return 1; } break; } fprintf(stderr, "\r%s: invalid or unknown option %s\n", appname, *argv); return 1; default: fprintf(stderr, "\r%s: invalid or unknown option %s\n", appname, *argv); return 1; } } else { url = *argv; } } } /* print separator line */ if(prtsep) { printf("-------------------------------------------------\n"); } /* print localtime */ if(prttime) { time_t t = time(NULL); printf("Localtime: %s", ctime(&t)); } /* init libcurl */ result = curl_global_init(CURL_GLOBAL_ALL); if(result != CURLE_OK) return (int)result; /* init the curl session */ curl = curl_easy_init(); if(curl) { /* specify URL to get */ curl_easy_setopt(curl, CURLOPT_URL, url); /* send all data to this function */ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); /* some servers do not like requests that are made without a user-agent field, so we provide one */ curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-speedchecker/" CHKSPEED_VERSION); /* get it! */ result = curl_easy_perform(curl); if(result == CURLE_OK) { curl_off_t val; /* check for bytes downloaded */ result = curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD_T, &val); if((result == CURLE_OK) && (val > 0)) printf("Data downloaded: %" CURL_FORMAT_CURL_OFF_T " bytes.\n", val); /* check for total download time */ result = curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME_T, &val); if((result == CURLE_OK) && (val > 0)) printf("Total download time: %" CURL_FORMAT_CURL_OFF_T ".%06" CURL_FORMAT_CURL_OFF_T " sec.\n", val / 1000000, val % 1000000); /* check for average download speed */ result = curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD_T, &val); if((result == CURLE_OK) && (val > 0)) printf("Average download speed: " "%" CURL_FORMAT_CURL_OFF_T " kbyte/sec.\n", val / 1024); if(prtall) { /* check for name resolution time */ result = curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME_T, &val); if((result == CURLE_OK) && (val > 0)) printf("Name lookup time: %" CURL_FORMAT_CURL_OFF_T ".%06" CURL_FORMAT_CURL_OFF_T " sec.\n", val / 1000000, val % 1000000); /* check for connect time */ result = curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME_T, &val); if((result == CURLE_OK) && (val > 0)) printf("Connect time: %" CURL_FORMAT_CURL_OFF_T ".%06" CURL_FORMAT_CURL_OFF_T " sec.\n", val / 1000000, val % 1000000); } } else { fprintf(stderr, "Error while fetching '%s' : %s\n", url, curl_easy_strerror(result)); } /* cleanup curl stuff */ curl_easy_cleanup(curl); } /* we are done with libcurl, so clean it up */ curl_global_cleanup(); return 0; }
Notice
This source code example is simplified and may ignore return
codes and error checks. We do this to highlight the libcurl function calls and
related options and reduce unrelated code.
A real-world application does of course properly check every return value and exit correctly at the first serious error.