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