communication.lisp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. ;;;; communication.lisp
  2. (in-package #:lserver-impl)
  3. ;;;;;;;;;;;;;;;;;;;
  4. (defparameter *buffer-size* 4096)
  5. (defvar *interpreter-stream*)
  6. (defun int-s (integer)
  7. (check-type integer (unsigned-byte 32))
  8. (check-type *interpreter-stream* stream)
  9. (loop for i from 3 downto 0 do
  10. (write-byte (ldb (byte 8 (* 8 i)) integer) *interpreter-stream*))
  11. (finish-output *interpreter-stream*))
  12. (defun char-s (octet)
  13. (check-type octet (unsigned-byte 8))
  14. (check-type *interpreter-stream* stream)
  15. (write-byte octet *interpreter-stream*)
  16. (finish-output *interpreter-stream*))
  17. (defun octets-s (octets &key (start 0) end)
  18. (check-type octets (vector (unsigned-byte 8)))
  19. (check-type *interpreter-stream* stream)
  20. (check-type start (and fixnum (integer 0)))
  21. (check-type end (or null (and fixnum (integer 0))))
  22. (when (null end)
  23. (setf end (length octets)))
  24. (unless (<= 0 start end (the fixnum (length octets)))
  25. (error 'type-error
  26. :datum (cons start end)
  27. :expected-type `(cons (integer 0 ,(length octets))
  28. (integer ,start ,(length octets)))))
  29. (assert (<= (the fixnum (- end start)) (expt 2 32)))
  30. (int-s (- end start))
  31. (write-sequence octets *interpreter-stream* :start start :end end)
  32. (finish-output *interpreter-stream*))
  33. (defun int-r ()
  34. (check-type *interpreter-stream* stream)
  35. (loop with n fixnum = 0
  36. repeat 4
  37. do (setf n (+ (ash n 8)
  38. (read-byte *interpreter-stream*)))
  39. finally (return n)))
  40. ;; Returns the length!
  41. (defun octets-r (vector &key (start 0))
  42. (check-type vector (vector (unsigned-byte 8)))
  43. (check-type *interpreter-stream* stream)
  44. (check-type start (and fixnum (integer 0)))
  45. (assert (<= start (length vector)))
  46. (let ((length (int-r)))
  47. (assert (<= length (- (length vector) start)))
  48. (when (plusp length)
  49. (unless (= (read-sequence vector *interpreter-stream*
  50. :start start
  51. :end (+ start length))
  52. length)
  53. (error "CORRUPT DATA")))
  54. length))
  55. #|
  56. Use cases: sending command line arguments & environment
  57. A fresh string is to be consed every time.
  58. It seems all right to use throw-away buffers.
  59. |#
  60. (defun string-r ()
  61. (check-type *interpreter-stream* stream)
  62. (let ((length (int-r)))
  63. (when (plusp length)
  64. (let ((buffer (make-array length :element-type '(unsigned-byte 8))))
  65. (unless (= (read-sequence buffer *interpreter-stream*) length)
  66. (error "CORRUPT DATA"))
  67. (flexi-streams:octets-to-string buffer :external-format :utf-8)))))
  68. ;;;;;;;;;;;;;;;;;;;
  69. (defmacro command-code (name number)
  70. `(defun ,name ()
  71. (char-s ,number)
  72. (finish-output *interpreter-stream*)))
  73. #|
  74. I doubt much can be gained by not flushing the commands right away, so we do that automatically.
  75. |#
  76. (command-code quit-c 0)
  77. (command-code ping-c 1)
  78. (command-code int-sc 2)
  79. (command-code data-sc 3)
  80. (command-code int-rc 4)
  81. (command-code data-rc 5)
  82. (command-code read-stdin-c 6)
  83. (command-code dump-to-stdout-c 7)
  84. (command-code flush-stdout-c 8)
  85. (command-code dump-to-stderr-c 9)
  86. (command-code flush-stderr-c 10)
  87. (command-code string-rc 11)
  88. (command-code save-argv0-c 12)
  89. (command-code save-argc-c 13)
  90. (command-code save-arg-c 14)
  91. (command-code save-env-c 15)
  92. (command-code save-cwd-c 16)
  93. (command-code save-isatty-c 17)
  94. (defun ping ()
  95. (ping-c)
  96. (zerop (int-r)))
  97. (defun send-int (integer)
  98. (int-sc)
  99. (int-s integer))
  100. (defun send-data (vector &key (start 0) end)
  101. (data-sc)
  102. (octets-s vector :start start :end end))
  103. (defun get-int ()
  104. (int-rc)
  105. (int-r))
  106. ;; Returns the length!
  107. (defun get-data (vector &key (start 0))
  108. (data-rc)
  109. (octets-r vector :start start))
  110. ;; Returns the length!
  111. (defun get-stdin (vector &key (start 0))
  112. (read-stdin-c)
  113. (get-data vector :start start))
  114. (defun get-string ()
  115. (string-rc)
  116. (string-r))
  117. (defun send-string (string)
  118. (check-type string string)
  119. (assert (<= (length string) (1- *buffer-size*)))
  120. (setf string (concatenate 'string string #.(string (code-char 0))))
  121. (send-data (flexi-streams:string-to-octets string :external-format :utf-8)))
  122. (defun argv ()
  123. (let ((argc (progn
  124. (save-argc-c)
  125. (get-int))))
  126. (loop for i below argc
  127. do (send-int i)
  128. (save-arg-c)
  129. collect (get-string))))
  130. (defun argv0 ()
  131. (save-argv0-c)
  132. (get-string))
  133. (defun getenv (name)
  134. (send-string name)
  135. (save-env-c)
  136. (let ((defined? (zerop (get-int))))
  137. (if defined?
  138. (get-string)
  139. nil)))
  140. (defun getcwd ()
  141. (save-cwd-c)
  142. (uiop:ensure-directory-pathname (get-string)))
  143. (defun isatty ()
  144. (save-isatty-c)
  145. (not (zerop (get-int))))
  146. (defun quit-interpreter (&optional (code 0))
  147. (flush-stdout-c)
  148. (flush-stderr-c)
  149. (send-int code)
  150. (quit-c))
  151. (defmacro with-interpreter-stream ((stream-form) &body body)
  152. `(let ((*interpreter-stream* ,stream-form))
  153. ,@body))
  154. ;;;;;;;;;;;;;;;;;;;
  155. (defstruct (octet-buffer (:constructor make-octet-buffer (size &aux (buffer (make-array size :element-type '(unsigned-byte 8))))))
  156. (buffer (make-array 0 :element-type '(unsigned-byte 8)) :type (vector (unsigned-byte 8)))
  157. (start 0 :type fixnum)
  158. (end 0 :type fixnum)
  159. (refillable-p t :type boolean))
  160. (defun refill (octet-buffer)
  161. (let ((data-length (get-stdin (octet-buffer-buffer octet-buffer))))
  162. (setf (octet-buffer-start octet-buffer) 0
  163. (octet-buffer-end octet-buffer) data-length)
  164. (when (zerop data-length)
  165. (setf (octet-buffer-refillable-p octet-buffer) nil))))
  166. (defun octet-buffer-read-byte (buffer)
  167. (check-type buffer octet-buffer)
  168. (cond ((< (octet-buffer-start buffer) (octet-buffer-end buffer))
  169. (locally
  170. (declare (optimize (speed 3) (safety 0)))
  171. (prog1
  172. (aref (octet-buffer-buffer buffer) (octet-buffer-start buffer))
  173. (the fixnum (incf (octet-buffer-start buffer))))))
  174. ((octet-buffer-refillable-p buffer)
  175. (refill buffer)
  176. (octet-buffer-read-byte buffer))
  177. (t :eof)))
  178. (defclass server-binary-input-stream (trivial-gray-streams:fundamental-binary-input-stream)
  179. ((octet-stream :reader octet-stream :initarg :octet-stream :initform (error "Octet stream must be supplied."))
  180. (octet-buffer :reader octet-buffer :initarg :octet-buffer :initform (error "Octet buffer must be supplied."))))
  181. (defmethod trivial-gray-streams:stream-read-byte ((stream server-binary-input-stream))
  182. (with-interpreter-stream ((octet-stream stream))
  183. (octet-buffer-read-byte (octet-buffer stream))))
  184. (defun make-server-binary-input-stream (stream)
  185. (make-instance 'server-binary-input-stream
  186. :octet-stream stream
  187. :octet-buffer (make-octet-buffer 4096)))
  188. ;;;;;;;;;;;;;;;;;;;
  189. #|
  190. don't dump fragments
  191. for simplicity we flush every time we dump
  192. |#
  193. (defun utf8-dump (buffer remote-stream)
  194. (when (plusp (length buffer))
  195. (let ((dump-end (length buffer)))
  196. (when (>= (aref buffer (1- dump-end)) #x80)
  197. (decf dump-end)
  198. (loop for i from (1- (length buffer)) downto 0
  199. repeat 4
  200. until (>= (aref buffer i)
  201. #b11000000)
  202. do (decf dump-end)))
  203. (when (plusp dump-end)
  204. (send-data buffer :end dump-end)
  205. (ecase remote-stream
  206. (:stdout
  207. (dump-to-stdout-c)
  208. (flush-stdout-c))
  209. (:stderr
  210. (dump-to-stderr-c)
  211. (flush-stderr-c)))
  212. (loop for i from dump-end below (length buffer)
  213. for j from 0
  214. do (setf (aref buffer j) (aref buffer i)))
  215. (setf (fill-pointer buffer) (- (length buffer) dump-end))))))
  216. (defun output-buffer-write-byte (byte buffer remote-stream buffering)
  217. (check-type byte (unsigned-byte 8))
  218. ;; TODO not necessarily utf8
  219. (flet ((dump ()
  220. (utf8-dump buffer remote-stream)))
  221. (unless (vector-push byte buffer)
  222. (dump)
  223. (or (vector-push byte buffer) (error "This shouldn't happen.")))
  224. (ecase buffering
  225. (:fully-buffered)
  226. (:line-buffered (when (= byte #.(char-code #\Newline))
  227. (dump)))
  228. (:unbuffered (dump))))
  229. byte)
  230. (defclass server-binary-output-stream (trivial-gray-streams:fundamental-binary-output-stream)
  231. ((octet-stream :reader octet-stream :initarg :octet-stream :initform (error "Octet stream must be supplied."))
  232. (buffer :reader buffer :initarg :buffer :initform (error "Buffer must be supplied."))
  233. (remote-stream :reader remote-stream :initarg :remote-stream :initform (error "Buffer must be supplied."))
  234. (buffering :accessor buffering :initarg :buffering :initform :fully-buffered)))
  235. (defun make-server-binary-output-stream (stream remote-stream buffering)
  236. (make-instance 'server-binary-output-stream
  237. :octet-stream stream
  238. :buffer (make-array *buffer-size*
  239. :element-type '(unsigned-byte 8)
  240. :fill-pointer 0)
  241. :remote-stream remote-stream
  242. :buffering buffering))
  243. (defmethod trivial-gray-streams::stream-element-type ((stream server-binary-output-stream))
  244. '(unsigned-byte 8))
  245. (defmethod trivial-gray-streams:stream-write-byte ((stream server-binary-output-stream) integer)
  246. (with-interpreter-stream ((octet-stream stream))
  247. (output-buffer-write-byte integer (buffer stream) (remote-stream stream) (buffering stream))))
  248. (defmethod trivial-gray-streams:stream-finish-output ((stream server-binary-output-stream))
  249. (with-interpreter-stream ((octet-stream stream))
  250. (utf8-dump (buffer stream) (remote-stream stream)) ;flushing is here
  251. ))
  252. ;; I don't know why this is necessary, but otherwise (format *query-io* "~&foo~%) won't work
  253. (defmethod sb-gray:stream-line-column ((s flexi-streams:flexi-input-stream))
  254. (declare (ignore s))
  255. nil)