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
)
66 (socket-close 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 ;; TODO: find out how to make an FD-STREAM on other implementations
78 (defun make-fd-stream (fd)
79 (check-type fd unsigned-byte
)
81 (sb-sys:make-fd-stream fd
82 :name
(format nil
"Socket stream, fd: ~A" fd
)
83 :input t
:output t
:buffering
:full
:dual-channel-p t
84 :element-type
:default
:auto-close nil
)
86 (system:make-fd-stream fd
87 :name
(format nil
"Socket stream, fd: ~A" fd
)
88 :input t
:output t
:buffering
:full
89 :binary-stream-p nil
:auto-close nil
))
91 (defmethod shared-initialize :after
((socket stream-socket
) slot-names
&key
)
92 (setf (slot-value socket
'lisp-stream
)
93 (make-fd-stream (socket-fd socket
))))
95 (defmethod socket-type ((socket stream-socket
))
98 (defmethod socket-type ((socket datagram-socket
))
106 (defmethod print-object ((socket socket-stream-internet-active
) stream
)
107 (print-unreadable-object (socket stream
:type nil
:identity t
)
108 (format stream
"internet stream socket" )
109 (if (socket-connected-p socket
)
110 (multiple-value-bind (addr port
) (remote-name socket
)
111 (format stream
" connected to ~A/~A"
112 (sockaddr->presentation addr
) port
))
113 (if (slot-boundp socket
'fd
)
114 (format stream
", unconnected")
115 (format stream
", closed")))))
117 (defmethod print-object ((socket socket-stream-internet-passive
) stream
)
118 (print-unreadable-object (socket stream
:type nil
:identity t
)
119 (format stream
"internet stream socket" )
120 (if (socket-bound-p socket
)
121 (multiple-value-bind (addr port
) (local-name socket
)
122 (format stream
" ~A ~A/~A"
123 (if (socket-listening-p socket
)
124 "waiting for connections @"
126 (sockaddr->presentation addr
) port
))
127 (if (slot-boundp socket
'fd
)
128 (format stream
", unbound")
129 (format stream
", closed")))))
131 (defmethod print-object ((socket socket-stream-local-active
) stream
)
132 (print-unreadable-object (socket stream
:type nil
:identity t
)
133 (format stream
"local stream socket" )
134 (if (socket-connected-p socket
)
135 (format stream
" connected")
136 (if (slot-boundp socket
'fd
)
137 (format stream
", unconnected")
138 (format stream
", closed")))))
140 (defmethod print-object ((socket socket-stream-local-passive
) stream
)
141 (print-unreadable-object (socket stream
:type nil
:identity t
)
142 (format stream
"local stream socket" )
143 (if (socket-bound-p socket
)
144 (format stream
" ~A ~A"
145 (if (socket-listening-p socket
)
146 "waiting for connections @"
148 (sockaddr->presentation
(socket-address socket
)))
149 (if (slot-boundp socket
'fd
)
150 (format stream
", unbound")
151 (format stream
", closed")))))
153 (defmethod print-object ((socket socket-datagram-local-active
) stream
)
154 (print-unreadable-object (socket stream
:type nil
:identity t
)
155 (format stream
"local datagram socket" )
156 (if (socket-connected-p socket
)
157 (format stream
" connected")
158 (if (slot-boundp socket
'fd
)
159 (format stream
", unconnected")
160 (format stream
", closed")))))
162 (defmethod print-object ((socket socket-datagram-internet-active
) stream
)
163 (print-unreadable-object (socket stream
:type nil
:identity t
)
164 (format stream
"internet stream socket" )
165 (if (socket-connected-p socket
)
166 (multiple-value-bind (addr port
) (remote-name socket
)
167 (format stream
" connected to ~A/~A"
168 (sockaddr->presentation addr
) port
))
169 (if (slot-boundp socket
'fd
)
170 (format stream
", unconnected")
171 (format stream
", closed")))))
178 (defmethod socket-close progn
((socket socket
))
179 (when (slot-boundp socket
'fd
)
180 (with-socket-error-filter
181 (et:close
(socket-fd socket
))))
182 (mapc #'(lambda (slot)
183 (slot-makunbound socket slot
))
184 '(fd family protocol
))
187 (defmethod socket-close progn
((socket stream-socket
))
188 (slot-makunbound socket
'lisp-stream
))
190 (defmethod socket-close progn
((socket passive-socket
))
191 (slot-makunbound socket
'listening
))
193 (defmethod socket-open-p ((socket socket
))
194 (unless (slot-boundp socket
'fd
)
195 (return-from socket-open-p nil
))
196 (with-socket-error-filter
198 (with-foreign-object (ss 'et
:sockaddr-storage
)
199 (et:bzero ss et
:size-of-sockaddr-storage
)
200 (with-foreign-pointer (size et
:size-of-socklen
)
201 (setf (mem-ref size
:socklen
)
202 et
:size-of-sockaddr-storage
)
203 (et:getsockname
(socket-fd socket
)
207 (case (error-identifier err
)
209 #+freebsd
:econnreset
)
212 (otherwise (error err
)))))))
215 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216 ;; get and set O_NONBLOCK ;;
217 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
219 (defmethod socket-non-blocking ((socket socket
))
220 (with-slots (fd) socket
221 (let ((current-flags (with-socket-error-filter
222 (et:fcntl fd et
:f-getfl
))))
223 (logtest et
:o-nonblock current-flags
))))
225 (defmethod (setf socket-non-blocking
) (value (socket socket
))
226 (check-type value boolean
"a boolean value")
227 (with-slots (fd) socket
228 (with-socket-error-filter
229 (let* ((current-flags (et:fcntl fd et
:f-getfl
))
231 (logior current-flags et
:o-nonblock
)
232 (logandc2 current-flags et
:o-nonblock
))))
233 (when (/= new-flags current-flags
)
234 (et:fcntl fd et
:f-setfl new-flags
)))))
242 (defmethod local-name ((socket internet-socket
))
243 (with-foreign-object (ss 'et
:sockaddr-storage
)
244 (et:bzero ss et
:size-of-sockaddr-storage
)
245 (with-foreign-pointer (size et
:size-of-socklen
)
246 (setf (mem-ref size
:socklen
)
247 et
:size-of-sockaddr-storage
)
248 (with-socket-error-filter
249 (et:getsockname
(socket-fd socket
)
251 (return-from local-name
252 (sockaddr-storage->sockaddr ss
)))))
254 (defmethod local-name ((socket local-socket
))
255 (with-foreign-object (sun 'et
:sockaddr-un
)
256 (et:bzero sun et
:size-of-sockaddr-un
)
257 (with-foreign-pointer (size et
:size-of-socklen
)
258 (setf (mem-ref size
:socklen
)
259 et
:size-of-sockaddr-storage
)
260 (with-socket-error-filter
261 (et:getsockname
(socket-fd socket
)
263 (return-from local-name
264 (sockaddr-un->sockaddr sun
)))))
266 (defmethod socket-address ((socket socket
))
267 (nth-value 0 (local-name socket
)))
269 (defmethod socket-port ((socket internet-socket
))
270 (nth-value 1 (local-name socket
)))
277 (defmethod remote-name ((socket internet-socket
))
278 (with-foreign-object (ss 'et
:sockaddr-storage
)
279 (et:bzero ss et
:size-of-sockaddr-storage
)
280 (with-foreign-pointer (size et
:size-of-socklen
)
281 (setf (mem-ref size
:socklen
)
282 et
:size-of-sockaddr-storage
)
283 (with-socket-error-filter
284 (et:getpeername
(socket-fd socket
)
286 (return-from remote-name
287 (sockaddr-storage->sockaddr ss
)))))
289 (defmethod remote-name ((socket local-socket
))
290 (with-foreign-object (sun 'et
:sockaddr-un
)
291 (et:bzero sun et
:size-of-sockaddr-un
)
292 (with-foreign-pointer (size et
:size-of-socklen
)
293 (setf (mem-ref size
:socklen
)
294 et
:size-of-sockaddr-storage
)
295 (with-socket-error-filter
296 (et:getpeername
(socket-fd socket
)
298 (return-from remote-name
299 (sockaddr-un->sockaddr sun
)))))
306 (defmethod bind-address :before
((socket internet-socket
)
307 address
&key
(reuse-address t
))
309 (set-socket-option socket
:reuse-address
:value t
)))
311 (defun bind-ipv4-address (fd address port
)
312 (with-foreign-object (sin 'et
:sockaddr-in
)
313 (make-sockaddr-in sin address port
)
314 (with-socket-error-filter
315 (et:bind fd sin et
:size-of-sockaddr-in
))))
317 (defun bind-ipv6-address (fd address port
)
318 (with-foreign-object (sin6 'et
:sockaddr-in6
)
319 (make-sockaddr-in6 sin6 address port
)
320 (with-socket-error-filter
321 (et:bind fd sin6 et
:size-of-sockaddr-in6
))))
323 (defmethod bind-address ((socket internet-socket
)
326 (if (eql (socket-family socket
) :ipv6
)
327 (bind-ipv6-address (socket-fd socket
)
328 (map-ipv4-vector-to-ipv6 (name address
))
330 (bind-ipv4-address (socket-fd socket
) (name address
) port
))
333 (defmethod bind-address ((socket internet-socket
)
336 (bind-ipv6-address (socket-fd socket
) (name address
) port
)
339 (defmethod bind-address :before
((socket local-socket
)
340 (address localaddr
) &key
)
341 (when (typep socket
'active-socket
)
342 (error "You can't bind an active Unix socket.")))
344 (defmethod bind-address ((socket local-socket
)
345 (address localaddr
) &key
)
346 (with-foreign-object (sun 'et
:sockaddr-un
)
347 (make-sockaddr-un sun
(name address
))
348 (with-socket-error-filter
349 (et:bind
(socket-fd socket
) sun et
:size-of-sockaddr-un
)))
352 (defmethod bind-address :after
((socket socket
)
353 (address sockaddr
) &key
)
354 (setf (slot-value socket
'bound
) t
))
361 (defmethod socket-listen ((socket passive-socket
)
362 &key
(backlog (min *default-backlog-size
*
363 +max-backlog-size
+)))
364 (check-type backlog unsigned-byte
"a non-negative integer")
365 (with-socket-error-filter
366 (et:listen
(socket-fd socket
) backlog
))
367 (setf (slot-value socket
'listening
) t
)
370 (defmethod socket-listen ((socket active-socket
)
372 (declare (ignore backlog
))
373 (error "You can't listen on active sockets."))
380 (defmethod accept-connection ((socket active-socket
)
382 (declare (ignore wait
))
383 (error "You can't accept connections on active sockets."))
385 (defmethod accept-connection ((socket passive-socket
)
387 (with-foreign-object (ss 'et
:sockaddr-storage
)
388 (et:bzero ss et
:size-of-sockaddr-storage
)
389 (with-foreign-pointer (size et
:size-of-socklen
)
390 (setf (mem-ref size
:socklen
)
391 et
:size-of-sockaddr-storage
)
392 (let (non-blocking-state
394 (with-socket-error-filter
397 ;; do a "normal" accept
398 ;; Note: the socket may already be in non-blocking mode
399 (setf client-fd
(et:accept
(socket-fd socket
)
401 ;; set the socket to non-blocking mode before calling accept()
402 ;; if there's no new connection return NIL
405 ;; saving the current non-blocking state
406 (setf non-blocking-state
(socket-non-blocking socket
))
407 ;; switch the socket to non-blocking mode
408 (setf (socket-non-blocking socket
) t
)
409 (setf client-fd
(et:accept
(socket-fd socket
)
411 ;; restoring the socket's non-blocking state
412 (setf (socket-non-blocking socket
) non-blocking-state
)))
413 ;; the socket is marked non-blocking and there's no new connection
414 (et:unix-error-wouldblock
(err)
415 (declare (ignore err
))
416 (return-from accept-connection nil
))))
419 ;; create the client socket object
420 (make-instance (active-class socket
)
421 :file-descriptor client-fd
)))
422 (return-from accept-connection client-socket
))))))
430 (defmethod connect :before
((socket active-socket
)
433 (set-socket-option socket
:no-sigpipe
:value t
)))
435 (defun ipv4-connect (fd address port
)
436 (with-foreign-object (sin 'et
:sockaddr-in
)
437 (make-sockaddr-in sin address port
)
438 (with-socket-error-filter
439 (et:connect fd sin et
:size-of-sockaddr-in
))))
441 (defun ipv6-connect (fd address port
)
442 (with-foreign-object (sin6 'et
:sockaddr-in6
)
443 (make-sockaddr-in6 sin6 address port
)
444 (with-socket-error-filter
445 (et:connect fd sin6 et
:size-of-sockaddr-in6
))))
447 (defmethod connect ((socket internet-socket
)
448 (address ipv4addr
) &key
(port 0))
449 (if (eql (socket-family socket
) :ipv6
)
450 (ipv6-connect (socket-fd socket
)
451 (map-ipv4-vector-to-ipv6 (name address
))
453 (ipv4-connect (socket-fd socket
) (name address
) port
))
456 (defmethod connect ((socket internet-socket
)
457 (address ipv6addr
) &key
(port 0))
458 (ipv6-connect (socket-fd socket
) (name address
) port
)
461 (defmethod connect ((socket local-socket
)
462 (address localaddr
) &key
)
463 (with-foreign-object (sun 'et
:sockaddr-un
)
464 (make-sockaddr-un sun
(name address
))
465 (with-socket-error-filter
466 (et:connect
(socket-fd socket
) sun et
:size-of-sockaddr-un
)))
469 (defmethod connect ((socket passive-socket
)
471 (error "You cannot connect passive sockets."))
473 (defmethod socket-connected-p ((socket socket
))
474 (unless (slot-boundp socket
'fd
)
475 (return-from socket-connected-p nil
))
476 (with-socket-error-filter
478 (with-foreign-object (ss 'et
:sockaddr-storage
)
479 (et:bzero ss et
:size-of-sockaddr-storage
)
480 (with-foreign-pointer (size et
:size-of-socklen
)
481 (setf (mem-ref size
:socklen
)
482 et
:size-of-sockaddr-storage
)
483 (et:getpeername
(socket-fd socket
)
486 (et:unix-error-notconn
(err)
487 (declare (ignore err
))
495 (defmethod shutdown ((socket active-socket
) direction
)
496 (check-type direction
(member :read
:write
:read-write
)
497 "valid direction specifier")
498 (with-socket-error-filter
499 (et:shutdown
(socket-fd socket
)
503 (:read-write et
:shut-rdwr
))))
506 (defmethod shutdown ((socket passive-socket
) direction
)
507 (error "You cannot shut down passive sockets."))
514 (defun normalize-send-buffer (buff vstart vend
)
515 (let ((start (or vstart
0))
517 (min vend
(length buff
))
519 (assert (<= start end
))
521 ((simple-array ub8
(*)) (values buff start
(- end start
)))
522 ((vector ub8
) (values (coerce buff
'(simple-array ub8
(*)))
523 start
(- end start
)))
524 (string (values (coerce (flexi-streams:string-to-octets buff
:external-format
:iso-8859-1
525 :start start
:end end
)
526 '(simple-array ub8
(*)))
529 (defmethod socket-send :before
((buffer array
)
530 (socket active-socket
)
532 remote-address remote-port
)
533 (check-type start
(or unsigned-byte null
)
534 "a non-negative value or NIL")
535 (check-type end
(or unsigned-byte null
)
536 "a non-negative value or NIL")
537 (when (or remote-port remote-address
)
538 (check-type remote-address sockaddr
"a network address")
539 (check-type remote-port
(unsigned-byte 16) "a valid IP port number")))
541 (defmethod socket-send ((buffer array
)
542 (socket active-socket
) &key start end
543 remote-address remote-port end-of-record
544 dont-route dont-wait
(no-signal *no-sigpipe
*)
545 out-of-band
#+linux more
#+linux confirm
)
547 (let ((flags (logior (if end-of-record et
:msg-eor
0)
548 (if dont-route et
:msg-dontroute
0)
549 (if dont-wait et
:msg-dontwait
0)
550 (if no-signal et
:msg-nosignal
0)
551 (if out-of-band et
:msg-oob
0)
552 #+linux
(if more et
:msg-more
0)
553 #+linux
(if confirm et
:msg-confirm
0))))
555 (when (and (ipv4-address-p remote-address
)
556 (eql (socket-family socket
) :ipv6
))
557 (setf remote-address
(map-ipv4-address->ipv6 remote-address
)))
558 (multiple-value-bind (buff start-offset bufflen
)
559 (normalize-send-buffer buffer start end
)
560 (with-foreign-object (ss 'et
:sockaddr-storage
)
561 (et:bzero ss et
:size-of-sockaddr-storage
)
563 (sockaddr->sockaddr-storage ss remote-address remote-port
))
564 (with-pointer-to-vector-data (buff-sap buff
)
565 (incf-pointer buff-sap start-offset
)
566 (with-socket-error-filter
567 (return-from socket-send
568 (et:sendto
(socket-fd socket
)
571 (if remote-address ss
(null-pointer))
572 (if remote-address et
:size-of-sockaddr-storage
0)))))))))
574 (defmethod socket-send (buffer (socket passive-socket
) &key
)
575 (error "You cannot send data on a passive socket."))
582 (defun normalize-receive-buffer (buff vstart vend
)
583 (let ((start (or vstart
0))
585 (min vend
(length buff
))
587 (assert (<= start end
))
589 ((simple-array ub8
(*)) (values buff start
(- end start
)))
590 (simple-base-string (values buff start
(- end start
))))))
592 (defmethod socket-receive :before
((buffer array
)
593 (socket active-socket
)
595 (check-type start
(or unsigned-byte null
)
596 "a non-negative value or NIL")
597 (check-type end
(or unsigned-byte null
)
598 "a non-negative value or NIL"))
600 (defmethod socket-receive ((buffer array
)
601 (socket active-socket
) &key start end
602 out-of-band peek wait-all
603 dont-wait
(no-signal *no-sigpipe
*))
605 (let ((flags (logior (if out-of-band et
:msg-oob
0)
606 (if peek et
:msg-peek
0)
607 (if wait-all et
:msg-waitall
0)
608 (if dont-wait et
:msg-dontwait
0)
609 (if no-signal et
:msg-nosignal
0)))
612 (multiple-value-bind (buff start-offset bufflen
)
613 (normalize-receive-buffer buffer start end
)
614 (with-foreign-object (ss 'et
:sockaddr-storage
)
615 (et:bzero ss et
:size-of-sockaddr-storage
)
616 (with-foreign-pointer (size et
:size-of-socklen
)
617 (setf (mem-ref size
:socklen
)
618 et
:size-of-sockaddr-storage
)
619 (with-pointer-to-vector-data (buff-sap buff
)
620 (incf-pointer buff-sap start-offset
)
621 (with-socket-error-filter
623 (et:recvfrom
(socket-fd socket
)
628 (return-from socket-receive
629 ;; when socket is a datagram socket
630 ;; return the sender's address as 3rd value
631 (if (typep socket
'datagram-socket
)
632 (multiple-value-bind (remote-address remote-port
)
633 (sockaddr-storage->sockaddr ss
)
634 (values buffer bytes-received remote-address remote-port
))
635 (values buffer bytes-received
)))))))
637 (defmethod socket-receive (buffer (socket passive-socket
) &key
)
638 (error "You cannot receive data from a passive socket."))
642 ;; Only for datagram sockets
645 (defmethod unconnect :before
((socket active-socket
))
646 (unless (typep socket
'datagram-socket
)
647 (error "You can only unconnect active datagram sockets.")))
649 (defmethod unconnect ((socket datagram-socket
))
650 (with-socket-error-filter
651 (with-foreign-object (sin 'et
:sockaddr-in
)
652 (et:bzero sin et
:size-of-sockaddr-in
)
653 (setf (foreign-slot-value sin
'et
:sockaddr-in
'et
:addr
) et
:af-unspec
)
654 (et:connect
(socket-fd socket
) sin et
:size-of-sockaddr-in
))))