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 (defparameter *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 shared-initialize :after
((socket socket
) slot-names
63 &key file-descriptor family
64 type
(protocol :default
))
65 (when (socket-open-p socket
)
67 (with-slots (fd (fam family
) (proto protocol
)) socket
68 (multiple-value-bind (sf st sp
)
69 (translate-make-socket-keywords-to-constants family type protocol
)
71 (setf fd file-descriptor
)
72 (setf fd
(with-socket-error-filter
73 (et:socket sf st sp
))))
77 (defmethod socket-type ((socket stream-socket
))
80 (defmethod socket-type ((socket datagram-socket
))
88 (defmethod print-object ((socket socket-stream-internet-active
) stream
)
89 (print-unreadable-object (socket stream
:type nil
:identity t
)
90 (format stream
"active internet stream socket" )
91 (if (socket-connected-p socket
)
92 (multiple-value-bind (addr port
) (remote-name socket
)
93 (format stream
" connected to ~A/~A"
94 (sockaddr->presentation addr
) port
))
95 (if (slot-value socket
'fd
)
96 (format stream
", unconnected")
97 (format stream
", closed")))))
99 (defmethod print-object ((socket socket-stream-internet-passive
) stream
)
100 (print-unreadable-object (socket stream
:type nil
:identity t
)
101 (format stream
"passive internet stream socket" )
102 (if (socket-bound-p socket
)
103 (multiple-value-bind (addr port
) (local-name socket
)
104 (format stream
" ~A ~A/~A"
105 (if (socket-listening-p socket
)
106 "waiting for connections @"
108 (sockaddr->presentation addr
) port
))
109 (if (slot-value socket
'fd
)
110 (format stream
", unbound")
111 (format stream
", closed")))))
113 (defmethod print-object ((socket socket-stream-local-active
) stream
)
114 (print-unreadable-object (socket stream
:type nil
:identity t
)
115 (format stream
"active local stream socket" )
116 (if (socket-connected-p socket
)
117 (format stream
" connected")
118 (if (slot-value socket
'fd
)
119 (format stream
", unconnected")
120 (format stream
", closed")))))
122 (defmethod print-object ((socket socket-stream-local-passive
) stream
)
123 (print-unreadable-object (socket stream
:type nil
:identity t
)
124 (format stream
"passive local stream socket" )
125 (if (socket-bound-p socket
)
126 (format stream
" ~A ~A"
127 (if (socket-listening-p socket
)
128 "waiting for connections @"
130 (sockaddr->presentation
(socket-address socket
)))
131 (if (slot-value socket
'fd
)
132 (format stream
", unbound")
133 (format stream
", closed")))))
135 (defmethod print-object ((socket socket-datagram-local-active
) stream
)
136 (print-unreadable-object (socket stream
:type nil
:identity t
)
137 (format stream
"local datagram socket" )
138 (if (socket-connected-p socket
)
139 (format stream
" connected")
140 (if (slot-value socket
'fd
)
141 (format stream
", unconnected")
142 (format stream
", closed")))))
144 (defmethod print-object ((socket socket-datagram-internet-active
) stream
)
145 (print-unreadable-object (socket stream
:type nil
:identity t
)
146 (format stream
"internet datagram socket" )
147 (if (socket-connected-p socket
)
148 (multiple-value-bind (addr port
) (remote-name socket
)
149 (format stream
" connected to ~A/~A"
150 (sockaddr->presentation addr
) port
))
151 (if (slot-value socket
'fd
)
152 (format stream
", unconnected")
153 (format stream
", closed")))))
160 (defmethod close :around
((socket socket
) &key abort
)
161 (declare (ignore abort
))
162 (when (slot-value socket
'fd
)
163 (with-socket-error-filter
164 (et:close
(socket-fd socket
))))
165 (setf (slot-value socket
'fd
) nil
)
169 (defmethod close :around
((socket passive-socket
) &key abort
)
170 (declare (ignore abort
))
172 (setf (slot-value socket
'bound
) nil
)
173 (setf (slot-value socket
'listening
) nil
)
176 (defmethod close ((socket socket
) &key abort
)
177 (declare (ignore socket abort
)))
179 (defmethod socket-open-p ((socket socket
))
180 (unless (slot-value socket
'fd
)
181 (return-from socket-open-p nil
))
182 (with-socket-error-filter
184 (with-foreign-object (ss 'et
:sockaddr-storage
)
185 (et:bzero ss et
:size-of-sockaddr-storage
)
186 (with-foreign-pointer (size et
:size-of-socklen
)
187 (setf (mem-ref size
:socklen
)
188 et
:size-of-sockaddr-storage
)
189 (et:getsockname
(socket-fd socket
)
193 (case (error-identifier err
)
195 #+freebsd
:econnreset
)
198 (otherwise (error err
)))))))
201 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
202 ;; get and set O_NONBLOCK ;;
203 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
205 (defmethod socket-non-blocking ((socket socket
))
206 (with-slots (fd) socket
207 (let ((current-flags (with-socket-error-filter
208 (et:fcntl fd et
:f-getfl
))))
209 (logtest et
:o-nonblock current-flags
))))
211 (defmethod (setf socket-non-blocking
) (value (socket socket
))
212 (check-type value boolean
"a boolean value")
213 (with-slots (fd) socket
214 (with-socket-error-filter
215 (let* ((current-flags (et:fcntl fd et
:f-getfl
))
217 (logior current-flags et
:o-nonblock
)
218 (logandc2 current-flags et
:o-nonblock
))))
219 (when (/= new-flags current-flags
)
220 (et:fcntl fd et
:f-setfl new-flags
)))))
228 (defmethod local-name ((socket internet-socket
))
229 (with-foreign-object (ss 'et
:sockaddr-storage
)
230 (et:bzero ss et
:size-of-sockaddr-storage
)
231 (with-foreign-pointer (size et
:size-of-socklen
)
232 (setf (mem-ref size
:socklen
)
233 et
:size-of-sockaddr-storage
)
234 (with-socket-error-filter
235 (et:getsockname
(socket-fd socket
)
237 (return-from local-name
238 (sockaddr-storage->sockaddr ss
)))))
240 (defmethod local-name ((socket local-socket
))
241 (with-foreign-object (sun 'et
:sockaddr-un
)
242 (et:bzero sun et
:size-of-sockaddr-un
)
243 (with-foreign-pointer (size et
:size-of-socklen
)
244 (setf (mem-ref size
:socklen
)
245 et
:size-of-sockaddr-storage
)
246 (with-socket-error-filter
247 (et:getsockname
(socket-fd socket
)
249 (return-from local-name
250 (sockaddr-un->sockaddr sun
)))))
252 (defmethod socket-address ((socket socket
))
253 (nth-value 0 (local-name socket
)))
255 (defmethod socket-port ((socket internet-socket
))
256 (nth-value 1 (local-name socket
)))
263 (defmethod remote-name ((socket internet-socket
))
264 (with-foreign-object (ss 'et
:sockaddr-storage
)
265 (et:bzero ss et
:size-of-sockaddr-storage
)
266 (with-foreign-pointer (size et
:size-of-socklen
)
267 (setf (mem-ref size
:socklen
)
268 et
:size-of-sockaddr-storage
)
269 (with-socket-error-filter
270 (et:getpeername
(socket-fd socket
)
272 (return-from remote-name
273 (sockaddr-storage->sockaddr ss
)))))
275 (defmethod remote-name ((socket local-socket
))
276 (with-foreign-object (sun 'et
:sockaddr-un
)
277 (et:bzero sun et
:size-of-sockaddr-un
)
278 (with-foreign-pointer (size et
:size-of-socklen
)
279 (setf (mem-ref size
:socklen
)
280 et
:size-of-sockaddr-storage
)
281 (with-socket-error-filter
282 (et:getpeername
(socket-fd socket
)
284 (return-from remote-name
285 (sockaddr-un->sockaddr sun
)))))
292 (defmethod bind-address :before
((socket internet-socket
)
293 address
&key
(reuse-address t
))
295 (set-socket-option socket
:reuse-address
:value t
)))
297 (defun bind-ipv4-address (fd address port
)
298 (with-foreign-object (sin 'et
:sockaddr-in
)
299 (make-sockaddr-in sin address port
)
300 (with-socket-error-filter
301 (et:bind fd sin et
:size-of-sockaddr-in
))))
303 (defun bind-ipv6-address (fd address port
)
304 (with-foreign-object (sin6 'et
:sockaddr-in6
)
305 (make-sockaddr-in6 sin6 address port
)
306 (with-socket-error-filter
307 (et:bind fd sin6 et
:size-of-sockaddr-in6
))))
309 (defmethod bind-address ((socket internet-socket
)
312 (if (eql (socket-family socket
) :ipv6
)
313 (bind-ipv6-address (socket-fd socket
)
314 (map-ipv4-vector-to-ipv6 (name address
))
316 (bind-ipv4-address (socket-fd socket
) (name address
) port
))
319 (defmethod bind-address ((socket internet-socket
)
322 (bind-ipv6-address (socket-fd socket
) (name address
) port
)
325 (defmethod bind-address :before
((socket local-socket
)
326 (address localaddr
) &key
)
327 (when (typep socket
'active-socket
)
328 (error "You can't bind an active Unix socket.")))
330 (defmethod bind-address ((socket local-socket
)
331 (address localaddr
) &key
)
332 (with-foreign-object (sun 'et
:sockaddr-un
)
333 (make-sockaddr-un sun
(name address
))
334 (with-socket-error-filter
335 (et:bind
(socket-fd socket
) sun et
:size-of-sockaddr-un
)))
338 (defmethod bind-address :after
((socket socket
)
339 (address sockaddr
) &key
)
340 (setf (slot-value socket
'bound
) t
))
347 (defmethod socket-listen ((socket passive-socket
)
348 &key
(backlog (min *default-backlog-size
*
349 +max-backlog-size
+)))
350 (check-type backlog unsigned-byte
"a non-negative integer")
351 (with-socket-error-filter
352 (et:listen
(socket-fd socket
) backlog
))
353 (setf (slot-value socket
'listening
) t
)
356 (defmethod socket-listen ((socket active-socket
)
358 (declare (ignore backlog
))
359 (error "You can't listen on active sockets."))
366 (defmethod accept-connection ((socket active-socket
)
368 (declare (ignore wait
))
369 (error "You can't accept connections on active sockets."))
371 (defmethod accept-connection ((socket passive-socket
)
373 (with-foreign-object (ss 'et
:sockaddr-storage
)
374 (et:bzero ss et
:size-of-sockaddr-storage
)
375 (with-foreign-pointer (size et
:size-of-socklen
)
376 (setf (mem-ref size
:socklen
)
377 et
:size-of-sockaddr-storage
)
378 (let (non-blocking-state
380 (with-socket-error-filter
383 ;; do a "normal" accept
384 ;; Note: the socket may already be in non-blocking mode
385 (setf client-fd
(et:accept
(socket-fd socket
)
387 ;; set the socket to non-blocking mode before calling accept()
388 ;; if there's no new connection return NIL
391 ;; saving the current non-blocking state
392 (setf non-blocking-state
(socket-non-blocking socket
))
393 ;; switch the socket to non-blocking mode
394 (setf (socket-non-blocking socket
) t
)
395 (setf client-fd
(et:accept
(socket-fd socket
)
397 ;; restoring the socket's non-blocking state
398 (setf (socket-non-blocking socket
) non-blocking-state
)))
399 ;; the socket is marked non-blocking and there's no new connection
400 (et:unix-error-wouldblock
(err)
401 (declare (ignore err
))
402 (return-from accept-connection nil
))))
405 ;; create the client socket object
406 (make-instance (active-class socket
)
407 :file-descriptor client-fd
)))
408 (return-from accept-connection client-socket
))))))
416 (defmethod connect :before
((socket active-socket
)
419 (set-socket-option socket
:no-sigpipe
:value t
)))
421 (defun ipv4-connect (fd address port
)
422 (with-foreign-object (sin 'et
:sockaddr-in
)
423 (make-sockaddr-in sin address port
)
424 (with-socket-error-filter
425 (et:connect fd sin et
:size-of-sockaddr-in
))))
427 (defun ipv6-connect (fd address port
)
428 (with-foreign-object (sin6 'et
:sockaddr-in6
)
429 (make-sockaddr-in6 sin6 address port
)
430 (with-socket-error-filter
431 (et:connect fd sin6 et
:size-of-sockaddr-in6
))))
433 (defmethod connect ((socket internet-socket
)
434 (address ipv4addr
) &key
(port 0))
435 (if (eql (socket-family socket
) :ipv6
)
436 (ipv6-connect (socket-fd socket
)
437 (map-ipv4-vector-to-ipv6 (name address
))
439 (ipv4-connect (socket-fd socket
) (name address
) port
))
442 (defmethod connect ((socket internet-socket
)
443 (address ipv6addr
) &key
(port 0))
444 (ipv6-connect (socket-fd socket
) (name address
) port
)
447 (defmethod connect ((socket local-socket
)
448 (address localaddr
) &key
)
449 (with-foreign-object (sun 'et
:sockaddr-un
)
450 (make-sockaddr-un sun
(name address
))
451 (with-socket-error-filter
452 (et:connect
(socket-fd socket
) sun et
:size-of-sockaddr-un
)))
455 (defmethod connect ((socket passive-socket
)
457 (error "You cannot connect passive sockets."))
459 (defmethod socket-connected-p ((socket socket
))
460 (unless (slot-value socket
'fd
)
461 (return-from socket-connected-p nil
))
462 (with-socket-error-filter
464 (with-foreign-object (ss 'et
:sockaddr-storage
)
465 (et:bzero ss et
:size-of-sockaddr-storage
)
466 (with-foreign-pointer (size et
:size-of-socklen
)
467 (setf (mem-ref size
:socklen
)
468 et
:size-of-sockaddr-storage
)
469 (et:getpeername
(socket-fd socket
)
472 (et:unix-error-notconn
(err)
473 (declare (ignore err
))
481 (defmethod shutdown ((socket active-socket
) direction
)
482 (check-type direction
(member :read
:write
:read-write
)
483 "valid direction specifier")
484 (with-socket-error-filter
485 (et:shutdown
(socket-fd socket
)
489 (:read-write et
:shut-rdwr
))))
492 (defmethod shutdown ((socket passive-socket
) direction
)
493 (error "You cannot shut down passive sockets."))
500 (defun normalize-send-buffer (buff vstart vend
)
501 (let ((start (or vstart
0))
503 (min vend
(length buff
))
505 (assert (<= start end
))
507 ((simple-array ub8
(*)) (values buff start
(- end start
)))
508 ((vector ub8
) (values (coerce buff
'(simple-array ub8
(*)))
509 start
(- end start
)))
510 (string (values (coerce (io.encodings
:string-to-octets buff
:external-format
:iso-8859-1
511 :start start
:end end
)
512 '(simple-array ub8
(*)))
515 (defmethod socket-send :before
((buffer array
)
516 (socket active-socket
)
518 remote-address remote-port
)
519 (check-type start
(or unsigned-byte null
)
520 "a non-negative value or NIL")
521 (check-type end
(or unsigned-byte null
)
522 "a non-negative value or NIL")
523 (when (or remote-port remote-address
)
524 (check-type remote-address sockaddr
"a network address")
525 (check-type remote-port
(unsigned-byte 16) "a valid IP port number")))
527 (defmethod socket-send ((buffer array
)
528 (socket active-socket
) &key start end
529 remote-address remote-port end-of-record
530 dont-route dont-wait
(no-signal *no-sigpipe
*)
531 out-of-band
#+linux more
#+linux confirm
)
533 (let ((flags (logior (if end-of-record et
:msg-eor
0)
534 (if dont-route et
:msg-dontroute
0)
535 (if dont-wait et
:msg-dontwait
0)
536 (if no-signal et
:msg-nosignal
0)
537 (if out-of-band et
:msg-oob
0)
538 #+linux
(if more et
:msg-more
0)
539 #+linux
(if confirm et
:msg-confirm
0))))
541 (when (and (ipv4-address-p remote-address
)
542 (eql (socket-family socket
) :ipv6
))
543 (setf remote-address
(map-ipv4-address->ipv6 remote-address
)))
544 (multiple-value-bind (buff start-offset bufflen
)
545 (normalize-send-buffer buffer start end
)
546 (with-foreign-object (ss 'et
:sockaddr-storage
)
547 (et:bzero ss et
:size-of-sockaddr-storage
)
549 (sockaddr->sockaddr-storage ss remote-address remote-port
))
550 (with-pointer-to-vector-data (buff-sap buff
)
551 (incf-pointer buff-sap start-offset
)
552 (with-socket-error-filter
553 (return-from socket-send
554 (et:sendto
(socket-fd socket
)
557 (if remote-address ss
(null-pointer))
558 (if remote-address et
:size-of-sockaddr-storage
0)))))))))
560 (defmethod socket-send (buffer (socket passive-socket
) &key
)
561 (error "You cannot send data on a passive socket."))
568 (defun normalize-receive-buffer (buff vstart vend
)
569 (let ((start (or vstart
0))
571 (min vend
(length buff
))
573 (assert (<= start end
))
575 ((simple-array ub8
(*)) (values buff start
(- end start
)))
576 (simple-base-string (values buff start
(- end start
))))))
578 (defmethod socket-receive :before
((buffer array
)
579 (socket active-socket
)
581 (check-type start
(or unsigned-byte null
)
582 "a non-negative value or NIL")
583 (check-type end
(or unsigned-byte null
)
584 "a non-negative value or NIL"))
586 (defmethod socket-receive ((buffer array
)
587 (socket active-socket
) &key start end
588 out-of-band peek wait-all
589 dont-wait
(no-signal *no-sigpipe
*))
591 (let ((flags (logior (if out-of-band et
:msg-oob
0)
592 (if peek et
:msg-peek
0)
593 (if wait-all et
:msg-waitall
0)
594 (if dont-wait et
:msg-dontwait
0)
595 (if no-signal et
:msg-nosignal
0)))
598 (multiple-value-bind (buff start-offset bufflen
)
599 (normalize-receive-buffer buffer start end
)
600 (with-foreign-object (ss 'et
:sockaddr-storage
)
601 (et:bzero ss et
:size-of-sockaddr-storage
)
602 (with-foreign-pointer (size et
:size-of-socklen
)
603 (setf (mem-ref size
:socklen
)
604 et
:size-of-sockaddr-storage
)
605 (with-pointer-to-vector-data (buff-sap buff
)
606 (incf-pointer buff-sap start-offset
)
607 (with-socket-error-filter
609 (et:recvfrom
(socket-fd socket
)
614 (return-from socket-receive
615 ;; when socket is a datagram socket
616 ;; return the sender's address as 3rd value
617 (if (typep socket
'datagram-socket
)
618 (multiple-value-bind (remote-address remote-port
)
619 (sockaddr-storage->sockaddr ss
)
620 (values buffer bytes-received remote-address remote-port
))
621 (values buffer bytes-received
)))))))
623 (defmethod socket-receive (buffer (socket passive-socket
) &key
)
624 (error "You cannot receive data from a passive socket."))
628 ;; Only for datagram sockets
631 (defmethod unconnect :before
((socket active-socket
))
632 (unless (typep socket
'datagram-socket
)
633 (error "You can only unconnect active datagram sockets.")))
635 (defmethod unconnect ((socket datagram-socket
))
636 (with-socket-error-filter
637 (with-foreign-object (sin 'et
:sockaddr-in
)
638 (et:bzero sin et
:size-of-sockaddr-in
)
639 (setf (foreign-slot-value sin
'et
:sockaddr-in
'et
:addr
) et
:af-unspec
)
640 (et:connect
(socket-fd socket
) sin et
:size-of-sockaddr-in
))))