116 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			116 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Factor
		
	
	
! Copyright (C) 2010 John Benediktsson
 | 
						|
! See http://factorcode.org/license.txt for BSD license
 | 
						|
 | 
						|
USING: accessors arrays calendar combinators destructors
 | 
						|
fry formatting kernel io io.sockets math pack random
 | 
						|
sequences ;
 | 
						|
 | 
						|
IN: ntp
 | 
						|
 | 
						|
<PRIVATE
 | 
						|
 | 
						|
CONSTANT: REQUEST B{ 0x1b 0 0 0 0 0 0 0
 | 
						|
                     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 | 
						|
                     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 | 
						|
                     0 0 0 0 0 0 0 0 }
 | 
						|
 | 
						|
: (time) ( sequence -- timestamp )
 | 
						|
    [ first ] [ second 32 2^ / ] bi + seconds
 | 
						|
    1900 1 1 0 0 0 instant <timestamp> time+ ;
 | 
						|
 | 
						|
: (leap) ( leap -- string/f )
 | 
						|
    {
 | 
						|
        { 0 [ "no warning" ] }
 | 
						|
        { 1 [ "last minute has 61 seconds" ] }
 | 
						|
        { 2 [ "last minute has 59 seconds" ] }
 | 
						|
        { 3 [ "alarm condition (clock not synchronized)" ] }
 | 
						|
        [ drop f ]
 | 
						|
    } case ;
 | 
						|
 | 
						|
: (mode) ( mode -- string )
 | 
						|
    {
 | 
						|
        { 0 [ "unspecified" ] }
 | 
						|
        { 1 [ "symmetric active" ] }
 | 
						|
        { 2 [ "symmetric passive" ] }
 | 
						|
        { 3 [ "client" ] }
 | 
						|
        { 4 [ "server" ] }
 | 
						|
        { 5 [ "broadcast" ] }
 | 
						|
        { 6 [ "reserved for NTP control message" ] }
 | 
						|
        { 7 [ "reserved for private use" ] }
 | 
						|
        [ drop f ]
 | 
						|
    } case ;
 | 
						|
 | 
						|
: (stratum) ( stratum -- string )
 | 
						|
    {
 | 
						|
        { 0 [ "unspecified or unavailable" ] }
 | 
						|
        { 1 [ "primary reference (e.g., radio clock)" ] }
 | 
						|
        [
 | 
						|
            [ 1 > ] [ 255 < ] bi and
 | 
						|
            [ "secondary reference (via NTP or SNTP)" ]
 | 
						|
            [ "invalid stratum" throw ] if
 | 
						|
        ]
 | 
						|
    } case ;
 | 
						|
 | 
						|
: (ref-id) ( ref-id stratum -- string )
 | 
						|
    [
 | 
						|
        {
 | 
						|
            [ -24 shift 0xff bitand ]
 | 
						|
            [ -16 shift 0xff bitand ]
 | 
						|
            [ -8 shift 0xff bitand ]
 | 
						|
            [ 0xff bitand ]
 | 
						|
        } cleave
 | 
						|
    ] dip {
 | 
						|
        { 0 [ "%c%c%c%c" sprintf ] }
 | 
						|
        { 1 [ "%c%c%c%c" sprintf ] }
 | 
						|
        [
 | 
						|
            [ 1 > ] [ 255 < ] bi and
 | 
						|
            [ "%d.%d.%d.%d" sprintf ]
 | 
						|
            [ "invalid stratum" throw ] if
 | 
						|
        ]
 | 
						|
    } case ;
 | 
						|
 | 
						|
TUPLE: ntp leap version mode stratum poll precision
 | 
						|
root-delay root-dispersion ref-id ref-timestamp
 | 
						|
orig-timestamp recv-timestamp tx-timestamp ;
 | 
						|
 | 
						|
: (ntp) ( payload -- ntp )
 | 
						|
    "CCCcIIIIIIIIIII" unpack-be {
 | 
						|
        [ first -6 shift 0x3 bitand ]  ! leap
 | 
						|
        [ first -3 shift 0x7 bitand ]  ! version
 | 
						|
        [ first 0x7 bitand ]           ! mode
 | 
						|
        [ second ]                        ! stratum
 | 
						|
        [ third ]                         ! poll
 | 
						|
        [ [ 3 ] dip nth ]                 ! precision
 | 
						|
        [ [ 4 ] dip nth 16 2^ / ]         ! root-delay
 | 
						|
        [ [ 5 ] dip nth 16 2^ / ]         ! root-dispersion
 | 
						|
        [ [ 6 ] dip nth ]                 ! ref-id
 | 
						|
        [ [ { 7 8 } ] dip nths (time) ]   ! ref-timestamp
 | 
						|
        [ [ { 9 10 } ] dip nths (time) ]  ! orig-timestamp
 | 
						|
        [ [ { 11 12 } ] dip nths (time) ] ! recv-timestamp
 | 
						|
        [ [ { 13 14 } ] dip nths (time) ] ! tx-timestamp
 | 
						|
    } cleave ntp boa
 | 
						|
    dup stratum>> '[ _ (ref-id) ] change-ref-id
 | 
						|
    [ dup (leap) 2array ] change-leap
 | 
						|
    [ dup (mode) 2array ] change-mode
 | 
						|
    [ dup (stratum) 2array ] change-stratum ;
 | 
						|
 | 
						|
PRIVATE>
 | 
						|
 | 
						|
! TODO:
 | 
						|
! - socket timeout?
 | 
						|
! - format request properly?
 | 
						|
! - strftime should format millis?
 | 
						|
! - why does <inet4> resolve-host not work?
 | 
						|
 | 
						|
: <ntp> ( host -- ntp )
 | 
						|
    123 <inet> resolve-host
 | 
						|
    [ inet4? ] filter random [
 | 
						|
        [ REQUEST ] 2dip [ send ] [ receive drop ] bi (ntp)
 | 
						|
    ] with-any-port-local-datagram ;
 | 
						|
 | 
						|
: default-ntp ( -- ntp )
 | 
						|
    "pool.ntp.org" <ntp> ;
 | 
						|
 | 
						|
: local-ntp ( -- ntp )
 | 
						|
    "localhost" <ntp> ;
 |