Introduction
Introduction Statistics Contact Development Disclaimer Help
tclisp.lisp - clic - Clic is an command line interactive client for gopher writ…
git clone git://bitreich.org/clic/ git://hg6vgqziawt5s4dj.onion/clic/
Log
Files
Refs
Tags
LICENSE
---
tclisp.lisp (26636B)
---
1 ;;;; See LICENSE for licensing information.
2
3 (in-package :usocket)
4
5 (eval-when (:compile-toplevel :load-toplevel :execute)
6 #-ffi
7 (warn "This image doesn't contain FFI package, GET-HOST-NAME won't wor…
8 #-(or ffi rawsock)
9 (warn "This image doesn't contain either FFI or RAWSOCK package, no UD…
10
11 ;; utility routine for looking up the current host name
12 #+ffi
13 (ffi:def-call-out get-host-name-internal
14 (:name "gethostname")
15 (:arguments (name (FFI:C-PTR (FFI:C-ARRAY-MAX ffi:character 256…
16 :OUT :ALLOCA)
17 (len ffi:int))
18 #+win32 (:library "WS2_32")
19 #-win32 (:library :default)
20 (:language #-win32 :stdc
21 #+win32 :stdc-stdcall)
22 (:return-type ffi:int))
23
24 (defun get-host-name ()
25 #+ffi
26 (multiple-value-bind (retcode name)
27 (get-host-name-internal 256)
28 (when (= retcode 0)
29 name))
30 #-ffi
31 "localhost")
32
33 (defun get-host-by-address (address)
34 (with-mapped-conditions ()
35 (let ((hostent (posix:resolve-host-ipaddr (host-to-hostname address)…
36 (posix:hostent-name hostent))))
37
38 (defun get-hosts-by-name (name)
39 (with-mapped-conditions ()
40 (let ((hostent (posix:resolve-host-ipaddr name)))
41 (mapcar #'host-to-vector-quad
42 (posix:hostent-addr-list hostent)))))
43
44 ;; Format: ((UNIX Windows) . CONDITION)
45 (defparameter +clisp-error-map+
46 #-win32
47 `((:EADDRINUSE . address-in-use-error)
48 (:EADDRNOTAVAIL . address-not-available-error)
49 (:EBADF . bad-file-descriptor-error)
50 (:ECONNREFUSED . connection-refused-error)
51 (:ECONNRESET . connection-reset-error)
52 (:ECONNABORTED . connection-aborted-error)
53 (:EINVAL . invalid-argument-error)
54 (:ENOBUFS . no-buffers-error)
55 (:ENOMEM . out-of-memory-error)
56 (:ENOTSUP . operation-not-supported-error)
57 (:EPERM . operation-not-permitted-error)
58 (:EPROTONOSUPPORT . protocol-not-supported-error)
59 (:ESOCKTNOSUPPORT . socket-type-not-supported-error)
60 (:ENETUNREACH . network-unreachable-error)
61 (:ENETDOWN . network-down-error)
62 (:ENETRESET . network-reset-error)
63 (:ESHUTDOWN . already-shutdown-error)
64 (:ETIMEDOUT . timeout-error)
65 (:EHOSTDOWN . host-down-error)
66 (:EHOSTUNREACH . host-unreachable-error)
67 ;; when blocked reading, and we close our socket due to a timeout.
68 ;; POSIX.1 says that EAGAIN and EWOULDBLOCK may have the same values.
69 (:EAGAIN . timeout-error)
70 (:EWOULDBLOCK . timeout-error)) ;linux
71 #+win32
72 `((:WSAEADDRINUSE . address-in-use-error)
73 (:WSAEADDRNOTAVAIL . address-not-available-error)
74 (:WSAEBADF . bad-file-descriptor-error)
75 (:WSAECONNREFUSED . connection-refused-error)
76 (:WSAECONNRESET . connection-reset-error)
77 (:WSAECONNABORTED . connection-aborted-error)
78 (:WSAEINVAL . invalid-argument-error)
79 (:WSAENOBUFS . no-buffers-error)
80 (:WSAENOMEM . out-of-memory-error)
81 (:WSAENOTSUP . operation-not-supported-error)
82 (:WSAEPERM . operation-not-permitted-error)
83 (:WSAEPROTONOSUPPORT . protocol-not-supported-error)
84 (:WSAESOCKTNOSUPPORT . socket-type-not-supported-error)
85 (:WSAENETUNREACH . network-unreachable-error)
86 (:WSAENETDOWN . network-down-error)
87 (:WSAENETRESET . network-reset-error)
88 (:WSAESHUTDOWN . already-shutdown-error)
89 (:WSAETIMEDOUT . timeout-error)
90 (:WSAEHOSTDOWN . host-down-error)
91 (:WSAEHOSTUNREACH . host-unreachable-error)))
92
93 (defun parse-errno (condition)
94 "Returns a number or keyword if it can parse what is within parens, el…
95 (let ((s (princ-to-string condition)))
96 (let ((pos1 (position #\( s))
97 (pos2 (position #\) s)))
98 ;mac: number, linux: keyword
99 (ignore-errors
100 (if (digit-char-p (char s (1+ pos1)))
101 (parse-integer s :start (1+ pos1) :end pos2)
102 (let ((*package* (find-package "KEYWORD")))
103 (car (read-from-string s t nil :start pos1 :end (1+ pos2))))…
104
105 (defun handle-condition (condition &optional (socket nil))
106 "Dispatch a usocket condition instead of a CLISP specific one, if we c…
107 (let ((errno
108 (cond
109 ;clisp 2.49+
110 ((typep condition (find-symbol "OS-STREAM-ERROR" "EXT"))
111 (parse-errno condition))
112 ;clisp 2.49
113 ((typep condition (find-symbol "SIMPLE-STREAM-ERROR" "SYSTEM…
114 (car (simple-condition-format-arguments condition))))))
115 (when errno
116 (let ((error-keyword (if (keywordp errno) errno #+ffi(os:errno err…
117 (let ((usocket-error (cdr (assoc error-keyword +clisp-error-map+…
118 (when usocket-error
119 (if (subtypep usocket-error 'error)
120 (error usocket-error :socket socket)
121 (signal usocket-error :socket socket))))))))
122
123 (defun socket-connect (host port &key (protocol :stream) (element-type '…
124 timeout deadline (nodelay t nodelay-specified)
125 local-host local-port)
126 (declare (ignorable timeout local-host local-port))
127 (when deadline (unsupported 'deadline 'socket-connect))
128 (when (and nodelay-specified
129 (not (eq nodelay :if-supported)))
130 (unsupported 'nodelay 'socket-connect))
131 (case protocol
132 (:stream
133 (let ((socket)
134 (hostname (host-to-hostname host)))
135 (with-mapped-conditions (socket)
136 (setf socket
137 (if timeout
138 (socket:socket-connect port hostname
139 :element-type element-type
140 :buffered t
141 :timeout timeout)
142 (socket:socket-connect port hostname
143 :element-type element-type
144 :buffered t))))
145 (make-stream-socket :socket socket
146 :stream socket))) ;; the socket is a stream t…
147 (:datagram
148 #+(or rawsock ffi)
149 (socket-create-datagram (or local-port *auto-port*)
150 :local-host (or local-host *wildcard-host*)
151 :remote-host (and host (host-to-vector-quad…
152 :remote-port port)
153 #-(or rawsock ffi)
154 (unsupported '(protocol :datagram) 'socket-connect))))
155
156 (defun socket-listen (host port
157 &key reuseaddress
158 (reuse-address nil reuse-address-supplied-p)
159 (backlog 5)
160 (element-type 'character))
161 ;; clisp 2.39 sets SO_REUSEADDRESS to 1 by default; no need to
162 ;; to explicitly turn it on; unfortunately, there's no way to turn it …
163 (declare (ignore reuseaddress reuse-address reuse-address-supplied-p))
164 (let ((sock (apply #'socket:socket-server
165 (append (list port
166 :backlog backlog)
167 (when (ip/= host *wildcard-host*)
168 (list :interface host))))))
169 (with-mapped-conditions ()
170 (make-stream-server-socket sock :element-type element-type))))
171
172 (defmethod socket-accept ((socket stream-server-usocket) &key element-ty…
173 (let ((stream
174 (with-mapped-conditions (socket)
175 (socket:socket-accept (socket socket)
176 :element-type (or element-type
177 (element-type socket)…
178 (make-stream-socket :socket stream
179 :stream stream)))
180
181 ;; Only one close method required:
182 ;; sockets and their associated streams
183 ;; are the same object
184 (defmethod socket-close ((usocket usocket))
185 "Close socket."
186 (when (wait-list usocket)
187 (remove-waiter (wait-list usocket) usocket))
188 (with-mapped-conditions (usocket)
189 (close (socket usocket))))
190
191 (defmethod socket-close ((usocket stream-server-usocket))
192 (when (wait-list usocket)
193 (remove-waiter (wait-list usocket) usocket))
194 (socket:socket-server-close (socket usocket)))
195
196 (defmethod socket-shutdown ((usocket stream-usocket) direction)
197 (with-mapped-conditions (usocket)
198 (socket:socket-stream-shutdown (socket usocket) direction)))
199
200 (defmethod get-local-name ((usocket stream-usocket))
201 (multiple-value-bind
202 (address port)
203 (socket:socket-stream-local (socket usocket) t)
204 (values (dotted-quad-to-vector-quad address) port)))
205
206 (defmethod get-local-name ((usocket stream-server-usocket))
207 (values (get-local-address usocket)
208 (get-local-port usocket)))
209
210 (defmethod get-peer-name ((usocket stream-usocket))
211 (multiple-value-bind
212 (address port)
213 (socket:socket-stream-peer (socket usocket) t)
214 (values (dotted-quad-to-vector-quad address) port)))
215
216 (defmethod get-local-address ((usocket usocket))
217 (nth-value 0 (get-local-name usocket)))
218
219 (defmethod get-local-address ((usocket stream-server-usocket))
220 (dotted-quad-to-vector-quad
221 (socket:socket-server-host (socket usocket))))
222
223 (defmethod get-peer-address ((usocket usocket))
224 (nth-value 0 (get-peer-name usocket)))
225
226 (defmethod get-local-port ((usocket usocket))
227 (nth-value 1 (get-local-name usocket)))
228
229 (defmethod get-local-port ((usocket stream-server-usocket))
230 (socket:socket-server-port (socket usocket)))
231
232 (defmethod get-peer-port ((usocket usocket))
233 (nth-value 1 (get-peer-name usocket)))
234
235 (defun %setup-wait-list (wait-list)
236 (declare (ignore wait-list)))
237
238 (defun %add-waiter (wait-list waiter)
239 ;; clisp's #'socket-status takes a list whose elts look either like,
240 ;; (socket-stream direction . x) or like,
241 ;; (socket-server . x)
242 ;; and it replaces the x's.
243 (push (cons (socket waiter)
244 (cond ((stream-usocket-p waiter) (cons NIL NIL))
245 (t NIL)))
246 (wait-list-%wait wait-list)))
247
248 (defun %remove-waiter (wait-list waiter)
249 (setf (wait-list-%wait wait-list)
250 (remove (socket waiter) (wait-list-%wait wait-list) :key #'car)))
251
252 (defmethod wait-for-input-internal (wait-list &key timeout)
253 (with-mapped-conditions ()
254 (multiple-value-bind
255 (secs musecs)
256 (split-timeout (or timeout 1))
257 (dolist (x (wait-list-%wait wait-list))
258 (when (consp (cdr x)) ;it's a socket-stream not socket-server
259 (setf (cadr x) :INPUT)))
260 (let* ((request-list (wait-list-%wait wait-list))
261 (status-list (if timeout
262 (socket:socket-status request-list secs mu…
263 (socket:socket-status request-list)))
264 (sockets (wait-list-waiters wait-list)))
265 (do* ((x (pop sockets) (pop sockets))
266 (y (cdr (last (pop status-list))) (cdr (last (pop status-l…
267 ((null x))
268 (when (member y '(T :INPUT :EOF))
269 (setf (state x) :READ)))
270 wait-list))))
271
272 ;;;
273 ;;; UDP/Datagram sockets (RAWSOCK version)
274 ;;;
275
276 #+rawsock
277 (progn
278 (defun make-sockaddr_in ()
279 (make-array 16 :element-type '(unsigned-byte 8) :initial-element 0))
280
281 (declaim (inline fill-sockaddr_in))
282 (defun fill-sockaddr_in (sockaddr_in ip port)
283 (port-to-octet-buffer port sockaddr_in)
284 (ip-to-octet-buffer ip sockaddr_in :start 2)
285 sockaddr_in)
286
287 (defun socket-create-datagram (local-port
288 &key (local-host *wildcard-host*)
289 remote-host
290 remote-port)
291 (let ((sock (rawsock:socket :inet :dgram 0))
292 (lsock_addr (fill-sockaddr_in (make-sockaddr_in)
293 local-host local-port))
294 (rsock_addr (when remote-host
295 (fill-sockaddr_in (make-sockaddr_in)
296 remote-host (or remote-port
297 local-port)))))
298 (rawsock:bind sock (rawsock:make-sockaddr :inet lsock_addr))
299 (when rsock_addr
300 (rawsock:connect sock (rawsock:make-sockaddr :inet rsock_addr)))
301 (make-datagram-socket sock :connected-p (if rsock_addr t nil))))
302
303 (defmethod socket-receive ((socket datagram-usocket) buffer length &ke…
304 "Returns the buffer, the number of octets copied into the buffer (re…
305 and the address of the sender as values."
306 (let* ((sock (socket socket))
307 (sockaddr (rawsock:make-sockaddr :inet))
308 (real-length (or length +max-datagram-packet-size+))
309 (real-buffer (or buffer
310 (make-array real-length
311 :element-type '(unsigned-byte 8)…
312 (let ((rv (rawsock:recvfrom sock real-buffer sockaddr
313 :start 0 :end real-length))
314 (host 0) (port 0))
315 (unless (connected-p socket)
316 (let ((data (rawsock:sockaddr-data sockaddr)))
317 (setq host (ip-from-octet-buffer data :start 4)
318 port (port-from-octet-buffer data :start 2))))
319 (values (if buffer real-buffer (subseq real-buffer 0 rv))
320 rv
321 host
322 port))))
323
324 (defmethod socket-send ((socket datagram-usocket) buffer size &key hos…
325 "Returns the number of octets sent."
326 (let* ((sock (socket socket))
327 (sockaddr (when (and host port)
328 (rawsock:make-sockaddr :inet
329 (fill-sockaddr_in
330 (make-sockaddr_in)
331 (host-byte-order host)
332 port))))
333 (real-size (min size +max-datagram-packet-size+))
334 (real-buffer (if (typep buffer '(simple-array (unsigned-byte …
335 buffer
336 (make-array real-size
337 :element-type '(unsigned-byte 8)
338 :initial-contents (subseq buffer 0…
339 (rv (if (and host port)
340 (rawsock:sendto sock real-buffer sockaddr
341 :start offset
342 :end (+ offset real-size))
343 (rawsock:send sock real-buffer
344 :start offset
345 :end (+ offset real-size)))))
346 rv))
347
348 (defmethod socket-close ((usocket datagram-usocket))
349 (when (wait-list usocket)
350 (remove-waiter (wait-list usocket) usocket))
351 (rawsock:sock-close (socket usocket)))
352
353 (declaim (inline get-socket-name))
354 (defun get-socket-name (socket function)
355 (let ((sockaddr (rawsock:make-sockaddr :inet (make-sockaddr_in))))
356 (funcall function socket sockaddr)
357 (let ((data (rawsock:sockaddr-data sockaddr)))
358 (values (hbo-to-vector-quad (ip-from-octet-buffer data :start 2))
359 (port-from-octet-buffer data :start 0)))))
360
361 (defmethod get-local-name ((usocket datagram-usocket))
362 (get-socket-name (socket usocket) 'rawsock:getsockname))
363
364 (defmethod get-peer-name ((usocket datagram-usocket))
365 (get-socket-name (socket usocket) 'rawsock:getpeername))
366
367 ) ; progn
368
369 ;;;
370 ;;; UDP/Datagram sockets (FFI version)
371 ;;;
372
373 #+(and ffi (not rawsock))
374 (progn
375 ;; C primitive types
376 (ffi:def-c-type socklen_t ffi:uint32)
377
378 ;; C structures
379 (ffi:def-c-struct sockaddr
380 #+macos (sa_len ffi:uint8)
381 (sa_family #-macos ffi:ushort
382 #+macos ffi:uint8)
383 (sa_data (ffi:c-array ffi:char 14)))
384
385 (ffi:def-c-struct sockaddr_in
386 #+macos (sin_len ffi:uint8)
387 (sin_family #-macos ffi:short
388 #+macos ffi:uint8)
389 (sin_port #-macos ffi:ushort
390 #+macos ffi:uint16)
391 (sin_addr ffi:uint32)
392 (sin_zero (ffi:c-array ffi:char 8)))
393
394 (ffi:def-c-struct timeval
395 (tv_sec ffi:long)
396 (tv_usec ffi:long))
397
398 ;; foreign functions
399 (ffi:def-call-out %sendto (:name "sendto")
400 (:arguments (socket ffi:int)
401 (buffer ffi:c-pointer)
402 (length ffi:int)
403 (flags ffi:int)
404 (address (ffi:c-ptr sockaddr))
405 (address-len ffi:int))
406 #+win32 (:library "WS2_32")
407 #-win32 (:library :default)
408 (:language #-win32 :stdc
409 #+win32 :stdc-stdcall)
410 (:return-type ffi:int))
411
412 (ffi:def-call-out %send (:name "send")
413 (:arguments (socket ffi:int)
414 (buffer ffi:c-pointer)
415 (length ffi:int)
416 (flags ffi:int))
417 #+win32 (:library "WS2_32")
418 #-win32 (:library :default)
419 (:language #-win32 :stdc
420 #+win32 :stdc-stdcall)
421 (:return-type ffi:int))
422
423 (ffi:def-call-out %recvfrom (:name "recvfrom")
424 (:arguments (socket ffi:int)
425 (buffer ffi:c-pointer)
426 (length ffi:int)
427 (flags ffi:int)
428 (address (ffi:c-ptr sockaddr) :in-out)
429 (address-len (ffi:c-ptr ffi:int) :in-out))
430 #+win32 (:library "WS2_32")
431 #-win32 (:library :default)
432 (:language #-win32 :stdc
433 #+win32 :stdc-stdcall)
434 (:return-type ffi:int))
435
436 (ffi:def-call-out %socket (:name "socket")
437 (:arguments (family ffi:int)
438 (type ffi:int)
439 (protocol ffi:int))
440 #+win32 (:library "WS2_32")
441 #-win32 (:library :default)
442 (:language #-win32 :stdc
443 #+win32 :stdc-stdcall)
444 (:return-type ffi:int))
445
446 (ffi:def-call-out %connect (:name "connect")
447 (:arguments (socket ffi:int)
448 (address (ffi:c-ptr sockaddr) :in)
449 (address_len socklen_t))
450 #+win32 (:library "WS2_32")
451 #-win32 (:library :default)
452 (:language #-win32 :stdc
453 #+win32 :stdc-stdcall)
454 (:return-type ffi:int))
455
456 (ffi:def-call-out %bind (:name "bind")
457 (:arguments (socket ffi:int)
458 (address (ffi:c-ptr sockaddr) :in)
459 (address_len socklen_t))
460 #+win32 (:library "WS2_32")
461 #-win32 (:library :default)
462 (:language #-win32 :stdc
463 #+win32 :stdc-stdcall)
464 (:return-type ffi:int))
465
466 (ffi:def-call-out %close (:name #-win32 "close" #+win32 "closesocket")
467 (:arguments (socket ffi:int))
468 #+win32 (:library "WS2_32")
469 #-win32 (:library :default)
470 (:language #-win32 :stdc
471 #+win32 :stdc-stdcall)
472 (:return-type ffi:int))
473
474 (ffi:def-call-out %getsockopt (:name "getsockopt")
475 (:arguments (sockfd ffi:int)
476 (level ffi:int)
477 (optname ffi:int)
478 (optval ffi:c-pointer)
479 (optlen (ffi:c-ptr socklen_t) :out))
480 #+win32 (:library "WS2_32")
481 #-win32 (:library :default)
482 (:language #-win32 :stdc
483 #+win32 :stdc-stdcall)
484 (:return-type ffi:int))
485
486 (ffi:def-call-out %setsockopt (:name "setsockopt")
487 (:arguments (sockfd ffi:int)
488 (level ffi:int)
489 (optname ffi:int)
490 (optval ffi:c-pointer)
491 (optlen socklen_t))
492 #+win32 (:library "WS2_32")
493 #-win32 (:library :default)
494 (:language #-win32 :stdc
495 #+win32 :stdc-stdcall)
496 (:return-type ffi:int))
497
498 (ffi:def-call-out %htonl (:name "htonl")
499 (:arguments (hostlong ffi:uint32))
500 #+win32 (:library "WS2_32")
501 #-win32 (:library :default)
502 (:language #-win32 :stdc
503 #+win32 :stdc-stdcall)
504 (:return-type ffi:uint32))
505
506 (ffi:def-call-out %htons (:name "htons")
507 (:arguments (hostshort ffi:uint16))
508 #+win32 (:library "WS2_32")
509 #-win32 (:library :default)
510 (:language #-win32 :stdc
511 #+win32 :stdc-stdcall)
512 (:return-type ffi:uint16))
513
514 (ffi:def-call-out %ntohl (:name "ntohl")
515 (:arguments (netlong ffi:uint32))
516 #+win32 (:library "WS2_32")
517 #-win32 (:library :default)
518 (:language #-win32 :stdc
519 #+win32 :stdc-stdcall)
520 (:return-type ffi:uint32))
521
522 (ffi:def-call-out %ntohs (:name "ntohs")
523 (:arguments (netshort ffi:uint16))
524 #+win32 (:library "WS2_32")
525 #-win32 (:library :default)
526 (:language #-win32 :stdc
527 #+win32 :stdc-stdcall)
528 (:return-type ffi:uint16))
529
530 (ffi:def-call-out %getsockname (:name "getsockname")
531 (:arguments (sockfd ffi:int)
532 (localaddr (ffi:c-ptr sockaddr) :in-out)
533 (addrlen (ffi:c-ptr socklen_t) :in-out))
534 #+win32 (:library "WS2_32")
535 #-win32 (:library :default)
536 (:language #-win32 :stdc
537 #+win32 :stdc-stdcall)
538 (:return-type ffi:int))
539
540 (ffi:def-call-out %getpeername (:name "getpeername")
541 (:arguments (sockfd ffi:int)
542 (peeraddr (ffi:c-ptr sockaddr) :in-out)
543 (addrlen (ffi:c-ptr socklen_t) :in-out))
544 #+win32 (:library "WS2_32")
545 #-win32 (:library :default)
546 (:language #-win32 :stdc
547 #+win32 :stdc-stdcall)
548 (:return-type ffi:int))
549
550 ;; socket constants
551 (defconstant +socket-af-inet+ 2)
552 (defconstant +socket-sock-dgram+ 2)
553 (defconstant +socket-ip-proto-udp+ 17)
554
555 (defconstant +sockopt-so-rcvtimeo+ #-linux #x1006 #+linux 20 "Socket r…
556
557 (defparameter *length-of-sockaddr_in* (ffi:sizeof 'sockaddr_in))
558
559 (declaim (inline fill-sockaddr_in))
560 (defun fill-sockaddr_in (sockaddr host port)
561 (let ((hbo (host-to-hbo host)))
562 (ffi:with-c-place (place sockaddr)
563 #+macos
564 (setf (ffi:slot place 'sin_len) *length-of-sockaddr_in*)
565 (setf (ffi:slot place 'sin_family) +socket-af-inet+
566 (ffi:slot place 'sin_port) (%htons port)
567 (ffi:slot place 'sin_addr) (%htonl hbo)))
568 sockaddr))
569
570 (defun socket-create-datagram (local-port
571 &key (local-host *wildcard-host*)
572 remote-host
573 remote-port)
574 (let ((sock (%socket +socket-af-inet+ +socket-sock-dgram+ +socket-ip…
575 (lsock_addr (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_…
576 local-host local-port))
577 (rsock_addr (when remote-host
578 (fill-sockaddr_in (ffi:allocate-shallow 'sockadd…
579 remote-host (or remote-port lo…
580 (unless (plusp sock)
581 (error "SOCKET-CREATE-DATAGRAM ERROR (socket): ~A" (os:errno)))
582 (unwind-protect
583 (let ((rv (%bind sock (ffi:cast (ffi:foreign-value lsock_addr…
584 *length-of-sockaddr_in*)))
585 (unless (zerop rv)
586 (error "SOCKET-CREATE-DATAGRAM ERROR (bind): ~A" (os:errn…
587 (when rsock_addr
588 (let ((rv (%connect sock
589 (ffi:cast (ffi:foreign-value rsock_ad…
590 *length-of-sockaddr_in*)))
591 (unless (zerop rv)
592 (error "SOCKET-CREATE-DATAGRAM ERROR (connect): ~A" (…
593 (ffi:foreign-free lsock_addr)
594 (when remote-host
595 (ffi:foreign-free rsock_addr)))
596 (make-datagram-socket sock :connected-p (if rsock_addr t nil))))
597
598 (defun finalize-datagram-usocket (object)
599 (when (datagram-usocket-p object)
600 (socket-close object)))
601
602 (defmethod initialize-instance :after ((usocket datagram-usocket) &key)
603 (setf (slot-value usocket 'recv-buffer)
604 (ffi:allocate-shallow 'ffi:uint8 :count +max-datagram-packet-s…
605 ;; finalize the object
606 (ext:finalize usocket 'finalize-datagram-usocket))
607
608 (defmethod socket-close ((usocket datagram-usocket))
609 (when (wait-list usocket)
610 (remove-waiter (wait-list usocket) usocket))
611 (with-slots (recv-buffer socket) usocket
612 (ffi:foreign-free recv-buffer)
613 (zerop (%close socket))))
614
615 (defmethod socket-receive ((usocket datagram-usocket) buffer length &k…
616 (let ((remote-address (ffi:allocate-shallow 'sockaddr_in))
617 (remote-address-length (ffi:allocate-shallow 'ffi:int))
618 nbytes (host 0) (port 0))
619 (setf (ffi:foreign-value remote-address-length)
620 *length-of-sockaddr_in*)
621 (unwind-protect
622 (multiple-value-bind (n address address-length)
623 (%recvfrom (socket usocket)
624 (ffi:foreign-address (slot-value usocket 'recv…
625 +max-datagram-packet-size+
626 0 ; flags
627 (ffi:cast (ffi:foreign-value remote-address) '…
628 (ffi:foreign-value remote-address-length))
629 (when (minusp n)
630 (error "SOCKET-RECEIVE ERROR: ~A" (os:errno)))
631 (setq nbytes n)
632 (when (= address-length *length-of-sockaddr_in*)
633 (let ((data (sockaddr-sa_data address)))
634 (setq host (ip-from-octet-buffer data :start 2)
635 port (port-from-octet-buffer data))))
636 (cond ((plusp n)
637 (let ((return-buffer (ffi:foreign-value (slot-value …
638 (if buffer ; replace exist buffer of create new re…
639 (let ((end-1 (min (or length (length buffer)) …
640 (end-2 (min n +max-datagram-packet-size+…
641 (replace buffer return-buffer :end1 end-1 :e…
642 (setq buffer (subseq return-buffer 0 (min n +m…
643 ((zerop n))))
644 (ffi:foreign-free remote-address)
645 (ffi:foreign-free remote-address-length))
646 (values buffer nbytes host port)))
647
648 ;; implementation note: different from socket-receive, we know how man…
649 ;; so, a send buffer will not needed, and if there is a buffer, it's h…
650 ;; in LispWorks. So, we allocate new foreign buffer for holding data (…
651 ;;
652 ;; I don't know if anyone is watching my coding work, but I think this…
653 (defmethod socket-send ((usocket datagram-usocket) buffer size &key ho…
654 (declare (type sequence buffer)
655 (type (integer 0 *) size offset))
656 (let ((remote-address
657 (when (and host port)
658 (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) host …
659 (send-buffer
660 (ffi:allocate-deep 'ffi:uint8
661 (if (zerop offset)
662 buffer
663 (subseq buffer offset (+ offset size)))
664 :count size :read-only t))
665 (real-size (min size +max-datagram-packet-size+))
666 (nbytes 0))
667 (unwind-protect
668 (let ((n (if remote-address
669 (%sendto (socket usocket)
670 (ffi:foreign-address send-buffer)
671 real-size
672 0 ; flags
673 (ffi:cast (ffi:foreign-value remote-add…
674 *length-of-sockaddr_in*)
675 (%send (socket usocket)
676 (ffi:foreign-address send-buffer)
677 real-size
678 0))))
679 (cond ((plusp n)
680 (setq nbytes n))
681 ((zerop n)
682 (setq nbytes n))
683 (t (error "SOCKET-SEND ERROR: ~A" (os:errno)))))
684 (ffi:foreign-free send-buffer)
685 (when remote-address
686 (ffi:foreign-free remote-address))
687 nbytes)))
688
689 (declaim (inline get-socket-name))
690 (defun get-socket-name (socket function)
691 (let ((address (ffi:allocate-shallow 'sockaddr_in))
692 (address-length (ffi:allocate-shallow 'ffi:int))
693 (host 0) (port 0))
694 (setf (ffi:foreign-value address-length) *length-of-sockaddr_in*)
695 (unwind-protect
696 (multiple-value-bind (rv return-address return-address-length)
697 (funcall function socket
698 (ffi:cast (ffi:foreign-value address) 'sockaddr)
699 (ffi:foreign-value address-length))
700 (declare (ignore return-address-length))
701 (if (zerop rv)
702 (let ((data (sockaddr-sa_data return-address)))
703 (setq host (ip-from-octet-buffer data :start 2)
704 port (port-from-octet-buffer data)))
705 (error "GET-SOCKET-NAME ERROR: ~A" (os:errno))))
706 (ffi:foreign-free address)
707 (ffi:foreign-free address-length))
708 (values (hbo-to-vector-quad host) port)))
709
710 (defmethod get-local-name ((usocket datagram-usocket))
711 (get-socket-name (socket usocket) '%getsockname))
712
713 (defmethod get-peer-name ((usocket datagram-usocket))
714 (get-socket-name (socket usocket) '%getpeername))
715
716 ) ; progn
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.