169 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Scheme
		
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Scheme
		
	
	
	
| (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 "" 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*))
 |