1 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
3 ;;; --- Main socket methods.
6 (in-package :common-lisp-user
)
8 (defpackage :iolib.trivial-sockets
9 (:use
:iolib.base
:iolib.sockets
)
10 (:shadow
#:socket-error
#:accept-connection
)
11 (:export
#:open-stream
#:socket-error
#:socket-nested-error
12 #:unsupported
#:unsupported-feature
13 #:open-server
#:close-server
#:accept-connection
16 (in-package :iolib.trivial-sockets
)
22 ;; you're using a part of the interface that the implementation doesn't do
23 (define-condition unsupported
(error)
24 ((feature :initarg
:feature
:reader unsupported-feature
))
25 (:report
(lambda (c s
)
26 (format s
"~S does not support trivial-socket feature ~S."
27 (lisp-implementation-type) (unsupported-feature c
)))))
29 ;; all-purpose error: host not found, host not responding,
30 ;; no service on that port, etc
31 (define-condition socket-error
(error)
32 ((nested-error :initarg
:nested-error
:reader socket-nested-error
)))
35 ;;;; Main implementation
38 (defun resolve-hostname (name)
41 ((eql :any name
) +ipv4-unspecified
+)
42 (t (nth-value 0 (ensure-hostname name
))))))
44 (defun open-stream (peer-host peer-port
&key
45 (local-host :any
) (local-port 0)
46 (external-format :default
)
47 (element-type 'character
)
49 (declare (ignore element-type
))
50 (unless (eql :tcp protocol
)
51 (error 'unsupported
:feature
`(:protocol
,protocol
)))
53 (handler-bind ((error (lambda (c) (error 'socket-error
:nested-error c
))))
54 (make-socket :address-family
:internet
57 :remote-host
(resolve-hostname peer-host
)
58 :remote-port peer-port
59 :local-host
(resolve-hostname local-host
)
60 :local-port local-port
61 :external-format external-format
))))
63 (defun open-server (&key
(host :any
) (port 0)
67 "Returns a SERVER object and the port that was bound, as multiple values."
68 (unless (eql :tcp protocol
)
69 (error 'unsupported
:feature
`(:protocol
,protocol
)))
71 (handler-bind ((error (lambda (c) (error 'socket-error
:nested-error c
))))
72 (let* ((host (if (eql :any host
) +ipv4-unspecified
+ host
))
73 (socket (make-socket :address-family
:internet
78 :reuse-address reuse-address
80 (values socket
(local-port socket
))))))
82 (defun close-server (server)
85 (defun accept-connection (socket &key
86 (external-format :default
)
87 (element-type 'character
))
88 (declare (ignore element-type
)) ; bivalent streams
90 (handler-bind ((error (lambda (c) (error 'socket-error
:nested-error c
))))
91 (iolib.sockets
:accept-connection socket
:external-format external-format
))))
97 (defmacro with-server
((name arguments
) &body forms
)
98 `(with-open-stream (,name
(open-server ,@arguments
))