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