Remove dynamic exceptions
[anna.git] / source / comm / ServerSocket.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 #include <anna/core/tracing/Logger.hpp>
10 #include <anna/core/tracing/TraceMethod.hpp>
11 #include <anna/config/defines.hpp>
12 #include <anna/core/functions.hpp>
13
14 #include <anna/xml/Node.hpp>
15 #include <anna/xml/Attribute.hpp>
16
17 #include <anna/comm/ServerSocket.hpp>
18 #include <anna/comm/internal/BinderSocket.hpp>
19 #include <anna/comm/ClientSocket.hpp>
20
21 using namespace std;
22 using namespace anna;
23
24 //static
25 const Millisecond comm::ServerSocket::DefaultBindDelay(200);
26
27 comm::ServerSocket::~ServerSocket() {
28    delete a_binderSocket;
29 }
30
31 void comm::ServerSocket::prepare()
32 noexcept(false) {
33    if (::listen(Socket::a_fd, a_backlog) == -1) {
34       const int xerrno(errno);
35       std::string msg(asString());
36       msg += " | listen";
37       throw RuntimeException(msg, xerrno, ANNA_FILE_LOCATION);
38    }
39 }
40
41 int comm::ServerSocket::do_bind(const struct sockaddr* s, const int len)
42 noexcept(false) {
43    if (a_sharedBind == false)
44       return Socket::do_bind(s, len);
45
46    if (a_binderSocket == NULL)
47       a_binderSocket = new BinderSocket(this);
48
49    a_binderSocket->requestBind(s, len);
50    return 0;
51 }
52 /*
53  * (1) Se invoca desde [Tx], pero hay que evitar que el .create se invoque a la misma vez que algún [Tz] este invocando
54  * al ServerSocket::release porque ha cerrado la conexión.
55  */
56 comm::LocalConnection* comm::ServerSocket::accept()
57 noexcept(false) {
58    LOGMETHOD(TraceMethod traceMethod(Logger::Local7, "comm::ServerSocket", "accept", ANNA_FILE_LOCATION));
59    LocalConnection* result(NULL);
60    sockaddr_in sourceAddress;
61    socklen_t len(sizeof(sockaddr_in));
62    anna_memset(&sourceAddress, 0, sizeof(sockaddr_in));
63    int newSocket = ::accept(Socket::a_fd, (sockaddr*) & sourceAddress, &len);
64
65    if (newSocket < 0) {
66       const int xerrno = errno;
67
68       if (xerrno != EWOULDBLOCK && xerrno != EINTR)
69          throw RuntimeException(asString(), xerrno, ANNA_FILE_LOCATION);
70    } else {
71       result = a_localConnections.create();              // (1)
72
73       try {
74          result->setServerSocket(this);
75          ClientSocket* clientSocket;
76
77          if ((clientSocket = result->getClientSocket()) == NULL) {
78             clientSocket = allocateClientSocket();
79             result->setClientSocket(clientSocket);
80             LOGDEBUG(
81                string msg("comm::ServerSocket::accept | New ClientSocket: ");
82                msg += functions::asHexString(anna_ptrnumber_cast(clientSocket));
83                msg += functions::asText(" | fd: ", newSocket);
84                Logger::debug(msg, ANNA_FILE_LOCATION);
85             );
86          } else {
87             LOGDEBUG(
88                string msg("comm::ServerSocket::accept | Reuse ClientSocket: ");
89                msg += functions::asHexString(anna_ptrnumber_cast(clientSocket));
90                msg += functions::asText(" | fd: ", newSocket);
91                Logger::debug(msg, ANNA_FILE_LOCATION);
92             );
93          }
94
95          clientSocket->setfd(newSocket);
96          clientSocket->setCategory(getCategory());
97          clientSocket->setReceiverFactory(*getReceiverFactory());
98          LOGDEBUG(
99             string msg("comm::ServerSocket::accept | ");
100             msg += asString();
101             msg += " | ";
102             msg += result->asString();
103             Logger::debug(msg, ANNA_FILE_LOCATION);
104          );
105       } catch (RuntimeException&) {
106          ::close(newSocket);
107          release(result);
108          throw;
109       }
110    }
111
112    return result;
113 }
114
115 comm::ClientSocket* comm::ServerSocket::allocateClientSocket() const
116 {
117    return new ClientSocket(getTransportFactory(), Socket::Domain::Inet, Socket::Type::Stream);
118 }
119
120 /*
121  * Se invoca desde el [Tz] = LocalConnection:[Tx] -> Communicator
122  * De forma que hay que bloquear esta instancia para que SU [Tx] no vaya a crear en este momento una nueva conexión.
123  *
124  *
125  * Se invoca desde comm::handler::ServerSocket::apply::[Tx] -> <null>
126  */
127 void comm::ServerSocket::release(LocalConnection* localConnection)
128 noexcept(false) {
129    if (localConnection == NULL)
130       return;
131
132    if (localConnection != NULL)
133       localConnection->setServerSocket(NULL);
134
135    a_localConnections.release(localConnection);
136 }
137
138 std::string comm::ServerSocket::asString() const
139 {
140    std::string msg("comm::ServerSocket { ");
141    msg += comm::Socket::asString();
142    msg += " | Bind: ";
143
144    if (a_sharedBind == true) {
145       msg += "Shared | ";
146       msg += functions::asString(a_binderSocket);
147    } else
148       msg += "Exclusive";
149
150    return msg += " }";
151 }
152
153 xml::Node* comm::ServerSocket::asXML(xml::Node* parent) const
154 noexcept(false) {
155    xml::Node* result = parent->createChild("comm.ServerSocket");
156    comm::Socket::asXML(result);
157    result->createAttribute("Bind", (a_sharedBind) ? "Shared" : "Exclusive");
158
159    if (a_sharedBind == true && a_binderSocket != NULL)
160       a_binderSocket->asXML(result);
161
162    return result;
163 }