LOOKUP-SERVICE now returns 3 values: port, name and protocol.
[iolib.git] / sockets / conditions.lisp
blob486fa3e1b9d71b0f4da56c4014a39e0567b0bf6b
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Indent-tabs-mode: NIL -*-
2 ;;;
3 ;;; conditions.lisp --- Conditions.
4 ;;;
5 ;;; Copyright (C) 2006-2007, 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 (defgeneric error-code (err))
28 (defmethod error-code ((err system-error))
29 (osicat-sys:system-error-code err))
31 (defgeneric error-identifier (err))
33 (defmethod error-identifier ((err system-error))
34 (osicat-sys:system-error-identifier err))
36 (defgeneric error-message (err))
38 (defmethod error-message ((err system-error))
39 (osicat-sys:system-error-message err))
41 (defun print-message-if-not-null (condition stream
42 &optional (eof-place :before))
43 (declare (type stream stream))
44 (let ((msg (error-message condition)))
45 (when msg
46 (when (eql eof-place :before)
47 (fresh-line stream))
48 (format stream "~A" msg)
49 (when (eql eof-place :after)
50 (fresh-line stream)))))
52 ;;;; Socket Errors
54 (defvar *socket-error-map* nil)
56 (define-condition socket-error (nix:posix-error) ())
58 (defmethod print-object ((socket-error socket-error) stream)
59 (print-unreadable-object (socket-error stream :type t :identity nil)
60 (let ((code (osicat-sys:system-error-code socket-error)))
61 (format stream "~S ~S ~S"
62 (or code "[No code]")
63 (osicat-sys:system-error-identifier socket-error)
64 (or (nix:strerror code)
65 "[Can't get error string.]")))))
67 (defmacro define-socket-error (name identifier &optional documentation)
68 `(progn
69 (push (cons ,identifier ',name) *socket-error-map*)
70 (define-condition ,name (socket-error) ()
71 (:default-initargs :code ,(foreign-enum-value 'socket-error-values
72 identifier)
73 :identifier ,identifier)
74 (:documentation ,(or documentation "")))))
76 (define-condition unknown-socket-error (socket-error)
78 (:documentation "Error signalled upon finding an unknown error."))
80 (defun lookup-socket-error (keyword)
81 (or (cdr (assoc keyword *socket-error-map*))
82 (make-instance 'unknown-socket-error :identifier keyword
83 :code (foreign-enum-value 'socket-error-values keyword))))
85 (define-socket-error socket-invalid-argument :einval)
86 (define-socket-error socket-address-in-use-error :eaddrinuse)
87 (define-socket-error socket-address-not-available-error :eaddrnotavail)
88 (define-socket-error socket-network-down-error :enetdown)
89 (define-socket-error socket-network-reset-error :enetreset)
90 (define-socket-error socket-network-unreachable-error :enetunreach)
91 (define-socket-error socket-no-network-error :enonet)
92 (define-socket-error socket-connection-aborted-error :econnaborted)
93 (define-socket-error socket-connection-reset-error :econnreset)
94 (define-socket-error socket-connection-refused-error :econnrefused)
95 (define-socket-error socket-endpoint-shutdown-error :eshutdown)
96 (define-socket-error socket-connection-timeout-error :etimedout)
97 (define-socket-error socket-no-buffer-space-error :enobufs)
98 (define-socket-error socket-host-down-error :ehostdown)
99 (define-socket-error socket-host-unreachable-error :ehostunreach)
100 (define-socket-error socket-already-connected-error :eisconn)
101 (define-socket-error socket-not-connected-error :enotconn)
102 (define-socket-error socket-option-not-supported-error :enoprotoopt)
103 (define-socket-error socket-operation-not-supported-error :eopnotsupp)
105 ;;; For regular POSIX functions that return extra errors when handling
106 ;;; sockets. Eg.: CLOSE and OPEN. But maybe we should simply define
107 ;;; our own bindings for those functions at some point in order to
108 ;;; ditch the CL-POSIX dependency? (especially if we at some point use
109 ;;; HANDLEs instead of FDs on windows)
110 (defmacro with-socket-error-filter (&body body)
111 `(handler-case
112 (progn ,@body)
113 (nix:posix-error (err)
114 (let* ((id (error-identifier err))
115 (condition (cdr (assoc id *socket-error-map*))))
116 (if condition
117 (error condition)
118 (error err))))))
120 ;;; Used in the ERRNO-WRAPPER foreign type.
121 (defun signal-socket-error (return-value)
122 (declare (ignore return-value))
123 (let ((errno (nix:get-errno)))
124 (let ((kw (foreign-enum-keyword 'socket-error-values errno :errorp nil)))
125 (if kw
126 (error (lookup-socket-error kw))
127 ;; this branch is probably mostly unused now. Should
128 ;; probably sinal an UNKOWN-SOCKET-ERROR here instead.
129 (nix:posix-error errno)))))
131 (define-condition resolver-error ()
132 ((data :initarg :data :reader resolver-error-data))
133 (:documentation
134 "Signaled when an error occurs while trying to resolve an address."))
136 (defmacro define-resolver-error (name code identifier format-string
137 &optional documentation)
138 `(define-condition ,name (resolver-error) ()
139 (:report (lambda (condition stream)
140 (format stream ,format-string (resolver-error-data condition))))
141 (:documentation ,documentation)))
143 (define-resolver-error resolver-again-error (resolver-error-code :eai-again)
144 :resolver-again
145 "Temporary failure occurred while resolving: ~S"
146 "Condition signaled when a temporary failure occurred.")
148 (define-resolver-error resolver-fail-error (resolver-error-code :eai-fail)
149 :resolver-fail
150 "Non recoverable error occurred while resolving: ~S"
151 "Condition signaled when a non-recoverable error occurred.")
153 (define-resolver-error resolver-no-name-error (resolver-error-code :eai-noname)
154 :resolver-no-name
155 "Host or service not found: ~S"
156 "Condition signaled when a host or service was not found.")
158 (define-resolver-error resolver-unknown-error 0 :resolver-unknown
159 "Unknown error while resolving: ~S"
160 "Condition signaled when an unknown error is signaled while resolving
161 an address.")