scl.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
       ---
       scl.lisp (10025B)
       ---
            1 ;;;; See LICENSE for licensing information.
            2 
            3 (in-package :usocket)
            4 
            5 (defparameter +scl-error-map+
            6   (append +unix-errno-condition-map+
            7           +unix-errno-error-map+))
            8 
            9 (defun scl-map-socket-error (err &key condition socket)
           10   (let ((usock-err (cdr (assoc err +scl-error-map+ :test #'member))))
           11     (cond (usock-err
           12        (if (subtypep usock-err 'error)
           13            (error usock-err :socket socket)
           14            (signal usock-err :socket socket)))
           15       (t
           16        (error 'unknown-error
           17           :socket socket
           18           :real-error condition)))))
           19 
           20 (defun handle-condition (condition &optional (socket nil) (host-or-ip nil))
           21   "Dispatch correct usocket condition."
           22   (typecase condition
           23     (ext::socket-error
           24      (scl-map-socket-error (ext::socket-errno condition)
           25                            :socket socket
           26                            :condition condition))))
           27 
           28 (defun socket-connect (host port &key (protocol :stream) (element-type 'character)
           29                        timeout deadline (nodelay t nodelay-specified)
           30                        (local-host nil local-host-p)
           31                        (local-port nil local-port-p)
           32                        &aux
           33                        (patch-udp-p (fboundp 'ext::inet-socket-send-to)))
           34   (when (and nodelay-specified 
           35              (not (eq nodelay :if-supported)))
           36     (unsupported 'nodelay 'socket-connect))
           37   (when deadline (unsupported 'deadline 'socket-connect))
           38   (when timeout (unsupported 'timeout 'socket-connect))
           39   (when (and local-host-p (not patch-udp-p))
           40      (unsupported 'local-host 'socket-connect :minimum "1.3.9"))
           41   (when (and local-port-p (not patch-udp-p))
           42      (unsupported 'local-port 'socket-connect :minimum "1.3.9"))
           43 
           44   (let ((socket))
           45     (ecase protocol
           46       (:stream
           47        (setf socket (let ((args (list (host-to-hbo host) port :kind protocol)))
           48                       (when (and patch-udp-p (or local-host-p local-port-p))
           49                         (nconc args (list :local-host (when local-host
           50                                                         (host-to-hbo local-host))
           51                                           :local-port local-port)))
           52                       (with-mapped-conditions (socket)
           53                         (apply #'ext:connect-to-inet-socket args))))
           54        (let ((stream (sys:make-fd-stream socket :input t :output t
           55                                          :element-type element-type
           56                                          :buffering :full)))
           57          (make-stream-socket :socket socket :stream stream)))
           58       (:datagram
           59        (when (not patch-udp-p)
           60          (error 'unsupported
           61                 :feature '(protocol :datagram)
           62                 :context 'socket-connect
           63                 :minumum "1.3.9"))
           64        (setf socket
           65              (if (and host port)
           66                  (let ((args (list (host-to-hbo host) port :kind protocol)))
           67                    (when (and patch-udp-p (or local-host-p local-port-p))
           68                      (nconc args (list :local-host (when local-host
           69                                                      (host-to-hbo local-host))
           70                                        :local-port local-port)))
           71                    (with-mapped-conditions (socket)
           72                      (apply #'ext:connect-to-inet-socket args)))
           73                  (if (or local-host-p local-port-p)
           74                      (with-mapped-conditions ()
           75                        (ext:create-inet-listener (or local-port 0)
           76                                                  protocol
           77                                                  :host (when local-host
           78                                                          (if (ip= local-host *wildcard-host*)
           79                                                              0
           80                                                              (host-to-hbo local-host)))))
           81                      (with-mapped-conditions ()
           82                        (ext:create-inet-socket protocol)))))
           83        (let ((usocket (make-datagram-socket socket :connected-p (and host port t))))
           84          (ext:finalize usocket #'(lambda ()
           85                                    (when (%open-p usocket)
           86                                      (ext:close-socket socket))))
           87          usocket)))))
           88 
           89 (defun socket-listen (host port
           90                            &key reuseaddress
           91                            (reuse-address nil reuse-address-supplied-p)
           92                            (backlog 5)
           93                            (element-type 'character))
           94   (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress))
           95          (host (if (ip= host *wildcard-host*)
           96                    0
           97                  (host-to-hbo host)))
           98          (server-sock
           99           (with-mapped-conditions ()
          100             (ext:create-inet-listener port :stream
          101                                       :host host
          102                                       :reuse-address reuseaddress
          103                                       :backlog backlog))))
          104    (make-stream-server-socket server-sock :element-type element-type)))
          105 
          106 (defmethod socket-accept ((usocket stream-server-usocket) &key element-type)
          107   (with-mapped-conditions (usocket)
          108     (let* ((sock (ext:accept-tcp-connection (socket usocket)))
          109            (stream (sys:make-fd-stream sock :input t :output t
          110                                       :element-type (or element-type
          111                                                         (element-type usocket))
          112                                       :buffering :full)))
          113       (make-stream-socket :socket sock :stream stream))))
          114 
          115 ;; Sockets and their associated streams are modelled as
          116 ;; different objects. Be sure to close the socket stream
          117 ;; when closing stream-sockets; it makes sure buffers
          118 ;; are flushed and the socket is closed correctly afterwards.
          119 (defmethod socket-close ((usocket usocket))
          120   "Close socket."
          121   (with-mapped-conditions (usocket)
          122     (ext:close-socket (socket usocket))))
          123 
          124 (defmethod socket-close ((usocket stream-usocket))
          125   "Close socket."
          126   (with-mapped-conditions (usocket)
          127     (close (socket-stream usocket))))
          128 
          129 (defmethod socket-close :after ((socket datagram-usocket))
          130   (setf (%open-p socket) nil))
          131 
          132 (defmethod socket-shutdown ((usocket usocket) direction)
          133   (declare (ignore usocket direction))
          134   (unsupported "shutdown" 'socket-shutdown))
          135 
          136 (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port)
          137   (let ((s (socket usocket))
          138         (host (if host (host-to-hbo host)))
          139         (real-buffer (if (zerop offset)
          140                          buffer
          141                          (subseq buffer offset (+ offset size)))))
          142     (multiple-value-bind (result errno)
          143         (ext:inet-socket-send-to s real-buffer size
          144                                  :remote-host host :remote-port port)
          145       (or result
          146           (scl-map-socket-error errno :socket usocket)))))
          147 
          148 (defmethod socket-receive ((socket datagram-usocket) buffer length &key)
          149   (declare (values (simple-array (unsigned-byte 8) (*)) ; buffer
          150                    (integer 0)                          ; size
          151                    (unsigned-byte 32)                   ; host
          152                    (unsigned-byte 16)))                 ; port
          153   (let ((s (socket socket)))
          154     (let ((real-buffer (or buffer
          155                            (make-array length :element-type '(unsigned-byte 8))))
          156           (real-length (or length
          157                            (length buffer))))
          158       (multiple-value-bind (result errno remote-host remote-port)
          159           (ext:inet-socket-receive-from s real-buffer real-length)
          160         (if result
          161             (values real-buffer result remote-host remote-port)
          162             (scl-map-socket-error errno :socket socket))))))
          163 
          164 (defmethod get-local-name ((usocket usocket))
          165   (multiple-value-bind (address port)
          166       (with-mapped-conditions (usocket)
          167         (ext:get-socket-host-and-port (socket usocket)))
          168     (values (hbo-to-vector-quad address) port)))
          169 
          170 (defmethod get-peer-name ((usocket stream-usocket))
          171   (multiple-value-bind (address port)
          172       (with-mapped-conditions (usocket)
          173         (ext:get-peer-host-and-port (socket usocket)))
          174     (values (hbo-to-vector-quad address) port)))
          175 
          176 (defmethod get-local-address ((usocket usocket))
          177   (nth-value 0 (get-local-name usocket)))
          178 
          179 (defmethod get-peer-address ((usocket stream-usocket))
          180   (nth-value 0 (get-peer-name usocket)))
          181 
          182 (defmethod get-local-port ((usocket usocket))
          183   (nth-value 1 (get-local-name usocket)))
          184 
          185 (defmethod get-peer-port ((usocket stream-usocket))
          186   (nth-value 1 (get-peer-name usocket)))
          187 
          188 
          189 (defun get-host-by-address (address)
          190   (multiple-value-bind (host errno)
          191       (ext:lookup-host-entry (host-byte-order address))
          192     (cond (host
          193            (ext:host-entry-name host))
          194           (t
          195            (let ((condition (cdr (assoc errno +unix-ns-error-map+))))
          196              (cond (condition
          197                     (error condition :host-or-ip address))
          198                    (t
          199                     (error 'ns-unknown-error :host-or-ip address
          200                            :real-error errno))))))))
          201 
          202 (defun get-hosts-by-name (name)
          203   (multiple-value-bind (host errno)
          204       (ext:lookup-host-entry name)
          205     (cond (host
          206            (mapcar #'hbo-to-vector-quad
          207                    (ext:host-entry-addr-list host)))
          208           (t
          209            (let ((condition (cdr (assoc errno +unix-ns-error-map+))))
          210              (cond (condition
          211                     (error condition :host-or-ip name))
          212                    (t
          213                     (error 'ns-unknown-error :host-or-ip name
          214                            :real-error errno))))))))
          215 
          216 (defun get-host-name ()
          217   (unix:unix-gethostname))
          218 
          219 
          220 ;;
          221 ;;
          222 ;;  WAIT-LIST part
          223 ;;
          224 
          225 
          226 (defun %add-waiter (wl waiter)
          227   (declare (ignore wl waiter)))
          228 
          229 (defun %remove-waiter (wl waiter)
          230   (declare (ignore wl waiter)))
          231 
          232 (defun %setup-wait-list (wl)
          233   (declare (ignore wl)))
          234 
          235 (defun wait-for-input-internal (wait-list &key timeout)
          236   (let* ((sockets (wait-list-waiters wait-list))
          237          (pollfd-size (alien:alien-size (alien:struct unix::pollfd) :bytes))
          238          (nfds (length sockets))
          239          (bytes (* nfds pollfd-size)))
          240     (alien:with-bytes (fds-sap bytes)
          241       (do ((sockets sockets (rest sockets))
          242           (base 0 (+ base 8)))
          243          ((endp sockets))
          244        (let ((fd (socket (first sockets))))
          245          (setf (sys:sap-ref-32 fds-sap base) fd)
          246          (setf (sys:sap-ref-16 fds-sap (+ base 4)) unix::pollin)))
          247       (multiple-value-bind (result errno)
          248          (let ((thread:*thread-whostate* "Poll wait")
          249                (timeout (if timeout
          250                             (truncate (* timeout 1000))
          251                             -1)))
          252            (declare (inline unix:unix-poll))
          253            (unix:unix-poll (alien:sap-alien fds-sap
          254                                             (* (alien:struct unix::pollfd)))
          255                            nfds timeout))
          256        (cond ((not result)
          257               (error "~@<Polling error: ~A~:@>"
          258                      (unix:get-unix-error-msg errno)))
          259              (t
          260               (do ((sockets sockets (rest sockets))
          261                    (base 0 (+ base 8)))
          262                   ((endp sockets))
          263                 (let ((flags (sys:sap-ref-16 fds-sap (+ base 6))))
          264                   (unless (zerop (logand flags unix::pollin))
          265                     (setf (state (first sockets)) :READ))))))))))
          266