* fix [GAM-28] problems in routingsender.cpp
[profile/ivi/genivi/genivi-audio-manager.git] / AudioManagerDaemon / src / CAmTelnetServer.cpp
1 /**
2  * Copyright (C) 2011, BMW AG
3  *
4  * GeniviAudioMananger AudioManagerDaemon
5  *
6  * \file CAmTelnetServer.cpp
7  *
8  * \date 20-Oct-2011 3:42:04 PM
9  * \author Christian Mueller (christian.ei.mueller@bmw.de)
10  *
11  * \section License
12  * GNU Lesser General Public License, version 2.1, with special exception (GENIVI clause)
13  * Copyright (C) 2011, BMW AG Christian Mueller  Christian.ei.mueller@bmw.de
14  *
15  * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation.
16  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License, version 2.1, for more details.
17  * You should have received a copy of the GNU Lesser General Public License, version 2.1, along with this program; if not, see <http://www.gnu.org/licenses/lgpl-2.1.html>.
18  * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may also be applicable to programs even in cases in which the program is not a library in the technical sense.
19  * Linking AudioManager statically or dynamically with other modules is making a combined work based on AudioManager. You may license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to license your linked modules under the GNU Lesser General Public License, version 2.1, you may use the program under the following exception.
20  * As a special exception, the copyright holders of AudioManager give you permission to combine AudioManager with software programs or libraries that are released under any license unless such a combination is not permitted by the license of such a software program or library. You may copy and distribute such a system following the terms of the GNU Lesser General Public License, version 2.1, including this special exception, for AudioManager and the licenses of the other code concerned.
21  * Note that people who make modified versions of AudioManager are not obligated to grant this special exception for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, version 2.1, gives permission to release a modified version without this exception; this exception also makes it possible to release a modified version which carries forward this exception.
22  *
23  */
24
25 #include "CAmTelnetServer.h"
26 #include <cassert>
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
29 #include <sys/ioctl.h>
30 #include <string.h>
31 #include <netdb.h>
32 #include <config.h>
33 #include <errno.h>
34 #include <sstream>
35 #include <istream>
36 #include <iostream>
37 #include <iterator>
38 #include "CAmDatabaseHandler.h"
39 #include "CAmRoutingSender.h"
40 #include "shared/CAmDltWrapper.h"
41 #include "CAmTelnetMenuHelper.h"
42
43 namespace am {
44
45 CAmTelnetServer* CAmTelnetServer::instance = 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),
51    telnetReceiveFiredCB(this,&CAmTelnetServer::receiveData),
52    telnetDispatchCB(this,&CAmTelnetServer::dispatchData),
53    telnetCheckCB(this,&CAmTelnetServer::check),
54    mSocketHandler(iSocketHandler),
55    mCommandSender(iCommandSender),
56    mCommandReceiver(iCommandReceiver),
57    mRoutingSender(iRoutingSender),
58    mRoutingReceiver(iRoutingReceiver),
59    mControlSender(iControlSender),
60    mControlReceiver(iControlReceiver),
61    mDatabasehandler(iDatabasehandler),
62    mRouter(iRouter),
63    mConnecthandle(),
64    mMsgList(),
65    mListConnections(),
66    mConnectFD(NULL),
67    mServerPort(servPort),
68    mMaxConnections(maxConnections),
69    mTelnetMenuHelper(iSocketHandler,iCommandSender,iCommandReceiver,iRoutingSender,iRoutingReceiver,iControlSender,iControlReceiver,iDatabasehandler,iRouter,this)
70 {
71         assert(mSocketHandler!=NULL);
72         assert(mCommandReceiver!=NULL);
73         assert(mCommandSender!=NULL);
74         assert(mControlSender!=NULL);
75         assert(mControlReceiver!=NULL);
76         assert(mRoutingSender!=NULL);
77         assert(mRoutingReceiver!=NULL);
78         assert(mDatabasehandler!=NULL);
79         assert(mRouter!=NULL);
80         assert(servPort!=0);
81         assert(mMaxConnections!=0);
82
83         instance = this;
84         //mTelnetMenuHelper.setTelnetServer(this);
85
86         int yes = 1;
87         struct sockaddr_in servAddr;
88
89     //setup the port Listener
90     mConnectFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
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     mSocketHandler->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         // Notiy menuhelper
130         mTelnetMenuHelper.newSocketConnection(connection.filedescriptor);
131
132         //set the correct event:
133         short event = 0;
134         event |=POLLIN;
135
136         //aded the filedescriptor to the sockethandler and register the callbacks for receiving the data
137         mSocketHandler->addFDPoll(connection.filedescriptor,event,NULL,&telnetReceiveFiredCB,&telnetCheckCB,&telnetDispatchCB,NULL,connection.handle);
138         mListConnections.push_back(connection);
139 }
140
141 void CAmTelnetServer::disconnectClient(int filedescriptor)
142 {
143    std::vector<connection_s>::iterator iter = mListConnections.begin();
144    while(iter != mListConnections.end())
145    {
146       if( filedescriptor == iter->filedescriptor )
147       {
148          if( E_OK == mSocketHandler->removeFDPoll(iter->handle))
149          {
150             mListConnections.erase(iter);
151             close(filedescriptor);
152          }
153          else
154          {
155             // TODO: Handle error
156          }
157
158          break;
159       }
160       iter++;
161    }
162 }
163
164 void CAmTelnetServer::receiveData(const pollfd pollfd, const sh_pollHandle_t handle, void *userData)
165 {
166     (void) handle;
167     (void) userData;
168         //initialize buffer
169         char buffer[100];
170         //read until buffer is full or no more data is there
171         int read=recv(pollfd.fd,buffer,100,NULL);
172         if (read>1)
173         {
174                 //read the message and store it in a queue - its a telnet connection so data will be sent on enter !
175                 std::string msg=std::string(buffer,read);
176                 mMsgList.push(msg);
177         }
178 }
179
180 bool CAmTelnetServer::dispatchData(const sh_pollHandle_t handle, void *userData)
181 {
182     (void) userData;
183         std::vector<connection_s>::iterator iterator=mListConnections.begin();
184         for(;iterator!=mListConnections.end();++iterator)
185         {
186                 if(iterator->handle==handle) break;
187         }
188         //if (iterator==mListConnections.end()) return false;
189
190         std::string command;
191         std::queue<std::string> MsgQueue;
192         if(!mMsgList.empty())
193         {
194            sliceCommand(mMsgList.front(),command,MsgQueue);
195            mMsgList.pop();
196         }
197
198         mTelnetMenuHelper.enterCmdQueue(MsgQueue,iterator->filedescriptor);
199
200         // must return false to stop endless polling
201         return false;
202
203         /*
204         mMsgList.pop();
205         mMapCommand_t::iterator commandIter=mMapCommands.find(command);
206         if (commandIter==mMapCommands.end())
207         {
208                 send(iterator->filedescriptor,"Command not found!\n",20,0);
209         }
210         else
211         {
212            commandIter->second(msg,iterator->filedescriptor);
213                 //(*commandIter).second(msg,iterator->filedescriptor);
214         }
215
216         //remove the message from the queue and return false if there is no more message to read.
217         if (mMsgList.size()!=0) return true;
218         return false;
219         */
220 }
221
222 bool CAmTelnetServer::check(const sh_pollHandle_t handle, void *userData)
223 {
224     (void)handle;
225     (void)userData;
226     if (mMsgList.size() != 0) return true;
227     return false;
228 }
229
230 void am::CAmTelnetServer::sliceCommand(const std::string & string, std::string & command, std::queue<std::string> & MsgQueue)
231 {
232     (void) command;
233     std::stringstream stream(string);
234     std::istream_iterator<std::string> begin(stream);
235     std::istream_iterator<std::string> end;
236     std::string cmd;
237     bool endOfStream = false;
238
239     int c = 0;
240
241     while(!endOfStream)
242     {
243        cmd = *begin;
244        MsgQueue.push(cmd);
245        begin++;
246
247        if(begin == end )
248        {
249           endOfStream = true;
250        }
251        c++;
252     }
253
254
255     /*
256     command = *begin++;
257     msg = std::vector<std::string>(begin, end);
258     */
259 }
260 }
261
262