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 "remoting/host/log_to_server.h"
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop_proxy.h"
9#include "remoting/base/constants.h"
10#include "remoting/host/host_status_monitor.h"
11#include "remoting/host/server_log_entry.h"
12#include "remoting/jingle_glue/iq_sender.h"
13#include "remoting/jingle_glue/signal_strategy.h"
14#include "remoting/protocol/transport.h"
15#include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
16#include "third_party/libjingle/source/talk/xmpp/constants.h"
17
18using buzz::QName;
19using buzz::XmlElement;
20
21namespace remoting {
22
23LogToServer::LogToServer(base::WeakPtr<HostStatusMonitor> monitor,
24                         ServerLogEntry::Mode mode,
25                         SignalStrategy* signal_strategy,
26                         const std::string& directory_bot_jid)
27    : monitor_(monitor),
28      mode_(mode),
29      signal_strategy_(signal_strategy),
30      directory_bot_jid_(directory_bot_jid) {
31  monitor_->AddStatusObserver(this);
32  signal_strategy_->AddListener(this);
33}
34
35LogToServer::~LogToServer() {
36  signal_strategy_->RemoveListener(this);
37  if (monitor_.get())
38    monitor_->RemoveStatusObserver(this);
39}
40
41void LogToServer::LogSessionStateChange(const std::string& jid,
42                                        bool connected) {
43  DCHECK(CalledOnValidThread());
44
45  scoped_ptr<ServerLogEntry> entry(
46      ServerLogEntry::MakeForSessionStateChange(connected));
47  entry->AddHostFields();
48  entry->AddModeField(mode_);
49
50  if (connected) {
51    DCHECK(connection_route_type_.count(jid) == 1);
52    entry->AddConnectionTypeField(connection_route_type_[jid]);
53  }
54  Log(*entry.get());
55}
56
57void LogToServer::OnSignalStrategyStateChange(SignalStrategy::State state) {
58  DCHECK(CalledOnValidThread());
59
60  if (state == SignalStrategy::CONNECTED) {
61    iq_sender_.reset(new IqSender(signal_strategy_));
62    SendPendingEntries();
63  } else if (state == SignalStrategy::DISCONNECTED) {
64    iq_sender_.reset();
65  }
66}
67
68bool LogToServer::OnSignalStrategyIncomingStanza(
69    const buzz::XmlElement* stanza) {
70  return false;
71}
72
73void LogToServer::OnClientConnected(const std::string& jid) {
74  DCHECK(CalledOnValidThread());
75  LogSessionStateChange(jid, true);
76}
77
78void LogToServer::OnClientDisconnected(const std::string& jid) {
79  DCHECK(CalledOnValidThread());
80  LogSessionStateChange(jid, false);
81  connection_route_type_.erase(jid);
82}
83
84void LogToServer::OnClientRouteChange(const std::string& jid,
85                                      const std::string& channel_name,
86                                      const protocol::TransportRoute& route) {
87  // Store connection type for the video channel. It is logged later
88  // when client authentication is finished.
89  if (channel_name == kVideoChannelName) {
90    connection_route_type_[jid] = route.type;
91  }
92}
93
94void LogToServer::Log(const ServerLogEntry& entry) {
95  pending_entries_.push_back(entry);
96  SendPendingEntries();
97}
98
99void LogToServer::SendPendingEntries() {
100  if (iq_sender_ == NULL) {
101    return;
102  }
103  if (pending_entries_.empty()) {
104    return;
105  }
106  // Make one stanza containing all the pending entries.
107  scoped_ptr<XmlElement> stanza(ServerLogEntry::MakeStanza());
108  while (!pending_entries_.empty()) {
109    ServerLogEntry& entry = pending_entries_.front();
110    stanza->AddElement(entry.ToStanza().release());
111    pending_entries_.pop_front();
112  }
113  // Send the stanza to the server.
114  scoped_ptr<IqRequest> req = iq_sender_->SendIq(
115      buzz::STR_SET, directory_bot_jid_, stanza.Pass(),
116      IqSender::ReplyCallback());
117  // We ignore any response, so let the IqRequest be destroyed.
118  return;
119}
120
121}  // namespace remoting
122