dol: initial dol commit
[jump.git] / dol / src / dol / visitor / hdsd / scd / scd_out_connector.cpp
diff --git a/dol/src/dol/visitor/hdsd/scd/scd_out_connector.cpp b/dol/src/dol/visitor/hdsd/scd/scd_out_connector.cpp
new file mode 100644 (file)
index 0000000..999a423
--- /dev/null
@@ -0,0 +1,185 @@
+#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()