* [GAM-74] resolving issues found by coverity scan
[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 "CAmDatabaseHandler.h"
37 #include "CAmRoutingSender.h"
38 #include "CAmTelnetMenuHelper.h"
39 #include "shared/CAmDltWrapper.h"
40
41 namespace am
42 {
43
44 CAmTelnetServer* CAmTelnetServer::mpInstance = NULL;
45
46 #define PRINT_BOOL(var) var ? output+="true\t\t" : output+="false\t\t";
47
48 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) :
49         telnetConnectFiredCB(this, &CAmTelnetServer::connectSocket), telnetReceiveFiredCB(this, &CAmTelnetServer::receiveData), telnetDispatchCB(this, &CAmTelnetServer::dispatchData), telnetCheckCB(this, &CAmTelnetServer::check), mpSocketHandler(iSocketHandler), mpCommandSender(iCommandSender), mpCommandReceiver(iCommandReceiver), mpRoutingSender(iRoutingSender), mpRoutingReceiver(iRoutingReceiver), mpControlSender(iControlSender), mpControlReceiver(iControlReceiver), mpDatabasehandler(iDatabasehandler), mpRouter(iRouter), mConnecthandle(), mListMessages(), mListConnections(), mConnectFD(NULL), mServerPort(servPort), mMaxConnections(maxConnections), mTelnetMenuHelper(iSocketHandler, iCommandSender, iCommandReceiver, iRoutingSender, iRoutingReceiver, iControlSender, iControlReceiver,
50                 iDatabasehandler, iRouter, this)
51 {
52     assert(mpSocketHandler!=NULL);
53     assert(mpCommandReceiver!=NULL);
54     assert(mpCommandSender!=NULL);
55     assert(mpControlSender!=NULL);
56     assert(mpControlReceiver!=NULL);
57     assert(mpRoutingSender!=NULL);
58     assert(mpRoutingReceiver!=NULL);
59     assert(mpDatabasehandler!=NULL);
60     assert(mpRouter!=NULL);
61     assert(servPort!=0);
62     assert(mMaxConnections!=0);
63
64     mpInstance = this;
65     //mTelnetMenuHelper.setTelnetServer(this);
66
67     int yes = 1;
68     struct sockaddr_in servAddr;
69
70     //setup the port Listener
71     mConnectFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
72     assert (mConnectFD>0);
73     setsockopt(mConnectFD, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
74     memset(&servAddr, 0, sizeof(servAddr));
75     servAddr.sin_family = AF_INET;
76     servAddr.sin_addr.s_addr = INADDR_ANY;
77     servAddr.sin_port = htons(servPort);
78     bind(mConnectFD, (struct sockaddr *) &servAddr, sizeof(servAddr));
79
80     if (listen(mConnectFD, mMaxConnections) < 0)
81     {
82         logError("TelnetServer::TelnetServerk cannot listen ", errno);
83     }
84     else
85         logInfo("TelnetServer::TelnetServer started listening on port", mServerPort);
86
87     int a = 1;
88     ioctl(mConnectFD, FIONBIO, (char *) &a);
89     setsockopt(mConnectFD, SOL_SOCKET, SO_KEEPALIVE, (char *) &a, sizeof(a));
90
91     short events = 0;
92     events |= POLLIN;
93     mpSocketHandler->addFDPoll(mConnectFD, events, NULL, &telnetConnectFiredCB, NULL, NULL, NULL, mConnecthandle);
94 }
95
96 CAmTelnetServer::~CAmTelnetServer()
97 {
98 }
99
100 void CAmTelnetServer::connectSocket(const pollfd pfd, const sh_pollHandle_t handle, void *userData)
101 {
102     (void) handle;
103     (void) userData;
104     //first, accept the connection, create a new filedescriptor
105     struct sockaddr answer;
106     socklen_t len = sizeof(answer);
107     connection_s connection;
108     connection.handle = 0;
109     connection.filedescriptor = accept(pfd.fd, (struct sockaddr*) &answer, &len);
110
111     assert(connection.filedescriptor>0);
112
113     // Notiy menuhelper
114     mTelnetMenuHelper.newSocketConnection(connection.filedescriptor);
115
116     //set the correct event:
117     short event = 0;
118     event |= POLLIN;
119
120     //aded the filedescriptor to the sockethandler and register the callbacks for receiving the data
121     mpSocketHandler->addFDPoll(connection.filedescriptor, event, NULL, &telnetReceiveFiredCB, &telnetCheckCB, &telnetDispatchCB, NULL, connection.handle);
122     mListConnections.push_back(connection);
123 }
124
125 void CAmTelnetServer::disconnectClient(int filedescriptor)
126 {
127     std::vector<connection_s>::iterator iter = mListConnections.begin();
128     while (iter != mListConnections.end())
129     {
130         if (filedescriptor == iter->filedescriptor)
131         {
132             if (E_OK == mpSocketHandler->removeFDPoll(iter->handle))
133             {
134                 mListConnections.erase(iter);
135                 close(filedescriptor);
136             }
137             else
138             {
139                 // TODO: Handle error
140             }
141
142             break;
143         }
144         iter++;
145     }
146 }
147
148 void CAmTelnetServer::receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
149 {
150     (void) handle;
151     (void) userData;
152     //initialize buffer
153     char buffer[100];
154     //read until buffer is full or no more data is there
155     int read = recv(pollfd.fd, buffer, 100, NULL);
156     if (read > 1)
157     {
158         //read the message and store it in a queue - its a telnet connection so data will be sent on enter !
159         std::string msg = std::string(buffer, read);
160         mListMessages.push(msg);
161     }
162 }
163
164 bool CAmTelnetServer::dispatchData(const sh_pollHandle_t handle, void *userData)
165 {
166     (void) userData;
167     std::vector<connection_s>::iterator iterator = mListConnections.begin();
168     for (; iterator != mListConnections.end(); ++iterator)
169     {
170         if (iterator->handle == handle)
171             break;
172     }
173     if (iterator==mListConnections.end())
174     {
175         logError("CAmTelnetServer::dispatchData could not find handle !");
176         return (false);
177     }
178
179     std::string command;
180     std::queue<std::string> MsgQueue;
181     if (!mListMessages.empty())
182     {
183         sliceCommand(mListMessages.front(), command, MsgQueue);
184         mListMessages.pop();
185         mTelnetMenuHelper.enterCmdQueue(MsgQueue, iterator->filedescriptor);
186     }
187     else
188     {
189         logError("CAmTelnetServer::dispatchData Message queue was empty!");
190     }
191
192     // must return false to stop endless polling
193     return (false);
194 }
195
196 bool CAmTelnetServer::check(const sh_pollHandle_t handle, void *userData)
197 {
198     (void) handle;
199     (void) userData;
200     if (mListMessages.size() != 0)
201         return (true);
202     return (false);
203 }
204
205 void am::CAmTelnetServer::sliceCommand(const std::string & string, std::string & command, std::queue<std::string> & MsgQueue)
206 {
207     (void) command;
208     std::stringstream stream(string);
209     std::istream_iterator<std::string> begin(stream);
210     std::istream_iterator<std::string> end;
211     std::string cmd;
212     bool endOfStream = false;
213
214     int c = 0;
215
216     while (!endOfStream)
217     {
218         cmd = *begin;
219         MsgQueue.push(cmd);
220         begin++;
221
222         if (begin == end)
223         {
224             endOfStream = true;
225         }
226         c++;
227     }
228 }
229 }
230