* add setSinkVolume to telnetserver
[profile/ivi/audiomanager.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     setsockopt(mConnectFD, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
73     memset(&servAddr, 0, sizeof(servAddr));
74     servAddr.sin_family = AF_INET;
75     servAddr.sin_addr.s_addr = INADDR_ANY;
76     servAddr.sin_port = htons(servPort);
77     bind(mConnectFD, (struct sockaddr *) &servAddr, sizeof(servAddr));
78
79     if (listen(mConnectFD, mMaxConnections) < 0)
80     {
81         logError("TelnetServer::TelnetServerk cannot listen ", errno);
82     }
83     else
84         logInfo("TelnetServer::TelnetServer started listening on port", mServerPort);
85
86     int a = 1;
87     ioctl(mConnectFD, FIONBIO, (char *) &a);
88     setsockopt(mConnectFD, SOL_SOCKET, SO_KEEPALIVE, (char *) &a, sizeof(a));
89
90     short events = 0;
91     events |= POLLIN;
92     mpSocketHandler->addFDPoll(mConnectFD, events, NULL, &telnetConnectFiredCB, NULL, NULL, NULL, mConnecthandle);
93 }
94
95 CAmTelnetServer::~CAmTelnetServer()
96 {
97 }
98
99 void CAmTelnetServer::connectSocket(const pollfd pfd, const sh_pollHandle_t handle, void *userData)
100 {
101     (void) handle;
102     (void) userData;
103     //first, accept the connection, create a new filedescriptor
104     struct sockaddr answer;
105     socklen_t len = sizeof(answer);
106     connection_s connection;
107     connection.handle = 0;
108     connection.filedescriptor = accept(pfd.fd, (struct sockaddr*) &answer, &len);
109
110     // Notiy menuhelper
111     mTelnetMenuHelper.newSocketConnection(connection.filedescriptor);
112
113     //set the correct event:
114     short event = 0;
115     event |= POLLIN;
116
117     //aded the filedescriptor to the sockethandler and register the callbacks for receiving the data
118     mpSocketHandler->addFDPoll(connection.filedescriptor, event, NULL, &telnetReceiveFiredCB, &telnetCheckCB, &telnetDispatchCB, NULL, connection.handle);
119     mListConnections.push_back(connection);
120 }
121
122 void CAmTelnetServer::disconnectClient(int filedescriptor)
123 {
124     std::vector<connection_s>::iterator iter = mListConnections.begin();
125     while (iter != mListConnections.end())
126     {
127         if (filedescriptor == iter->filedescriptor)
128         {
129             if (E_OK == mpSocketHandler->removeFDPoll(iter->handle))
130             {
131                 mListConnections.erase(iter);
132                 close(filedescriptor);
133             }
134             else
135             {
136                 // TODO: Handle error
137             }
138
139             break;
140         }
141         iter++;
142     }
143 }
144
145 void CAmTelnetServer::receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
146 {
147     (void) handle;
148     (void) userData;
149     //initialize buffer
150     char buffer[100];
151     //read until buffer is full or no more data is there
152     int read = recv(pollfd.fd, buffer, 100, NULL);
153     if (read > 1)
154     {
155         //read the message and store it in a queue - its a telnet connection so data will be sent on enter !
156         std::string msg = std::string(buffer, read);
157         mListMessages.push(msg);
158     }
159 }
160
161 bool CAmTelnetServer::dispatchData(const sh_pollHandle_t handle, void *userData)
162 {
163     (void) userData;
164     std::vector<connection_s>::iterator iterator = mListConnections.begin();
165     for (; iterator != mListConnections.end(); ++iterator)
166     {
167         if (iterator->handle == handle)
168             break;
169     }
170
171     std::string command;
172     std::queue<std::string> MsgQueue;
173     if (!mListMessages.empty())
174     {
175         sliceCommand(mListMessages.front(), command, MsgQueue);
176         mListMessages.pop();
177     }
178
179     mTelnetMenuHelper.enterCmdQueue(MsgQueue, iterator->filedescriptor);
180
181     // must return false to stop endless polling
182     return (false);
183 }
184
185 bool CAmTelnetServer::check(const sh_pollHandle_t handle, void *userData)
186 {
187     (void) handle;
188     (void) userData;
189     if (mListMessages.size() != 0)
190         return (true);
191     return (false);
192 }
193
194 void am::CAmTelnetServer::sliceCommand(const std::string & string, std::string & command, std::queue<std::string> & MsgQueue)
195 {
196     (void) command;
197     std::stringstream stream(string);
198     std::istream_iterator<std::string> begin(stream);
199     std::istream_iterator<std::string> end;
200     std::string cmd;
201     bool endOfStream = false;
202
203     int c = 0;
204
205     while (!endOfStream)
206     {
207         cmd = *begin;
208         MsgQueue.push(cmd);
209         begin++;
210
211         if (begin == end)
212         {
213             endOfStream = true;
214         }
215         c++;
216     }
217 }
218 }
219