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