/* k9linux
*
* k9linux is a simple NTP broadcast client
*
* (C) Copyright H.C.Mingham-Smith Ltd. 1999. All rights reserved.
*
* You have a royalty-free right to use, modify, reproduce and
* distribute the Sample Files (and/or any modified version) in
* any way you find useful, provided that you agree that
* H.C.Mingham-Smith Ltd. has no warranty obligations or liability for any
* Executable Files generated from this source code
*
* Implements a basic NTP broadcast listener
*
* Command line options are
*
* -d Run as debug (don't run in background, don't set the time, show trace
* -o Run until time received then die
* -b Beep when message received
*
* Build this source as follows
*
* cc k9linux.c -o k9linux
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#define TRUE 1
#define FALSE 0
#ifdef __alpha__
#define long int
#endif
/* NTP packet (no authentication) */
struct ntppkt {
unsigned char flags[4];
unsigned long rootdelay;
unsigned long rootdispersion;
unsigned long refid;
unsigned long reftimehi;
unsigned long reftimelo;
unsigned long orghi;
unsigned long orglo;
unsigned long rechi;
unsigned long reclo;
unsigned long xmthi;
unsigned long xmtlo;
};
/* Last server, stratum, time used */
struct last {
int stratum;
unsigned long addr;
time_t time;
} last;
int main(int argc, char ** argv)
{
struct sockaddr_in srv_addr;
struct servent *sp;
struct sockaddr_in remoteAddr;
struct ip_mreq mreq;
struct ntppkt ipkt;
int remoteAddrLength = sizeof(remoteAddr);
int mastersd;
int i;
char debug=FALSE;
char runonce=FALSE;
char beep=FALSE;
while( (i=getopt(argc,argv,"dbo")) != EOF) {
switch(i) {
case 'd' :
debug = TRUE;
break;
case 'o' :
runonce = TRUE;
break;
case 'b' :
beep = TRUE;
break;
default :
printf("Usage: k9linux [-b][-d][-o]\n");
exit(1);
}
}
if( !debug ) {
if( fork() ) { /* Put process into background */
exit(0);
}
setpgrp(); /* Detach from tty */
} else {
printf( "K9 V1.3 © H.C. Mingham-Smith Ltd. 1998-2000\n" );
}
if ((mastersd=socket(PF_INET,SOCK_DGRAM,0))== -1){
perror("Couldn't create socket");
exit(1);
}
srv_addr.sin_family = AF_INET;
srv_addr.sin_addr.s_addr = INADDR_ANY;
srv_addr.sin_port = ((sp = getservbyname("ntp", "udp")) == 0) ? htons(123) : sp->s_port;
if (bind(mastersd, (struct sockaddr *) &srv_addr,sizeof(srv_addr))== -1){
perror( "Couldn't bind socket");
exit(1);
}
// Join Multicast group
mreq.imr_multiaddr.s_addr = inet_addr("224.0.1.1");
mreq.imr_interface.s_addr = INADDR_ANY;
if ( setsockopt(mastersd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) == -1) {
perror( "Couldn't add membership of multicast group" );
}
while(1) {
if ( recvfrom( mastersd, (char *)&ipkt, sizeof(ipkt),0, (struct sockaddr *) &remoteAddr, &remoteAddrLength ) != -1 ) {
if( (ipkt.flags[0] & 7) == 5 ) { /* If it is a broadcast */
time_t secs= ntohl(ipkt.xmthi)-2208988800.0; //Seconds since 1900
time_t subsecs= ntohl(ipkt.xmtlo);
int stratum = ipkt.flags[1];
if( debug ) {
printf( "Time broadcast received from %s\n", inet_ntoa(remoteAddr.sin_addr) );
printf( "Ver: %d Stratum: %d Mode: %d Poll: %d Precision %d\n",
((ipkt.flags[0] & 0x38) >> 3), ipkt.flags[1],
(ipkt.flags[0] & 0x07), ipkt.flags[2],
(char)ipkt.flags[3]);
printf("UTC Time is %s", asctime(gmtime(&secs)));
} else {
/*
** If stratum is valid and (message is from our selected server
** or the stratum is higher than our server or too long since a messge received
*/
if( ( (stratum>0) && (stratum<=16) ) && ( (last.addr==remoteAddr.sin_addr.s_addr)
|| (last.stratum>stratum) || (abs(secs-last.time)>600) ) ) {
struct timeval tv;
tv.tv_sec =secs;
tv.tv_usec=(unsigned long) 1000000*((double)subsecs/(double)0x100000000);
if( settimeofday(&tv, NULL) == -1 ) {
perror("Couldn't set the time");
}
last.addr = remoteAddr.sin_addr.s_addr;
last.time = secs;
last.stratum = stratum;
}
}
if( beep ) { /* Beep when we get a message */
write(1,"\a",1);
}
if( runonce ) { /* exit when we get a message */
break;
}
}
}
}
return (0);
}
Bookmarks