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