PageRenderTime 20ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/extensions/browser/api/cast_channel/logger.cc

https://gitlab.com/jonnialva90/iridium-browser
C++ | 366 lines | 279 code | 75 blank | 12 comment | 31 complexity | 123bbfef969d3e52275bf9f36fb5ac6f MD5 | raw file
  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. #include "extensions/browser/api/cast_channel/logger.h"
  5. #include <string>
  6. #include "base/strings/string_util.h"
  7. #include "base/time/clock.h"
  8. #include "extensions/browser/api/cast_channel/cast_auth_util.h"
  9. #include "extensions/browser/api/cast_channel/cast_socket.h"
  10. #include "extensions/browser/api/cast_channel/logger_util.h"
  11. #include "net/base/net_errors.h"
  12. #include "third_party/zlib/zlib.h"
  13. namespace extensions {
  14. namespace api {
  15. namespace cast_channel {
  16. using net::IPEndPoint;
  17. using proto::AggregatedSocketEvent;
  18. using proto::EventType;
  19. using proto::Log;
  20. using proto::SocketEvent;
  21. namespace {
  22. const char* kInternalNamespacePrefix = "com.google.cast";
  23. proto::ChallengeReplyErrorType ChallegeReplyErrorToProto(
  24. AuthResult::ErrorType error_type) {
  25. switch (error_type) {
  26. case AuthResult::ERROR_NONE:
  27. return proto::CHALLENGE_REPLY_ERROR_NONE;
  28. case AuthResult::ERROR_PEER_CERT_EMPTY:
  29. return proto::CHALLENGE_REPLY_ERROR_PEER_CERT_EMPTY;
  30. case AuthResult::ERROR_WRONG_PAYLOAD_TYPE:
  31. return proto::CHALLENGE_REPLY_ERROR_WRONG_PAYLOAD_TYPE;
  32. case AuthResult::ERROR_NO_PAYLOAD:
  33. return proto::CHALLENGE_REPLY_ERROR_NO_PAYLOAD;
  34. case AuthResult::ERROR_PAYLOAD_PARSING_FAILED:
  35. return proto::CHALLENGE_REPLY_ERROR_PAYLOAD_PARSING_FAILED;
  36. case AuthResult::ERROR_MESSAGE_ERROR:
  37. return proto::CHALLENGE_REPLY_ERROR_MESSAGE_ERROR;
  38. case AuthResult::ERROR_NO_RESPONSE:
  39. return proto::CHALLENGE_REPLY_ERROR_NO_RESPONSE;
  40. case AuthResult::ERROR_FINGERPRINT_NOT_FOUND:
  41. return proto::CHALLENGE_REPLY_ERROR_FINGERPRINT_NOT_FOUND;
  42. case AuthResult::ERROR_CERT_PARSING_FAILED:
  43. return proto::CHALLENGE_REPLY_ERROR_CERT_PARSING_FAILED;
  44. case AuthResult::ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA:
  45. return proto::CHALLENGE_REPLY_ERROR_CERT_NOT_SIGNED_BY_TRUSTED_CA;
  46. case AuthResult::ERROR_CANNOT_EXTRACT_PUBLIC_KEY:
  47. return proto::CHALLENGE_REPLY_ERROR_CANNOT_EXTRACT_PUBLIC_KEY;
  48. case AuthResult::ERROR_SIGNED_BLOBS_MISMATCH:
  49. return proto::CHALLENGE_REPLY_ERROR_SIGNED_BLOBS_MISMATCH;
  50. default:
  51. NOTREACHED();
  52. return proto::CHALLENGE_REPLY_ERROR_NONE;
  53. }
  54. }
  55. scoped_ptr<char[]> Compress(const std::string& input, size_t* length) {
  56. *length = 0;
  57. z_stream stream = {0};
  58. int result = deflateInit2(&stream,
  59. Z_DEFAULT_COMPRESSION,
  60. Z_DEFLATED,
  61. // 16 is added to produce a gzip header + trailer.
  62. MAX_WBITS + 16,
  63. 8, // memLevel = 8 is default.
  64. Z_DEFAULT_STRATEGY);
  65. DCHECK_EQ(Z_OK, result);
  66. size_t out_size = deflateBound(&stream, input.size());
  67. scoped_ptr<char[]> out(new char[out_size]);
  68. static_assert(sizeof(uint8) == sizeof(char),
  69. "uint8 char should be of different sizes");
  70. stream.next_in = reinterpret_cast<uint8*>(const_cast<char*>(input.data()));
  71. stream.avail_in = input.size();
  72. stream.next_out = reinterpret_cast<uint8*>(out.get());
  73. stream.avail_out = out_size;
  74. // Do a one-shot compression. This will return Z_STREAM_END only if |output|
  75. // is large enough to hold all compressed data.
  76. result = deflate(&stream, Z_FINISH);
  77. bool success = (result == Z_STREAM_END);
  78. if (!success)
  79. VLOG(2) << "deflate() failed. Result: " << result;
  80. result = deflateEnd(&stream);
  81. DCHECK(result == Z_OK || result == Z_DATA_ERROR);
  82. if (success)
  83. *length = out_size - stream.avail_out;
  84. return out.Pass();
  85. }
  86. // Propagate any error fields set in |event| to |last_errors|. If any error
  87. // field in |event| is set, then also set |last_errors->event_type|.
  88. void MaybeSetLastErrors(const SocketEvent& event, LastErrors* last_errors) {
  89. if (event.has_net_return_value() &&
  90. event.net_return_value() < net::ERR_IO_PENDING) {
  91. last_errors->net_return_value = event.net_return_value();
  92. last_errors->event_type = event.type();
  93. }
  94. if (event.has_challenge_reply_error_type()) {
  95. last_errors->challenge_reply_error_type =
  96. event.challenge_reply_error_type();
  97. last_errors->event_type = event.type();
  98. }
  99. }
  100. } // namespace
  101. Logger::AggregatedSocketEventLog::AggregatedSocketEventLog() {
  102. }
  103. Logger::AggregatedSocketEventLog::~AggregatedSocketEventLog() {
  104. }
  105. Logger::Logger(scoped_ptr<base::Clock> clock, base::Time unix_epoch_time)
  106. : clock_(clock.Pass()), unix_epoch_time_(unix_epoch_time) {
  107. DCHECK(clock_);
  108. // Logger may not be necessarily be created on the IO thread, but logging
  109. // happens exclusively there.
  110. thread_checker_.DetachFromThread();
  111. }
  112. Logger::~Logger() {
  113. }
  114. void Logger::LogNewSocketEvent(const CastSocket& cast_socket) {
  115. DCHECK(thread_checker_.CalledOnValidThread());
  116. SocketEvent event = CreateEvent(proto::CAST_SOCKET_CREATED);
  117. AggregatedSocketEvent& aggregated_socket_event =
  118. LogSocketEvent(cast_socket.id(), event);
  119. const net::IPAddressNumber& ip = cast_socket.ip_endpoint().address();
  120. aggregated_socket_event.set_endpoint_id(ip.back());
  121. aggregated_socket_event.set_channel_auth_type(cast_socket.channel_auth() ==
  122. CHANNEL_AUTH_TYPE_SSL
  123. ? proto::SSL
  124. : proto::SSL_VERIFIED);
  125. }
  126. void Logger::LogSocketEvent(int channel_id, EventType event_type) {
  127. DCHECK(thread_checker_.CalledOnValidThread());
  128. LogSocketEventWithDetails(channel_id, event_type, std::string());
  129. }
  130. void Logger::LogSocketEventWithDetails(int channel_id,
  131. EventType event_type,
  132. const std::string& details) {
  133. DCHECK(thread_checker_.CalledOnValidThread());
  134. SocketEvent event = CreateEvent(event_type);
  135. if (!details.empty())
  136. event.set_details(details);
  137. LogSocketEvent(channel_id, event);
  138. }
  139. void Logger::LogSocketEventWithRv(int channel_id,
  140. EventType event_type,
  141. int rv) {
  142. DCHECK(thread_checker_.CalledOnValidThread());
  143. SocketEvent event = CreateEvent(event_type);
  144. event.set_net_return_value(rv);
  145. AggregatedSocketEvent& aggregated_socket_event =
  146. LogSocketEvent(channel_id, event);
  147. if ((event_type == proto::SOCKET_READ || event_type == proto::SOCKET_WRITE) &&
  148. rv > 0) {
  149. if (event_type == proto::SOCKET_READ) {
  150. aggregated_socket_event.set_bytes_read(
  151. aggregated_socket_event.bytes_read() + rv);
  152. } else {
  153. aggregated_socket_event.set_bytes_written(
  154. aggregated_socket_event.bytes_written() + rv);
  155. }
  156. }
  157. }
  158. void Logger::LogSocketReadyState(int channel_id, proto::ReadyState new_state) {
  159. DCHECK(thread_checker_.CalledOnValidThread());
  160. SocketEvent event = CreateEvent(proto::READY_STATE_CHANGED);
  161. event.set_ready_state(new_state);
  162. LogSocketEvent(channel_id, event);
  163. }
  164. void Logger::LogSocketConnectState(int channel_id,
  165. proto::ConnectionState new_state) {
  166. DCHECK(thread_checker_.CalledOnValidThread());
  167. SocketEvent event = CreateEvent(proto::CONNECTION_STATE_CHANGED);
  168. event.set_connection_state(new_state);
  169. LogSocketEvent(channel_id, event);
  170. }
  171. void Logger::LogSocketReadState(int channel_id, proto::ReadState new_state) {
  172. DCHECK(thread_checker_.CalledOnValidThread());
  173. SocketEvent event = CreateEvent(proto::READ_STATE_CHANGED);
  174. event.set_read_state(new_state);
  175. LogSocketEvent(channel_id, event);
  176. }
  177. void Logger::LogSocketWriteState(int channel_id, proto::WriteState new_state) {
  178. DCHECK(thread_checker_.CalledOnValidThread());
  179. SocketEvent event = CreateEvent(proto::WRITE_STATE_CHANGED);
  180. event.set_write_state(new_state);
  181. LogSocketEvent(channel_id, event);
  182. }
  183. void Logger::LogSocketErrorState(int channel_id, proto::ErrorState new_state) {
  184. DCHECK(thread_checker_.CalledOnValidThread());
  185. SocketEvent event = CreateEvent(proto::ERROR_STATE_CHANGED);
  186. event.set_error_state(new_state);
  187. LogSocketEvent(channel_id, event);
  188. }
  189. void Logger::LogSocketEventForMessage(int channel_id,
  190. EventType event_type,
  191. const std::string& message_namespace,
  192. const std::string& details) {
  193. DCHECK(thread_checker_.CalledOnValidThread());
  194. SocketEvent event = CreateEvent(event_type);
  195. if (base::StartsWith(message_namespace, kInternalNamespacePrefix,
  196. base::CompareCase::INSENSITIVE_ASCII))
  197. event.set_message_namespace(message_namespace);
  198. event.set_details(details);
  199. LogSocketEvent(channel_id, event);
  200. }
  201. void Logger::LogSocketChallengeReplyEvent(int channel_id,
  202. const AuthResult& auth_result) {
  203. DCHECK(thread_checker_.CalledOnValidThread());
  204. SocketEvent event = CreateEvent(proto::AUTH_CHALLENGE_REPLY);
  205. event.set_challenge_reply_error_type(
  206. ChallegeReplyErrorToProto(auth_result.error_type));
  207. LogSocketEvent(channel_id, event);
  208. }
  209. SocketEvent Logger::CreateEvent(EventType event_type) {
  210. SocketEvent event;
  211. event.set_type(event_type);
  212. event.set_timestamp_micros(
  213. (clock_->Now() - unix_epoch_time_).InMicroseconds());
  214. return event;
  215. }
  216. AggregatedSocketEvent& Logger::LogSocketEvent(int channel_id,
  217. const SocketEvent& socket_event) {
  218. AggregatedSocketEventLogMap::iterator it =
  219. aggregated_socket_events_.find(channel_id);
  220. if (it == aggregated_socket_events_.end()) {
  221. if (aggregated_socket_events_.size() >= kMaxSocketsToLog) {
  222. AggregatedSocketEventLogMap::iterator erase_it =
  223. aggregated_socket_events_.begin();
  224. log_.set_num_evicted_aggregated_socket_events(
  225. log_.num_evicted_aggregated_socket_events() + 1);
  226. log_.set_num_evicted_socket_events(
  227. log_.num_evicted_socket_events() +
  228. erase_it->second->socket_events.size());
  229. aggregated_socket_events_.erase(erase_it);
  230. }
  231. it = aggregated_socket_events_
  232. .insert(std::make_pair(
  233. channel_id, make_linked_ptr(new AggregatedSocketEventLog)))
  234. .first;
  235. it->second->aggregated_socket_event.set_id(channel_id);
  236. }
  237. std::deque<proto::SocketEvent>& socket_events = it->second->socket_events;
  238. if (socket_events.size() >= kMaxEventsPerSocket) {
  239. socket_events.pop_front();
  240. log_.set_num_evicted_socket_events(log_.num_evicted_socket_events() + 1);
  241. }
  242. socket_events.push_back(socket_event);
  243. MaybeSetLastErrors(socket_event, &(it->second->last_errors));
  244. return it->second->aggregated_socket_event;
  245. }
  246. scoped_ptr<char[]> Logger::GetLogs(size_t* length) const {
  247. *length = 0;
  248. Log log;
  249. // Copy "global" values from |log_|. Don't use |log_| directly since this
  250. // function is const.
  251. log.CopyFrom(log_);
  252. for (AggregatedSocketEventLogMap::const_iterator it =
  253. aggregated_socket_events_.begin();
  254. it != aggregated_socket_events_.end();
  255. ++it) {
  256. AggregatedSocketEvent* new_aggregated_socket_event =
  257. log.add_aggregated_socket_event();
  258. new_aggregated_socket_event->CopyFrom(it->second->aggregated_socket_event);
  259. const std::deque<SocketEvent>& socket_events = it->second->socket_events;
  260. for (std::deque<SocketEvent>::const_iterator socket_event_it =
  261. socket_events.begin();
  262. socket_event_it != socket_events.end();
  263. ++socket_event_it) {
  264. SocketEvent* socket_event =
  265. new_aggregated_socket_event->add_socket_event();
  266. socket_event->CopyFrom(*socket_event_it);
  267. }
  268. }
  269. std::string serialized;
  270. if (!log.SerializeToString(&serialized)) {
  271. VLOG(2) << "Failed to serialized proto to string.";
  272. return scoped_ptr<char[]>();
  273. }
  274. return Compress(serialized, length);
  275. }
  276. void Logger::Reset() {
  277. aggregated_socket_events_.clear();
  278. log_.Clear();
  279. }
  280. LastErrors Logger::GetLastErrors(int channel_id) const {
  281. AggregatedSocketEventLogMap::const_iterator it =
  282. aggregated_socket_events_.find(channel_id);
  283. if (it != aggregated_socket_events_.end()) {
  284. return it->second->last_errors;
  285. } else {
  286. return LastErrors();
  287. }
  288. }
  289. } // namespace cast_channel
  290. } // namespace api
  291. } // namespace extensions