+#include "scd_cont_man_slave.h"
+
+#include "scd_logging.h"
+#include "scd_exception.h"
+
+
+scd_cont_man_slave::scd_cont_man_slave(scd_simulator& sim):
+ scd_cont_fsm("slave"), _sim(sim),
+ _connector(sim, SCD_CM_NETSIM, sim.get_name()), _has_master(false),
+ _st_init(sim, *this), _st_busy(sim, *this), _st_fail(sim, *this),
+ _st_failed(sim, *this), _st_idle(sim, *this), _st_done(sim, *this),
+ _st_time_ack(sim, *this), _st_time(sim, *this), _st_term_ack(sim, *this),
+ _st_terminated(sim, *this)
+{
+ // set initial state
+ set_state(_st_init);
+}
+
+
+scd_cont_man_slave::~scd_cont_man_slave()
+{
+ if (_socket != NULL)
+ delete _socket;
+}
+
+
+void scd_cont_man_slave::set_socket()
+{
+ _socket = _connector.get_connection();
+ _writer.set_socket(*_socket);
+ _reader.set_socket(*_socket);
+} // set_socket()
+
+
+void scd_cont_man_slave::send_command(scd_command* cmd)
+{
+ // register write event if not registered
+ if (!_writer.is_writing() && _socket->is_valid())
+ _sim.get_poller().set_ev(*this, SOCK_EV_WRITE | SOCK_EV_READ
+ | SOCK_EV_CLOSE);
+
+ // queue command to be written
+ _writer.queue_command(cmd);
+}
+
+
+bool scd_cont_man_slave::is_sending()
+{
+ return _writer.is_writing() && _socket->is_valid();
+}
+
+
+void scd_cont_man_slave::close()
+{
+ if (_socket != NULL)
+ _socket->close();
+}
+
+
+void scd_cont_man_slave::set_master(const std::string& host, uint16_t port)
+{
+ if (!_has_master)
+ _connector.connect_to(host, port);
+ else
+ {
+ scd_error("master already set");
+ throw scd_exception("master already set");
+ }
+} // set_master()
+
+
+void scd_cont_man_slave::register_slave(const std::string& name)
+{
+ scd_error("simulator is slave, can not have other slaves");
+ throw scd_exception("simulator is slave");
+
+} // register_slave
+
+
+void scd_cont_man_slave::handle_sock_ev(sock_ev events)
+{
+ scd_sts_base& state = *static_cast<scd_sts_base*>(_state);
+
+ if (events & SOCK_EV_CLOSE)
+ {
+ scd_error("connection to master lost");
+ _socket->close();
+ state.set_failed();
+ return;
+ }
+
+ if (events & SOCK_EV_READ)
+ {
+ _reader.read();
+
+ if (!_socket->is_valid())
+ {
+ // connection closed
+ scd_error("connection to master lost");
+ state.set_failed();
+ return;
+ }
+
+ if (!_reader.is_reading() && !_reader.has_command())
+ {
+ // received an illegal command
+ scd_error("received illegal command");
+ state.set_fail();
+ return;
+ }
+
+ if (_reader.has_command())
+ {
+ scd_command* cmd = _reader.get_command();
+ _process_cmd(*cmd);
+ delete cmd;
+ }
+
+ } // end read event
+
+ if (events & SOCK_EV_WRITE)
+ {
+ _writer.write();
+ if (!_writer.is_writing())
+ {
+ // done sending commands
+ _sim.get_poller().set_ev(*this, SOCK_EV_READ | SOCK_EV_CLOSE);
+ }
+ } // end write event
+
+ if (!_socket->is_valid())
+ {
+ scd_error("connection to master lost");
+ state.set_failed();
+ }
+
+} // handle_sock_ev()
+
+
+const scd_socket& scd_cont_man_slave::get_sock() { return *_socket; }
+
+
+void scd_cont_man_slave::_process_cmd(scd_command& cmd)
+{
+ if (cmd.get_type() != SCD_CM_CONTROL)
+ {
+ scd_warn("received non-control command");
+ return;
+ }
+
+ scd_sts_base* state = static_cast<scd_sts_base*>(_state);
+
+ switch (cmd.get_subtype())
+ {
+ case SCD_CM_FAILED:
+ scd_error("master failed");
+ state->set_failed();
+ break;
+ case SCD_CM_TIME_REQ:
+ state->recv_time_req();
+ break;
+ case SCD_CM_TIME_NACK:
+ state->recv_time_nack();
+ break;
+ case SCD_CM_TIME:
+ state->recv_time(cmd.get_time());
+ break;
+ case SCD_CM_TERM_REQ:
+ state->recv_term_req();
+ break;
+ case SCD_CM_TERM_NACK:
+ state->recv_term_nack();
+ break;
+ case SCD_CM_TERM:
+ state->recv_term();
+ break;
+ default:
+ scd_warn("received unknown command");
+ break;
+ }
+} // _process_cmd()