tcondition.lisp - clic - Clic is an command line interactive client for gopher written in Common LISP (HTM) git clone git://bitreich.org/clic/ git://hg6vgqziawt5s4dj.onion/clic/ (DIR) Log (DIR) Files (DIR) Refs (DIR) Tags (DIR) LICENSE --- tcondition.lisp (8435B) --- 1 ;;;; See LICENSE for licensing information. 2 3 (in-package :usocket) 4 5 ;; Condition signalled by operations with unsupported arguments 6 ;; For trivial-sockets compatibility. 7 8 (define-condition insufficient-implementation (error) 9 ((feature :initarg :feature :reader feature) 10 (context :initarg :context :reader context 11 :documentation "String designator of the public API function which 12 the feature belongs to.")) 13 (:documentation "The ancestor of all errors usocket may generate 14 because of insufficient support from the underlying implementation 15 with respect to the arguments given to `function'. 16 17 One call may signal several errors, if the caller allows processing 18 to continue. 19 ")) 20 21 (define-condition unsupported (insufficient-implementation) 22 ((minimum :initarg :minimum :reader minimum 23 :documentation "Indicates the minimal version of the 24 implementation required to support the requested feature.")) 25 (:report (lambda (c stream) 26 (format stream "~A in ~A is unsupported." 27 (feature c) (context c)) 28 (when (minimum c) 29 (format stream " Minimum version (~A) is required." 30 (minimum c))))) 31 (:documentation "Signalled when the underlying implementation 32 doesn't allow supporting the requested feature. 33 34 When you see this error, go bug your vendor/implementation developer!")) 35 36 (define-condition unimplemented (insufficient-implementation) 37 () 38 (:report (lambda (c stream) 39 (format stream "~A in ~A is unimplemented." 40 (feature c) (context c)))) 41 (:documentation "Signalled if a certain feature might be implemented, 42 based on the features of the underlying implementation, but hasn't 43 been implemented yet.")) 44 45 ;; Conditions raised by sockets operations 46 47 (define-condition socket-condition (condition) 48 ((socket :initarg :socket 49 :accessor usocket-socket)) 50 ;;###FIXME: no slots (yet); should at least be the affected usocket... 51 (:documentation "Parent condition for all socket related conditions.")) 52 53 (define-condition socket-error (socket-condition error) 54 () ;; no slots (yet) 55 (:documentation "Parent error for all socket related errors")) 56 57 (define-condition ns-condition (condition) 58 ((host-or-ip :initarg :host-or-ip 59 :accessor host-or-ip)) 60 (:documentation "Parent condition for all name resolution conditions.")) 61 62 (define-condition ns-error (ns-condition error) 63 () 64 (:documentation "Parent error for all name resolution errors.")) 65 66 (eval-when (:compile-toplevel :load-toplevel :execute) 67 (defun define-usocket-condition-class (class &rest parents) 68 `(progn 69 (define-condition ,class ,parents ()) 70 (export ',class)))) 71 72 (defmacro define-usocket-condition-classes (class-list parents) 73 `(progn ,@(mapcar #'(lambda (x) 74 (apply #'define-usocket-condition-class 75 x parents)) 76 class-list))) 77 78 ;; Mass define and export our conditions 79 (define-usocket-condition-classes 80 (interrupted-condition) 81 (socket-condition)) 82 83 (define-condition unknown-condition (socket-condition) 84 ((real-condition :initarg :real-condition 85 :accessor usocket-real-condition)) 86 (:documentation "Condition raised when there's no other - more applicable - 87 condition available.")) 88 89 90 ;; Mass define and export our errors 91 (define-usocket-condition-classes 92 (address-in-use-error 93 address-not-available-error 94 bad-file-descriptor-error 95 connection-refused-error 96 connection-aborted-error 97 connection-reset-error 98 invalid-argument-error 99 no-buffers-error 100 operation-not-supported-error 101 operation-not-permitted-error 102 protocol-not-supported-error 103 socket-type-not-supported-error 104 network-unreachable-error 105 network-down-error 106 network-reset-error 107 host-down-error 108 host-unreachable-error 109 shutdown-error 110 timeout-error 111 deadline-timeout-error 112 invalid-socket-error 113 invalid-socket-stream-error) 114 (socket-error)) 115 116 (define-condition unknown-error (socket-error) 117 ((real-error :initarg :real-error 118 :accessor usocket-real-error 119 :initform nil) 120 (errno :initarg :errno 121 :reader usocket-errno 122 :initform 0)) 123 (:report (lambda (c stream) 124 (typecase c 125 (simple-condition 126 (format stream 127 (simple-condition-format-control (usocket-real-error c)) 128 (simple-condition-format-arguments (usocket-real-error c)))) 129 (otherwise 130 (format stream "The condition ~A occurred with errno: ~D." 131 (usocket-real-error c) 132 (usocket-errno c)))))) 133 (:documentation "Error raised when there's no other - more applicable - 134 error available.")) 135 136 (define-usocket-condition-classes 137 (ns-try-again-condition) 138 (ns-condition)) 139 140 (define-condition ns-unknown-condition (ns-condition) 141 ((real-condition :initarg :real-condition 142 :accessor ns-real-condition 143 :initform nil)) 144 (:documentation "Condition raised when there's no other - more applicable - 145 condition available.")) 146 147 (define-usocket-condition-classes 148 ;; the no-data error code in the Unix 98 api 149 ;; isn't really an error: there's just no data to return. 150 ;; with lisp, we just return NIL (indicating no data) instead of 151 ;; raising an exception... 152 (ns-host-not-found-error 153 ns-no-recovery-error) 154 (ns-error)) 155 156 (define-condition ns-unknown-error (ns-error) 157 ((real-error :initarg :real-error 158 :accessor ns-real-error 159 :initform nil)) 160 (:report (lambda (c stream) 161 (typecase c 162 (simple-condition 163 (format stream 164 (simple-condition-format-control (usocket-real-error c)) 165 (simple-condition-format-arguments (usocket-real-error c)))) 166 (otherwise 167 (format stream "The condition ~A occurred." (usocket-real-error c)))))) 168 (:documentation "Error raised when there's no other - more applicable - 169 error available.")) 170 171 (defmacro with-mapped-conditions ((&optional socket) &body body) 172 `(handler-bind ((condition #'(lambda (c) (handle-condition c ,socket)))) 173 ,@body)) 174 175 (defparameter +unix-errno-condition-map+ 176 `(((11) . ns-try-again-condition) ;; EAGAIN 177 ((35) . ns-try-again-condition) ;; EDEADLCK 178 ((4) . interrupted-condition))) ;; EINTR 179 180 (defparameter +unix-errno-error-map+ 181 ;;### the first column is for non-(linux or srv4) systems 182 ;; the second for linux 183 ;; the third for srv4 184 ;;###FIXME: How do I determine on which Unix we're running 185 ;; (at least in clisp and sbcl; I know about cmucl...) 186 ;; The table below works under the assumption we'll *only* see 187 ;; socket associated errors... 188 `(((48 98) . address-in-use-error) 189 ((49 99) . address-not-available-error) 190 ((9) . bad-file-descriptor-error) 191 ((61 111) . connection-refused-error) 192 ((54 104) . connection-reset-error) 193 ((53 103) . connection-aborted-error) 194 ((22) . invalid-argument-error) 195 ((55 105) . no-buffers-error) 196 ((12) . out-of-memory-error) 197 ((45 95) . operation-not-supported-error) 198 ((1) . operation-not-permitted-error) 199 ((43 92) . protocol-not-supported-error) 200 ((44 93) . socket-type-not-supported-error) 201 ((51 101) . network-unreachable-error) 202 ((50 100) . network-down-error) 203 ((52 102) . network-reset-error) 204 ((58 108) . already-shutdown-error) 205 ((60 110) . timeout-error) 206 ((64 112) . host-down-error) 207 ((65 113) . host-unreachable-error))) 208 209 (defun map-errno-condition (errno) 210 (cdr (assoc errno +unix-errno-error-map+ :test #'member))) 211 212 (defun map-errno-error (errno) 213 (cdr (assoc errno +unix-errno-error-map+ :test #'member))) 214 215 (defparameter +unix-ns-error-map+ 216 `((1 . ns-host-not-found-error) 217 (2 . ns-try-again-condition) 218 (3 . ns-no-recovery-error))) 219 220 (defmacro unsupported (feature context &key minimum) 221 `(cerror "Ignore it and continue" 'unsupported 222 :feature ,feature 223 :context ,context 224 :minimum ,minimum)) 225 226 (defmacro unimplemented (feature context) 227 `(signal 'unimplemented :feature ,feature :context ,context)) 228 229 ;;; People may want to ignore all unsupported warnings, here it is. 230 (defmacro ignore-unsupported-warnings (&body body) 231 `(handler-bind ((unsupported 232 #'(lambda (c) 233 (declare (ignore c)) (continue)))) 234 (progn ,@body)))