--- /dev/null
+#include "scd_out_connector.h"
+
+#include <assert.h>
+
+#include "scd_logging.h"
+#include "scd_exception.h"
+#include "scd_command.h"
+
+
+scd_out_connector::scd_out_connector(scd_simulator& sim, uint16_t type,
+ const std::string& name):
+ _sim(sim), _name(name),
+ _is_connecting(true), _is_connected(false), _has_connection(false)
+{
+ // create socket
+ _socket = new scd_socket;
+ _socket->create();
+
+ // prepare register command (do not send yet)
+ scd_command* cmd = new scd_command(SCD_CM_REGISTER, type, name);
+ _writer = new scd_command_writer();
+ _writer->set_socket(*_socket);
+ _writer->queue_command(cmd);
+}
+
+
+scd_out_connector::~scd_out_connector()
+{
+ close();
+ delete _writer;
+}
+
+
+void scd_out_connector::connect_to(const std::string& host, uint16_t port)
+{
+ _host = host;
+ _port = port;
+
+ // register the handler to check if a connection attempt succeeded
+ _sim.get_poller().register_handler(*this, SOCK_EV_WRITE);
+
+ // start connection attempt
+ _conn_attempt();
+
+} // connect_to()
+
+
+bool scd_out_connector::is_connecting() { return _is_connecting; }
+
+
+bool scd_out_connector::has_connection() { return _has_connection; }
+
+
+scd_socket* scd_out_connector::get_connection()
+{
+ if (_has_connection)
+ {
+ _has_connection = false;
+ return _socket;
+ }
+ else
+ return NULL;
+}
+
+
+void scd_out_connector::process()
+{
+ if (_is_connecting && !_is_connected)
+ {
+ struct timeval now;
+ gettimeofday(&now, NULL);
+
+ // check if an attempt had timed out (i.e. because of "drop" FW policy)
+ if ( _socket->is_connecting() &&
+ (now.tv_sec - _last_con.tv_sec >= SCD_CON_TIMEOUT) )
+ {
+ // close and reopen the socket
+ scd_debug("connecting to " + _host + " timed out");
+ _sim.get_poller().remove_handler(*this);
+ _socket->close();
+ _socket->create();
+ _sim.get_poller().register_handler(*this, 0);
+ }
+
+ // check if it is time to try again
+ if ( !_socket->is_connecting() &&
+ (now.tv_sec - _last_con.tv_sec >= SCD_CON_RETRY) )
+ {
+ scd_debug("reconnecting to " + _host);
+ _conn_attempt();
+ _sim.get_poller().set_ev(*this, SOCK_EV_WRITE);
+ }
+ } // still trying to tcp-connect
+
+} // process()
+
+
+void scd_out_connector::close()
+{
+ if (_is_connecting)
+ {
+ _sim.get_poller().remove_handler(*this);
+ }
+
+ if (_is_connecting || _has_connection)
+ {
+ _socket->close();
+ delete _socket;
+
+ _is_connecting = false;
+ _has_connection = false;
+ }
+
+ _is_connected = false;
+
+} // close()
+
+
+const std::string& scd_out_connector::get_name() const { return _name; }
+
+
+void scd_out_connector::handle_sock_ev(sock_ev events)
+{
+ if (events & SOCK_EV_CLOSE)
+ {
+ // the close event is only polled if _is_connected is true
+ scd_error("outgoing connection closed");
+ close();
+ return;
+ } // end close event
+ else if (events & SOCK_EV_WRITE)
+ {
+ if (!_is_connected)
+ {
+ if (_socket->connected_event())
+ {
+ // connection established
+ scd_debug("ougoing connection established to " + _host);
+ _is_connected = true;
+ _sim.get_poller().set_ev(*this, SOCK_EV_WRITE | SOCK_EV_CLOSE);
+ }
+ else
+ {
+ // connection attempt failed
+ _sim.get_poller().set_ev(*this, 0);
+ return;
+ }
+ }
+
+ assert( _is_connected || !_socket->is_connecting());
+
+ _writer->write();
+ if (!_writer->is_writing())
+ {
+ // done sending the command
+ _is_connecting = false;
+ _has_connection = true;
+ _sim.get_poller().remove_handler(*this);
+ }
+
+ if (!_socket->is_valid())
+ {
+ close();
+ }
+ } // end write event
+
+} // handle_sock_ev()
+
+
+const scd_socket& scd_out_connector::get_sock() { return *_socket; }
+
+
+void scd_out_connector::_conn_attempt()
+{
+ if (_socket->connect(_host, _port))
+ {
+ gettimeofday(&_last_con, NULL);
+ }
+ else
+ {
+ scd_error("unable to connect to " + _host);
+ close();
+ }
+
+} // _conn_attempt()