dol: initial dol commit
[jump.git] / dol / src / dol / visitor / hdsd / scd / scd_out_connector.cpp
1 #include "scd_out_connector.h"
2
3 #include <assert.h>
4
5 #include "scd_logging.h"
6 #include "scd_exception.h"
7 #include "scd_command.h"
8
9
10 scd_out_connector::scd_out_connector(scd_simulator& sim, uint16_t type,
11         const std::string& name):
12     _sim(sim), _name(name),
13     _is_connecting(true), _is_connected(false), _has_connection(false)
14 {
15     // create socket
16     _socket = new scd_socket;
17     _socket->create();
18
19     // prepare register command (do not send yet)
20     scd_command* cmd = new scd_command(SCD_CM_REGISTER, type, name);
21     _writer = new scd_command_writer();
22     _writer->set_socket(*_socket);
23     _writer->queue_command(cmd);
24 }
25
26
27 scd_out_connector::~scd_out_connector()
28 {
29     close();
30     delete _writer;
31 }
32
33
34 void scd_out_connector::connect_to(const std::string& host, uint16_t port)
35 {
36     _host = host;
37     _port = port;
38
39     // register the handler to check if a connection attempt succeeded
40     _sim.get_poller().register_handler(*this, SOCK_EV_WRITE);
41
42     // start connection attempt
43     _conn_attempt();
44
45 } // connect_to()
46
47
48 bool scd_out_connector::is_connecting() { return _is_connecting; }
49
50
51 bool scd_out_connector::has_connection() { return _has_connection; }
52
53
54 scd_socket* scd_out_connector::get_connection()
55 {
56     if (_has_connection)
57     {
58         _has_connection = false;
59         return _socket;
60     }
61     else
62         return NULL;
63 }
64
65
66 void scd_out_connector::process()
67 {
68     if (_is_connecting && !_is_connected)
69     {
70         struct timeval now;
71         gettimeofday(&now, NULL);
72
73         // check if an attempt had timed out (i.e. because of "drop" FW policy)
74         if ( _socket->is_connecting() &&
75                 (now.tv_sec - _last_con.tv_sec >= SCD_CON_TIMEOUT) )
76         {
77             // close and reopen the socket
78             scd_debug("connecting to " + _host + " timed out");
79             _sim.get_poller().remove_handler(*this);
80             _socket->close();
81             _socket->create();
82             _sim.get_poller().register_handler(*this, 0);
83         }
84
85         // check if it is time to try again
86         if ( !_socket->is_connecting() && 
87                 (now.tv_sec - _last_con.tv_sec >= SCD_CON_RETRY) )
88         {
89             scd_debug("reconnecting to " + _host);
90             _conn_attempt();
91             _sim.get_poller().set_ev(*this, SOCK_EV_WRITE);
92         }
93     } // still trying to tcp-connect
94
95 } // process()
96
97
98 void scd_out_connector::close()
99 {
100     if (_is_connecting)
101     {
102         _sim.get_poller().remove_handler(*this);
103     }
104     
105     if (_is_connecting || _has_connection)
106     {
107         _socket->close();
108         delete _socket;
109
110         _is_connecting = false;
111         _has_connection = false;
112     }
113
114     _is_connected = false;
115
116 } // close()
117
118
119 const std::string& scd_out_connector::get_name() const { return _name; }
120
121
122 void scd_out_connector::handle_sock_ev(sock_ev events)
123 {
124     if (events & SOCK_EV_CLOSE)
125     {
126         // the close event is only polled if _is_connected is true
127         scd_error("outgoing connection closed");
128         close();
129         return;
130     } // end close event
131     else if (events & SOCK_EV_WRITE)
132     {
133         if (!_is_connected)
134         {
135             if (_socket->connected_event())
136             {
137                 // connection established
138                 scd_debug("ougoing connection established to " + _host);
139                 _is_connected = true;
140                 _sim.get_poller().set_ev(*this, SOCK_EV_WRITE | SOCK_EV_CLOSE);
141             }
142             else
143             {
144                 // connection attempt failed
145                 _sim.get_poller().set_ev(*this, 0);
146                 return;
147             }
148         }
149
150         assert( _is_connected || !_socket->is_connecting());
151
152         _writer->write();
153         if (!_writer->is_writing())
154         {
155             // done sending the command
156             _is_connecting = false;
157             _has_connection = true;
158             _sim.get_poller().remove_handler(*this);
159         }
160
161         if (!_socket->is_valid())
162         {
163             close();
164         }
165     } // end write event
166
167 } // handle_sock_ev()
168
169
170 const scd_socket& scd_out_connector::get_sock() { return *_socket; }
171
172
173 void scd_out_connector::_conn_attempt()
174 {
175     if (_socket->connect(_host, _port))
176     {
177         gettimeofday(&_last_con, NULL);
178     }
179     else
180     {
181         scd_error("unable to connect to " + _host);
182         close();
183     }
184
185 } // _conn_attempt()