+#include "scd_chan_wrapper.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include "scd_logging.h"
+
+
+scd_chan_wrapper::scd_chan_wrapper(scd_simulator& sim, const std::string& name,
+ sc_prim_channel& chan):
+ _sim(sim), _name(name), _is_initialized(false),
+ _is_writing(false), _is_reading(false)
+{
+ try
+ {
+ _chan_in = &dynamic_cast<scd_rem_chan_in_if&>(chan);
+ } catch (std::bad_cast e)
+ {
+ _chan_in = NULL;
+ }
+
+ try
+ {
+ _chan_out = &dynamic_cast<scd_rem_chan_out_if&>(chan);
+ } catch (std::bad_cast e)
+ {
+ _chan_out = NULL;
+ }
+
+ if (_chan_in == NULL && _chan_out == NULL)
+ scd_warn("channel \"" + _name + "\" is not a remote channel");
+}
+
+
+scd_chan_wrapper::~scd_chan_wrapper()
+{
+ if ( _is_initialized )
+ {
+ _sim.get_poller().remove_handler(*this);
+ _socket->close();
+ delete _socket;
+ }
+}
+
+
+bool scd_chan_wrapper::is_initialized() const { return _is_initialized; }
+
+
+const std::string& scd_chan_wrapper::get_name() const { return _name; }
+
+
+void scd_chan_wrapper::connect(scd_socket* sock)
+{
+ assert(!_is_initialized);
+
+ _socket = sock;
+ _is_initialized = true;
+
+ sock_ev flags = SOCK_EV_CLOSE;
+ if (_chan_in != NULL)
+ {
+ flags |= SOCK_EV_READ;
+ _is_reading = true;
+ }
+ _sim.get_poller().register_handler(*this, flags);
+
+} // connect()
+
+
+void scd_chan_wrapper::process()
+{
+ // check if channel has data to send
+ if (_chan_out != NULL && _is_initialized )
+ {
+ if (!_is_writing && _socket->is_valid() && _chan_out->available() > 0 )
+ {
+ // register write event
+ sock_ev events;
+ _sim.get_poller().get_ev(*this, events);
+ events |= SOCK_EV_WRITE;
+ _sim.get_poller().set_ev( *this, events );
+ _is_writing = true;
+ }
+ }
+
+ // check if channel has data to read
+ if (_chan_in != NULL && _is_initialized )
+ {
+ if (!_is_reading && _socket->is_valid() && _chan_in->free() > 0 )
+ {
+ // register read event
+ sock_ev events;
+ _sim.get_poller().get_ev(*this, events);
+ events |= SOCK_EV_READ;
+ _sim.get_poller().set_ev( *this, events );
+ _is_reading = true;
+ }
+ }
+
+} // process()
+
+
+void scd_chan_wrapper::close()
+{
+ if (_is_initialized)
+ _socket->close();
+
+} // close()
+
+
+void scd_chan_wrapper::handle_sock_ev(sock_ev events)
+{
+ if (events & SOCK_EV_CLOSE)
+ {
+ scd_debug("channel \"" + _name + "\" closed connection");
+ _sim.get_poller().set_ev(*this, 0);
+ _sim.get_cont_man().set_fail();
+ close();
+ return;
+ } // end close event
+
+ if (events & SOCK_EV_READ)
+ {
+ _read_event();
+ }
+
+ if (events & SOCK_EV_WRITE)
+ {
+ _write_event();
+ }
+
+} // handle_sock_ev()
+
+
+const scd_socket& scd_chan_wrapper::get_sock() { return *_socket; }
+
+
+void scd_chan_wrapper::_read_event()
+{
+ size_t free = _chan_in->free();
+
+ /* receive portions as long as they can be received */
+ size_t recv = 0xFF; //dummy
+ while ( free != 0 && recv != 0)
+ {
+ free = ( free < SCD_CHAN_BUFLEN ) ? free : SCD_CHAN_BUFLEN ;
+ recv = _socket->recv(_buf, free);
+ if (recv != 0)
+ _chan_in->receive(_buf, recv);
+ free = _chan_in->free();
+ }
+
+ if (free == 0)
+ {
+ sock_ev events;
+ _sim.get_poller().get_ev(*this, events);
+ events &= ~SOCK_EV_READ;
+ _sim.get_poller().set_ev(*this, events );
+ _is_reading = false;
+ return;
+ }
+
+ if (!_socket->is_valid())
+ {
+ scd_debug("channel \"" + _name + "\" closed connection");
+ _sim.get_poller().set_ev(*this, 0);
+ _sim.get_cont_man().set_fail();
+ return;
+ }
+
+} // end _read_event()
+
+
+void scd_chan_wrapper::_write_event()
+{
+ /* send portions as long as they can be sent */
+ size_t sent = 0xFF; //dummy
+ while ( sent )
+ {
+ sent = _socket->send( _chan_out->send(), _chan_out->available() );
+ if (sent != 0)
+ _chan_out->remove(sent);
+ }
+
+ if (_chan_out->available() == 0)
+ {
+ sock_ev events;
+ _sim.get_poller().get_ev(*this, events);
+ events &= ~SOCK_EV_WRITE;
+ _sim.get_poller().set_ev(*this, events );
+ _is_writing = false;
+ return;
+ }
+
+ if (!_socket->is_valid())
+ {
+ scd_debug("channel \"" + _name + "\" closed connection");
+ _sim.get_poller().set_ev(*this, 0);
+ _sim.get_cont_man().set_fail();
+ }
+}