Suuports clang compiler
[anna.git] / example / comm / datagramRServer / main.cpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // http://redmine.teslayout.com/projects/anna-suite
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
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
16 // distribution.
17 //     *  Neither the name of the copyright holder 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.
20 //
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.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 /*
38   Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte
39   sera el comm::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.
41   
42   Ejemplo de uso del sistema de receiveres, que son capaces de tratar N peticiones de forma
43   totalmetne simultanea en caso de estar en un entorno MT.
44
45   Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de 
46   retardo aplicados a cada contestacion.
47
48   Los clientes pueden ser: client.p o kclient.p
49 */
50 #include <iostream>
51
52 #include <anna/core/core.hpp>
53 #include <anna/comm/comm.hpp>
54
55 #include <anna/xml/Node.hpp>
56 #include <anna/xml/Attribute.hpp>
57
58 #include <anna/app/functions.hpp>
59
60 #include <anna/test/Request.hpp>
61 #include <anna/test/Response.hpp>
62 #include <anna/test/Communicator.hpp>
63
64 using namespace std;
65 using namespace test;
66
67 class MyCommunicator : public test::Communicator {
68 public:
69    MyCommunicator () :  test::Communicator () {;}
70 };
71
72 class MyReceiver : public Receiver {
73 public:
74    static const char* className () throw () { return "MyReceiver"; }
75
76 private:
77    Request a_request;
78    Response a_response;
79    MyCommunicator* a_communicator;
80    
81    MyReceiver () : Receiver ("MyReceiver") { ; }
82    void initialize () throw (RuntimeException);
83    void apply (comm::ClientSocket &, const Message&) throw (RuntimeException);
84    
85    friend class Allocator <MyReceiver>;      
86 };
87
88 class ArithmeticServer : public comm::Application {
89 public:
90    ArithmeticServer ();
91
92    comm::DatagramSocket* getOutput () throw () { return a_output; }
93       
94 private:
95    MyCommunicator* a_communicator;
96    ReceiverFactoryImpl <MyReceiver> a_receiverFactory;
97    comm::DatagramSocket* a_input;
98    comm::DatagramSocket* a_output;
99
100    void initialize () throw (RuntimeException);
101    void run () throw (RuntimeException);
102    xml::Node* asXML (xml::Node* app) const throw ();
103 };
104
105 using namespace std;
106 using namespace anna::comm;
107
108 int main (int argc, const char** argv)
109 {
110    CommandLine& commandLine (CommandLine::instantiate ());
111    ArithmeticServer app;
112
113    srand (time (NULL));
114    
115    try {
116       commandLine.initialize (argv, argc);
117       commandLine.verify ();
118
119       Logger::setLevel (Logger::Debug); 
120       Logger::initialize ("arithmeticServer", new TraceWriter ("file.trace",4096000));
121  
122       app.start ();
123    }
124    catch (Exception& ex) {
125       cout << ex.asString () << endl;
126    }
127    
128    return 0;
129 }
130
131 ArithmeticServer::ArithmeticServer () : 
132    Application ("arithmeticServer", "Servidor de operaciones (iRS)", "1.0"),
133    a_communicator (NULL)
134 {
135    CommandLine& commandLine (CommandLine::instantiate ());
136    
137    commandLine.add ("as", CommandLine::Argument::Optional, "Direccion broadcast en el que servidor atiende peticiones.");
138    commandLine.add ("ps", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende las peticiones.");
139    commandLine.add ("ac", CommandLine::Argument::Optional, "Direccion broadcast en el que cliente atiende respuestas.");
140    commandLine.add ("pc", CommandLine::Argument::Mandatory, "Puerto al que enviar las respuestas");
141    commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
142 }
143
144 //-----------------------------------------------------------------------------------------
145 // Inicializa el servidor de sockets.
146 //-----------------------------------------------------------------------------------------
147 void ArithmeticServer::initialize () 
148    throw (RuntimeException)
149 {
150    CommandLine& cl (CommandLine::instantiate ());
151
152    const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("as")));
153    int port = cl.getIntegerValue ("ps");
154
155    a_communicator = new MyCommunicator ();
156
157    INetAddress localAddress (device, port);
158    a_input = new DatagramSocket (DatagramSocket::ReadOnly, localAddress);
159    a_input->setReceiverFactory (a_receiverFactory);
160    a_communicator->attach (a_input);
161
162    device = Network::instantiate ().find (Device::asAddress (cl.getValue ("ac")));
163    port = cl.getIntegerValue ("pc");
164
165    INetAddress remoteAddress (device, port);
166    a_output = new DatagramSocket (DatagramSocket::WriteOnly, remoteAddress);
167    a_output->connect ();
168 }
169
170 //-----------------------------------------------------------------------------------------
171 // Atiende las peticiones.
172 // Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage
173 //-----------------------------------------------------------------------------------------
174 void ArithmeticServer::run ()
175    throw (RuntimeException)
176 {
177    CommandLine& cl (CommandLine::instantiate ());
178
179    if (cl.exists ("trace"))
180       Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
181
182    a_communicator->accept ();
183 }
184
185 xml::Node* ArithmeticServer::asXML (xml::Node* app) const 
186    throw ()
187 {
188    xml::Node* node = app::Application::asXML (app);
189    
190    node->createAttribute ("MaxMessage", a_communicator->getMaxMessage ());
191    node->createAttribute ("Message", a_communicator->getMessage ());
192    
193    return node;
194 }
195
196 void MyReceiver::initialize ()
197    throw (RuntimeException)
198 {
199    a_communicator = app::functions::component <MyCommunicator> (ANNA_FILE_LOCATION);
200 }
201
202 void MyReceiver::apply (ClientSocket&, const Message& message) 
203    throw (RuntimeException)
204 {
205    LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION));
206
207    a_request.decode (message.getBody ());
208
209    a_communicator->delay ();
210
211    a_response.x = a_request.x;
212    a_response.y = a_request.y;
213    a_response.initTime = a_request.initTime;
214
215    switch (a_response.op = a_request.op) {
216       case '+':
217          a_response.result = a_request.x + a_request.y;
218          break;
219       case '-':
220          a_response.result = a_request.x - a_request.y;
221          break;
222       case '*':
223          a_response.result = a_request.x * a_request.y;
224          break;
225       case '/':
226          a_response.result = (a_request.y != 0) ? (a_request.x / a_request.y): 0;
227          break;
228    }
229
230    LOGINFORMATION (
231       string msg = anna::functions::asString ("%d %c %d = %d", a_request.x, a_request.op, a_request.y, a_response.result);
232       msg += anna::functions::asText (" | InitTime: ",  a_response.initTime);
233       Logger::information (msg, ANNA_FILE_LOCATION);
234    )
235
236    try {
237       static_cast <ArithmeticServer&> (app::functions::getApp ()).getOutput ()->send (a_response);
238    }
239    catch (Exception& ex) {
240       ex.trace ();
241    }
242 }