Remove dynamic exceptions
[anna.git] / example / comm / server / main.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
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 //
7
8
9 /*
10   Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte
11   sera el comm::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.
13
14   Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de 
15   retardo aplicados a cada contestacion.
16
17   Los clientes pueden ser: client o kClient
18 */
19 #include <iostream>
20 #include <signal.h>
21
22 #include <anna/core/core.hpp>
23 #include <anna/comm/comm.hpp>
24
25 #include <anna/xml/Node.hpp>
26 #include <anna/xml/Attribute.hpp>
27
28 #include <anna/test/Request.hpp>
29 #include <anna/test/Response.hpp>
30 #include <anna/test/Communicator.hpp>
31
32 using namespace std;
33 using namespace test;
34
35 struct Context {
36    Request request;
37    Response response;
38 };
39
40 class MyCommunicator : public test::Communicator {
41 public:
42    MyCommunicator () : 
43       a_contexts ("Contexts")
44    {;}
45       
46 private:
47    ThreadData <Context> a_contexts;
48
49    void eventReceiveMessage (comm::ClientSocket&, const Message&) noexcept(false);
50 };
51
52 class ArithmeticServer : public comm::Application {
53 public:
54    ArithmeticServer ();
55       
56 private:
57    MyCommunicator a_communicator;
58    comm::ServerSocket* a_serverSocket;
59
60    void initialize () noexcept(false);
61    void run () noexcept(false);
62    xml::Node* asXML (xml::Node* app) const ;
63 };
64
65 using namespace std;
66 using namespace anna::comm;
67
68 int main (int argc, const char** argv)
69 {
70    CommandLine& commandLine (CommandLine::instantiate ());
71    ArithmeticServer app;
72
73    srand (time (NULL));
74
75    sigignore (SIGABRT);
76    
77    try {
78       commandLine.initialize (argv, argc);
79       commandLine.verify ();
80
81       Logger::setLevel (Logger::Debug); 
82       string traceFile ("server.");
83       traceFile += anna::functions::asString ((int) getpid ());
84       traceFile += ".trace";      
85       Logger::initialize ("arithmeticServer", new TraceWriter (traceFile.c_str (),4096000));
86  
87       app.start ();
88    }
89    catch (Exception& ex) {
90       cout << ex.asString () << endl;
91    }
92    
93    return 0;
94 }
95
96 ArithmeticServer::ArithmeticServer () : 
97    Application ("arithmeticServer", "Servidor de operaciones aritm�icas", "1.0") 
98 {
99    CommandLine& commandLine (CommandLine::instantiate ());
100       
101    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones");
102    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender");
103    commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion");
104    commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos");
105    commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false);
106    commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true);
107    commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
108 }
109
110 //-----------------------------------------------------------------------------------------
111 // Inicializa el servidor de sockets.
112 //-----------------------------------------------------------------------------------------
113 void ArithmeticServer::initialize () 
114    noexcept(false)
115 {
116    CommandLine& cl (CommandLine::instantiate ());
117
118    int port = cl.getIntegerValue ("p");
119    const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a")));
120
121    a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"));
122    a_serverSocket->setCategory (777);
123 }
124
125 //-----------------------------------------------------------------------------------------
126 // Atiende las peticiones.
127 // Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage
128 //-----------------------------------------------------------------------------------------
129 void ArithmeticServer::run ()
130    noexcept(false)
131 {
132    CommandLine& cl (CommandLine::instantiate ());
133
134    a_communicator.attach (a_serverSocket);
135    a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d"));
136
137    if (cl.exists ("n") == true)
138       a_communicator.setMaxMessage (cl.getIntegerValue ("n"));
139
140    if (cl.exists ("trace"))
141       Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
142
143    CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit"));
144
145    a_communicator.accept ();
146 }
147
148 xml::Node* ArithmeticServer::asXML (xml::Node* app) const 
149    
150 {
151    xml::Node* node = app::Application::asXML (app);
152    
153    node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ());
154    node->createAttribute ("Message", a_communicator.getMessage ());
155    
156    return node;
157 }
158
159 //-----------------------------------------------------------------------------------------
160 // Manejador de peticiones.
161 // Calcular�la operacin solicitada y devolver�el resultado.
162 //
163 // clientSocket: Socket cliente por el que podemos responder a la peticin.
164 // transport: Instancia del transporto que ha interpretado el mensaje (getMessage).
165 //-----------------------------------------------------------------------------------------
166 void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message)
167    noexcept(false)
168 {
169    LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION));
170
171    if (canContinue (clientSocket) == false)
172       return;   
173
174    delay ();   
175     
176    Context& context = a_contexts.get ();
177    Request& request (context.request);
178    Response& response (context.response);
179
180    request.decode (message.getBody ());
181
182    response.x = request.x;
183    response.y = request.y;
184    response.initTime = request.initTime;
185
186    switch (response.op = request.op) {
187       case '+':
188          response.result = request.x + request.y;
189          break;
190       case '-':
191          response.result = request.x - request.y;
192          break;
193       case '*':
194          response.result = request.x * request.y;
195          break;
196       case '/':
197          response.result = (request.y != 0) ? (request.x / request.y): 0;
198          break;
199    }
200
201    LOGINFORMATION (
202       string msg = anna::functions::asString ("%d %c %d = %d", request.x, request.op, request.y, response.result);
203       msg += anna::functions::asText (" | InitTime: ",  response.initTime);
204       Logger::information (msg, ANNA_FILE_LOCATION);
205    )
206
207    try {
208       clientSocket.send (response);
209    }
210    catch (Exception& ex) {
211       ex.trace ();
212    }
213 }
214