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//------------------------------------------------------------------------------
44Server::Server(
45    ConnectionHandler *connectionHandler,
46    const char *localAddr
47) : socketAddr(localAddr)
48{
49    this->connectionHandler = connectionHandler;
50}
51
52
53//------------------------------------------------------------------------------
54void 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//------------------------------------------------------------------------------
199void 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//------------------------------------------------------------------------------
219Server::~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