* updated license headers
[profile/ivi/genivi/genivi-audio-manager.git] / AudioManagerDaemon / src / CAmTelnetServer.cpp
1 /**
2  * Copyright (C) 2012, GENIVI Alliance, Inc.
3  * Copyright (C) 2012, BMW AG
4  *
5  * This file is part of GENIVI Project AudioManager.
6  *
7  * Contributions are licensed to the GENIVI Alliance under one or more
8  * Contribution License Agreements.
9  *
10  * \copyright
11  * This Source Code Form is subject to the terms of the
12  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
13  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  *
16  * \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
17  * \author Frank Herchet, frank.fh.herchet@bmw.de BMW 2012
18  *
19  * \file CAmTelnetServer.cpp
20  * For further information see http://www.genivi.org/.
21  *
22  */
23
24 #include "CAmTelnetServer.h"
25 #include <cassert>
26 #include <sys/socket.h>
27 #include <arpa/inet.h>
28 #include <sys/ioctl.h>
29 #include <string.h>
30 #include <netdb.h>
31 #include <config.h>
32 #include <errno.h>
33 #include <sstream>
34 #include <istream>
35 #include <iostream>
36 #include <iterator>
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), 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,
51                 iDatabasehandler, iRouter, this)
52 {
53     assert(mpSocketHandler!=NULL);
54     assert(mpCommandReceiver!=NULL);
55     assert(mpCommandSender!=NULL);
56     assert(mpControlSender!=NULL);
57     assert(mpControlReceiver!=NULL);
58     assert(mpRoutingSender!=NULL);
59     assert(mpRoutingReceiver!=NULL);
60     assert(mpDatabasehandler!=NULL);
61     assert(mpRouter!=NULL);
62     assert(servPort!=0);
63     assert(mMaxConnections!=0);
64
65     mpInstance = this;
66     //mTelnetMenuHelper.setTelnetServer(this);
67
68     int yes = 1;
69     struct sockaddr_in servAddr;
70
71     //setup the port Listener
72     mConnectFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
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     // Notiy menuhelper
112     mTelnetMenuHelper.newSocketConnection(connection.filedescriptor);
113
114     //set the correct event:
115     short event = 0;
116     event |= POLLIN;
117
118     //aded the filedescriptor to the sockethandler and register the callbacks for receiving the data
119     mpSocketHandler->addFDPoll(connection.filedescriptor, event, NULL, &telnetReceiveFiredCB, &telnetCheckCB, &telnetDispatchCB, NULL, connection.handle);
120     mListConnections.push_back(connection);
121 }
122
123 void CAmTelnetServer::disconnectClient(int filedescriptor)
124 {
125     std::vector<connection_s>::iterator iter = mListConnections.begin();
126     while (iter != mListConnections.end())
127     {
128         if (filedescriptor == iter->filedescriptor)
129         {
130             if (E_OK == mpSocketHandler->removeFDPoll(iter->handle))
131             {
132                 mListConnections.erase(iter);
133                 close(filedescriptor);
134             }
135             else
136             {
137                 // TODO: Handle error
138             }
139
140             break;
141         }
142         iter++;
143     }
144 }
145
146 void CAmTelnetServer::receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
147 {
148     (void) handle;
149     (void) userData;
150     //initialize buffer
151     char buffer[100];
152     //read until buffer is full or no more data is there
153     int read = recv(pollfd.fd, buffer, 100, NULL);
154     if (read > 1)
155     {
156         //read the message and store it in a queue - its a telnet connection so data will be sent on enter !
157         std::string msg = std::string(buffer, read);
158         mListMessages.push(msg);
159     }
160 }
161
162 bool CAmTelnetServer::dispatchData(const sh_pollHandle_t handle, void *userData)
163 {
164     (void) userData;
165     std::vector<connection_s>::iterator iterator = mListConnections.begin();
166     for (; iterator != mListConnections.end(); ++iterator)
167     {
168         if (iterator->handle == handle)
169             break;
170     }
171
172     std::string command;
173     std::queue<std::string> MsgQueue;
174     if (!mListMessages.empty())
175     {
176         sliceCommand(mListMessages.front(), command, MsgQueue);
177         mListMessages.pop();
178     }
179
180     mTelnetMenuHelper.enterCmdQueue(MsgQueue, iterator->filedescriptor);
181
182     // must return false to stop endless polling
183     return (false);
184 }
185
186 bool CAmTelnetServer::check(const sh_pollHandle_t handle, void *userData)
187 {
188     (void) handle;
189     (void) userData;
190     if (mListMessages.size() != 0)
191         return (true);
192     return (false);
193 }
194
195 void am::CAmTelnetServer::sliceCommand(const std::string & string, std::string & command, std::queue<std::string> & MsgQueue)
196 {
197     (void) command;
198     std::stringstream stream(string);
199     std::istream_iterator<std::string> begin(stream);
200     std::istream_iterator<std::string> end;
201     std::string cmd;
202     bool endOfStream = false;
203
204     int c = 0;
205
206     while (!endOfStream)
207     {
208         cmd = *begin;
209         MsgQueue.push(cmd);
210         begin++;
211
212         if (begin == end)
213         {
214             endOfStream = true;
215         }
216         c++;
217     }
218 }
219 }
220