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