scl.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP
HTML git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
DIR Log
DIR Files
DIR Refs
DIR Tags
DIR README
DIR LICENSE
---
scl.lisp (10025B)
---
1 ;;;; See LICENSE for licensing information.
2
3 (in-package :usocket)
4
5 (defparameter +scl-error-map+
6 (append +unix-errno-condition-map+
7 +unix-errno-error-map+))
8
9 (defun scl-map-socket-error (err &key condition socket)
10 (let ((usock-err (cdr (assoc err +scl-error-map+ :test #'member))))
11 (cond (usock-err
12 (if (subtypep usock-err 'error)
13 (error usock-err :socket socket)
14 (signal usock-err :socket socket)))
15 (t
16 (error 'unknown-error
17 :socket socket
18 :real-error condition)))))
19
20 (defun handle-condition (condition &optional (socket nil) (host-or-ip nil))
21 "Dispatch correct usocket condition."
22 (typecase condition
23 (ext::socket-error
24 (scl-map-socket-error (ext::socket-errno condition)
25 :socket socket
26 :condition condition))))
27
28 (defun socket-connect (host port &key (protocol :stream) (element-type 'character)
29 timeout deadline (nodelay t nodelay-specified)
30 (local-host nil local-host-p)
31 (local-port nil local-port-p)
32 &aux
33 (patch-udp-p (fboundp 'ext::inet-socket-send-to)))
34 (when (and nodelay-specified
35 (not (eq nodelay :if-supported)))
36 (unsupported 'nodelay 'socket-connect))
37 (when deadline (unsupported 'deadline 'socket-connect))
38 (when timeout (unsupported 'timeout 'socket-connect))
39 (when (and local-host-p (not patch-udp-p))
40 (unsupported 'local-host 'socket-connect :minimum "1.3.9"))
41 (when (and local-port-p (not patch-udp-p))
42 (unsupported 'local-port 'socket-connect :minimum "1.3.9"))
43
44 (let ((socket))
45 (ecase protocol
46 (:stream
47 (setf socket (let ((args (list (host-to-hbo host) port :kind protocol)))
48 (when (and patch-udp-p (or local-host-p local-port-p))
49 (nconc args (list :local-host (when local-host
50 (host-to-hbo local-host))
51 :local-port local-port)))
52 (with-mapped-conditions (socket)
53 (apply #'ext:connect-to-inet-socket args))))
54 (let ((stream (sys:make-fd-stream socket :input t :output t
55 :element-type element-type
56 :buffering :full)))
57 (make-stream-socket :socket socket :stream stream)))
58 (:datagram
59 (when (not patch-udp-p)
60 (error 'unsupported
61 :feature '(protocol :datagram)
62 :context 'socket-connect
63 :minumum "1.3.9"))
64 (setf socket
65 (if (and host port)
66 (let ((args (list (host-to-hbo host) port :kind protocol)))
67 (when (and patch-udp-p (or local-host-p local-port-p))
68 (nconc args (list :local-host (when local-host
69 (host-to-hbo local-host))
70 :local-port local-port)))
71 (with-mapped-conditions (socket)
72 (apply #'ext:connect-to-inet-socket args)))
73 (if (or local-host-p local-port-p)
74 (with-mapped-conditions ()
75 (ext:create-inet-listener (or local-port 0)
76 protocol
77 :host (when local-host
78 (if (ip= local-host *wildcard-host*)
79 0
80 (host-to-hbo local-host)))))
81 (with-mapped-conditions ()
82 (ext:create-inet-socket protocol)))))
83 (let ((usocket (make-datagram-socket socket :connected-p (and host port t))))
84 (ext:finalize usocket #'(lambda ()
85 (when (%open-p usocket)
86 (ext:close-socket socket))))
87 usocket)))))
88
89 (defun socket-listen (host port
90 &key reuseaddress
91 (reuse-address nil reuse-address-supplied-p)
92 (backlog 5)
93 (element-type 'character))
94 (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress))
95 (host (if (ip= host *wildcard-host*)
96 0
97 (host-to-hbo host)))
98 (server-sock
99 (with-mapped-conditions ()
100 (ext:create-inet-listener port :stream
101 :host host
102 :reuse-address reuseaddress
103 :backlog backlog))))
104 (make-stream-server-socket server-sock :element-type element-type)))
105
106 (defmethod socket-accept ((usocket stream-server-usocket) &key element-type)
107 (with-mapped-conditions (usocket)
108 (let* ((sock (ext:accept-tcp-connection (socket usocket)))
109 (stream (sys:make-fd-stream sock :input t :output t
110 :element-type (or element-type
111 (element-type usocket))
112 :buffering :full)))
113 (make-stream-socket :socket sock :stream stream))))
114
115 ;; Sockets and their associated streams are modelled as
116 ;; different objects. Be sure to close the socket stream
117 ;; when closing stream-sockets; it makes sure buffers
118 ;; are flushed and the socket is closed correctly afterwards.
119 (defmethod socket-close ((usocket usocket))
120 "Close socket."
121 (with-mapped-conditions (usocket)
122 (ext:close-socket (socket usocket))))
123
124 (defmethod socket-close ((usocket stream-usocket))
125 "Close socket."
126 (with-mapped-conditions (usocket)
127 (close (socket-stream usocket))))
128
129 (defmethod socket-close :after ((socket datagram-usocket))
130 (setf (%open-p socket) nil))
131
132 (defmethod socket-shutdown ((usocket usocket) direction)
133 (declare (ignore usocket direction))
134 (unsupported "shutdown" 'socket-shutdown))
135
136 (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port)
137 (let ((s (socket usocket))
138 (host (if host (host-to-hbo host)))
139 (real-buffer (if (zerop offset)
140 buffer
141 (subseq buffer offset (+ offset size)))))
142 (multiple-value-bind (result errno)
143 (ext:inet-socket-send-to s real-buffer size
144 :remote-host host :remote-port port)
145 (or result
146 (scl-map-socket-error errno :socket usocket)))))
147
148 (defmethod socket-receive ((socket datagram-usocket) buffer length &key)
149 (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer
150 (integer 0) ; size
151 (unsigned-byte 32) ; host
152 (unsigned-byte 16))) ; port
153 (let ((s (socket socket)))
154 (let ((real-buffer (or buffer
155 (make-array length :element-type '(unsigned-byte 8))))
156 (real-length (or length
157 (length buffer))))
158 (multiple-value-bind (result errno remote-host remote-port)
159 (ext:inet-socket-receive-from s real-buffer real-length)
160 (if result
161 (values real-buffer result remote-host remote-port)
162 (scl-map-socket-error errno :socket socket))))))
163
164 (defmethod get-local-name ((usocket usocket))
165 (multiple-value-bind (address port)
166 (with-mapped-conditions (usocket)
167 (ext:get-socket-host-and-port (socket usocket)))
168 (values (hbo-to-vector-quad address) port)))
169
170 (defmethod get-peer-name ((usocket stream-usocket))
171 (multiple-value-bind (address port)
172 (with-mapped-conditions (usocket)
173 (ext:get-peer-host-and-port (socket usocket)))
174 (values (hbo-to-vector-quad address) port)))
175
176 (defmethod get-local-address ((usocket usocket))
177 (nth-value 0 (get-local-name usocket)))
178
179 (defmethod get-peer-address ((usocket stream-usocket))
180 (nth-value 0 (get-peer-name usocket)))
181
182 (defmethod get-local-port ((usocket usocket))
183 (nth-value 1 (get-local-name usocket)))
184
185 (defmethod get-peer-port ((usocket stream-usocket))
186 (nth-value 1 (get-peer-name usocket)))
187
188
189 (defun get-host-by-address (address)
190 (multiple-value-bind (host errno)
191 (ext:lookup-host-entry (host-byte-order address))
192 (cond (host
193 (ext:host-entry-name host))
194 (t
195 (let ((condition (cdr (assoc errno +unix-ns-error-map+))))
196 (cond (condition
197 (error condition :host-or-ip address))
198 (t
199 (error 'ns-unknown-error :host-or-ip address
200 :real-error errno))))))))
201
202 (defun get-hosts-by-name (name)
203 (multiple-value-bind (host errno)
204 (ext:lookup-host-entry name)
205 (cond (host
206 (mapcar #'hbo-to-vector-quad
207 (ext:host-entry-addr-list host)))
208 (t
209 (let ((condition (cdr (assoc errno +unix-ns-error-map+))))
210 (cond (condition
211 (error condition :host-or-ip name))
212 (t
213 (error 'ns-unknown-error :host-or-ip name
214 :real-error errno))))))))
215
216 (defun get-host-name ()
217 (unix:unix-gethostname))
218
219
220 ;;
221 ;;
222 ;; WAIT-LIST part
223 ;;
224
225
226 (defun %add-waiter (wl waiter)
227 (declare (ignore wl waiter)))
228
229 (defun %remove-waiter (wl waiter)
230 (declare (ignore wl waiter)))
231
232 (defun %setup-wait-list (wl)
233 (declare (ignore wl)))
234
235 (defun wait-for-input-internal (wait-list &key timeout)
236 (let* ((sockets (wait-list-waiters wait-list))
237 (pollfd-size (alien:alien-size (alien:struct unix::pollfd) :bytes))
238 (nfds (length sockets))
239 (bytes (* nfds pollfd-size)))
240 (alien:with-bytes (fds-sap bytes)
241 (do ((sockets sockets (rest sockets))
242 (base 0 (+ base 8)))
243 ((endp sockets))
244 (let ((fd (socket (first sockets))))
245 (setf (sys:sap-ref-32 fds-sap base) fd)
246 (setf (sys:sap-ref-16 fds-sap (+ base 4)) unix::pollin)))
247 (multiple-value-bind (result errno)
248 (let ((thread:*thread-whostate* "Poll wait")
249 (timeout (if timeout
250 (truncate (* timeout 1000))
251 -1)))
252 (declare (inline unix:unix-poll))
253 (unix:unix-poll (alien:sap-alien fds-sap
254 (* (alien:struct unix::pollfd)))
255 nfds timeout))
256 (cond ((not result)
257 (error "~@<Polling error: ~A~:@>"
258 (unix:get-unix-error-msg errno)))
259 (t
260 (do ((sockets sockets (rest sockets))
261 (base 0 (+ base 8)))
262 ((endp sockets))
263 (let ((flags (sys:sap-ref-16 fds-sap (+ base 6))))
264 (unless (zerop (logand flags unix::pollin))
265 (setf (state (first sockets)) :READ))))))))))
266