rotor_stream/protocol.rs
1use std::io;
2use std::error::Error;
3use rotor::Scope;
4
5use {Transport, Intent, StreamSocket};
6
7quick_error!{
8 /// An exception value that is received in `Protocol::exception` method
9 ///
10 /// This thing is usually used for nice error detection. But sometimes it
11 /// is also useful for valid protocol processing. For example it allows
12 /// to detect end-of-stream-delimited prootols (of those which make of
13 /// use of TCP half close)
14 #[derive(Debug)]
15 pub enum Exception {
16 /// End of stream reached (when reading)
17 ///
18 /// This may be not a broken expectation, we just notify of end of
19 /// stream always (if the state machine is still alive)
20 ///
21 /// Note: the equivalent of end of stream for write system call is
22 /// translated to `WriteError(WriteZero)`
23 EndOfStream {
24 description("end of stream reached")
25 }
26 /// Limit for the number of bytes reached
27 ///
28 /// This is called when there is alredy maximum bytes in the buffer
29 /// (third argument of `Delimiter`) but no delimiter found.
30 LimitReached {
31 description("reached the limit of bytes buffered")
32 }
33 ReadError(err: io::Error) {
34 description("error when reading from stream")
35 display("read error: {}", err)
36 }
37 WriteError(err: io::Error) {
38 description("error when writing to stream")
39 display("write error: {}", err)
40 }
41 ConnectError(err: io::Error) {
42 description("error when connecting to an address")
43 display("connection error: {}", err)
44 }
45 }
46}
47
48
49/// This is an enumeration used to declare what next protocol is expecting
50///
51/// The value is used in `Intent::expect()`.
52///
53/// Most users should use `IntentBuilder`'s (a type which is returned from
54/// `Intent::of(..)`) methods. But for some kinds of control flow being
55/// able to specify expectation as a separate enum is very useful.
56// #[derive(Clone, Clone)]
57// This could be Copy, but I think it could be implemented efficient enough
58// without Copy and Clone. Probably we will enable them for the user code later
59#[derive(Debug)]
60pub enum Expectation {
61 /// Read number of bytes
62 ///
63 /// The buffer that is passed to bytes_read might contain more bytes, but
64 /// `num` parameter of the `bytes_read()` method will contain a number of
65 /// bytes passed into `Bytes` constructor.
66 ///
67 /// Note that bytes passed here is neither limit on bytes actually read
68 /// from the network (we resize buffer as convenient for memory allocator
69 /// and read as much as possible), nor is the preallocated buffer size
70 /// (we don't preallocate the buffer to be less vulnerable to DoS attacks).
71 ///
72 /// Note that real number of bytes that `netbuf::Buf` might contain is less
73 /// than 4Gb. So this value can't be as big as `usize::MAX`
74 Bytes(usize),
75 /// Read until delimiter
76 ///
77 /// Parameters: `offset`, `delimiter`, `max_bytes`
78 ///
79 /// Only static strings are supported for delimiter now.
80 ///
81 /// `bytes_read` action gets passed `num` bytes before the delimeter, or
82 /// in other words, the position of the delimiter in the buffer.
83 /// The delimiter is guaranteed to be in the buffer too. The `max_bytes`
84 /// do include the offset itself.
85 ///
86 Delimiter(usize, &'static [u8], usize),
87 /// Wait until no more than N bytes is in output buffer
88 ///
89 /// This is going to be used for several cases:
90 ///
91 /// 1. `Flush(0)` before closing the connection
92 /// 2. `Flush(0)` to before receiving new request (if needed)
93 /// 3. `Flush(N)` to wait when you can continue producing some data, this
94 /// allows TCP pushback. To be able not to put everything in output
95 /// buffer at once. Still probably more efficient than `Flush(0)`
96 Flush(usize),
97 /// Wait until deadline
98 ///
99 /// This useful for two cases:
100 ///
101 /// 1. Just wait before doing anything if required by business logic
102 /// 2. Wait until `wakeup` happens or atimeout whatever comes first
103 Sleep,
104}
105
106pub trait Protocol: Sized {
107 type Context;
108 type Socket: StreamSocket;
109 type Seed;
110 /// Starting the protocol (e.g. accepted a socket)
111 // TODO(tailhook) transport be here instead of sock?
112 fn create(seed: Self::Seed, sock: &mut Self::Socket,
113 scope: &mut Scope<Self::Context>)
114 -> Intent<Self>;
115
116 /// The action WaitBytes or WaitDelimiter is complete
117 ///
118 /// Note you don't have to consume input buffer. The data is in the
119 /// transport, but you are free to ignore it. This may be useful for
120 /// example to yield `Bytes(4)` to read the header size and then yield
121 /// bigger value to read the whole header at once. But be careful, if
122 /// you don't consume bytes you will repeatedly receive them again.
123 fn bytes_read(self, transport: &mut Transport<Self::Socket>,
124 end: usize, scope: &mut Scope<Self::Context>)
125 -> Intent<Self>;
126
127 /// The action Flush is complete
128 fn bytes_flushed(self, transport: &mut Transport<Self::Socket>,
129 scope: &mut Scope<Self::Context>)
130 -> Intent<Self>;
131
132 /// Timeout happened, which means either deadline reached in
133 /// Bytes, Delimiter, Flush. Or Sleep has passed.
134 fn timeout(self, transport: &mut Transport<Self::Socket>,
135 scope: &mut Scope<Self::Context>)
136 -> Intent<Self>;
137
138 /// The method is called when too much bytes are read but no delimiter
139 /// is found within the number of bytes specified. Or end of stream reached
140 ///
141 /// The usual case is to just close the connection (because it's probably
142 /// DoS attack is going on or the protocol mismatch), but sometimes you
143 /// want to send error code, like 413 Entity Too Large for HTTP.
144 ///
145 /// Note it's your responsibility to wait for the buffer to be flushed.
146 /// If you write to the buffer and then return Intent::done() immediately,
147 /// your data will be silently discarded.
148 ///
149 /// The `WriteError` and `ConnectError` are never passed here but passed
150 /// into `fatal` handler instead.
151 fn exception(self, _transport: &mut Transport<Self::Socket>,
152 reason: Exception, _scope: &mut Scope<Self::Context>)
153 -> Intent<Self>;
154
155 /// This method is called on fatal errors of the connection
156 ///
157 /// Connection can't proceed after this method is called
158 ///
159 /// Note: we use shared `Exception` type for both exception and fatal
160 /// exceptions. This method receives ``WriteError`` and ``ConnectError``
161 /// options only.
162 fn fatal(self, reason: Exception, scope: &mut Scope<Self::Context>)
163 -> Option<Box<Error>>;
164
165 /// Message received (from the main loop)
166 fn wakeup(self, transport: &mut Transport<Self::Socket>,
167 scope: &mut Scope<Self::Context>)
168 -> Intent<Self>;
169}