clucumber 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +4 -9
  3. data/lib/clucumber/clucumber-bootstrap.lisp +32 -0
  4. data/lib/clucumber/vendor/cl-interpol/alias.lisp +55 -0
  5. data/lib/clucumber/vendor/cl-interpol/cl-interpol.asd +56 -0
  6. data/lib/clucumber/vendor/cl-interpol/load.lisp +53 -0
  7. data/lib/clucumber/vendor/cl-interpol/packages.lisp +40 -0
  8. data/lib/clucumber/vendor/cl-interpol/read.lisp +716 -0
  9. data/lib/clucumber/vendor/cl-interpol/specials.lisp +113 -0
  10. data/lib/clucumber/vendor/cl-interpol/test/packages.lisp +34 -0
  11. data/lib/clucumber/vendor/cl-interpol/test/tests.lisp +128 -0
  12. data/lib/clucumber/vendor/cl-interpol/test.lisp +177 -0
  13. data/lib/clucumber/vendor/cl-interpol/test2.lisp +6254 -0
  14. data/lib/clucumber/vendor/cl-interpol/unicode.lisp +13912 -0
  15. data/lib/clucumber/vendor/cl-interpol/util.lisp +122 -0
  16. data/lib/clucumber/vendor/cl-ppcre/api.lisp +1262 -0
  17. data/lib/clucumber/vendor/cl-ppcre/charmap.lisp +152 -0
  18. data/lib/clucumber/vendor/cl-ppcre/charset.lisp +242 -0
  19. data/lib/clucumber/vendor/cl-ppcre/chartest.lisp +98 -0
  20. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-test.asd +34 -0
  21. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/packages.lisp +38 -0
  22. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode/resolver.lisp +61 -0
  23. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre-unicode.asd +58 -0
  24. data/lib/clucumber/vendor/cl-ppcre/cl-ppcre.asd +79 -0
  25. data/lib/clucumber/vendor/cl-ppcre/closures.lisp +471 -0
  26. data/lib/clucumber/vendor/cl-ppcre/convert.lisp +875 -0
  27. data/lib/clucumber/vendor/cl-ppcre/errors.lisp +84 -0
  28. data/lib/clucumber/vendor/cl-ppcre/lexer.lisp +737 -0
  29. data/lib/clucumber/vendor/cl-ppcre/lispworks-defsystem.lisp +57 -0
  30. data/lib/clucumber/vendor/cl-ppcre/load.lisp +67 -0
  31. data/lib/clucumber/vendor/cl-ppcre/optimize.lisp +578 -0
  32. data/lib/clucumber/vendor/cl-ppcre/packages.lisp +68 -0
  33. data/lib/clucumber/vendor/cl-ppcre/parser.lisp +319 -0
  34. data/lib/clucumber/vendor/cl-ppcre/ppcre-tests.lisp +269 -0
  35. data/lib/clucumber/vendor/cl-ppcre/regex-class-util.lisp +555 -0
  36. data/lib/clucumber/vendor/cl-ppcre/regex-class.lisp +259 -0
  37. data/lib/clucumber/vendor/cl-ppcre/repetition-closures.lisp +833 -0
  38. data/lib/clucumber/vendor/cl-ppcre/scanner.lisp +506 -0
  39. data/lib/clucumber/vendor/cl-ppcre/specials.lisp +172 -0
  40. data/lib/clucumber/vendor/cl-ppcre/test/packages.lisp +37 -0
  41. data/lib/clucumber/vendor/cl-ppcre/test/perl-tests.lisp +150 -0
  42. data/lib/clucumber/vendor/cl-ppcre/test/tests.lisp +159 -0
  43. data/lib/clucumber/vendor/cl-ppcre/test/unicode-tests.lisp +80 -0
  44. data/lib/clucumber/vendor/cl-ppcre/util.lisp +201 -0
  45. data/lib/clucumber/vendor/cl-unicode/alias.lisp +135 -0
  46. data/lib/clucumber/vendor/cl-unicode/api.lisp +412 -0
  47. data/lib/clucumber/vendor/cl-unicode/build/char-info.lisp +133 -0
  48. data/lib/clucumber/vendor/cl-unicode/build/dump.lisp +239 -0
  49. data/lib/clucumber/vendor/cl-unicode/build/read.lisp +280 -0
  50. data/lib/clucumber/vendor/cl-unicode/build/util.lisp +182 -0
  51. data/lib/clucumber/vendor/cl-unicode/cl-unicode.asd +90 -0
  52. data/lib/clucumber/vendor/cl-unicode/conditions.lisp +54 -0
  53. data/lib/clucumber/vendor/cl-unicode/derived.lisp +120 -0
  54. data/lib/clucumber/vendor/cl-unicode/hash-tables.lisp +20 -0
  55. data/lib/clucumber/vendor/cl-unicode/lists.lisp +10 -0
  56. data/lib/clucumber/vendor/cl-unicode/methods.lisp +15 -0
  57. data/lib/clucumber/vendor/cl-unicode/packages.lisp +76 -0
  58. data/lib/clucumber/vendor/cl-unicode/specials.lisp +135 -0
  59. data/lib/clucumber/vendor/cl-unicode/test/packages.lisp +34 -0
  60. data/lib/clucumber/vendor/cl-unicode/test/tests.lisp +150 -0
  61. data/lib/clucumber/vendor/cl-unicode/test-functions.lisp +94 -0
  62. data/lib/clucumber/vendor/cl-unicode/util.lisp +274 -0
  63. data/lib/clucumber/vendor/lift/compare/fiveam-tests.lisp +14 -0
  64. data/lib/clucumber/vendor/lift/compare/lift-tests.lisp +13 -0
  65. data/lib/clucumber/vendor/lift/compare/rt-tests.lisp +16 -0
  66. data/lib/clucumber/vendor/lift/compare/xlunit-tests.lisp +15 -0
  67. data/lib/clucumber/vendor/lift/dev/changes.lisp +61 -0
  68. data/lib/clucumber/vendor/lift/dev/config.lisp +354 -0
  69. data/lib/clucumber/vendor/lift/dev/copy-file.lisp +117 -0
  70. data/lib/clucumber/vendor/lift/dev/introspection.lisp +232 -0
  71. data/lib/clucumber/vendor/lift/dev/lift-interface.lisp +56 -0
  72. data/lib/clucumber/vendor/lift/dev/lift-notes.lisp +202 -0
  73. data/lib/clucumber/vendor/lift/dev/lift-randomized.lisp +45 -0
  74. data/lib/clucumber/vendor/lift/dev/lift.lisp +2383 -0
  75. data/lib/clucumber/vendor/lift/dev/macros.lisp +229 -0
  76. data/lib/clucumber/vendor/lift/dev/measuring.lisp +156 -0
  77. data/lib/clucumber/vendor/lift/dev/packages.lisp +161 -0
  78. data/lib/clucumber/vendor/lift/dev/port.lisp +151 -0
  79. data/lib/clucumber/vendor/lift/dev/prototypes.lisp +282 -0
  80. data/lib/clucumber/vendor/lift/dev/random-testing.lisp +124 -0
  81. data/lib/clucumber/vendor/lift/dev/report-locations.lisp +13 -0
  82. data/lib/clucumber/vendor/lift/dev/reports.lisp +916 -0
  83. data/lib/clucumber/vendor/lift/dev/utilities.lisp +242 -0
  84. data/lib/clucumber/vendor/lift/docs/package.lisp +6 -0
  85. data/lib/clucumber/vendor/lift/docs/setup.lisp +17 -0
  86. data/lib/clucumber/vendor/lift/examples/basic-examples.lisp +289 -0
  87. data/lib/clucumber/vendor/lift/examples/random-testing.lisp +32 -0
  88. data/lib/clucumber/vendor/lift/lift-documentation.asd +28 -0
  89. data/lib/clucumber/vendor/lift/lift-test.asd +35 -0
  90. data/lib/clucumber/vendor/lift/lift.asd +77 -0
  91. data/lib/clucumber/vendor/lift/test/equality-tests.lisp +40 -0
  92. data/lib/clucumber/vendor/lift/test/finding-tests.lisp +32 -0
  93. data/lib/clucumber/vendor/lift/test/lift-test.lisp +783 -0
  94. data/lib/clucumber/vendor/lift/test/order-of-operations.lisp +54 -0
  95. data/lib/clucumber/vendor/lift/test/packages.lisp +17 -0
  96. data/lib/clucumber/vendor/lift/test/test-config-files.lisp +20 -0
  97. data/lib/clucumber/vendor/lift/test/test-dynamic-variables.lisp +57 -0
  98. data/lib/clucumber/vendor/lift/test/test-maximum-problems.lisp +74 -0
  99. data/lib/clucumber/vendor/lift/test/test-prototypes.lisp +278 -0
  100. data/lib/clucumber/vendor/lift/test/test-timeout.lisp +37 -0
  101. data/lib/clucumber/vendor/lift/test/tests-in-progress.lisp +62 -0
  102. data/lib/clucumber/vendor/lift/test/testsuite-expects.lisp +60 -0
  103. data/lib/clucumber/vendor/lift/timeout/package.lisp +13 -0
  104. data/lib/clucumber/vendor/lift/timeout/with-timeout.lisp +123 -0
  105. data/lib/clucumber/vendor/lift/website/stuff/Temp.lisp +34 -0
  106. data/lib/clucumber/vendor/st-json/st-json.asd +3 -0
  107. data/lib/clucumber/vendor/st-json/st-json.lisp +310 -0
  108. data/lib/clucumber/vendor/trivial-backtrace/dev/backtrace.lisp +127 -0
  109. data/lib/clucumber/vendor/trivial-backtrace/dev/fallback.lisp +10 -0
  110. data/lib/clucumber/vendor/trivial-backtrace/dev/map-backtrace.lisp +103 -0
  111. data/lib/clucumber/vendor/trivial-backtrace/dev/mucking.lisp +75 -0
  112. data/lib/clucumber/vendor/trivial-backtrace/dev/packages.lisp +13 -0
  113. data/lib/clucumber/vendor/trivial-backtrace/dev/utilities.lisp +104 -0
  114. data/lib/clucumber/vendor/trivial-backtrace/test/packages.lisp +5 -0
  115. data/lib/clucumber/vendor/trivial-backtrace/test/test-setup.lisp +4 -0
  116. data/lib/clucumber/vendor/trivial-backtrace/test/tests.lisp +16 -0
  117. data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace-test.asd +22 -0
  118. data/lib/clucumber/vendor/trivial-backtrace/trivial-backtrace.asd +35 -0
  119. data/lib/clucumber/vendor/usocket/backend/allegro.lisp +199 -0
  120. data/lib/clucumber/vendor/usocket/backend/armedbear.lisp +491 -0
  121. data/lib/clucumber/vendor/usocket/backend/clisp.lisp +260 -0
  122. data/lib/clucumber/vendor/usocket/backend/cmucl.lisp +266 -0
  123. data/lib/clucumber/vendor/usocket/backend/lispworks.lisp +741 -0
  124. data/lib/clucumber/vendor/usocket/backend/mcl.lisp +369 -0
  125. data/lib/clucumber/vendor/usocket/backend/openmcl.lisp +206 -0
  126. data/lib/clucumber/vendor/usocket/backend/sbcl.lisp +424 -0
  127. data/lib/clucumber/vendor/usocket/backend/scl.lisp +261 -0
  128. data/lib/clucumber/vendor/usocket/condition.lisp +227 -0
  129. data/lib/clucumber/vendor/usocket/package.lisp +82 -0
  130. data/lib/clucumber/vendor/usocket/server.lisp +45 -0
  131. data/lib/clucumber/vendor/usocket/test/package.lisp +13 -0
  132. data/lib/clucumber/vendor/usocket/test/test-usocket.lisp +166 -0
  133. data/lib/clucumber/vendor/usocket/usocket-test.asd +26 -0
  134. data/lib/clucumber/vendor/usocket/usocket.asd +37 -0
  135. data/lib/clucumber/vendor/usocket/usocket.lisp +542 -0
  136. data/lib/clucumber/vendor/usocket/vendor/kqueue.lisp +1 -0
  137. data/lib/clucumber/vendor/usocket/vendor/split-sequence.lisp +245 -0
  138. data/lib/clucumber.rb +29 -7
  139. 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
+ ")