]> git.llucax.com Git - z.facultad/75.42/plaqui.git/blob - Server/src/server.cpp
Se pasa la conexion suicida al finish del TCPServer para que sea 'transparente'.
[z.facultad/75.42/plaqui.git] / Server / src / server.cpp
1 // vim: set noexpandtab tabstop=4 shiftwidth=4:
2 //----------------------------------------------------------------------------
3 //                                  PlaQui
4 //----------------------------------------------------------------------------
5 // This file is part of PlaQui.
6 //
7 // PlaQui is free software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the Free Software
9 // Foundation; either version 2 of the License, or (at your option) any later
10 // version.
11 //
12 // PlaQui is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 // details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with PlaQui; if not, write to the Free Software Foundation, Inc., 59 Temple
19 // Place, Suite 330, Boston, MA  02111-1307  USA
20 //----------------------------------------------------------------------------
21 // Creado:  Sat Oct 18 18:18:36 2003
22 // Autores: Leandro Lucarella <llucare@fi.uba.ar>
23 //----------------------------------------------------------------------------
24 //
25 // $Id$
26 //
27
28 #include "plaqui/server/server.h"
29 #include "plaqui/server/connection.h"
30 #include "plaqui/server/controlserver.h"
31 #include <sigc++/class_slot.h>
32 #include <glibmm/timer.h>
33 #include <sstream>
34 #include <exception>
35 #ifdef DEBUG
36 #       include "plaqui/server/string.h"
37 #       include <iostream>
38 #endif // DEBUG
39
40 using namespace std;
41
42 namespace PlaQui {
43
44 namespace Server {
45
46 Server::~Server(void) {
47 #ifdef DEBUG
48         cerr << __FILE__ << "(" << __LINE__ << ")"
49                 <<  ": destructor." << endl;
50 #endif // DEBUG
51         // Mando a terminar todas las plantas.
52         plants_mutex.lock();
53         for (PlantList::iterator i = plants.begin(); i != plants.end(); i++) {
54                 i->second->finish();
55         }
56         PlantList::size_type count = plants.size();
57         plants_mutex.unlock();
58         // Espero que terminen realmente.
59         while (count) {
60                 Glib::usleep(10000); // 10 milisegundos
61                 plants_mutex.lock();
62                 count = plants.size();
63                 plants_mutex.unlock();
64         }
65 }
66
67 Server::Server(const string& plant_filename, const Connection::Port& port)
68                 throw(sockerr): TCPServer(port) {
69 #ifdef DEBUG
70         cerr << __FILE__ << "(" << __LINE__ << ")"
71                 <<  ": port = " << port << endl;
72 #endif // DEBUG
73         // FIXME - hacer que se puedan cargar mas plantas bien.
74         Glib::Mutex::Lock lock(plants_mutex);
75         plants["default"] = new Plant(plant_filename);
76         plants["default"]->signal_finished().connect(
77                         SigC::bind<const char*>(
78                                 SigC::slot_class(*this, &Server::on_plant_finished),
79                                 "default"));
80         plants["default"]->run();
81 }
82
83 Connection* Server::new_connection(const sockbuf::sockdesc& sd) {
84 #ifdef DEBUG
85         cerr << __FILE__ << "(" << __LINE__ << ")"
86                 <<  ": new_connection(sd = " << sd.sock << ")"
87                 << endl;
88 #endif // DEBUG
89         ControlServer* connection = new ControlServer(sd);
90         // TODO verificar si el new se hace bien? no creo.
91         connection->signal_command_received().connect(
92                         SigC::bind<ControlServer*>(
93                                 SigC::slot_class(*this, &Server::on_control_command_received),
94                                 connection));
95         // TODO: 
96         return connection;
97 }
98
99 void Server::on_plant_finished(const char* plant) {
100 #ifdef DEBUG
101         cerr << __FILE__ << "(" << __LINE__ << ")"
102                 <<  ": on_plant_finished(plant_name = " << plant << endl;
103 #endif // DEBUG
104         Glib::Mutex::Lock lock(plants_mutex);
105         plants.erase(plant);
106 }
107
108 /// \todo Terminar de implementar.
109 void Server::on_control_command_received(const Command& command,
110                 ControlServer* controlserver) {
111 #ifdef DEBUG
112         cerr << __FILE__ << "(" << __LINE__ << ")"
113                 <<  ": on_control_command_received(target = "
114                 << command.get_target() << ", command = " << command.get_command()
115                 << ", args = [" << String::join(command.get_args(), ", ") << "])"
116                 << endl;
117 #endif // DEBUG
118         HTTPResponse* response;
119         //bool stop_controlserver = false;
120         if (command.get_target() == "server") {
121                 if (command.get_command() == "status") {
122                         response = cmd_server_status();
123                 } else if (command.get_command() == "stop") {
124                         response = new HTTPResponse(HTTPMessage::OK,
125                                         "<response desc=\"El server se apagará en instantes...\" />");
126                         // XXX - Sin mandar la respuesta enseguida podría ser que el server
127                         // cierre la conexión antes de mandar la respuesta.
128                         //response->headers["Content-Type"] = "text/xml; charset=iso-8859-1";
129                         //controlserver->send(*response);
130                         //delete response;
131                         finish();
132                         //return;
133                 } else {
134                         response = new HTTPResponse(HTTPMessage::NOT_FOUND,
135                                         "<response desc=\"Invalid command for 'server' taget!\" />");
136                 }
137         } else if (command.get_target() == "connection") {
138                 if (command.get_command() == "list") {
139                         response = cmd_connection_list();
140                 } else if (command.get_command() == "stop") {
141                         response = cmd_connection_stop(command);
142                 } else {
143                         response = new HTTPResponse(HTTPMessage::NOT_FOUND,
144                                         "<response desc=\"Invalid command for 'connection' taget!\" />");
145                 }
146         } else if (command.get_target() == "transmission") {
147                 if (command.get_command() == "list") {
148                         response = cmd_transmission_list();
149                 } else if (command.get_command() == "start") {
150                         response = cmd_transmission_start(command);
151                 } else if (command.get_command() == "stop") {
152                         response = cmd_transmission_stop(command);
153                 } else {
154                         response = new HTTPResponse(HTTPMessage::NOT_FOUND,
155                                         "<response desc=\"Invalid command for 'transmission' taget!\" />");
156                 }
157         } else if (command.get_target() == "plant") {
158                 if (command.get_command() == "list") {
159                         response = cmd_plant_list();
160                 } else if (command.get_command() == "get") {
161                         response = cmd_plant_get(command);
162                 } else if (command.get_command() == "set") {
163                         response = cmd_plant_set(command);
164                 } else if (command.get_command() == "stop") {
165                         response = cmd_plant_stop(command);
166                 } else {
167                         response = new HTTPResponse(HTTPMessage::NOT_FOUND,
168                                         "<response desc=\"Invalid command for 'plant' taget!\" />");
169                 }
170         } else {
171                 response = new HTTPResponse(HTTPMessage::NOT_FOUND,
172                                 "<response desc=\"Invalid taget!\" />");
173         }
174         // FIXME
175         response->headers["Content-Type"] = "text/xml; charset=iso-8859-1";
176         //response->headers["Connection"] = "close";
177         controlserver->send(*response);
178         delete response;
179         // FIXME con timeout no debería ser necesario. Verificar cabecera Connection
180         // para saber si hay que finish()earlo o no.
181         //if (stop_controlserver) {
182         //      controlserver->finish();
183         //}
184 }
185
186 HTTPResponse* Server::cmd_server_status(void) const {
187         // FIXME
188         stringstream xml;
189         xml << "<serverstatus>" << endl;
190         xml << "\t<version>" VERSION "</version>" << endl;
191         xml << "\t<authors>" << endl;
192         xml << "\t\t<author>Nicolás Dimov</author>" << endl;
193         xml << "\t\t<author>Leandro Lucarella</author>" << endl;
194         xml << "\t\t<author>Ricardo Markiewicz</author>" << endl;
195         xml << "\t</authors>" << endl;
196         xml << "</serverstatus>" << endl;
197         return new HTTPResponse(HTTPMessage::OK, xml.str());
198 }
199
200 HTTPResponse* Server::cmd_connection_list(void) {
201         // FIXME
202         TCPServer::ConnectionInfoList cil = get_connected();
203         stringstream xml;
204         xml << "<list type=\"connection\">" << endl;
205         for (TCPServer::ConnectionInfoList::const_iterator i = cil.begin();
206                         i != cil.end(); i++) {
207                 xml << "\t<row>" << endl;
208                 xml << "\t\t<cell>" << i->host << "</cell>" << endl;
209                 xml << "\t\t<cell>" << i->port << "</cell>" << endl;
210                 xml << "\t</row>" << endl;
211         }
212         xml << "</list>" << endl;
213         return new HTTPResponse(HTTPMessage::OK, xml.str());
214 }
215
216 HTTPResponse* Server::cmd_connection_stop(const Command& command) {
217         const Command::Arguments& args = command.get_args();
218         Connection::Port port;
219         if (args.size() < 2) {
220                 return new HTTPResponse(HTTPMessage::CONFLICT,
221                                 "<response desc=\"Faltan argumentos.\" />");
222         } else if (disconnect(args[0], to(args[1], port))) {
223                 return new HTTPResponse(HTTPMessage::OK,
224                                 string("<response desc=\"La conexión a ") + args[0] + ":" + args[1]
225                                 + " se cerrará en instantes...\" />");
226         } else {
227                 return new HTTPResponse(HTTPMessage::NOT_FOUND,
228                                 string("<response desc=\"No existe una conexión a ") + args[0]
229                                 + ":" + args[1] + "\" />");
230         }
231 }
232
233 HTTPResponse* Server::cmd_transmission_list(void) {
234         // FIXME
235         stringstream xml;
236         xml << "<list type=\"transmission\">" << endl;
237 /*TODO  plants_mutex.lock();
238         for (PlantList::const_iterator i = plants.begin();
239                         i != plants.end(); i++) {
240                 trans
241                 xml << "       <li>" << (*i)->get_host() << ":"
242                         << (*i)->get_port() << " [<a href=\"/transmission/stop/"
243                         << (*i)->get_host() << "/" << (*i)->get_port()
244                         << "\">desconectar</a>]</li>" << endl;
245         }
246         transmissions_mutex.unlock();*/
247         xml << "</list>" << endl;
248         return new HTTPResponse(HTTPMessage::OK, xml.str());
249 }
250
251 HTTPResponse* Server::cmd_transmission_start(const Command& command) {
252         const Command::Arguments& args = command.get_args();
253         if (args.size() < 3) {
254                 return new HTTPResponse(HTTPMessage::CONFLICT,
255                                 "<response desc=\"Faltan argumentos.\" />");
256         } else {
257                 string plant = args[0];
258                 string host = args[1];
259                 Connection::Port port = to(args[2], port);
260                 Glib::Mutex::Lock lock(plants_mutex);
261                 PlantList::iterator p = plants.find(plant);
262                 if (p == plants.end()) {
263                         return new HTTPResponse(HTTPMessage::NOT_FOUND,
264                                         string("<response desc=\"No existe la planta '") + plant + "'.\" />");
265                 // TODO - agregar chequeo de que la transmision a ese host:port no
266                 //        exista para otra planta?
267                 } else if (plants[plant]->transmission_start(host, port)) {
268                         return new HTTPResponse(HTTPMessage::OK,
269                                         string("<response desc=\"Se empieza a transmitir la planta '") + plant
270                                         + "' a " + host + ":" + String().from(port) + ".\" />");
271                 } else {
272                         return new HTTPResponse(HTTPMessage::INTERNAL_SERVER_ERROR,
273                                         string("<response desc=\"Error al crear la transmisión a de la planta '")
274                                         + plant + "' a " + host + ":" + args[2] + ".\" />");
275                 }
276         }
277 }
278
279 HTTPResponse* Server::cmd_transmission_stop(const Command& command) {
280         const Command::Arguments& args = command.get_args();
281         if (args.size() < 2) {
282                 return new HTTPResponse(HTTPMessage::CONFLICT,
283                                 "<response desc=\"Faltan argumentos.\" />");
284         } else {
285                 const string& host = args[0];
286                 Connection::Port port = to(args[1], port);
287                 for (PlantList::iterator i = plants.begin(); i != plants.end(); i++) {
288                         // TODO - agregar chequeo para saber si existe una conexion (para
289                         // tirar error de que no hay conexion o de que no se pudo
290                         // desconectar.
291                         if (i->second->transmission_stop(host, port)) {
292                                 return new HTTPResponse(HTTPMessage::OK,
293                                                 string("<response desc=\"Se finaliza la transmisión de la planta '")
294                                                 + i->first + "' a " + host + ":" + args[1] + ".\" />");
295                         }
296                 }
297                 return new HTTPResponse(HTTPMessage::NOT_FOUND,
298                                 string("<response desc=\"No se puede finalizar la transmisión a ")
299                                 + host + ":" + args[1] + ".\" />");
300         }
301 }
302
303 HTTPResponse* Server::cmd_plant_list(void) {
304         // FIXME
305         stringstream xml;
306         xml << "<list type=\"plant\">" << endl;
307         plants_mutex.lock();
308         for (PlantList::const_iterator i = plants.begin();
309                         i != plants.end(); i++) {
310                 xml << "\t<row>" << endl;
311                 xml << "\t\t<cell>" << i->first << "</cell>" << endl;
312                 xml << "\t</row>" << endl;
313         }
314         plants_mutex.unlock();
315         xml << "</list>" << endl;
316         return new HTTPResponse(HTTPMessage::OK, xml.str());
317 }
318
319 HTTPResponse* Server::cmd_plant_get(const Command& command) {
320         if (!command.get_args().size()) {
321                 return new HTTPResponse(HTTPMessage::CONFLICT,
322                                 "<response desc=\"Faltan argumentos.\" />");
323         }
324         Glib::Mutex::Lock lock(plants_mutex);
325         string plant = command.get_args()[0];
326         if (plants.find(plant) == plants.end()) {
327                 return new HTTPResponse(HTTPMessage::NOT_FOUND,
328                                 string("<response desc=\"No existe la planta ") + plant + "\" />");
329         }
330         // TODO try/catch?
331         string xml = plants[plant]->get_xml();
332         if (xml.length()) {
333                 return new HTTPResponse(HTTPMessage::OK, xml);
334         } else {
335                 return new HTTPResponse(HTTPMessage::INTERNAL_SERVER_ERROR,
336                                 ("<response desc=\"No se pudo obtener el XML de la planta ") + plant + "\" />");
337         }
338 }
339
340 HTTPResponse* Server::cmd_plant_set(const Command& command) {
341         const Command::Arguments& args = command.get_args();
342         if (args.size() < 4) {
343                 return new HTTPResponse(HTTPMessage::CONFLICT,
344                                 "<response desc=\"Faltan argumentos.\" />");
345         }
346         string plant = args[0];
347         string element = args[1];
348         string key = args[2];
349         if (key != "open") {
350                 return new HTTPResponse(HTTPMessage::NOT_FOUND,
351                                 string("<response desc=\"La clave '") + key + "' es inválida.\" />");
352         }
353         string value = args[3];
354         Glib::Mutex::Lock lock(plants_mutex);
355         PlantList::iterator p = plants.find(plant);
356         if (p == plants.end()) {
357                 return new HTTPResponse(HTTPMessage::NOT_FOUND,
358                                 string("<response desc=\"No existe la planta '") + plant + "'.\" />");
359         }
360         bool open = true;
361         if ((value == "false") || (value == "0") || (value == "off")
362                         || (value == "no")) {
363                 open = false;
364         }
365         if (!plants[plant]->set_open(element, open)) {
366                 return new HTTPResponse(HTTPMessage::CONFLICT,
367                                 string("<response desc=\"No se pudo cambiar el estado del elemento '") + element + "'.\" />");
368         }
369         return new HTTPResponse(HTTPMessage::OK,
370                         string("<response desc=\"Se cambió el estado del elemento '") + element + "'.\" />");
371 }
372
373 HTTPResponse* Server::cmd_plant_stop(const Command& command) {
374         if (!command.get_args().size()) {
375                 return new HTTPResponse(HTTPMessage::CONFLICT,
376                                 "<response desc=\"Faltan argumentos.\" />");
377         }
378         Glib::Mutex::Lock lock(plants_mutex);
379         const string name = command.get_args()[0];
380         if (plants.find(name) == plants.end()) {
381                 return new HTTPResponse(HTTPMessage::NOT_FOUND,
382                                 string("<response desc=\"No existe la planta ") + name + "\" />");
383         }
384         // TODO Ver si al frenar la planta se destruye (no deberia!!!)
385         plants[name]->finish();
386         return new HTTPResponse(HTTPMessage::OK,
387                         string("<response desc=\"La planta '") + name + "' se cerrará en instantes...\" />");
388 }
389
390 } // namespace Server
391
392 } // namespace PlaQui
393