genera.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
       ---
       genera.lisp (9940B)
       ---
            1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Package: USOCKET; Base: 10 -*-
            2 
            3 
            4 ;;;; See LICENSE for licensing information.
            5 
            6 (in-package :usocket)
            7 
            8 (defclass genera-socket ()
            9     ((foreign-address :initform 0 :initarg :foreign-address :accessor gs-foreign-address)
           10      (foreign-port :initform 0 :initarg :foreign-port :accessor gs-foreign-port)
           11      (local-address :initform 0 :initarg :local-address :accessor gs-local-address)
           12      (local-port :initform 0 :initarg :local-port :accessor gs-local-port))
           13   )
           14 
           15 (defclass genera-stream-socket (genera-socket)
           16     ((stream :initform nil :initarg :stream :accessor gs-stream))
           17   )
           18 
           19 (defclass genera-stream-server-socket (genera-socket)
           20     ((backlog :initform nil :initarg :backlog :accessor gs-backlog)
           21      (element-type :initform nil :initarg :element-type :accessor gs-element-type)
           22      (pending-connections :initform nil :accessor gs-pending-connections))
           23   )
           24 
           25 (defclass genera-datagram-socket (genera-socket)
           26     ((connection :initform nil :initarg :connection :accessor gs-connection))
           27   )
           28 
           29 (defun host-to-host-object (host)
           30   (let ((host (host-to-hostname host)))
           31     (cond ((string-equal host "localhost")
           32            net:*local-host*)
           33           ((ip-address-string-p host)
           34            (let ((quad (dotted-quad-to-vector-quad host)))
           35              ;;---*** NOTE: This test is temporary until we have a loopback interface
           36              (if (= (aref quad 0) 127)
           37                  net:*local-host*
           38                  (net:parse-host (format nil "INTERNET|~A" host)))))
           39           (t
           40            (net:parse-host host)))))
           41 
           42 (defun element-type-to-format (element-type protocol)
           43   (cond ((null element-type)
           44          (ecase protocol
           45            (:stream :text)
           46            (:datagram :binary)))
           47         ((subtypep element-type 'character)
           48          :text)
           49         (t :binary)))
           50 
           51 (defun handle-condition (condition &optional (socket nil) (host-or-ip nil))
           52   (typecase condition
           53     ;;---*** TODO: Add additional conditions as appropriate
           54     (sys:connection-refused
           55       (error 'connection-refused-error :socket socket))
           56     ((or tcp::tcp-destination-unreachable-during-connection tcp::udp-destination-unreachable)
           57       (error 'host-unreachable-error :socket socket))
           58     (sys:host-not-responding-during-connection
           59       (error 'timeout-error :socket socket))
           60     (sys:unknown-host-name
           61       (error 'ns-host-not-found-error :host-or-ip host-or-ip))
           62     (sys:network-error
           63       (error 'unknown-error :socket socket :real-error condition :errno -1))))
           64 
           65 (defun socket-connect (host port &key (protocol :stream) element-type
           66                             timeout deadline (nodelay nil nodelay-p)
           67                             local-host local-port)
           68   (declare (ignore local-host))
           69   (when deadline
           70     (unsupported 'deadline 'socket-connect))
           71   (when (and nodelay-p (not (eq nodelay :if-supported)))
           72     (unsupported 'nodelay 'socket-connect))
           73   (with-mapped-conditions (nil host)
           74     (ecase protocol
           75       (:stream
           76         (let* ((host-object (host-to-host-object host))
           77                (format (element-type-to-format element-type protocol))
           78                (characters (eq format :text))
           79                (timeout (if timeout
           80                             (* 60 timeout)
           81                             tcp:*tcp-connect-timeout*))
           82                (stream (tcp:open-tcp-stream host-object port local-port
           83                                             :characters characters
           84                                             :ascii-translation characters
           85                                             :timeout timeout))
           86                (gs (make-instance 'genera-stream-socket
           87                                   :stream stream)))
           88           (setf (gs-foreign-address gs) (scl:send stream :foreign-address))
           89           (setf (gs-foreign-port gs) (scl:send stream :foreign-port))
           90           (setf (gs-local-address gs) (scl:send stream :local-address))
           91           (setf (gs-local-port gs) (scl:send stream :local-port))
           92           (make-stream-socket :socket gs :stream stream)))
           93       (:datagram
           94         ;;---*** TODO
           95         (unsupported 'datagram 'socket-connect)))))
           96 
           97 (defmethod socket-close ((usocket usocket))
           98   (with-mapped-conditions (usocket)
           99     (socket-close (socket usocket))))
          100 
          101 (defmethod socket-close ((socket genera-stream-socket))
          102   (with-slots (stream) socket
          103     (when stream
          104       (scl:send (shiftf stream nil) :close nil))))
          105 
          106 (defmethod socket-close ((socket genera-stream-server-socket))
          107   (with-slots (local-port pending-connections) socket
          108     (when local-port
          109       (tcp:remove-tcp-port-listener local-port))
          110     (dolist (tcb pending-connections)
          111       (tcp::reject-tcb tcb))))
          112 
          113 (defmethod socket-close ((socket genera-datagram-socket))
          114   (with-slots (connection) socket
          115     (when connection
          116       (scl:send (shiftf connection nil) :close nil))
          117     ;;---*** TODO: listening?
          118     ))
          119 
          120 ;;; Cribbed from TCP::MAKE-TCB
          121 (defun gensym-tcp-port ()
          122   (loop as number = (incf tcp::*last-gensym-port-number*) then tcp::*last-gensym-port-number*
          123         do (cond ((loop for existing-tcb in tcp::*tcb-list*
          124                         thereis (= number (tcp::tcb-local-port existing-tcb))))
          125                  ((and (<= #.(expt 2 10) number) (< number #.(expt 2 16)))
          126                   (return number))
          127                  (t
          128                   (setq tcp::*last-gensym-port-number* #.(expt 2 10))))))
          129 
          130 (defun socket-listen (host port &key (reuse-address nil reuse-address-p)
          131                                      (reuseaddress nil reuseaddress-p)
          132                                      (backlog 5) (element-type 'character))
          133   (let ((host-object (host-to-host-object host))
          134         (port (if (zerop port) (gensym-tcp-port) port))
          135         (reuse-address (cond (reuse-address-p reuse-address)
          136                              (reuseaddress-p reuseaddress)
          137                              (t nil))))
          138     (when (<= port 1024)
          139       ;; Don't allow listening on "privileged" ports to mimic Unix/Linux semantics
          140       (error 'operation-not-permitted-error :socket nil))
          141     (when (tcp:tcp-port-protocol-name port)
          142       ;; Can't replace a Genera server
          143       (error 'address-in-use-error :socket nil))
          144     (when (tcp:tcp-port-listener port)
          145       (unless reuse-address
          146         (error 'address-in-use-error :socket nil)))
          147     (let ((gs (make-instance 'genera-stream-server-socket
          148                              :backlog backlog
          149                              :element-type element-type)))
          150       (setf (gs-local-address gs)
          151             (loop for (network address) in (scl:send host-object :network-addresses)
          152                   when (typep network 'tcp:internet-network)
          153                     return address))
          154       (setf (gs-local-port gs) port)
          155       (flet ((add-to-queue (tcb)
          156                (cond ((and (not (zerop (gs-local-address gs)))
          157                            (not (= (gs-local-address gs) (tcp::tcb-local-address tcb))))
          158                       ;; Reject if not destined for the proper address
          159                       (tcp::reject-tcb tcb))
          160                      ((<= (length (gs-pending-connections gs)) (gs-backlog gs))
          161                       (tcp::accept-tcb tcb)
          162                       (tcp::tcb-travel-through-states tcb "Accept" nil :listen :syn-received)
          163                       (setf (gs-pending-connections gs)
          164                             (append (gs-pending-connections gs) (list tcb))))
          165                       (t
          166                         ;; Reject if backlog is full
          167                         (tcp::reject-tcb tcb)))))
          168         (tcp:add-tcp-port-listener port #'add-to-queue))
          169       (make-stream-server-socket gs :element-type element-type))))
          170 
          171 (defmethod socket-accept ((socket stream-server-usocket) &key element-type)
          172   (with-slots (pending-connections) (socket socket)
          173     (loop
          174       (process:process-block "Wait for connection" #'(lambda ()
          175                                                        (not (null pending-connections))))
          176       (let ((tcb (pop pending-connections)))
          177         (when tcb
          178           (let* ((format (element-type-to-format (or element-type (element-type socket))
          179                                                  :stream))
          180                  (characters (eq format :text))
          181                  (stream (tcp::make-tcp-stream tcb
          182                                                :characters characters
          183                                                :ascii-translation characters))
          184                  (gs (make-instance 'genera-stream-socket
          185                                     :stream stream)))
          186             (setf (gs-foreign-address gs) (scl:send stream :foreign-address))
          187             (setf (gs-foreign-port gs) (scl:send stream :foreign-port))
          188             (setf (gs-local-address gs) (scl:send stream :local-address))
          189             (setf (gs-local-port gs) (scl:send stream :local-port))
          190             (return (make-stream-socket :socket gs :stream stream))))))))
          191 
          192 (defmethod get-local-address ((usocket usocket))
          193   (hbo-to-vector-quad (gs-local-address (socket usocket))))
          194 
          195 (defmethod get-peer-address ((usocket stream-usocket))
          196   (hbo-to-vector-quad (gs-foreign-address (socket usocket))))
          197 
          198 (defmethod get-local-port ((usocket usocket))
          199   (gs-local-port (socket usocket)))
          200 
          201 (defmethod get-peer-port ((usocket stream-usocket))
          202   (gs-foreign-port (socket usocket)))
          203 
          204 (defmethod get-local-name ((usocket usocket))
          205   (values (get-local-address usocket)
          206           (get-local-port usocket)))
          207 
          208 (defmethod get-peer-name ((usocket stream-usocket))
          209   (values (get-peer-address usocket)
          210           (get-peer-port usocket)))
          211 
          212 (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0))
          213   ;;---*** TODO
          214   (unsupported 'datagram 'socket-send))
          215 
          216 (defmethod socket-receive ((socket datagram-usocket) buffer length &key)
          217   ;;---*** TODO
          218   (unsupported 'datagram 'socket-receive))
          219 
          220 (defun get-host-by-address (address)
          221   ) ;; TODO
          222 
          223 (defun get-hosts-by-name (name)
          224   (with-mapped-conditions (nil name)
          225     (let ((host-object (host-to-host-object name)))
          226       (loop for (network address) in (scl:send host-object :network-addresses)
          227             when (typep network 'tcp:internet-network)
          228               collect (hbo-to-vector-quad address)))))
          229 
          230 (defun %setup-wait-list (wait-list)
          231   (declare (ignore wait-list)))
          232 
          233 (defun %add-waiter (wait-list waiter)
          234   (declare (ignore wait-list waiter)))
          235 
          236 (defun %remove-waiter (wait-list waiter)
          237   (declare (ignore wait-list waiter)))
          238 
          239 (defun wait-for-input-internal (wait-list &key timeout)
          240   (with-mapped-conditions ()
          241     (process:process-block-with-timeout timeout "Wait for input"
          242       #'(lambda (wait-list)
          243           (let ((ready-sockets nil))
          244             (dolist (waiter (wait-list-waiters wait-list) ready-sockets)
          245               (setf (state waiter)
          246                     (cond ((stream-usocket-p waiter)
          247                            (if (listen (socket-stream waiter))
          248                                :read
          249                                nil))
          250                           ((datagram-usocket-p waiter)
          251                            (let ((connection (gs-connection (socket waiter))))
          252                              (if (and connection
          253                                       (not (scl:send connection :connection-pending-p)))
          254                                  :read
          255                                  nil)))
          256                           ((stream-server-usocket-p waiter)
          257                            (if (gs-pending-connections (socket waiter))
          258                                :read
          259                                nil))))
          260               (when (not (null (state waiter)))
          261                 (setf ready-sockets t)))))
          262       wait-list)
          263     wait-list))
          264