genera.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
---
genera.lisp (9940B)
---
1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Package: USOCKET; Base: 10 -*-
2
3
4 ;;;; See LICENSE for licensing information.
5
6 (in-package :usocket)
7
8 (defclass genera-socket ()
9 ((foreign-address :initform 0 :initarg :foreign-address :accessor gs-foreign-address)
10 (foreign-port :initform 0 :initarg :foreign-port :accessor gs-foreign-port)
11 (local-address :initform 0 :initarg :local-address :accessor gs-local-address)
12 (local-port :initform 0 :initarg :local-port :accessor gs-local-port))
13 )
14
15 (defclass genera-stream-socket (genera-socket)
16 ((stream :initform nil :initarg :stream :accessor gs-stream))
17 )
18
19 (defclass genera-stream-server-socket (genera-socket)
20 ((backlog :initform nil :initarg :backlog :accessor gs-backlog)
21 (element-type :initform nil :initarg :element-type :accessor gs-element-type)
22 (pending-connections :initform nil :accessor gs-pending-connections))
23 )
24
25 (defclass genera-datagram-socket (genera-socket)
26 ((connection :initform nil :initarg :connection :accessor gs-connection))
27 )
28
29 (defun host-to-host-object (host)
30 (let ((host (host-to-hostname host)))
31 (cond ((string-equal host "localhost")
32 net:*local-host*)
33 ((ip-address-string-p host)
34 (let ((quad (dotted-quad-to-vector-quad host)))
35 ;;---*** NOTE: This test is temporary until we have a loopback interface
36 (if (= (aref quad 0) 127)
37 net:*local-host*
38 (net:parse-host (format nil "INTERNET|~A" host)))))
39 (t
40 (net:parse-host host)))))
41
42 (defun element-type-to-format (element-type protocol)
43 (cond ((null element-type)
44 (ecase protocol
45 (:stream :text)
46 (:datagram :binary)))
47 ((subtypep element-type 'character)
48 :text)
49 (t :binary)))
50
51 (defun handle-condition (condition &optional (socket nil) (host-or-ip nil))
52 (typecase condition
53 ;;---*** TODO: Add additional conditions as appropriate
54 (sys:connection-refused
55 (error 'connection-refused-error :socket socket))
56 ((or tcp::tcp-destination-unreachable-during-connection tcp::udp-destination-unreachable)
57 (error 'host-unreachable-error :socket socket))
58 (sys:host-not-responding-during-connection
59 (error 'timeout-error :socket socket))
60 (sys:unknown-host-name
61 (error 'ns-host-not-found-error :host-or-ip host-or-ip))
62 (sys:network-error
63 (error 'unknown-error :socket socket :real-error condition :errno -1))))
64
65 (defun socket-connect (host port &key (protocol :stream) element-type
66 timeout deadline (nodelay nil nodelay-p)
67 local-host local-port)
68 (declare (ignore local-host))
69 (when deadline
70 (unsupported 'deadline 'socket-connect))
71 (when (and nodelay-p (not (eq nodelay :if-supported)))
72 (unsupported 'nodelay 'socket-connect))
73 (with-mapped-conditions (nil host)
74 (ecase protocol
75 (:stream
76 (let* ((host-object (host-to-host-object host))
77 (format (element-type-to-format element-type protocol))
78 (characters (eq format :text))
79 (timeout (if timeout
80 (* 60 timeout)
81 tcp:*tcp-connect-timeout*))
82 (stream (tcp:open-tcp-stream host-object port local-port
83 :characters characters
84 :ascii-translation characters
85 :timeout timeout))
86 (gs (make-instance 'genera-stream-socket
87 :stream stream)))
88 (setf (gs-foreign-address gs) (scl:send stream :foreign-address))
89 (setf (gs-foreign-port gs) (scl:send stream :foreign-port))
90 (setf (gs-local-address gs) (scl:send stream :local-address))
91 (setf (gs-local-port gs) (scl:send stream :local-port))
92 (make-stream-socket :socket gs :stream stream)))
93 (:datagram
94 ;;---*** TODO
95 (unsupported 'datagram 'socket-connect)))))
96
97 (defmethod socket-close ((usocket usocket))
98 (with-mapped-conditions (usocket)
99 (socket-close (socket usocket))))
100
101 (defmethod socket-close ((socket genera-stream-socket))
102 (with-slots (stream) socket
103 (when stream
104 (scl:send (shiftf stream nil) :close nil))))
105
106 (defmethod socket-close ((socket genera-stream-server-socket))
107 (with-slots (local-port pending-connections) socket
108 (when local-port
109 (tcp:remove-tcp-port-listener local-port))
110 (dolist (tcb pending-connections)
111 (tcp::reject-tcb tcb))))
112
113 (defmethod socket-close ((socket genera-datagram-socket))
114 (with-slots (connection) socket
115 (when connection
116 (scl:send (shiftf connection nil) :close nil))
117 ;;---*** TODO: listening?
118 ))
119
120 ;;; Cribbed from TCP::MAKE-TCB
121 (defun gensym-tcp-port ()
122 (loop as number = (incf tcp::*last-gensym-port-number*) then tcp::*last-gensym-port-number*
123 do (cond ((loop for existing-tcb in tcp::*tcb-list*
124 thereis (= number (tcp::tcb-local-port existing-tcb))))
125 ((and (<= #.(expt 2 10) number) (< number #.(expt 2 16)))
126 (return number))
127 (t
128 (setq tcp::*last-gensym-port-number* #.(expt 2 10))))))
129
130 (defun socket-listen (host port &key (reuse-address nil reuse-address-p)
131 (reuseaddress nil reuseaddress-p)
132 (backlog 5) (element-type 'character))
133 (let ((host-object (host-to-host-object host))
134 (port (if (zerop port) (gensym-tcp-port) port))
135 (reuse-address (cond (reuse-address-p reuse-address)
136 (reuseaddress-p reuseaddress)
137 (t nil))))
138 (when (<= port 1024)
139 ;; Don't allow listening on "privileged" ports to mimic Unix/Linux semantics
140 (error 'operation-not-permitted-error :socket nil))
141 (when (tcp:tcp-port-protocol-name port)
142 ;; Can't replace a Genera server
143 (error 'address-in-use-error :socket nil))
144 (when (tcp:tcp-port-listener port)
145 (unless reuse-address
146 (error 'address-in-use-error :socket nil)))
147 (let ((gs (make-instance 'genera-stream-server-socket
148 :backlog backlog
149 :element-type element-type)))
150 (setf (gs-local-address gs)
151 (loop for (network address) in (scl:send host-object :network-addresses)
152 when (typep network 'tcp:internet-network)
153 return address))
154 (setf (gs-local-port gs) port)
155 (flet ((add-to-queue (tcb)
156 (cond ((and (not (zerop (gs-local-address gs)))
157 (not (= (gs-local-address gs) (tcp::tcb-local-address tcb))))
158 ;; Reject if not destined for the proper address
159 (tcp::reject-tcb tcb))
160 ((<= (length (gs-pending-connections gs)) (gs-backlog gs))
161 (tcp::accept-tcb tcb)
162 (tcp::tcb-travel-through-states tcb "Accept" nil :listen :syn-received)
163 (setf (gs-pending-connections gs)
164 (append (gs-pending-connections gs) (list tcb))))
165 (t
166 ;; Reject if backlog is full
167 (tcp::reject-tcb tcb)))))
168 (tcp:add-tcp-port-listener port #'add-to-queue))
169 (make-stream-server-socket gs :element-type element-type))))
170
171 (defmethod socket-accept ((socket stream-server-usocket) &key element-type)
172 (with-slots (pending-connections) (socket socket)
173 (loop
174 (process:process-block "Wait for connection" #'(lambda ()
175 (not (null pending-connections))))
176 (let ((tcb (pop pending-connections)))
177 (when tcb
178 (let* ((format (element-type-to-format (or element-type (element-type socket))
179 :stream))
180 (characters (eq format :text))
181 (stream (tcp::make-tcp-stream tcb
182 :characters characters
183 :ascii-translation characters))
184 (gs (make-instance 'genera-stream-socket
185 :stream stream)))
186 (setf (gs-foreign-address gs) (scl:send stream :foreign-address))
187 (setf (gs-foreign-port gs) (scl:send stream :foreign-port))
188 (setf (gs-local-address gs) (scl:send stream :local-address))
189 (setf (gs-local-port gs) (scl:send stream :local-port))
190 (return (make-stream-socket :socket gs :stream stream))))))))
191
192 (defmethod get-local-address ((usocket usocket))
193 (hbo-to-vector-quad (gs-local-address (socket usocket))))
194
195 (defmethod get-peer-address ((usocket stream-usocket))
196 (hbo-to-vector-quad (gs-foreign-address (socket usocket))))
197
198 (defmethod get-local-port ((usocket usocket))
199 (gs-local-port (socket usocket)))
200
201 (defmethod get-peer-port ((usocket stream-usocket))
202 (gs-foreign-port (socket usocket)))
203
204 (defmethod get-local-name ((usocket usocket))
205 (values (get-local-address usocket)
206 (get-local-port usocket)))
207
208 (defmethod get-peer-name ((usocket stream-usocket))
209 (values (get-peer-address usocket)
210 (get-peer-port usocket)))
211
212 (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0))
213 ;;---*** TODO
214 (unsupported 'datagram 'socket-send))
215
216 (defmethod socket-receive ((socket datagram-usocket) buffer length &key)
217 ;;---*** TODO
218 (unsupported 'datagram 'socket-receive))
219
220 (defun get-host-by-address (address)
221 ) ;; TODO
222
223 (defun get-hosts-by-name (name)
224 (with-mapped-conditions (nil name)
225 (let ((host-object (host-to-host-object name)))
226 (loop for (network address) in (scl:send host-object :network-addresses)
227 when (typep network 'tcp:internet-network)
228 collect (hbo-to-vector-quad address)))))
229
230 (defun %setup-wait-list (wait-list)
231 (declare (ignore wait-list)))
232
233 (defun %add-waiter (wait-list waiter)
234 (declare (ignore wait-list waiter)))
235
236 (defun %remove-waiter (wait-list waiter)
237 (declare (ignore wait-list waiter)))
238
239 (defun wait-for-input-internal (wait-list &key timeout)
240 (with-mapped-conditions ()
241 (process:process-block-with-timeout timeout "Wait for input"
242 #'(lambda (wait-list)
243 (let ((ready-sockets nil))
244 (dolist (waiter (wait-list-waiters wait-list) ready-sockets)
245 (setf (state waiter)
246 (cond ((stream-usocket-p waiter)
247 (if (listen (socket-stream waiter))
248 :read
249 nil))
250 ((datagram-usocket-p waiter)
251 (let ((connection (gs-connection (socket waiter))))
252 (if (and connection
253 (not (scl:send connection :connection-pending-p)))
254 :read
255 nil)))
256 ((stream-server-usocket-p waiter)
257 (if (gs-pending-connections (socket waiter))
258 :read
259 nil))))
260 (when (not (null (state waiter)))
261 (setf ready-sockets t)))))
262 wait-list)
263 wait-list))
264