1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Indent-tabs-mode: NIL -*-
3 ;;; socket-methods.lisp --- Various socket methods.
5 ;;; Copyright (C) 2006-2008, Stelian Ionescu <sionescu@common-lisp.net>
7 ;;; This code is free software; you can redistribute it and/or
8 ;;; modify it under the terms of the version 2.1 of
9 ;;; the GNU Lesser General Public License as published by
10 ;;; the Free Software Foundation, as clarified by the
11 ;;; preamble found here:
12 ;;; http://opensource.franz.com/preamble.html
14 ;;; This program is distributed in the hope that it will be useful,
15 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;;; GNU General Public License for more details.
19 ;;; You should have received a copy of the GNU Lesser General
20 ;;; Public License along with this library; if not, write to the
21 ;;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 ;;; Boston, MA 02110-1301, USA
24 (in-package :net.sockets
)
26 (defvar *socket-type-map
*
27 '(((:ipv4
:stream
:active
:default
) . socket-stream-internet-active
)
28 ((:ipv6
:stream
:active
:default
) . socket-stream-internet-active
)
29 ((:ipv4
:stream
:passive
:default
) . socket-stream-internet-passive
)
30 ((:ipv6
:stream
:passive
:default
) . socket-stream-internet-passive
)
31 ((:local
:stream
:active
:default
) . socket-stream-local-active
)
32 ((:local
:stream
:passive
:default
) . socket-stream-local-passive
)
33 ((:local
:datagram
:active
:default
) . socket-datagram-local-active
)
34 ((:ipv4
:datagram
:active
:default
) . socket-datagram-internet-active
)
35 ((:ipv6
:datagram
:active
:default
) . socket-datagram-internet-active
)))
37 ;;; FIXME: should match :default to whatever protocol is the default.
38 (defun select-socket-class (family type connect protocol
)
39 (or (cdr (assoc (list family type connect protocol
) *socket-type-map
*
41 (error "No socket class found !!")))
43 ;;;; Shared Initialization
45 (defun translate-make-socket-keywords-to-constants (family type protocol
)
46 (let ((sf (ecase family
52 (:datagram sock-dgram
)))
54 ((integerp protocol
) protocol
)
55 ((eq :default protocol
) 0)
56 (t (lookup-protocol protocol
)))))
59 (defmethod socket-os-fd ((socket socket
))
62 (defmethod initialize-instance :after
((socket socket
) &key
63 file-descriptor family type
65 (with-accessors ((fd fd-of
) (fam socket-family
) (proto socket-protocol
))
67 (setf fd
(or file-descriptor
68 (multiple-value-call #'%socket
69 (translate-make-socket-keywords-to-constants
70 family type protocol
))))
74 (defmethod (setf external-format-of
) (external-format (socket passive-socket
))
75 (setf (slot-value socket
'external-format
)
76 (babel:ensure-external-format external-format
)))
78 (defmethod initialize-instance :after
((socket passive-socket
)
80 (setf (external-format-of socket
) external-format
))
82 (defmethod socket-type ((socket stream-socket
))
85 (defmethod socket-type ((socket datagram-socket
))
90 (defun sock-fam (socket)
91 (ecase (socket-family socket
)
95 (defmethod print-object ((socket socket-stream-internet-active
) stream
)
96 (print-unreadable-object (socket stream
:identity t
)
97 (format stream
"active ~A stream socket" (sock-fam socket
))
98 (if (socket-connected-p socket
)
99 (multiple-value-bind (host port
) (remote-name socket
)
100 (format stream
" connected to ~A/~A"
101 (address-to-string host
) port
))
102 (format stream
", ~:[closed~;unconnected~]" (fd-of socket
)))))
104 (defmethod print-object ((socket socket-stream-internet-passive
) stream
)
105 (print-unreadable-object (socket stream
:identity t
)
106 (format stream
"passive ~A stream socket" (sock-fam socket
))
107 (if (socket-bound-p socket
)
108 (multiple-value-bind (host port
) (local-name socket
)
109 (format stream
" ~:[bound to~;waiting @~] ~A/~A"
110 (socket-listening-p socket
)
111 (address-to-string host
) port
))
112 (format stream
", ~:[closed~;unbound~]" (fd-of socket
)))))
114 (defmethod print-object ((socket socket-stream-local-active
) stream
)
115 (print-unreadable-object (socket stream
:identity t
)
116 (format stream
"active local stream socket")
117 (if (socket-connected-p socket
)
118 (format stream
" connected to ~S"
119 (address-to-string (remote-filename socket
)))
120 (format stream
", ~:[closed~;unconnected~]" (fd-of socket
)))))
122 (defmethod print-object ((socket socket-stream-local-passive
) stream
)
123 (print-unreadable-object (socket stream
:identity t
)
124 (format stream
"passive local stream socket")
125 (if (socket-bound-p socket
)
126 (format stream
" ~:[bound to~;waiting @~] ~S"
127 (socket-listening-p socket
)
128 (address-to-string (local-filename socket
)))
129 (format stream
", ~:[closed~;unbound~]" (fd-of socket
)))))
131 (defmethod print-object ((socket socket-datagram-local-active
) stream
)
132 (print-unreadable-object (socket stream
:identity t
)
133 (format stream
"local datagram socket")
134 (if (socket-connected-p socket
)
135 (format stream
" connected to ~S"
136 (address-to-string (remote-filename socket
)))
138 (format stream
" waiting @ ~S" (address-to-string (local-filename socket
)))
139 (format stream
", closed" )))))
141 (defmethod print-object ((socket socket-datagram-internet-active
) stream
)
142 (print-unreadable-object (socket stream
:identity t
)
143 (format stream
"~A datagram socket" (sock-fam socket
))
144 (if (socket-connected-p socket
)
145 (multiple-value-bind (host port
) (remote-name socket
)
146 (format stream
" connected to ~A/~A"
147 (address-to-string host
) port
))
149 (multiple-value-bind (host port
) (local-name socket
)
150 (format stream
" waiting @ ~A/~A"
151 (address-to-string host
) port
))
152 (format stream
", closed" )))))
156 (defmethod close :around
((socket socket
) &key abort
)
157 (declare (ignore abort
))
160 (nix:close
(fd-of socket
)))
161 (setf (fd-of socket
) nil
162 (slot-value socket
'bound
) nil
)
165 (defmethod close :around
((socket passive-socket
) &key abort
)
166 (declare (ignore abort
))
168 (setf (slot-value socket
'listening
) nil
)
171 (defmethod close ((socket socket
) &key abort
)
172 (declare (ignore socket abort
)))
174 (defmethod socket-open-p ((socket socket
))
176 (with-sockaddr-storage (ss)
177 (with-socklen (size size-of-sockaddr-storage
)
179 (%getsockname
(fd-of socket
) ss size
)
181 (nix:econnreset
() nil
)
182 (:no-error
(_) (declare (ignore _
)) t
))))))
186 (defun %local-name
(socket)
187 (with-sockaddr-storage (ss)
188 (with-socklen (size size-of-sockaddr-storage
)
189 (%getsockname
(fd-of socket
) ss size
)
190 (sockaddr-storage->sockaddr ss
))))
192 (defmethod local-name ((socket socket
))
193 (%local-name socket
))
195 (defmethod local-host ((socket internet-socket
))
196 (nth-value 0 (local-name socket
)))
198 (defmethod local-port ((socket internet-socket
))
199 (nth-value 1 (local-name socket
)))
201 (defmethod local-filename ((socket local-socket
))
202 (%local-name socket
))
206 (defun %remote-name
(socket)
207 (with-sockaddr-storage (ss)
208 (with-socklen (size size-of-sockaddr-storage
)
209 (%getpeername
(fd-of socket
) ss size
)
210 (sockaddr-storage->sockaddr ss
))))
212 (defmethod remote-name ((socket socket
))
213 (%remote-name socket
))
215 (defmethod remote-host ((socket internet-socket
))
216 (nth-value 0 (remote-name socket
)))
218 (defmethod remote-port ((socket internet-socket
))
219 (nth-value 1 (remote-name socket
)))
221 (defmethod remote-filename ((socket local-socket
))
222 (%remote-name socket
))
226 (defmethod bind-address :before
((socket internet-socket
) address
227 &key
(reuse-address t
))
228 (declare (ignore address
))
230 (setf (socket-option socket
:reuse-address
) t
)))
232 (defun bind-ipv4-address (fd address port
)
233 (with-sockaddr-in (sin address port
)
234 (%bind fd sin size-of-sockaddr-in
)))
236 (defun bind-ipv6-address (fd address port
)
237 (with-sockaddr-in6 (sin6 address port
)
238 (%bind fd sin6 size-of-sockaddr-in6
)))
240 (defmethod bind-address ((socket internet-socket
) (address ipv4-address
)
242 (if (eq :ipv6
(socket-family socket
))
243 (bind-ipv6-address (fd-of socket
)
244 (map-ipv4-vector-to-ipv6 (address-name address
))
246 (bind-ipv4-address (fd-of socket
) (address-name address
) port
))
249 (defmethod bind-address ((socket internet-socket
) (address ipv6-address
)
251 (bind-ipv6-address (fd-of socket
) (address-name address
) port
)
254 (defmethod bind-address ((socket local-socket
) (address local-address
) &key
)
255 (with-sockaddr-un (sun (address-name address
))
256 (%bind
(fd-of socket
) sun size-of-sockaddr-un
))
259 (defmethod bind-address :after
((socket socket
) (address address
) &key
)
260 (setf (slot-value socket
'bound
) t
))
264 (defmethod socket-listen ((socket passive-socket
) &key backlog
)
265 (unless backlog
(setf backlog
(min *default-backlog-size
*
266 +max-backlog-size
+)))
267 (check-type backlog unsigned-byte
"a non-negative integer")
268 (%listen
(fd-of socket
) backlog
)
269 (setf (slot-value socket
'listening
) t
)
272 (defmethod socket-listen ((socket active-socket
) &key
)
273 (error "You can't listen on active sockets."))
277 (defmethod accept-connection ((socket active-socket
) &key
)
278 (error "You can't accept connections on active sockets."))
280 (defmethod accept-connection ((socket passive-socket
) &key external-format
281 input-buffer-size output-buffer-size
)
282 (flet ((make-client-socket (fd)
283 (make-instance (active-class socket
)
285 :external-format
(or external-format
286 (external-format-of socket
))
287 :input-buffer-size input-buffer-size
288 :output-buffer-size output-buffer-size
)))
289 (with-sockaddr-storage (ss)
290 (with-socklen (size size-of-sockaddr-storage
)
292 (make-client-socket (%accept
(fd-of socket
) ss size
))
293 (nix:ewouldblock
()))))))
298 (defmethod connect :before
((socket active-socket
) sockaddr
&key
)
299 (declare (ignore sockaddr
))
300 (setf (socket-option socket
:no-sigpipe
) t
))
302 (defun ipv4-connect (fd address port
)
303 (with-sockaddr-in (sin address port
)
304 (%connect fd sin size-of-sockaddr-in
)))
306 (defun ipv6-connect (fd address port
)
307 (with-sockaddr-in6 (sin6 address port
)
308 (%connect fd sin6 size-of-sockaddr-in6
)))
310 (defmethod connect ((socket internet-socket
) (address ipv4-address
)
312 (if (eq :ipv6
(socket-family socket
))
313 (ipv6-connect (fd-of socket
)
314 (map-ipv4-vector-to-ipv6 (address-name address
))
316 (ipv4-connect (fd-of socket
) (address-name address
) port
))
319 (defmethod connect ((socket internet-socket
) (address ipv6-address
)
321 (ipv6-connect (fd-of socket
) (address-name address
) port
)
324 (defmethod connect ((socket local-socket
) (address local-address
) &key
)
325 (with-sockaddr-un (sun (address-name address
))
326 (%connect
(fd-of socket
) sun size-of-sockaddr-un
))
329 (defmethod connect ((socket passive-socket
) address
&key
)
330 (declare (ignore address
))
331 (error "You cannot connect passive sockets."))
333 (defmethod socket-connected-p ((socket socket
))
335 (with-sockaddr-storage (ss)
336 (with-socklen (size size-of-sockaddr-storage
)
338 (%getpeername
(fd-of socket
) ss size
)
339 (socket-not-connected-error () nil
)
340 (:no-error
(_) (declare (ignore _
)) t
))))))
344 (defmethod shutdown ((socket socket
) &key read write
)
345 (assert (or read write
) (read write
)
346 "You must select at least one direction to shut down.")
347 (%shutdown
(fd-of socket
)
348 (multiple-value-case (read write
)
356 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
357 (defun compute-flags (flags args
)
358 (loop :with flag-combination
:= 0
359 :for cons
:on args
:by
#'cddr
360 :for flag
:= (car cons
)
361 :for val
:= (cadr cons
)
362 :for const
:= (cdr (assoc flag flags
))
364 (when (not (constantp val
)) (return-from compute-flags
))
365 (setf flag-combination
(logior flag-combination const
))
366 :finally
(return flag-combination
)))
368 (defmacro define-socket-flag
(place name value platform
)
369 (let ((val (cond ((or (not platform
)
370 (featurep platform
)) value
)
371 ((not (featurep platform
)) 0))))
372 `(push (cons ,name
,val
) ,place
))))
374 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
375 (defparameter *sendmsg-flags
* nil
)
377 (defmacro define-sendmsg-flags
(&rest forms
)
379 (destructuring-bind (name value
&optional platform
) form
380 `(define-socket-flag *sendmsg-flags
* ,name
,value
,platform
))))
382 ,@(mapcar #'dflag forms
))))
384 (define-sendmsg-flags
385 (:dont-route msg-dontroute
)
386 (:dont-wait msg-dontwait
(:not
:windows
))
387 (:out-of-band msg-oob
)
388 (:more msg-more
:linux
)
389 (:confirm msg-confirm
:linux
)))
391 (defun %normalize-send-buffer
(buff start end ef
)
392 (check-bounds buff start end
)
394 (ub8-sarray (values buff start
(- end start
)))
395 (ub8-vector (values (coerce buff
'ub8-sarray
)
396 start
(- end start
)))
397 (string (values (%to-octets buff ef start end
)
399 (vector (values (coerce buff
'ub8-sarray
)
400 start
(- end start
)))))
402 (defun %send-to
(socket buffer start end remote-host remote-port remote-filename flags
)
404 (with-sockaddr-storage (ss)
407 (check-type socket internet-socket
"an INTERNET socket")
408 (sockaddr->sockaddr-storage ss
(ensure-hostname remote-host
)
409 (ensure-numerical-service remote-port
)))
411 (check-type socket local-socket
"an LOCAL socket")
412 (sockaddr->sockaddr-storage ss
(ensure-address remote-filename
:family
:local
) 0))
413 (t (setf got-peer nil
)))
414 (multiple-value-bind (buff start-offset bufflen
)
415 (%normalize-send-buffer buffer start end
(external-format-of socket
))
416 (with-pointer-to-vector-data (buff-sap buff
)
417 (incf-pointer buff-sap start-offset
)
418 (%sendto
(fd-of socket
) buff-sap bufflen flags
419 (if got-peer ss
(null-pointer))
420 (if got-peer size-of-sockaddr-storage
0)))))))
422 (defmethod send-to ((socket active-socket
) buffer
&rest args
423 &key
(start 0) end remote-host
(remote-port 0)
424 remote-filename
(ipv6 *ipv6
*))
426 (%send-to socket buffer start end remote-host remote-port
427 remote-filename
(compute-flags *sendmsg-flags
* args
))))
429 (define-compiler-macro send-to
(&whole form socket buffer
&rest args
430 &key
(start 0) end remote-host
(remote-port 0)
431 remote-filename
(ipv6 '*ipv6
* ipv6p
))
432 (let ((flags (compute-flags *sendmsg-flags
* args
)))
433 (cond (flags (if ipv6p
434 `(let ((*ipv6
* ,ipv6
))
435 (%send-to
,socket
,buffer
,start
,end
436 ,remote-host
,remote-port
,remote-filename
,flags
))
437 `(%send-to
,socket
,buffer
,start
,end
438 ,remote-host
,remote-port
,remote-filename
,flags
)))
443 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
444 (defparameter *recvfrom-flags
* nil
)
446 (defmacro define-recvfrom-flags
(&rest forms
)
448 (destructuring-bind (name value
&optional platform
) form
449 `(define-socket-flag *recvfrom-flags
* ,name
,value
,platform
))))
451 ,@(mapcar #'dflag forms
))))
453 (define-recvfrom-flags
454 (:out-of-band msg-oob
)
456 (:wait-all msg-waitall
(:not
:windows
))
457 (:dont-wait msg-dontwait
(:not
:windows
))))
459 (defun %normalize-receive-buffer
(buff start end
)
460 (check-bounds buff start end
)
462 (ub8-sarray (values buff start
(- end start
)))))
464 (defun %socket-receive-bytes
(fd buffer start end flags ss
)
465 (multiple-value-bind (buff start-offset bufflen
)
466 (%normalize-receive-buffer buffer start end
)
467 (with-socklen (size size-of-sockaddr-storage
)
468 (bzero ss size-of-sockaddr-storage
)
469 (with-pointer-to-vector-data (buff-sap buff
)
470 (incf-pointer buff-sap start-offset
)
471 (%recvfrom fd buff-sap bufflen flags ss size
)))))
473 (declaim (inline %receive-from-stream-socket
))
474 (defun %receive-from-stream-socket
(socket buffer start end flags
)
475 (with-sockaddr-storage (ss)
476 (let ((bytes-received (%socket-receive-bytes
(fd-of socket
) buffer
477 start end flags ss
)))
478 (values buffer bytes-received
))))
480 (declaim (inline %receive-from-datagram-socket
))
481 (defun %receive-from-datagram-socket
(socket buffer start end flags
)
482 (with-sockaddr-storage (ss)
483 (let ((bytes-received (%socket-receive-bytes
(fd-of socket
) buffer
484 start end flags ss
)))
485 (multiple-value-call #'values buffer bytes-received
486 (sockaddr-storage->sockaddr ss
)))))
488 (defun %receive-from
(socket buffer start end size flags
)
490 (check-type size unsigned-byte
"a non-negative integer")
491 (setf buffer
(make-array size
:element-type
'ub8
)
494 (stream-socket (%receive-from-stream-socket socket buffer start end flags
))
495 (datagram-socket (%receive-from-datagram-socket socket buffer start end flags
))))
497 (defmethod receive-from ((socket active-socket
) &rest args
498 &key buffer size
(start 0) end
)
499 (%receive-from socket buffer start end size
500 (compute-flags *recvfrom-flags
* args
)))
502 (define-compiler-macro receive-from
(&whole form socket
&rest args
503 &key buffer size
(start 0) end
)
504 (let ((flags (compute-flags *recvfrom-flags
* args
)))
505 (cond (flags `(%receive-from
,socket
,buffer
,start
,end
,size
,flags
))
508 ;;;; Datagram Sockets
510 (defmethod disconnect :before
((socket active-socket
))
511 (unless (typep socket
'datagram-socket
)
512 (error "You can only disconnect active datagram sockets.")))
514 (defmethod disconnect ((socket datagram-socket
))
515 (with-foreign-object (sin 'sockaddr-in
)
516 (bzero sin size-of-sockaddr-in
)
517 (setf (foreign-slot-value sin
'sockaddr-in
'addr
) af-unspec
)
518 (%connect
(fd-of socket
) sin size-of-sockaddr-in
)))