1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
10 Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte sera HTTP
11 ver http::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los
12 (x, y, op) -> El resultado sera estos tres componente mas result.
14 Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de
15 retardo aplicados a cada contestacion.
17 Los clientes pueden ser: http_kclient.p http_client.p
21 #include <anna/core/core.hpp>
23 #include <anna/xml/Node.hpp>
24 #include <anna/xml/Attribute.hpp>
25 #include <anna/xml/DocumentMemory.hpp>
27 #include <anna/comm/comm.hpp>
29 #include <anna/http/Request.hpp>
30 #include <anna/http/Response.hpp>
31 #include <anna/http/Handler.hpp>
32 #include <anna/http/Transport.hpp>
33 #include <anna/http/functions.hpp>
36 #include <anna/test/Communicator.hpp>
41 class MyHandler : public http::Handler {
43 MyHandler () : http::Handler ("http_rserver::MyHandler")
45 anna_memset (a_xmlAttributes, 0, sizeof (a_xmlAttributes));
50 static const char* className () throw () { return "http_rserver::ReceiverFactory"; }
53 struct Attribute { enum _v { ValueOne, ValueTwo, Operator, Result, Time, Max }; };
55 test::Communicator* a_communicator;
56 xml::DocumentMemory a_xmlRequest;
57 xml::Node* a_xmlResponse;
58 xml::Attribute* a_xmlAttributes [Attribute::Max];
60 void initialize () throw (RuntimeException);
61 void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException);
62 void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;}
65 class WIMS20ArithmeticServer : public comm::Application {
67 WIMS20ArithmeticServer ();
70 test::Communicator a_communicator;
71 ReceiverFactoryImpl <MyHandler> a_receiverFactory;
72 comm::ServerSocket* a_serverSocket;
74 void initialize () throw (RuntimeException);
75 void run () throw (RuntimeException);
76 xml::Node* asXML (xml::Node* app) const throw ();
80 using namespace anna::comm;
82 int main (int argc, const char** argv)
84 CommandLine& commandLine (CommandLine::instantiate ());
85 WIMS20ArithmeticServer app;
87 http::functions::initialize ();
92 commandLine.initialize (argv, argc);
93 commandLine.verify ();
95 Logger::setLevel (Logger::Debug);
96 Logger::initialize ("http_server", new anna::TraceWriter ("file.trace", 4048000));
100 catch (Exception& ex) {
101 cout << ex.asString () << endl;
107 WIMS20ArithmeticServer::WIMS20ArithmeticServer () :
108 Application ("http_rserver", "Servidor WIMS20 de operaciones aritmeticas (iRS)", "1.0")
110 CommandLine& commandLine (CommandLine::instantiate ());
112 commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones");
113 commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender");
114 commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion");
115 commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccion", false);
116 commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos");
117 commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true);
118 commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
119 commandLine.add ("timeout", CommandLine::Argument::Optional, "Timeout (ms) del cliente sin enviar peticiones");
120 commandLine.add ("quota", CommandLine::Argument::Optional, "Numero de bytes aceptados antes de cerrar el socket");
123 void WIMS20ArithmeticServer::initialize ()
124 throw (RuntimeException)
126 CommandLine& cl (CommandLine::instantiate ());
128 int port = cl.getIntegerValue ("p");
129 const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a")));
131 comm::TransportFactory* ttff = &http::Transport::getFactory ();
133 if (cl.exists ("quota") == true)
134 ttff->setOverQuotaSize (cl.getIntegerValue ("quota"));
136 a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), ttff);
137 a_serverSocket->setReceiverFactory (a_receiverFactory);
140 void WIMS20ArithmeticServer::run ()
141 throw (RuntimeException)
143 CommandLine& cl (CommandLine::instantiate ());
145 a_communicator.attach (a_serverSocket);
146 a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d"));
148 if (cl.exists ("n") == true)
149 a_communicator.setMaxMessage (cl.getIntegerValue ("n"));
151 if (cl.exists ("trace"))
152 Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
154 CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit"));
156 if (cl.exists ("timeout") == true)
157 a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout"));
159 a_communicator.accept ();
162 xml::Node* WIMS20ArithmeticServer::asXML (xml::Node* app) const
165 xml::Node* node = app::Application::asXML (app);
167 node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ());
168 node->createAttribute ("Message", a_communicator.getMessage ());
173 void MyHandler::initialize ()
174 throw (RuntimeException)
176 a_communicator = app::functions::component <test::Communicator> (ANNA_FILE_LOCATION);
179 * Crea el documento XML que usaremos para codificar la respuesta y
180 * pre-localiza los objetos sobre los que tendrá que actuar
182 a_xmlResponse = new xml::Node ("Response");
183 a_xmlAttributes [Attribute::ValueOne] = a_xmlResponse->createAttribute ("ValueOne", 0);
184 a_xmlAttributes [Attribute::ValueTwo] = a_xmlResponse->createAttribute ("ValueTwo", 0);
185 a_xmlAttributes [Attribute::Operator] = a_xmlResponse->createAttribute ("Operator", 0);
186 a_xmlAttributes [Attribute::Result] = a_xmlResponse->createAttribute ("Result", 0);
187 a_xmlAttributes [Attribute::Time] = a_xmlResponse->createAttribute ("Time", 0);
191 * Recibe una peticion
193 void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& httpRequest)
194 throw (RuntimeException)
196 LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION));
198 if (a_communicator->canContinue (clientSocket) == false)
201 // Extrace el documento XML de la petición.
202 a_xmlRequest.initialize (httpRequest.getBody ());
204 const xml::Node* request = a_xmlRequest.parse ();
206 http::Response* response = allocateResponse ();
208 // Antes de contestar espera el tiempo indicado en la configuración
209 a_communicator->delay ();
212 * Obtiene los valores de los atributos del documento XML
214 const char* op = request->getAttribute ("Operator")->getCStringValue ();
215 int v1 = request->getAttribute ("ValueOne")->getIntegerValue ();
216 int v2 = request->getAttribute ("ValueTwo")->getIntegerValue ();
219 * Establece el valor de los objetos XML pre-localizados que irán en la respuesta
221 a_xmlAttributes [Attribute::ValueOne]->setValue (v1);
222 a_xmlAttributes [Attribute::ValueTwo]->setValue (v2);
223 a_xmlAttributes [Attribute::Operator]->setValue (op);
225 // Este dato sirve para calcular el tiempo de respuesta del servidor
226 a_xmlAttributes [Attribute::Time]->setValue (request->getAttribute ("Millisecond")->getIntegerValue ());
228 response->setStatusCode (200);
231 case '+': a_xmlAttributes [Attribute::Result]->setValue (v1 + v2); break;
232 case '-': a_xmlAttributes [Attribute::Result]->setValue (v1 - v2); break;
233 case '*': a_xmlAttributes [Attribute::Result]->setValue (v1 * v2); break;
236 response->setStatusCode (400);
237 response->setReasonPhrase ("Division por cero");
240 a_xmlAttributes [Attribute::Result]->setValue (v1 / v2);
243 response->setStatusCode (501);
247 /* Observar que establece directamente el documento XML como cuerpo
248 * de la respuesta HTTP.
250 if (response->getStatusCode () == 200)
251 response->setBody (a_xmlResponse);
253 response->clearBody ();
255 clientSocket.send (*response);