// This method is called on acceptor side when the lost connection is detected. // A timer is scheduled to check if a new connection is created within the // passive_reconnect_duration_ period. int OpenDDS::DCPS::TcpConnection::passive_reconnect_i() { DBG_ENTRY_LVL("TcpConnection","passive_reconnect_i",6); GuardType guard(this->reconnect_lock_); // The passive_reconnect_timer_id_ is used as flag to allow the timer scheduled just once. if (this->reconnect_state_ == INIT_STATE) { // Mark the connection lost since the recv/send just failed. this->connected_ = false; if (this->tcp_config_->passive_reconnect_duration_ == 0) return -1; ACE_Time_Value timeout(this->tcp_config_->passive_reconnect_duration_/1000, this->tcp_config_->passive_reconnect_duration_%1000 * 1000); this->reconnect_state_ = PASSIVE_WAITING_STATE; this->link_->notify(DataLink::DISCONNECTED); // It is possible that the passive reconnect is called after the new connection // is accepted and the receive_strategy of this old connection is reset to nil. if (!this->receive_strategy_.is_nil()) { TcpReceiveStrategy* rs = dynamic_cast <TcpReceiveStrategy*>(this->receive_strategy_.in()); // Give a copy to reactor. this->_add_ref(); this->passive_reconnect_timer_id_ = rs->get_reactor()->schedule_timer(this, 0, timeout); if (this->passive_reconnect_timer_id_ == -1) { this->_remove_ref(); ACE_ERROR_RETURN((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: TcpConnection::passive_reconnect_i") ACE_TEXT(", %p.\n"), ACE_TEXT("schedule_timer")), -1); } } } return 0; }
/// This object would be "old" connection object and the provided is the new /// connection object. The "old" connection object will copy its states to /// to the "new" connection object. This is called by the TcpDataLink /// when a new connection is accepted (with a new TcpConnection object). /// We need make the state in "new" connection object consistent with the "old" /// connection object. void OpenDDS::DCPS::TcpConnection::transfer(TcpConnection* connection) { DBG_ENTRY_LVL("TcpConnection","transfer",6); GuardType guard(this->reconnect_lock_); bool notify_reconnect = false; switch (this->reconnect_state_) { case INIT_STATE: // We have not detected the lost connection and the peer is faster than us and // re-established the connection. so do not notify reconnected. break; case LOST_STATE: // The reconnect timed out. case PASSIVE_TIMEOUT_CALLED_STATE: // TODO: If the handle_timeout is called before the old connection // transfer its state to new connection then should we disconnect // the new connection or keep it alive ? // I think we should keep the connection, the user will get a // lost connection notification and then a reconnected notification. notify_reconnect = true; break; case PASSIVE_WAITING_STATE: { TcpReceiveStrategy* rs = dynamic_cast <TcpReceiveStrategy*>(this->receive_strategy_.in()); // Cancel the timer since we got new connection. if (rs->get_reactor()->cancel_timer(this) == -1) { ACE_ERROR((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: TcpConnection::transfer, ") ACE_TEXT(" %p. \n"), ACE_TEXT("cancel_timer"))); } else passive_reconnect_timer_id_ = -1; this->_remove_ref(); notify_reconnect = true; } break; default : ACE_ERROR((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: TcpConnection::transfer, ") ACE_TEXT(" unknown state or it should not be in state=%d \n"), this->reconnect_state_)); break; } // Verify if this acceptor side. if (this->is_connector_ || connection->is_connector_) { ACE_ERROR((LM_ERROR, ACE_TEXT("(%P|%t) ERROR: TcpConnection::transfer, ") ACE_TEXT(" should NOT be called by the connector side \n"))); } this->reconnect_task_.close(1); connection->receive_strategy_ = this->receive_strategy_; connection->send_strategy_ = this->send_strategy_; connection->remote_address_ = this->remote_address_; connection->local_address_ = this->local_address_; connection->tcp_config_ = this->tcp_config_; connection->link_ = this->link_; VDBG((LM_DEBUG, "(%P|%t) DBG: " "transfer(%C:%d->%C:%d) passive reconnected. new con %@ " " old con %@ \n", this->remote_address_.get_host_addr(), this->remote_address_.get_port_number(), this->local_address_.get_host_addr(), this->local_address_.get_port_number(), connection, this)); if (notify_reconnect) { this->reconnect_state_ = RECONNECTED_STATE; this->link_->notify(DataLink::RECONNECTED); } }