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