1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
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 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.
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
40 #include <sys/types.h>
45 #include <anna/core/tracing/Logger.hpp>
46 #include <anna/core/tracing/TraceMethod.hpp>
47 #include <anna/core/DataBlock.hpp>
49 #include <anna/xml/Node.hpp>
51 #include <anna/comm/Socket.hpp>
52 #include <anna/comm/INetAddress.hpp>
53 #include <anna/comm/functions.hpp>
54 #include <anna/comm/Application.hpp>
55 #include <anna/comm/TransportFactory.hpp>
56 #include <anna/comm/ReceiverFactory.hpp>
60 using namespace anna::comm;
62 Socket::Socket(const Domain::_v domain, const Type::_v type, TransportFactory* transportFactory) :
69 a_receiverFactory(NULL) {
70 if((a_transportFactory = transportFactory) == NULL) {
72 comm::Application& app = comm::functions::getApp();
73 a_transportFactory = &app.comm::Application::getDefaultTransportFactory();
74 } catch(Exception& ex) {
80 Socket::Socket(const INetAddress& localAddress, const Type::_v type, TransportFactory* transportFactory) :
81 a_domain(Domain::Inet),
84 a_localAccessPoint(localAddress),
88 a_receiverFactory(NULL) {
89 if((a_transportFactory = transportFactory) == NULL) {
91 comm::Application& app = comm::functions::getApp();
92 a_transportFactory = &app.comm::Application::getDefaultTransportFactory();
93 } catch(Exception& ex) {
99 Socket::Socket(const std::string& path, const Type::_v type, TransportFactory* transportFactory) :
100 a_transportFactory(NULL),
101 a_domain(Domain::Unix),
104 a_localAccessPoint(path),
108 a_receiverFactory(NULL) {
109 if((a_transportFactory = transportFactory) == NULL) {
111 comm::Application& app = comm::functions::getApp();
112 a_transportFactory = &app.comm::Application::getDefaultTransportFactory();
113 } catch(Exception& ex) {
122 } catch(RuntimeException& ex) {
127 bool Socket::support(const char* transportClassName) const
129 if(a_transportFactory == NULL)
132 return anna_strcmp(a_transportFactory->getName().c_str(), transportClassName) == 0;
135 //---------------------------------------------------------------------------
136 // No hace falta que sea MT-safe porque siempre se invoca desde m�odo que
137 // ya tienen activa su propia zona de exclusin.
138 //---------------------------------------------------------------------------
140 throw(RuntimeException) {
144 if(a_transportFactory == NULL) {
145 std::string msg(asString());
146 msg += " | Transport factory was not especified";
147 throw RuntimeException(msg, ANNA_FILE_LOCATION);
150 anna_comm_socket_check(a_fd = socket((int) a_domain, (int) a_type, 0), "Cannot create the socket");
152 socklen_t len = sizeof(int);
153 anna_comm_socket_check(
154 getsockopt(a_fd, SOL_SOCKET, SO_REUSEADDR, &value, &len),
155 "Cannot obtain reuse mode"
157 a_reuseMode = (value == 1);
159 if(a_type == Type::Datagram) {
161 anna_comm_socket_check(
162 setsockopt(a_fd, SOL_SOCKET, SO_BROADCAST, &value, sizeof(int)),
163 "Cannot activate broadcast system"
168 string msg("comm::Socket::open | ");
170 Logger::debug(msg, ANNA_FILE_LOCATION);
179 Guard guard(*this, "comm::Socket::close");
188 string msg("comm::Socket::close | ");
190 Logger::debug(msg, ANNA_FILE_LOCATION);
194 bool Socket::setBlockingMode(const bool blockingMode)
195 throw(RuntimeException) {
198 anna_socket_assert(a_fd == -1, "Socket is not opened");
199 anna_comm_socket_check(opts = fcntl(a_fd, F_GETFL), "Cannot obtain state bits (F_GETFL)");
200 result = !(opts & O_NONBLOCK);
202 if(blockingMode == false)
207 anna_comm_socket_check(fcntl(a_fd, F_SETFL, opts), "Cannot set state bits (F_SETFL)");
209 string msg("comm::Socket::setBlockingMode | Current: ");
210 msg += functions::asString(blockingMode);
211 msg += functions::asText(" | Previous: ", result != 0);
212 Logger::debug(msg, ANNA_FILE_LOCATION);
214 return (result != 0);
217 bool Socket::setReuseMode(const bool reuseMode)
218 throw(RuntimeException) {
219 anna_socket_assert(a_fd == -1, "Socket is not opened");
221 if(a_reuseMode == reuseMode)
225 result = a_reuseMode;
226 int value = htons((a_reuseMode = reuseMode) == true);
227 anna_comm_socket_check(
228 setsockopt(a_fd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int)),
229 "Cannot set the reuse mode"
235 throw(RuntimeException) {
236 Guard guard(*this, "comm::Socket::bind");
241 anna_socket_assert(a_isBound == true, "Already attached");
245 a_localAccessPoint.translate(*this, s, len);
247 if(do_bind(s, len) < 0) {
248 RuntimeException ex(asString(), errno, ANNA_FILE_LOCATION);
255 string msg("comm::Socket::bind | ");
257 Logger::debug(msg, ANNA_FILE_LOCATION);
261 int Socket::do_bind(const struct sockaddr *addr, const int len)
262 throw(RuntimeException) {
263 return ::bind(a_fd, addr, len);
266 std::string Socket::asString() const
268 std::string msg("comm::Socket { Domain: ");
271 return msg += " <null> }";
274 case Domain::Unix: msg += "Unix"; break;
275 case Domain::Inet: msg += "Inet"; break;
276 default: msg += '<'; msg += functions::asString((int) a_domain); msg += '>'; break;
280 msg += (a_type == Type::Stream) ? "Stream" : "Datagram";
283 if(a_transportFactory != NULL) {
284 msg += a_transportFactory->asString();
289 msg += functions::asString(a_fd);
290 msg += " | LocalPoint: ";
291 a_localAccessPoint.asString(msg);
293 msg += functions::asString(a_isBound);
294 msg += " | Opened: ";
295 msg += functions::asString(isOpened());
298 msg += functions::asText(" | Category: ", a_category);
300 if(a_receiverFactory != NULL) {
302 msg += a_receiverFactory->asString();
308 xml::Node* Socket::asXML(xml::Node* parent) const
309 throw(RuntimeException) {
311 xml::Node* result = parent->createChild("comm.Socket");
314 case Domain::Unix: aux = "Unix"; break;
315 case Domain::Inet: aux = "Inet"; break;
316 default: aux = functions::asString((int) a_domain).c_str(); break;
319 result->createAttribute("Domain", aux);
320 result->createAttribute("Type", (a_type == Type::Stream) ? "Stream" : "Datagram");
322 if(a_transportFactory != NULL)
323 a_transportFactory->asXML(result);
325 result->createAttribute("fd", a_fd);
326 result->createAttribute("Bound", functions::asString(a_isBound));
327 result->createAttribute("Opened", functions::asString(isOpened()));
328 a_localAccessPoint.asXML("comm.LocalPoint", result);
333 if((opts = fcntl(a_fd, F_GETFL)) != -1)
334 result->createAttribute("Mode", (opts & O_NONBLOCK) ? "Non-Blocking" : "Blocking");
338 result->createAttribute("Category", a_category);
340 if(a_receiverFactory != NULL)
341 a_receiverFactory->asXML(result);
346 const char* Socket::asText(const Socket::Notify::_v v)
348 static const char* text [] = { "None", "ReceiveData", "Close", "Corrupt" };