(define-library (srfi 106) (import (scheme base) (srfi 60) (picrin optional)) ; TODO: Define assq-ref anywhere else. (define (assq-ref alist key . opt) (cond ((assq key alist) => cdr) (else (if (null? opt) #f (car opt))))) (define (socket-merge-flags flag . flags) (if (null? flags) flag (apply socket-merge-flags (logior (or flag 0) (or (car flags) 0)) (cdr flags)))) (define (socket-purge-flags base-flag . flags) (if (null? flags) base-flag (apply socket-purge-flags (logxor (or base-flag 0) (or (car flags) 0)) (cdr flags)))) (define (make-client-socket node service . args) (let-optionals* args ((family *af-inet*) (type *sock-stream*) (flags (socket-merge-flags *ai-v4mapped* *ai-addrconfig*)) (protocol *ipproto-ip*)) (make-socket node service family type flags protocol))) (define (make-server-socket service . args) (let-optionals* args ((family *af-inet*) (type *sock-stream*) (flags *ai-passive*) (protocol *ipproto-ip*)) (make-socket #f service family type flags protocol))) (define %address-family `((inet . ,*af-inet*) (inet6 . ,*af-inet6*) (unspec . ,*af-unspec*))) (define %socket-domain `((stream . ,*sock-stream*) (datagram . ,*sock-dgram*))) (define %address-info `((canoname . ,*ai-canonname*) (numerichost . ,*ai-numerichost*) (v4mapped . ,*ai-v4mapped*) (all . ,*ai-all*) (addrconfig . ,*ai-addrconfig*))) (define %ip-protocol `((ip . ,*ipproto-ip*) (tcp . ,*ipproto-tcp*) (udp . ,*ipproto-udp*))) (define %message-types `((none . 0) (peek . ,*msg-peek*) (oob . ,*msg-oob*) (wait-all . ,*msg-waitall*))) (define-syntax address-family (syntax-rules () ((_ name) (assq-ref %address-family 'name)))) (define-syntax socket-domain (syntax-rules () ((_ name) (assq-ref %socket-domain 'name)))) (define-syntax address-info (syntax-rules () ((_ names ...) (apply socket-merge-flags (map (lambda (name) (assq-ref %address-info name)) '(names ...)))))) (define-syntax ip-protocol (syntax-rules () ((_ name) (assq-ref %ip-protocol 'name)))) (define-syntax message-type (syntax-rules () ((_ names ...) (apply socket-merge-flags (map (lambda (name) (assq-ref %message-types name)) '(names ...)))))) (define (%shutdown-method names) (define (state->method state) (case state ((read) *shut-rd*) ((write) *shut-wr*) ((read-write) *shut-rdwr*) (else #f))) (let loop ((names names) (state 'none)) (cond ((null? names) (state->method state)) ((eq? (car names) 'read) (loop (cdr names) (cond ((eq? state 'none) 'read) ((eq? state 'write) 'read-write) (else state)))) ((eq? (car names) 'write) (loop (cdr names) (cond ((eq? state 'none) 'write) ((eq? state 'read) 'read-write) (else state)))) (else (loop (cdr names) 'other))))) (define-syntax shutdown-method (syntax-rules () ((_ names ...) (%shutdown-method '(names ...))))) ;; Constructors and predicate (export make-client-socket make-server-socket socket?) ;; Socket operations (export socket-accept socket-send socket-recv socket-shutdown socket-close) ;; Port conversion (export socket-input-port socket-output-port) ;; Control feature (export call-with-socket) ;; Flag operations (export address-family socket-domain address-info ip-protocol message-type shutdown-method socket-merge-flags socket-purge-flags) ;; Constant values (export *af-inet* *af-inet6* *af-unspec*) (export *sock-stream* *sock-dgram*) (export *ai-canonname* *ai-numerichost* *ai-v4mapped* *ai-all* *ai-addrconfig*) (export *ipproto-ip* *ipproto-tcp* *ipproto-udp*) (export *msg-peek* *msg-oob* *msg-waitall*) (export *shut-rd* *shut-wr* *shut-rdwr*))