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,741 @@
1
+ ;;;; $Id: lispworks.lisp 521 2010-02-21 03:38:51Z ctian $
2
+ ;;;; $URL: svn://common-lisp.net/project/usocket/svn/usocket/trunk/backend/lispworks.lisp $
3
+
4
+ ;;;; See LICENSE for licensing information.
5
+
6
+ (in-package :usocket)
7
+
8
+ (eval-when (:compile-toplevel :load-toplevel :execute)
9
+ (require "comm")
10
+
11
+ #+lispworks3
12
+ (error "LispWorks 3 is not supported by USOCKET."))
13
+
14
+ ;;; ---------------------------------------------------------------------------
15
+ ;;; Warn if multiprocessing is not running on Lispworks
16
+
17
+ (defun check-for-multiprocessing-started (&optional errorp)
18
+ (unless mp:*current-process*
19
+ (funcall (if errorp 'error 'warn)
20
+ "You must start multiprocessing on Lispworks by calling~
21
+ ~%~3t(~s)~
22
+ ~%for ~s function properly."
23
+ 'mp:initialize-multiprocessing
24
+ 'wait-for-input)))
25
+
26
+ (eval-when (:load-toplevel :execute)
27
+ (check-for-multiprocessing-started))
28
+
29
+ #+win32
30
+ (eval-when (:load-toplevel :execute)
31
+ (fli:register-module "ws2_32")
32
+ (comm::ensure-sockets))
33
+
34
+ (fli:define-foreign-function (get-host-name-internal "gethostname" :source)
35
+ ((return-string (:reference-return (:ef-mb-string :limit 257)))
36
+ (namelen :int))
37
+ :lambda-list (&aux (namelen 256) return-string)
38
+ :result-type :int
39
+ #+win32 :module
40
+ #+win32 "ws2_32")
41
+
42
+ (defun get-host-name ()
43
+ (multiple-value-bind (retcode name)
44
+ (get-host-name-internal)
45
+ (when (= 0 retcode)
46
+ name)))
47
+
48
+ #+win32
49
+ (defun remap-maybe-for-win32 (z)
50
+ (mapcar #'(lambda (x)
51
+ (cons (mapcar #'(lambda (y)
52
+ (+ 10000 y))
53
+ (car x))
54
+ (cdr x)))
55
+ z))
56
+
57
+ (defparameter +lispworks-error-map+
58
+ #+win32
59
+ (append (remap-maybe-for-win32 +unix-errno-condition-map+)
60
+ (remap-maybe-for-win32 +unix-errno-error-map+))
61
+ #-win32
62
+ (append +unix-errno-condition-map+
63
+ +unix-errno-error-map+))
64
+
65
+ (defun raise-or-signal-socket-error (errno socket)
66
+ (let ((usock-err
67
+ (cdr (assoc errno +lispworks-error-map+ :test #'member))))
68
+ (if usock-err
69
+ (if (subtypep usock-err 'error)
70
+ (error usock-err :socket socket)
71
+ (signal usock-err :socket))
72
+ (error 'unknown-error
73
+ :socket socket
74
+ :real-condition nil))))
75
+
76
+ (defun raise-usock-err (errno socket &optional condition)
77
+ (let* ((usock-err
78
+ (cdr (assoc errno +lispworks-error-map+
79
+ :test #'member))))
80
+ (if usock-err
81
+ (if (subtypep usock-err 'error)
82
+ (error usock-err :socket socket)
83
+ (signal usock-err :socket))
84
+ (error 'unknown-error
85
+ :socket socket
86
+ :real-error condition))))
87
+
88
+ (defun handle-condition (condition &optional (socket nil))
89
+ "Dispatch correct usocket condition."
90
+ (typecase condition
91
+ (simple-error (destructuring-bind (&optional host port err-msg errno)
92
+ (simple-condition-format-arguments condition)
93
+ (declare (ignore host port err-msg))
94
+ (raise-usock-err errno socket condition)))))
95
+
96
+ (defconstant *socket_sock_dgram* 2
97
+ "Connectionless, unreliable datagrams of fixed maximum length.")
98
+
99
+ (defconstant *sockopt_so_rcvtimeo*
100
+ #+(not linux) #x1006
101
+ #+linux 20
102
+ "Socket receive timeout")
103
+
104
+ (fli:define-c-struct timeval
105
+ (tv-sec :long)
106
+ (tv-usec :long))
107
+
108
+ ;;; ssize_t
109
+ ;;; recvfrom(int socket, void *restrict buffer, size_t length, int flags,
110
+ ;;; struct sockaddr *restrict address, socklen_t *restrict address_len);
111
+ (fli:define-foreign-function (%recvfrom "recvfrom" :source)
112
+ ((socket :int)
113
+ (buffer (:pointer (:unsigned :byte)))
114
+ (length :int)
115
+ (flags :int)
116
+ (address (:pointer (:struct comm::sockaddr)))
117
+ (address-len (:pointer :int)))
118
+ :result-type :int
119
+ #+win32 :module
120
+ #+win32 "ws2_32")
121
+
122
+ ;;; ssize_t
123
+ ;;; sendto(int socket, const void *buffer, size_t length, int flags,
124
+ ;;; const struct sockaddr *dest_addr, socklen_t dest_len);
125
+ (fli:define-foreign-function (%sendto "sendto" :source)
126
+ ((socket :int)
127
+ (buffer (:pointer (:unsigned :byte)))
128
+ (length :int)
129
+ (flags :int)
130
+ (address (:pointer (:struct comm::sockaddr)))
131
+ (address-len :int))
132
+ :result-type :int
133
+ #+win32 :module
134
+ #+win32 "ws2_32")
135
+
136
+ #-win32
137
+ (defun set-socket-receive-timeout (socket-fd seconds)
138
+ "Set socket option: RCVTIMEO, argument seconds can be a float number"
139
+ (declare (type integer socket-fd)
140
+ (type number seconds))
141
+ (multiple-value-bind (sec usec) (truncate seconds)
142
+ (fli:with-dynamic-foreign-objects ((timeout (:struct timeval)))
143
+ (fli:with-foreign-slots (tv-sec tv-usec) timeout
144
+ (setf tv-sec sec
145
+ tv-usec (truncate (* 1000000 usec)))
146
+ (if (zerop (comm::setsockopt socket-fd
147
+ comm::*sockopt_sol_socket*
148
+ *sockopt_so_rcvtimeo*
149
+ (fli:copy-pointer timeout
150
+ :type '(:pointer :void))
151
+ (fli:size-of '(:struct timeval))))
152
+ seconds)))))
153
+
154
+ #+win32
155
+ (defun set-socket-receive-timeout (socket-fd seconds)
156
+ "Set socket option: RCVTIMEO, argument seconds can be a float number.
157
+ On win32, you must bind the socket before use this function."
158
+ (declare (type integer socket-fd)
159
+ (type number seconds))
160
+ (fli:with-dynamic-foreign-objects ((timeout :int))
161
+ (setf (fli:dereference timeout)
162
+ (truncate (* 1000 seconds)))
163
+ (if (zerop (comm::setsockopt socket-fd
164
+ comm::*sockopt_sol_socket*
165
+ *sockopt_so_rcvtimeo*
166
+ (fli:copy-pointer timeout
167
+ :type '(:pointer :char))
168
+ (fli:size-of :int)))
169
+ seconds)))
170
+
171
+ #-win32
172
+ (defmethod get-socket-receive-timeout (socket-fd)
173
+ "Get socket option: RCVTIMEO, return value is a float number"
174
+ (declare (type integer socket-fd))
175
+ (fli:with-dynamic-foreign-objects ((timeout (:struct timeval))
176
+ (len :int))
177
+ (comm::getsockopt socket-fd
178
+ comm::*sockopt_sol_socket*
179
+ *sockopt_so_rcvtimeo*
180
+ (fli:copy-pointer timeout
181
+ :type '(:pointer :void))
182
+ len)
183
+ (fli:with-foreign-slots (tv-sec tv-usec) timeout
184
+ (float (+ tv-sec (/ tv-usec 1000000))))))
185
+
186
+ #+win32
187
+ (defmethod get-socket-receive-timeout (socket-fd)
188
+ "Get socket option: RCVTIMEO, return value is a float number"
189
+ (declare (type integer socket-fd))
190
+ (fli:with-dynamic-foreign-objects ((timeout :int)
191
+ (len :int))
192
+ (comm::getsockopt socket-fd
193
+ comm::*sockopt_sol_socket*
194
+ *sockopt_so_rcvtimeo*
195
+ (fli:copy-pointer timeout
196
+ :type '(:pointer :void))
197
+ len)
198
+ (float (/ (fli:dereference timeout) 1000))))
199
+
200
+ (defun open-udp-socket (&key local-address local-port read-timeout)
201
+ "Open a unconnected UDP socket.
202
+ For binding on address ANY(*), just not set LOCAL-ADDRESS (NIL),
203
+ for binding on random free unused port, set LOCAL-PORT to 0."
204
+ (let ((socket-fd (comm::socket comm::*socket_af_inet* *socket_sock_dgram* comm::*socket_pf_unspec*)))
205
+ (if socket-fd
206
+ (progn
207
+ (when read-timeout (set-socket-receive-timeout socket-fd read-timeout))
208
+ (if local-port
209
+ (fli:with-dynamic-foreign-objects ((client-addr (:struct comm::sockaddr_in)))
210
+ (comm::initialize-sockaddr_in client-addr comm::*socket_af_inet*
211
+ local-address local-port "udp")
212
+ (if (comm::bind socket-fd
213
+ (fli:copy-pointer client-addr :type '(:struct comm::sockaddr))
214
+ (fli:pointer-element-size client-addr))
215
+ ;; success, return socket fd
216
+ socket-fd
217
+ (progn
218
+ (comm::close-socket socket-fd)
219
+ (error "cannot bind"))))
220
+ socket-fd))
221
+ (error "cannot create socket"))))
222
+
223
+ (defun connect-to-udp-server (hostname service
224
+ &key local-address local-port read-timeout)
225
+ "Something like CONNECT-TO-TCP-SERVER"
226
+ (let ((socket-fd (open-udp-socket :local-address local-address
227
+ :local-port local-port
228
+ :read-timeout read-timeout)))
229
+ (if socket-fd
230
+ (fli:with-dynamic-foreign-objects ((server-addr (:struct comm::sockaddr_in)))
231
+ ;; connect to remote address/port
232
+ (comm::initialize-sockaddr_in server-addr comm::*socket_af_inet* hostname service "udp")
233
+ (if (comm::connect socket-fd
234
+ (fli:copy-pointer server-addr :type '(:struct comm::sockaddr))
235
+ (fli:pointer-element-size server-addr))
236
+ ;; success, return socket fd
237
+ socket-fd
238
+ ;; fail, close socket and return nil
239
+ (progn
240
+ (comm::close-socket socket-fd)
241
+ (error "cannot connect"))))
242
+ (error "cannot create socket"))))
243
+
244
+ ;; Register a special free action for closing datagram usocket when being GCed
245
+ (defun usocket-special-free-action (object)
246
+ (when (and (typep object 'datagram-usocket)
247
+ (%open-p object))
248
+ (socket-close object)))
249
+
250
+ (eval-when (:load-toplevel :execute)
251
+ (hcl:add-special-free-action 'usocket-special-free-action))
252
+
253
+ (defun socket-connect (host port &key (protocol :stream) (element-type 'base-char)
254
+ timeout deadline (nodelay t nodelay-specified)
255
+ local-host (local-port #+win32 *auto-port* #-win32 nil))
256
+ (declare (ignorable nodelay))
257
+
258
+ ;; What's the meaning of this keyword?
259
+ (when deadline
260
+ (unimplemented 'deadline 'socket-connect))
261
+
262
+ #+(and lispworks4 (not lispworks4.4)) ; < 4.4.5
263
+ (when timeout
264
+ (unsupported 'timeout 'socket-connect :minimum "LispWorks 4.4.5"))
265
+
266
+ #+(or lispworks4 lispworks5.0) ; < 5.1
267
+ (when nodelay-specified
268
+ (unsupported 'nodelay 'socket-connect :minimum "LispWorks 5.1"))
269
+
270
+ #+lispworks4 #+lispworks4
271
+ (when local-host
272
+ (unsupported 'local-host 'socket-connect :minimum "LispWorks 5.0"))
273
+ (when local-port
274
+ (unsupported 'local-port 'socket-connect :minimum "LispWorks 5.0"))
275
+
276
+ (ecase protocol
277
+ (:stream
278
+ (let ((hostname (host-to-hostname host))
279
+ (stream))
280
+ (setf stream
281
+ (with-mapped-conditions ()
282
+ (comm:open-tcp-stream hostname port
283
+ :element-type element-type
284
+ #-(and lispworks4 (not lispworks4.4)) ; >= 4.4.5
285
+ #-(and lispworks4 (not lispworks4.4))
286
+ :timeout timeout
287
+ #-lispworks4 #-lispworks4
288
+ #-lispworks4 #-lispworks4
289
+ :local-address (when local-host (host-to-hostname local-host))
290
+ :local-port local-port
291
+ #-(or lispworks4 lispworks5.0) ; >= 5.1
292
+ #-(or lispworks4 lispworks5.0)
293
+ :nodelay nodelay)))
294
+ (if stream
295
+ (make-stream-socket :socket (comm:socket-stream-socket stream)
296
+ :stream stream)
297
+ (error 'unknown-error))))
298
+ (:datagram
299
+ (let ((usocket (make-datagram-socket
300
+ (if (and host port)
301
+ (connect-to-udp-server host port
302
+ :local-address local-host
303
+ :local-port local-port)
304
+ (open-udp-socket :local-address local-host
305
+ :local-port local-port))
306
+ :connected-p t)))
307
+ (hcl:flag-special-free-action usocket)
308
+ usocket))))
309
+
310
+ (defun socket-listen (host port
311
+ &key reuseaddress
312
+ (reuse-address nil reuse-address-supplied-p)
313
+ (backlog 5)
314
+ (element-type 'base-char))
315
+ #+lispworks4.1
316
+ (unsupported 'host 'socket-listen :minimum "LispWorks 4.0 or newer than 4.1")
317
+ #+lispworks4.1
318
+ (unsupported 'backlog 'socket-listen :minimum "LispWorks 4.0 or newer than 4.1")
319
+
320
+ (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress))
321
+ (comm::*use_so_reuseaddr* reuseaddress)
322
+ (hostname (host-to-hostname host))
323
+ (sock (with-mapped-conditions ()
324
+ #-lispworks4.1 (comm::create-tcp-socket-for-service
325
+ port :address hostname :backlog backlog)
326
+ #+lispworks4.1 (comm::create-tcp-socket-for-service port))))
327
+ (make-stream-server-socket sock :element-type element-type)))
328
+
329
+ (defmethod socket-accept ((usocket stream-server-usocket) &key element-type)
330
+ (let* ((sock (with-mapped-conditions (usocket)
331
+ (comm::get-fd-from-socket (socket usocket))))
332
+ (stream (make-instance 'comm:socket-stream
333
+ :socket sock
334
+ :direction :io
335
+ :element-type (or element-type
336
+ (element-type usocket)))))
337
+ #+win32
338
+ (when sock
339
+ (setf (%ready-p usocket) nil))
340
+ (make-stream-socket :socket sock :stream stream)))
341
+
342
+ ;; Sockets and their streams are different objects
343
+ ;; close the stream in order to make sure buffers
344
+ ;; are correctly flushed and the socket closed.
345
+ (defmethod socket-close ((usocket stream-usocket))
346
+ "Close socket."
347
+ (when (wait-list usocket)
348
+ (remove-waiter (wait-list usocket) usocket))
349
+ (close (socket-stream usocket)))
350
+
351
+ (defmethod socket-close ((usocket usocket))
352
+ (when (wait-list usocket)
353
+ (remove-waiter (wait-list usocket) usocket))
354
+ (with-mapped-conditions (usocket)
355
+ (comm::close-socket (socket usocket))))
356
+
357
+ (defmethod socket-close :after ((socket datagram-usocket))
358
+ "Additional socket-close method for datagram-usocket"
359
+ (setf (%open-p socket) nil))
360
+
361
+ (defvar *message-send-buffer*
362
+ (make-array +max-datagram-packet-size+
363
+ :element-type '(unsigned-byte 8)
364
+ :allocation :static))
365
+
366
+ (defvar *message-send-lock*
367
+ (mp:make-lock :name "USOCKET message send lock"))
368
+
369
+ (defun send-message (socket-fd buffer &optional (length (length buffer)) host service)
370
+ "Send message to a socket, using sendto()/send()"
371
+ (declare (type integer socket-fd)
372
+ (type sequence buffer))
373
+ (let ((message *message-send-buffer*))
374
+ (fli:with-dynamic-foreign-objects ((client-addr (:struct comm::sockaddr_in))
375
+ (len :int
376
+ #-(or lispworks4 lispworks5.0) ; <= 5.0
377
+ :initial-element
378
+ (fli:size-of '(:struct comm::sockaddr_in))))
379
+ (fli:with-dynamic-lisp-array-pointer (ptr message :type '(:unsigned :byte))
380
+ (mp:with-lock (*message-send-lock*)
381
+ (replace message buffer :end2 length)
382
+ (if (and host service)
383
+ (progn
384
+ (comm::initialize-sockaddr_in client-addr comm::*socket_af_inet* host service "udp")
385
+ (%sendto socket-fd ptr (min length +max-datagram-packet-size+) 0
386
+ (fli:copy-pointer client-addr :type '(:struct comm::sockaddr))
387
+ (fli:dereference len)))
388
+ (comm::%send socket-fd ptr (min length +max-datagram-packet-size+) 0)))))))
389
+
390
+ (defmethod socket-send ((socket datagram-usocket) buffer length &key host port)
391
+ (let ((s (socket socket)))
392
+ (send-message s buffer length (and host (host-to-hbo host)) port)))
393
+
394
+ (defvar *message-receive-buffer*
395
+ (make-array +max-datagram-packet-size+
396
+ :element-type '(unsigned-byte 8)
397
+ :allocation :static))
398
+
399
+ (defvar *message-receive-lock*
400
+ (mp:make-lock :name "USOCKET message receive lock"))
401
+
402
+ (defun receive-message (socket-fd &optional buffer (length (length buffer))
403
+ &key read-timeout (max-buffer-size +max-datagram-packet-size+))
404
+ "Receive message from socket, read-timeout is a float number in seconds.
405
+
406
+ This function will return 4 values:
407
+ 1. receive buffer
408
+ 2. number of receive bytes
409
+ 3. remote address
410
+ 4. remote port"
411
+ (declare (type integer socket-fd)
412
+ (type sequence buffer))
413
+ (let ((message *message-receive-buffer*)
414
+ old-timeout)
415
+ (fli:with-dynamic-foreign-objects ((client-addr (:struct comm::sockaddr_in))
416
+ (len :int
417
+ #-(or lispworks4 lispworks5.0) ; <= 5.0
418
+ :initial-element
419
+ (fli:size-of '(:struct comm::sockaddr_in))))
420
+ (fli:with-dynamic-lisp-array-pointer (ptr message :type '(:unsigned :byte))
421
+ ;; setup new read timeout
422
+ (when read-timeout
423
+ (setf old-timeout (get-socket-receive-timeout socket-fd))
424
+ (set-socket-receive-timeout socket-fd read-timeout))
425
+ (mp:with-lock (*message-receive-lock*)
426
+ (let ((n (%recvfrom socket-fd ptr max-buffer-size 0
427
+ (fli:copy-pointer client-addr :type '(:struct comm::sockaddr))
428
+ len)))
429
+ ;; restore old read timeout
430
+ (when (and read-timeout (/= old-timeout read-timeout))
431
+ (set-socket-receive-timeout socket-fd old-timeout))
432
+ (if (plusp n)
433
+ (values (if buffer
434
+ (replace buffer message
435
+ :end1 (min length max-buffer-size)
436
+ :end2 (min n max-buffer-size))
437
+ (subseq message 0 (min n max-buffer-size)))
438
+ (min n max-buffer-size)
439
+ (comm::ntohl (fli:foreign-slot-value
440
+ (fli:foreign-slot-value client-addr
441
+ 'comm::sin_addr
442
+ :object-type '(:struct comm::sockaddr_in)
443
+ :type '(:struct comm::in_addr)
444
+ :copy-foreign-object nil)
445
+ 'comm::s_addr
446
+ :object-type '(:struct comm::in_addr)))
447
+ (comm::ntohs (fli:foreign-slot-value client-addr
448
+ 'comm::sin_port
449
+ :object-type '(:struct comm::sockaddr_in)
450
+ :type '(:unsigned :short)
451
+ :copy-foreign-object nil)))
452
+ (values nil n 0 0))))))))
453
+
454
+ (defmethod socket-receive ((socket datagram-usocket) buffer length &key)
455
+ (let ((s (socket socket)))
456
+ (multiple-value-bind (buffer size host port)
457
+ (receive-message s buffer length)
458
+ (values buffer size host port))))
459
+
460
+ (defmethod get-local-name ((usocket usocket))
461
+ (multiple-value-bind
462
+ (address port)
463
+ (comm:get-socket-address (socket usocket))
464
+ (values (hbo-to-vector-quad address) port)))
465
+
466
+ (defmethod get-peer-name ((usocket stream-usocket))
467
+ (multiple-value-bind
468
+ (address port)
469
+ (comm:get-socket-peer-address (socket usocket))
470
+ (values (hbo-to-vector-quad address) port)))
471
+
472
+ (defmethod get-local-address ((usocket usocket))
473
+ (nth-value 0 (get-local-name usocket)))
474
+
475
+ (defmethod get-peer-address ((usocket stream-usocket))
476
+ (nth-value 0 (get-peer-name usocket)))
477
+
478
+ (defmethod get-local-port ((usocket usocket))
479
+ (nth-value 1 (get-local-name usocket)))
480
+
481
+ (defmethod get-peer-port ((usocket stream-usocket))
482
+ (nth-value 1 (get-peer-name usocket)))
483
+
484
+ (defun get-hosts-by-name (name)
485
+ (with-mapped-conditions ()
486
+ (mapcar #'hbo-to-vector-quad
487
+ (comm:get-host-entry name :fields '(:addresses)))))
488
+
489
+ (defun os-socket-handle (usocket)
490
+ (socket usocket))
491
+
492
+ (defun usocket-listen (usocket)
493
+ (if (stream-usocket-p usocket)
494
+ (when (listen (socket-stream usocket))
495
+ usocket)
496
+ (when (comm::socket-listen (socket usocket))
497
+ usocket)))
498
+
499
+ ;;;
500
+ ;;; Non Windows implementation
501
+ ;;; The Windows implementation needs to resort to the Windows API in order
502
+ ;;; to achieve what we want (what we want is waiting without busy-looping)
503
+ ;;;
504
+
505
+ #-win32
506
+ (progn
507
+
508
+ (defun %setup-wait-list (wait-list)
509
+ (declare (ignore wait-list)))
510
+
511
+ (defun %add-waiter (wait-list waiter)
512
+ (declare (ignore wait-list waiter)))
513
+
514
+ (defun %remove-waiter (wait-list waiter)
515
+ (declare (ignore wait-list waiter)))
516
+
517
+ (defun wait-for-input-internal (wait-list &key timeout)
518
+ (with-mapped-conditions ()
519
+ ;; unfortunately, it's impossible to share code between
520
+ ;; non-win32 and win32 platforms...
521
+ ;; Can we have a sane -pref. complete [UDP!?]- API next time, please?
522
+ (dolist (x (wait-list-waiters wait-list))
523
+ (mp:notice-fd (os-socket-handle x)))
524
+ (labels ((wait-function (socks)
525
+ (let (rv)
526
+ (dolist (x socks rv)
527
+ (when (usocket-listen x)
528
+ (setf (state x) :READ
529
+ rv t))))))
530
+ (if timeout
531
+ (mp:process-wait-with-timeout "Waiting for a socket to become active"
532
+ (truncate timeout)
533
+ #'wait-function
534
+ (wait-list-waiters wait-list))
535
+ (mp:process-wait "Waiting for a socket to become active"
536
+ #'wait-function
537
+ (wait-list-waiters wait-list))))
538
+ (dolist (x (wait-list-waiters wait-list))
539
+ (mp:unnotice-fd (os-socket-handle x)))
540
+ wait-list))
541
+
542
+ ) ; end of block
543
+
544
+
545
+ ;;;
546
+ ;;; The Windows side of the story
547
+ ;;; We want to wait without busy looping
548
+ ;;; This code only works in threads which don't have (hidden)
549
+ ;;; windows which need to receive messages. There are workarounds in the Windows API
550
+ ;;; but are those available to 'us'.
551
+ ;;;
552
+
553
+
554
+ #+win32
555
+ (progn
556
+
557
+ ;; LispWorks doesn't provide an interface to wait for a socket
558
+ ;; to become ready (under Win32, that is) meaning that we need
559
+ ;; to resort to system calls to achieve the same thing.
560
+ ;; Luckily, it provides us access to the raw socket handles (as we
561
+ ;; wrote the code above.
562
+
563
+ (defconstant fd-read 1)
564
+ (defconstant fd-read-bit 0)
565
+ (defconstant fd-write 2)
566
+ (defconstant fd-write-bit 1)
567
+ (defconstant fd-oob 4)
568
+ (defconstant fd-oob-bit 2)
569
+ (defconstant fd-accept 8)
570
+ (defconstant fd-accept-bit 3)
571
+ (defconstant fd-connect 16)
572
+ (defconstant fd-connect-bit 4)
573
+ (defconstant fd-close 32)
574
+ (defconstant fd-close-bit 5)
575
+ (defconstant fd-qos 64)
576
+ (defconstant fd-qos-bit 6)
577
+ (defconstant fd-group-qos 128)
578
+ (defconstant fd-group-qos-bit 7)
579
+ (defconstant fd-routing-interface 256)
580
+ (defconstant fd-routing-interface-bit 8)
581
+ (defconstant fd-address-list-change 512)
582
+ (defconstant fd-address-list-change-bit 9)
583
+
584
+ (defconstant fd-max-events 10)
585
+
586
+ (defconstant fionread 1074030207)
587
+
588
+
589
+ ;; Note:
590
+ ;;
591
+ ;; If special finalization has to occur for a given
592
+ ;; system resource (handle), an associated object should
593
+ ;; be created. A special cleanup action should be added
594
+ ;; to the system and a special cleanup action should
595
+ ;; be flagged on all objects created for resources like it
596
+ ;;
597
+ ;; We have 2 functions to do so:
598
+ ;; * hcl:add-special-free-action (function-symbol)
599
+ ;; * hcl:flag-special-free-action (object)
600
+ ;;
601
+ ;; Note that the special free action will be called on all
602
+ ;; objects which have been flagged for special free, so be
603
+ ;; sure to check for the right argument type!
604
+
605
+ (fli:define-foreign-type ws-socket () '(:unsigned :int))
606
+ (fli:define-foreign-type win32-handle () '(:unsigned :int))
607
+ (fli:define-c-struct wsa-network-events (network-events :long)
608
+ (error-code (:c-array :int 10)))
609
+
610
+ (fli:define-foreign-function (wsa-event-create "WSACreateEvent" :source)
611
+ ()
612
+ :lambda-list nil
613
+ :result-type :int
614
+ :module "ws2_32")
615
+
616
+ (fli:define-foreign-function (wsa-event-close "WSACloseEvent" :source)
617
+ ((event-object win32-handle))
618
+ :result-type :int
619
+ :module "ws2_32")
620
+
621
+ (fli:define-foreign-function (wsa-enum-network-events "WSAEnumNetworkEvents" :source)
622
+ ((socket ws-socket)
623
+ (event-object win32-handle)
624
+ (network-events (:reference-return wsa-network-events)))
625
+ :result-type :int
626
+ :module "ws2_32")
627
+
628
+ (fli:define-foreign-function (wsa-event-select "WSAEventSelect" :source)
629
+ ((socket ws-socket)
630
+ (event-object win32-handle)
631
+ (network-events :long))
632
+ :result-type :int
633
+ :module "ws2_32")
634
+
635
+ (fli:define-foreign-function (wsa-get-last-error "WSAGetLastError" :source)
636
+ ()
637
+ :result-type :int
638
+ :module "ws2_32")
639
+
640
+ (fli:define-foreign-function (wsa-ioctlsocket "ioctlsocket" :source)
641
+ ((socket :long) (cmd :long) (argp (:ptr :long)))
642
+ :result-type :int
643
+ :module "ws2_32")
644
+
645
+
646
+ ;; The Windows system
647
+
648
+
649
+ ;; Now that we have access to the system calls, this is the plan:
650
+
651
+ ;; 1. Receive a wait-list with associated sockets to wait for
652
+ ;; 2. Add all those sockets to an event handle
653
+ ;; 3. Listen for an event on that handle (we have a LispWorks system:: internal for that)
654
+ ;; 4. After listening, detect if there are errors
655
+ ;; (this step is different from Unix, where we can have only one error)
656
+ ;; 5. If so, raise one of them
657
+ ;; 6. If not so, return the sockets which have input waiting for them
658
+
659
+
660
+ (defun maybe-wsa-error (rv &optional socket)
661
+ (unless (zerop rv)
662
+ (raise-usock-err (wsa-get-last-error) socket)))
663
+
664
+ (defun bytes-available-for-read (socket)
665
+ (fli:with-dynamic-foreign-objects ((int-ptr :long))
666
+ (let ((rv (wsa-ioctlsocket (os-socket-handle socket) fionread int-ptr)))
667
+ (if (= 0 rv)
668
+ (fli:dereference int-ptr)
669
+ 0))))
670
+
671
+ (defun socket-ready-p (socket)
672
+ (if (typep socket 'stream-usocket)
673
+ (< 0 (bytes-available-for-read socket))
674
+ (%ready-p socket)))
675
+
676
+ (defun waiting-required (sockets)
677
+ (notany #'socket-ready-p sockets))
678
+
679
+ (defun wait-for-input-internal (wait-list &key timeout)
680
+ (when (waiting-required (wait-list-waiters wait-list))
681
+ (system:wait-for-single-object (wait-list-%wait wait-list)
682
+ "Waiting for socket activity" timeout))
683
+ (update-ready-and-state-slots (wait-list-waiters wait-list)))
684
+
685
+ (defun map-network-events (func network-events)
686
+ (let ((event-map (fli:foreign-slot-value network-events 'network-events))
687
+ (error-array (fli:foreign-slot-pointer network-events 'error-code)))
688
+ (unless (zerop event-map)
689
+ (dotimes (i fd-max-events)
690
+ (unless (zerop (ldb (byte 1 i) event-map)) ;;### could be faster with ash and logand?
691
+ (funcall func (fli:foreign-aref error-array i)))))))
692
+
693
+ (defun update-ready-and-state-slots (sockets)
694
+ (dolist (socket sockets)
695
+ (if (or (and (stream-usocket-p socket)
696
+ (listen (socket-stream socket)))
697
+ (%ready-p socket))
698
+ (setf (state socket) :READ)
699
+ (multiple-value-bind
700
+ (rv network-events)
701
+ (wsa-enum-network-events (os-socket-handle socket) 0 t)
702
+ (if (zerop rv)
703
+ (map-network-events #'(lambda (err-code)
704
+ (if (zerop err-code)
705
+ (setf (%ready-p socket) t
706
+ (state socket) :READ)
707
+ (raise-usock-err err-code socket)))
708
+ network-events)
709
+ (maybe-wsa-error rv socket))))))
710
+
711
+
712
+
713
+ ;; The wait-list part
714
+
715
+ (defun free-wait-list (wl)
716
+ (when (wait-list-p wl)
717
+ (unless (null (wait-list-%wait wl))
718
+ (wsa-event-close (wait-list-%wait wl)))))
719
+
720
+ (eval-when (:load-toplevel :execute)
721
+ (hcl:add-special-free-action 'free-wait-list))
722
+
723
+ (defun %setup-wait-list (wait-list)
724
+ (hcl:flag-special-free-action wait-list)
725
+ (setf (wait-list-%wait wait-list) (wsa-event-create)))
726
+
727
+ (defun %add-waiter (wait-list waiter)
728
+ (let ((events (etypecase waiter
729
+ (stream-server-usocket (logior fd-connect fd-accept fd-close))
730
+ (stream-usocket (logior fd-connect fd-read fd-oob fd-close))
731
+ (datagram-usocket (logior fd-read)))))
732
+ (maybe-wsa-error
733
+ (wsa-event-select (os-socket-handle waiter) (wait-list-%wait wait-list) events)
734
+ waiter)))
735
+
736
+ (defun %remove-waiter (wait-list waiter)
737
+ (maybe-wsa-error
738
+ (wsa-event-select (os-socket-handle waiter) (wait-list-%wait wait-list) 0)
739
+ waiter))
740
+
741
+ ) ; end of WIN32-block