1 ;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*-
3 ;; Copyright (C) 2006, 2007 Stelian Ionescu
5 ;; This code is free software; you can redistribute it and/or
6 ;; modify it under the terms of the version 2.1 of
7 ;; the GNU Lesser General Public License as published by
8 ;; the Free Software Foundation, as clarified by the
9 ;; preamble found here:
10 ;; http://opensource.franz.com/preamble.html
12 ;; This program is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU Lesser General
18 ;; Public License along with this library; if not, write to the
19 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 ;; Boston, MA 02110-1301, USA
22 (in-package :net.sockets
)
24 (defvar *socket-type-map
*
25 '(((:ipv4
:stream
:active
:default
) . socket-stream-internet-active
)
26 ((:ipv6
:stream
:active
:default
) . socket-stream-internet-active
)
27 ((:ipv4
:stream
:passive
:default
) . socket-stream-internet-passive
)
28 ((:ipv6
:stream
:passive
:default
) . socket-stream-internet-passive
)
29 ((:local
:stream
:active
:default
) . socket-stream-local-active
)
30 ((:local
:stream
:passive
:default
) . socket-stream-local-passive
)
31 ((:local
:datagram
:active
:default
) . socket-datagram-local-active
)
32 ((:ipv4
:datagram
:active
:default
) . socket-datagram-internet-active
)
33 ((:ipv6
:datagram
:active
:default
) . socket-datagram-internet-active
)))
35 (defun select-socket-type (family type connect protocol
)
36 (or (cdr (assoc (list family type connect protocol
) *socket-type-map
*
38 (error "No socket class found !!")))
41 ;;;;;;;;;;;;;;;;;;;;;;;;;
42 ;; SHARED-INITIALIZE ;;
43 ;;;;;;;;;;;;;;;;;;;;;;;;;
45 (defun translate-make-socket-keywords-to-constants (family type protocol
)
46 (let ((sf (ecase family
49 (:local et
:af-local
)))
51 (:stream et
:sock-stream
)
52 (:datagram et
:sock-dgram
)))
54 ((integerp protocol
) protocol
)
55 ((eql protocol
:default
) 0)
58 (get-protocol-by-name (string-downcase
59 (string protocol
))))))))
62 (defmethod socket-fd ((socket socket
))
64 (defmethod (setf socket-fd
) (fd (socket socket
))
65 (setf (fd-of socket
) fd
))
67 (defmethod shared-initialize :after
((socket socket
) slot-names
68 &key file-descriptor family
69 type
(protocol :default
))
70 (declare (ignore slot-names
))
71 (when (socket-open-p socket
)
73 (with-accessors ((fd fd-of
)
75 (proto socket-protocol
)) socket
76 (setf fd
(or file-descriptor
77 (multiple-value-bind (sf st sp
)
78 (translate-make-socket-keywords-to-constants family type protocol
)
79 (with-socket-error-filter
80 (et:socket sf st sp
)))))
84 (defmethod (setf external-format-of
) (external-format (socket passive-socket
))
85 (setf (slot-value socket
'external-format
)
86 (ensure-external-format external-format
)))
88 (defmethod shared-initialize :after
((socket passive-socket
) slot-names
90 (declare (ignore slot-names
))
91 (setf (external-format-of socket
) external-format
))
93 (defmethod socket-type ((socket stream-socket
))
96 (defmethod socket-type ((socket datagram-socket
))
104 (defun sock-fam (socket)
105 (ecase (socket-family socket
)
109 (defmethod print-object ((socket socket-stream-internet-active
) stream
)
110 (print-unreadable-object (socket stream
:identity t
)
111 (format stream
"active ~A stream socket" (sock-fam socket
))
112 (if (socket-connected-p socket
)
113 (multiple-value-bind (addr port
) (remote-name socket
)
114 (format stream
" connected to ~A/~A"
115 (sockaddr->presentation addr
) port
))
116 (format stream
", ~:[closed~;unconnected~]" (fd-of socket
)))))
118 (defmethod print-object ((socket socket-stream-internet-passive
) stream
)
119 (print-unreadable-object (socket stream
:identity t
)
120 (format stream
"passive ~A stream socket" (sock-fam socket
))
121 (if (socket-bound-p socket
)
122 (multiple-value-bind (addr port
) (local-name socket
)
123 (format stream
" ~:[bound to~;waiting @~] ~A/~A"
124 (socket-listening-p socket
)
125 (sockaddr->presentation addr
) port
))
126 (format stream
", ~:[closed~;unbound~]" (fd-of socket
)))))
128 (defmethod print-object ((socket socket-stream-local-active
) stream
)
129 (print-unreadable-object (socket stream
:identity t
)
130 (format stream
"active local stream socket")
131 (if (socket-connected-p socket
)
132 (format stream
" connected to ~A"
133 (sockaddr->presentation
(remote-address socket
)))
134 (format stream
", ~:[closed~;unconnected~]" (fd-of socket
)))))
136 (defmethod print-object ((socket socket-stream-local-passive
) stream
)
137 (print-unreadable-object (socket stream
:identity t
)
138 (format stream
"passive local stream socket")
139 (if (socket-bound-p socket
)
140 (format stream
" ~:[bound to~;waiting @~] ~A"
141 (socket-listening-p socket
)
142 (sockaddr->presentation
(local-address socket
)))
143 (format stream
", ~:[closed~;unbound~]" (fd-of socket
)))))
145 (defmethod print-object ((socket socket-datagram-local-active
) stream
)
146 (print-unreadable-object (socket stream
:identity t
)
147 (format stream
"local datagram socket")
148 (if (socket-connected-p socket
)
149 (format stream
" connected to ~A"
150 (sockaddr->presentation
(remote-address socket
)))
151 (format stream
", ~:[closed~;unconnected~]" (fd-of socket
)))))
153 (defmethod print-object ((socket socket-datagram-internet-active
) stream
)
154 (print-unreadable-object (socket stream
:identity t
)
155 (format stream
"~A datagram socket" (sock-fam socket
))
156 (if (socket-connected-p socket
)
157 (multiple-value-bind (addr port
) (remote-name socket
)
158 (format stream
" connected to ~A/~A"
159 (sockaddr->presentation addr
) port
))
160 (format stream
", ~:[closed~;unconnected~]" (fd-of socket
)))))
167 (defmethod close :around
((socket socket
) &key abort
)
168 (declare (ignore abort
))
171 (with-socket-error-filter
172 (et:close
(fd-of socket
))))
173 (setf (fd-of socket
) nil
174 (slot-value socket
'bound
) nil
)
177 (defmethod close :around
((socket passive-socket
) &key abort
)
178 (declare (ignore abort
))
180 (setf (slot-value socket
'listening
) nil
)
183 (defmethod close ((socket socket
) &key abort
)
184 (declare (ignore socket abort
)))
186 (defmethod socket-open-p ((socket socket
))
187 (unless (fd-of socket
)
188 (return-from socket-open-p nil
))
189 (with-socket-error-filter
191 (with-foreign-object (ss 'et
:sockaddr-storage
)
192 (et:bzero ss et
:size-of-sockaddr-storage
)
193 (with-socklen (size et
:size-of-sockaddr-storage
)
194 (et:getsockname
(fd-of socket
) ss size
)
197 #+freebsd
(et:econnreset
()))))
204 (defmethod local-name ((socket socket
))
205 (with-foreign-object (ss 'et
:sockaddr-storage
)
206 (et:bzero ss et
:size-of-sockaddr-storage
)
207 (with-socklen (size et
:size-of-sockaddr-storage
)
208 (with-socket-error-filter
209 (et:getsockname
(fd-of socket
) ss size
))
210 (sockaddr-storage->sockaddr ss
))))
212 (defmethod local-address ((socket socket
))
213 (nth-value 0 (local-name socket
)))
215 (defmethod local-port ((socket internet-socket
))
216 (nth-value 1 (local-name socket
)))
223 (defmethod remote-name ((socket socket
))
224 (with-foreign-object (ss 'et
:sockaddr-storage
)
225 (et:bzero ss et
:size-of-sockaddr-storage
)
226 (with-socklen (size et
:size-of-sockaddr-storage
)
227 (with-socket-error-filter
228 (et:getpeername
(fd-of socket
) ss size
))
229 (sockaddr-storage->sockaddr ss
))))
231 (defmethod remote-address ((socket socket
))
232 (nth-value 0 (remote-name socket
)))
234 (defmethod remote-port ((socket internet-socket
))
235 (nth-value 1 (remote-name socket
)))
242 (defmethod bind-address :before
((socket internet-socket
)
243 address
&key
(reuse-address t
))
244 (declare (ignore address
))
246 (set-socket-option socket
:reuse-address
:value t
)))
248 (defun bind-ipv4-address (fd address port
)
249 (with-sockaddr-in (sin address port
)
250 (with-socket-error-filter
251 (et:bind fd sin et
:size-of-sockaddr-in
))))
253 (defun bind-ipv6-address (fd address port
)
254 (with-sockaddr-in6 (sin6 address port
)
255 (with-socket-error-filter
256 (et:bind fd sin6 et
:size-of-sockaddr-in6
))))
258 (defmethod bind-address ((socket internet-socket
)
261 (if (eql (socket-family socket
) :ipv6
)
262 (bind-ipv6-address (fd-of socket
)
263 (map-ipv4-vector-to-ipv6 (name address
))
265 (bind-ipv4-address (fd-of socket
) (name address
) port
))
268 (defmethod bind-address ((socket internet-socket
)
271 (bind-ipv6-address (fd-of socket
) (name address
) port
)
274 (defmethod bind-address ((socket local-socket
)
275 (address localaddr
) &key
)
276 (with-sockaddr-un (sun (name address
))
277 (with-socket-error-filter
278 (et:bind
(fd-of socket
) sun et
:size-of-sockaddr-un
)))
281 (defmethod bind-address :after
((socket socket
)
282 (address sockaddr
) &key
)
283 (setf (slot-value socket
'bound
) t
))
290 (defmethod socket-listen ((socket passive-socket
)
292 (unless backlog
(setf backlog
(min *default-backlog-size
*
293 +max-backlog-size
+)))
294 (check-type backlog unsigned-byte
"a non-negative integer")
295 (with-socket-error-filter
296 (et:listen
(fd-of socket
) backlog
))
297 (setf (slot-value socket
'listening
) t
)
300 (defmethod socket-listen ((socket active-socket
)
302 (declare (ignore backlog
))
303 (error "You can't listen on active sockets."))
310 (defmethod accept-connection ((socket active-socket
))
311 (error "You can't accept connections on active sockets."))
313 (defmethod accept-connection ((socket passive-socket
))
314 (flet ((make-client-socket (fd)
315 (make-instance (active-class socket
)
316 :external-format
(external-format-of socket
)
317 :file-descriptor fd
)))
318 (with-foreign-object (ss 'et
:sockaddr-storage
)
319 (et:bzero ss et
:size-of-sockaddr-storage
)
320 (with-socklen (size et
:size-of-sockaddr-storage
)
321 (with-socket-error-filter
323 (make-client-socket (et:accept
(fd-of socket
) ss size
))
324 (et:ewouldblock
())))))))
332 (defmethod connect :before
((socket active-socket
)
334 (declare (ignore sockaddr
))
335 (set-socket-option socket
:no-sigpipe
:value t
))
337 (defun ipv4-connect (fd address port
)
338 (with-sockaddr-in (sin address port
)
339 (with-socket-error-filter
340 (et:connect fd sin et
:size-of-sockaddr-in
))))
342 (defun ipv6-connect (fd address port
)
343 (with-sockaddr-in6 (sin6 address port
)
344 (with-socket-error-filter
345 (et:connect fd sin6 et
:size-of-sockaddr-in6
))))
347 (defmethod connect ((socket internet-socket
)
348 (address ipv4addr
) &key
(port 0))
349 (if (eql (socket-family socket
) :ipv6
)
350 (ipv6-connect (fd-of socket
)
351 (map-ipv4-vector-to-ipv6 (name address
))
353 (ipv4-connect (fd-of socket
) (name address
) port
))
356 (defmethod connect ((socket internet-socket
)
357 (address ipv6addr
) &key
(port 0))
358 (ipv6-connect (fd-of socket
) (name address
) port
)
361 (defmethod connect ((socket local-socket
)
362 (address localaddr
) &key
)
363 (with-sockaddr-un (sun (name address
))
364 (with-socket-error-filter
365 (et:connect
(fd-of socket
) sun et
:size-of-sockaddr-un
)))
368 (defmethod connect ((socket passive-socket
) address
&key
)
369 (declare (ignore address
))
370 (error "You cannot connect passive sockets."))
372 (defmethod socket-connected-p ((socket socket
))
373 (unless (fd-of socket
)
374 (return-from socket-connected-p nil
))
375 (with-socket-error-filter
377 (with-foreign-object (ss 'et
:sockaddr-storage
)
378 (et:bzero ss et
:size-of-sockaddr-storage
)
379 (with-socklen (size et
:size-of-sockaddr-storage
)
380 (et:getpeername
(fd-of socket
) ss size
)
389 (defmethod shutdown ((socket active-socket
) direction
)
390 (check-type direction
(member :read
:write
:read-write
)
391 "valid direction specifier")
392 (with-socket-error-filter
393 (et:shutdown
(fd-of socket
)
397 (:read-write et
:shut-rdwr
))))
400 (defmethod shutdown ((socket passive-socket
) direction
)
401 (declare (ignore direction
))
402 (error "You cannot shut down passive sockets."))
409 (defun %normalize-send-buffer
(buff start end ef
)
410 (setf (values start end
) (%check-bounds buff start end
))
412 (ub8-sarray (values buff start
(- end start
)))
413 (ub8-vector (values (coerce buff
'ub8-sarray
)
414 start
(- end start
)))
415 (string (values (%to-octets buff ef start end
)
418 (defmethod socket-send ((buffer array
)
419 (socket active-socket
) &key
(start 0) end
420 remote-address remote-port end-of-record
421 dont-route dont-wait no-signal
422 out-of-band
#+linux more
#+linux confirm
)
423 (check-type start unsigned-byte
424 "a non-negative unsigned integer")
425 (check-type end
(or unsigned-byte null
)
426 "a non-negative unsigned integer or NIL")
427 (when (or remote-port remote-address
)
428 (check-type remote-address sockaddr
"a network address")
429 (check-type remote-port
(unsigned-byte 16) "a valid IP port number"))
430 (let ((flags (logior (if end-of-record et
:msg-eor
0)
431 (if dont-route et
:msg-dontroute
0)
432 (if dont-wait et
:msg-dontwait
0)
433 (if no-signal et
:msg-nosignal
0)
434 (if out-of-band et
:msg-oob
0)
435 #+linux
(if more et
:msg-more
0)
436 #+linux
(if confirm et
:msg-confirm
0))))
437 (when (and (ipv4-address-p remote-address
)
438 (eql (socket-family socket
) :ipv6
))
439 (setf remote-address
(map-ipv4-address->ipv6 remote-address
)))
440 (multiple-value-bind (buff start-offset bufflen
)
441 (%normalize-send-buffer buffer start end
(external-format-of socket
))
442 (with-foreign-object (ss 'et
:sockaddr-storage
)
443 (et:bzero ss et
:size-of-sockaddr-storage
)
445 (sockaddr->sockaddr-storage ss remote-address remote-port
))
446 (with-pointer-to-vector-data (buff-sap buff
)
447 (incf-pointer buff-sap start-offset
)
448 (with-socket-error-filter
449 (return-from socket-send
450 (et:sendto
(fd-of socket
)
453 (if remote-address ss
(null-pointer))
454 (if remote-address et
:size-of-sockaddr-storage
0)))))))))
456 (defmethod socket-send (buffer (socket passive-socket
) &key
)
457 (declare (ignore buffer
))
458 (error "You cannot send data on a passive socket."))
465 (defun %normalize-receive-buffer
(buff start end
)
466 (setf (values start end
) (%check-bounds buff start end
))
468 ((simple-array ub8
(*)) (values buff start
(- end start
)))))
470 (defun calc-recvfrom-flags (out-of-band peek wait-all dont-wait no-signal
)
471 (logior (if out-of-band et
:msg-oob
0)
472 (if peek et
:msg-peek
0)
473 (if wait-all et
:msg-waitall
0)
474 (if dont-wait et
:msg-dontwait
0)
475 (if no-signal et
:msg-nosignal
0)))
477 (defun %do-recvfrom
(buffer ss fd flags start end
)
478 (multiple-value-bind (buff start-offset bufflen
)
479 (%normalize-receive-buffer buffer start end
)
480 (with-socklen (size et
:size-of-sockaddr-storage
)
481 (et:bzero ss et
:size-of-sockaddr-storage
)
482 (with-pointer-to-vector-data (buff-sap buff
)
483 (incf-pointer buff-sap start-offset
)
484 (with-socket-error-filter
485 (return-from %do-recvfrom
486 (et:recvfrom fd buff-sap bufflen flags ss size
)))))))
488 (defmethod socket-receive ((buffer array
) (socket stream-socket
) &key
(start 0) end
489 out-of-band peek wait-all dont-wait no-signal
)
490 (with-foreign-object (ss 'et
:sockaddr-storage
)
491 (let* ((flags (calc-recvfrom-flags out-of-band peek wait-all dont-wait no-signal
))
492 (bytes-received (%do-recvfrom buffer ss
(fd-of socket
) flags start end
)))
493 (values buffer bytes-received
))))
495 (defmethod socket-receive ((buffer array
) (socket datagram-socket
) &key
(start 0) end
496 out-of-band peek wait-all dont-wait no-signal
)
497 (with-foreign-object (ss 'et
:sockaddr-storage
)
498 (let* ((flags (calc-recvfrom-flags out-of-band peek wait-all dont-wait no-signal
))
499 (bytes-received (%do-recvfrom buffer ss
(fd-of socket
) flags start end
)))
500 (multiple-value-bind (remote-address remote-port
)
501 (sockaddr-storage->sockaddr ss
)
502 (values buffer bytes-received remote-address remote-port
)))))
504 (defmethod socket-receive (buffer (socket passive-socket
) &key
)
505 (declare (ignore buffer
))
506 (error "You cannot receive data from a passive socket."))
510 ;; Only for datagram sockets
513 (defmethod disconnect :before
((socket active-socket
))
514 (unless (typep socket
'datagram-socket
)
515 (error "You can only disconnect active datagram sockets.")))
517 (defmethod disconnect ((socket datagram-socket
))
518 (with-foreign-object (sin 'et
:sockaddr-in
)
519 (et:bzero sin et
:size-of-sockaddr-in
)
520 (setf (foreign-slot-value sin
'et
:sockaddr-in
'et
:addr
) et
:af-unspec
)
521 (with-socket-error-filter
522 (et:connect
(fd-of socket
) sin et
:size-of-sockaddr-in
))))