Small cosmetic fix in CLOSE for PASSIVE-SOCKETs.
[iolib.git] / sockets / socket-methods.lisp
blob6c5856d18389c4ef18f2b90a8689a40b498bc2a4
1 ;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*-
3 ;; Copyright (C) 2006, 2007 Stelian Ionescu
4 ;;
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 (defvar *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*
37 :test #'equal))
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
47 (:ipv4 et:af-inet)
48 (:ipv6 et:af-inet6)
49 (:local et:af-local)))
50 (st (ecase type
51 (:stream et:sock-stream)
52 (:datagram et:sock-dgram)))
53 (sp (cond
54 ((integerp protocol) protocol)
55 ((eql protocol :default) 0)
56 ((keywordp protocol)
57 (protocol-number
58 (get-protocol-by-name (string-downcase
59 (string protocol))))))))
60 (values sf st sp)))
62 (defmethod socket-fd ((socket socket))
63 (fd-of socket))
64 (defmethod (setf socket-fd) (fd (socket socket))
65 (setf (fd-of socket) fd))
67 (defmethod shared-initialize :after ((socket socket) slot-names
68 &key file-descriptor family
69 type (protocol :default))
70 (declare (ignore slot-names))
71 (when (socket-open-p socket)
72 (close socket))
73 (with-accessors ((fd fd-of)
74 (fam socket-family)
75 (proto socket-protocol)) socket
76 (setf fd (or file-descriptor
77 (multiple-value-bind (sf st sp)
78 (translate-make-socket-keywords-to-constants family type protocol)
79 (with-socket-error-filter
80 (et:socket sf st sp)))))
81 (setf fam family
82 proto protocol)))
84 (defmethod socket-type ((socket stream-socket))
85 :stream)
87 (defmethod socket-type ((socket datagram-socket))
88 :datagram)
91 ;;;;;;;;;;;;;;;;;;;;
92 ;; PRINT-OBJECT ;;
93 ;;;;;;;;;;;;;;;;;;;;
95 (defun sock-fam (socket)
96 (ecase (socket-family socket)
97 (:ipv4 "IPv4")
98 (:ipv6 "IPv6")))
100 (defmethod print-object ((socket socket-stream-internet-active) stream)
101 (print-unreadable-object (socket stream :type nil :identity t)
102 (format stream "active ~A stream socket" (sock-fam socket))
103 (if (socket-connected-p socket)
104 (multiple-value-bind (addr port) (remote-name socket)
105 (format stream " connected to ~A/~A"
106 (sockaddr->presentation addr) port))
107 (if (fd-of socket)
108 (format stream ", unconnected")
109 (format stream ", closed")))))
111 (defmethod print-object ((socket socket-stream-internet-passive) stream)
112 (print-unreadable-object (socket stream :type nil :identity t)
113 (format stream "passive ~A stream socket" (sock-fam socket))
114 (if (socket-bound-p socket)
115 (multiple-value-bind (addr port) (local-name socket)
116 (format stream " ~A ~A/~A"
117 (if (socket-listening-p socket)
118 "waiting for connections @"
119 "bound to")
120 (sockaddr->presentation addr) port))
121 (if (fd-of socket)
122 (format stream ", unbound")
123 (format stream ", closed")))))
125 (defmethod print-object ((socket socket-stream-local-active) stream)
126 (print-unreadable-object (socket stream :type nil :identity t)
127 (format stream "active local stream socket")
128 (if (socket-connected-p socket)
129 (format stream " connected")
130 (if (fd-of socket)
131 (format stream ", unconnected")
132 (format stream ", closed")))))
134 (defmethod print-object ((socket socket-stream-local-passive) stream)
135 (print-unreadable-object (socket stream :type nil :identity t)
136 (format stream "passive local stream socket")
137 (if (socket-bound-p socket)
138 (format stream " ~A ~A"
139 (if (socket-listening-p socket)
140 "waiting for connections @"
141 "bound to")
142 (sockaddr->presentation (socket-address socket)))
143 (if (fd-of socket)
144 (format stream ", unbound")
145 (format stream ", closed")))))
147 (defmethod print-object ((socket socket-datagram-local-active) stream)
148 (print-unreadable-object (socket stream :type nil :identity t)
149 (format stream "local datagram socket")
150 (if (socket-connected-p socket)
151 (format stream " connected")
152 (if (fd-of socket)
153 (format stream ", unconnected")
154 (format stream ", closed")))))
156 (defmethod print-object ((socket socket-datagram-internet-active) stream)
157 (print-unreadable-object (socket stream :type nil :identity t)
158 (format stream "~A datagram socket" (sock-fam socket))
159 (if (socket-connected-p socket)
160 (multiple-value-bind (addr port) (remote-name socket)
161 (format stream " connected to ~A/~A"
162 (sockaddr->presentation addr) port))
163 (if (fd-of socket)
164 (format stream ", unconnected")
165 (format stream ", closed")))))
168 ;;;;;;;;;;;;;
169 ;; CLOSE ;;
170 ;;;;;;;;;;;;;
172 (defmethod close :around ((socket socket) &key abort)
173 (declare (ignore abort))
174 (when (fd-of socket)
175 (with-socket-error-filter
176 (et:close (fd-of socket))))
177 (setf (fd-of socket) nil)
178 (call-next-method)
179 (values socket))
181 (defmethod close :around ((socket passive-socket) &key abort)
182 (declare (ignore abort))
183 (call-next-method)
184 (setf (slot-value socket 'bound) nil
185 (slot-value socket 'listening) nil)
186 (values socket))
188 (defmethod close ((socket socket) &key abort)
189 (declare (ignore socket abort)))
191 (defmethod socket-open-p ((socket socket))
192 (unless (fd-of socket)
193 (return-from socket-open-p nil))
194 (with-socket-error-filter
195 (handler-case
196 (with-foreign-object (ss 'et:sockaddr-storage)
197 (et:bzero ss et:size-of-sockaddr-storage)
198 (with-foreign-pointer (size et:size-of-socklen)
199 (setf (mem-ref size 'et:socklen)
200 et:size-of-sockaddr-storage)
201 (et:getsockname (fd-of socket) ss size)
203 (et:ebadf ())
204 #+freebsd (et:econnreset ()))))
207 ;;;;;;;;;;;;;;;;;;;
208 ;; GETSOCKNAME ;;
209 ;;;;;;;;;;;;;;;;;;;
211 (defmethod local-name ((socket internet-socket))
212 (with-foreign-object (ss 'et:sockaddr-storage)
213 (et:bzero ss et:size-of-sockaddr-storage)
214 (with-foreign-pointer (size et:size-of-socklen)
215 (setf (mem-ref size 'et:socklen)
216 et:size-of-sockaddr-storage)
217 (with-socket-error-filter
218 (et:getsockname (fd-of socket) ss size))
219 (return-from local-name
220 (sockaddr-storage->sockaddr ss)))))
222 (defmethod local-name ((socket local-socket))
223 (with-foreign-object (sun 'et:sockaddr-un)
224 (et:bzero sun et:size-of-sockaddr-un)
225 (with-foreign-pointer (size et:size-of-socklen)
226 (setf (mem-ref size 'et:socklen)
227 et:size-of-sockaddr-storage)
228 (with-socket-error-filter
229 (et:getsockname (fd-of socket) sun size))
230 (return-from local-name
231 (sockaddr-un->sockaddr sun)))))
233 (defmethod socket-address ((socket socket))
234 (nth-value 0 (local-name socket)))
236 (defmethod socket-port ((socket internet-socket))
237 (nth-value 1 (local-name socket)))
240 ;;;;;;;;;;;;;;;;;;;
241 ;; GETPEERNAME ;;
242 ;;;;;;;;;;;;;;;;;;;
244 (defmethod remote-name ((socket internet-socket))
245 (with-foreign-object (ss 'et:sockaddr-storage)
246 (et:bzero ss et:size-of-sockaddr-storage)
247 (with-foreign-pointer (size et:size-of-socklen)
248 (setf (mem-ref size 'et:socklen)
249 et:size-of-sockaddr-storage)
250 (with-socket-error-filter
251 (et:getpeername (fd-of socket) ss size))
252 (return-from remote-name
253 (sockaddr-storage->sockaddr ss)))))
255 (defmethod remote-name ((socket local-socket))
256 (with-foreign-object (sun 'et:sockaddr-un)
257 (et:bzero sun et:size-of-sockaddr-un)
258 (with-foreign-pointer (size et:size-of-socklen)
259 (setf (mem-ref size 'et:socklen)
260 et:size-of-sockaddr-storage)
261 (with-socket-error-filter
262 (et:getpeername (fd-of socket) sun size))
263 (return-from remote-name
264 (sockaddr-un->sockaddr sun)))))
267 ;;;;;;;;;;;;
268 ;; BIND ;;
269 ;;;;;;;;;;;;
271 (defmethod bind-address :before ((socket internet-socket)
272 address &key (reuse-address t))
273 (declare (ignore address))
274 (when reuse-address
275 (set-socket-option socket :reuse-address :value t)))
277 (defun bind-ipv4-address (fd address port)
278 (with-foreign-object (sin 'et:sockaddr-in)
279 (make-sockaddr-in sin address port)
280 (with-socket-error-filter
281 (et:bind fd sin et:size-of-sockaddr-in))))
283 (defun bind-ipv6-address (fd address port)
284 (with-foreign-object (sin6 'et:sockaddr-in6)
285 (make-sockaddr-in6 sin6 address port)
286 (with-socket-error-filter
287 (et:bind fd sin6 et:size-of-sockaddr-in6))))
289 (defmethod bind-address ((socket internet-socket)
290 (address ipv4addr)
291 &key (port 0))
292 (if (eql (socket-family socket) :ipv6)
293 (bind-ipv6-address (fd-of socket)
294 (map-ipv4-vector-to-ipv6 (name address))
295 port)
296 (bind-ipv4-address (fd-of socket) (name address) port))
297 (values socket))
299 (defmethod bind-address ((socket internet-socket)
300 (address ipv6addr)
301 &key (port 0))
302 (bind-ipv6-address (fd-of socket) (name address) port)
303 (values socket))
305 (defmethod bind-address :before ((socket local-socket)
306 (address localaddr) &key)
307 (when (typep socket 'active-socket)
308 (error "You can't bind an active Unix socket.")))
310 (defmethod bind-address ((socket local-socket)
311 (address localaddr) &key)
312 (with-foreign-object (sun 'et:sockaddr-un)
313 (make-sockaddr-un sun (name address))
314 (with-socket-error-filter
315 (et:bind (fd-of socket) sun et:size-of-sockaddr-un)))
316 (values socket))
318 (defmethod bind-address :after ((socket socket)
319 (address sockaddr) &key)
320 (setf (slot-value socket 'bound) t))
323 ;;;;;;;;;;;;;;
324 ;; LISTEN ;;
325 ;;;;;;;;;;;;;;
327 (defmethod socket-listen ((socket passive-socket)
328 &key (backlog (min *default-backlog-size*
329 +max-backlog-size+)))
330 (unless backlog (setf backlog (min *default-backlog-size*
331 +max-backlog-size+)))
332 (check-type backlog unsigned-byte "a non-negative integer")
333 (with-socket-error-filter
334 (et:listen (fd-of socket) backlog))
335 (setf (slot-value socket 'listening) t)
336 (values socket))
338 (defmethod socket-listen ((socket active-socket)
339 &key backlog)
340 (declare (ignore backlog))
341 (error "You can't listen on active sockets."))
344 ;;;;;;;;;;;;;;
345 ;; ACCEPT ;;
346 ;;;;;;;;;;;;;;
348 (defmethod accept-connection ((socket active-socket)
349 &key wait)
350 (declare (ignore wait))
351 (error "You can't accept connections on active sockets."))
353 (defmethod accept-connection ((socket passive-socket)
354 &key (wait t))
355 (with-foreign-object (ss 'et:sockaddr-storage)
356 (et:bzero ss et:size-of-sockaddr-storage)
357 (with-foreign-pointer (size et:size-of-socklen)
358 (setf (mem-ref size 'et:socklen)
359 et:size-of-sockaddr-storage)
360 (let (non-blocking-state
361 client-fd)
362 (with-socket-error-filter
363 (handler-case
364 (if wait
365 ;; do a "normal" accept
366 ;; Note: the socket may already be in non-blocking mode
367 (setf client-fd (et:accept (fd-of socket) ss size))
368 ;; set the socket to non-blocking mode before calling accept()
369 ;; if there's no new connection return NIL
370 (unwind-protect
371 (progn
372 ;; saving the current non-blocking state
373 (setf non-blocking-state (fd-non-blocking socket))
374 ;; switch the socket to non-blocking mode
375 (setf (fd-non-blocking socket) t)
376 (setf client-fd (et:accept (fd-of socket) ss size)))
377 ;; restoring the socket's non-blocking state
378 (setf (fd-non-blocking socket) non-blocking-state)))
379 ;; the socket is marked non-blocking and there's no new connection
380 (et:ewouldblock ()
381 (return-from accept-connection nil))))
383 (let ((client-socket
384 ;; create the client socket object
385 (make-instance (active-class socket)
386 :file-descriptor client-fd)))
387 (return-from accept-connection client-socket))))))
390 ;;;;;;;;;;;;;;;
391 ;; CONNECT ;;
392 ;;;;;;;;;;;;;;;
394 #+freebsd
395 (defmethod connect :before ((socket active-socket)
396 sockaddr &key)
397 (declare (ignore sockaddr))
398 (when *no-sigpipe*
399 (set-socket-option socket :no-sigpipe :value t)))
401 (defun ipv4-connect (fd address port)
402 (with-foreign-object (sin 'et:sockaddr-in)
403 (make-sockaddr-in sin address port)
404 (with-socket-error-filter
405 (et:connect fd sin et:size-of-sockaddr-in))))
407 (defun ipv6-connect (fd address port)
408 (with-foreign-object (sin6 'et:sockaddr-in6)
409 (make-sockaddr-in6 sin6 address port)
410 (with-socket-error-filter
411 (et:connect fd sin6 et:size-of-sockaddr-in6))))
413 (defmethod connect ((socket internet-socket)
414 (address ipv4addr) &key (port 0))
415 (if (eql (socket-family socket) :ipv6)
416 (ipv6-connect (fd-of socket)
417 (map-ipv4-vector-to-ipv6 (name address))
418 port)
419 (ipv4-connect (fd-of socket) (name address) port))
420 (values socket))
422 (defmethod connect ((socket internet-socket)
423 (address ipv6addr) &key (port 0))
424 (ipv6-connect (fd-of socket) (name address) port)
425 (values socket))
427 (defmethod connect ((socket local-socket)
428 (address localaddr) &key)
429 (with-foreign-object (sun 'et:sockaddr-un)
430 (make-sockaddr-un sun (name address))
431 (with-socket-error-filter
432 (et:connect (fd-of socket) sun et:size-of-sockaddr-un)))
433 (values socket))
435 (defmethod connect ((socket passive-socket)
436 address &key)
437 (declare (ignore address))
438 (error "You cannot connect passive sockets."))
440 (defmethod socket-connected-p ((socket socket))
441 (unless (fd-of socket)
442 (return-from socket-connected-p nil))
443 (with-socket-error-filter
444 (handler-case
445 (with-foreign-object (ss 'et:sockaddr-storage)
446 (et:bzero ss et:size-of-sockaddr-storage)
447 (with-foreign-pointer (size et:size-of-socklen)
448 (setf (mem-ref size 'et:socklen)
449 et:size-of-sockaddr-storage)
450 (et:getpeername (fd-of socket) ss size)
452 (et:enotconn () nil))))
455 ;;;;;;;;;;;;;;;;
456 ;; SHUTDOWN ;;
457 ;;;;;;;;;;;;;;;;
459 (defmethod shutdown ((socket active-socket) direction)
460 (check-type direction (member :read :write :read-write)
461 "valid direction specifier")
462 (with-socket-error-filter
463 (et:shutdown (fd-of socket)
464 (ecase direction
465 (:read et:shut-rd)
466 (:write et:shut-wr)
467 (:read-write et:shut-rdwr))))
468 (values socket))
470 (defmethod shutdown ((socket passive-socket) direction)
471 (declare (ignore direction))
472 (error "You cannot shut down passive sockets."))
475 ;;;;;;;;;;;;
476 ;; SEND ;;
477 ;;;;;;;;;;;;
479 (defun %normalize-send-buffer (buff start end ef)
480 (setf (values start end) (%check-bounds buff start end))
481 (etypecase buff
482 (ub8-sarray (values buff start (- end start)))
483 (ub8-vector (values (coerce buff 'ub8-sarray)
484 start (- end start)))
485 (string (values (%to-octets buff ef start end)
486 0 (- end start)))))
488 (defmethod socket-send ((buffer array)
489 (socket active-socket) &key (start 0) end
490 remote-address remote-port end-of-record
491 dont-route dont-wait (no-signal *no-sigpipe*)
492 out-of-band #+linux more #+linux confirm)
493 (check-type start unsigned-byte
494 "a non-negative unsigned integer")
495 (check-type end (or unsigned-byte null)
496 "a non-negative unsigned integer or NIL")
497 (when (or remote-port remote-address)
498 (check-type remote-address sockaddr "a network address")
499 (check-type remote-port (unsigned-byte 16) "a valid IP port number"))
500 (let ((flags (logior (if end-of-record et:msg-eor 0)
501 (if dont-route et:msg-dontroute 0)
502 (if dont-wait et:msg-dontwait 0)
503 (if no-signal et:msg-nosignal 0)
504 (if out-of-band et:msg-oob 0)
505 #+linux (if more et:msg-more 0)
506 #+linux (if confirm et:msg-confirm 0))))
507 (when (and (ipv4-address-p remote-address)
508 (eql (socket-family socket) :ipv6))
509 (setf remote-address (map-ipv4-address->ipv6 remote-address)))
510 (multiple-value-bind (buff start-offset bufflen)
511 (%normalize-send-buffer buffer start end (external-format-of socket))
512 (with-foreign-object (ss 'et:sockaddr-storage)
513 (et:bzero ss et:size-of-sockaddr-storage)
514 (when remote-address
515 (sockaddr->sockaddr-storage ss remote-address remote-port))
516 (with-pointer-to-vector-data (buff-sap buff)
517 (incf-pointer buff-sap start-offset)
518 (with-socket-error-filter
519 (return-from socket-send
520 (et:sendto (fd-of socket)
521 buff-sap bufflen
522 flags
523 (if remote-address ss (null-pointer))
524 (if remote-address et:size-of-sockaddr-storage 0)))))))))
526 (defmethod socket-send (buffer (socket passive-socket) &key)
527 (declare (ignore buffer))
528 (error "You cannot send data on a passive socket."))
531 ;;;;;;;;;;;;
532 ;; RECV ;;
533 ;;;;;;;;;;;;
535 (defun %normalize-receive-buffer (buff start end)
536 (setf (values start end) (%check-bounds buff start end))
537 (etypecase buff
538 ((simple-array ub8 (*)) (values buff start (- end start)))))
540 (defmethod socket-receive ((buffer array)
541 (socket active-socket) &key (start 0) end
542 out-of-band peek wait-all
543 dont-wait (no-signal *no-sigpipe*))
544 (let ((flags (logior (if out-of-band et:msg-oob 0)
545 (if peek et:msg-peek 0)
546 (if wait-all et:msg-waitall 0)
547 (if dont-wait et:msg-dontwait 0)
548 (if no-signal et:msg-nosignal 0)))
549 bytes-received)
550 (multiple-value-bind (buff start-offset bufflen)
551 (%normalize-receive-buffer buffer start end)
552 (with-foreign-object (ss 'et:sockaddr-storage)
553 (et:bzero ss et:size-of-sockaddr-storage)
554 (with-foreign-pointer (size et:size-of-socklen)
555 (setf (mem-ref size 'et:socklen)
556 et:size-of-sockaddr-storage)
557 (with-pointer-to-vector-data (buff-sap buff)
558 (incf-pointer buff-sap start-offset)
559 (with-socket-error-filter
560 (setf bytes-received
561 (et:recvfrom (fd-of socket)
562 buff-sap bufflen
563 flags
564 ss size)))))
566 (return-from socket-receive
567 ;; when socket is a datagram socket
568 ;; return the sender's address as 3rd value
569 (if (typep socket 'datagram-socket)
570 (multiple-value-bind (remote-address remote-port)
571 (sockaddr-storage->sockaddr ss)
572 (values buffer bytes-received remote-address remote-port))
573 (values buffer bytes-received)))))))
575 (defmethod socket-receive (buffer (socket passive-socket) &key)
576 (declare (ignore buffer))
577 (error "You cannot receive data from a passive socket."))
581 ;; Only for datagram sockets
584 (defmethod unconnect :before ((socket active-socket))
585 (unless (typep socket 'datagram-socket)
586 (error "You can only unconnect active datagram sockets.")))
588 (defmethod unconnect ((socket datagram-socket))
589 (with-socket-error-filter
590 (with-foreign-object (sin 'et:sockaddr-in)
591 (et:bzero sin et:size-of-sockaddr-in)
592 (setf (foreign-slot-value sin 'et:sockaddr-in 'et:addr) et:af-unspec)
593 (et:connect (fd-of socket) sin et:size-of-sockaddr-in))))