source: branches/home/psmith/restructure/src/io/async-fd.lisp @ 58

Last change on this file since 58 was 58, checked in by psmith, 18 years ago

Added ip authorisation

File size: 7.8 KB
Line 
1#|
2Copyright (c) 2006 Risto Laakso
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions
7are met:
81. Redistributions of source code must retain the above copyright
9notice, this list of conditions and the following disclaimer.
102. Redistributions in binary form must reproduce the above copyright
11notice, this list of conditions and the following disclaimer in the
12documentation and/or other materials provided with the distribution.
133. The name of the author may not be used to endorse or promote products
14derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26|#
27(in-package :nio)
28
29(declaim (optimize (debug 3) (speed 3) (space 0)))
30
31(defclass async-fd ()
32  ((write-fd :initarg :write-fd
33             :accessor write-fd)
34   (read-fd :initarg :read-fd
35            :accessor read-fd)
36   (foreign-read-buffer :initform (byte-buffer 1024)
37                        :accessor foreign-read-buffer)
38   (foreign-write-buffer :initform (byte-buffer 1024)
39                         :accessor foreign-write-buffer)
40   (read-ready :initform nil
41                 :accessor read-ready
42                 :documentation "Have we been notified as read ready and not received EAGAIN from %read?")
43   (write-ready :initform nil
44                  :accessor write-ready
45                  :documentation "Have we been notified as write ready and not received EAGAIN from %write?")
46   (close-pending :initform nil)
47   (socket :initarg :socket
48           :accessor socket)))
49
50
51(defmethod print-object ((async-fd async-fd) stream)
52  (with-slots (socket read-fd write-fd) async-fd
53    (format stream "#<ASYNC-FD :socket ~D :read-fd ~D :write-fd ~D.>"
54            socket read-fd write-fd)))
55
56;;Implement this in concrete SM for read
57(defgeneric process-read (async-fd))
58
59;;Implement this in concrete SM for read
60(defgeneric process-write (async-fd))
61
62;;SM factory
63(defun create-state-machine(sm-type read-fd write-fd socket)
64  (let ((sm (make-instance sm-type :read-fd read-fd :write-fd write-fd :socket socket)))
65    (format-log t "async-fd:create-state-machine - Created ~S~%" sm)
66    (nio-buffer:clear (foreign-read-buffer sm))
67    (nio-buffer:clear (foreign-write-buffer sm))
68    sm))
69
70;;override this in concrete SM for close
71(defmethod process-close((async-fd async-fd)reason)())
72
73
74(defmethod close-sm((async-fd async-fd))
75  :documentation "Mark the socket for close to write"
76#+nio-debug  (format t "(mark for)close called with ~A~%" async-fd)
77  (with-slots (close-pending) async-fd
78      (setf close-pending t)))
79
80(define-condition read-error (error) ())
81
82;;  "Read more data from STATE-MACHINE."
83(defun read-more (state-machine)
84  (with-slots (foreign-read-buffer read-fd) state-machine
85#+nio-debug  (format t "read-more called with ~A~%" state-machine)
86#+nio-debug      (format t "read-more - calling read() into ~A~%" foreign-read-buffer) 
87    (let ((new-bytes (%read read-fd (buffer-buf foreign-read-buffer) (remaining foreign-read-buffer))))
88#+nio-debug      (format t "read-more : Read ~A bytes into ~A~%" new-bytes foreign-read-buffer)
89      (cond
90       ((< new-bytes 0)
91        (progn
92;;TODO if ret is -1 and errno is EAGAIN save state and wait for notification
93          (format t "read-error - Errno: ~A~%" (get-errno))
94          (error 'read-error)))
95       ((= new-bytes 0)
96        nil);;(throw 'end-of-file nil)
97       (t
98          ;;Update buffer position
99          (inc-position foreign-read-buffer new-bytes)
100          (setf (read-ready state-machine) nil))))))
101
102(defun close-async-fd (async-fd)
103  "Close ASYNC-FD's fd after everything has been written from write-queue."
104#+nio-debug    (format t "close-async-fd called with :async-fd ~A~%" async-fd)
105  (with-slots (read-fd write-fd foreign-read-buffer foreign-write-buffer) async-fd
106    (nio-buffer:flip foreign-write-buffer)
107#+nio-debug    (format t "close-async-fd foreign-write-buffer ~A~%" foreign-write-buffer)
108    (assert (eql (remaining foreign-write-buffer) 0))
109      ;; if write-queue is emtpy, close now
110       (close-fd read-fd)
111       (free-buffer foreign-read-buffer)
112       (free-buffer foreign-write-buffer)
113       (unless (= read-fd write-fd) (close-fd write-fd))))
114
115
116(define-condition read-error (error) ())
117
118(defun write-more (async-fd)
119  "Write data from ASYNC-FD's write bytebuffer"
120  (format-log t "async-fd:write-more - called with ~A~%" async-fd)
121  (with-slots (write-fd foreign-write-buffer close-pending) async-fd
122#+nio-debug  (format t "async-fd:write-more - foreign-write-buffer b4 flip ~A~%" foreign-write-buffer)
123    (nio-buffer:flip foreign-write-buffer)
124#+nio-debug (format t "async-fd:write-more -foreign-write-buffer after flip ~A~%" foreign-write-buffer)
125    (let ((now-written 0))
126      (do ((total-written 0))
127          ((or (eql now-written -1) (eql (remaining foreign-write-buffer) 0)) total-written)
128        (progn
129          (setf now-written (%write write-fd (buffer-buf foreign-write-buffer) (remaining foreign-write-buffer)))
130          (when (not (eql now-written -1))
131            (inc-position foreign-write-buffer now-written)
132            (incf total-written now-written)))
133#+nio-debug (format t "async-fd:write-more - after write :foreign-write-buffer ~A :now-written ~A :total-written ~A ~%" foreign-write-buffer now-written total-written))
134      (if (eql now-written -1)
135          ;;Deal with failure
136        (let ((err (get-errno)))
137          (format t "write-more - write returned -1 :errno ~A~%" err)
138          (unless (eql err 11) ;; eagain - failed to write whole buffer need to wait for next notify
139            (let ((err-cond (make-instance 'write-error :error err)))
140              (close err-cond)
141              (error err-cond))))
142        ;;update buffers
143        (if (eql (remaining foreign-write-buffer) 0)
144            (clear foreign-write-buffer)
145            (error 'not-implemented-yet))))
146
147#+nio-debug    (format t "write buffer after write :~A~%" foreign-write-buffer)
148      (when (eql (remaining foreign-write-buffer) 0)
149        (when close-pending (close-async-fd async-fd)))))
150
151
152(defconstant +MAX-BUFFER-SIZE-BYTES+ (* 1024 1024))
153
154(defmacro check-buffer-size (buffer size)
155  `(>= (length ,buffer) ,size))
156
157(defun realloc-buffer (async-fd buffer size)
158  (if (check-buffer-size buffer size)
159      t
160      (let ((new-buffer (byte-buffer size)))
161        (copy-buffer buffer new-buffer)
162        (free-buffer buffer)
163        (setf (foreign-read-buffer async-fd) new-buffer))))
164
165
166;TODO actually deal with cuffer allocation failure
167(defmethod recommend-buffer-size((async-fd async-fd) mode size)
168  (if (> size +MAX-BUFFER-SIZE-BYTES+) nil
169      (ecase mode
170        (:read (realloc-buffer (foreign-read-buffer async-fd) size))
171        (:write (realloc-buffer (foreign-write-buffer async-fd) size)))))
172   
173
174
175(defun force-close-async-fd (async-fd)
176  "Drop ASYNC-FD's write-queue and close it."
177  (free-buffer (slot-value async-fd 'foreign-write-buffer))
178  (close-async-fd async-fd))
179
180
181(defun add-async-fd (event-queue async-fd mode)
182  (ecase mode
183    (:read-write (add-fd event-queue (slot-value async-fd 'write-fd) :read-write))))
184
185
186(defun remove-async-fd (event-queue async-fd mode)
187  (ecase mode
188    (:read (remove-fd event-queue (slot-value async-fd 'read-fd) :read))
189    (:write (remove-fd event-queue (slot-value async-fd 'write-fd) :write))
190    (:read-write (remove-fd event-queue (slot-value async-fd 'write-fd) :read-write))))
191
192
193(defun async-fd-read-fd (async-fd)
194  (slot-value async-fd 'read-fd))
195
196(defun async-fd-write-fd (async-fd)
197  (slot-value async-fd 'write-fd))
198
Note: See TracBrowser for help on using the repository browser.