First commit
[anna.git] / example / http / echo / main.cpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
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 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.
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 #include <iostream>
38
39 #include <anna/core/core.hpp>
40 #include <anna/comm/comm.hpp>
41
42 #include <anna/http/Request.hpp>
43 #include <anna/http/Response.hpp>
44 #include <anna/http/Handler.hpp>
45 #include <anna/http/Transport.hpp>
46 #include <anna/http/functions.hpp>
47 #include <anna/http/internal/sccs.hpp>
48 #include <anna/core/internal/sccs.hpp>
49
50 anna_import_sccs_tag (http);
51
52 using namespace std;
53
54 class MyHandler : public http::Handler {
55 public:
56    MyHandler () : http::Handler ("http_echo::MyHandler") { 
57       a_httpResponse.createHeader (http::Header::Type::Date); 
58       a_httpResponse.createHeader (http::Header::Type::Server)->setValue (anna_use_sccs_tag (http));
59    }
60
61    void setNotSend (const bool notSend) throw () { a_notSend = notSend; }
62
63 private:
64    http::Response a_httpResponse;
65    bool a_notSend;
66
67    void evRequest (ClientSocket&, const http::Request& request) throw (RuntimeException);
68    void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException) {;}
69 };
70
71 class MyCommunicator : public comm::Communicator {
72 public:
73    MyCommunicator () {;}
74
75    void setNotSend (const bool notSend) throw () { a_httpHandler.setNotSend (notSend); }
76
77 private:
78    MyHandler a_httpHandler;
79
80    void eventReceiveMessage (comm::ClientSocket &, const Message& message)
81       throw (RuntimeException);
82 };
83
84 class HTTPArithmeticServer : public comm::Application {
85 public:
86    HTTPArithmeticServer ();
87       
88 private:
89    MyCommunicator a_communicator;
90    comm::ServerSocket* a_serverSocket;
91
92    void initialize () throw (RuntimeException);
93    void run () throw (RuntimeException);
94 };
95
96 using namespace std;
97 using namespace anna::comm;
98
99 int main (int argc, const char** argv)
100 {
101    CommandLine& commandLine (CommandLine::instantiate ());
102    HTTPArithmeticServer app;
103
104    http::functions::initialize ();
105
106    srand (time (NULL));
107
108    try {
109       commandLine.initialize (argv, argc);
110       commandLine.verify ();
111
112       Logger::setLevel (Logger::Debug); 
113       Logger::initialize ("http_echo", new anna::TraceWriter ("file.trace", 4048000));
114  
115       app.start ();
116    }
117    catch (Exception& ex) {
118       cout << ex.asString () << endl;
119    }
120    
121    return 0;
122 }
123
124 HTTPArithmeticServer::HTTPArithmeticServer () : 
125    Application ("http_echo", "Servidor de echo", "1.0") 
126 {
127    CommandLine& commandLine (CommandLine::instantiate ());
128       
129    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones");
130    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender");
131    commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false);
132    commandLine.add ("notsend", CommandLine::Argument::Optional, "Indicador de no responder al mensaje", false);
133 }
134
135 void HTTPArithmeticServer::initialize () 
136    throw (RuntimeException)
137 {
138    CommandLine& cl (CommandLine::instantiate ());
139
140    int port = cl.getIntegerValue ("p");
141    const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a")));
142
143    a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), &http::Transport::getFactory ());
144
145    a_communicator.setNotSend (cl.exists ("notsend"));
146 }
147
148 void HTTPArithmeticServer::run ()
149    throw (RuntimeException)
150 {
151    a_communicator.attach (a_serverSocket);
152    a_communicator.accept ();
153 }
154
155 void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message)
156    throw (RuntimeException)
157 {
158    LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION));
159
160    if (clientSocket.support (http::Transport::className ()) == false)
161       return;
162
163    static int messageCounter = 0;
164    static int successCounter = 0;
165
166    int value;
167
168    CongestionController& congestionController = CongestionController::instantiate ();
169
170    messageCounter ++;
171
172    if (congestionController.getAdvice (clientSocket) == CongestionController::Advice::Discard)
173       return;
174
175    successCounter ++;
176
177    a_httpHandler.apply (clientSocket, message);
178 }
179
180 void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request)
181    throw (RuntimeException)
182 {
183    const DataBlock& body = request.getBody ();
184
185    LOGINFORMATION (
186       string msg ("Body recibido: ");
187       msg += anna::functions::asString (body);
188       Logger::information (msg, ANNA_FILE_LOCATION);
189    );
190
191    LOGINFORMATION (
192       const http::Header* header;
193       string msg;
194
195       for (http::Request::const_header_iterator ii = request.header_begin (), maxii = request.header_end (); ii != maxii; ii ++) {
196          header = http::Request::header (ii);
197          Logger::information (header->asString (), ANNA_FILE_LOCATION);
198       }
199
200       if ((header = request.find (http::Header::Type::Connection)) != NULL) {
201          if (header->match ("keep-alive", http::Header::Compare::FullMode))
202             Logger::information ("Keep Alive activado en la conexion", ANNA_FILE_LOCATION);
203          else
204             Logger::information ("Keep Alive NO activado en la conexion", ANNA_FILE_LOCATION);
205       }
206    );
207
208    if (a_notSend == true)
209       return;
210
211    a_httpResponse.clearBody ();
212    a_httpResponse.find (http::Header::Type::Date)->setValue ("Mon, 30 Jan 2006 14:36:18 GMT");
213
214    http::Header* userData = a_httpResponse.find ("UserData");
215  
216    if (userData == NULL)
217       userData = a_httpResponse.createHeader ("UserData");
218
219    userData->setValue ("Verificacio del cambio 1.0.7");
220    a_httpResponse.setBody (body);
221
222    try {
223       clientSocket.send (a_httpResponse);
224    }
225    catch (Exception& ex) {
226       ex.trace ();
227    }
228 }
229