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