;;; Networking for the Scheme Shell ;;; Copyright (c) 1994-1995 by Brian D. Carlstrom. ;;; Copyright (c) 1994 by Olin Shivers. ;;; See file COPYING. ;;; Scheme48 implementation. ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; High Level Prototypes ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (socket-connect protocol-family socket-type . args) (let* ((sock (create-socket protocol-family socket-type)) (addr (cond ((= protocol-family protocol-family/internet) (let* ((host (car args)) (port (cadr args)) (host (car (host-info:addresses (name->host-info host)))) (port (cond ((integer? port) port) ((string? port) (service-info:port (service-info (cadr args) "tcp"))) (else (error "socket-connect: bad port arg ~s" args))))) (internet-address->socket-address host port))) ((= protocol-family protocol-family/unix) (unix-address->socket-address (car args))) (else (error "socket-connect: unsupported protocol-family ~s" protocol-family))))) ;; Close the socket and free the file-descriptors ;; if the connect fails: (let ((connected #f)) (dynamic-wind (lambda () #f) (lambda () (connect-socket sock addr) (set! connected #t)) (lambda () (if (not connected) (close-socket sock)) )) (if connected sock #f)))) (define (bind-listen-accept-loop protocol-family proc arg) (bind-prepare-listen-accept-loop protocol-family (lambda () #t) proc arg)) (define (bind-prepare-listen-accept-loop protocol-family prepare proc arg) (let* ((sock (create-socket protocol-family socket-type/stream)) (addr (cond ((= protocol-family protocol-family/internet) (let ((port (cond ((integer? arg) arg) ((string? arg) (service-info:port (service-info arg "tcp"))) (else (error "socket-connect: bad arg ~s" arg))))) (internet-address->socket-address internet-address/any arg))) ((= protocol-family protocol-family/unix) (unix-address->socket-address arg)) (else (error "bind-listen-accept-loop: unsupported protocol-family ~s" protocol-family))))) (set-socket-option sock level/socket socket/reuse-address #t) (bind-socket sock addr) (with-handler (lambda (condition more) (with-handler (lambda (condition ignore) (more)) (lambda () (close-socket sock))) (more)) prepare) (listen-socket sock 5) (with-handler (lambda (condition more) (with-handler (lambda (condition ignore) (more)) (lambda () (close-socket sock))) (more)) (lambda () (let loop () (with-errno-handler ;; ECONNABORTED we just ignore ((errno packet) ((errno/connaborted) 'fick-dich-ins-knie)) (call-with-values (lambda () (accept-connection sock)) proc)) (loop)))))) ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; Socket Record Structure ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define-record socket family ; protocol family inport ; input port outport) ; output port (define-record socket-address family ; address family address) ; address ;;; returns the fdes of a socket ;;; not exported (define (socket->fdes sock) (fdport-data:fd (port-data (socket:inport sock)))) ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; Socket Address Routines ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (internet-address->socket-address address32 port16) (cond ((not (<= 0 address32 #xffffffff)) (error "internet-address->socket-address: address out of range ~s" address32)) ((not (<= 0 port16 #xffff)) (error "internet-address->socket-address: port out of range ~s" port16)) (else (make-socket-address address-family/internet (cons address32 port16))))) (define (socket-address->internet-address sockaddr) (if (or (not (socket-address? sockaddr)) (not (= (socket-address:family sockaddr) address-family/internet))) (error "socket-address->internet-address: internet socket expected ~s" sockaddr) (values (car (socket-address:address sockaddr)) (cdr (socket-address:address sockaddr))))) (define (unix-address->socket-address path) (if (> (string-length path) 108) (error "unix-address->socket-address: path too long ~s" path) (make-socket-address address-family/unix path))) (define (socket-address->unix-address sockaddr) (if (or (not (socket-address? sockaddr)) (not (= (socket-address:family sockaddr) address-family/unix))) (error "socket-address->unix-address expects an unix socket ~s" sockaddr) (socket-address:address sockaddr))) (define (make-addr af) (make-string (cond ((= af address-family/unix) 108) ((= af address-family/internet) 8) (else (error "make-addr: unknown address-family ~s" af))))) ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; socket syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (create-socket pf type . maybe-protocol) (let ((protocol (:optional maybe-protocol 0))) (if (not (and (integer? pf) (integer? type) (integer? protocol))) (error "create-socket: integer arguments expected ~s ~s ~s" pf type protocol) (let* ((fd (%socket pf type protocol)) (in (make-input-fdport fd 0)) (out (dup->outport in))) (set-fdes-status in open/non-blocking) (set-fdes-status out open/non-blocking) (make-socket pf in out))))) ;;; Turn a file descriptor into a socket. (define (port->socket port pf) ;;; ensure underlying fd is a socket by a random getsockopt call (if (not (port? port)) (error "first argument to port->socket is not a port" port)) (sleazy-call/fdes port (lambda (fd) (%getsockopt fd level/socket socket/debug))) (let ((in (dup->inport port)) (out (dup->outport port))) (make-socket pf in out))) (import-os-error-syscall %socket (pf type protocol) "scsh_socket") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; close syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (close-socket sock) (close (socket:inport sock)) (close (socket:outport sock))) ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; bind syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (bind-socket sock name) (cond ((not (socket? sock)) (error "bind-socket: socket expected ~s" sock)) ((not (socket-address? name)) (error "bind-socket: socket-address expected ~s" name)) (else (let ((family (socket:family sock))) (cond ((not (= family (socket-address:family name))) (error "bind-socket: trying to bind incompatible address to socket ~s" name)) ((and (= family address-family/unix) (> (string-length (socket-address->unix-address name)) 107)) (error "bind-socket: path too long" name)) (else (%bind (socket->fdes sock) family (socket-address:address name)))))))) (import-os-error-syscall %bind (sockfd family name) "scheme_bind") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; connect syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (connect-socket-no-wait sock name) (cond ((not (socket? sock)) (error "connect-socket: socket expected ~s" sock)) ((not (socket-address? name)) (error "connect-socket: socket-address expected ~s" name)) (else (let ((family (socket:family sock))) (cond ((not (= family (socket-address:family name))) (error "connect: trying to connect socket to incompatible address ~s" name)) ((and (= family address-family/unix) ; save space for \0 (> (string-length (socket-address:address name)) 107)) (error "connect: filename too long" name)) (else (let loop () (let* ((fdes (socket->fdes sock)) (error?.einprogress? (%connect fdes (socket:family sock) (socket-address:address name)))) (if (car error?.einprogress?) (if (cdr error?.einprogress?) #f (loop)) #t))))))))) (define (connect-socket-successful? sock) ;; If connect returned EINPROGRESS, we can check ;; it's success after the next success with getsockopt (zero? (socket-option sock level/socket socket/error))) (define (connect-socket sock name) (let ((success? (connect-socket-no-wait sock name))) (cond ((not success?) (select '#() (vector (fdport-data:fd (fdport-data (socket:outport sock)))) '#()) (if (not (connect-socket-successful? sock)) (let ((errno (socket-option sock level/socket socket/error))) (errno-error errno (errno-msg errno) %connect sock name))))))) (import-os-error-syscall %connect (sockfd family name) "scheme_connect") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; listen syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (listen-socket sock backlog) (cond ((not (socket? sock)) (error "listen-socket: socket expected ~s" sock)) ((not (integer? backlog)) (error "listen-socket: integer expected ~s" backlog)) (else (%listen (socket->fdes sock) backlog)))) (import-os-error-syscall %listen (sockfd backlog) "scsh_listen") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; accept syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (accept-connection sock) (if (not (socket? sock)) (error "accept-connection: socket expected ~s" sock) (let ((family (socket:family sock))) (let loop () ((structure-ref interrupts disable-interrupts!)) (let ((fd-addr (%accept (socket->fdes sock) family))) (cond ((pair? fd-addr) (let ((fd (car fd-addr)) (addr (cdr fd-addr))) ((structure-ref interrupts enable-interrupts!)) (let* ((in (make-input-fdport fd 0)) (out (dup->outport in))) (values (make-socket family in out) (make-socket-address family addr))))) (else (wait-for-channel (fdport-data:channel (fdport-data (socket:inport sock)))) (loop)))))))) (import-os-error-syscall %accept (sockfd family) "scheme_accept") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; getpeername syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (socket-remote-address sock) (if (or (not (socket? sock)) (not (= (socket:family sock) address-family/internet))) (error "socket-remote-address: internet socket expected ~s" sock) (let* ((family (socket:family sock)) (addr (%peer-name (socket->fdes sock) family))) (make-socket-address family addr)))) (import-os-error-syscall %peer-name (sockfd family) "scheme_peer_name") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; getsockname syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (socket-local-address sock) (if (or (not (socket? sock)) (not (= (socket:family sock) address-family/internet))) (error "socket-local-address: internet socket expected ~s" sock) (let* ((family (socket:family sock)) (addr (%socket-name (socket->fdes sock) family))) (make-socket-address family addr)))) (import-os-error-syscall %socket-name (sockfd family) "scheme_socket_name") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; shutdown syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (shutdown-socket sock how) (cond ((not (socket? sock)) (error "shutdown-socket: socket expected ~s" sock)) ((not (integer? how)) (error "shutdown-socket: integer expected ~s" how)) (else (%shutdown (socket->fdes sock) how)))) (import-os-error-syscall %shutdown (sockfd how) "scsh_shutdown") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; socketpair syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (create-socket-pair type) (if (not (integer? type)) (error "create-socket-pair: integer argument expected ~s" type) (apply (lambda (s1 s2) (let* ((in1 (make-input-fdport s1 0)) (out1 (dup->outport in1)) (in2 (make-input-fdport s2 0)) (out2 (dup->outport in2))) (values (make-socket protocol-family/unix in1 out1) (make-socket protocol-family/unix in2 out2)))) (%socket-pair type)))) (import-os-error-syscall %socket-pair (type) "scheme_socket_pair") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; recv syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (receive-message socket len . maybe-flags) (let ((flags (:optional maybe-flags 0))) (cond ((not (socket? socket)) (error "receive-message: socket expected ~s" socket)) ((or (not (integer? flags)) (not (integer? len))) (error "receive-message: integer expected ~s ~s" flags len)) (else (let ((s (make-string len))) (receive (nread from) (receive-message! socket s 0 len flags) (values (cond ((not nread) #f) ; EOF ((= nread len) s) (else (substring s 0 nread))) from))))))) (define (receive-message! socket s . args) (if (not (string? s)) (error "receive-message!: string expected ~s" s) (let-optionals args ((start 0) (end (string-length s)) (flags 0)) (cond ((not (socket? socket)) (error "receive-message!: socket expected ~s" socket)) ((not (or (integer? flags) (integer? start) (integer? end))) (error "receive-message!: integer expected ~s ~s ~s" flags start end)) (else (generic-receive-message! socket flags s start end recv-substring! (socket:family socket))))))) (define (generic-receive-message! socket flags s start end reader family) (if (bogus-substring-spec? s start end) (error "Bad substring indices" reader socket flags s start end family)) (let loop ((i start) (remote #f)) (if (>= i end) (values (- i start) (make-socket-address family remote)) (let* ((res (reader socket flags s i end))) (apply (lambda (nread from) (cond ((zero? nread) ; EOF (values (let ((result (- i start))) (and (not (zero? result)) result)) (make-socket-address family from))) (else (loop (+ i nread) from)))) res))))) (define (receive-message/partial socket len . maybe-flags) (let ((flags (:optional maybe-flags 0))) (cond ((not (socket? socket)) (error "receive-message/partial: socket expected ~s" socket)) ((or (not (integer? flags)) (not (integer? len))) (error "receive-message/partial: integer expected ~s ~s" flags len)) (else (let ((s (make-string len))) (receive (nread addr) (receive-message!/partial socket s 0 len flags) (values (cond ((not nread) #f) ; EOF ((= nread len) s) (else (substring s 0 nread))) addr))))))) (define (receive-message!/partial socket s . args) (if (not (string? s)) (error "receive-message!/partial: string expected ~s" s) (let-optionals args ((start 0) (end (string-length s)) (flags 0)) (cond ((not (socket? socket)) (error "receive-message!/partial: socket expected ~s" socket)) ((not (integer? flags)) (error "receive-message!/partial: integer expected ~s" flags)) (else (generic-receive-message!/partial socket flags s start end recv-substring! (socket:family socket))))))) (define (generic-receive-message!/partial socket flags s start end reader from) (if (bogus-substring-spec? s start end) (error "Bad substring indices" reader s start end)) (if (= start end) 0 ; Vacuous request. (let loop () (apply (lambda (nread addr) (values (and (not (zero? nread)) nread) (make-socket-address from addr))) (reader socket flags s start end))))) (define (recv-substring! socket flags buf start end) (let loop () ((structure-ref interrupts disable-interrupts!)) (let ((maybe-size-addr (%recv-substring! (socket->fdes socket) flags buf start end))) (cond (maybe-size-addr ((structure-ref interrupts enable-interrupts!)) maybe-size-addr) (else (wait-for-channel (fdport-data:channel (fdport-data (socket:inport socket)))) (loop)))))) (import-os-error-syscall %recv-substring! (sockfd flags buf start end) "recv_substring") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; send syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (send-message socket s . args) (let-optionals args ((start 0) (end (string-length s)) (flags 0) (addr #f)) (cond ((not (socket? socket)) (error "send-message: socket expected ~s" socket)) ((not (integer? flags)) (error "send-message: integer expected ~s" flags)) ((not (string? s)) (error "send-message: string expected ~s" s)) (else (generic-send-message socket flags s start end send-substring (if addr (socket-address:family addr) 0) (if addr (socket-address:address addr) #f)))))) (define (generic-send-message socket flags s start end writer family addr) (if (bogus-substring-spec? s start end) (error "Bad substring indices" socket flags family addr s start end writer)) (if (= start end) ;; there is such a thing as an empty message (writer socket flags s start end family addr) (let loop ((i start)) (if (< i end) (loop (+ i (writer socket flags s i end family addr))))))) (define (send-message/partial socket s . args) (let-optionals args ((start 0) (end (string-length s)) (flags 0) (addr #f)) (cond ((not (socket? socket)) (error "send-message/partial: socket expected ~s" socket)) ((not (integer? flags)) (error "send-message/partial: integer expected ~s" flags)) ((not (string? s)) (error "send-message/partial: string expected ~s" s)) (else (generic-send-message/partial socket flags s start end send-substring (if addr (socket-address:family addr) 0) (if addr (socket-address:address addr) #f)))))) (define (generic-send-message/partial socket flags s start end writer family addr) (if (bogus-substring-spec? s start end) (error "Bad substring indices" socket flags family addr s start end writer)) (if (= start end) 0 ; Vacuous request. (writer socket flags s start end family addr))) (define (send-substring socket flags buf start end family name) (let loop () ((structure-ref interrupts disable-interrupts!)) (cond ((%send-substring (socket->fdes socket) flags buf start end family name) => (lambda (nwritten) ((structure-ref interrupts enable-interrupts!)) nwritten)) (else (wait-for-channel (fdport-data:channel (fdport-data (socket:inport socket)))) (loop))))) (import-os-error-syscall %send-substring (sockfd flags buf start end family name) "send_substring") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; getsockopt syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (socket-option sock level option) (cond ((not (socket? sock)) (error "socket-option: socket expected ~s" sock)) ((or (not (integer? level))(not (integer? option))) (error "socket-option: integer expected ~s ~s" level option)) ((boolean-option? option) (let ((result (%getsockopt (socket->fdes sock) level option))) (not (= result 0)))) ((value-option? option) (%getsockopt (socket->fdes sock) level option)) ((linger-option? option) (apply (lambda (result/on-off time) (if (= result/on-off 0) #f time)) (%getsockopt-linger (socket->fdes sock) level option))) ((timeout-option? option) (apply (lambda (result/secs usecs) (cond ((= result/secs -1) (error "socket-option ~s ~s ~s" sock level option)) (else (+ result/secs (/ usecs 1000))))) (%getsockopt-timeout (socket->fdes sock) level option))) (else "socket-option: unknown option type ~s" option))) (import-os-error-syscall %getsockopt (sock level option) "scheme_getsockopt") ;;; returns (list on-off linger) (import-os-error-syscall %getsockopt-linger (sockfd level optname) "scheme_getsockopt_linger") ;;; returns (list secs usecs) (import-os-error-syscall %getsockopt-timeout (sockfd level optname) "scheme_getsockopt_timeout") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; setsockopt syscall ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (set-socket-option sock level option value) (cond ((not (socket? sock)) (error "set-socket-option: socket expected ~s" sock)) ((or (not (integer? level)) (not (integer? option))) (error "set-socket-option: integer expected ~s ~s" level option)) ((boolean-option? option) (%setsockopt (socket->fdes sock) level option (if value 1 0))) ((value-option? option) (%setsockopt (socket->fdes sock) level option value)) ((linger-option? option) (%setsockopt-linger (socket->fdes sock) level option (if value 1 0) (if value value 0))) ((timeout-option? option) (let ((secs (truncate value))) (%setsockopt-timeout (socket->fdes sock) level option secs (truncate (* (- value secs) 1000))))) (else "set-socket-option: unknown option type"))) (import-os-error-syscall %setsockopt (sockfd level optname optval) "scheme_setsockopt") (import-os-error-syscall %setsockopt-linger (sockfd level optname on-off time) "scheme_setsockopt_linger") (import-os-error-syscall %setsockopt-timeout (sockfd level optname secs usecs) "scheme_setsockopt_timeout") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; socket-option routines ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define (boolean-option? opt) (member opt options/boolean)) (define (value-option? opt) (member opt options/value)) (define (linger-option? opt) (member opt options/linger)) (define (timeout-option? opt) (member opt options/timeout)) ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; host lookup ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define-record host-info name ; Host name aliases ; Alternative names addresses ; Host addresses ((disclose hi) ; Make host-info records print like (list "host" (host-info:name hi)))) ; #{host clark.lcs.mit.edu}. (define-exported-binding "host-info-type" type/host-info) (define (host-info arg) (cond ((string? arg) (name->host-info arg)) ((socket-address? arg) (address->host-info arg)) (else (error "host-info: string or socket-address expected ~s" arg)))) (define (address->host-info name) (if (or (not (socket-address? name)) (not (= (socket-address:family name) address-family/internet))) (error "address->host-info: internet address expected ~s" name) (let ((res (%host-address->host-info/h-errno (socket-address:address name)))) (if (number? res) (error "address->host-info: non-zero herrno" res name) res)))) (import-lambda-definition %host-address->host-info/h-errno (name) "scheme_host_address2host_info") (define (name->host-info name) (if (not (string? name)) (error "name->host-info: string expected ~s" name) (let ((res (%host-name->host-info/h-errno name))) (if (number? res) (error "name->host-info: non-zero herrno" res name) res)))) (import-lambda-definition %host-name->host-info/h-errno (name) "scheme_host_name2host_info") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; network lookup ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define-record network-info name ; Network name aliases ; Alternative names net) ; Network number (define-exported-binding "network-info-type" type/network-info) (define (network-info arg) (cond ((string? arg) (name->network-info arg)) ((socket-address? arg) (car (socket-address:address arg))) (else (error "network-info: string or socket-address expected ~s" arg)))) (define (address->network-info addr) (if (not (integer? addr)) (error "address->network-info: integer expected ~s" addr) (%net-address->network-info addr))) (import-lambda-definition %net-address->network-info (addr) "scheme_net_address2net_info") (define (name->network-info name) (if (not (string? name)) (error "name->network-info: string expected ~s" name) (%net-name->network-info name))) (import-lambda-definition %net-name->network-info (name) "scheme_net_name2net_info") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; service lookup ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define-record service-info name ; Service name aliases ; Alternative names port ; Port number protocol) ; Protocol name (define-exported-binding "service-info-type" type/service-info) (define (service-info . args) (apply (cond ((string? (car args)) name->service-info) ((integer? (car args)) port->service-info) (else (error "service-info: string or integer expected ~s" args))) args)) (define (port->service-info name . maybe-proto) (let ((proto (:optional maybe-proto ""))) (cond ((not (integer? name)) (error "port->service-info: integer expected ~s" name)) ((not (string? proto)) (error "port->service-info: string expected ~s" proto)) (else (%service-port->service-info name (if (equal? "" proto) #f proto)))))) (import-lambda-definition %service-port->service-info (port proto) "scheme_serv_port2serv_info") (define (name->service-info name . maybe-proto) (let ((proto (:optional maybe-proto ""))) (cond ((not (string? name)) (error "name->service-info: integer expected ~s" name)) ((not (string? proto)) (error "name->service-info: string expected ~s" proto)) (else (%service-name->service-info name (if (equal? "" proto) #f proto)))))) (import-lambda-definition %service-name->service-info (name proto) "scheme_serv_name2serv_info") ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ;;; protocol lookup ;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- (define-record protocol-info name ; Protocol name aliases ; Alternative names number) ; Protocol number (define-exported-binding "protocol-info-type" type/protocol-info) (define (protocol-info arg) (cond ((string? arg) (name->protocol-info arg)) ((integer? arg) (number->protocol-info arg)) (else (error "protocol-info: string or integer expected ~s" arg)))) (define (number->protocol-info name) (if (not (integer? name)) (error "number->protocol-info: integer expected ~s" name) (%protocol-port->protocol-info name))) (import-lambda-definition %protocol-port->protocol-info (name) "scheme_proto_num2proto_info") (define (name->protocol-info name) (if (not (string? name)) (error "name->protocol-info: string expected ~s" name) (%protocol-name->protocol-info name))) (import-lambda-definition %protocol-name->protocol-info (name) "scheme_proto_name2proto_info")