Change arglist of SHUTDOWN from (SOCKET DIRECTION) to (SOCKET &KEY READ WRITE).
[iolib.git] / net.sockets / socket-methods.lisp
blobf3d5b9f24d7d9a85d4f2ed39989ef28c1e36ee27
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Indent-tabs-mode: NIL -*-
2 ;;;
3 ;;; socket-methods.lisp --- Various socket methods.
4 ;;;
5 ;;; Copyright (C) 2006-2008, Stelian Ionescu <sionescu@common-lisp.net>
6 ;;;
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
13 ;;;
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.
18 ;;;
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*
40 :test #'equal))
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
47 (:ipv4 af-inet)
48 (:ipv6 af-inet6)
49 (:local af-local)))
50 (st (ecase type
51 (:stream sock-stream)
52 (:datagram sock-dgram)))
53 (sp (cond
54 ((integerp protocol) protocol)
55 ((eq protocol :default) 0)
56 (t (lookup-protocol protocol)))))
57 (values sf st sp)))
59 (defmethod socket-fd ((socket socket))
60 (fd-of socket))
62 (defmethod (setf socket-fd) (fd (socket socket))
63 (setf (fd-of socket) fd))
65 (defmethod initialize-instance :after ((socket socket) &key
66 file-descriptor family type
67 (protocol :default))
68 (with-accessors ((fd fd-of) (fam socket-family) (proto socket-protocol))
69 socket
70 (setf fd (or file-descriptor
71 (multiple-value-call #'%socket
72 (translate-make-socket-keywords-to-constants
73 family type protocol))))
74 (setf fam family
75 proto protocol)))
77 (defmethod (setf external-format-of) (external-format (socket passive-socket))
78 (setf (slot-value socket 'external-format)
79 (babel:ensure-external-format external-format)))
81 (defmethod initialize-instance :after ((socket passive-socket)
82 &key external-format)
83 (setf (external-format-of socket) external-format))
85 (defmethod socket-type ((socket stream-socket))
86 :stream)
88 (defmethod socket-type ((socket datagram-socket))
89 :datagram)
91 ;;;; Printing
93 (defun sock-fam (socket)
94 (ecase (socket-family socket)
95 (:ipv4 "IPv4")
96 (:ipv6 "IPv6")))
98 (defmethod print-object ((socket socket-stream-internet-active) stream)
99 (print-unreadable-object (socket stream :identity t)
100 (format stream "active ~A stream socket" (sock-fam socket))
101 (if (socket-connected-p socket)
102 (multiple-value-bind (addr port) (remote-name socket)
103 (format stream " connected to ~A/~A"
104 (address-to-string addr) port))
105 (format stream ", ~:[closed~;unconnected~]" (fd-of socket)))))
107 (defmethod print-object ((socket socket-stream-internet-passive) stream)
108 (print-unreadable-object (socket stream :identity t)
109 (format stream "passive ~A stream socket" (sock-fam socket))
110 (if (socket-bound-p socket)
111 (multiple-value-bind (addr port) (local-name socket)
112 (format stream " ~:[bound to~;waiting @~] ~A/~A"
113 (socket-listening-p socket)
114 (address-to-string addr) port))
115 (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
117 (defmethod print-object ((socket socket-stream-local-active) stream)
118 (print-unreadable-object (socket stream :identity t)
119 (format stream "active local stream socket")
120 (if (socket-connected-p socket)
121 (format stream " connected to ~S"
122 (address-to-string (remote-address socket)))
123 (format stream ", ~:[closed~;unconnected~]" (fd-of socket)))))
125 (defmethod print-object ((socket socket-stream-local-passive) stream)
126 (print-unreadable-object (socket stream :identity t)
127 (format stream "passive local stream socket")
128 (if (socket-bound-p socket)
129 (format stream " ~:[bound to~;waiting @~] ~S"
130 (socket-listening-p socket)
131 (address-to-string (local-address socket)))
132 (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
134 (defmethod print-object ((socket socket-datagram-local-active) stream)
135 (print-unreadable-object (socket stream :identity t)
136 (format stream "local datagram socket")
137 (if (socket-connected-p socket)
138 (format stream " connected to ~S"
139 (address-to-string (remote-address socket)))
140 (if (fd-of socket)
141 (format stream " waiting @ ~S" (address-to-string (local-address socket)))
142 (format stream ", closed" )))))
144 (defmethod print-object ((socket socket-datagram-internet-active) stream)
145 (print-unreadable-object (socket stream :identity t)
146 (format stream "~A datagram socket" (sock-fam socket))
147 (if (socket-connected-p socket)
148 (multiple-value-bind (addr port) (remote-name socket)
149 (format stream " connected to ~A/~A"
150 (address-to-string addr) port))
151 (if (fd-of socket)
152 (multiple-value-bind (addr port) (local-name socket)
153 (format stream " waiting @ ~A/~A"
154 (address-to-string addr) port))
155 (format stream ", closed" )))))
157 ;;;; CLOSE
159 (defmethod close :around ((socket socket) &key abort)
160 (declare (ignore abort))
161 (call-next-method)
162 (when (fd-of socket)
163 (nix:close (fd-of socket)))
164 (setf (fd-of socket) nil
165 (slot-value socket 'bound) nil)
166 (values socket))
168 (defmethod close :around ((socket passive-socket) &key abort)
169 (declare (ignore abort))
170 (call-next-method)
171 (setf (slot-value socket 'listening) nil)
172 (values socket))
174 (defmethod close ((socket socket) &key abort)
175 (declare (ignore socket abort)))
177 (defmethod socket-open-p ((socket socket))
178 (when (fd-of socket)
179 (with-sockaddr-storage (ss)
180 (with-socklen (size size-of-sockaddr-storage)
181 (handler-case
182 (%getsockname (fd-of socket) ss size)
183 (nix:ebadf () nil)
184 (nix:econnreset () nil)
185 (:no-error (_) (declare (ignore _)) t))))))
187 ;;;; GETSOCKNAME
189 (defmethod local-name ((socket socket))
190 (with-sockaddr-storage (ss)
191 (with-socklen (size size-of-sockaddr-storage)
192 (%getsockname (fd-of socket) ss size)
193 (sockaddr-storage->sockaddr ss))))
195 (defmethod local-address ((socket socket))
196 (nth-value 0 (local-name socket)))
198 (defmethod local-port ((socket internet-socket))
199 (nth-value 1 (local-name socket)))
201 ;;;; GETPEERNAME
203 (defmethod remote-name ((socket socket))
204 (with-sockaddr-storage (ss)
205 (with-socklen (size size-of-sockaddr-storage)
206 (%getpeername (fd-of socket) ss size)
207 (sockaddr-storage->sockaddr ss))))
209 (defmethod remote-address ((socket socket))
210 (nth-value 0 (remote-name socket)))
212 (defmethod remote-port ((socket internet-socket))
213 (nth-value 1 (remote-name socket)))
215 ;;;; BIND
217 (defmethod bind-address :before ((socket internet-socket) address
218 &key (reuse-address t))
219 (declare (ignore address))
220 (when reuse-address
221 (setf (socket-option socket :reuse-address) t)))
223 (defun bind-ipv4-address (fd address port)
224 (with-sockaddr-in (sin address port)
225 (%bind fd sin size-of-sockaddr-in)))
227 (defun bind-ipv6-address (fd address port)
228 (with-sockaddr-in6 (sin6 address port)
229 (%bind fd sin6 size-of-sockaddr-in6)))
231 (defmethod bind-address ((socket internet-socket) (address ipv4-address)
232 &key (port 0))
233 (if (eq (socket-family socket) :ipv6)
234 (bind-ipv6-address (fd-of socket)
235 (map-ipv4-vector-to-ipv6 (address-name address))
236 port)
237 (bind-ipv4-address (fd-of socket) (address-name address) port))
238 (values socket))
240 (defmethod bind-address ((socket internet-socket) (address ipv6-address)
241 &key (port 0))
242 (bind-ipv6-address (fd-of socket) (address-name address) port)
243 (values socket))
245 (defmethod bind-address ((socket local-socket) (address local-address) &key)
246 (with-sockaddr-un (sun (address-name address))
247 (%bind (fd-of socket) sun size-of-sockaddr-un))
248 (values socket))
250 (defmethod bind-address :after ((socket socket) (address address) &key)
251 (setf (slot-value socket 'bound) t))
253 ;;;; LISTEN
255 (defmethod socket-listen ((socket passive-socket) &key backlog)
256 (unless backlog (setf backlog (min *default-backlog-size*
257 +max-backlog-size+)))
258 (check-type backlog unsigned-byte "a non-negative integer")
259 (%listen (fd-of socket) backlog)
260 (setf (slot-value socket 'listening) t)
261 (values socket))
263 (defmethod socket-listen ((socket active-socket) &key)
264 (error "You can't listen on active sockets."))
266 ;;;; ACCEPT
268 (defmethod accept-connection ((socket active-socket) &key)
269 (error "You can't accept connections on active sockets."))
271 (defmethod accept-connection ((socket passive-socket) &key external-format
272 input-buffer-size output-buffer-size)
273 (flet ((make-client-socket (fd)
274 (make-instance (active-class socket)
275 :file-descriptor fd
276 :external-format (or external-format
277 (external-format-of socket))
278 :input-buffer-size input-buffer-size
279 :output-buffer-size output-buffer-size)))
280 (with-sockaddr-storage (ss)
281 (with-socklen (size size-of-sockaddr-storage)
282 (handler-case
283 (make-client-socket (%accept (fd-of socket) ss size))
284 (nix:ewouldblock ()))))))
286 ;;;; CONNECT
288 #+freebsd
289 (defmethod connect :before ((socket active-socket) sockaddr &key)
290 (declare (ignore sockaddr))
291 (setf (socket-option socket :no-sigpipe) t))
293 (defun ipv4-connect (fd address port)
294 (with-sockaddr-in (sin address port)
295 (%connect fd sin size-of-sockaddr-in)))
297 (defun ipv6-connect (fd address port)
298 (with-sockaddr-in6 (sin6 address port)
299 (%connect fd sin6 size-of-sockaddr-in6)))
301 (defmethod connect ((socket internet-socket) (address ipv4-address)
302 &key (port 0))
303 (if (eq (socket-family socket) :ipv6)
304 (ipv6-connect (fd-of socket)
305 (map-ipv4-vector-to-ipv6 (address-name address))
306 port)
307 (ipv4-connect (fd-of socket) (address-name address) port))
308 (values socket))
310 (defmethod connect ((socket internet-socket) (address ipv6-address)
311 &key (port 0))
312 (ipv6-connect (fd-of socket) (address-name address) port)
313 (values socket))
315 (defmethod connect ((socket local-socket) (address local-address) &key)
316 (with-sockaddr-un (sun (address-name address))
317 (%connect (fd-of socket) sun size-of-sockaddr-un))
318 (values socket))
320 (defmethod connect ((socket passive-socket) address &key)
321 (declare (ignore address))
322 (error "You cannot connect passive sockets."))
324 (defmethod socket-connected-p ((socket socket))
325 (when (fd-of socket)
326 (with-sockaddr-storage (ss)
327 (with-socklen (size size-of-sockaddr-storage)
328 (handler-case
329 (%getpeername (fd-of socket) ss size)
330 (socket-not-connected-error () nil)
331 (:no-error (_) (declare (ignore _)) t))))))
333 ;;;; SHUTDOWN
335 (defmethod shutdown ((socket active-socket) &key read write)
336 (assert (or read write) (read write)
337 "You must select at least one direction to shut down.")
338 (%shutdown (fd-of socket)
339 (multiple-value-case (read write)
340 ((_ nil) shut-rd)
341 ((nil _) shut-wr)
342 (t shut-rdwr)))
343 (values socket))
345 (defmethod shutdown ((socket passive-socket) &key)
346 (error "You cannot shut down passive sockets."))
348 ;;;; SENDTO
350 (eval-when (:compile-toplevel :load-toplevel :execute)
351 (defun compute-flags (flags args)
352 (loop :with flag-combination := 0
353 :for cons :on args :by #'cddr
354 :for flag := (car cons)
355 :for val := (cadr cons)
356 :for const := (cdr (assoc flag flags))
357 :when const :do
358 (when (not (constantp val)) (return-from compute-flags))
359 (setf flag-combination (logior flag-combination const))
360 :finally (return flag-combination)))
362 (defmacro define-socket-flag (place name value platform)
363 (let ((val (cond ((or (not platform)
364 (featurep platform)) value)
365 ((not (featurep platform)) 0))))
366 `(push (cons ,name ,val) ,place))))
368 (eval-when (:compile-toplevel :load-toplevel :execute)
369 (defparameter *sendmsg-flags* nil)
371 (defmacro define-sendmsg-flags (&rest forms)
372 (flet ((dflag (form)
373 (destructuring-bind (name value &optional platform) form
374 `(define-socket-flag *sendmsg-flags* ,name ,value ,platform))))
375 `(progn
376 ,@(mapcar #'dflag forms))))
378 (define-sendmsg-flags
379 (:end-of-record msg-eor (:not :windows))
380 (:dont-route msg-dontroute)
381 (:dont-wait msg-dontwait (:not :windows))
382 (:no-signal msg-nosignal (:not (:or :darwin :windows)))
383 (:out-of-band msg-oob)
384 (:more msg-more :linux)
385 (:confirm msg-confirm :linux)))
387 (defun %normalize-send-buffer (buff start end ef)
388 (check-bounds buff start end)
389 (etypecase buff
390 (ub8-sarray (values buff start (- end start)))
391 (ub8-vector (values (coerce buff 'ub8-sarray)
392 start (- end start)))
393 (string (values (%to-octets buff ef start end)
394 0 (- end start)))
395 (vector (values (coerce buff 'ub8-sarray)
396 start (- end start)))))
398 (defun %send-to (socket buffer start end remote-address remote-port flags)
399 (when (typep socket 'passive-socket)
400 (error "You cannot send data on a passive socket."))
401 (when remote-address (setf remote-address (convert-or-lookup-inet-address remote-address)))
402 (when remote-port (setf remote-port (ensure-numerical-service remote-port)))
403 (when (and (ipv4-address-p remote-address)
404 (eq (socket-family socket) :ipv6))
405 (setf remote-address (map-ipv4-address-to-ipv6 remote-address)))
406 (multiple-value-bind (buff start-offset bufflen)
407 (%normalize-send-buffer buffer start end (external-format-of socket))
408 (with-sockaddr-storage (ss)
409 (when remote-address
410 (sockaddr->sockaddr-storage ss remote-address remote-port))
411 (with-pointer-to-vector-data (buff-sap buff)
412 (incf-pointer buff-sap start-offset)
413 (%sendto (fd-of socket) buff-sap bufflen flags
414 (if remote-address ss (null-pointer))
415 (if remote-address size-of-sockaddr-storage 0))))))
417 (defmethod send-to ((socket active-socket) buffer &rest args
418 &key (start 0) end remote-address (remote-port 0) (ipv6 *ipv6*))
419 (let ((*ipv6* ipv6))
420 (%send-to socket buffer start end remote-address remote-port
421 (compute-flags *sendmsg-flags* args))))
423 (define-compiler-macro send-to (&whole form socket buffer &rest args
424 &key (start 0) end remote-address (remote-port 0)
425 (ipv6 '*ipv6* ipv6p))
426 (let ((flags (compute-flags *sendmsg-flags* args)))
427 (cond (flags (if ipv6p
428 `(let ((*ipv6* ,ipv6))
429 (%send-to ,socket ,buffer ,start ,end
430 ,remote-address ,remote-port ,flags))
431 `(%send-to ,socket ,buffer ,start ,end
432 ,remote-address ,remote-port ,flags)))
433 (t form))))
435 ;;;; RECVFROM
437 (eval-when (:compile-toplevel :load-toplevel :execute)
438 (defparameter *recvfrom-flags* nil)
440 (defmacro define-recvfrom-flags (&rest forms)
441 (flet ((dflag (form)
442 (destructuring-bind (name value &optional platform) form
443 `(define-socket-flag *recvfrom-flags* ,name ,value ,platform))))
444 `(progn
445 ,@(mapcar #'dflag forms))))
447 (define-recvfrom-flags
448 (:out-of-band msg-oob)
449 (:peek msg-peek)
450 (:wait-all msg-waitall (:not :windows))
451 (:dont-wait msg-dontwait (:not :windows))
452 (:no-signal msg-nosignal (:not (:or :darwin :windows)))))
454 (defun %normalize-receive-buffer (buff start end)
455 (check-bounds buff start end)
456 (etypecase buff
457 (ub8-sarray (values buff start (- end start)))))
459 (defun %socket-receive-bytes (fd buffer start end flags ss)
460 (multiple-value-bind (buff start-offset bufflen)
461 (%normalize-receive-buffer buffer start end)
462 (with-socklen (size size-of-sockaddr-storage)
463 (bzero ss size-of-sockaddr-storage)
464 (with-pointer-to-vector-data (buff-sap buff)
465 (incf-pointer buff-sap start-offset)
466 (%recvfrom fd buff-sap bufflen flags ss size)))))
468 (declaim (inline %receive-from-stream-socket))
469 (defun %receive-from-stream-socket (socket buffer start end flags)
470 (with-sockaddr-storage (ss)
471 (let ((bytes-received (%socket-receive-bytes (fd-of socket) buffer
472 start end flags ss)))
473 (values buffer bytes-received))))
475 (declaim (inline %receive-from-datagram-socket))
476 (defun %receive-from-datagram-socket (socket buffer start end flags)
477 (with-sockaddr-storage (ss)
478 (let ((bytes-received (%socket-receive-bytes (fd-of socket) buffer
479 start end flags ss)))
480 (multiple-value-bind (remote-address remote-port)
481 (sockaddr-storage->sockaddr ss)
482 (values buffer bytes-received remote-address remote-port)))))
484 (defun %receive-from (socket buffer start end size flags)
485 (when (typep socket 'passive-socket)
486 (error "You cannot receive data from a passive socket."))
487 (unless buffer
488 (check-type size unsigned-byte "a non-negative integer")
489 (setf buffer (make-array size :element-type 'ub8)
490 start 0 end size))
491 (etypecase socket
492 (stream-socket (%receive-from-stream-socket socket buffer start end flags))
493 (datagram-socket (%receive-from-datagram-socket socket buffer start end flags))))
495 (defmethod receive-from ((socket active-socket) &rest args
496 &key buffer size (start 0) end)
497 (%receive-from socket buffer start end size
498 (compute-flags *recvfrom-flags* args)))
500 (define-compiler-macro receive-from (&whole form socket &rest args
501 &key buffer size (start 0) end)
502 (let ((flags (compute-flags *recvfrom-flags* args)))
503 (cond (flags `(%receive-from ,socket ,buffer ,start ,end ,size ,flags))
504 (t form))))
506 ;;;; Datagram Sockets
508 (defmethod disconnect :before ((socket active-socket))
509 (unless (typep socket 'datagram-socket)
510 (error "You can only disconnect active datagram sockets.")))
512 (defmethod disconnect ((socket datagram-socket))
513 (with-foreign-object (sin 'sockaddr-in)
514 (bzero sin size-of-sockaddr-in)
515 (setf (foreign-slot-value sin 'sockaddr-in 'addr) af-unspec)
516 (%connect (fd-of socket) sin size-of-sockaddr-in)))