a342190969bd215b37a1efaa5f90d5d81f63e84b
[iolib.git] / src / sockets / socket-methods.lisp
bloba342190969bd215b37a1efaa5f90d5d81f63e84b
1 ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
2 ;;;
3 ;;; --- Various socket methods.
4 ;;;
6 (in-package :iolib.sockets)
8 ;;;-------------------------------------------------------------------------
9 ;;; Shared Initialization
10 ;;;-------------------------------------------------------------------------
12 (defun translate-make-socket-keywords-to-constants (address-family type protocol)
13 (let ((sf (ecase address-family
14 (:ipv4 af-inet)
15 (:ipv6 af-inet6)
16 (:local af-local)
17 (:netlink af-netlink)))
18 (st (ecase type
19 (:stream sock-stream)
20 (:datagram sock-dgram)
21 (:raw sock-raw)))
22 (sp (etypecase protocol
23 ((eql :default) 0)
24 (integer protocol))))
25 (values sf st sp)))
27 (defmethod socket-os-fd ((socket socket))
28 (fd-of socket))
30 (defmethod shared-initialize :after
31 ((socket socket) slot-names
32 &key file-descriptor (dup t) address-family type protocol)
33 (declare (ignore slot-names))
34 (with-accessors ((fd fd-of) (fam socket-address-family) (proto socket-protocol))
35 socket
36 (setf fd (or (and file-descriptor (if dup
37 (isys:dup file-descriptor)
38 file-descriptor))
39 (multiple-value-call #'%socket
40 (translate-make-socket-keywords-to-constants
41 address-family type protocol))))
42 (setf fam address-family
43 proto protocol)))
45 (defmethod (setf external-format-of) (external-format (socket passive-socket))
46 (setf (slot-value socket 'external-format)
47 (babel:ensure-external-format (or external-format :default))))
49 (defmethod shared-initialize :after ((socket passive-socket) slot-names
50 &key external-format
51 input-buffer-size output-buffer-size)
52 ;; Makes CREATE-SOCKET simpler
53 (declare (ignore slot-names input-buffer-size output-buffer-size))
54 (setf (external-format-of socket) (or external-format :default)))
57 ;;;-------------------------------------------------------------------------
58 ;;; Misc
59 ;;;-------------------------------------------------------------------------
61 (defmethod socket-type ((socket stream-socket))
62 :stream)
64 (defmethod socket-type ((socket datagram-socket))
65 :datagram)
67 (defun socket-ipv6-p (socket)
68 "Return T if SOCKET is an AF_INET6 socket."
69 (eql :ipv6 (socket-address-family socket)))
71 (defun ipv6-socket-p (&rest args)
72 (apply #'socket-ipv6-p args))
74 (defobsolete ipv6-socket-p socket-ipv6-p)
77 ;;;-------------------------------------------------------------------------
78 ;;; PRINT-OBJECT
79 ;;;-------------------------------------------------------------------------
81 (defun sock-fam (socket)
82 (ecase (socket-address-family socket)
83 (:ipv4 "IPv4")
84 (:ipv6 "IPv6")))
86 (defmethod print-object ((socket socket-stream-internet-active) stream)
87 (print-unreadable-object (socket stream :identity t)
88 (format stream "active ~A stream socket" (sock-fam socket))
89 (if (socket-connected-p socket)
90 (multiple-value-bind (host port) (remote-name socket)
91 (format stream " connected to ~A/~A"
92 (address-to-string host) port))
93 (format stream ", ~:[closed~;unconnected~]" (fd-of socket)))))
95 (defmethod print-object ((socket socket-stream-internet-passive) stream)
96 (print-unreadable-object (socket stream :identity t)
97 (format stream "passive ~A stream socket" (sock-fam socket))
98 (if (socket-bound-p socket)
99 (multiple-value-bind (host port) (local-name socket)
100 (format stream " ~:[bound to~;waiting @~] ~A/~A"
101 (socket-listening-p socket)
102 (address-to-string host) port))
103 (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
105 (defmethod print-object ((socket socket-stream-local-active) stream)
106 (print-unreadable-object (socket stream :identity t)
107 (format stream "active local stream socket")
108 (if (socket-connected-p socket)
109 (format stream " connected to ~S"
110 (address-to-string (remote-filename socket)))
111 (format stream ", ~:[closed~;unconnected~]" (fd-of socket)))))
113 (defmethod print-object ((socket socket-stream-local-passive) stream)
114 (print-unreadable-object (socket stream :identity t)
115 (format stream "passive local stream socket")
116 (if (socket-bound-p socket)
117 (format stream " ~:[bound to~;waiting @~] ~A"
118 (socket-listening-p socket)
119 (address-to-string (local-filename socket)))
120 (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
122 (defmethod print-object ((socket socket-datagram-local) stream)
123 (print-unreadable-object (socket stream :identity t)
124 (format stream "local datagram socket")
125 (if (socket-connected-p socket)
126 (format stream " connected to ~S"
127 (address-to-string (remote-filename socket)))
128 (if (fd-of socket)
129 (format stream " waiting @ ~S" (address-to-string (local-filename socket)))
130 (format stream ", closed" )))))
132 (defmethod print-object ((socket socket-datagram-internet) stream)
133 (print-unreadable-object (socket stream :identity t)
134 (format stream "~A datagram socket" (sock-fam socket))
135 (if (socket-connected-p socket)
136 (multiple-value-bind (host port) (remote-name socket)
137 (format stream " connected to ~A/~A"
138 (address-to-string host) port))
139 (if (fd-of socket)
140 (multiple-value-bind (host port) (local-name socket)
141 (format stream " waiting @ ~A/~A"
142 (address-to-string host) port))
143 (format stream ", closed" )))))
145 (defmethod print-object ((socket socket-raw-netlink) stream)
146 (print-unreadable-object (socket stream :identity t)
147 (format stream "netlink socket")
148 (if (socket-bound-p socket)
149 (multiple-value-bind (address port)
150 (local-name socket)
151 (format stream " bound to ~A@~A"
152 port (address-to-string address)))
153 (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
156 ;;;-------------------------------------------------------------------------
157 ;;; CLOSE
158 ;;;-------------------------------------------------------------------------
160 (defmethod close :before ((socket socket) &key abort)
161 (declare (ignore abort))
162 (setf (slot-value socket 'bound) nil))
164 (defmethod close ((socket socket) &key abort)
165 (declare (ignore abort))
166 (when (next-method-p)
167 (call-next-method))
168 (socket-open-p socket))
170 (defmethod close :before ((socket passive-socket) &key abort)
171 (declare (ignore abort))
172 (setf (slot-value socket 'listening) nil))
174 (defmethod socket-open-p ((socket socket))
175 (if (null (fd-of socket))
177 (with-sockaddr-storage-and-socklen (ss size)
178 (handler-case
179 (%getsockname (fd-of socket) ss size)
180 (isys:ebadf () nil)
181 (socket-connection-reset-error () nil)
182 (:no-error (_) (declare (ignore _)) t)))))
185 ;;;-------------------------------------------------------------------------
186 ;;; GETSOCKNAME
187 ;;;-------------------------------------------------------------------------
189 (defun %local-name (socket)
190 (with-sockaddr-storage-and-socklen (ss size)
191 (%getsockname (fd-of socket) ss size)
192 (sockaddr-storage->sockaddr ss)))
194 (defmethod local-name ((socket socket))
195 (%local-name socket))
197 (defmethod local-host ((socket internet-socket))
198 (nth-value 0 (%local-name socket)))
200 (defmethod local-port ((socket internet-socket))
201 (nth-value 1 (%local-name socket)))
203 (defmethod local-port ((socket netlink-socket))
204 (nth-value 1 (%local-name socket)))
206 (defmethod local-filename ((socket local-socket))
207 (%local-name socket))
210 ;;;-------------------------------------------------------------------------
211 ;;; GETPEERNAME
212 ;;;-------------------------------------------------------------------------
214 (defun %remote-name (socket)
215 (with-sockaddr-storage-and-socklen (ss size)
216 (%getpeername (fd-of socket) ss size)
217 (sockaddr-storage->sockaddr ss)))
219 (defmethod remote-name ((socket socket))
220 (%remote-name socket))
222 (defmethod remote-host ((socket internet-socket))
223 (nth-value 0 (%remote-name socket)))
225 (defmethod remote-port ((socket internet-socket))
226 (nth-value 1 (%remote-name socket)))
228 (defmethod remote-filename ((socket local-socket))
229 (%remote-name socket))
232 ;;;-------------------------------------------------------------------------
233 ;;; BIND
234 ;;;-------------------------------------------------------------------------
236 (defmethod bind-address :before ((socket internet-socket) address
237 &key (reuse-address t))
238 (declare (ignore address))
239 (when reuse-address
240 (setf (socket-option socket :reuse-address) t)))
242 (defun bind-ipv4-address (fd address port)
243 (with-sockaddr-in (sin address port)
244 (%bind fd sin (isys:sizeof 'sockaddr-in))))
246 (defun bind-ipv6-address (fd address port)
247 (with-sockaddr-in6 (sin6 address port)
248 (%bind fd sin6 (isys:sizeof 'sockaddr-in6))))
250 (defmethod bind-address ((socket internet-socket) (address ipv4-address)
251 &key (port 0))
252 (let ((port (ensure-numerical-service port)))
253 (if (socket-ipv6-p socket)
254 (bind-ipv6-address (fd-of socket)
255 (map-ipv4-vector-to-ipv6 (address-name address))
256 port)
257 (bind-ipv4-address (fd-of socket) (address-name address) port)))
258 (values socket))
260 (defmethod bind-address ((socket internet-socket) (address ipv6-address)
261 &key (port 0))
262 (bind-ipv6-address (fd-of socket)
263 (address-name address)
264 (ensure-numerical-service port))
265 (values socket))
267 (defmethod bind-address ((socket local-socket) (address local-address) &key)
268 (with-sockaddr-un (sun (address-name address) (abstract-address-p address))
269 (%bind (fd-of socket) sun (actual-size-of-sockaddr-un sun)))
270 (values socket))
272 (defmethod bind-address ((socket netlink-socket) (address netlink-address)
273 &key (port 0))
274 (with-sockaddr-nl (snl (netlink-address-multicast-groups address) port)
275 (%bind (fd-of socket) snl (isys:sizeof 'sockaddr-nl)))
276 (values socket))
278 (defmethod bind-address :after ((socket socket) (address address) &key)
279 (setf (slot-value socket 'bound) t))
282 ;;;-------------------------------------------------------------------------
283 ;;; LISTEN
284 ;;;-------------------------------------------------------------------------
286 (defmethod listen-on ((socket socket) &key backlog)
287 (unless backlog (setf backlog (min *default-backlog-size*
288 +max-backlog-size+)))
289 (check-type backlog unsigned-byte "a non-negative integer")
290 (%listen (fd-of socket) backlog)
291 (setf (slot-value socket 'listening) t)
292 (values socket))
295 ;;;-------------------------------------------------------------------------
296 ;;; ACCEPT
297 ;;;-------------------------------------------------------------------------
299 (defmethod accept-connection ((socket passive-socket) &key external-format
300 input-buffer-size output-buffer-size (wait t))
301 (check-type wait timeout-designator)
302 (flet ((make-client-socket (fd)
303 (make-instance (active-class socket)
304 :address-family (socket-address-family socket)
305 :file-descriptor fd :dup nil
306 :external-format (or external-format
307 (external-format-of socket))
308 :input-buffer-size input-buffer-size
309 :output-buffer-size output-buffer-size)))
310 (ignore-some-conditions (isys:ewouldblock iomux:poll-timeout)
311 (iomux:wait-until-fd-ready (fd-of socket) :input (wait->timeout wait) t)
312 (with-sockaddr-storage-and-socklen (ss size)
313 (multiple-value-call #'values
314 (make-client-socket (%accept (fd-of socket) ss size))
315 (sockaddr-storage->sockaddr ss))))))
318 ;;;-------------------------------------------------------------------------
319 ;;; CONNECT
320 ;;;-------------------------------------------------------------------------
322 (defun ipv4-connect (fd address port)
323 (with-sockaddr-in (sin address port)
324 (%connect fd sin (isys:sizeof 'sockaddr-in))))
326 (defun ipv6-connect (fd address port)
327 (with-sockaddr-in6 (sin6 address port)
328 (%connect fd sin6 (isys:sizeof 'sockaddr-in6))))
330 (defun call-with-socket-to-wait-connect (socket thunk wait)
331 (check-type wait timeout-designator)
332 (let ((timeout (wait->timeout wait)))
333 (flet
334 ((wait-connect ()
335 (when (or (null timeout)
336 (plusp timeout))
337 (handler-case
338 (iomux:wait-until-fd-ready (fd-of socket) :output timeout t)
339 (iomux:poll-error ()
340 (let ((errcode (socket-option socket :error)))
341 (if (zerop errcode)
342 (bug "Polling socket signalled an error but SO_ERROR is 0")
343 (signal-socket-error errcode "connect" (fd-of socket)))))))))
344 (ignore-some-conditions (iomux:poll-timeout)
345 (handler-case
346 (funcall thunk)
347 ((or isys:ewouldblock
348 isys:einprogress) ()
349 (wait-connect)))))))
351 (defmacro with-socket-to-wait-connect ((socket wait) &body body)
352 `(call-with-socket-to-wait-connect ,socket (lambda () ,@body) ,wait))
354 (defmethod connect ((socket internet-socket) (address inet-address)
355 &key (port 0) (wait t))
356 (let ((name (address-name address))
357 (port (ensure-numerical-service port)))
358 (with-socket-to-wait-connect (socket wait)
359 (cond
360 ((socket-ipv6-p socket)
361 (when (ipv4-address-p address)
362 (setf name (map-ipv4-vector-to-ipv6 name)))
363 (ipv6-connect (fd-of socket) name port))
364 (t (ipv4-connect (fd-of socket) name port)))))
365 (values socket))
367 (defmethod connect ((socket local-socket) (address local-address) &key (wait t))
368 (with-socket-to-wait-connect (socket wait)
369 (with-sockaddr-un (sun (address-name address) (abstract-address-p address))
370 (%connect (fd-of socket) sun (actual-size-of-sockaddr-un sun))))
371 (values socket))
373 (defmethod socket-connected-p ((socket socket))
374 (if (fd-of socket)
375 (with-sockaddr-storage-and-socklen (ss size)
376 (handler-case
377 (%getpeername (fd-of socket) ss size)
378 ((or isys:enotconn isys:einval) () nil)
379 (:no-error (_) (declare (ignore _)) t)))
380 nil))
383 ;;;-------------------------------------------------------------------------
384 ;;; DISCONNECT
385 ;;;-------------------------------------------------------------------------
387 (defmethod disconnect ((socket datagram-socket))
388 (with-foreign-object (sin 'sockaddr-in)
389 (isys:bzero sin (isys:sizeof 'sockaddr-in))
390 (setf (foreign-slot-value sin 'sockaddr-in 'addr) af-unspec)
391 (%connect (fd-of socket) sin (isys:sizeof 'sockaddr-in))
392 (values socket)))
395 ;;;-------------------------------------------------------------------------
396 ;;; SHUTDOWN
397 ;;;-------------------------------------------------------------------------
399 (defmethod shutdown ((socket socket) &key read write)
400 (assert (or read write) (read write)
401 "You must select at least one direction to shut down.")
402 (%shutdown (fd-of socket)
403 (multiple-value-case ((read write))
404 ((* nil) shut-rd)
405 ((nil *) shut-wr)
406 (t shut-rdwr)))
407 (values socket))
410 ;;;-------------------------------------------------------------------------
411 ;;; Socket flag definition
412 ;;;-------------------------------------------------------------------------
414 (defmacro define-socket-flag (place name value platform)
415 (let ((val (cond ((or (not platform)
416 (featurep platform)) value)
417 ((not (featurep platform)) 0))))
418 `(pushnew (cons ,name ,val) ,place)))
420 (defmacro define-socket-flags (place &body definitions)
421 (flet ((dflag (form)
422 (destructuring-bind (name value &optional platform) form
423 `(define-socket-flag ,place ,name ,value ,platform))))
424 `(progn
425 ,@(mapcar #'dflag definitions))))
428 ;;;-------------------------------------------------------------------------
429 ;;; SENDTO
430 ;;;-------------------------------------------------------------------------
432 (defvar *sendto-flags* ())
434 (define-socket-flags *sendto-flags*
435 (:dont-route msg-dontroute)
436 (:dont-wait msg-dontwait (:not :windows))
437 (:out-of-band msg-oob)
438 (:more msg-more :linux)
439 (:confirm msg-confirm :linux))
441 (defun %%send-to (fd ss got-peer buff-sap start length flags)
442 (incf-pointer buff-sap start)
443 (loop
444 (restart-case
445 (return*
446 (%sendto fd buff-sap length flags
447 (if got-peer ss (null-pointer))
448 (if got-peer (sockaddr-size ss) 0)))
449 (ignore-syscall-error ()
450 :report "Ignore this socket condition"
451 :test isys:syscall-error-p
452 (return* 0))
453 (retry-syscall (&optional (timeout 15.0d0))
454 :report "Try to send data again"
455 :test isys:syscall-error-p
456 (when (plusp timeout)
457 (iomux:wait-until-fd-ready fd :output timeout nil))))))
459 (defun %send-to (fd ss got-peer buffer start end flags)
460 (etypecase buffer
461 (ub8-sarray
462 (check-bounds buffer start end)
463 (with-pointer-to-vector-data (buff-sap buffer)
464 (%%send-to fd ss got-peer buff-sap start (- end start) flags)))
465 ((or ub8-vector (vector t))
466 (check-bounds buffer start end)
467 (with-pointer-to-vector-data (buff-sap (coerce buffer 'ub8-sarray))
468 (%%send-to fd ss got-peer buff-sap start (- end start) flags)))
469 (foreign-pointer
470 (check-type start unsigned-byte)
471 (check-type end unsigned-byte)
472 (%%send-to fd ss got-peer buffer start (- end start) flags))))
474 (defmethod send-to ((socket internet-socket) buffer &rest args
475 &key (start 0) end remote-host (remote-port 0) flags (ipv6 *ipv6*))
476 (let ((*ipv6* ipv6))
477 (with-sockaddr-storage (ss)
478 (when remote-host
479 (sockaddr->sockaddr-storage ss (ensure-hostname remote-host)
480 (ensure-numerical-service remote-port)))
481 (%send-to (fd-of socket) ss (if remote-host t) buffer start end
482 (or flags (compute-flags *sendto-flags* args))))))
484 (defmethod send-to ((socket local-socket) buffer &rest args
485 &key (start 0) end remote-filename flags)
486 (with-sockaddr-storage (ss)
487 (when remote-filename
488 (sockaddr->sockaddr-storage ss (ensure-address remote-filename :family :local) 0))
489 (%send-to (fd-of socket) ss (if remote-filename t) buffer start end
490 (or flags (compute-flags *sendto-flags* args)))))
492 (define-compiler-macro send-to (&whole form &environment env socket buffer &rest args
493 &key (start 0) end (remote-host nil host-p) (remote-port 0 port-p)
494 (remote-filename nil file-p) flags (ipv6 '*ipv6* ipv6-p) &allow-other-keys)
495 (let ((flags-val (compute-flags *sendto-flags* args env)))
496 (cond
497 ((and (not flags) flags-val)
498 (append
499 `(send-to ,socket ,buffer :start ,start :end ,end :flags ,flags-val)
500 (when host-p `(:remote-host ,remote-host))
501 (when port-p `(:remote-port ,remote-port))
502 (when ipv6-p `(:ipv6 ,ipv6))
503 (when file-p `(:remote-filename ,remote-filename))))
505 form))))
508 ;;;-------------------------------------------------------------------------
509 ;;; RECVFROM
510 ;;;-------------------------------------------------------------------------
512 (defvar *recvfrom-flags* ())
514 (define-socket-flags *recvfrom-flags*
515 (:out-of-band msg-oob)
516 (:peek msg-peek)
517 (:wait-all msg-waitall (:not :windows))
518 (:dont-wait msg-dontwait (:not :windows)))
520 (defun %%receive-from (fd ss size buffer start length flags)
521 (with-pointer-to-vector-data (buff-sap buffer)
522 (incf-pointer buff-sap start)
523 (loop
524 (restart-case
525 (return* (%recvfrom fd buff-sap length flags ss size))
526 (ignore-syscall-error ()
527 :report "Ignore this socket condition"
528 :test isys:syscall-error-p
529 (return* 0))
530 (retry-syscall (&optional (timeout 15.0d0))
531 :report "Try to receive data again"
532 :test isys:syscall-error-p
533 (when (plusp timeout)
534 (iomux:wait-until-fd-ready fd :input timeout nil)))))))
536 (defun %receive-from (fd ss size buffer start end flags)
537 (check-bounds buffer start end)
538 (flet ((%do-recvfrom (buff start length)
539 (%%receive-from fd ss size buff start length flags)))
540 (let (nbytes)
541 (etypecase buffer
542 (ub8-sarray
543 (setf nbytes (%do-recvfrom buffer start (- end start))))
544 ((or ub8-vector (vector t))
545 (let ((tmpbuff (make-array (- end start) :element-type 'ub8)))
546 (setf nbytes (%do-recvfrom tmpbuff 0 (- end start)))
547 (replace buffer tmpbuff :start1 start :end1 end :start2 0 :end2 nbytes))))
548 (values nbytes))))
550 (defmethod receive-from :around ((socket socket) &rest args
551 &key buffer size (start 0) end flags &allow-other-keys)
552 (let ((flags-val (or flags (compute-flags *recvfrom-flags* args))))
553 (cond
554 (buffer
555 (call-next-method socket :buffer buffer :start start :end end :flags flags-val))
557 (check-type size unsigned-byte "a non-negative integer")
558 (call-next-method socket :buffer (make-array size :element-type 'ub8)
559 :start 0 :end size :flags flags-val)))))
561 (defmethod receive-from ((socket stream-socket) &key buffer start end flags)
562 (with-sockaddr-storage-and-socklen (ss size)
563 (let ((nbytes (%receive-from (fd-of socket) ss size buffer start end flags)))
564 (values buffer nbytes))))
566 (defmethod receive-from ((socket datagram-socket) &key buffer start end flags)
567 (with-sockaddr-storage-and-socklen (ss size)
568 (let ((nbytes (%receive-from (fd-of socket) ss size buffer start end flags)))
569 (multiple-value-call #'values buffer nbytes
570 (sockaddr-storage->sockaddr ss)))))
572 (define-compiler-macro receive-from (&whole form &environment env socket &rest args
573 &key buffer size (start 0) end flags &allow-other-keys)
574 (let ((flags-val (compute-flags *recvfrom-flags* args env)))
575 (cond
576 ((and (not flags) flags-val)
577 `(receive-from ,socket :buffer ,buffer :start ,start :end ,end
578 :size ,size :flags ,flags-val))
580 form))))