| /* | |
| * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
| * | |
| * Use of this source code is governed by a BSD-style license | |
| * that can be found in the LICENSE file in the root of the source | |
| * tree. An additional intellectual property rights grant can be found | |
| * in the file PATENTS. All contributing project authors may | |
| * be found in the AUTHORS file in the root of the source tree. | |
| */ | |
| #include "p2p/test/stun_server.h" | |
| #include <memory> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/strings/string_view.h" | |
| #include "api/sequence_checker.h" | |
| #include "api/transport/stun.h" | |
| #include "rtc_base/async_packet_socket.h" | |
| #include "rtc_base/async_udp_socket.h" | |
| #include "rtc_base/byte_buffer.h" | |
| #include "rtc_base/checks.h" | |
| #include "rtc_base/logging.h" | |
| #include "rtc_base/network/received_packet.h" | |
| #include "rtc_base/socket_address.h" | |
| namespace webrtc { | |
| StunServer::StunServer(std::unique_ptr<AsyncUDPSocket> socket) | |
| : socket_(std::move(socket)) { | |
| socket_->RegisterReceivedPacketCallback( | |
| [&](AsyncPacketSocket* socket, const ReceivedIpPacket& packet) { | |
| OnPacket(socket, packet); | |
| }); | |
| } | |
| StunServer::~StunServer() { | |
| RTC_DCHECK_RUN_ON(&sequence_checker_); | |
| socket_->DeregisterReceivedPacketCallback(); | |
| } | |
| void StunServer::OnPacket(AsyncPacketSocket* socket, | |
| const ReceivedIpPacket& packet) { | |
| RTC_DCHECK_RUN_ON(&sequence_checker_); | |
| // Parse the STUN message; eat any messages that fail to parse. | |
| ByteBufferReader bbuf(packet.payload()); | |
| StunMessage msg; | |
| if (!msg.Read(&bbuf)) { | |
| return; | |
| } | |
| // TODO(?): If unknown non-optional (<= 0x7fff) attributes are found, | |
| // send a | |
| // 420 "Unknown Attribute" response. | |
| // Send the message to the appropriate handler function. | |
| switch (msg.type()) { | |
| case STUN_BINDING_REQUEST: | |
| OnBindingRequest(&msg, packet.source_address()); | |
| break; | |
| default: | |
| SendErrorResponse(msg, packet.source_address(), 600, | |
| "Operation Not Supported"); | |
| } | |
| } | |
| void StunServer::OnBindingRequest(StunMessage* msg, | |
| const SocketAddress& remote_addr) { | |
| StunMessage response(STUN_BINDING_RESPONSE, msg->transaction_id()); | |
| GetStunBindResponse(msg, remote_addr, &response); | |
| SendResponse(response, remote_addr); | |
| } | |
| void StunServer::SendErrorResponse(const StunMessage& msg, | |
| const SocketAddress& addr, | |
| int error_code, | |
| absl::string_view error_desc) { | |
| StunMessage err_msg(GetStunErrorResponseType(msg.type()), | |
| msg.transaction_id()); | |
| auto err_code = StunAttribute::CreateErrorCode(); | |
| err_code->SetCode(error_code); | |
| err_code->SetReason(std::string(error_desc)); | |
| err_msg.AddAttribute(std::move(err_code)); | |
| SendResponse(err_msg, addr); | |
| } | |
| void StunServer::SendResponse(const StunMessage& msg, | |
| const SocketAddress& addr) { | |
| ByteBufferWriter buf; | |
| msg.Write(&buf); | |
| AsyncSocketPacketOptions options; | |
| if (socket_->SendTo(buf.Data(), buf.Length(), addr, options) < 0) | |
| RTC_LOG_ERR(LS_ERROR) << "sendto"; | |
| } | |
| void StunServer::GetStunBindResponse(StunMessage* message, | |
| const SocketAddress& remote_addr, | |
| StunMessage* response) const { | |
| RTC_DCHECK_EQ(response->type(), STUN_BINDING_RESPONSE); | |
| RTC_DCHECK_EQ(response->transaction_id(), message->transaction_id()); | |
| // Tell the user the address that we received their message from. | |
| std::unique_ptr<StunAddressAttribute> mapped_addr; | |
| if (message->IsLegacy()) { | |
| mapped_addr = StunAttribute::CreateAddress(STUN_ATTR_MAPPED_ADDRESS); | |
| } else { | |
| mapped_addr = StunAttribute::CreateXorAddress(STUN_ATTR_XOR_MAPPED_ADDRESS); | |
| } | |
| mapped_addr->SetAddress(remote_addr); | |
| response->AddAttribute(std::move(mapped_addr)); | |
| } | |
| } // namespace webrtc |