* some minor coverity check fixes
[profile/ivi/genivi/genivi-audio-manager.git] / AudioManagerDaemon / src / CAmTelnetServer.cpp
1 /**
2  * Copyright (C) 2012, BMW AG
3  *
4  * This file is part of GENIVI Project AudioManager.
5  *
6  * Contributions are licensed to the GENIVI Alliance under one or more
7  * Contribution License Agreements.
8  *
9  * \copyright
10  * This Source Code Form is subject to the terms of the
11  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
12  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  *
15  * \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
16  * \author Frank Herchet, frank.fh.herchet@bmw.de BMW 2012
17  *
18  * \file CAmTelnetServer.cpp
19  * For further information see http://www.genivi.org/.
20  *
21  */
22
23 #include "CAmTelnetServer.h"
24 #include <cassert>
25 #include <sys/socket.h>
26 #include <arpa/inet.h>
27 #include <sys/ioctl.h>
28 #include <string.h>
29 #include <netdb.h>
30 #include <config.h>
31 #include <errno.h>
32 #include <sstream>
33 #include <istream>
34 #include <iostream>
35 #include <iterator>
36 #include <unistd.h>
37 #include "CAmDatabaseHandler.h"
38 #include "CAmRoutingSender.h"
39 #include "CAmTelnetMenuHelper.h"
40 #include "shared/CAmDltWrapper.h"
41
42 namespace am
43 {
44
45 CAmTelnetServer* CAmTelnetServer::mpInstance = NULL;
46
47 #define PRINT_BOOL(var) var ? output+="true\t\t" : output+="false\t\t";
48
49 CAmTelnetServer::CAmTelnetServer(CAmSocketHandler *iSocketHandler, CAmCommandSender *iCommandSender, CAmCommandReceiver *iCommandReceiver, CAmRoutingSender *iRoutingSender, CAmRoutingReceiver *iRoutingReceiver, CAmControlSender *iControlSender, CAmControlReceiver *iControlReceiver, CAmDatabaseHandler *iDatabasehandler, CAmRouter *iRouter, unsigned int servPort, unsigned int maxConnections) :
50         telnetConnectFiredCB(this, &CAmTelnetServer::connectSocket), //
51         telnetReceiveFiredCB(this, &CAmTelnetServer::receiveData), //
52         telnetDispatchCB(this, &CAmTelnetServer::dispatchData), //
53         telnetCheckCB(this, &CAmTelnetServer::check), //
54         mpSocketHandler(iSocketHandler), //
55         mpCommandSender(iCommandSender), //
56         mpCommandReceiver(iCommandReceiver), //
57         mpRoutingSender(iRoutingSender), //
58         mpRoutingReceiver(iRoutingReceiver), //
59         mpControlSender(iControlSender), //
60         mpControlReceiver(iControlReceiver), //
61         mpDatabasehandler(iDatabasehandler), //
62         mpRouter(iRouter), //
63         mConnecthandle(), //
64         mListMessages(), //
65         mListConnections(), //
66         mConnectFD(0), //
67         mServerPort(servPort), //
68         mMaxConnections(maxConnections), //
69         mTelnetMenuHelper(iSocketHandler, iCommandSender, iCommandReceiver, iRoutingSender, iRoutingReceiver, iControlSender, iControlReceiver, iDatabasehandler, iRouter, this)
70 {
71     assert(mpSocketHandler!=NULL);
72     assert(mpCommandReceiver!=NULL);
73     assert(mpCommandSender!=NULL);
74     assert(mpControlSender!=NULL);
75     assert(mpControlReceiver!=NULL);
76     assert(mpRoutingSender!=NULL);
77     assert(mpRoutingReceiver!=NULL);
78     assert(mpDatabasehandler!=NULL);
79     assert(mpRouter!=NULL);
80     assert(servPort!=0);
81     assert(mMaxConnections!=0);
82
83     mpInstance = this;
84     //mTelnetMenuHelper.setTelnetServer(this);
85
86     int yes = 1;
87     struct sockaddr_in servAddr;
88
89     //setup the port Listener
90     mConnectFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
91     assert (mConnectFD>0);
92     assert(setsockopt(mConnectFD, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int))==0);
93     memset(&servAddr, 0, sizeof(servAddr));
94     servAddr.sin_family = AF_INET;
95     servAddr.sin_addr.s_addr = INADDR_ANY;
96     servAddr.sin_port = htons(servPort);
97     assert(bind(mConnectFD, (struct sockaddr *) &servAddr, sizeof(servAddr))==0);
98
99     if (listen(mConnectFD, mMaxConnections) < 0)
100     {
101         logError("TelnetServer::TelnetServerk cannot listen ", errno);
102     }
103     else
104         logInfo("TelnetServer::TelnetServer started listening on port", mServerPort);
105
106     int a = 1;
107     ioctl(mConnectFD, FIONBIO, (char *) &a);
108     setsockopt(mConnectFD, SOL_SOCKET, SO_KEEPALIVE, (char *) &a, sizeof(a));
109
110     short events = 0;
111     events |= POLLIN;
112     mpSocketHandler->addFDPoll(mConnectFD, events, NULL, &telnetConnectFiredCB, NULL, NULL, NULL, mConnecthandle);
113 }
114
115 CAmTelnetServer::~CAmTelnetServer()
116 {
117 }
118
119 void CAmTelnetServer::connectSocket(const pollfd pfd, const sh_pollHandle_t handle, void *userData)
120 {
121     (void) handle;
122     (void) userData;
123     //first, accept the connection, create a new filedescriptor
124     struct sockaddr answer;
125     socklen_t len = sizeof(answer);
126     connection_s connection;
127     connection.handle = 0;
128     connection.filedescriptor = accept(pfd.fd, (struct sockaddr*) &answer, &len);
129
130     assert(connection.filedescriptor>0);
131
132     // Notiy menuhelper
133     mTelnetMenuHelper.newSocketConnection(connection.filedescriptor);
134
135     //set the correct event:
136     short event = 0;
137     event |= POLLIN;
138
139     //aded the filedescriptor to the sockethandler and register the callbacks for receiving the data
140     mpSocketHandler->addFDPoll(connection.filedescriptor, event, NULL, &telnetReceiveFiredCB, &telnetCheckCB, &telnetDispatchCB, NULL, connection.handle);
141     mListConnections.push_back(connection);
142 }
143
144 void CAmTelnetServer::disconnectClient(int filedescriptor)
145 {
146     std::vector<connection_s>::iterator iter = mListConnections.begin();
147     while (iter != mListConnections.end())
148     {
149         if (filedescriptor == iter->filedescriptor)
150         {
151             if (E_OK == mpSocketHandler->removeFDPoll(iter->handle))
152             {
153                 mListConnections.erase(iter);
154                 close(filedescriptor);
155             }
156             else
157             {
158                 // TODO: Handle error
159             }
160
161             break;
162         }
163         iter++;
164     }
165 }
166
167 void CAmTelnetServer::receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
168 {
169     (void) handle;
170     (void) userData;
171     //initialize buffer
172     char buffer[100];
173     //read until buffer is full or no more data is there
174     int read = recv(pollfd.fd, buffer, 100, 0);
175     if (read > 1)
176     {
177         //read the message and store it in a queue - its a telnet connection so data will be sent on enter !
178         std::string msg = std::string(buffer, read);
179         mListMessages.push(msg);
180     }
181 }
182
183 bool CAmTelnetServer::dispatchData(const sh_pollHandle_t handle, void *userData)
184 {
185     (void) userData;
186     std::vector<connection_s>::iterator iterator = mListConnections.begin();
187     for (; iterator != mListConnections.end(); ++iterator)
188     {
189         if (iterator->handle == handle)
190             break;
191     }
192     if (iterator==mListConnections.end())
193     {
194         logError("CAmTelnetServer::dispatchData could not find handle !");
195         return (false);
196     }
197
198     std::string command;
199     std::queue<std::string> MsgQueue;
200     if (!mListMessages.empty())
201     {
202         sliceCommand(mListMessages.front(), command, MsgQueue);
203         mListMessages.pop();
204         mTelnetMenuHelper.enterCmdQueue(MsgQueue, iterator->filedescriptor);
205     }
206     else
207     {
208         logError("CAmTelnetServer::dispatchData Message queue was empty!");
209     }
210
211     // must return false to stop endless polling
212     return (false);
213 }
214
215 bool CAmTelnetServer::check(const sh_pollHandle_t handle, void *userData)
216 {
217     (void) handle;
218     (void) userData;
219     if (mListMessages.size() != 0)
220         return (true);
221     return (false);
222 }
223
224 void am::CAmTelnetServer::sliceCommand(const std::string & string, std::string & command, std::queue<std::string> & MsgQueue)
225 {
226     (void) command;
227     std::stringstream stream(string);
228     std::istream_iterator<std::string> begin(stream);
229     std::istream_iterator<std::string> end;
230     std::string cmd;
231     bool endOfStream = false;
232
233     int c = 0;
234
235     while (!endOfStream)
236     {
237         cmd = *begin;
238         MsgQueue.push(cmd);
239         begin++;
240
241         if (begin == end)
242         {
243             endOfStream = true;
244         }
245         c++;
246     }
247 }
248 }
249