Annotation of embedaddon/curl/docs/examples/synctime.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2019, 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: /* <DESC>
! 23: * Set your system time from a remote HTTP server's Date: header.
! 24: * </DESC>
! 25: */
! 26: /* This example code only builds as-is on Windows.
! 27: *
! 28: * While Unix/Linux user, you do not need this software.
! 29: * You can achieve the same result as synctime using curl, awk and date.
! 30: * Set proxy as according to your network, but beware of proxy Cache-Control.
! 31: *
! 32: * To set your system clock, root access is required.
! 33: * # date -s "`curl -sI https://nist.time.gov/timezone.cgi?UTC/s/0 \
! 34: * | awk -F': ' '/Date: / {print $2}'`"
! 35: *
! 36: * To view remote webserver date and time.
! 37: * $ curl -sI https://nist.time.gov/timezone.cgi?UTC/s/0 \
! 38: * | awk -F': ' '/Date: / {print $2}'
! 39: *
! 40: * Synchronising your computer clock via Internet time server usually relies
! 41: * on DAYTIME, TIME, or NTP protocols. These protocols provide good accurate
! 42: * time synchronisation but it does not work very well through a
! 43: * firewall/proxy. Some adjustment has to be made to the firewall/proxy for
! 44: * these protocols to work properly.
! 45: *
! 46: * There is an indirect method. Since most webserver provide server time in
! 47: * their HTTP header, therefore you could synchronise your computer clock
! 48: * using HTTP protocol which has no problem with firewall/proxy.
! 49: *
! 50: * For this software to work, you should take note of these items.
! 51: * 1. Your firewall/proxy must allow your computer to surf internet.
! 52: * 2. Webserver system time must in sync with the NTP time server,
! 53: * or at least provide an accurate time keeping.
! 54: * 3. Webserver HTTP header does not provide the milliseconds units,
! 55: * so there is no way to get very accurate time.
! 56: * 4. This software could only provide an accuracy of +- a few seconds,
! 57: * as Round-Trip delay time is not taken into consideration.
! 58: * Compensation of network, firewall/proxy delay cannot be simply divide
! 59: * the Round-Trip delay time by half.
! 60: * 5. Win32 SetSystemTime() API will set your computer clock according to
! 61: * GMT/UTC time. Therefore your computer timezone must be properly set.
! 62: * 6. Webserver data should not be cached by the proxy server. Some
! 63: * webserver provide Cache-Control to prevent caching.
! 64: *
! 65: * References:
! 66: * https://web.archive.org/web/20100228012139/ \
! 67: * tf.nist.gov/timefreq/service/its.htm
! 68: * https://web.archive.org/web/20100409024302/ \
! 69: * tf.nist.gov/timefreq/service/firewall.htm
! 70: *
! 71: * Usage:
! 72: * This software will synchronise your computer clock only when you issue
! 73: * it with --synctime. By default, it only display the webserver's clock.
! 74: *
! 75: * Written by: Frank (contributed to libcurl)
! 76: *
! 77: * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
! 78: * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
! 79: * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
! 80: *
! 81: * IN NO EVENT SHALL THE AUTHOR OF THIS SOFTWARE BE LIABLE FOR
! 82: * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
! 83: * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
! 84: * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
! 85: * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
! 86: * OF THIS SOFTWARE.
! 87: *
! 88: */
! 89:
! 90: #include <stdio.h>
! 91: #include <time.h>
! 92: #ifndef __CYGWIN__
! 93: #include <winsock2.h>
! 94: #include <windows.h>
! 95: #endif
! 96: #include <curl/curl.h>
! 97:
! 98:
! 99: #define MAX_STRING 256
! 100: #define MAX_STRING1 MAX_STRING + 1
! 101:
! 102: #define SYNCTIME_UA "synctime/1.0"
! 103:
! 104: typedef struct
! 105: {
! 106: char http_proxy[MAX_STRING1];
! 107: char proxy_user[MAX_STRING1];
! 108: char timeserver[MAX_STRING1];
! 109: } conf_t;
! 110:
! 111: const char DefaultTimeServer[3][MAX_STRING1] =
! 112: {
! 113: "https://nist.time.gov/",
! 114: "https://www.google.com/"
! 115: };
! 116:
! 117: const char *DayStr[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
! 118: const char *MthStr[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
! 119: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
! 120:
! 121: int ShowAllHeader;
! 122: int AutoSyncTime;
! 123: SYSTEMTIME SYSTime;
! 124: SYSTEMTIME LOCALTime;
! 125:
! 126: #define HTTP_COMMAND_HEAD 0
! 127: #define HTTP_COMMAND_GET 1
! 128:
! 129:
! 130: size_t SyncTime_CURL_WriteOutput(void *ptr, size_t size, size_t nmemb,
! 131: void *stream)
! 132: {
! 133: fwrite(ptr, size, nmemb, stream);
! 134: return (nmemb*size);
! 135: }
! 136:
! 137: size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb,
! 138: void *stream)
! 139: {
! 140: char TmpStr1[26], TmpStr2[26];
! 141:
! 142: (void)stream;
! 143:
! 144: if(ShowAllHeader == 1)
! 145: fprintf(stderr, "%s", (char *)(ptr));
! 146:
! 147: if(strncmp((char *)(ptr), "Date:", 5) == 0) {
! 148: if(ShowAllHeader == 0)
! 149: fprintf(stderr, "HTTP Server. %s", (char *)(ptr));
! 150:
! 151: if(AutoSyncTime == 1) {
! 152: *TmpStr1 = 0;
! 153: *TmpStr2 = 0;
! 154: if(strlen((char *)(ptr)) > 50) /* Can prevent buffer overflow to
! 155: TmpStr1 & 2? */
! 156: AutoSyncTime = 0;
! 157: else {
! 158: int RetVal = sscanf((char *)(ptr), "Date: %s %hu %s %hu %hu:%hu:%hu",
! 159: TmpStr1, &SYSTime.wDay, TmpStr2, &SYSTime.wYear,
! 160: &SYSTime.wHour, &SYSTime.wMinute,
! 161: &SYSTime.wSecond);
! 162:
! 163: if(RetVal == 7) {
! 164: int i;
! 165: SYSTime.wMilliseconds = 500; /* adjust to midpoint, 0.5 sec */
! 166: for(i = 0; i<12; i++) {
! 167: if(strcmp(MthStr[i], TmpStr2) == 0) {
! 168: SYSTime.wMonth = i + 1;
! 169: break;
! 170: }
! 171: }
! 172: AutoSyncTime = 3; /* Computer clock will be adjusted */
! 173: }
! 174: else {
! 175: AutoSyncTime = 0; /* Error in sscanf() fields conversion */
! 176: }
! 177: }
! 178: }
! 179: }
! 180:
! 181: if(strncmp((char *)(ptr), "X-Cache: HIT", 12) == 0) {
! 182: fprintf(stderr, "ERROR: HTTP Server data is cached."
! 183: " Server Date is no longer valid.\n");
! 184: AutoSyncTime = 0;
! 185: }
! 186: return (nmemb*size);
! 187: }
! 188:
! 189: void SyncTime_CURL_Init(CURL *curl, char *proxy_port,
! 190: char *proxy_user_password)
! 191: {
! 192: if(strlen(proxy_port) > 0)
! 193: curl_easy_setopt(curl, CURLOPT_PROXY, proxy_port);
! 194:
! 195: if(strlen(proxy_user_password) > 0)
! 196: curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_user_password);
! 197:
! 198: #ifdef SYNCTIME_UA
! 199: curl_easy_setopt(curl, CURLOPT_USERAGENT, SYNCTIME_UA);
! 200: #endif
! 201: curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, *SyncTime_CURL_WriteOutput);
! 202: curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, *SyncTime_CURL_WriteHeader);
! 203: }
! 204:
! 205: int SyncTime_CURL_Fetch(CURL *curl, char *URL_Str, char *OutFileName,
! 206: int HttpGetBody)
! 207: {
! 208: FILE *outfile;
! 209: CURLcode res;
! 210:
! 211: outfile = NULL;
! 212: if(HttpGetBody == HTTP_COMMAND_HEAD)
! 213: curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
! 214: else {
! 215: outfile = fopen(OutFileName, "wb");
! 216: curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
! 217: }
! 218:
! 219: curl_easy_setopt(curl, CURLOPT_URL, URL_Str);
! 220: res = curl_easy_perform(curl);
! 221: if(outfile != NULL)
! 222: fclose(outfile);
! 223: return res; /* (CURLE_OK) */
! 224: }
! 225:
! 226: void showUsage(void)
! 227: {
! 228: fprintf(stderr, "SYNCTIME: Synchronising computer clock with time server"
! 229: " using HTTP protocol.\n");
! 230: fprintf(stderr, "Usage : SYNCTIME [Option]\n");
! 231: fprintf(stderr, "Options :\n");
! 232: fprintf(stderr, " --server=WEBSERVER Use this time server instead"
! 233: " of default.\n");
! 234: fprintf(stderr, " --showall Show all HTTP header.\n");
! 235: fprintf(stderr, " --synctime Synchronising computer clock"
! 236: " with time server.\n");
! 237: fprintf(stderr, " --proxy-user=USER[:PASS] Set proxy username and"
! 238: " password.\n");
! 239: fprintf(stderr, " --proxy=HOST[:PORT] Use HTTP proxy on given"
! 240: " port.\n");
! 241: fprintf(stderr, " --help Print this help.\n");
! 242: fprintf(stderr, "\n");
! 243: return;
! 244: }
! 245:
! 246: int conf_init(conf_t *conf)
! 247: {
! 248: int i;
! 249:
! 250: *conf->http_proxy = 0;
! 251: for(i = 0; i<MAX_STRING1; i++)
! 252: conf->proxy_user[i] = 0; /* Clean up password from memory */
! 253: *conf->timeserver = 0;
! 254: return 1;
! 255: }
! 256:
! 257: int main(int argc, char *argv[])
! 258: {
! 259: CURL *curl;
! 260: conf_t conf[1];
! 261: int RetValue;
! 262:
! 263: ShowAllHeader = 0; /* Do not show HTTP Header */
! 264: AutoSyncTime = 0; /* Do not synchronise computer clock */
! 265: RetValue = 0; /* Successful Exit */
! 266: conf_init(conf);
! 267:
! 268: if(argc > 1) {
! 269: int OptionIndex = 0;
! 270: while(OptionIndex < argc) {
! 271: if(strncmp(argv[OptionIndex], "--server=", 9) == 0)
! 272: snprintf(conf->timeserver, MAX_STRING, "%s", &argv[OptionIndex][9]);
! 273:
! 274: if(strcmp(argv[OptionIndex], "--showall") == 0)
! 275: ShowAllHeader = 1;
! 276:
! 277: if(strcmp(argv[OptionIndex], "--synctime") == 0)
! 278: AutoSyncTime = 1;
! 279:
! 280: if(strncmp(argv[OptionIndex], "--proxy-user=", 13) == 0)
! 281: snprintf(conf->proxy_user, MAX_STRING, "%s", &argv[OptionIndex][13]);
! 282:
! 283: if(strncmp(argv[OptionIndex], "--proxy=", 8) == 0)
! 284: snprintf(conf->http_proxy, MAX_STRING, "%s", &argv[OptionIndex][8]);
! 285:
! 286: if((strcmp(argv[OptionIndex], "--help") == 0) ||
! 287: (strcmp(argv[OptionIndex], "/?") == 0)) {
! 288: showUsage();
! 289: return 0;
! 290: }
! 291: OptionIndex++;
! 292: }
! 293: }
! 294:
! 295: if(*conf->timeserver == 0) /* Use default server for time information */
! 296: snprintf(conf->timeserver, MAX_STRING, "%s", DefaultTimeServer[0]);
! 297:
! 298: /* Init CURL before usage */
! 299: curl_global_init(CURL_GLOBAL_ALL);
! 300: curl = curl_easy_init();
! 301: if(curl) {
! 302: struct tm *lt;
! 303: struct tm *gmt;
! 304: time_t tt;
! 305: time_t tt_local;
! 306: time_t tt_gmt;
! 307: double tzonediffFloat;
! 308: int tzonediffWord;
! 309: char timeBuf[61];
! 310: char tzoneBuf[16];
! 311:
! 312: SyncTime_CURL_Init(curl, conf->http_proxy, conf->proxy_user);
! 313:
! 314: /* Calculating time diff between GMT and localtime */
! 315: tt = time(0);
! 316: lt = localtime(&tt);
! 317: tt_local = mktime(lt);
! 318: gmt = gmtime(&tt);
! 319: tt_gmt = mktime(gmt);
! 320: tzonediffFloat = difftime(tt_local, tt_gmt);
! 321: tzonediffWord = (int)(tzonediffFloat/3600.0);
! 322:
! 323: if((double)(tzonediffWord * 3600) == tzonediffFloat)
! 324: snprintf(tzoneBuf, 15, "%+03d'00'", tzonediffWord);
! 325: else
! 326: snprintf(tzoneBuf, 15, "%+03d'30'", tzonediffWord);
! 327:
! 328: /* Get current system time and local time */
! 329: GetSystemTime(&SYSTime);
! 330: GetLocalTime(&LOCALTime);
! 331: snprintf(timeBuf, 60, "%s, %02d %s %04d %02d:%02d:%02d.%03d, ",
! 332: DayStr[LOCALTime.wDayOfWeek], LOCALTime.wDay,
! 333: MthStr[LOCALTime.wMonth-1], LOCALTime.wYear,
! 334: LOCALTime.wHour, LOCALTime.wMinute, LOCALTime.wSecond,
! 335: LOCALTime.wMilliseconds);
! 336:
! 337: fprintf(stderr, "Fetch: %s\n\n", conf->timeserver);
! 338: fprintf(stderr, "Before HTTP. Date: %s%s\n\n", timeBuf, tzoneBuf);
! 339:
! 340: /* HTTP HEAD command to the Webserver */
! 341: SyncTime_CURL_Fetch(curl, conf->timeserver, "index.htm",
! 342: HTTP_COMMAND_HEAD);
! 343:
! 344: GetLocalTime(&LOCALTime);
! 345: snprintf(timeBuf, 60, "%s, %02d %s %04d %02d:%02d:%02d.%03d, ",
! 346: DayStr[LOCALTime.wDayOfWeek], LOCALTime.wDay,
! 347: MthStr[LOCALTime.wMonth-1], LOCALTime.wYear,
! 348: LOCALTime.wHour, LOCALTime.wMinute, LOCALTime.wSecond,
! 349: LOCALTime.wMilliseconds);
! 350: fprintf(stderr, "\nAfter HTTP. Date: %s%s\n", timeBuf, tzoneBuf);
! 351:
! 352: if(AutoSyncTime == 3) {
! 353: /* Synchronising computer clock */
! 354: if(!SetSystemTime(&SYSTime)) { /* Set system time */
! 355: fprintf(stderr, "ERROR: Unable to set system time.\n");
! 356: RetValue = 1;
! 357: }
! 358: else {
! 359: /* Successfully re-adjusted computer clock */
! 360: GetLocalTime(&LOCALTime);
! 361: snprintf(timeBuf, 60, "%s, %02d %s %04d %02d:%02d:%02d.%03d, ",
! 362: DayStr[LOCALTime.wDayOfWeek], LOCALTime.wDay,
! 363: MthStr[LOCALTime.wMonth-1], LOCALTime.wYear,
! 364: LOCALTime.wHour, LOCALTime.wMinute, LOCALTime.wSecond,
! 365: LOCALTime.wMilliseconds);
! 366: fprintf(stderr, "\nNew System's Date: %s%s\n", timeBuf, tzoneBuf);
! 367: }
! 368: }
! 369:
! 370: /* Cleanup before exit */
! 371: conf_init(conf);
! 372: curl_easy_cleanup(curl);
! 373: }
! 374: return RetValue;
! 375: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>