]> git.tdb.fi Git - r2c2.git/blob - server.cpp
c9a56e39b243d7673d15c80259d4410658aabe8f
[r2c2.git] / server.cpp
1 #include <msp/net/inet.h>
2 #include "libr2c2/driver.h"
3 #include "libr2c2/route.h"
4 #include "libr2c2/train.h"
5 #include "libr2c2/vehicletype.h"
6 #include "server.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 namespace R2C2 {
12
13 Server::Server(Layout &l):
14         layout(l),
15         listen_sock(Net::INET),
16         event_disp(0)
17 {
18         layout.get_driver().signal_power.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
19         layout.get_driver().signal_halt.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
20         layout.signal_emergency.connect(sigc::mem_fun(this, &Server::emergency));
21
22         layout.signal_train_added.connect(sigc::mem_fun(this, &Server::train_added));
23
24         const map<unsigned, Train *> &trains = layout.get_trains();
25         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
26                 train_added(*i->second);
27
28         listen_sock.listen(Net::InetAddr(0, 8315), 4);
29         listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection));
30 }
31
32 void Server::use_event_dispatcher(IO::EventDispatcher &ed)
33 {
34         event_disp = &ed;
35         event_disp->add(listen_sock);
36 }
37
38 void Server::incoming_connection()
39 {
40         Net::StreamSocket *sock = listen_sock.accept();
41         if(event_disp)
42                 event_disp->add(*sock);
43         connections.push_back(new Connection(*this, sock));
44 }
45
46 void Server::driver_state_changed()
47 {
48         DriverStatePacket pkt;
49         pkt.power = layout.get_driver().get_power();
50         pkt.halt = layout.get_driver().is_halted();
51         send(pkt);
52 }
53
54 void Server::emergency(const string &msg)
55 {
56         EmergencyPacket pkt;
57         pkt.message = msg;
58         send(pkt);
59 }
60
61 void Server::train_added(Train &train)
62 {
63         train.signal_control_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_control_changed), sigc::ref(train)));
64         train.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train)));
65         train.signal_route_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_route_changed), sigc::ref(train)));
66         train.signal_status_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train)));
67
68         TrainInfoPacket pkt;
69         pkt.address = train.get_address();
70         pkt.loco_type = train.get_locomotive_type().get_article_number().str();
71         pkt.name = train.get_name();
72         send(pkt);
73
74         TrainStatus *status = new TrainStatus(train);
75         status->set_tag("server:status");
76         status->signal_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_status_changed), sigc::ref(train)));
77 }
78
79 void Server::train_control_changed(const Train &train, const string &control, float value)
80 {
81         TrainControlPacket pkt;
82         pkt.address = train.get_address();
83         pkt.control = control;
84         pkt.value = value;
85         send(pkt);
86 }
87
88 void Server::train_function_changed(const Train &train, unsigned, bool)
89 {
90         TrainFunctionPacket pkt;
91         pkt.address = train.get_address();
92         pkt.functions = train.get_functions();
93         send(pkt);
94 }
95
96 void Server::train_route_changed(const Train &train, const Route *route)
97 {
98         TrainRoutePacket pkt;
99         pkt.address = train.get_address();
100         if(route)
101                 pkt.route = route->get_name();
102         send(pkt);
103 }
104
105 void Server::train_status_changed(const Train &train, const string &status)
106 {
107         TrainStatusPacket pkt;
108         pkt.address = train.get_address();
109         pkt.status = status;
110         send(pkt);
111 }
112
113 template<typename P>
114 void Server::send(const P &pkt)
115 {
116         for(vector<Connection *>::const_iterator i=connections.begin(); i!=connections.end(); ++i)
117                 if(!(*i)->stale && (*i)->comm.is_handshake_done())
118                 {
119                         try
120                         {
121                                 (*i)->comm.send(pkt);
122                         }
123                         catch(...)
124                         {
125                                 (*i)->stale = true;
126                         }
127                 }
128 }
129
130
131 Server::Connection::Connection(Server &s, Net::StreamSocket *o):
132         server(s),
133         socket(o),
134         comm(*socket, server.proto, *this)
135 {
136         socket->signal_end_of_file.connect(sigc::mem_fun(this, &Connection::end_of_file));
137         comm.signal_handshake_done.connect(sigc::mem_fun(this, &Connection::handshake_done));
138         comm.initiate_handshake();
139 }
140
141 Server::Connection::~Connection()
142 {
143         delete socket;
144 }
145
146 void Server::Connection::handshake_done()
147 {
148         {
149                 DriverStatePacket pkt;
150                 pkt.power = server.layout.get_driver().get_power();
151                 pkt.halt = server.layout.get_driver().is_halted();
152                 comm.send(pkt);
153         }
154
155         const set<Route *> &routes = server.layout.get_routes();
156         for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
157                 if(!(*i)->is_temporary())
158                 {
159                         RouteInfoPacket pkt;
160                         pkt.name = (*i)->get_name();
161                         comm.send(pkt);
162                 }
163
164         const map<unsigned, Train *> &trains = server.layout.get_trains();
165         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
166         {
167                 const Train &train = *i->second;
168
169                 {
170                         TrainInfoPacket pkt;
171                         pkt.address = train.get_address();
172                         pkt.loco_type = train.get_locomotive_type().get_article_number().str();
173                         pkt.name = train.get_name();
174                         comm.send(pkt);
175                 }
176                 for(unsigned j=0;; ++j)
177                 {
178                         const char *name = train.get_controller().enumerate_controls(j);
179                         if(!name)
180                                 break;
181
182                         TrainControlPacket pkt;
183                         pkt.address = train.get_address();
184                         pkt.control = name;
185                         pkt.value = train.get_control(name);
186                         comm.send(pkt);
187                 }
188                 {
189                         TrainFunctionPacket pkt;
190                         pkt.address = train.get_address();
191                         pkt.functions = train.get_functions();
192                         comm.send(pkt);
193                 }
194                 if(TrainStatus *status = dynamic_cast<TrainStatus *>(train.get_tagged_ai("server:status")))
195                 {
196                         TrainStatusPacket pkt;
197                         pkt.address = train.get_address();
198                         pkt.status = status->get_status();
199                         comm.send(pkt);
200                 }
201                 if(train.get_route())
202                 {
203                         TrainRoutePacket pkt;
204                         pkt.address = train.get_address();
205                         pkt.route = train.get_route()->get_name();
206                         comm.send(pkt);
207                 }
208         }
209 }
210
211 void Server::Connection::end_of_file()
212 {
213         socket->close();
214         stale = true;
215 }
216
217 void Server::Connection::receive(const DriverStatePacket &pkt)
218 {
219         Driver &driver = server.layout.get_driver();
220         if(pkt.power!=driver.get_power())
221                 driver.set_power(pkt.power);
222         if(pkt.halt!=driver.is_halted())
223                 driver.halt(pkt.halt);
224 }
225
226 void Server::Connection::receive(const TrainControlPacket &pkt)
227 {
228         try
229         {
230                 Train &train = server.layout.get_train(pkt.address);
231                 train.set_control(pkt.control, pkt.value);
232         }
233         catch(const Exception &e)
234         {
235                 error(e.what());
236         }
237 }
238
239 void Server::Connection::receive(const TrainFunctionPacket &pkt)
240 {
241         try
242         {
243                 Train &train = server.layout.get_train(pkt.address);
244                 for(unsigned i=0; i<9; ++i)
245                         if(((pkt.functions^train.get_functions())>>i)&1)
246                                 train.set_function(i, (pkt.functions>>i)&1);
247         }
248         catch(const Exception &e)
249         {
250                 error(e.what());
251         }
252 }
253
254 void Server::Connection::receive(const TrainRoutePacket &pkt)
255 {
256         try
257         {
258                 Train &train = server.layout.get_train(pkt.address);
259                 if(pkt.route.empty())
260                         train.set_route(0);
261                 else
262                 {
263                         Route &route = server.layout.get_route(pkt.route);
264                         train.set_route(&route);
265                 }
266         }
267         catch(const Exception &e)
268         {
269                 error(e.what());
270         }
271 }
272
273 void Server::Connection::error(const string &msg)
274 {
275         ErrorPacket pkt;
276         pkt.message = msg;
277         comm.send(pkt);
278 }
279
280 } // namespace R2C2