OLD | NEW |
| (Empty) |
1 // Copyright 2014 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/client/log_to_server.h" | |
6 | |
7 #include "base/macros.h" | |
8 #include "base/rand_util.h" | |
9 #include "remoting/base/constants.h" | |
10 #include "remoting/client/chromoting_stats.h" | |
11 #include "remoting/client/server_log_entry_client.h" | |
12 #include "remoting/jingle_glue/iq_sender.h" | |
13 #include "remoting/jingle_glue/signal_strategy.h" | |
14 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h" | |
15 #include "third_party/libjingle/source/talk/xmpp/constants.h" | |
16 | |
17 using buzz::QName; | |
18 using buzz::XmlElement; | |
19 using remoting::protocol::ConnectionToHost; | |
20 | |
21 namespace { | |
22 | |
23 const char kSessionIdAlphabet[] = | |
24 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; | |
25 const int kSessionIdLength = 20; | |
26 | |
27 const int kMaxSessionIdAgeDays = 1; | |
28 | |
29 bool IsStartOfSession(ConnectionToHost::State state) { | |
30 return state == ConnectionToHost::INITIALIZING || | |
31 state == ConnectionToHost::CONNECTING || | |
32 state == ConnectionToHost::AUTHENTICATED || | |
33 state == ConnectionToHost::CONNECTED; | |
34 } | |
35 | |
36 bool IsEndOfSession(ConnectionToHost::State state) { | |
37 return state == ConnectionToHost::FAILED || | |
38 state == ConnectionToHost::CLOSED; | |
39 } | |
40 | |
41 bool ShouldAddDuration(ConnectionToHost::State state) { | |
42 // Duration is added to log entries at the end of the session, as well as at | |
43 // some intermediate states where it is relevant (e.g. to determine how long | |
44 // it took for a session to become CONNECTED). | |
45 return IsEndOfSession(state) || state == ConnectionToHost::CONNECTED; | |
46 } | |
47 | |
48 } // namespace | |
49 | |
50 namespace remoting { | |
51 | |
52 namespace client { | |
53 | |
54 LogToServer::LogToServer(ServerLogEntry::Mode mode, | |
55 SignalStrategy* signal_strategy, | |
56 const std::string& directory_bot_jid) | |
57 : mode_(mode), | |
58 signal_strategy_(signal_strategy), | |
59 directory_bot_jid_(directory_bot_jid) { | |
60 signal_strategy_->AddListener(this); | |
61 } | |
62 | |
63 LogToServer::~LogToServer() { | |
64 signal_strategy_->RemoveListener(this); | |
65 } | |
66 | |
67 void LogToServer::LogSessionStateChange( | |
68 protocol::ConnectionToHost::State state, | |
69 protocol::ErrorCode error) { | |
70 DCHECK(CalledOnValidThread()); | |
71 | |
72 scoped_ptr<ServerLogEntry> entry( | |
73 MakeLogEntryForSessionStateChange(state, error)); | |
74 AddClientFieldsToLogEntry(entry.get()); | |
75 entry->AddModeField(mode_); | |
76 | |
77 MaybeExpireSessionId(); | |
78 if (IsStartOfSession(state)) { | |
79 // Maybe set the session ID and start time. | |
80 if (session_id_.empty()) { | |
81 GenerateSessionId(); | |
82 } | |
83 if (session_start_time_.is_null()) { | |
84 session_start_time_ = base::TimeTicks::Now(); | |
85 } | |
86 } | |
87 | |
88 if (!session_id_.empty()) { | |
89 AddSessionIdToLogEntry(entry.get(), session_id_); | |
90 } | |
91 | |
92 // Maybe clear the session start time and log the session duration. | |
93 if (ShouldAddDuration(state) && !session_start_time_.is_null()) { | |
94 AddSessionDurationToLogEntry(entry.get(), | |
95 base::TimeTicks::Now() - session_start_time_); | |
96 } | |
97 | |
98 if (IsEndOfSession(state)) { | |
99 session_start_time_ = base::TimeTicks(); | |
100 session_id_.clear(); | |
101 } | |
102 | |
103 Log(*entry.get()); | |
104 } | |
105 | |
106 void LogToServer::LogStatistics(ChromotingStats* statistics) { | |
107 DCHECK(CalledOnValidThread()); | |
108 | |
109 MaybeExpireSessionId(); | |
110 | |
111 scoped_ptr<ServerLogEntry> entry(MakeLogEntryForStatistics(statistics)); | |
112 AddClientFieldsToLogEntry(entry.get()); | |
113 entry->AddModeField(mode_); | |
114 AddSessionIdToLogEntry(entry.get(), session_id_); | |
115 Log(*entry.get()); | |
116 } | |
117 | |
118 void LogToServer::OnSignalStrategyStateChange(SignalStrategy::State state) { | |
119 DCHECK(CalledOnValidThread()); | |
120 | |
121 if (state == SignalStrategy::CONNECTED) { | |
122 iq_sender_.reset(new IqSender(signal_strategy_)); | |
123 SendPendingEntries(); | |
124 } else if (state == SignalStrategy::DISCONNECTED) { | |
125 iq_sender_.reset(); | |
126 } | |
127 } | |
128 | |
129 bool LogToServer::OnSignalStrategyIncomingStanza( | |
130 const buzz::XmlElement* stanza) { | |
131 return false; | |
132 } | |
133 | |
134 void LogToServer::Log(const ServerLogEntry& entry) { | |
135 pending_entries_.push_back(entry); | |
136 SendPendingEntries(); | |
137 } | |
138 | |
139 void LogToServer::SendPendingEntries() { | |
140 if (iq_sender_ == NULL) { | |
141 return; | |
142 } | |
143 if (pending_entries_.empty()) { | |
144 return; | |
145 } | |
146 // Make one stanza containing all the pending entries. | |
147 scoped_ptr<XmlElement> stanza(ServerLogEntry::MakeStanza()); | |
148 while (!pending_entries_.empty()) { | |
149 ServerLogEntry& entry = pending_entries_.front(); | |
150 stanza->AddElement(entry.ToStanza().release()); | |
151 pending_entries_.pop_front(); | |
152 } | |
153 // Send the stanza to the server. | |
154 scoped_ptr<IqRequest> req = iq_sender_->SendIq( | |
155 buzz::STR_SET, directory_bot_jid_, stanza.Pass(), | |
156 IqSender::ReplyCallback()); | |
157 // We ignore any response, so let the IqRequest be destroyed. | |
158 return; | |
159 } | |
160 | |
161 void LogToServer::GenerateSessionId() { | |
162 session_id_.resize(kSessionIdLength); | |
163 for (int i = 0; i < kSessionIdLength; i++) { | |
164 const int alphabet_size = arraysize(kSessionIdAlphabet) - 1; | |
165 session_id_[i] = kSessionIdAlphabet[base::RandGenerator(alphabet_size)]; | |
166 } | |
167 session_id_generation_time_ = base::TimeTicks::Now(); | |
168 } | |
169 | |
170 void LogToServer::MaybeExpireSessionId() { | |
171 if (session_id_.empty()) { | |
172 return; | |
173 } | |
174 | |
175 base::TimeDelta max_age = base::TimeDelta::FromDays(kMaxSessionIdAgeDays); | |
176 if (base::TimeTicks::Now() - session_id_generation_time_ > max_age) { | |
177 // Log the old session ID. | |
178 scoped_ptr<ServerLogEntry> entry(MakeLogEntryForSessionIdOld(session_id_)); | |
179 entry->AddModeField(mode_); | |
180 Log(*entry.get()); | |
181 | |
182 // Generate a new session ID. | |
183 GenerateSessionId(); | |
184 | |
185 // Log the new session ID. | |
186 entry = MakeLogEntryForSessionIdNew(session_id_); | |
187 entry->AddModeField(mode_); | |
188 Log(*entry.get()); | |
189 } | |
190 } | |
191 | |
192 } // namespace client | |
193 | |
194 } // namespace remoting | |
OLD | NEW |