1 ;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp -*-
3 ;; Copyright (C) 2007 Stelian Ionescu
5 ;; This code is free software; you can redistribute it and/or
6 ;; modify it under the terms of the version 2.1 of
7 ;; the GNU Lesser General Public License as published by
8 ;; the Free Software Foundation, as clarified by the
9 ;; preamble found here:
10 ;; http://opensource.franz.com/preamble.html
12 ;; This program is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU Lesser General
18 ;; Public License along with this library; if not, write to the
19 ;; Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 ;; Boston, MA 02110-1301, USA
22 (in-package :net.sockets
)
24 ;; TODO: use the buffer pool
25 ;; TODO: handle instance reinitialization
26 (defmethod shared-initialize :after
((s dual-channel-gray-stream
) slot-names
27 &key
(input-buffer-size +bytes-per-iobuf
+)
28 (output-buffer-size +bytes-per-iobuf
+)
29 (external-format :default
))
30 (declare (ignore slot-names
))
31 (check-type input-buffer-size buffer-index
)
32 (check-type output-buffer-size buffer-index
)
33 (when (open-stream-p s
) (close s
))
34 (with-slots ((ib input-buffer
) (ob output-buffer
)
35 (ef external-format
)) s
36 (setf ib
(allocate-iobuf input-buffer-size
)
37 ob
(allocate-iobuf output-buffer-size
))
38 (setf ef
(etypecase external-format
39 (symbol (find-external-format external-format
))
40 ((and list
(not null
))
41 (apply #'make-external-format external-format
))))))
49 (defmethod stream-element-type ((stream active-socket
))
53 ;; TODO: use the buffer pool
54 (defmethod close :around
((stream active-socket
) &key abort
)
55 (declare (ignore abort
))
56 (with-slots ((ib input-buffer
)
57 (ob output-buffer
)) stream
58 (when ib
(free-iobuf ib
))
59 (when ob
(free-iobuf ob
))
64 (defmethod close ((stream dual-channel-gray-stream
) &key abort
)
65 (declare (ignore stream abort
)))
73 (defmethod stream-clear-input ((stream active-socket
))
74 (with-slots ((ib input-buffer
)) stream
78 ;; (defmethod stream-read-sequence ((stream active-socket) seq
79 ;; &optional start end)
88 (defmethod stream-clear-output ((stream active-socket
))
89 (with-slots ((ob output-buffer
)) stream
93 ;; (defmethod stream-finish-output ((stream active-socket))
94 ;; (with-slots ((ob output-buffer)) stream
97 ;; (defmethod stream-force-output ((stream active-socket))
98 ;; (with-slots ((ob output-buffer)) stream
101 ;; (defmethod stream-read-sequence ((stream active-socket) seq
102 ;; &optional start end)
105 ;;;;;;;;;;;;;;;;;;;;;
107 ;; Character Input ;;
109 ;;;;;;;;;;;;;;;;;;;;;
111 (defun fill-iobuf (buf fd
&optional timeout
)
112 (iomux:wait-until-fd-ready fd
:read timeout
)
113 (let ((num (et:read fd
(cffi:inc-pointer
(iobuf-data buf
)
119 (incf (iobuf-end buf
) num
))))
121 (defun maybe-find-line-ending (fd ib ef
)
122 (let* ((start-off (iobuf-start ib
))
123 (char-code (bref ib start-off
)))
125 (ecase (ioenc:ef-line-terminator ef
)
126 (:unix
(when (= char-code
(char-code #\Linefeed
))
127 (incf (iobuf-start ib
))
128 (return (values #\Newline
1))))
129 (:mac
(when (= char-code
(char-code #\Return
))
130 (incf (iobuf-start ib
))
131 (return (values #\Newline
1))))
132 (:dos
(when (= char-code
(char-code #\Return
))
133 (when (and (= (iobuf-length ib
) 1)
134 (eq (fill-iobuf ib fd
) :eof
))
135 (incf (iobuf-start ib
))
136 (return (values #\Return
1)))
137 (when (= (bref ib
(1+ start-off
))
138 (char-code #\Linefeed
))
139 (incf (iobuf-start ib
) 2)
140 (return (values #\Newline
2)))))))))
142 (defmethod stream-read-char ((stream active-socket
))
143 (with-slots ((fd fd
) (ib input-buffer
)
145 (ef external-format
)) stream
146 (let ((str (make-string 1))
148 (flet ((fill-buf-or-eof ()
149 (setf ret
(fill-iobuf ib fd
))
151 (return-from stream-read-char
:eof
))))
152 (cond ((zerop (iobuf-length ib
))
155 ((< 0 (iobuf-end-space-length ib
) 4)
156 (iobuf-copy-data-to-start ib
)))
158 (multiple-value-bind (line-end bytes-consumed
)
159 (maybe-find-line-ending fd ib ef
)
161 (incf pos bytes-consumed
)
162 (return-from stream-read-char line-end
)))
165 (setf ret
(nth-value 1 (ioenc::%octets-to-string
168 (iobuf-end ib
) ef
1)))
169 (end-of-input-in-character (err)
170 (declare (ignore err
))
174 (incf (iobuf-start ib
) ret
))
177 (defun maybe-find-line-ending-no-hang (fd ib ef
)
178 (declare (ignore fd
))
179 (let* ((start-off (iobuf-start ib
))
180 (char-code (bref ib start-off
)))
182 (ecase (ioenc:ef-line-terminator ef
)
183 (:unix
(when (= char-code
(char-code #\Linefeed
))
184 (incf (iobuf-start ib
))
185 (return (values #\Newline
1))))
186 (:mac
(when (= char-code
(char-code #\Return
))
187 (incf (iobuf-start ib
))
188 (return (values #\Newline
1))))
189 (:dos
(when (= char-code
(char-code #\Return
))
190 (when (= (iobuf-length ib
) 1)
191 (incf (iobuf-start ib
))
192 (return :starvation
))
193 (when (= (bref ib
(1+ start-off
))
194 (char-code #\Linefeed
))
195 (incf (iobuf-start ib
) 2)
196 (return (values #\Newline
2)))))))))
198 (defmethod stream-read-char-no-hang ((stream active-socket
))
199 (with-slots ((fd fd
) (ib input-buffer
)
201 (ef external-format
)) stream
202 (let ((str (make-string 1))
206 (when (< 0 (iobuf-end-space-length ib
) 4)
207 (iobuf-copy-data-to-start ib
))
208 (when (and (iomux:fd-ready-p fd
:read
)
209 (eql :eof
(fill-iobuf ib fd
)))
211 (when (zerop (iobuf-length ib
))
212 (return (if eof
:eof nil
)))
214 (multiple-value-bind (line-end bytes-consumed
)
215 (maybe-find-line-ending-no-hang fd ib ef
)
216 (cond ((eql line-end
:starvation
)
222 ((characterp line-end
)
223 (incf pos bytes-consumed
)
227 (setf ret
(nth-value 1 (ioenc::%octets-to-string
230 (iobuf-end ib
) ef
1)))
231 (end-of-input-in-character (err)
232 (declare (ignore err
))
235 (incf (iobuf-start ib
) ret
)
238 (defmethod stream-peek-char ((stream active-socket
))
239 (let ((char (stream-read-char stream
)))
243 (stream-unread-char stream char
)
246 ;; (defmethod stream-read-line ((stream active-socket))
247 ;; (with-slots ((fd fd) (ib input-buffer)
249 ;; (ef external-format)) stream
250 ;; (let ((str (make-string 80)) (strsz 80) (strlen 0)
251 ;; (chars-out 0) (bytes-in 0)
255 (defmethod stream-listen ((stream active-socket
))
256 (characterp (stream-read-char-no-hang stream
)))
258 ;; (defmethod stream-unread-char ((stream active-socket) character))
260 ;;;;;;;;;;;;;;;;;;;;;;
262 ;; Character Output ;;
264 ;;;;;;;;;;;;;;;;;;;;;;
266 (defun buffer-string-to-octets (string buffer start end ef fd
&optional max-char-num
)
267 (declare (string string
)
269 (type buffer-index start
)
270 (type buffer-index end
)
272 (optimize (speed 3) (space 0) (safety 0) (debug 0)))
273 (unless max-char-num
(setf max-char-num -
1))
274 (let ((ptr start
) oldptr
279 (prog1 (char string ptr
) (incf ptr
)))
281 (setf (bref buffer
(incf pos
)) octet
))
284 (error symbol
:string string
285 :start start
:end end
287 :external-format
(ef-name ef
))
289 :report
"Supply a replacement character."
290 :interactive ioenc
::read-replacement-char
292 (use-standard-unicode-replacement ()
293 :report
"Use standard UCS replacement character"
294 (code-char ioenc
::+replacement-char
+))
296 :report
"Stop decoding and return to last good offset."
299 (loop :while
(and (< ptr end
)
300 (/= (incf char-count
) max-char-num
))
301 :do
(setf oldpos pos oldptr ptr
)
302 (ioenc::char-to-octets ef
#'input
#'output
#'error-fn
(- end ptr
))))
303 :exit
(return-from buffer-string-to-octets
(1+ pos
)))))
305 ;; (defmethod stream-write-char ((stream active-socket) character)
308 ;; (defmethod stream-advance-to-column ((stream active-socket)
309 ;; (column integer)))
311 ;; (defmethod stream-line-column ((stream active-socket)))
313 ;; (defmethod stream-line-length ((stream active-socket)))
315 (defmethod stream-start-line-p ((stream active-socket
))
318 ;; (defmethod stream-terpri ((stream active-socket)))
320 ;; (defmethod stream-fresh-line ((stream active-socket)))
322 ;; (defmethod stream-write-string ((stream active-socket)
324 ;; &optional start end))
332 (defmethod stream-read-byte ((stream active-socket
))
333 (with-slots ((fd fd
) (ib input-buffer
)
334 (pos istream-pos
)) stream
336 (flet ((fill-buf-or-eof ()
337 (setf ret
(fill-iobuf ib fd
))
339 (return-from stream-read-byte
:eof
))))
340 (cond ((zerop (iobuf-length ib
))
343 ((< 0 (iobuf-end-space-length ib
) 4)
344 (iobuf-copy-data-to-start ib
)))
345 (prog1 (bref ib
(iobuf-start ib
))
347 (incf (iobuf-start ib
)))))))
355 ;; (defmethod stream-write-byte ((stream active-socket) (integer integer))