A few changes.
[iolib.git] / net.sockets / socket-methods.lisp
blobcadeec62cb3cce614bf740bba99d0b9d9ce0e411
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 :default protocol) 0)
56 (t (lookup-protocol protocol)))))
57 (values sf st sp)))
59 (defmethod socket-os-fd ((socket socket))
60 (fd-of socket))
62 (defmethod initialize-instance :after ((socket socket) &key
63 file-descriptor family type
64 (protocol :default))
65 (with-accessors ((fd fd-of) (fam socket-family) (proto socket-protocol))
66 socket
67 (setf fd (or file-descriptor
68 (multiple-value-call #'%socket
69 (translate-make-socket-keywords-to-constants
70 family type protocol))))
71 (setf fam family
72 proto 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)
79 &key external-format)
80 (setf (external-format-of socket) external-format))
82 (defmethod socket-type ((socket stream-socket))
83 :stream)
85 (defmethod socket-type ((socket datagram-socket))
86 :datagram)
88 ;;;; Printing
90 (defun sock-fam (socket)
91 (ecase (socket-family socket)
92 (:ipv4 "IPv4")
93 (:ipv6 "IPv6")))
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)))
137 (if (fd-of 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))
148 (if (fd-of socket)
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" )))))
154 ;;;; CLOSE
156 (defmethod close :around ((socket socket) &key abort)
157 (declare (ignore abort))
158 (call-next-method)
159 (when (fd-of socket)
160 (nix:close (fd-of socket)))
161 (setf (fd-of socket) nil
162 (slot-value socket 'bound) nil)
163 (values socket))
165 (defmethod close :around ((socket passive-socket) &key abort)
166 (declare (ignore abort))
167 (call-next-method)
168 (setf (slot-value socket 'listening) nil)
169 (values socket))
171 (defmethod close ((socket socket) &key abort)
172 (declare (ignore socket abort)))
174 (defmethod socket-open-p ((socket socket))
175 (when (fd-of socket)
176 (with-sockaddr-storage (ss)
177 (with-socklen (size size-of-sockaddr-storage)
178 (handler-case
179 (%getsockname (fd-of socket) ss size)
180 (nix:ebadf () nil)
181 (nix:econnreset () nil)
182 (:no-error (_) (declare (ignore _)) t))))))
184 ;;;; GETSOCKNAME
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))
204 ;;;; GETPEERNAME
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))
224 ;;;; BIND
226 (defmethod bind-address :before ((socket internet-socket) address
227 &key (reuse-address t))
228 (declare (ignore address))
229 (when reuse-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)
241 &key (port 0))
242 (if (eq :ipv6 (socket-family socket))
243 (bind-ipv6-address (fd-of socket)
244 (map-ipv4-vector-to-ipv6 (address-name address))
245 port)
246 (bind-ipv4-address (fd-of socket) (address-name address) port))
247 (values socket))
249 (defmethod bind-address ((socket internet-socket) (address ipv6-address)
250 &key (port 0))
251 (bind-ipv6-address (fd-of socket) (address-name address) port)
252 (values socket))
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))
257 (values socket))
259 (defmethod bind-address :after ((socket socket) (address address) &key)
260 (setf (slot-value socket 'bound) t))
262 ;;;; LISTEN
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)
270 (values socket))
272 (defmethod socket-listen ((socket active-socket) &key)
273 (error "You can't listen on active sockets."))
275 ;;;; ACCEPT
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)
284 :file-descriptor fd
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)
291 (handler-case
292 (make-client-socket (%accept (fd-of socket) ss size))
293 (nix:ewouldblock ()))))))
295 ;;;; CONNECT
297 #+freebsd
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)
311 &key (port 0))
312 (if (eq :ipv6 (socket-family socket))
313 (ipv6-connect (fd-of socket)
314 (map-ipv4-vector-to-ipv6 (address-name address))
315 port)
316 (ipv4-connect (fd-of socket) (address-name address) port))
317 (values socket))
319 (defmethod connect ((socket internet-socket) (address ipv6-address)
320 &key (port 0))
321 (ipv6-connect (fd-of socket) (address-name address) port)
322 (values socket))
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))
327 (values socket))
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))
334 (when (fd-of socket)
335 (with-sockaddr-storage (ss)
336 (with-socklen (size size-of-sockaddr-storage)
337 (handler-case
338 (%getpeername (fd-of socket) ss size)
339 (socket-not-connected-error () nil)
340 (:no-error (_) (declare (ignore _)) t))))))
342 ;;;; SHUTDOWN
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)
349 ((_ nil) shut-rd)
350 ((nil _) shut-wr)
351 (t shut-rdwr)))
352 (values socket))
354 ;;;; SENDTO
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))
363 :when const :do
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)
378 (flet ((dflag (form)
379 (destructuring-bind (name value &optional platform) form
380 `(define-socket-flag *sendmsg-flags* ,name ,value ,platform))))
381 `(progn
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)
393 (etypecase buff
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)
398 0 (- end start)))
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)
403 (let ((got-peer t))
404 (with-sockaddr-storage (ss)
405 (cond
406 (remote-host
407 (check-type socket internet-socket "an INTERNET socket")
408 (sockaddr->sockaddr-storage ss (ensure-hostname remote-host)
409 (ensure-numerical-service remote-port)))
410 (remote-filename
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*))
425 (let ((*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)))
439 (t form))))
441 ;;;; RECVFROM
443 (eval-when (:compile-toplevel :load-toplevel :execute)
444 (defparameter *recvfrom-flags* nil)
446 (defmacro define-recvfrom-flags (&rest forms)
447 (flet ((dflag (form)
448 (destructuring-bind (name value &optional platform) form
449 `(define-socket-flag *recvfrom-flags* ,name ,value ,platform))))
450 `(progn
451 ,@(mapcar #'dflag forms))))
453 (define-recvfrom-flags
454 (:out-of-band msg-oob)
455 (:peek msg-peek)
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)
461 (etypecase buff
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)
489 (unless buffer
490 (check-type size unsigned-byte "a non-negative integer")
491 (setf buffer (make-array size :element-type 'ub8)
492 start 0 end size))
493 (etypecase socket
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))
506 (t form))))
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)))