| @@ -372,7 +372,7 @@ macro_rules! conn_response { | |||||||
|             } |             } | ||||||
|             None => { |             None => { | ||||||
|                 if let Some((key, socket)) = $scope.awaiting_slot.pop_front() { |                 if let Some((key, socket)) = $scope.awaiting_slot.pop_front() { | ||||||
|                     rotor_try!($scope.register(&socket, EventSet::writable(), PollOpt::level())); |                     rotor_try!($scope.register(&socket, EventSet::writable() | EventSet::hup(), PollOpt::level())); | ||||||
|                     rotor::Response::ok(ClientFsm::Connecting((key, socket))) |                     rotor::Response::ok(ClientFsm::Connecting((key, socket))) | ||||||
|                 } else { |                 } else { | ||||||
|                     rotor::Response::done() |                     rotor::Response::done() | ||||||
| @@ -460,7 +460,7 @@ where C: Connect, | |||||||
|     type Seed = (C::Key, C::Output); |     type Seed = (C::Key, C::Output); | ||||||
|  |  | ||||||
|     fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> { |     fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> { | ||||||
|         rotor_try!(scope.register(&seed.1, EventSet::writable(), PollOpt::level())); |         rotor_try!(scope.register(&seed.1, EventSet::writable() | EventSet::hup(), PollOpt::level())); | ||||||
|         rotor::Response::ok(ClientFsm::Connecting(seed)) |         rotor::Response::ok(ClientFsm::Connecting(seed)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -483,11 +483,11 @@ where C: Connect, | |||||||
|                     if let Some(err) = seed.1.take_socket_error().err() { |                     if let Some(err) = seed.1.take_socket_error().err() { | ||||||
|                         debug!("error while connecting: {:?}", err); |                         debug!("error while connecting: {:?}", err); | ||||||
|                         scope.pop_queue(&seed.0).map(move |mut queued| queued.handler.on_error(::Error::Io(err))); |                         scope.pop_queue(&seed.0).map(move |mut queued| queued.handler.on_error(::Error::Io(err))); | ||||||
|                         rotor::Response::done() |  | ||||||
|                     } else { |                     } else { | ||||||
|                         trace!("connecting is_error, but no socket error"); |                         trace!("connecting is_error, but no socket error"); | ||||||
|                         rotor::Response::ok(ClientFsm::Connecting(seed)) |  | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  |                     rotor::Response::done() | ||||||
|                 } else if events.is_writable() { |                 } else if events.is_writable() { | ||||||
|                     if scope.queue.contains_key(&seed.0) { |                     if scope.queue.contains_key(&seed.0) { | ||||||
|                         trace!("connected and writable {:?}", seed.0); |                         trace!("connected and writable {:?}", seed.0); | ||||||
| @@ -541,6 +541,7 @@ where C: Connect, | |||||||
|  |  | ||||||
|                 // Check all idle connections regardless of origin |                 // Check all idle connections regardless of origin | ||||||
|                 for (key, idle) in scope.idle_conns.iter_mut() { |                 for (key, idle) in scope.idle_conns.iter_mut() { | ||||||
|  |                     // Pop from the front since those are lease recently used | ||||||
|                     while let Some(ctrl) = idle.pop_front() { |                     while let Some(ctrl) = idle.pop_front() { | ||||||
|                         // Signal connection to close. An err here means the |                         // Signal connection to close. An err here means the | ||||||
|                         // socket is already dead can should be tossed. |                         // socket is already dead can should be tossed. | ||||||
| @@ -667,7 +668,9 @@ where C: Connect, | |||||||
|                                 let mut remove_idle = false; |                                 let mut remove_idle = false; | ||||||
|                                 let mut woke_up = false; |                                 let mut woke_up = false; | ||||||
|                                 if let Some(mut idle) = scope.idle_conns.get_mut(&key) { |                                 if let Some(mut idle) = scope.idle_conns.get_mut(&key) { | ||||||
|                                     while let Some(ctrl) = idle.pop_front() { |                                     // Pop from back since those are most recently used. Connections | ||||||
|  |                                     // at the front are allowed to expire. | ||||||
|  |                                     while let Some(ctrl) = idle.pop_back() { | ||||||
|                                         // err means the socket has since died |                                         // err means the socket has since died | ||||||
|                                         if ctrl.ready(Next::write()).is_ok() { |                                         if ctrl.ready(Next::write()).is_ok() { | ||||||
|                                             woke_up = true; |                                             woke_up = true; | ||||||
|   | |||||||
| @@ -37,6 +37,10 @@ struct ConnInner<K: Key, T: Transport, H: MessageHandler<T>> { | |||||||
|     key: K, |     key: K, | ||||||
|     state: State<H, T>, |     state: State<H, T>, | ||||||
|     transport: T, |     transport: T, | ||||||
|  |     /// Records a WouldBlock error when trying to read | ||||||
|  |     /// | ||||||
|  |     /// This flag is used to prevent busy looping | ||||||
|  |     read_would_block: bool, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl<K: Key, T: Transport, H: MessageHandler<T>> fmt::Debug for ConnInner<K, T, H> { | impl<K: Key, T: Transport, H: MessageHandler<T>> fmt::Debug for ConnInner<K, T, H> { | ||||||
| @@ -153,7 +157,10 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|                     Ok(head) => head, |                     Ok(head) => head, | ||||||
|                     Err(::Error::Io(e)) => match e.kind() { |                     Err(::Error::Io(e)) => match e.kind() { | ||||||
|                         io::ErrorKind::WouldBlock | |                         io::ErrorKind::WouldBlock | | ||||||
|                         io::ErrorKind::Interrupted => return state, |                         io::ErrorKind::Interrupted => { | ||||||
|  |                             self.read_would_block = true; | ||||||
|  |                             return state; | ||||||
|  |                         }, | ||||||
|                         _ => { |                         _ => { | ||||||
|                             debug!("io error trying to parse {:?}", e); |                             debug!("io error trying to parse {:?}", e); | ||||||
|                             return State::Closed; |                             return State::Closed; | ||||||
| @@ -236,6 +243,30 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|  |             State::Init { interest: Next_::Wait, .. } => { | ||||||
|  |                 match self.buf.read_from(&mut self.transport) { | ||||||
|  |                     Ok(0) => { | ||||||
|  |                         // End-of-file; connection was closed by peer | ||||||
|  |                         State::Closed | ||||||
|  |                     }, | ||||||
|  |                     Ok(n) => { | ||||||
|  |                         // Didn't expect bytes here! Close the connection. | ||||||
|  |                         warn!("read {} bytes in State::Init with Wait interest", n); | ||||||
|  |                         State::Closed | ||||||
|  |                     }, | ||||||
|  |                     Err(e) => match e.kind() { | ||||||
|  |                         io::ErrorKind::WouldBlock => { | ||||||
|  |                             // This is the expected case reading in this state | ||||||
|  |                             self.read_would_block = true; | ||||||
|  |                             state | ||||||
|  |                         }, | ||||||
|  |                         _ => { | ||||||
|  |                             warn!("socket error reading State::Init with Wait interest: {}", e); | ||||||
|  |                             State::Closed | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|             State::Init { .. } => { |             State::Init { .. } => { | ||||||
|                 trace!("on_readable State::{:?}", state); |                 trace!("on_readable State::{:?}", state); | ||||||
|                 state |                 state | ||||||
| @@ -265,7 +296,10 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|                         }, |                         }, | ||||||
|                         Err(::Error::Io(e)) => match e.kind() { |                         Err(::Error::Io(e)) => match e.kind() { | ||||||
|                             io::ErrorKind::WouldBlock | |                             io::ErrorKind::WouldBlock | | ||||||
|                             io::ErrorKind::Interrupted => None, |                             io::ErrorKind::Interrupted => { | ||||||
|  |                                 self.read_would_block = true; | ||||||
|  |                                 None | ||||||
|  |                             }, | ||||||
|                             _ => { |                             _ => { | ||||||
|                                 debug!("io error trying to parse {:?}", e); |                                 debug!("io error trying to parse {:?}", e); | ||||||
|                                 return State::Closed; |                                 return State::Closed; | ||||||
| @@ -459,10 +493,15 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn can_read_more(&self, was_init: bool) -> bool { |     fn can_read_more(&self, was_init: bool) -> bool { | ||||||
|         match self.state { |         let transport_blocked = self.transport.blocked().is_some(); | ||||||
|  |         let read_would_block = self.read_would_block; | ||||||
|  |  | ||||||
|  |         let state_machine_ok = match self.state { | ||||||
|             State::Init { .. } => !was_init && !self.buf.is_empty(), |             State::Init { .. } => !was_init && !self.buf.is_empty(), | ||||||
|             _ => !self.buf.is_empty() |             _ => !self.buf.is_empty() | ||||||
|         } |         }; | ||||||
|  |  | ||||||
|  |         !transport_blocked && !read_would_block && state_machine_ok | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn on_error<F>(&mut self, err: ::Error, factory: &F) where F: MessageHandlerFactory<K, T> { |     fn on_error<F>(&mut self, err: ::Error, factory: &F) where F: MessageHandlerFactory<K, T> { | ||||||
| @@ -478,6 +517,8 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> ConnInner<K, T, H> { | |||||||
|  |  | ||||||
|     fn on_readable<F>(&mut self, scope: &mut Scope<F>) |     fn on_readable<F>(&mut self, scope: &mut Scope<F>) | ||||||
|     where F: MessageHandlerFactory<K, T, Output=H> { |     where F: MessageHandlerFactory<K, T, Output=H> { | ||||||
|  |         // Clear would_block flag so state is clear going into read | ||||||
|  |         self.read_would_block = false; | ||||||
|         trace!("on_readable -> {:?}", self.state); |         trace!("on_readable -> {:?}", self.state); | ||||||
|         let state = mem::replace(&mut self.state, State::Closed); |         let state = mem::replace(&mut self.state, State::Closed); | ||||||
|         self.state = self.read(scope, state); |         self.state = self.read(scope, state); | ||||||
| @@ -526,6 +567,7 @@ impl<K: Key, T: Transport, H: MessageHandler<T>> Conn<K, T, H> { | |||||||
|                 timeout_start: Some(now), |                 timeout_start: Some(now), | ||||||
|             }, |             }, | ||||||
|             transport: transport, |             transport: transport, | ||||||
|  |             read_would_block: false, | ||||||
|         })) |         })) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user