Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / base / natserver.cc
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "talk/base/natsocketfactory.h"
29 #include "talk/base/natserver.h"
30 #include "talk/base/logging.h"
31
32 namespace talk_base {
33
34 RouteCmp::RouteCmp(NAT* nat) : symmetric(nat->IsSymmetric()) {
35 }
36
37 size_t RouteCmp::operator()(const SocketAddressPair& r) const {
38   size_t h = r.source().Hash();
39   if (symmetric)
40     h ^= r.destination().Hash();
41   return h;
42 }
43
44 bool RouteCmp::operator()(
45       const SocketAddressPair& r1, const SocketAddressPair& r2) const {
46   if (r1.source() < r2.source())
47     return true;
48   if (r2.source() < r1.source())
49     return false;
50   if (symmetric && (r1.destination() < r2.destination()))
51     return true;
52   if (symmetric && (r2.destination() < r1.destination()))
53     return false;
54   return false;
55 }
56
57 AddrCmp::AddrCmp(NAT* nat)
58     : use_ip(nat->FiltersIP()), use_port(nat->FiltersPort()) {
59 }
60
61 size_t AddrCmp::operator()(const SocketAddress& a) const {
62   size_t h = 0;
63   if (use_ip)
64     h ^= HashIP(a.ipaddr());
65   if (use_port)
66     h ^= a.port() | (a.port() << 16);
67   return h;
68 }
69
70 bool AddrCmp::operator()(
71       const SocketAddress& a1, const SocketAddress& a2) const {
72   if (use_ip && (a1.ipaddr() < a2.ipaddr()))
73     return true;
74   if (use_ip && (a2.ipaddr() < a1.ipaddr()))
75     return false;
76   if (use_port && (a1.port() < a2.port()))
77     return true;
78   if (use_port && (a2.port() < a1.port()))
79     return false;
80   return false;
81 }
82
83 NATServer::NATServer(
84     NATType type, SocketFactory* internal, const SocketAddress& internal_addr,
85     SocketFactory* external, const SocketAddress& external_ip)
86     : external_(external), external_ip_(external_ip.ipaddr(), 0) {
87   nat_ = NAT::Create(type);
88
89   server_socket_ = AsyncUDPSocket::Create(internal, internal_addr);
90   server_socket_->SignalReadPacket.connect(this, &NATServer::OnInternalPacket);
91
92   int_map_ = new InternalMap(RouteCmp(nat_));
93   ext_map_ = new ExternalMap();
94 }
95
96 NATServer::~NATServer() {
97   for (InternalMap::iterator iter = int_map_->begin();
98        iter != int_map_->end();
99        iter++)
100     delete iter->second;
101
102   delete nat_;
103   delete server_socket_;
104   delete int_map_;
105   delete ext_map_;
106 }
107
108 void NATServer::OnInternalPacket(
109     AsyncPacketSocket* socket, const char* buf, size_t size,
110     const SocketAddress& addr, const PacketTime& packet_time) {
111
112   // Read the intended destination from the wire.
113   SocketAddress dest_addr;
114   size_t length = UnpackAddressFromNAT(buf, size, &dest_addr);
115
116   // Find the translation for these addresses (allocating one if necessary).
117   SocketAddressPair route(addr, dest_addr);
118   InternalMap::iterator iter = int_map_->find(route);
119   if (iter == int_map_->end()) {
120     Translate(route);
121     iter = int_map_->find(route);
122   }
123   ASSERT(iter != int_map_->end());
124
125   // Allow the destination to send packets back to the source.
126   iter->second->WhitelistInsert(dest_addr);
127
128   // Send the packet to its intended destination.
129   talk_base::PacketOptions options;
130   iter->second->socket->SendTo(buf + length, size - length, dest_addr, options);
131 }
132
133 void NATServer::OnExternalPacket(
134     AsyncPacketSocket* socket, const char* buf, size_t size,
135     const SocketAddress& remote_addr, const PacketTime& packet_time) {
136
137   SocketAddress local_addr = socket->GetLocalAddress();
138
139   // Find the translation for this addresses.
140   ExternalMap::iterator iter = ext_map_->find(local_addr);
141   ASSERT(iter != ext_map_->end());
142
143   // Allow the NAT to reject this packet.
144   if (ShouldFilterOut(iter->second, remote_addr)) {
145     LOG(LS_INFO) << "Packet from " << remote_addr.ToSensitiveString()
146                  << " was filtered out by the NAT.";
147     return;
148   }
149
150   // Forward this packet to the internal address.
151   // First prepend the address in a quasi-STUN format.
152   scoped_ptr<char[]> real_buf(new char[size + kNATEncodedIPv6AddressSize]);
153   size_t addrlength = PackAddressForNAT(real_buf.get(),
154                                         size + kNATEncodedIPv6AddressSize,
155                                         remote_addr);
156   // Copy the data part after the address.
157   talk_base::PacketOptions options;
158   std::memcpy(real_buf.get() + addrlength, buf, size);
159   server_socket_->SendTo(real_buf.get(), size + addrlength,
160                          iter->second->route.source(), options);
161 }
162
163 void NATServer::Translate(const SocketAddressPair& route) {
164   AsyncUDPSocket* socket = AsyncUDPSocket::Create(external_, external_ip_);
165
166   if (!socket) {
167     LOG(LS_ERROR) << "Couldn't find a free port!";
168     return;
169   }
170
171   TransEntry* entry = new TransEntry(route, socket, nat_);
172   (*int_map_)[route] = entry;
173   (*ext_map_)[socket->GetLocalAddress()] = entry;
174   socket->SignalReadPacket.connect(this, &NATServer::OnExternalPacket);
175 }
176
177 bool NATServer::ShouldFilterOut(TransEntry* entry,
178                                 const SocketAddress& ext_addr) {
179   return entry->WhitelistContains(ext_addr);
180 }
181
182 NATServer::TransEntry::TransEntry(
183     const SocketAddressPair& r, AsyncUDPSocket* s, NAT* nat)
184     : route(r), socket(s) {
185   whitelist = new AddressSet(AddrCmp(nat));
186 }
187
188 NATServer::TransEntry::~TransEntry() {
189   delete whitelist;
190   delete socket;
191 }
192
193 void NATServer::TransEntry::WhitelistInsert(const SocketAddress& addr) {
194   CritScope cs(&crit_);
195   whitelist->insert(addr);
196 }
197
198 bool NATServer::TransEntry::WhitelistContains(const SocketAddress& ext_addr) {
199   CritScope cs(&crit_);
200   return whitelist->find(ext_addr) == whitelist->end();
201 }
202
203 }  // namespace talk_base