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