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