;;; nettime.scm -- obtain the time on remote machines ;;; This file is part of the Scheme Untergrund Networking package. ;;; Copyright (c) 1998 by Eric Marsden ;;; Copyright (c) 2003 by Mike Sperber ;;; For copyright information, see the file COPYING which comes with ;;; the distribution. ;;; Related work ====================================================== ;; ;; * Time.pm is a Perl module by Graham Barr ;; * rfc868 describes the Time protocol ;; http://www.ietf.org/rfc/rfc868.txt ;; * rfc867 describes the Daytime protocol in all its glory ;; http://www.ietf.org/rfc/rfc867.txt ;; * for a genuinely useful protocol look at the Network Time Protocol ;; defined in rfc1305, which allows for the synchronization of clocks ;; on networked computers. ;; args host protocol, where host may be an IP number or a fqdn. we ;; subtract 70 years' worth of seconds at the end, since the time ;; protocol returns the number of seconds since 1900, whereas Unix ;; time is since 1970. (define (rfc868-time/tcp host) (let* ((hst-info (host-info host)) (srvc-info (service-info "time" "tcp")) (sock (socket-connect protocol-family/internet socket-type/stream (host-info:name hst-info) (service-info:port srvc-info))) (result (read-integer (socket:inport sock)))) (close-socket sock) (- result 2208988800))) (define (rfc868-time/udp host . maybe-timeout) (let* ((hst-info (host-info host)) (srvc-info (service-info "time" "udp")) (timeout (if (pair? maybe-timeout) (car maybe-timeout) #f)) (socket (create-socket protocol-family/internet socket-type/datagram))) (connect-socket socket (internet-address->socket-address (car (host-info:addresses hst-info)) (service-info:port srvc-info))) (send-message socket "") (if (null? (select-ports timeout (socket:inport socket))) (begin (close-socket socket) #f) (with-fatal-error-handler* (lambda (result punt) ;; we may see a "connection refused" error here #f) (lambda () (let ((result (read-integer (socket:inport socket)))) (close-socket socket) (- result 2208988800))))))) (define (rfc867-daytime/tcp host) (let* ((hst-info (host-info host)) (srvc-info (service-info "daytime" "tcp")) (sock (socket-connect protocol-family/internet socket-type/stream (host-info:name hst-info) (service-info:port srvc-info))) (result (read-string 20 (socket:inport sock)))) (close-socket sock) result)) (define (rfc867-daytime/udp host . maybe-timeout) (let* ((hst-info (host-info host)) (srvc-info (service-info "daytime" "udp")) (timeout (if (pair? maybe-timeout) (car maybe-timeout) #f)) (socket (create-socket protocol-family/internet socket-type/datagram))) (connect-socket socket (internet-address->socket-address (car (host-info:addresses hst-info)) (service-info:port srvc-info))) (send-message socket "") (if (null? (select-ports timeout (socket:inport socket))) (begin (close-socket socket) #f) (with-fatal-error-handler* (lambda (result punt) ;; we may see a "connection refused" error here #f) (lambda () (call-with-values (lambda () (receive-message socket 20)) (lambda (result socket-address) (close-socket socket) result))))))) ;; read 4 bytes from fd and build an integer from them (define (read-integer fd) (let loop ((accum 0) (remaining 4)) (if (zero? remaining) accum (loop (+ (arithmetic-shift accum 8) (read-byte fd)) (- remaining 1))))) ;; what about EOF?? (define (read-byte fd) (char->ascii (read-char fd)))