1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
17 // * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
38 Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte sera HTTP
39 ver http::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los
40 (x, y, op) -> El resultado sera estos tres componente mas result.
42 Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de
43 retardo aplicados a cada contestacion.
45 Los clientes pueden ser: http_kclient.p http_client.p
49 #include <anna/core/core.hpp>
51 #include <anna/xml/Node.hpp>
52 #include <anna/xml/Attribute.hpp>
53 #include <anna/xml/DocumentMemory.hpp>
55 #include <anna/comm/comm.hpp>
57 #include <anna/http/Request.hpp>
58 #include <anna/http/Response.hpp>
59 #include <anna/http/Handler.hpp>
60 #include <anna/http/Transport.hpp>
61 #include <anna/http/functions.hpp>
64 #include <anna/test/Communicator.hpp>
69 class MyHandler : public http::Handler {
71 MyHandler () : http::Handler ("http_rserver::MyHandler")
73 anna_memset (a_xmlAttributes, 0, sizeof (a_xmlAttributes));
78 static const char* className () throw () { return "http_rserver::ReceiverFactory"; }
81 struct Attribute { enum _v { ValueOne, ValueTwo, Operator, Result, Time, Max }; };
83 test::Communicator* a_communicator;
84 xml::DocumentMemory a_xmlRequest;
85 xml::Node* a_xmlResponse;
86 xml::Attribute* a_xmlAttributes [Attribute::Max];
88 void initialize () throw (RuntimeException);
89 void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException);
90 void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;}
93 class WIMS20ArithmeticServer : public comm::Application {
95 WIMS20ArithmeticServer ();
98 test::Communicator a_communicator;
99 ReceiverFactoryImpl <MyHandler> a_receiverFactory;
100 comm::ServerSocket* a_serverSocket;
102 void initialize () throw (RuntimeException);
103 void run () throw (RuntimeException);
104 xml::Node* asXML (xml::Node* app) const throw ();
108 using namespace anna::comm;
110 int main (int argc, const char** argv)
112 CommandLine& commandLine (CommandLine::instantiate ());
113 WIMS20ArithmeticServer app;
115 http::functions::initialize ();
120 commandLine.initialize (argv, argc);
121 commandLine.verify ();
123 Logger::setLevel (Logger::Debug);
124 Logger::initialize ("http_server", new anna::TraceWriter ("file.trace", 4048000));
128 catch (Exception& ex) {
129 cout << ex.asString () << endl;
135 WIMS20ArithmeticServer::WIMS20ArithmeticServer () :
136 Application ("http_rserver", "Servidor WIMS20 de operaciones aritmeticas (iRS)", "1.0")
138 CommandLine& commandLine (CommandLine::instantiate ());
140 commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones");
141 commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender");
142 commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion");
143 commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccion", false);
144 commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos");
145 commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true);
146 commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
147 commandLine.add ("timeout", CommandLine::Argument::Optional, "Timeout (ms) del cliente sin enviar peticiones");
148 commandLine.add ("quota", CommandLine::Argument::Optional, "Numero de bytes aceptados antes de cerrar el socket");
151 void WIMS20ArithmeticServer::initialize ()
152 throw (RuntimeException)
154 CommandLine& cl (CommandLine::instantiate ());
156 int port = cl.getIntegerValue ("p");
157 const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a")));
159 comm::TransportFactory* ttff = &http::Transport::getFactory ();
161 if (cl.exists ("quota") == true)
162 ttff->setOverQuotaSize (cl.getIntegerValue ("quota"));
164 a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), ttff);
165 a_serverSocket->setReceiverFactory (a_receiverFactory);
168 void WIMS20ArithmeticServer::run ()
169 throw (RuntimeException)
171 CommandLine& cl (CommandLine::instantiate ());
173 a_communicator.attach (a_serverSocket);
174 a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d"));
176 if (cl.exists ("n") == true)
177 a_communicator.setMaxMessage (cl.getIntegerValue ("n"));
179 if (cl.exists ("trace"))
180 Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
182 CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit"));
184 if (cl.exists ("timeout") == true)
185 a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout"));
187 a_communicator.accept ();
190 xml::Node* WIMS20ArithmeticServer::asXML (xml::Node* app) const
193 xml::Node* node = app::Application::asXML (app);
195 node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ());
196 node->createAttribute ("Message", a_communicator.getMessage ());
201 void MyHandler::initialize ()
202 throw (RuntimeException)
204 a_communicator = app::functions::component <test::Communicator> (ANNA_FILE_LOCATION);
207 * Crea el documento XML que usaremos para codificar la respuesta y
208 * pre-localiza los objetos sobre los que tendrá que actuar
210 a_xmlResponse = new xml::Node ("Response");
211 a_xmlAttributes [Attribute::ValueOne] = a_xmlResponse->createAttribute ("ValueOne", 0);
212 a_xmlAttributes [Attribute::ValueTwo] = a_xmlResponse->createAttribute ("ValueTwo", 0);
213 a_xmlAttributes [Attribute::Operator] = a_xmlResponse->createAttribute ("Operator", 0);
214 a_xmlAttributes [Attribute::Result] = a_xmlResponse->createAttribute ("Result", 0);
215 a_xmlAttributes [Attribute::Time] = a_xmlResponse->createAttribute ("Time", 0);
219 * Recibe una peticion
221 void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& httpRequest)
222 throw (RuntimeException)
224 LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION));
226 if (a_communicator->canContinue (clientSocket) == false)
229 // Extrace el documento XML de la petición.
230 a_xmlRequest.initialize (httpRequest.getBody ());
232 const xml::Node* request = a_xmlRequest.parse ();
234 http::Response* response = allocateResponse ();
236 // Antes de contestar espera el tiempo indicado en la configuración
237 a_communicator->delay ();
240 * Obtiene los valores de los atributos del documento XML
242 const char* op = request->getAttribute ("Operator")->getCStringValue ();
243 int v1 = request->getAttribute ("ValueOne")->getIntegerValue ();
244 int v2 = request->getAttribute ("ValueTwo")->getIntegerValue ();
247 * Establece el valor de los objetos XML pre-localizados que irán en la respuesta
249 a_xmlAttributes [Attribute::ValueOne]->setValue (v1);
250 a_xmlAttributes [Attribute::ValueTwo]->setValue (v2);
251 a_xmlAttributes [Attribute::Operator]->setValue (op);
253 // Este dato sirve para calcular el tiempo de respuesta del servidor
254 a_xmlAttributes [Attribute::Time]->setValue (request->getAttribute ("Millisecond")->getIntegerValue ());
256 response->setStatusCode (200);
259 case '+': a_xmlAttributes [Attribute::Result]->setValue (v1 + v2); break;
260 case '-': a_xmlAttributes [Attribute::Result]->setValue (v1 - v2); break;
261 case '*': a_xmlAttributes [Attribute::Result]->setValue (v1 * v2); break;
264 response->setStatusCode (400);
265 response->setReasonPhrase ("Division por cero");
268 a_xmlAttributes [Attribute::Result]->setValue (v1 / v2);
271 response->setStatusCode (501);
275 /* Observar que establece directamente el documento XML como cuerpo
276 * de la respuesta HTTP.
278 if (response->getStatusCode () == 200)
279 response->setBody (a_xmlResponse);
281 response->clearBody ();
283 clientSocket.send (*response);