clucumber 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.md +4 -9
- data/lib/clucumber/clucumber-bootstrap.lisp +32 -0
- data/lib/clucumber/vendor/cl-interpol/alias.lisp +55 -0
- data/lib/clucumber/vendor/cl-interpol/cl-interpol.asd +56 -0
- data/lib/clucumber/vendor/cl-interpol/load.lisp +53 -0
- data/lib/clucumber/vendor/cl-interpol/packages.lisp +40 -0
- data/lib/clucumber/vendor/cl-interpol/read.lisp +716 -0
- data/lib/clucumber/vendor/cl-interpol/specials.lisp +113 -0
- data/lib/clucumber/vendor/cl-interpol/test/packages.lisp +34 -0
- data/lib/clucumber/vendor/cl-interpol/test/tests.lisp +128 -0
- data/lib/clucumber/vendor/cl-interpol/test.lisp +177 -0
- data/lib/clucumber/vendor/cl-interpol/test2.lisp +6254 -0
- data/lib/clucumber/vendor/cl-interpol/unicode.lisp +13912 -0
- data/lib/clucumber/vendor/cl-interpol/util.lisp +122 -0
- data/lib/clucumber/vendor/cl-ppcre/api.lisp +1262 -0
- data/lib/clucumber/vendor/cl-ppcre/charmap.lisp +152 -0
- data/lib/clucumber/vendor/cl-ppcre/charset.lisp +242 -0
- data/lib/clucumber/vendor/cl-ppcre/chartest.lisp +98 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-test.asd +34 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/packages.lisp +38 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/resolver.lisp +61 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode.asd +58 -0
- data/lib/clucumber/vendor/cl-ppcre/cl-ppcre.asd +79 -0
- data/lib/clucumber/vendor/cl-ppcre/closures.lisp +471 -0
- data/lib/clucumber/vendor/cl-ppcre/convert.lisp +875 -0
- data/lib/clucumber/vendor/cl-ppcre/errors.lisp +84 -0
- data/lib/clucumber/vendor/cl-ppcre/lexer.lisp +737 -0
- data/lib/clucumber/vendor/cl-ppcre/lispworks-defsystem.lisp +57 -0
- data/lib/clucumber/vendor/cl-ppcre/load.lisp +67 -0
- data/lib/clucumber/vendor/cl-ppcre/optimize.lisp +578 -0
- data/lib/clucumber/vendor/cl-ppcre/packages.lisp +68 -0
- data/lib/clucumber/vendor/cl-ppcre/parser.lisp +319 -0
- data/lib/clucumber/vendor/cl-ppcre/ppcre-tests.lisp +269 -0
- data/lib/clucumber/vendor/cl-ppcre/regex-class-util.lisp +555 -0
- data/lib/clucumber/vendor/cl-ppcre/regex-class.lisp +259 -0
- data/lib/clucumber/vendor/cl-ppcre/repetition-closures.lisp +833 -0
- data/lib/clucumber/vendor/cl-ppcre/scanner.lisp +506 -0
- data/lib/clucumber/vendor/cl-ppcre/specials.lisp +172 -0
- data/lib/clucumber/vendor/cl-ppcre/test/packages.lisp +37 -0
- data/lib/clucumber/vendor/cl-ppcre/test/perl-tests.lisp +150 -0
- data/lib/clucumber/vendor/cl-ppcre/test/tests.lisp +159 -0
- data/lib/clucumber/vendor/cl-ppcre/test/unicode-tests.lisp +80 -0
- data/lib/clucumber/vendor/cl-ppcre/util.lisp +201 -0
- data/lib/clucumber/vendor/cl-unicode/alias.lisp +135 -0
- data/lib/clucumber/vendor/cl-unicode/api.lisp +412 -0
- data/lib/clucumber/vendor/cl-unicode/build/char-info.lisp +133 -0
- data/lib/clucumber/vendor/cl-unicode/build/dump.lisp +239 -0
- data/lib/clucumber/vendor/cl-unicode/build/read.lisp +280 -0
- data/lib/clucumber/vendor/cl-unicode/build/util.lisp +182 -0
- data/lib/clucumber/vendor/cl-unicode/cl-unicode.asd +90 -0
- data/lib/clucumber/vendor/cl-unicode/conditions.lisp +54 -0
- data/lib/clucumber/vendor/cl-unicode/derived.lisp +120 -0
- data/lib/clucumber/vendor/cl-unicode/hash-tables.lisp +20 -0
- data/lib/clucumber/vendor/cl-unicode/lists.lisp +10 -0
- data/lib/clucumber/vendor/cl-unicode/methods.lisp +15 -0
- data/lib/clucumber/vendor/cl-unicode/packages.lisp +76 -0
- data/lib/clucumber/vendor/cl-unicode/specials.lisp +135 -0
- data/lib/clucumber/vendor/cl-unicode/test/packages.lisp +34 -0
- data/lib/clucumber/vendor/cl-unicode/test/tests.lisp +150 -0
- data/lib/clucumber/vendor/cl-unicode/test-functions.lisp +94 -0
- data/lib/clucumber/vendor/cl-unicode/util.lisp +274 -0
- data/lib/clucumber/vendor/lift/compare/fiveam-tests.lisp +14 -0
- data/lib/clucumber/vendor/lift/compare/lift-tests.lisp +13 -0
- data/lib/clucumber/vendor/lift/compare/rt-tests.lisp +16 -0
- data/lib/clucumber/vendor/lift/compare/xlunit-tests.lisp +15 -0
- data/lib/clucumber/vendor/lift/dev/changes.lisp +61 -0
- data/lib/clucumber/vendor/lift/dev/config.lisp +354 -0
- data/lib/clucumber/vendor/lift/dev/copy-file.lisp +117 -0
- data/lib/clucumber/vendor/lift/dev/introspection.lisp +232 -0
- data/lib/clucumber/vendor/lift/dev/lift-interface.lisp +56 -0
- data/lib/clucumber/vendor/lift/dev/lift-notes.lisp +202 -0
- data/lib/clucumber/vendor/lift/dev/lift-randomized.lisp +45 -0
- data/lib/clucumber/vendor/lift/dev/lift.lisp +2383 -0
- data/lib/clucumber/vendor/lift/dev/macros.lisp +229 -0
- data/lib/clucumber/vendor/lift/dev/measuring.lisp +156 -0
- data/lib/clucumber/vendor/lift/dev/packages.lisp +161 -0
- data/lib/clucumber/vendor/lift/dev/port.lisp +151 -0
- data/lib/clucumber/vendor/lift/dev/prototypes.lisp +282 -0
- data/lib/clucumber/vendor/lift/dev/random-testing.lisp +124 -0
- data/lib/clucumber/vendor/lift/dev/report-locations.lisp +13 -0
- data/lib/clucumber/vendor/lift/dev/reports.lisp +916 -0
- data/lib/clucumber/vendor/lift/dev/utilities.lisp +242 -0
- data/lib/clucumber/vendor/lift/docs/package.lisp +6 -0
- data/lib/clucumber/vendor/lift/docs/setup.lisp +17 -0
- data/lib/clucumber/vendor/lift/examples/basic-examples.lisp +289 -0
- data/lib/clucumber/vendor/lift/examples/random-testing.lisp +32 -0
- data/lib/clucumber/vendor/lift/lift-documentation.asd +28 -0
- data/lib/clucumber/vendor/lift/lift-test.asd +35 -0
- data/lib/clucumber/vendor/lift/lift.asd +77 -0
- data/lib/clucumber/vendor/lift/test/equality-tests.lisp +40 -0
- data/lib/clucumber/vendor/lift/test/finding-tests.lisp +32 -0
- data/lib/clucumber/vendor/lift/test/lift-test.lisp +783 -0
- data/lib/clucumber/vendor/lift/test/order-of-operations.lisp +54 -0
- data/lib/clucumber/vendor/lift/test/packages.lisp +17 -0
- data/lib/clucumber/vendor/lift/test/test-config-files.lisp +20 -0
- data/lib/clucumber/vendor/lift/test/test-dynamic-variables.lisp +57 -0
- data/lib/clucumber/vendor/lift/test/test-maximum-problems.lisp +74 -0
- data/lib/clucumber/vendor/lift/test/test-prototypes.lisp +278 -0
- data/lib/clucumber/vendor/lift/test/test-timeout.lisp +37 -0
- data/lib/clucumber/vendor/lift/test/tests-in-progress.lisp +62 -0
- data/lib/clucumber/vendor/lift/test/testsuite-expects.lisp +60 -0
- data/lib/clucumber/vendor/lift/timeout/package.lisp +13 -0
- data/lib/clucumber/vendor/lift/timeout/with-timeout.lisp +123 -0
- data/lib/clucumber/vendor/lift/website/stuff/Temp.lisp +34 -0
- data/lib/clucumber/vendor/st-json/st-json.asd +3 -0
- data/lib/clucumber/vendor/st-json/st-json.lisp +310 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/backtrace.lisp +127 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/fallback.lisp +10 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/map-backtrace.lisp +103 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/mucking.lisp +75 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/packages.lisp +13 -0
- data/lib/clucumber/vendor/trivial-backtrace/dev/utilities.lisp +104 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/packages.lisp +5 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/test-setup.lisp +4 -0
- data/lib/clucumber/vendor/trivial-backtrace/test/tests.lisp +16 -0
- data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace-test.asd +22 -0
- data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace.asd +35 -0
- data/lib/clucumber/vendor/usocket/backend/allegro.lisp +199 -0
- data/lib/clucumber/vendor/usocket/backend/armedbear.lisp +491 -0
- data/lib/clucumber/vendor/usocket/backend/clisp.lisp +260 -0
- data/lib/clucumber/vendor/usocket/backend/cmucl.lisp +266 -0
- data/lib/clucumber/vendor/usocket/backend/lispworks.lisp +741 -0
- data/lib/clucumber/vendor/usocket/backend/mcl.lisp +369 -0
- data/lib/clucumber/vendor/usocket/backend/openmcl.lisp +206 -0
- data/lib/clucumber/vendor/usocket/backend/sbcl.lisp +424 -0
- data/lib/clucumber/vendor/usocket/backend/scl.lisp +261 -0
- data/lib/clucumber/vendor/usocket/condition.lisp +227 -0
- data/lib/clucumber/vendor/usocket/package.lisp +82 -0
- data/lib/clucumber/vendor/usocket/server.lisp +45 -0
- data/lib/clucumber/vendor/usocket/test/package.lisp +13 -0
- data/lib/clucumber/vendor/usocket/test/test-usocket.lisp +166 -0
- data/lib/clucumber/vendor/usocket/usocket-test.asd +26 -0
- data/lib/clucumber/vendor/usocket/usocket.asd +37 -0
- data/lib/clucumber/vendor/usocket/usocket.lisp +542 -0
- data/lib/clucumber/vendor/usocket/vendor/kqueue.lisp +1 -0
- data/lib/clucumber/vendor/usocket/vendor/split-sequence.lisp +245 -0
- data/lib/clucumber.rb +29 -7
- metadata +151 -5
@@ -0,0 +1,542 @@
|
|
1
|
+
;;;; $Id: usocket.lisp 518 2010-01-13 07:01:21Z ctian $
|
2
|
+
;;;; $URL: svn://common-lisp.net/project/usocket/svn/usocket/trunk/usocket.lisp $
|
3
|
+
|
4
|
+
;;;; See LICENSE for licensing information.
|
5
|
+
|
6
|
+
(in-package :usocket)
|
7
|
+
|
8
|
+
(defparameter *wildcard-host* #(0 0 0 0)
|
9
|
+
"Hostname to pass when all interfaces in the current system are to be bound.")
|
10
|
+
|
11
|
+
(defparameter *auto-port* 0
|
12
|
+
"Port number to pass when an auto-assigned port number is wanted.")
|
13
|
+
|
14
|
+
(defconstant +max-datagram-packet-size+ 65536)
|
15
|
+
|
16
|
+
(defclass usocket ()
|
17
|
+
((socket
|
18
|
+
:initarg :socket
|
19
|
+
:accessor socket
|
20
|
+
:documentation "Implementation specific socket object instance.'")
|
21
|
+
(wait-list
|
22
|
+
:initform nil
|
23
|
+
:accessor wait-list
|
24
|
+
:documentation "WAIT-LIST the object is associated with.")
|
25
|
+
(state
|
26
|
+
:initform nil
|
27
|
+
:accessor state
|
28
|
+
:documentation "Per-socket return value for the `wait-for-input' function.
|
29
|
+
|
30
|
+
The value stored in this slot can be any of
|
31
|
+
NIL - not ready
|
32
|
+
:READ - ready to read
|
33
|
+
:READ-WRITE - ready to read and write
|
34
|
+
:WRITE - ready to write
|
35
|
+
|
36
|
+
The last two remain unused in the current version.
|
37
|
+
")
|
38
|
+
#+(and lispworks win32)
|
39
|
+
(%ready-p
|
40
|
+
:initform nil
|
41
|
+
:accessor %ready-p
|
42
|
+
:documentation "Indicates whether the socket has been signalled
|
43
|
+
as ready for reading a new connection.
|
44
|
+
|
45
|
+
The value will be set to T by `wait-for-input-internal' (given the
|
46
|
+
right conditions) and reset to NIL by `socket-accept'.
|
47
|
+
|
48
|
+
Don't modify this slot or depend on it as it is really intended
|
49
|
+
to be internal only.
|
50
|
+
|
51
|
+
Note: Accessed, but not used for 'stream-usocket'.
|
52
|
+
"
|
53
|
+
))
|
54
|
+
(:documentation
|
55
|
+
"The main socket class.
|
56
|
+
|
57
|
+
Sockets should be closed using the `socket-close' method."))
|
58
|
+
|
59
|
+
(defclass stream-usocket (usocket)
|
60
|
+
((stream
|
61
|
+
:initarg :stream
|
62
|
+
:accessor socket-stream
|
63
|
+
:documentation "Stream instance associated with the socket."
|
64
|
+
;;
|
65
|
+
;;Iff an external-format was passed to `socket-connect' or `socket-listen'
|
66
|
+
;;the stream is a flexi-stream. Otherwise the stream is implementation
|
67
|
+
;;specific."
|
68
|
+
))
|
69
|
+
(:documentation
|
70
|
+
"Stream socket class.
|
71
|
+
'
|
72
|
+
Contrary to other sockets, these sockets may be closed either
|
73
|
+
with the `socket-close' method or by closing the associated stream
|
74
|
+
(which can be retrieved with the `socket-stream' accessor)."))
|
75
|
+
|
76
|
+
(defclass stream-server-usocket (usocket)
|
77
|
+
((element-type
|
78
|
+
:initarg :element-type
|
79
|
+
:initform #-lispworks 'character
|
80
|
+
#+lispworks 'base-char
|
81
|
+
:reader element-type
|
82
|
+
:documentation "Default element type for streams created by
|
83
|
+
`socket-accept'."))
|
84
|
+
(:documentation "Socket which listens for stream connections to
|
85
|
+
be initiated from remote sockets."))
|
86
|
+
|
87
|
+
(defclass datagram-usocket (usocket)
|
88
|
+
((connected-p :type boolean
|
89
|
+
:accessor connected-p
|
90
|
+
:initarg :connected-p)
|
91
|
+
#+(or cmu scl lispworks)
|
92
|
+
(%open-p :type boolean
|
93
|
+
:accessor %open-p
|
94
|
+
:initform t
|
95
|
+
:documentation "Flag to indicate if usocket is open,
|
96
|
+
for GC on implementions operate on raw socket fd."))
|
97
|
+
(:documentation "UDP (inet-datagram) socket"))
|
98
|
+
|
99
|
+
(defun usocket-p (socket)
|
100
|
+
(typep socket 'usocket))
|
101
|
+
|
102
|
+
(defun stream-usocket-p (socket)
|
103
|
+
(typep socket 'stream-usocket))
|
104
|
+
|
105
|
+
(defun stream-server-usocket-p (socket)
|
106
|
+
(typep socket 'stream-server-usocket))
|
107
|
+
|
108
|
+
(defun datagram-usocket-p (socket)
|
109
|
+
(typep socket 'datagram-usocket))
|
110
|
+
|
111
|
+
(defun make-socket (&key socket)
|
112
|
+
"Create a usocket socket type from implementation specific socket."
|
113
|
+
(unless socket
|
114
|
+
(error 'invalid-socket))
|
115
|
+
(make-stream-socket :socket socket))
|
116
|
+
|
117
|
+
(defun make-stream-socket (&key socket stream)
|
118
|
+
"Create a usocket socket type from implementation specific socket
|
119
|
+
and stream objects.
|
120
|
+
|
121
|
+
Sockets returned should be closed using the `socket-close' method or
|
122
|
+
by closing the stream associated with the socket.
|
123
|
+
"
|
124
|
+
(unless socket
|
125
|
+
(error 'invalid-socket-error))
|
126
|
+
(unless stream
|
127
|
+
(error 'invalid-socket-stream-error))
|
128
|
+
(make-instance 'stream-usocket
|
129
|
+
:socket socket
|
130
|
+
:stream stream))
|
131
|
+
|
132
|
+
(defun make-stream-server-socket (socket &key (element-type
|
133
|
+
#-lispworks 'character
|
134
|
+
#+lispworks 'base-char))
|
135
|
+
"Create a usocket-server socket type from an
|
136
|
+
implementation-specific socket object.
|
137
|
+
|
138
|
+
The returned value is a subtype of `stream-server-usocket'.
|
139
|
+
"
|
140
|
+
(unless socket
|
141
|
+
(error 'invalid-socket-error))
|
142
|
+
(make-instance 'stream-server-usocket
|
143
|
+
:socket socket
|
144
|
+
:element-type element-type))
|
145
|
+
|
146
|
+
(defun make-datagram-socket (socket &key connected-p)
|
147
|
+
(unless socket
|
148
|
+
(error 'invalid-socket-error))
|
149
|
+
(make-instance 'datagram-usocket
|
150
|
+
:socket socket
|
151
|
+
:connected-p connected-p))
|
152
|
+
|
153
|
+
(defgeneric socket-accept (socket &key element-type)
|
154
|
+
(:documentation
|
155
|
+
"Accepts a connection from `socket', returning a `stream-socket'.
|
156
|
+
|
157
|
+
The stream associated with the socket returned has `element-type' when
|
158
|
+
explicitly specified, or the element-type passed to `socket-listen' otherwise."))
|
159
|
+
|
160
|
+
(defgeneric socket-close (usocket)
|
161
|
+
(:documentation "Close a previously opened `usocket'."))
|
162
|
+
|
163
|
+
(defgeneric socket-send (usocket buffer length &key host port)
|
164
|
+
(:documentation "Send packets through a previously opend `usocket'."))
|
165
|
+
|
166
|
+
(defgeneric socket-receive (usocket buffer length &key)
|
167
|
+
(:documentation "Receive packets from a previously opend `usocket'.
|
168
|
+
|
169
|
+
Returns 4 values: (values buffer size host port)"))
|
170
|
+
|
171
|
+
(defgeneric get-local-address (socket)
|
172
|
+
(:documentation "Returns the IP address of the socket."))
|
173
|
+
|
174
|
+
(defgeneric get-peer-address (socket)
|
175
|
+
(:documentation
|
176
|
+
"Returns the IP address of the peer the socket is connected to."))
|
177
|
+
|
178
|
+
(defgeneric get-local-port (socket)
|
179
|
+
(:documentation "Returns the IP port of the socket.
|
180
|
+
|
181
|
+
This function applies to both `stream-usocket' and `server-stream-usocket'
|
182
|
+
type objects."))
|
183
|
+
|
184
|
+
(defgeneric get-peer-port (socket)
|
185
|
+
(:documentation "Returns the IP port of the peer the socket to."))
|
186
|
+
|
187
|
+
(defgeneric get-local-name (socket)
|
188
|
+
(:documentation "Returns the IP address and port of the socket as values.
|
189
|
+
|
190
|
+
This function applies to both `stream-usocket' and `server-stream-usocket'
|
191
|
+
type objects."))
|
192
|
+
|
193
|
+
(defgeneric get-peer-name (socket)
|
194
|
+
(:documentation
|
195
|
+
"Returns the IP address and port of the peer
|
196
|
+
the socket is connected to as values."))
|
197
|
+
|
198
|
+
(defmacro with-connected-socket ((var socket) &body body)
|
199
|
+
"Bind `socket' to `var', ensuring socket destruction on exit.
|
200
|
+
|
201
|
+
`body' is only evaluated when `var' is bound to a non-null value.
|
202
|
+
|
203
|
+
The `body' is an implied progn form."
|
204
|
+
`(let ((,var ,socket))
|
205
|
+
(unwind-protect
|
206
|
+
(when ,var
|
207
|
+
(with-mapped-conditions (,var)
|
208
|
+
,@body))
|
209
|
+
(when ,var
|
210
|
+
(socket-close ,var)))))
|
211
|
+
|
212
|
+
(defmacro with-client-socket ((socket-var stream-var &rest socket-connect-args)
|
213
|
+
&body body)
|
214
|
+
"Bind the socket resulting from a call to `socket-connect' with
|
215
|
+
the arguments `socket-connect-args' to `socket-var' and if `stream-var' is
|
216
|
+
non-nil, bind the associated socket stream to it."
|
217
|
+
`(with-connected-socket (,socket-var (socket-connect ,@socket-connect-args))
|
218
|
+
,(if (null stream-var)
|
219
|
+
`(progn ,@body)
|
220
|
+
`(let ((,stream-var (socket-stream ,socket-var)))
|
221
|
+
,@body))))
|
222
|
+
|
223
|
+
(defmacro with-server-socket ((var server-socket) &body body)
|
224
|
+
"Bind `server-socket' to `var', ensuring socket destruction on exit.
|
225
|
+
|
226
|
+
`body' is only evaluated when `var' is bound to a non-null value.
|
227
|
+
|
228
|
+
The `body' is an implied progn form."
|
229
|
+
`(with-connected-socket (,var ,server-socket)
|
230
|
+
,@body))
|
231
|
+
|
232
|
+
(defmacro with-socket-listener ((socket-var &rest socket-listen-args)
|
233
|
+
&body body)
|
234
|
+
"Bind the socket resulting from a call to `socket-listen' with arguments
|
235
|
+
`socket-listen-args' to `socket-var'."
|
236
|
+
`(with-server-socket (,socket-var (socket-listen ,@socket-listen-args))
|
237
|
+
,@body))
|
238
|
+
|
239
|
+
|
240
|
+
(defstruct (wait-list (:constructor %make-wait-list))
|
241
|
+
%wait ;; implementation specific
|
242
|
+
waiters ;; the list of all usockets
|
243
|
+
map ;; maps implementation sockets to usockets
|
244
|
+
)
|
245
|
+
|
246
|
+
;; Implementation specific:
|
247
|
+
;;
|
248
|
+
;; %setup-wait-list
|
249
|
+
;; %add-waiter
|
250
|
+
;; %remove-waiter
|
251
|
+
|
252
|
+
(defun make-wait-list (waiters)
|
253
|
+
(let ((wl (%make-wait-list)))
|
254
|
+
(setf (wait-list-map wl) (make-hash-table))
|
255
|
+
(%setup-wait-list wl)
|
256
|
+
(dolist (x waiters)
|
257
|
+
(add-waiter wl x))
|
258
|
+
wl))
|
259
|
+
|
260
|
+
(defun add-waiter (wait-list input)
|
261
|
+
(setf (gethash (socket input) (wait-list-map wait-list)) input
|
262
|
+
(wait-list input) wait-list)
|
263
|
+
(pushnew input (wait-list-waiters wait-list))
|
264
|
+
(%add-waiter wait-list input))
|
265
|
+
|
266
|
+
(defun remove-waiter (wait-list input)
|
267
|
+
(%remove-waiter wait-list input)
|
268
|
+
(setf (wait-list-waiters wait-list)
|
269
|
+
(remove input (wait-list-waiters wait-list))
|
270
|
+
(wait-list input) nil)
|
271
|
+
(remhash (socket input) (wait-list-map wait-list)))
|
272
|
+
|
273
|
+
(defun remove-all-waiters (wait-list)
|
274
|
+
(dolist (waiter (wait-list-waiters wait-list))
|
275
|
+
(%remove-waiter wait-list waiter))
|
276
|
+
(setf (wait-list-waiters wait-list) nil)
|
277
|
+
(clrhash (wait-list-map wait-list)))
|
278
|
+
|
279
|
+
|
280
|
+
(defun wait-for-input (socket-or-sockets &key timeout ready-only)
|
281
|
+
"Waits for one or more streams to become ready for reading from
|
282
|
+
the socket. When `timeout' (a non-negative real number) is
|
283
|
+
specified, wait `timeout' seconds, or wait indefinitely when
|
284
|
+
it isn't specified. A `timeout' value of 0 (zero) means polling.
|
285
|
+
|
286
|
+
Returns two values: the first value is the list of streams which
|
287
|
+
are readable (or in case of server streams acceptable). NIL may
|
288
|
+
be returned for this value either when waiting timed out or when
|
289
|
+
it was interrupted (EINTR). The second value is a real number
|
290
|
+
indicating the time remaining within the timeout period or NIL if
|
291
|
+
none."
|
292
|
+
(unless (wait-list-p socket-or-sockets)
|
293
|
+
(let ((wl (make-wait-list (if (listp socket-or-sockets)
|
294
|
+
socket-or-sockets (list socket-or-sockets)))))
|
295
|
+
(multiple-value-bind
|
296
|
+
(socks to)
|
297
|
+
(wait-for-input wl :timeout timeout :ready-only ready-only)
|
298
|
+
(return-from wait-for-input
|
299
|
+
(values (if ready-only socks socket-or-sockets) to)))))
|
300
|
+
(let* ((start (get-internal-real-time))
|
301
|
+
(sockets-ready 0))
|
302
|
+
(dolist (x (wait-list-waiters socket-or-sockets))
|
303
|
+
(when (setf (state x)
|
304
|
+
(if (and (stream-usocket-p x)
|
305
|
+
(listen (socket-stream x)))
|
306
|
+
:READ NIL))
|
307
|
+
(incf sockets-ready)))
|
308
|
+
;; the internal routine is responsibe for
|
309
|
+
;; making sure the wait doesn't block on socket-streams of
|
310
|
+
;; which theready- socket isn't ready, but there's space left in the
|
311
|
+
;; buffer
|
312
|
+
(wait-for-input-internal socket-or-sockets
|
313
|
+
:timeout (if (zerop sockets-ready) timeout 0))
|
314
|
+
(let ((to-result (when timeout
|
315
|
+
(let ((elapsed (/ (- (get-internal-real-time) start)
|
316
|
+
internal-time-units-per-second)))
|
317
|
+
(when (< elapsed timeout)
|
318
|
+
(- timeout elapsed))))))
|
319
|
+
(values (if ready-only
|
320
|
+
(remove-if #'null (wait-list-waiters socket-or-sockets) :key #'state)
|
321
|
+
socket-or-sockets)
|
322
|
+
to-result))))
|
323
|
+
|
324
|
+
;;
|
325
|
+
;; Data utility functions
|
326
|
+
;;
|
327
|
+
|
328
|
+
(defun integer-to-octet-buffer (integer buffer octets &key (start 0))
|
329
|
+
(do ((b start (1+ b))
|
330
|
+
(i (ash (1- octets) 3) ;; * 8
|
331
|
+
(- i 8)))
|
332
|
+
((> 0 i) buffer)
|
333
|
+
(setf (aref buffer b)
|
334
|
+
(ldb (byte 8 i) integer))))
|
335
|
+
|
336
|
+
(defun octet-buffer-to-integer (buffer octets &key (start 0))
|
337
|
+
(let ((integer 0))
|
338
|
+
(do ((b start (1+ b))
|
339
|
+
(i (ash (1- octets) 3) ;; * 8
|
340
|
+
(- i 8)))
|
341
|
+
((> 0 i)
|
342
|
+
integer)
|
343
|
+
(setf (ldb (byte 8 i) integer)
|
344
|
+
(aref buffer b)))))
|
345
|
+
|
346
|
+
|
347
|
+
(defmacro port-to-octet-buffer (port buffer &key (start 0))
|
348
|
+
`(integer-to-octet-buffer ,port ,buffer 2 ,start))
|
349
|
+
|
350
|
+
(defmacro ip-to-octet-buffer (ip buffer &key (start 0))
|
351
|
+
`(integer-to-octet-buffer (host-byte-order ,ip) ,buffer 4 ,start))
|
352
|
+
|
353
|
+
(defmacro port-from-octet-buffer (buffer &key (start 0))
|
354
|
+
`(octet-buffer-to-integer ,buffer 2 ,start))
|
355
|
+
|
356
|
+
(defmacro ip-from-octet-buffer (buffer &key (start 0))
|
357
|
+
`(octet-buffer-to-integer ,buffer 4 ,start))
|
358
|
+
|
359
|
+
;;
|
360
|
+
;; IP(v4) utility functions
|
361
|
+
;;
|
362
|
+
|
363
|
+
(defun list-of-strings-to-integers (list)
|
364
|
+
"Take a list of strings and return a new list of integers (from
|
365
|
+
parse-integer) on each of the string elements."
|
366
|
+
(let ((new-list nil))
|
367
|
+
(dolist (element (reverse list))
|
368
|
+
(push (parse-integer element) new-list))
|
369
|
+
new-list))
|
370
|
+
|
371
|
+
(defun ip-address-string-p (string)
|
372
|
+
"Return a true value if the given string could be an IP address."
|
373
|
+
(every (lambda (char)
|
374
|
+
(or (digit-char-p char)
|
375
|
+
(eql char #\.)))
|
376
|
+
string))
|
377
|
+
|
378
|
+
(defun hbo-to-dotted-quad (integer)
|
379
|
+
"Host-byte-order integer to dotted-quad string conversion utility."
|
380
|
+
(let ((first (ldb (byte 8 24) integer))
|
381
|
+
(second (ldb (byte 8 16) integer))
|
382
|
+
(third (ldb (byte 8 8) integer))
|
383
|
+
(fourth (ldb (byte 8 0) integer)))
|
384
|
+
(format nil "~A.~A.~A.~A" first second third fourth)))
|
385
|
+
|
386
|
+
(defun hbo-to-vector-quad (integer)
|
387
|
+
"Host-byte-order integer to dotted-quad string conversion utility."
|
388
|
+
(let ((first (ldb (byte 8 24) integer))
|
389
|
+
(second (ldb (byte 8 16) integer))
|
390
|
+
(third (ldb (byte 8 8) integer))
|
391
|
+
(fourth (ldb (byte 8 0) integer)))
|
392
|
+
(vector first second third fourth)))
|
393
|
+
|
394
|
+
(defun vector-quad-to-dotted-quad (vector)
|
395
|
+
(format nil "~A.~A.~A.~A"
|
396
|
+
(aref vector 0)
|
397
|
+
(aref vector 1)
|
398
|
+
(aref vector 2)
|
399
|
+
(aref vector 3)))
|
400
|
+
|
401
|
+
(defun dotted-quad-to-vector-quad (string)
|
402
|
+
(let ((list (list-of-strings-to-integers (split-sequence #\. string))))
|
403
|
+
(vector (first list) (second list) (third list) (fourth list))))
|
404
|
+
|
405
|
+
(defgeneric host-byte-order (address))
|
406
|
+
(defmethod host-byte-order ((string string))
|
407
|
+
"Convert a string, such as 192.168.1.1, to host-byte-order,
|
408
|
+
such as 3232235777."
|
409
|
+
(let ((list (list-of-strings-to-integers (split-sequence #\. string))))
|
410
|
+
(+ (* (first list) 256 256 256) (* (second list) 256 256)
|
411
|
+
(* (third list) 256) (fourth list))))
|
412
|
+
|
413
|
+
(defmethod host-byte-order ((vector vector))
|
414
|
+
"Convert a vector, such as #(192 168 1 1), to host-byte-order, such as
|
415
|
+
3232235777."
|
416
|
+
(+ (* (aref vector 0) 256 256 256) (* (aref vector 1) 256 256)
|
417
|
+
(* (aref vector 2) 256) (aref vector 3)))
|
418
|
+
|
419
|
+
(defmethod host-byte-order ((int integer))
|
420
|
+
int)
|
421
|
+
|
422
|
+
(defun host-to-hostname (host)
|
423
|
+
"Translate a string or vector quad to a stringified hostname."
|
424
|
+
(etypecase host
|
425
|
+
(string host)
|
426
|
+
((or (vector t 4)
|
427
|
+
(array (unsigned-byte 8) (4)))
|
428
|
+
(vector-quad-to-dotted-quad host))
|
429
|
+
(integer (hbo-to-dotted-quad host))))
|
430
|
+
|
431
|
+
(defun ip= (ip1 ip2)
|
432
|
+
(etypecase ip1
|
433
|
+
(string (string= ip1 (host-to-hostname ip2)))
|
434
|
+
((or (vector t 4)
|
435
|
+
(array (unsigned-byte 8) (4)))
|
436
|
+
(or (eq ip1 ip2)
|
437
|
+
(and (= (aref ip1 0) (aref ip2 0))
|
438
|
+
(= (aref ip1 1) (aref ip2 1))
|
439
|
+
(= (aref ip1 2) (aref ip2 2))
|
440
|
+
(= (aref ip1 3) (aref ip2 3)))))
|
441
|
+
(integer (= ip1 (host-byte-order ip2)))))
|
442
|
+
|
443
|
+
(defun ip/= (ip1 ip2)
|
444
|
+
(not (ip= ip1 ip2)))
|
445
|
+
|
446
|
+
;;
|
447
|
+
;; DNS helper functions
|
448
|
+
;;
|
449
|
+
|
450
|
+
#-(or clisp armedbear)
|
451
|
+
(progn
|
452
|
+
(defun get-host-by-name (name)
|
453
|
+
(let ((hosts (get-hosts-by-name name)))
|
454
|
+
(car hosts)))
|
455
|
+
|
456
|
+
(defun get-random-host-by-name (name)
|
457
|
+
(let ((hosts (get-hosts-by-name name)))
|
458
|
+
(when hosts
|
459
|
+
(elt hosts (random (length hosts))))))
|
460
|
+
|
461
|
+
(defun host-to-vector-quad (host)
|
462
|
+
"Translate a host specification (vector quad, dotted quad or domain name)
|
463
|
+
to a vector quad."
|
464
|
+
(etypecase host
|
465
|
+
(string (let* ((ip (when (ip-address-string-p host)
|
466
|
+
(dotted-quad-to-vector-quad host))))
|
467
|
+
(if (and ip (= 4 (length ip)))
|
468
|
+
;; valid IP dotted quad?
|
469
|
+
ip
|
470
|
+
(get-random-host-by-name host))))
|
471
|
+
((or (vector t 4)
|
472
|
+
(array (unsigned-byte 8) (4)))
|
473
|
+
host)
|
474
|
+
(integer (hbo-to-vector-quad host))))
|
475
|
+
|
476
|
+
(defun host-to-hbo (host)
|
477
|
+
(etypecase host
|
478
|
+
(string (let ((ip (when (ip-address-string-p host)
|
479
|
+
(dotted-quad-to-vector-quad host))))
|
480
|
+
(if (and ip (= 4 (length ip)))
|
481
|
+
(host-byte-order ip)
|
482
|
+
(host-to-hbo (get-host-by-name host)))))
|
483
|
+
((or (vector t 4)
|
484
|
+
(array (unsigned-byte 8) (4)))
|
485
|
+
(host-byte-order host))
|
486
|
+
(integer host))))
|
487
|
+
|
488
|
+
;;
|
489
|
+
;; Other utility functions
|
490
|
+
;;
|
491
|
+
|
492
|
+
(defun split-timeout (timeout &optional (fractional 1000000))
|
493
|
+
"Split real value timeout into seconds and microseconds.
|
494
|
+
Optionally, a different fractional part can be specified."
|
495
|
+
(multiple-value-bind
|
496
|
+
(secs sec-frac)
|
497
|
+
(truncate timeout 1)
|
498
|
+
(values secs
|
499
|
+
(truncate (* fractional sec-frac) 1))))
|
500
|
+
|
501
|
+
|
502
|
+
|
503
|
+
|
504
|
+
;;
|
505
|
+
;; Setting of documentation for backend defined functions
|
506
|
+
;;
|
507
|
+
|
508
|
+
;; Documentation for the function
|
509
|
+
;;
|
510
|
+
;; (defun SOCKET-CONNECT (host port &key element-type) ..)
|
511
|
+
;;
|
512
|
+
(setf (documentation 'socket-connect 'function)
|
513
|
+
"Connect to `host' on `port'. `host' is assumed to be a string or
|
514
|
+
an IP address represented in vector notation, such as #(192 168 1 1).
|
515
|
+
`port' is assumed to be an integer.
|
516
|
+
|
517
|
+
`element-type' specifies the element type to use when constructing the
|
518
|
+
stream associated with the socket. The default is 'character.
|
519
|
+
|
520
|
+
Returns a usocket object.")
|
521
|
+
|
522
|
+
;; Documentation for the function
|
523
|
+
;;
|
524
|
+
;; (defun SOCKET-LISTEN (host port &key reuseaddress backlog element-type) ..)
|
525
|
+
;;###FIXME: extend with default-element-type
|
526
|
+
(setf (documentation 'socket-listen 'function)
|
527
|
+
"Bind to interface `host' on `port'. `host' should be the
|
528
|
+
representation of an ready-interface address. The implementation is not
|
529
|
+
required to do an address lookup, making no guarantees that hostnames
|
530
|
+
will be correctly resolved. If `*wildcard-host*' is passed for `host',
|
531
|
+
the socket will be bound to all available interfaces for the IPv4
|
532
|
+
protocol in the system. `port' can be selected by the IP stack by
|
533
|
+
passing `*auto-port*'.
|
534
|
+
|
535
|
+
Returns an object of type `stream-server-usocket'.
|
536
|
+
|
537
|
+
`reuse-address' and `backlog' are advisory parameters for setting socket
|
538
|
+
options at creation time. `element-type' is the element type of the
|
539
|
+
streams to be created by `socket-accept'. `reuseaddress' is supported for
|
540
|
+
backward compatibility (but deprecated); when both `reuseaddress' and
|
541
|
+
`reuse-address' have been specified, the latter takes precedence.
|
542
|
+
")
|