3 ;(use-package '(sb-simple-streams))
6 (defclass meta-tcp-client
(standard-class) ())
8 (defmethod validate-superclass ((class meta-tcp-client
) (superclass standard-class
))
11 ;;; Now this class can be confusing,
12 ;;; it seems to be a character stream, however it supports
13 ;;; multivalent read-byte and write-byte as well for HTTP convenience
15 (defclass tcp-client-stream
(sb-simple-streams:socket-simple-stream
)
17 (remote-host :initform nil
)
18 (remote-port :initform nil
)
19 ; (listen-sockaddr :initform nil :initarg :listen-sockaddr)
20 (process :initform nil
:accessor tcp-stream-process
)
21 (alive :initform t
:accessor tcp-client-alive
))
22 (:metaclass meta-tcp-client
))
24 ;; (defmethod make-instance ((class meta-tcp-client) &rest args &key host port &allow-other-keys)
27 (defmethod tcp-client-alive ((stream t
))
30 (defmethod close :around
((stream tcp-client-stream
) &key
(abort t
))
31 ;; When remote end aborts stream while we are transfering
32 ;; closing the stream can cause a Signal 13 on our end.
33 (setf (tcp-client-alive stream
) nil
)
36 (defun tcp-destroy-process (stream)
37 (let ((process (tcp-stream-process stream
)))
38 ;; If closing multiple times
40 (acl-compat-mp:process-kill process
)))
41 (setf (tcp-stream-process stream
) nil
))
44 ;; (setq a (make-instance 'tcp-client-stream :remote-host #(127 0 0 1) :remote-port 6600))
47 ;; (setq b (make-instance 'sb-bsd-sockets:inet-socket :type :stream :protocol :tcp))
49 ;; (sb-bsd-sockets:socket-connect b #(127 0 0 1) 6600)
51 ;; (setq a (make-instance 'tcp-client-stream :remote-socket b :direction :io))
57 ;; (format a "hello~%")
60 ;; (tcp-client-alive a)
65 (defclass meta-tcp-server
(standard-class) ())
67 (defmethod validate-superclass ((class meta-tcp-server
) (superclass standard-class
))
70 (defclass tcp-server-stream
();socket-simple-stream)
71 ((host :initarg
:host
:accessor host
) ;This is the local host
72 (port :initarg
:port
:accessor port
)
73 ; (listen-socket-fd :initarg :fn-in)
74 ; (listen-sockaddr :initarg :listen-sockaddr)
75 (socket :initform nil
:accessor tcp-server-socket
)
76 (client-streams :initform nil
)
77 (process :initform
:initializing
:accessor tcp-stream-process
))
78 (:metaclass meta-tcp-server
))
80 ;(defvar *tcp-server-terminate* nil)
82 ;; (defmethod make-instance :around ((class tcp-server-stream) &key host port);&rest initargs &key host port &allow-other-keys)
83 ;; (format t "make instance 'tcp-server-stream ~A :host ~A :port ~A~%" class host port)
84 ;; (setf (slot-value class 'host) host
85 ;; (slot-value class 'port) port)
86 ;; (initialize-tcp-server-process class)
87 ;; ; (call-next-method)
91 ;(setq a (make-instance 'tcp-server-stream :host "localhost" :port 8223))
93 (defmethod close #|
:around|
# ((stream tcp-server-stream
) &key
(abort t
))
94 (with-slots (process) stream
96 (acl-compat-mp:process-allow-schedule
)
97 (with-slots (client-streams) stream
98 (mapc #'(lambda (client)
102 (defmethod initialize-tcp-server-process ((stream tcp-server-stream
))
103 (format t
"initialize-tcp-server-process ~A~%" stream
)
104 (let ((server-name (format nil
"TCP Server [~a]" (slot-value stream
'port
)))
106 (setq proc
(acl-compat-mp:process-run-function server-name
107 #'tcp-server-daemon-function
109 (setf (tcp-stream-process stream
) proc
)
112 ;;; Define useful errors
114 (define-condition protocol-error
(error)
115 ((stream :initform nil
:initarg
:stream
)))
117 (defun nslookup (hostname)
118 "Performs a DNS look up for HOSTNAME and returns the address as a
119 four element array, suitable for socket-connect. If HOSTNAME is
120 not found, a host-not-found-error condition is thrown."
122 (sb-bsd-sockets:host-ent-address
(sb-bsd-sockets:get-host-by-name hostname
))
125 (defmethod tcp-server-daemon-function ((stream tcp-server-stream
))
127 (let ((socket (make-instance 'sb-bsd-sockets
:inet-socket
:type
:stream
:protocol
:tcp
))
131 (setf (tcp-server-socket stream
) socket
)
132 (setf (sb-bsd-sockets:sockopt-reuse-address socket
) t
)
133 (setf (sb-bsd-sockets:non-blocking-mode socket
) t
)
135 (sb-bsd-sockets:socket-bind socket
(nslookup host
) port
)
136 (format t
"listen~%") (force-output)
137 (sb-bsd-sockets:socket-listen socket
5)
138 ; (loop until *tcp-server-terminate* do
143 (cond ((tcp-stream-process stream
)
144 (setq client
(sb-bsd-sockets:socket-accept socket
))
145 ; (format t "accepted ~A~%" client)
150 ((< (sb-bsd-sockets:socket-file-descriptor client
) 0)
151 (format t
"Accept failure~%")
153 (acl-compat-mp:without-scheduling
154 (push (cons 'protocol-error nil
)
155 (slot-value stream
'client-streams
))))
157 (format t
"accepted ~A~%" client
)
159 (acl-compat-mp:without-scheduling
160 (push (cons client t
);(sb-bsd-sockets:socket-make-stream client :input t :output t :buffering :none))
161 (slot-value stream
'client-streams
))))))
165 (sb-bsd-sockets:interrupted-error
()
167 (format t
"exit") (force-output)
168 (sb-bsd-sockets:socket-close socket
))
170 (sb-bsd-sockets:address-in-use-error
()
171 (format t
"address ~A : ~A is already in use"
172 (host stream
) (port stream
))
177 (defmethod stream-read ((stream tcp-server-stream
))
178 (with-slots (client-streams) stream
179 (destructuring-bind (client . client-stream
)
180 (acl-compat-mp:without-scheduling
(pop client-streams
))
182 (if (symbolp client
) ;Handle future protocol errors
183 (error client
:stream stream
))
184 ;; (let ((host-address (sockaddr-in-addr listen-sockaddr))
186 ;; (port (sockaddr-in-port listen-sockaddr)))
187 ;; (setq host (handler-case (get-host-name-by-address host-address)
188 ;; (unknown-host-name () host-address)))
189 ;; ;; Open "" can fail here?
190 ;(format t "tcp-client ~A~%"
191 (make-instance 'tcp-client-stream
:remote-socket client
:direction
:io
)))))
194 ;; (setq a (make-instance 'tcp-server-stream :host "localhost" :port 8223))
196 ;; (setq b (tcp-server-daemon-function a))
200 ;; (setq x1 (stream-read a))
203 ;; (format x1 "hello, this is ~A ~A~%" (lisp-implementation-type) (lisp-implementation-version))
204 ;; (force-output x1))
208 ;; (defvar *term* nil)
210 ;; (loop unless *term* do
211 ;; (format x1 "> ") (force-output x1)
213 ;; (format x1 "~A~%" (eval (read x1)))
215 ;; (format x1 "~A~%" err)))
216 ;; (force-output x1))
221 ;; ;(setq *tcp-server-terminate* t)
222 ;; ;(sb-bsd-sockets:socket-close (tcp-server-socket a))
225 ;; (sb-bsd-sockets:non-blocking-mode (tcp-server-socket a))
229 ;; (format d "hello too~%")