Continuando con la búsqueda, encontré la implementación de OpenBSD de su cliente NTP y en el archivo ntp.h hay una buena descripción de que es cada campo. También ayudaron algunas páginas como ésta y ésta.
Finalmente, llegué a una implementación, simple pero a la vez. La dejo a continuación.
#!/usr/bin/python
# NTP client class for python, based on OpenBSD's ntp C code and ActiveState code recipe 117211
# v 0.1 (2011-01-28) Initial release
# Features:
# Conversion from/to NTP timestamp
# Ability to query NTP servers
# Calculation of delay and offset
import socket
import struct
import time
TIME1970 = 2208988800L # seconds from 1900
def NTPtimestamp2time(ts):
# print '%016X' % ts
# print '%016X' % (ts >>32)
ia = (ts >> 32) - TIME1970
fa = ts & 0x0000FFFF
return float(ia)+float(fa)/2**32
def time2NTPtimestamp(time):
ia = int(time)
fa = int((time-ia)*2**32)
return (ia<<32 | fa)+(TIME1970<<32)
class ntpclient:
def __init__(self):
self.sockt = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
self.server = None
self.port = 123
self.data = '\x1b' + 47* '\0'
#packet fields
self.leapIndicator = None
self.versionNumber = None
self.mode = None
self.stratum = None
self.pollInterval = None
self.precision = None
self.rootDelay = None
self.rootDispersion = None
self.referenceIdentifier = None
self.referenceTimestamp = None
self.originateTimestamp = None
self.recieveTimestamp = None
self.transmitTimestamp = None
self.destinationTimestamp = None
self.keyIdentifier = None
self.messageDigest = None
self.keyAlgorithmIdentifier = None
self.messageHash = None
def poll(self,server=None):
if server == None:
return
self.server = server
self.sockt.sendto(self.makeReqPackt(),(self.server,self.port))
data,address = self.sockt.recvfrom(1024)
self.destinationTimestamp = time2NTPtimestamp(time.time())
# print len(data)
if data and len(data) == 60:
smallfields, \
self.stratum, \
self.pollInterval, \
self.precision, \
self.rootDelay, \
self.rootDispersion, \
self.referenceIdentifier, \
self.referenceTimestamp, \
self.originateTimestamp, \
self.recieveTimestamp, \
self.transmitTimestamp, \
self.keyIdentifier, \
self.messageDigest, \
self.keyAlgorithmIdentifier, \
self.messageHash = \
struct.unpack('!BBBBIIIQQQQI8s',data)
self.leapIndicator = smallfields & 0b11000000 >> 6
self.versionNumber = smallfields & 0b00111000 >> 3
self.mode = smallfields & 0b00000111
if data and len(data) == 48:
smallfields, \
self.stratum, \
self.pollInterval, \
self.precision, \
self.rootDelay, \
self.rootDispersion, \
self.referenceIdentifier, \
self.referenceTimestamp, \
self.originateTimestamp, \
self.recieveTimestamp, \
self.transmitTimestamp = \
struct.unpack('!BBBBIIIQQQQ',data)
self.leapIndicator = smallfields & 0b11000000 >> 6
self.versionNumber = smallfields & 0b00111000 >> 3
self.mode = smallfields & 0b00000111
def toCtime(mytime):
return time.ctime((mytime>>32)-TIME1970)
def offset(self):
# t1 = self.referenceTimestamp
# t2 = self.originateTimestamp
# t3 = self.recieveTimestamp
# t4 = self.transmitTimestamp
t1 = NTPtimestamp2time(self.originateTimestamp)
t2 = NTPtimestamp2time(self.recieveTimestamp)
t3 = NTPtimestamp2time(self.transmitTimestamp)
t4 = NTPtimestamp2time(self.destinationTimestamp)
return ((t2-t1)+(t3-t4))/2
def delay(self):
t1 = NTPtimestamp2time(self.originateTimestamp)
t2 = NTPtimestamp2time(self.recieveTimestamp)
t3 = NTPtimestamp2time(self.transmitTimestamp)
t4 = NTPtimestamp2time(self.destinationTimestamp)
return ((t4-t1)-(t2-t3))
def makeReqPackt(self):
leapind = 0b00
version = 0b100 # NTP V4
mode = 0b011 # client mode
# a = time.time()
# ia = int(a)
# fa = int((a-ia)*2**32)
# tt = (ia<<32 | fa)+(TIME1970<<32)
tt = time2NTPtimestamp(time.time())
#print '%16X' % TIME1970
#print '%16X' % tt
return struct.pack('!BBBBIIIQQQQ',
leapind <<6 | version <<3 | mode,
0, #unspecified stratum
0, #poll interval
0, # local clock precision
0, # root delay
0, # root dispersion
0, # reference clock identifier
0, #reference timestamp
0, #originating timestamp
0, #recieve timestamp
tt #transmit timestamp
)
if __name__ == '__main__':
from sys import argv
c = ntpclient()
# print repr(c.makeReqPackt())
# c.poll('time.tigo.cl')
c.poll(argv[1])
# print c.versionNumber
# print c.stratum
# print '%016X'%(c.referenceTimestamp)
# print '%016X'%(c.originateTimestamp)
# print '%016X'%(c.recieveTimestamp)
# print '%016X'%(c.transmitTimestamp)
# print '%016X'%(c.destinationTimestamp)
# print c.delay()>>32, c.offset()>>32
print c.delay(), c.offset()
Espero que le sirva a alguien.
No hay comentarios.:
Publicar un comentario