1 /** @addtogroup MCD_MCDIMPL_DAEMON_SRV
2  * @{
3  * @file
4  *
5  * Connection server.
6  *
7  * Handles incoming socket connections from clients using the MobiCore driver.
8  *
9  * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote
20  *    products derived from this software without specific prior
21  *    written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
24  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
27  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 #include "public/Server.h"
36 #include <unistd.h>
37 #include <string.h>
38 #include <errno.h>
39 
40 //#define LOG_VERBOSE
41 #include "log.h"
42 
43 //------------------------------------------------------------------------------
Server(ConnectionHandler * connectionHandler,const char * localAddr)44 Server::Server(
45     ConnectionHandler *connectionHandler,
46     const char *localAddr
47 ) : socketAddr(localAddr)
48 {
49     this->connectionHandler = connectionHandler;
50 }
51 
52 
53 //------------------------------------------------------------------------------
run(void)54 void Server::run(
55     void
56 )
57 {
58     do {
59         LOG_I("Server: start listening on socket %s", socketAddr.c_str());
60 
61         // Open a socket (a UNIX domain stream socket)
62         serverSock = socket(AF_UNIX, SOCK_STREAM, 0);
63         if (serverSock < 0) {
64             LOG_ERRNO("Can't open stream socket, because socket");
65             break;
66         }
67 
68         // Fill in address structure and bind to socket
69         struct sockaddr_un  serverAddr;
70         serverAddr.sun_family = AF_UNIX;
71         strncpy(serverAddr.sun_path, socketAddr.c_str(), sizeof(serverAddr.sun_path) - 1);
72 
73         uint32_t len = strlen(serverAddr.sun_path) + sizeof(serverAddr.sun_family);
74         // Make the socket in the Abstract Domain(no path but everyone can connect)
75         serverAddr.sun_path[0] = 0;
76         if (bind(serverSock, (struct sockaddr *) &serverAddr, len) < 0) {
77             LOG_ERRNO("Binding to server socket failed, because bind");
78         }
79 
80         // Start listening on the socket
81         if (listen(serverSock, LISTEN_QUEUE_LEN) < 0) {
82             LOG_ERRNO("listen");
83             break;
84         }
85 
86         LOG_I("\n********* successfully initialized Daemon *********\n");
87 
88         for (;;) {
89             fd_set fdReadSockets;
90 
91             // Clear FD for select()
92             FD_ZERO(&fdReadSockets);
93 
94             // Select server socket descriptor
95             FD_SET(serverSock, &fdReadSockets);
96             int maxSocketDescriptor = serverSock;
97 
98             // Select socket descriptor of all connections
99             for (connectionIterator_t iterator = peerConnections.begin();
100                     iterator != peerConnections.end();
101                     ++iterator) {
102                 Connection *connection = (*iterator);
103                 int peerSocket = connection->socketDescriptor;
104                 FD_SET(peerSocket, &fdReadSockets);
105                 if (peerSocket > maxSocketDescriptor) {
106                     maxSocketDescriptor = peerSocket;
107                 }
108             }
109 
110             // Wait for activities, select() returns the number of sockets
111             // which require processing
112             LOG_V(" Server: waiting on sockets");
113             int numSockets = select(
114                                  maxSocketDescriptor + 1,
115                                  &fdReadSockets,
116                                  NULL, NULL, NULL);
117 
118             // Check if select failed
119             if (numSockets < 0) {
120                 LOG_ERRNO("select");
121                 break;
122             }
123 
124             // actually, this should not happen.
125             if (0 == numSockets) {
126                 LOG_W(" Server: select() returned 0, spurious event?.");
127                 continue;
128             }
129 
130             LOG_V(" Server: events on %d socket(s).", numSockets);
131 
132             // Check if a new client connected to the server socket
133             if (FD_ISSET(serverSock, &fdReadSockets)) {
134                 do {
135                     LOG_V(" Server: new connection attempt.");
136                     numSockets--;
137 
138                     struct sockaddr_un clientAddr;
139                     socklen_t clientSockLen = sizeof(clientAddr);
140                     int clientSock = accept(
141                                          serverSock,
142                                          (struct sockaddr *) &clientAddr,
143                                          &clientSockLen);
144 
145                     if (clientSock <= 0) {
146                         LOG_ERRNO("accept");
147                         break;
148                     }
149 
150                     Connection *connection = new Connection(clientSock, &clientAddr);
151                     peerConnections.push_back(connection);
152                     LOG_I(" Server: new socket connection established and start listening.");
153                 } while (false);
154 
155                 // we can ignore any errors from accepting a new connection.
156                 // If this fail, the client has to deal with it, we are done
157                 // and nothing has changed.
158             }
159 
160             // Handle traffic on existing client connections
161             connectionIterator_t iterator = peerConnections.begin();
162             while ( (iterator != peerConnections.end())
163                     && (numSockets > 0) ) {
164                 Connection *connection = (*iterator);
165                 int peerSocket = connection->socketDescriptor;
166 
167                 if (!FD_ISSET(peerSocket, &fdReadSockets)) {
168                     ++iterator;
169                     continue;
170                 }
171 
172                 numSockets--;
173 
174                 // the connection will be terminated if command processing
175                 // fails
176                 if (!connectionHandler->handleConnection(connection)) {
177                     LOG_I(" Server: dropping connection.");
178 
179                     //Inform the driver
180                     connectionHandler->dropConnection(connection);
181 
182                     // Remove connection from list
183                     delete connection;
184                     iterator = peerConnections.erase(iterator);
185                     continue;
186                 }
187 
188                 ++iterator;
189             }
190         }
191 
192     } while (false);
193 
194     LOG_ERRNO("Exiting Server, because");
195 }
196 
197 
198 //------------------------------------------------------------------------------
detachConnection(Connection * connection)199 void Server::detachConnection(
200     Connection *connection
201 )
202 {
203     LOG_V(" Stopping to listen on notification socket.");
204 
205     for (connectionIterator_t iterator = peerConnections.begin();
206             iterator != peerConnections.end();
207             ++iterator) {
208         Connection *tmpConnection = (*iterator);
209         if (tmpConnection == connection) {
210             peerConnections.erase(iterator);
211             LOG_I(" Stopped listening on notification socket.");
212             break;
213         }
214     }
215 }
216 
217 
218 //------------------------------------------------------------------------------
~Server(void)219 Server::~Server(
220     void
221 )
222 {
223     // Shut down the server socket
224     close(serverSock);
225 
226     // Destroy all client connections
227     connectionIterator_t iterator = peerConnections.begin();
228     while (iterator != peerConnections.end()) {
229         Connection *tmpConnection = (*iterator);
230         delete tmpConnection;
231         iterator = peerConnections.erase(iterator);
232     }
233 }
234 
235 /** @} */
236