1 // ANNA - Anna is Not 'N' 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>
54 #include <anna/comm/comm.hpp>
56 #include <anna/http/Request.hpp>
57 #include <anna/http/Response.hpp>
58 #include <anna/http/Handler.hpp>
59 #include <anna/http/Transport.hpp>
60 #include <anna/http/functions.hpp>
62 #include <anna/test/Request.hpp>
63 #include <anna/test/Response.hpp>
64 #include <anna/test/Communicator.hpp>
68 class MyHandler : public http::Handler {
70 MyHandler () : http::Handler ("http_server::MyHandler") {
71 allocateResponse ()->createHeader (http::Header::Type::Date);
75 test::Request a_testRequest;
76 test::Response a_testResponse;
78 void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException);
79 void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;}
82 class MyCommunicator : public test::Communicator {
85 a_contexts ("Contexts")
89 ThreadData <MyHandler> a_contexts;
91 void eventReceiveMessage (comm::ClientSocket&, const Message&) throw (RuntimeException);
94 class HTTPArithmeticServer : public comm::Application {
96 HTTPArithmeticServer ();
99 MyCommunicator a_communicator;
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 HTTPArithmeticServer 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 HTTPArithmeticServer::HTTPArithmeticServer () :
136 Application ("http_server", "Servidor HTTP de operaciones aritmeticas", "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 direccin", 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, "Milisegundos transcurridos sin actividad para cerrar el socket");
150 void HTTPArithmeticServer::initialize ()
151 throw (RuntimeException)
153 CommandLine& cl (CommandLine::instantiate ());
155 int port = cl.getIntegerValue ("p");
156 const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a")));
158 a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), &http::Transport::getFactory ());
161 void HTTPArithmeticServer::run ()
162 throw (RuntimeException)
164 CommandLine& cl (CommandLine::instantiate ());
166 a_communicator.attach (a_serverSocket);
167 a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d"));
169 if (cl.exists ("n") == true)
170 a_communicator.setMaxMessage (cl.getIntegerValue ("n"));
172 if (cl.exists ("trace"))
173 Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
175 CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit"));
177 if (cl.exists ("timeout"))
178 a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout"));
180 a_communicator.accept ();
183 xml::Node* HTTPArithmeticServer::asXML (xml::Node* app) const
186 xml::Node* node = app::Application::asXML (app);
188 node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ());
189 node->createAttribute ("Message", a_communicator.getMessage ());
194 void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message)
195 throw (RuntimeException)
197 LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION));
199 if (clientSocket.support (http::Transport::className ()) == false)
202 if (canContinue (clientSocket) == false)
207 MyHandler& httpHandler = a_contexts.get ();
209 httpHandler.apply (clientSocket, message);
212 void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request)
213 throw (RuntimeException)
215 const DataBlock& body = request.getBody ();
217 if (body.getSize () == 0)
218 throw RuntimeException ("La peticion no incorpora los parametros de operacion", ANNA_FILE_LOCATION);
221 string msg ("Body recibido: ");
222 msg += anna::functions::asString (body);
223 Logger::information (msg, ANNA_FILE_LOCATION);
226 if (Codec::getType (body) != test::Request::Id)
227 throw RuntimeException ("El mensaje recibido no es una peticion aritmetica", ANNA_FILE_LOCATION);
229 a_testRequest.decode (body);
231 a_testResponse.x = a_testRequest.x;
232 a_testResponse.y = a_testRequest.y;
233 a_testResponse.initTime = a_testRequest.initTime;
235 http::Response* response = allocateResponse ();
237 response->setStatusCode (200);
239 switch (a_testResponse.op = a_testRequest.op) {
241 a_testResponse.result = a_testRequest.x + a_testRequest.y;
244 a_testResponse.result = a_testRequest.x - a_testRequest.y;
247 a_testResponse.result = a_testRequest.x * a_testRequest.y;
250 if (a_testRequest.y == 0) {
251 response->setStatusCode (400);
252 response->setReasonPhrase ("Division por cero");
253 a_testResponse.result = 0;
256 a_testResponse.result = a_testRequest.x / a_testRequest.y;
260 response->setBody (a_testResponse.code ());
262 response->find (http::Header::Type::Date)->setValue ("Mon, 30 Jan 2006 14:36:18 GMT");
264 http::Header* keepAlive = response->find ("Keep-Alive");
266 if (keepAlive == NULL)
267 keepAlive = response->createHeader ("Keep-Alive");
269 keepAlive->setValue ("Verificacion del cambio 1.0.7");
273 string msg = anna::functions::asString ("%d %c %d = %d", a_testRequest.x, a_testRequest.op, a_testRequest.y, a_testResponse.result);
274 Logger::information (msg, ANNA_FILE_LOCATION);
278 clientSocket.send (*response);
280 catch (Exception& ex) {