;;; -*- Mode: Scheme -*- ;;;; Scheme48 Networking Interface ;;;; C Data Grovel Specification ;;; This code is written by Taylor Campbell and placed in the Public ;;; Domain. All warranties are disclaimed. (prelude (system-include "sys/socket.h" "sys/types.h" "netinet/in.h" "netinet/tcp.h" "sys/un.h" )) ;;;; Network Constants (define socket-type/stream "SOCK_STREAM") (define socket-type/datagram "SOCK_DGRAM") (define socket-type/raw "SOCK_RAW") (define socket-type/sequenced-packet-stream "SOCK_SEQPACKET") (define-maybe socket-type/rdm "SOCK_RDM") ;non-POSIX (define address-family/unspecified "AF_UNSPEC") (define address-family/unix ("AF_UNIX" "AF_LOCAL")) (define address-family/internet "AF_INET") (define-maybe address-family/internet6 "AF_INET6") (define protocol-family/unspecified "AF_UNSPEC") (define protocol-family/unix ("AF_UNIX" "AF_LOCAL")) (define protocol-family/internet "AF_INET") (define-maybe protocol-family/internet6 "AF_INET6") (define shutdown/sends "SHUT_RD") (define shutdown/receives "SHUT_WR") (define shutdown/sends+receives "SHUT_RDWR") (define message/out-of-band "MSG_OOB") (define message/peek "MSG_PEEK") (define message/dont-route "MSG_DONTROUTE") (define message/eor "MSG_EOR") ; Why not END-OF-RECORD? (define message/trunc "MSG_TRUNC") ; TRUNCATED? (define message/ctrunc "MSG_CTRUNC") ; CONTROL-TRUNCATED? (define message/wait-all "MSG_WAITALL") (define message/dont-wait "MSG_DONTWAIT") (define level/socket "SOL_SOCKET") (define socket/accept-connect "SO_ACCEPTCONN") (define socket/broadcast "SO_BROADCAST") (define socket/debug "SO_DONTROUTE") (define socket/dont-route "SO_DONTROUTE") (define socket/error "SO_ERROR") (define socket/keep-alive "SO_KEEPALIVE") (define socket/linger "SO_LINGER") (define socket/oob-inline "SO_OOBINLINE") (define socket/receive-buffer "SO_RCVBUF") (define socket/receive-low-water "SO_RCVLOWAT") (define socket/receive-timeout "SO_RCVTIMEO") (define socket/reuse-address "SO_REUSEADDR") (define-maybe socket/reuse-port "SO_REUSEPORT") ;non-POSIX (define socket/send-buffer "SO_SNDBUF") (define socket/send-low-water "SO_SNDLOWAT") (define socket/send-timeout "SO_SNDTIMEO") (define socket/type "SO_TYPE") (define-maybe socket/use-loop-back "SO_USELOOPBACK") ;non-POSIX ;;; These are not really necessary given the network database. (define ip-level/ip "IPPROTO_IP") (define-maybe ip-level/ipv6 "IPPROTO_IPV6") (define ip-level/icmp "IPPROTO_ICMP") (define ip-level/raw "IPPROTO_RAW") (define ip-level/tcp "IPPROTO_TCP") (define ip-level/udp "IPPROTO_UDP") ;;; None of these is in POSIX. (define-maybe ip/options "IP_OPTIONS") (define-maybe ip/header-included "IP_HDRINCL") (define-maybe ip/type-of-service "IP_TOS") (define-maybe ip/time-to-live "IP_TTL") (define-maybe ip/receive-options "IP_RECVOPTS") (define-maybe ip/response-options "IP_RECVRETOPTS") (define-maybe ip/destination-address "IP_RECVDSTADDR") (define-maybe ip/ret-options "IP_RETOPTS") (define-maybe ip/multicast-if "IP_MULTICAST_IF") (define-maybe ip/multicast-ttl "IP_MULTICAST_TTL") (define-maybe ip/multicast-loop "IP_MULTICAST_LOOP") (define-maybe ip/add-membership "IP_ADD_MEMBERSHIP") (define-maybe ip/drop-membership "IP_DROP_MEMBERSHIP") (define tcp/no-delay "TCP_NODELAY") (define-maybe tcp/max-segment "TCP_MAXSEG") ;non-POSIX ;;;; Socket Addresses ;;; A little frobbery here to get ALLOCATE-SOCKADDR to do the right ;;; thing and allocate enough storage for any sockaddr, but to get ;;; SOCKADDR.FAMILY to access the sa_family field of a sockaddr struct, ;;; since sockaddr_storage does not have any standard fields. (struct sockaddr "sockaddr_storage") (struct (generic-sockaddr) "sockaddr" (field sockaddr.family "sa_family" integer)) (struct sockaddr-un "sockaddr_un" (field path "sun_path" (array 1 ascii-char))) (struct sockaddr-in "sockaddr_in" (field port "sin_port" (be integer)) (field address "sin_addr" (array 1 integer))) (if (not (defined? "INADDR_LOOPBACK")) (define-macro "INADDR_LOOPBACK" "0x7F000001")) (define internet-address/any "INADDR_ANY") (define internet-address/loopback "INADDR_LOOPBACK") (define internet-address/broadcast "INADDR_BROADCAST") ;;;;; IPv6 Socket Addresses (if (and (defined? "AF_INET6") (defined? "PF_INET6")) ;; Ideally, we want a MAYBE-STRUCT or STRUCT-IF or something here, ;; which would generate a DEFINE-C-STRUCT form if some condition is ;; true or a dummy substitute if not. (begin (struct sockaddr-in6 "sockaddr_in6" (field port "sin6_port" (be integer)) (field flow-info "sin6_flowinfo" (be integer)) (field address "sin6_addr" (array 1 integer)) (field scope-id "sin6_scope_id" (be integer))) ;;; Most of this crud is really just to test features of the groveller. ;;; I haven't the faintest idea what's going on when it comes to IPv6, ;;; beyond the fact that IPv6 addresses have 128 bits. ;; We happen to know that this will be 16... "printf (\"(define internet6-address-size %ld)\\n\"," " (sizeof (struct in6_addr)));" (scheme (define (make-internet6-address) (make-byte-vector internet6-address-size 0))) (scheme (define internet6-address/any (make-internet6-address)) (define internet6-address/loopback (make-internet6-address)) (define internet6-address/nodelocal-allnodes (make-internet6-address)) (define internet6-address/linklocal-allnodes (make-internet6-address)) (define internet6-address/linklocal-allrouters (make-internet6-address))) (define-macro "IN6_ADDR8(SCM, C, N)" "printf (\"(byte-vector-set! %s/%s %d %hhu)\\n\"," " \"internet6-address\", SCM, N," " (((in6addr_ ## C) . s6_addr) [N]))") (define-macro "IN6_ADDR16(SCM, C, N)" "IN6_ADDR8 (SCM, C, N);" "IN6_ADDR8 (SCM, C, (N + 1))") (define-macro "IN6_ADDR32(SCM, C, N)" "IN6_ADDR16 (SCM, C, N);" "IN6_ADDR16 (SCM, C, (N + 2))") (define-macro "IN6_ADDR64(SCM, C, N)" "IN6_ADDR32 (SCM, C, N);" "IN6_ADDR32 (SCM, C, (N + 4))") (define-macro "IN6_ADDR(SCM, C)" "IN6_ADDR64 (SCM, C, 0);" "IN6_ADDR64 (SCM, C, 8)") "IN6_ADDR (\"any\", any);" "IN6_ADDR (\"loopback\", loopback);" "IN6_ADDR (\"nodelocal-allnodes\", nodelocal_allnodes);" "IN6_ADDR (\"linklocal-allnodes\", linklocal_allnodes);" "IN6_ADDR (\"linklocal-allrouters\", linklocal_allrouters);" )) ; end if (defined? "AF_INET6")