1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "webrtc/p2p/base/stunserver.h"
12 
13 #include "webrtc/base/bytebuffer.h"
14 #include "webrtc/base/logging.h"
15 
16 namespace cricket {
17 
StunServer(rtc::AsyncUDPSocket * socket)18 StunServer::StunServer(rtc::AsyncUDPSocket* socket) : socket_(socket) {
19   socket_->SignalReadPacket.connect(this, &StunServer::OnPacket);
20 }
21 
~StunServer()22 StunServer::~StunServer() {
23   socket_->SignalReadPacket.disconnect(this);
24 }
25 
OnPacket(rtc::AsyncPacketSocket * socket,const char * buf,size_t size,const rtc::SocketAddress & remote_addr,const rtc::PacketTime & packet_time)26 void StunServer::OnPacket(
27     rtc::AsyncPacketSocket* socket, const char* buf, size_t size,
28     const rtc::SocketAddress& remote_addr,
29     const rtc::PacketTime& packet_time) {
30   // Parse the STUN message; eat any messages that fail to parse.
31   rtc::ByteBuffer bbuf(buf, size);
32   StunMessage msg;
33   if (!msg.Read(&bbuf)) {
34     return;
35   }
36 
37   // TODO: If unknown non-optional (<= 0x7fff) attributes are found, send a
38   //       420 "Unknown Attribute" response.
39 
40   // Send the message to the appropriate handler function.
41   switch (msg.type()) {
42     case STUN_BINDING_REQUEST:
43       OnBindingRequest(&msg, remote_addr);
44       break;
45 
46     default:
47       SendErrorResponse(msg, remote_addr, 600, "Operation Not Supported");
48   }
49 }
50 
OnBindingRequest(StunMessage * msg,const rtc::SocketAddress & remote_addr)51 void StunServer::OnBindingRequest(
52     StunMessage* msg, const rtc::SocketAddress& remote_addr) {
53   StunMessage response;
54   GetStunBindReqponse(msg, remote_addr, &response);
55   SendResponse(response, remote_addr);
56 }
57 
SendErrorResponse(const StunMessage & msg,const rtc::SocketAddress & addr,int error_code,const char * error_desc)58 void StunServer::SendErrorResponse(
59     const StunMessage& msg, const rtc::SocketAddress& addr,
60     int error_code, const char* error_desc) {
61   StunMessage err_msg;
62   err_msg.SetType(GetStunErrorResponseType(msg.type()));
63   err_msg.SetTransactionID(msg.transaction_id());
64 
65   StunErrorCodeAttribute* err_code = StunAttribute::CreateErrorCode();
66   err_code->SetCode(error_code);
67   err_code->SetReason(error_desc);
68   err_msg.AddAttribute(err_code);
69 
70   SendResponse(err_msg, addr);
71 }
72 
SendResponse(const StunMessage & msg,const rtc::SocketAddress & addr)73 void StunServer::SendResponse(
74     const StunMessage& msg, const rtc::SocketAddress& addr) {
75   rtc::ByteBuffer buf;
76   msg.Write(&buf);
77   rtc::PacketOptions options;
78   if (socket_->SendTo(buf.Data(), buf.Length(), addr, options) < 0)
79     LOG_ERR(LS_ERROR) << "sendto";
80 }
81 
GetStunBindReqponse(StunMessage * request,const rtc::SocketAddress & remote_addr,StunMessage * response) const82 void StunServer::GetStunBindReqponse(StunMessage* request,
83                                      const rtc::SocketAddress& remote_addr,
84                                      StunMessage* response) const {
85   response->SetType(STUN_BINDING_RESPONSE);
86   response->SetTransactionID(request->transaction_id());
87 
88   // Tell the user the address that we received their request from.
89   StunAddressAttribute* mapped_addr;
90   if (!request->IsLegacy()) {
91     mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS);
92   } else {
93     mapped_addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS);
94   }
95   mapped_addr->SetAddress(remote_addr);
96   response->AddAttribute(mapped_addr);
97 }
98 
99 }  // namespace cricket
100