First commit
[anna.git] / source / comm / Network.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 <netdb.h>
38
39 #include <anna/core/tracing/Logger.hpp>
40
41 #include <anna/comm/Network.hpp>
42
43 #include <anna/comm/Device.hpp>
44 #include <anna/comm/Host.hpp>
45 #include <anna/comm/Server.hpp>
46
47 #include <anna/xml/Node.hpp>
48 #include <anna/xml/Attribute.hpp>
49
50 using namespace std;
51 using namespace anna;
52
53 comm::Device* comm::Network::find(const in_addr_t& address)
54 throw() {
55   Device* result = NULL;
56
57   if(a_cacheDevice != NULL && *a_cacheDevice == address)
58     return a_cacheDevice;
59
60   for(device_iterator ii = device_begin(), maxii = device_end(); ii != maxii; ii ++) {
61     result = device(ii);
62
63     if(*result == address)
64       return a_cacheDevice = result;
65   }
66
67   a_devices.push_back(result = new Device(address));
68   return a_cacheDevice = result;
69 }
70
71 comm::Host* comm::Network::find_host(const char* name)
72 throw() {
73   Host* result = NULL;
74
75   if(a_cacheHost != NULL && anna_strcmp(a_cacheHost->getName().c_str(), name) == 0)
76     return a_cacheHost;
77
78   for(host_iterator ii = host_begin(), maxii = host_end(); ii != maxii; ii ++) {
79     result = host(ii);
80
81     if(anna_strcmp(result->getName().c_str(), name) == 0)
82       return a_cacheHost = result;
83   }
84
85   a_hosts.push_back(result = new Host(name));
86   return a_cacheHost = result;
87 }
88
89 comm::Host* comm::Network::resolve(const char* hostname)
90 throw(RuntimeException) {
91   comm::Host* result = find_host(hostname);
92   struct hostent *host;
93
94   if((host = gethostbyname(hostname)) == NULL) {
95     string msg("comm::Network::resolve | Host: ");
96     msg += hostname;
97     msg += " | ";
98     msg += hstrerror(h_errno);
99     throw RuntimeException(msg, ANNA_FILE_LOCATION);
100   }
101
102   if(host->h_addrtype != AF_INET) {
103     string msg("comm::Network::resolve | Host: ");
104     msg += hostname;
105     msg += " | Address type unsupported";
106     throw RuntimeException(msg, ANNA_FILE_LOCATION);
107   }
108
109   for(int i = 0; host->h_addr_list[i] != NULL; i ++) {
110     const in_addr_t& address = *reinterpret_cast <in_addr_t*>(host->h_addr_list[i]);
111     LOGDEBUG(
112       string msg("comm::Network::resolve | Host: ");
113       msg += hostname;
114       msg += " | IP: ";
115       msg += inet_ntoa(*reinterpret_cast <in_addr*>(host->h_addr_list[i]));
116       Logger::debug(msg, ANNA_FILE_LOCATION);
117     );
118     result->assign(find(address));
119   }
120
121   return result;
122 }
123
124
125 comm::Server* comm::Network::createServer(const char* ip, const int remotePort, const bool autoRecovery, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect)
126 throw(RuntimeException) {
127   comm::Server* result(NULL);
128   comm::Host* host = find_host(ip);
129   Guard guard(host, "comm::Host from comm::Network::createServer");
130
131   if(mode == Port::Unique) {
132     /**
133      * Si ya existe una conexión previa con esa (ip, port) la devuelve
134      */
135     if((result = host->find_server(remotePort)) != NULL)
136       return result;
137   }
138
139   comm::Device* device = find(comm::Device::asAddress(ip));
140   host->assign(device);
141   string serverName = ip;
142   serverName += functions::asText(":", remotePort);
143   return host->createServer(serverName, remotePort, autoRecovery, transportFactory, false /* ignore incoming messages */, (doConnect == DoConnect::Yes));
144 }
145
146 comm::Server* comm::Network::createServer(const char* ip, const int remotePort, const bool autoRecovery, comm::ReceiverFactory& rrff, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect)
147 throw(RuntimeException) {
148   Server* result = createServer(ip, remotePort, autoRecovery, transportFactory, mode, doConnect);
149   result->setReceiverFactory(rrff);
150   return result;
151 }
152
153 //comm::Server* comm::Network::findServer (const char* ip, const int remotePort)
154 //   throw (RuntimeException)
155 //{
156 //   comm::Host* _host (NULL);
157 //
158 //   for (host_iterator ii = host_begin (), maxii = host_end (); ii != maxii; ii ++) {
159 //      if (host (ii)->getName () == ip) {
160 //         _host = host (ii);
161 //         break;
162 //      }
163 //   }
164 //
165 //   return (_host == NULL) ? NULL: _host->find_server (remotePort);
166 //}
167
168
169 comm::Server* comm::Network::resolveServer(const char* hostname, const int remotePort, const bool autoRecovery, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect)
170 throw(RuntimeException) {
171   comm::Server* result(NULL);
172   comm::Host* host = resolve(hostname);
173   Guard guard(host, "comm::Host from comm::Network::resolveServer");
174
175   if(mode == Port::Unique) {
176     /**
177      * Si ya existe una conexión previa con esa (ip, port) la devuelve
178      */
179     if((result = host->find_server(remotePort)) != NULL)
180       return result;
181   }
182
183   string serverName = hostname;
184   serverName += functions::asText(":", remotePort);
185   return host->createServer(serverName, remotePort, autoRecovery, transportFactory, false /* ignore incoming messages */, (doConnect == DoConnect::Yes));
186 }
187
188 comm::Server* comm::Network::resolveServer(const char* hostname, const int remotePort, const bool autoRecovery, comm::ReceiverFactory& rrff, comm::TransportFactory* transportFactory, const Port::_v mode, const DoConnect::_v doConnect)
189 throw(RuntimeException) {
190   Server* result = resolveServer(hostname, remotePort, autoRecovery, transportFactory, mode, doConnect);
191   result->setReceiverFactory(rrff);
192   return result;
193 }
194
195 comm::INetAddress comm::Network::getINetAddress(const char* ip, const int port)
196 throw(RuntimeException) {
197   const Device* device = find(Device::asAddress(ip));
198   return INetAddress(device, port);
199 }
200
201 comm::INetAddress comm::Network::getINetAddress(const std::string& ip, const int port)
202 throw(RuntimeException) {
203   const Device* device = find(Device::asAddress(ip));
204   return INetAddress(device, port);
205 }
206
207 xml::Node* comm::Network::asXML(xml::Node* parent) const
208 throw() {
209   xml::Node* result = parent->createChild("comm.Network");
210   xml::Node* node = result->createChild("comm.Devices");
211
212   for(const_device_iterator ii = device_begin(), maxii = device_end(); ii != maxii; ii ++)
213     device(ii)->asXML(node);
214
215   node = result->createChild("comm.Hosts");
216
217   for(const_host_iterator ii = host_begin(), maxii = host_end(); ii != maxii; ii ++)
218     host(ii)->asXML(node);
219
220   return result;
221 }
222