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