1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/p2p/host_address_request.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "base/message_loop/message_loop_proxy.h"
10#include "content/common/p2p_messages.h"
11#include "content/renderer/p2p/socket_dispatcher.h"
12#include "jingle/glue/utils.h"
13
14namespace content {
15
16P2PAsyncAddressResolver::P2PAsyncAddressResolver(
17    P2PSocketDispatcher* dispatcher)
18    : dispatcher_(dispatcher),
19      ipc_message_loop_(dispatcher->message_loop()),
20      delegate_message_loop_(base::MessageLoopProxy::current()),
21      state_(STATE_CREATED),
22      request_id_(0),
23      registered_(false) {
24  AddRef();  // Balanced in Destroy().
25}
26
27P2PAsyncAddressResolver::~P2PAsyncAddressResolver() {
28  DCHECK(state_ == STATE_CREATED || state_ == STATE_FINISHED);
29  DCHECK(!registered_);
30}
31
32void P2PAsyncAddressResolver::Start(const rtc::SocketAddress& host_name,
33                                    const DoneCallback& done_callback) {
34  DCHECK(delegate_message_loop_->BelongsToCurrentThread());
35  DCHECK_EQ(STATE_CREATED, state_);
36
37  state_ = STATE_SENT;
38  ipc_message_loop_->PostTask(FROM_HERE, base::Bind(
39      &P2PAsyncAddressResolver::DoSendRequest, this, host_name, done_callback));
40}
41
42void P2PAsyncAddressResolver::Cancel() {
43  DCHECK(delegate_message_loop_->BelongsToCurrentThread());
44
45  if (state_ != STATE_FINISHED) {
46    state_ = STATE_FINISHED;
47    ipc_message_loop_->PostTask(FROM_HERE, base::Bind(
48        &P2PAsyncAddressResolver::DoUnregister, this));
49  }
50  done_callback_.Reset();
51}
52
53void P2PAsyncAddressResolver::DoSendRequest(
54    const rtc::SocketAddress& host_name,
55    const DoneCallback& done_callback) {
56  DCHECK(ipc_message_loop_->BelongsToCurrentThread());
57
58  done_callback_ = done_callback;
59  request_id_ = dispatcher_->RegisterHostAddressRequest(this);
60  registered_ = true;
61  dispatcher_->SendP2PMessage(
62      new P2PHostMsg_GetHostAddress(host_name.hostname(), request_id_));
63}
64
65void P2PAsyncAddressResolver::DoUnregister() {
66  DCHECK(ipc_message_loop_->BelongsToCurrentThread());
67  if (registered_) {
68    dispatcher_->UnregisterHostAddressRequest(request_id_);
69    registered_ = false;
70  }
71}
72
73void P2PAsyncAddressResolver::OnResponse(const net::IPAddressList& addresses) {
74  DCHECK(ipc_message_loop_->BelongsToCurrentThread());
75  DCHECK(registered_);
76
77  dispatcher_->UnregisterHostAddressRequest(request_id_);
78  registered_ = false;
79
80  delegate_message_loop_->PostTask(FROM_HERE, base::Bind(
81      &P2PAsyncAddressResolver::DeliverResponse, this, addresses));
82}
83
84void P2PAsyncAddressResolver::DeliverResponse(
85    const net::IPAddressList& addresses) {
86  DCHECK(delegate_message_loop_->BelongsToCurrentThread());
87  if (state_ == STATE_SENT) {
88    state_ = STATE_FINISHED;
89    base::ResetAndReturn(&done_callback_).Run(addresses);
90  }
91}
92
93}  // namespace content
94