147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/asyncudpsocket.h"
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h"
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const int BUF_SIZE = 64 * 1024;
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAsyncUDPSocket* AsyncUDPSocket::Create(
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    AsyncSocket* socket,
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    const SocketAddress& bind_address) {
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  scoped_ptr<AsyncSocket> owned_socket(socket);
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (socket->Bind(bind_address) < 0) {
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Bind() failed with error " << socket->GetError();
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return NULL;
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return new AsyncUDPSocket(owned_socket.release());
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAsyncUDPSocket* AsyncUDPSocket::Create(SocketFactory* factory,
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                       const SocketAddress& bind_address) {
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  AsyncSocket* socket =
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      factory->CreateAsyncSocket(bind_address.family(), SOCK_DGRAM);
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!socket)
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return NULL;
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return Create(socket, bind_address);
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAsyncUDPSocket::AsyncUDPSocket(AsyncSocket* socket)
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : socket_(socket) {
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(socket_);
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  size_ = BUF_SIZE;
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  buf_ = new char[size_];
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // The socket should start out readable but not writable.
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  socket_->SignalReadEvent.connect(this, &AsyncUDPSocket::OnReadEvent);
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  socket_->SignalWriteEvent.connect(this, &AsyncUDPSocket::OnWriteEvent);
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAsyncUDPSocket::~AsyncUDPSocket() {
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  delete [] buf_;
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSocketAddress AsyncUDPSocket::GetLocalAddress() const {
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->GetLocalAddress();
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgSocketAddress AsyncUDPSocket::GetRemoteAddress() const {
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->GetRemoteAddress();
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint AsyncUDPSocket::Send(const void *pv, size_t cb,
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                         const rtc::PacketOptions& options) {
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->Send(pv, cb);
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint AsyncUDPSocket::SendTo(const void *pv, size_t cb,
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                           const SocketAddress& addr,
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                           const rtc::PacketOptions& options) {
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->SendTo(pv, cb, addr);
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint AsyncUDPSocket::Close() {
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->Close();
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAsyncUDPSocket::State AsyncUDPSocket::GetState() const {
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return STATE_BOUND;
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint AsyncUDPSocket::GetOption(Socket::Option opt, int* value) {
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->GetOption(opt, value);
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint AsyncUDPSocket::SetOption(Socket::Option opt, int value) {
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->SetOption(opt, value);
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgint AsyncUDPSocket::GetError() const {
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->GetError();
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AsyncUDPSocket::SetError(int error) {
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket_->SetError(error);
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(socket_.get() == socket);
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SocketAddress remote_addr;
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int len = socket_->RecvFrom(buf_, size_, &remote_addr);
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (len < 0) {
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // An error here typically means we got an ICMP error in response to our
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // send datagram, indicating the remote address was unreachable.
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // When doing ICE, this kind of thing will often happen.
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // TODO: Do something better like forwarding the error to the user.
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    SocketAddress local_addr = socket_->GetLocalAddress();
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "AsyncUDPSocket[" << local_addr.ToSensitiveString() << "] "
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                 << "receive failed with error " << socket_->GetError();
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return;
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // TODO: Make sure that we got all of the packet.
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // If we did not, then we should resize our buffer to be large enough.
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SignalReadPacket(this, buf_, static_cast<size_t>(len), remote_addr,
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                   CreatePacketTime(0));
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid AsyncUDPSocket::OnWriteEvent(AsyncSocket* socket) {
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SignalReadyToSend(this);
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
123