Imported Upstream version 0.3.2
[anytun.git] / src / anyrtpproxy / commandHandler.cpp
1 /*
2  *  anytun
3  *
4  *  The secure anycast tunneling protocol (satp) defines a protocol used
5  *  for communication between any combination of unicast and anycast
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
8  *  ethernet, ip, arp ...). satp directly includes cryptography and
9  *  message authentication based on the methodes used by SRTP.  It is
10  *  intended to deliver a generic, scaleable and secure solution for
11  *  tunneling and relaying of packets of any protocol.
12  *
13  *
14  *  Copyright (C) 2007-2009 Othmar Gsenger, Erwin Nindl, 
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
19  *  Anytun is free software: you can redistribute it and/or modify
20  *  it under the terms of the GNU General Public License as published by
21  *  the Free Software Foundation, either version 3 of the License, or
22  *  any later version.
23  *
24  *  Anytun is distributed in the hope that it will be useful,
25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *  GNU General Public License for more details.
28  *
29  *  You should have received a copy of the GNU General Public License
30  *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.
31  */
32
33 #include <sstream>
34 #include <vector>
35
36 #include <iomanip>
37 #include <iostream>
38 #include <sstream>
39
40 #include <boost/bind.hpp>
41
42 #include "commandHandler.h"
43 #include "../buffer.h"
44 #include "../log.h"
45 #include "../syncQueue.h"
46 #include "syncRtpCommand.h"
47 #include "rtpSessionTable.h"
48 #include "callIdQueue.h"
49 #include "options.h"
50
51 #define MAX_COMMAND_LENGTH 1000
52
53 CommandHandler::CommandHandler(SyncQueue& q, std::string lp,PortWindow & pw) : thread_(boost::bind(run,this)), 
54                                                                                queue_(q), running_(true), control_sock_(io_service_), 
55                                                                                local_address_(""), local_port_(lp),port_window_(pw)
56 {
57   proto::resolver resolver(io_service_);
58   proto::resolver::query query(local_port_);  
59   proto::endpoint e = *resolver.resolve(query);
60   control_sock_.open(e.protocol());
61   control_sock_.bind(e);
62 }
63
64 CommandHandler::CommandHandler(SyncQueue& q, string la, std::string lp, PortWindow & pw) : thread_(boost::bind(run,this)), 
65                                                                                            queue_(q), running_(true), control_sock_(io_service_), 
66                                                                                            local_address_(la), local_port_(lp),port_window_(pw)
67 {
68   proto::resolver resolver(io_service_);
69   proto::resolver::query query(local_address_, local_port_);  
70   proto::endpoint e = *resolver.resolve(query);
71   control_sock_.open(e.protocol());
72   control_sock_.bind(e);
73 }
74
75 void CommandHandler::run(void* s)
76 {
77   CommandHandler* self = reinterpret_cast<CommandHandler*>(s);
78
79   Buffer buf(u_int32_t(MAX_COMMAND_LENGTH));
80   try
81   {
82     proto::endpoint remote_end;
83
84     int len;
85     while(1)
86     {
87       buf.setLength(MAX_COMMAND_LENGTH);
88
89       len = self->control_sock_.receive_from(boost::asio::buffer(buf.getBuf(), buf.getLength()), remote_end);
90       buf.setLength(len);
91
92       std::string ret = self->handle(std::string(reinterpret_cast<char*>(buf.getBuf()), buf.getLength())); // TODO: reinterpret is ugly
93
94       cLog.msg(Log::PRIO_DEBUG) << "CommandHandler received Command from " << remote_end << ", ret='" << ret << "'";
95
96       self->control_sock_.send_to(boost::asio::buffer(ret.c_str(), ret.length()), remote_end);
97     }
98   }
99   catch(std::exception& e)
100   {
101     self->running_ = false;
102   }
103   self->running_ = false;
104 }
105
106 bool CommandHandler::isRunning()
107 {
108   return running_;
109 }
110
111
112
113 std::string CommandHandler::handle(std::string command)
114 {
115   istringstream iss(command);
116   ostringstream oss;
117   std::string cookie;
118   std::string cmd;
119
120   iss >> cookie;
121   oss << cookie << " ";
122
123   if(iss.bad() || iss.eof()) {
124     oss << RET_ERR_SYNTAX;
125     return oss.str();
126   }
127   iss >> cmd;
128
129   std::vector<std::string> params;
130   while(!iss.bad() && !iss.eof()) {
131     std::string tmp;
132     iss >> tmp;
133     params.push_back(tmp);
134   }
135
136   switch(std::toupper(cmd[0]))
137   {
138   case CMD_REQUEST:
139     if(params.size() < 4) { oss << RET_ERR_SYNTAX; break; }
140     oss << handleRequest(cmd.erase(0,1), params[0], params[1], params[2], params[3], (params.size() < 5) ? "" : params[4]);
141     break;
142   case CMD_RESPONSE:
143     if(params.size() < 4) { oss << RET_ERR_SYNTAX; break; }
144     oss << handleResponse(cmd.erase(0,1), params[0], params[1], params[2], params[3], (params.size() < 5) ? "" : params[4]);
145     break;
146   case CMD_DELETE:
147     if(params.size() < 2) { oss << RET_ERR_SYNTAX; break; }
148     oss << handleDelete(params[0], params[1], (params.size() < 3) ? "" : params[2]);
149     break;
150   case CMD_VERSION:
151     if(cmd.length() > 1 && cmd[1] == 'F') {
152       if(params.size() < 1) { oss << RET_ERR_SYNTAX; break; }
153       oss << handleVersionF(params[0]);
154       break;
155     }
156     oss << handleVersion();
157     break;
158   case CMD_INFO:
159     oss << handleInfo();
160     break;
161   default:
162     oss << RET_ERR_SYNTAX;
163     break;
164   }
165
166   return oss.str();
167 }
168
169 string CommandHandler::handleRequest(string modifiers, string call_id, string addr, string port, string from_tag, string to_tag)
170 {
171   std::cout << "received request[" << modifiers << "] command ('" << call_id << "','" << addr  << "','" << port 
172             << "','" << from_tag << "','" << to_tag << "')" << std::endl;
173
174   try 
175   {
176     RtpSession::proto::resolver resolver(io_service_);
177     bool is_new;
178     RtpSession& session = gRtpSessionTable.getOrNewSession(call_id, is_new);
179     if(is_new)
180     {
181       u_int16_t port1 = port_window_.newPort(); // TODO: get next available port
182       u_int16_t port2 = port_window_.newPort(); // TODO: get next available port
183                         if( !port1 || !port2)
184                         {
185                                 if( port1) port_window_.freePort(port1);
186                                 if( port2) port_window_.freePort(port2);
187                                 throw std::runtime_error("no free port found");
188                         }
189       std::stringstream ps1, ps2;
190       ps1 << port1;
191       ps2 << port2;
192
193       RtpSession::proto::endpoint e1, e2;
194       if(gOpt.getLocalAddr() == "") {
195         RtpSession::proto::resolver::query query1(ps1.str());
196         e1 = *resolver.resolve(query1);
197         RtpSession::proto::resolver::query query2(ps2.str());
198         e2 = *resolver.resolve(query2);
199       }
200       else {
201         RtpSession::proto::resolver::query query1(gOpt.getLocalAddr(),ps1.str());
202         e1 = *resolver.resolve(query1);
203         RtpSession::proto::resolver::query query2(gOpt.getLocalAddr(),ps2.str());
204         e2 = *resolver.resolve(query2);
205       }
206
207       session.setLocalEnd1(e1);
208       session.setLocalEnd2(e2);
209     }
210     RtpSession::proto::resolver::query query(addr,port);
211     session.setRemoteEnd1(*resolver.resolve(query));
212
213     ostringstream oss;
214     oss << session.getLocalEnd2().port();
215     return oss.str();
216   }
217   catch(std::exception& e)
218   {
219     return RET_ERR_UNKNOWN; // TODO: change to corret error value
220   }
221 }
222
223 string CommandHandler::handleResponse(string modifiers, string call_id, string addr, string port, string from_tag, string to_tag)
224 {
225   std::cout << "received response[" << modifiers << "] command ('" << call_id << "','" << addr  << "','" << port 
226             << "','" << from_tag << "','" << to_tag << "')" << std::endl;
227
228   try
229   {
230     RtpSession& session = gRtpSessionTable.getSession(call_id);
231     RtpSession::proto::resolver resolver(io_service_);
232     RtpSession::proto::resolver::query query(addr,port);
233     session.setRemoteEnd2(*resolver.resolve(query));
234     session.isComplete(true);
235     SyncRtpCommand sc(call_id);
236     queue_.push(sc);
237
238     ostringstream oss;
239     oss << session.getLocalEnd1().port();
240     return oss.str();
241   }
242   catch(std::exception& e)
243   {
244     return RET_ERR_UNKNOWN; // TODO: change to corret error value
245   }
246 }
247
248 string CommandHandler::handleDelete(string call_id, string from_tag, string to_tag)
249 {
250   std::cout << "received delete command ('" << call_id << "','" << from_tag << "','" << to_tag << "')" << std::endl;
251
252   try
253   {
254     RtpSession& session = gRtpSessionTable.getSession(call_id);
255     session.isDead(true);
256     SyncRtpCommand sc(call_id);
257     queue_.push(sc);
258
259     return RET_OK;
260   }
261   catch(std::exception& e)
262   {
263     return RET_ERR_UNKNOWN; // TODO: change to corret error value
264   }
265 }
266
267 string CommandHandler::handleVersion()
268 {
269   std::cout << "received version command" << std::endl;  
270   return BASE_VERSION;
271 }
272
273 string CommandHandler::handleVersionF(string date_code)
274 {
275   std::cout << "received version[F] command ('" << date_code << "')" << std::endl;  
276   if(!date_code.compare(SUP_VERSION))
277     return "1";
278   
279   return "0";
280 }
281
282 string CommandHandler::handleInfo()
283 {
284   std::cout << "received info command, ignoring" << std::endl;  
285   return RET_OK;
286 }
287