scsh-0.5/scsh/network.scm

988 lines
33 KiB
Scheme

;;; Networking for the Scheme Shell
;;; Copyright (c) 1994-1995 by Brian D. Carlstrom.
;;; Copyright (c) 1994 by Olin Shivers.
;;; See file COPYING.
;;; Scheme48 implementation.
(foreign-source
"#include <sys/types.h>"
"#include <sys/socket.h>"
"#include <errno.h>"
""
"/* Make sure foreign-function stubs interface to the C funs correctly: */"
"#include \"network1.h\""
""
"extern int h_errno;"
""
"#define errno_on_zero_or_false(x) ((x) ? SCHFALSE : ENTER_FIXNUM(errno))"
"#define errno_or_false(x) (((x) == -1) ? ENTER_FIXNUM(errno) : SCHFALSE)"
"#define False_on_zero(x) ((x) ? ENTER_FIXNUM(x) : SCHFALSE)"
"" )
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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 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)
(let ((sock (create-socket protocol-family socket-type/stream))
(addr (cond ((= protocol-family protocol-family/internet)
(internet-address->socket-address internet-address/any
(cond ((integer? arg) arg)
((string? arg)
(service-info:port (service-info arg "tcp")))
(else (error "socket-connect: bad arg ~s" 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)
(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) (loop)))
(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 (extensible-input-port-local-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
(string-append (integer->string address32)
(integer->string 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 (string->integer (substring (socket-address:address sockaddr)
0 4))
(string->integer (substring (socket-address:address sockaddr)
4 8)))))
(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)))
(make-socket pf in out)))))
(define-foreign %socket/errno
(socket (integer pf)
(integer type)
(integer protocol))
(multi-rep (to-scheme integer errno_or_false)
integer))
(define-errno-syscall (%socket pf type protocol) %socket/errno
sockfd)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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)))
(if (not (= family (socket-address:family name)))
(error
"bind-socket: trying to bind incompatible address to socket ~s"
name)
(%bind (socket->fdes sock)
family
(socket-address:address name)))))))
(define-foreign %bind/errno
(scheme_bind (integer sockfd) ; socket fdes
(integer family) ; address family
(string-desc name)) ; scheme descriptor
(to-scheme integer errno_or_false))
(define-errno-syscall (%bind sockfd family name) %bind/errno)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; connect syscall
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(define (connect-socket 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))
(else
(%connect (socket->fdes sock)
(socket:family sock)
(socket-address:address name))))))))
(define-foreign %connect/errno
(scheme_connect (integer sockfd) ; socket fdes
(integer family) ; address family
(desc name)) ; scheme descriptor
(to-scheme integer errno_or_false))
(define-errno-syscall (%connect sockfd family name) %connect/errno)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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))))
(define-foreign %listen/errno
(listen (integer sockfd) ; socket fdes
(integer backlog)) ; backlog
no-declare ; for Linux
(to-scheme integer errno_or_false))
(define-errno-syscall (%listen sockfd backlog) %listen/errno)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; accept syscall
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(define (accept-connection sock)
(if (not (socket? sock))
(error "accept-connection: socket expected ~s" sock)
(let* ((family (socket:family sock))
(name (make-addr family))
(fd (%accept (socket->fdes sock) family name))
(in (make-input-fdport fd 0))
(out (dup->outport in)))
(values (make-socket family in out)
(make-socket-address family name)))))
(define-foreign %accept/errno
(scheme_accept (integer sockfd)
(integer family)
(string-desc name))
(multi-rep (to-scheme integer errno_or_false)
integer))
(define-errno-syscall (%accept sock family name) %accept/errno
sockfd)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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))
(name (make-addr family)))
(%peer-name (socket->fdes sock)
family
name)
(make-socket-address family name))))
(define-foreign %peer-name/errno
(scheme_peer_name (integer sockfd)
(integer family)
(string-desc name))
(to-scheme integer errno_or_false))
(define-errno-syscall (%peer-name sock family name) %peer-name/errno)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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))
(name (make-addr family)))
(%socket-name (socket->fdes sock)
family
name)
(make-socket-address family name))))
(define-foreign %socket-name/errno
(scheme_socket_name (integer sockfd)
(integer family)
(string-desc name))
(to-scheme integer "False_on_zero"))
(define-errno-syscall
(%socket-name sock family name) %socket-name/errno)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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))))
(define-foreign %shutdown/errno
(shutdown (integer sockfd)
(integer how))
(to-scheme integer errno_or_false))
(define-errno-syscall
(%shutdown sock how) %shutdown/errno)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; socketpair syscall
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(define (create-socket-pair type)
(if (not (integer? type))
(error "create-socket-pair: integer argument expected ~s" type)
(receive (s1 s2)
(%socket-pair type)
(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))))))
;; based on pipe in syscalls.scm
(define-foreign %socket-pair/errno
(scheme_socket_pair (integer type))
(to-scheme integer errno_or_false)
integer
integer)
(define-errno-syscall
(%socket-pair type) %socket-pair/errno
sockfd1
sockfd2)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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->fdes socket) flags
s start end
recv-substring!/errno
(socket:family socket)))))))
(define (generic-receive-message! sockfd flags s start end reader from)
(if (bogus-substring-spec? s start end)
(error "Bad substring indices"
reader sockfd flags
s start end from))
(let ((addr (make-addr from)))
(let loop ((i start) (remote #f))
(if (>= i end)
(values (- i start) remote)
(receive (err nread)
(reader sockfd flags s i end addr)
(cond (err (if (= err errno/intr) (loop i)
;; Give info on partially-read data in error packet.
(errno-error err reader sockfd flags
s start i end addr)))
((zero? nread) ; EOF
(values
(let ((result (- i start)))
(and (not (zero? result)) result))
from))
(else (loop (+ i nread) from))))))))
(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->fdes socket)
flags
s start end
recv-substring!/errno
(socket:family socket)))))))
(define (generic-receive-message!/partial sockfd 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 ((addr (make-addr from)))
(let loop ()
(receive (err nread)
(reader sockfd flags s start end addr)
(cond ((not err)
(values (and (not (zero? nread)) nread)
(make-socket-address from addr)))
((= err errno/intr) (loop))
; No forward-progess here.
((or (= err errno/wouldblock)
(= err errno/again))
0)
(else (errno-error err reader sockfd flags
s start start end addr))))))))
(define-foreign recv-substring!/errno
(recv_substring (integer sockfd)
(integer flags)
(string-desc buf)
(integer start)
(integer end)
(string-desc name))
(multi-rep (to-scheme integer errno_or_false)
integer))
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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->fdes socket) flags
s start end
send-substring/errno
(if addr (socket-address:family addr) 0)
(and addr (socket-address:address addr)))))))
(define (generic-send-message sockfd flags s start end writer family addr)
(if (bogus-substring-spec? s start end)
(error "Bad substring indices"
sockfd flags family addr
s start end writer))
(let ((addr (if addr (make-addr family) "")))
(let loop ((i start))
(if (< i end)
(receive (err nwritten)
(writer sockfd flags s i end family addr)
(cond ((not err) (loop (+ i nwritten)))
((= err errno/intr) (loop i))
(else (errno-error err sockfd flags family addr
s start i end writer))))))))
(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->fdes socket) flags
s start end
send-substring/errno
(if addr (socket-address:family addr) 0)
(if addr (socket-address:address addr)))))))
(define (generic-send-message/partial sockfd flags s start end writer family addr)
(if (bogus-substring-spec? s start end)
(error "Bad substring indices"
sockfd flags family addr
s start end writer))
(if (= start end) 0 ; Vacuous request.
(let loop ()
(receive (err nwritten)
(writer sockfd flags s start end family addr)
(cond ((not err) nwritten)
((= err errno/intr) (loop))
((or (= err errno/again) (= err errno/wouldblock)) 0)
(else (errno-error err sockfd flags family addr
s start start end writer)))))))
(define-foreign send-substring/errno
(send_substring (integer sockfd)
(integer flags)
(string-desc buf)
(integer start)
(integer end)
(integer family)
(string-desc name))
(multi-rep (to-scheme integer errno_or_false)
integer))
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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)))
(cond ((= result -1)
(error "socket-option ~s ~s ~s" sock level option))
(else (not (= result 0))))))
((value-option? option)
(let ((result (%getsockopt (socket->fdes sock) level option)))
(cond ((= result -1)
(error "socket-option ~s ~s ~s" sock level option))
(else result))))
((linger-option? option)
(receive (result/on-off time)
(%getsockopt-linger (socket->fdes sock) level option)
(cond ((= result/on-off -1)
(error "socket-option ~s ~s ~s" sock level option))
(else (if (= result/on-off 0) #f time)))))
((timeout-option? option)
(receive (result/secs usecs)
(%getsockopt-linger (socket->fdes sock) level option)
(cond ((= result/secs -1)
(error "socket-option ~s ~s ~s" sock level option))
(else (+ result/secs (/ usecs 1000))))))
(else
"socket-option: unknown option type ~s" option)))
(define-foreign %getsockopt/errno
(scheme_getsockopt (integer sockfd)
(integer level)
(integer optname))
(multi-rep (to-scheme integer errno_or_false)
integer))
(define-errno-syscall (%getsockopt sock level option) %getsockopt/errno
value)
(define-foreign %getsockopt-linger/errno
(scheme_getsockopt_linger (integer sockfd)
(integer level)
(integer optname))
(multi-rep (to-scheme integer errno_or_false)
integer) ; error/on-off
integer) ; linger time
(define-errno-syscall
(%getsockopt-linger sock level option) %getsockopt-linger/errno
on-off
linger)
(define-foreign %getsockopt-timeout/errno
(scheme_getsockopt_timeout (integer sockfd)
(integer level)
(integer optname))
(multi-rep (to-scheme integer errno_or_false)
integer) ; error/secs
integer) ; usecs
(define-errno-syscall
(%getsockopt-timeout sock level option) %getsockopt-timeout/errno
secs
usecs)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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")))
(define-foreign %setsockopt/errno
(scheme_setsockopt (integer sockfd)
(integer level)
(integer optname)
(integer optval))
(to-scheme integer errno_or_false))
(define-errno-syscall
(%setsockopt sock level option value) %setsockopt/errno)
(define-foreign %setsockopt-linger/errno
(scheme_setsockopt_linger (integer sockfd)
(integer level)
(integer optname)
(integer on-off)
(integer time))
(to-scheme integer errno_or_false))
(define-errno-syscall
(%setsockopt-linger sock level option on-off time) %setsockopt-linger/errno)
(define-foreign %setsockopt-timeout/errno
(scheme_setsockopt_timeout (integer sockfd)
(integer level)
(integer optname)
(integer secs)
(integer usecs))
(to-scheme integer errno_or_false))
(define-errno-syscall
(%setsockopt-timeout sock level option secs usecs) %setsockopt-timeout/errno)
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; 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 (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)
(receive (herrno name aliases addresses)
(%host-address->host-info/h-errno
(socket-address:address name))
(if herrno
(error "address->host-info: non-zero herrno ~s ~s" name herrno)
(make-host-info name
(vector->list
(C-string-vec->Scheme aliases #f))
(vector->list
(C-long-vec->Scheme addresses #f)))))))
(define-foreign %host-address->host-info/h-errno
(scheme_host_address2host_info (string-desc name))
(to-scheme integer "False_on_zero")
static-string ; host name
(C char**) ; alias list
(C char**)) ; address list
(define (name->host-info name)
(if (not (string? name))
(error "name->host-info: string expected ~s" name)
(receive (herrno name aliases addresses)
(%host-name->host-info/h-errno name)
(if herrno
(error "name->host-info: non-zero herrno ~s ~s" herrno name)
(make-host-info name
(vector->list
(C-string-vec->Scheme aliases #f))
(vector->list
(C-long-vec->Scheme addresses #f)))))))
(define-foreign %host-name->host-info/h-errno
(scheme_host_name2host_info (string name))
(to-scheme integer "False_on_zero")
static-string ; host name
(C char**) ; alias list
(C char**)) ; address list
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; network lookup
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(define-record network-info
name ; Network name
aliases ; Alternative names
net) ; Network number
(define (network-info arg)
(cond ((string? arg) (name->network-info arg))
((socket-address? arg) (address->network-info arg))
(else
(error "network-info: string or socket-address expected ~s" arg))))
(define (address->network-info name)
(if (not (integer? name))
(error "address->network-info: integer expected ~s" name)
(let ((name (integer->string name))
(net (make-string 4)))
(receive (result name aliases)
(%net-address->network-info name net)
(make-network-info name
(vector->list
(C-string-vec->Scheme aliases #f))
(string->integer net))))))
(define-foreign %net-address->network-info
(scheme_net_address2net_info (string-desc name) (string-desc net))
(to-scheme integer "False_on_zero")
static-string ; net name
(C char**)) ; alias list
(define (name->network-info name)
(if (not (string? name))
(error "name->network-info: string expected ~s" name)
(let ((net (make-string 4)))
(receive (result name aliases)
(%net-name->network-info name net)
(make-network-info name
(vector->list
(C-string-vec->Scheme aliases #f))
(string->integer net))))))
(define-foreign %net-name->network-info
(scheme_net_name2net_info (string name) (string-desc net))
(to-scheme integer "False_on_zero")
static-string ; net name
(C char**)) ; alias list
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; service lookup
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(define-record service-info
name ; Service name
aliases ; Alternative names
port ; Port number
protocol) ; Protocol name
(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
(receive (result name aliases port protocol)
(%service-port->service-info name proto)
(make-service-info name
(vector->list (C-string-vec->Scheme aliases #f))
port
protocol))))))
(define-foreign %service-port->service-info
(scheme_serv_port2serv_info (integer name) (string proto))
(to-scheme integer "False_on_zero")
static-string ; service name
(C char**) ; alias list
integer ; port number
static-string) ; protocol name
(define (name->service-info name . maybe-proto)
(receive (result name aliases port protocol)
(%service-name->service-info name (:optional maybe-proto ""))
(make-service-info name (vector->list (C-string-vec->Scheme aliases #f))
port protocol)))
(define-foreign %service-name->service-info
(scheme_serv_name2serv_info (string name) (string proto))
(to-scheme integer "False_on_zero")
static-string ; service name
(C char**) ; alias list
integer ; port number
static-string) ; protocol name
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; protocol lookup
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(define-record protocol-info
name ; Protocol name
aliases ; Alternative names
number) ; Protocol number
(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)
(receive (result name aliases protocol)
(%protocol-port->protocol-info name)
(make-protocol-info name
(vector->list
(C-string-vec->Scheme aliases #f))
protocol))))
(define-foreign %protocol-port->protocol-info
(scheme_proto_num2proto_info (integer name))
(to-scheme integer "False_on_zero")
static-string ; protocol name
(C char**) ; alias list
integer) ; protocol number
(define (name->protocol-info name)
(if (not (string? name))
(error "name->protocol-info: string expected ~s" name)
(receive (result name aliases protocol)
(%protocol-name->protocol-info name)
(make-protocol-info name
(vector->list
(C-string-vec->Scheme aliases #f))
protocol))))
(define-foreign %protocol-name->protocol-info
(scheme_proto_name2proto_info (string name))
(to-scheme integer "False_on_zero")
static-string ; protocol name
(C char**) ; alias list
integer) ; protocol number
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;;; Lowlevel junk
;;;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;; Used to pull address list back
;; based on C-string-vec->Scheme from cig/libcig.scm
(define (C-long-vec->Scheme cvec veclen) ; No free.
(let ((vec (make-vector (or veclen (%c-veclen-or-false cvec) 0))))
(mapv! (lambda (ignore) (make-string 4)) vec)
(%set-long-vector-carriers! vec cvec)
(mapv! string->integer vec)))
(define (integer->string num32)
(let* ((str (make-string 4))
(num24 (arithmetic-shift num32 -8))
(num16 (arithmetic-shift num24 -8))
(num08 (arithmetic-shift num16 -8))
(byte0 (bitwise-and #b11111111 num08))
(byte1 (bitwise-and #b11111111 num16))
(byte2 (bitwise-and #b11111111 num24))
(byte3 (bitwise-and #b11111111 num32)))
(string-set! str 0 (ascii->char byte0))
(string-set! str 1 (ascii->char byte1))
(string-set! str 2 (ascii->char byte2))
(string-set! str 3 (ascii->char byte3))
str))
(define (string->integer str)
(+ (arithmetic-shift(char->ascii(string-ref str 0))24)
(arithmetic-shift(char->ascii(string-ref str 1))16)
(arithmetic-shift(char->ascii(string-ref str 2)) 8)
(char->ascii(string-ref str 3))))
;; also from cig/libcig.scm
(define-foreign %c-veclen-or-false
(veclen ((C "const long * ~a") c-vec)); redefining can we open cig-aux?
desc) ; integer or #f if arg is NULL.
;; also from cig/libcig.scm
(define-foreign %set-long-vector-carriers!
(set_longvec_carriers (vector-desc svec)
((C "long const * const * ~a") cvec))
ignore)
;; also from cig/libcig.scm
(define (mapv! f v)
(let ((len (vector-length v)))
(do ((i 0 (+ i 1)))
((= i len) v)
(vector-set! v i (f (vector-ref v i))))))