(M);
145 |
--------------------------------------------------------------------------------
/src/persistent.rs:
--------------------------------------------------------------------------------
1 | use std::fmt::Debug;
2 | use std::error::Error;
3 |
4 | use rotor::{Machine, EventSet, PollOpt, Scope, Response, Time};
5 | use rotor::void::{unreachable, Void};
6 | use rotor::{GenericScope};
7 |
8 | use {ActiveStream, Protocol, Stream, ProtocolStop, Transport};
9 | use extensions::{ResponseExt, ScopeExt};
10 |
11 |
12 | /// Reconnect timeout in milliseconds.
13 | ///
14 | /// TODO(tailhook) should be overridable at runtime
15 | pub const RECONNECT_TIMEOUT: u64 = 200;
16 |
17 | /// Time for establishing a connection
18 | ///
19 | /// TODO(tailhook) should be overridable at runtime
20 | pub const CONNECT_TIMEOUT: u64 = 1_000;
21 |
22 |
23 | /// Persistent client connection
24 | ///
25 | /// TODO(tailhook) this should include name resolution
26 | pub struct Persistent(::Address,
27 | P::Seed, Fsm)
28 | where P: Protocol, P::Socket: ActiveStream;
29 |
30 | #[derive(Debug)]
31 | pub enum Fsm {
32 | Idle,
33 | Connecting(P::Socket, Time),
34 | Established(Stream),
35 | Sleeping(Time),
36 | }
37 |
38 | fn response
(addr: ::Address,
39 | seed: P::Seed, fsm: Fsm)
40 | -> Response, Void>
41 | where P: Protocol, P::Socket: ActiveStream
42 | {
43 | use self::Fsm::*;
44 | let timeo = match *&fsm {
45 | Idle => None,
46 | Connecting(_, tm) => Some(tm),
47 | // Can't find out a timeout for established connection
48 | // some other way should be used for this case
49 | Established(..) => unreachable!(),
50 | Sleeping(tm) => Some(tm),
51 | };
52 | Response::ok(Persistent(addr, seed, fsm))
53 | .deadline_opt(timeo)
54 | }
55 |
56 | impl Persistent
57 | where P: Protocol,
58 | P::Socket: ActiveStream,
59 | ::Address: Debug
60 | {
61 | pub fn new(_scope: &mut S,
62 | address: ::Address, seed: P::Seed)
63 | -> Response, Void>
64 | {
65 | Response::ok(Persistent(address, seed, Fsm::Idle))
66 | }
67 |
68 | pub fn connect(scope: &mut S,
69 | address: ::Address, seed: P::Seed)
70 | -> Response, Void>
71 | {
72 | let fsm = match P::Socket::connect(&address) {
73 | Ok(sock) => {
74 | scope.register(&sock, EventSet::writable(), PollOpt::level())
75 | .expect("Can't register socket");
76 | Fsm::Connecting(sock, scope.after(CONNECT_TIMEOUT))
77 | }
78 | Err(e) => {
79 | info!("Failed to connect to {:?}: {}", address, e);
80 | Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
81 | }
82 | };
83 | response(address, seed, fsm)
84 | }
85 | }
86 |
87 | impl Persistent
88 | where P: Protocol, P::Socket: ActiveStream
89 | {
90 | /// Get a `Transport` object of the underlying stream
91 | ///
92 | /// This method is only useful if you want to manipulate buffers
93 | /// externally (like pushing to the buffer from another thread). Just be
94 | /// sure to **wake up** state machine after manipulating buffers.
95 | ///
96 | /// Returns `None` if stream is not currently connected
97 | pub fn transport(&mut self) -> Option> {
98 | match self.2 {
99 | Fsm::Established(ref mut s) => Some(s.transport()),
100 | _ => None,
101 | }
102 | }
103 | /// Get a `Protocol` object for the stream
104 | ///
105 | /// This method is only useful if you want to adjust protocol dysyr
106 | /// externally (like update some values after pushing data to buffer).
107 | /// Just be sure to **wake up** state machine if needed by the protocol.
108 | pub fn protocol(&mut self) -> Option<&mut P> {
109 | match self.2 {
110 | Fsm::Established(ref mut s) => Some(s.protocol()),
111 | _ => None,
112 | }
113 | }
114 | }
115 |
116 | impl Fsm
117 | where P: Protocol,
118 | P::Seed: Clone,
119 | P::Socket: ActiveStream,
120 | ::Address: Debug
121 | {
122 | fn action(resp: Response, Void>,
123 | addr: ::Address,
124 | seed: P::Seed, scope: &mut S)
125 | -> Response, Void>
126 | {
127 | if resp.is_stopped() {
128 | if let Some(err) = resp.cause() {
129 | warn!("Connection is failed: {}", err);
130 | } else {
131 | warn!("Connection is stopped by protocol");
132 | }
133 | response(addr, seed,
134 | Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT)))
135 | } else {
136 | resp
137 | .wrap(Fsm::Established)
138 | .wrap(|x| Persistent(addr, seed, x))
139 | }
140 | }
141 | }
142 |
143 | impl Machine for Persistent
144 | where P: Protocol,
145 | P::Seed: Clone,
146 | P::Socket: ActiveStream,
147 | ::Address: Debug
148 | {
149 | type Context = P::Context;
150 | type Seed = Void;
151 | fn create(seed: Self::Seed, _scope: &mut Scope)
152 | -> Response
153 | {
154 | unreachable(seed)
155 | }
156 | fn ready(self, events: EventSet, scope: &mut Scope)
157 | -> Response
158 | {
159 | use self::Fsm::*;
160 | let Persistent(addr, seed, state) = self;
161 | let state = match state {
162 | Idle => Idle, // spurious event
163 | Connecting(sock, dline) => {
164 | if events.is_writable() {
165 | let resp = Stream::connected(sock, seed.clone(), scope);
166 | if resp.is_stopped() {
167 | error!("Error creating stream FSM: {}",
168 | resp.cause().unwrap_or(&ProtocolStop));
169 | Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
170 | } else {
171 | return Fsm::action(resp, addr, seed, scope);
172 | }
173 | } else if events.is_hup() {
174 | error!("Connection closed immediately");
175 | Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
176 | } else {
177 | Connecting(sock, dline) // spurious event
178 | }
179 | }
180 | Established(x) => {
181 | return Fsm::action(x.ready(events, scope), addr, seed, scope);
182 | }
183 | Sleeping(dline) => Sleeping(dline), // spurious event
184 | };
185 | response(addr, seed, state)
186 | }
187 | fn spawned(self, _scope: &mut Scope)
188 | -> Response
189 | {
190 | unreachable!();
191 | }
192 | fn timeout(self, scope: &mut Scope)
193 | -> Response
194 | {
195 | use self::Fsm::*;
196 | let Persistent(addr, seed, state) = self;
197 | let state = match state {
198 | Idle => Idle, // spurious timeout
199 | Connecting(sock, dline) => {
200 | if scope.now() >= dline {
201 | warn!("Timeout while establishing connection");
202 | Fsm::Sleeping(scope.after(RECONNECT_TIMEOUT))
203 | } else { // spurious timeout
204 | Connecting(sock, dline)
205 | }
206 | }
207 | Established(x) => {
208 | return Fsm::action(x.timeout(scope), addr, seed, scope);
209 | }
210 | Sleeping(dline) => {
211 | if scope.now() >= dline {
212 | return Self::connect(scope, addr, seed);
213 | } else {
214 | Sleeping(dline) // spurious timeout
215 | }
216 | }
217 | };
218 | response(addr, seed, state)
219 | }
220 | fn wakeup(self, scope: &mut Scope)
221 | -> Response
222 | {
223 | use self::Fsm::*;
224 | let Persistent(addr, seed, state) = self;
225 | let state = match state {
226 | Established(x) => {
227 | return Fsm::action(x.wakeup(scope), addr, seed, scope);
228 | }
229 | x => x, // spurious wakeup
230 | };
231 | response(addr, seed, state)
232 | }
233 | }
234 |
235 | #[cfg(feature="replaceable")]
236 | mod replaceable {
237 |
238 | use std::fmt::Debug;
239 |
240 | use {ActiveStream, Protocol, Persistent};
241 | use rotor_tools::sync::Replaceable;
242 |
243 | use super::Fsm;
244 |
245 | impl Replaceable for Persistent
246 | where P: Protocol,
247 | P::Seed: Clone,
248 | ::Address: Clone + Debug,
249 | P::Socket: ActiveStream
250 | {
251 | fn empty(&self) -> Self {
252 | // We assume that cloning is cheap enough. Probably just Copy
253 | Persistent(self.0.clone(), self.1.clone(), Fsm::Idle)
254 | }
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/src/protocol.rs:
--------------------------------------------------------------------------------
1 | use std::io;
2 | use std::error::Error;
3 | use rotor::Scope;
4 |
5 | use {Transport, Intent, StreamSocket};
6 |
7 | quick_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)]
60 | pub 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 |
106 | pub 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)
114 | -> Intent;
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,
124 | end: usize, scope: &mut Scope)
125 | -> Intent;
126 |
127 | /// The action Flush is complete
128 | fn bytes_flushed(self, transport: &mut Transport,
129 | scope: &mut Scope)
130 | -> Intent;
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,
135 | scope: &mut Scope)
136 | -> Intent;
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,
152 | reason: Exception, _scope: &mut Scope)
153 | -> Intent;
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)
163 | -> Option>;
164 |
165 | /// Message received (from the main loop)
166 | fn wakeup(self, transport: &mut Transport,
167 | scope: &mut Scope)
168 | -> Intent;
169 | }
170 |
--------------------------------------------------------------------------------
/src/stream.rs:
--------------------------------------------------------------------------------
1 | use std::io;
2 | use std::error::Error;
3 | use std::io::ErrorKind::{WouldBlock, BrokenPipe, WriteZero, ConnectionReset};
4 |
5 | use rotor::{Response, Scope, Machine, EventSet, PollOpt, Time};
6 | use rotor::void::{Void, unreachable};
7 |
8 | use substr::find_substr;
9 | use extensions::{ScopeExt, ResponseExt};
10 | use {Expectation, Protocol, StreamSocket, Stream, StreamImpl};
11 | use {Buf, Transport, Accepted, Exception, Intent};
12 | use {ProtocolStop, SocketError};
13 |
14 |
15 | #[derive(Debug)]
16 | enum IoOp {
17 | Done,
18 | NoOp,
19 | Eos,
20 | Error(io::Error),
21 | }
22 |
23 | fn to_result(intent: Intent)
24 | -> Result<(P, Expectation, Option