00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 #include <sys/time.h>
00077 #include <time.h>
00078 #include <sys/types.h>
00079 #include <sys/stat.h>
00080 #include <fcntl.h>
00081 #include <unistd.h>
00082 #include <stdio.h>
00083 #include <stdlib.h>
00084 #include <sys/socket.h>
00085 #include <netinet/in.h>
00086 #include <arpa/inet.h>
00087 #include <string.h>
00088 #include <syslog.h>
00089 #include <netdb.h>
00090 #include <signal.h>
00091 #include <ctype.h>
00092 #include <stdarg.h>
00093 #include <errno.h>
00094
00095 #include <asm/elphel/c313a.h>
00096 #include <asm/elphel/fpgaconfa.h>
00097
00098 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00099 #include <asm/rtc.h>
00100 #endif
00101 #include <sys/ioctl.h>
00102
00103 #define NTPDATE_FILE "/etc/sntpdate.conf"
00104 #define NTPPORT 123 // NTP UDP port number
00105 #define NTPTIMEOUT 4 // retry timeout in seconds
00106 #define MAXRETRY 5 // number of times to retry
00107
00108 #define D(x)
00109
00110
00111
00112 #define D2(x)
00113 #define D3(x)
00114
00115
00116
00117
00118
00119 #ifdef __CRIS__
00120 typedef long double ntp_double;
00121 #else
00122 typedef double ntp_double;
00123 #endif
00124 #define SET_FPGA_TIME 0
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 const unsigned long UNIX_NTP_DIFF = 2208988800U;
00173
00174
00175
00176
00177
00178 const ntp_double NTP_SCALE = 4294967296.0;
00179 const ntp_double NTP_SCALE_I = 2.3283064365e-10;
00180
00181 const long MILLION_L = 1000000;
00182 const ntp_double MILLION_D = 1.0e6;
00183 const ntp_double MILLION_D_I = 1.0e-6;
00184
00185 struct ntp_stamp {
00186 unsigned long sec, frac;
00187 };
00188
00189 struct ntpmsg {
00190 unsigned long flags;
00191 unsigned long root_delay, root_dispersion, ref_id;
00192 struct ntp_stamp ref_stamp;
00193 struct ntp_stamp orig_stamp;
00194 struct ntp_stamp receive_stamp;
00195 struct ntp_stamp transmit_stamp;
00196 };
00197
00198
00199
00200
00201
00202 #define TO_FRAC(x) ((unsigned long)((((ntp_double)x) * 1.0e-6) * NTP_SCALE))
00203 #define TO_USEC(x) ((unsigned long)((((ntp_double)x) * NTP_SCALE_I) * 1.0e6))
00204 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00205 void set_rtc(struct timeval *);
00206 #endif
00207 #define USESYSLOG
00208
00209 #if SET_FPGA_TIME
00210 void set_rtc_fpga(struct timeval *);
00211 #endif
00212 static int as_daemon = 0;
00213
00214 #ifdef USESYSLOG
00215
00216
00217
00218
00219 static void
00220 log(char *str, ...)
00221 {
00222 va_list ap;
00223 static char buf[256];
00224
00225 va_start(ap, str);
00226 vsnprintf(buf, 255, str, ap);
00227 if(as_daemon)
00228 syslog(LOG_ERR, buf);
00229 else
00230 fprintf(stderr, "sntpdate: %s\n", buf);
00231 va_end(ap);
00232 return;
00233 }
00234 #else
00235 #define log printf
00236 #endif
00237
00238 static volatile int check_config = 0;
00239
00240 static void
00241 catch_signal(int sig)
00242 {
00243 check_config = 1;
00244 signal(SIGUSR1, (void *)catch_signal);
00245 }
00246
00247 int
00248 main(int argc, char **argv)
00249 {
00250 int ntpofd = 0;
00251 struct sockaddr_in addr;
00252 struct hostent *hp;
00253 struct ntpmsg ntpreq;
00254 struct ntpmsg ntpanswer;
00255 int retries;
00256 fd_set myset;
00257 struct timeval timeout;
00258 ntp_double T1, T2, T3, T4;
00259 ntp_double offset;
00260
00261 #define MAXNUMSERVERS 10
00262 unsigned char * ntpservers[MAXNUMSERVERS];
00263 int numNTPServers=0;
00264 int curNTPServer=0;
00265 int refreshinterval = 3600;
00266 int refresh_counter = 0;
00267 int setup_connection = 0;
00268 int start_connection = 0;
00269 int zone_diff = 0;
00270 int ntp_active = 0;
00271 int use_config = 0;
00272 char* time_zone = NULL;
00273 char* time_source = NULL;
00274 int success=0;
00275 for (curNTPServer=0;curNTPServer<MAXNUMSERVERS;curNTPServer++) ntpservers[curNTPServer]=NULL;
00276
00277 if(argc < 2) {
00278 use_config = 1;
00279 check_config = 1;
00280 as_daemon++;
00281 }
00282 else {
00283 if(argc == 4 && !strcmp("-d", argv[1])) {
00284 refreshinterval = atoi(argv[2]) * 60;
00285
00286 ntpservers[numNTPServers++] = argv[3];
00287 as_daemon++;
00288 } else
00289
00290 ntpservers[numNTPServers++] = argv[1];
00291 setup_connection++;
00292 }
00293
00294 as_daemon=0;
00295
00296
00297
00298 signal(SIGUSR1, (void *)catch_signal);
00299
00300 #ifdef USESYSLOG
00301
00302
00303 if (as_daemon) {
00304 openlog(argv[0], LOG_PID, LOG_DAEMON);
00305 syslog(LOG_INFO, "Starting sntpdate as daemon...");
00306 }
00307 #endif
00308
00309 D(printf("Starting sntpdate as daemon...\n"));
00310 D3(printf("Starting sntpdate as daemon...\n"));
00311
00312
00313 if (as_daemon) {
00314 if(fork()) {
00315 D(printf("sntpdate started as daemon...\n"));
00316 sleep(1);
00317 exit(0);
00318 }
00319 }
00320 do {
00321 if ((check_config) && (use_config)) {
00322 int fd;
00323 char fdata[2048];
00324 char* param = NULL;
00325 char* value = NULL;
00326 int cnt;
00327 int cnt2;
00328 int cnt3;
00329 int cnt4;
00330 int scnt;
00331 int tcnt;
00332 int missing = 0;
00333
00334 check_config = 0;
00335 ntp_active = 0;
00336 start_connection = 0;
00337
00338 fd = open (NTPDATE_FILE, O_RDONLY);
00339 if (fd >= 0) {
00340 memset(fdata,0,2048);
00341 tcnt=read(fd,fdata,2047);
00342 if (tcnt==2047) {
00343 log("warning! conf-file too BIG!");
00344 }
00345 close(fd);
00346 cnt=0;
00347 scnt=0;
00348 while (scnt<tcnt) {
00349 while (cnt<tcnt) {
00350 if ( (fdata[cnt]=='\0') ||
00351 (fdata[cnt]=='\r') ||
00352 (fdata[cnt]=='\n') ) {
00353 fdata[cnt]='\0';
00354 break;
00355 }
00356 D(printf("%c",fdata[cnt]));
00357 cnt++;
00358 }
00359 D(printf("\n"));
00360 cnt2 = scnt;
00361 cnt4 = scnt;
00362 cnt3 = 0;
00363 while (cnt2 < cnt) {
00364 if ((fdata[cnt2] == ' ')||
00365 (fdata[cnt2 + 1] == '\0')) {
00366 if (fdata[cnt2] == ' ') {
00367 fdata[cnt2] = '\0';
00368 }
00369 switch (cnt3) {
00370 case 0:
00371 param = &fdata[cnt4];
00372 break;
00373 case 1:
00374 value = &fdata[cnt4];
00375 break;
00376 default:
00377 break;
00378 }
00379 cnt3++;
00380 cnt4 = cnt2 + 1;
00381 }
00382 cnt2++;
00383 }
00384
00385 if (cnt3 == 2) {
00386 D(printf("DATA=(%s)(%s)\n", param, value));
00387
00388 if (!strncmp ("TimeZone", param, strlen ("TimeZone"))) {
00389 D(printf("found TimeZone %s\n",value));
00390 if (time_zone) free(time_zone);
00391 time_zone = strdup(value);
00392 }
00393 else if (!strncmp ("TimeSyncSource", param, strlen ("TimeSyncSource"))) {
00394 D(printf("found SyncSource %s\n",value));
00395 if (time_source) free(time_source);
00396 time_source = strdup(value);
00397 }
00398 else if (!strncmp ("NTPServer", param, strlen ("NTPServer"))) {
00399 D(printf("found NTPServer %s\n",value));
00400
00401
00402 if (numNTPServers>=MAXNUMSERVERS) printf ("Too many NTPServers (>%d) - ignoring\n",MAXNUMSERVERS);
00403 else ntpservers[numNTPServers++] = strdup(value);
00404 }
00405 else if (!strncmp ("NTPUpdate", param, strlen ("NTPUpdate"))) {
00406 D(printf("found NTPUpdate %s\n",value));
00407 refreshinterval = atoi(value);
00408 if (refreshinterval == 0) {
00409 refreshinterval = 1;
00410 }
00411 refreshinterval *= 60;
00412 D(printf("Refresh = %d\n",refreshinterval));
00413 }
00414 }
00415 scnt = ++cnt;
00416 }
00417 close(fd);
00418 }
00419 else {
00420 log("error when opening config file");
00421 }
00422
00423
00424
00425
00426
00427 if (numNTPServers>0)
00428 for (curNTPServer=0;curNTPServer<numNTPServers; curNTPServer++){
00429 log("NTP server #%d = %s", curNTPServer, ntpservers[curNTPServer]);
00430 }
00431 else
00432 missing++;
00433
00434 if (time_source) {
00435 if (strcmp("NTP",time_source)==0) ntp_active=1;
00436 log("Time Sync Source %s", time_source);
00437 }
00438 else
00439 missing++;
00440
00441 if (time_zone) {
00442 int tmp_time = 0;
00443 zone_diff = 0;
00444
00445 D(printf("Time Zone = %s\n",time_zone));
00446 if (!strncmp ("NONE", time_zone, strlen ("NONE"))) {
00447 D(printf("No Time Zone correction!\n"));
00448 }
00449 else if (!strncmp ("GMT", time_zone, strlen ("GMT"))) {
00450
00451 if (strlen(time_zone) == 3) {
00452 tmp_time = 0;
00453 }
00454 else if (time_zone[3] == '+') {
00455 tmp_time = 1;
00456 }
00457 else if (time_zone[3] == '-') {
00458 tmp_time = -1;
00459 }
00460 else {
00461 log("Time Zone corrupt");
00462 }
00463
00464 if (tmp_time != 0) {
00465 switch (strlen(time_zone)) {
00466 case 5:
00467 if (isdigit(time_zone[4])) {
00468 tmp_time*=(time_zone[4]-'0')*10;
00469 }
00470 break;
00471 case 6:
00472 if ((isdigit(time_zone[4])) &&
00473 (isdigit(time_zone[5]))) {
00474 tmp_time*=
00475 (time_zone[4]-'0')*100+(time_zone[5]-'0')*10;
00476 }
00477 break;
00478 case 7:
00479 if ((isdigit(time_zone[4])) &&
00480 (time_zone[5]=='.') &&
00481 (isdigit(time_zone[6]))) {
00482 tmp_time*=
00483 (time_zone[4]-'0')*10+(time_zone[6]-'0');
00484 }
00485 break;
00486 case 8:
00487 if ((isdigit(time_zone[4])) &&
00488 (isdigit(time_zone[5])) &&
00489 (time_zone[6]=='.') &&
00490 (isdigit(time_zone[7]))) {
00491 tmp_time*=
00492 (time_zone[4]-'0')*100 +
00493 (time_zone[5]-'0')*10 +
00494 (time_zone[7]-'0');
00495 }
00496 break;
00497 default:
00498 break;
00499 }
00500 }
00501 zone_diff = tmp_time * 360;
00502 log("Zone Diff = %d", zone_diff);
00503 }
00504 }
00505 else
00506 missing++;
00507
00508 if (missing) {
00509 log("NTP config not complete!");
00510 check_config = 0;
00511 }
00512 else {
00513 setup_connection = ntp_active;
00514 check_config = 0;
00515 }
00516 }
00517 curNTPServer=0;
00518
00519 retries = 0;
00520 while(retries < MAXRETRY) {
00521
00522 if (setup_connection) {
00523
00524
00525 D(printf("NTP: Setting up connection with server #%d (%s)\n",curNTPServer,ntpservers[curNTPServer]));
00526
00527
00528
00529
00530 if ((hp = gethostbyname(ntpservers[curNTPServer])) == NULL) {
00531
00532 log("unknown host %s", ntpservers[curNTPServer]);
00533 }
00534
00535 else if((ntpofd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00536 perror("socket");
00537 }
00538 else {
00539 memset(&addr, 0, sizeof(addr));
00540 memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
00541 addr.sin_family = AF_INET;
00542 addr.sin_port = htons(NTPPORT);
00543
00544 if(connect(ntpofd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00545 log("cant connect to %s", inet_ntoa(addr.sin_addr));
00546 }
00547 else {
00548 start_connection = 1;
00549 setup_connection = 0;
00550 }
00551 }
00552 }
00553
00554 if (start_connection) {
00555 D(printf("NTP: Open connection\n"));
00556
00557
00558
00559
00560
00561 memset(&ntpreq, 0, sizeof(ntpreq));
00562 ntpreq.flags = htonl(0x23000000);
00563
00564
00565
00566
00567 struct timeval daytime;
00568
00569 D(printf("sending NTP client request, retry %d\n", retries));
00570
00571
00572
00573
00574 gettimeofday(&daytime, NULL);
00575
00576 T1 = (unsigned long)daytime.tv_sec + MILLION_D_I * daytime.tv_usec;
00577
00578 ntpreq.transmit_stamp.sec = htonl(daytime.tv_sec + UNIX_NTP_DIFF);
00579 ntpreq.transmit_stamp.frac = htonl(TO_FRAC(daytime.tv_usec));
00580
00581
00582
00583 if (send(ntpofd, &ntpreq, sizeof(ntpreq), 0) !=
00584 sizeof(ntpreq)) {
00585 log("cant send ntp request");
00586 }
00587
00588 D2(log("transmit %u,%u frac = %u", daytime.tv_sec, daytime.tv_usec,
00589 ntohl(ntpreq.transmit_stamp.frac)));
00590
00591
00592
00593 timeout.tv_sec = NTPTIMEOUT;
00594 timeout.tv_usec = 0;
00595
00596 FD_ZERO (&myset);
00597 FD_SET (ntpofd, &myset);
00598
00599 if(select(ntpofd + 1, &myset, NULL, NULL, &timeout) > 0) {
00600
00601
00602
00603 gettimeofday(&daytime, NULL);
00604
00605 D2(log("receive %u,%u", daytime.tv_sec, daytime.tv_usec));
00606
00607 T4 = (unsigned long)daytime.tv_sec + MILLION_D_I * daytime.tv_usec;
00608
00609
00610
00611 if(recv(ntpofd, &ntpanswer,
00612 sizeof(ntpanswer), 0) == sizeof(ntpanswer)) {
00613 D(printf("got NTP reply, flags 0x%x\n",
00614 ntohl(ntpanswer.flags)));
00615 break;
00616 }
00617 }
00618 }
00619
00620
00621 retries++;
00622 curNTPServer++;
00623 if (curNTPServer>=numNTPServers) curNTPServer=0;
00624 setup_connection = 1;
00625 start_connection=0;
00626 }
00627 D(printf("broke from while(retries < MAXRETRY), retries=%d, MAXRETRY=%d\n",retries, MAXRETRY));
00628
00629 if(retries == MAXRETRY) {
00630 log("connection attempts timed out");
00631 close(ntpofd);
00632 setup_connection = 1;
00633 } else {
00634 struct timeval adjust, old, new;
00635
00636 long n;
00637
00638
00639
00640 D2(log("T2 %u,%u T3 = %u,%u",
00641 ntohl(ntpanswer.receive_stamp.sec) - UNIX_NTP_DIFF,
00642 ntohl(ntpanswer.receive_stamp.frac),
00643 ntohl(ntpanswer.transmit_stamp.sec) - UNIX_NTP_DIFF,
00644 ntohl(ntpanswer.transmit_stamp.frac)));
00645 D(printf("T2 %u,%u T3 = %u,%u",
00646 ntohl(ntpanswer.receive_stamp.sec) - UNIX_NTP_DIFF,
00647 ntohl(ntpanswer.receive_stamp.frac),
00648 ntohl(ntpanswer.transmit_stamp.sec) - UNIX_NTP_DIFF,
00649 ntohl(ntpanswer.transmit_stamp.frac)));
00650
00651 T2 = (ntohl(ntpanswer.receive_stamp.sec) - UNIX_NTP_DIFF) +
00652 ((ntp_double)ntohl(ntpanswer.receive_stamp.frac)) * NTP_SCALE_I;
00653
00654 T3 = (ntohl(ntpanswer.transmit_stamp.sec) - UNIX_NTP_DIFF) +
00655 ((ntp_double)ntohl(ntpanswer.transmit_stamp.frac)) * NTP_SCALE_I;
00656
00657 D(printf("T1 %f T2 %f T3 %f T4 %f\n", T1, T2, T3, T4));
00658
00659
00660
00661 offset = ((T2 - T1) + (T3 - T4)) * 0.5;
00662
00663 D(printf("clock offset %f\n", offset));
00664 D2(log("T2-T1 %d, T3-T4 %d, offset %d",
00665 (long)(T2-T1),
00666 (long)(T3-T4),
00667 (long)offset));
00668
00669
00670
00671 offset += zone_diff;
00672
00673
00674
00675
00676 if ((n = (long)offset) > offset)
00677 --n;
00678 adjust.tv_sec = n;
00679 adjust.tv_usec = (long)(MILLION_D * (offset - n));
00680
00681 gettimeofday(&old, NULL);
00682
00683 new.tv_sec = old.tv_sec + adjust.tv_sec;
00684 new.tv_usec = (n = (long)old.tv_usec + (long)adjust.tv_usec);
00685
00686 if (n < 0) {
00687 new.tv_usec += MILLION_L;
00688 --new.tv_sec;
00689 } else if (n >= MILLION_L) {
00690 new.tv_usec -= MILLION_L;
00691 ++new.tv_sec;
00692 }
00693
00694
00695
00696 if(as_daemon && ((!adjust.tv_sec && adjust.tv_usec < 131072) ||
00697 (adjust.tv_sec == -1 && adjust.tv_usec > 868928))) {
00698 struct timeval previous;
00699
00700
00701
00702 if(adjtime(&adjust, &previous)) {
00703 D(printf("Unable to adjust time (%d,%d): error %m",
00704 adjust.tv_sec, adjust.tv_usec, errno));
00705 log("Unable to adjust time (%d,%d): error %m",
00706 adjust.tv_sec, adjust.tv_usec, errno);
00707 } else {
00708 if (previous.tv_sec || previous.tv_usec) {
00709 D(printf("outstanding adjustment %u sec %u usec",
00710 (long)previous.tv_sec,
00711 (long)previous.tv_usec));
00712 log("outstanding adjustment %u sec %u usec",
00713 (long)previous.tv_sec,
00714 (long)previous.tv_usec);
00715 } else {
00716 D(printf("adjusted %d usec",
00717 adjust.tv_sec < 0 ?
00718 (adjust.tv_usec - MILLION_L) :
00719 adjust.tv_usec));
00720 log("adjusted %d usec",
00721 adjust.tv_sec < 0 ?
00722 (adjust.tv_usec - MILLION_L) :
00723 adjust.tv_usec);
00724 }
00725 }
00726
00727 } else {
00728
00729
00730 settimeofday(&new, NULL);
00731 #if SET_FPGA_TIME
00732 set_rtc_fpga(&new);
00733 #endif
00734 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00735 set_rtc(&new);
00736 #endif
00737 log("set time: old=(%ld,%.6ld) new=(%ld,%.6ld) adjust=(%ld,%.6ld)",
00738 (long)old.tv_sec,(long)old.tv_usec,
00739 (long)new.tv_sec,(long)new.tv_usec,
00740 (long)adjust.tv_sec,(long)adjust.tv_usec);
00741 }
00742 success=1;
00743
00744
00745
00746 }
00747
00748
00749
00750
00751
00752 if(as_daemon) {
00753 refresh_counter = refreshinterval;
00754
00755 do {
00756 sleep(1);
00757 if (check_config)
00758 break;
00759 } while(refresh_counter-- > 0);
00760
00761 sleep(1);
00762 }
00763
00764 } while(as_daemon);
00765
00766 log("Exiting...");
00767 exit(success?0:1);
00768 }
00769
00770
00771 #ifdef DEVICE_HAS_RTC_WE_DO_NOT
00772 void
00773 set_rtc(struct timeval *tv)
00774 {
00775 int fd;
00776 struct tm *mytm;
00777 unsigned int secs;
00778
00779
00780
00781 fd = open("/dev/rtc", O_RDONLY);
00782
00783 if(fd < 0) {
00784 log("cant open /dev/rtc: %m", errno);
00785 return;
00786 }
00787
00788
00789
00790
00791
00792
00793 secs = tv->tv_sec + ((tv->tv_usec > 500000) ? 1 : 0);
00794
00795 mytm = localtime((time_t *)&secs);
00796
00797
00798
00799
00800
00801 if(ioctl(fd, RTC_SET_TIME, mytm) < 0) {
00802 log("RTC_SET_TIME failed: %m", errno);
00803 }
00804
00805 close(fd);
00806 }
00807 #endif
00808
00810 #if SET_FPGA_TIME
00811 #define X313_WA_RTC_USEC 0x44
00812 #define X313_WA_RTC_SEC 0x45
00813
00814 void set_rtc_fpga(struct timeval *tv) {
00815 int fd;
00816 struct tm *mytm;
00817 unsigned int secs;
00818 unsigned long id, id_d;
00819 unsigned long tv_sec, tv_usec;
00820
00821 if((fd = open("/dev/fpgaio", O_RDWR)) < 0)
00822 return;
00823 id_d = ioctl(fd, _IO(FPGACONF_READREG, 0x13), (void *)&id);
00824 if((id_d & 0x0FFFF000) == 0x03331000)
00825 if((id_d & 0x00000FFF) >= 0x0E) {
00826 tv_sec = tv->tv_sec;
00827 tv_usec = tv->tv_usec;
00828 ioctl(fd, _IO(FPGACONF_WRITEREG, X313_WA_RTC_USEC), tv_usec);
00829 ioctl(fd, _IO(FPGACONF_WRITEREG, X313_WA_RTC_SEC), tv_sec);
00830
00831
00832 }
00833 close(fd);
00834 }
00835 #endif