| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/udp/udp_socket_libevent.h" | 5 #include "net/udp/udp_socket_libevent.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <netdb.h> | 9 #include <netdb.h> |
| 10 #include <net/if.h> | 10 #include <net/if.h> |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 | 60 |
| 61 } // namespace | 61 } // namespace |
| 62 | 62 |
| 63 UDPSocketLibevent::UDPSocketLibevent( | 63 UDPSocketLibevent::UDPSocketLibevent( |
| 64 DatagramSocket::BindType bind_type, | 64 DatagramSocket::BindType bind_type, |
| 65 const RandIntCallback& rand_int_cb, | 65 const RandIntCallback& rand_int_cb, |
| 66 net::NetLog* net_log, | 66 net::NetLog* net_log, |
| 67 const net::NetLog::Source& source) | 67 const net::NetLog::Source& source) |
| 68 : socket_(kInvalidSocket), | 68 : socket_(kInvalidSocket), |
| 69 addr_family_(0), | 69 addr_family_(0), |
| 70 is_connected_(false), |
| 70 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), | 71 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), |
| 71 multicast_interface_(0), | 72 multicast_interface_(0), |
| 72 multicast_time_to_live_(1), | 73 multicast_time_to_live_(1), |
| 73 bind_type_(bind_type), | 74 bind_type_(bind_type), |
| 74 rand_int_cb_(rand_int_cb), | 75 rand_int_cb_(rand_int_cb), |
| 75 read_watcher_(this), | 76 read_watcher_(this), |
| 76 write_watcher_(this), | 77 write_watcher_(this), |
| 77 read_buf_len_(0), | 78 read_buf_len_(0), |
| 78 recv_from_address_(NULL), | 79 recv_from_address_(NULL), |
| 79 write_buf_len_(0), | 80 write_buf_len_(0), |
| 80 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { | 81 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { |
| 81 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, | 82 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, |
| 82 source.ToEventParametersCallback()); | 83 source.ToEventParametersCallback()); |
| 83 if (bind_type == DatagramSocket::RANDOM_BIND) | 84 if (bind_type == DatagramSocket::RANDOM_BIND) |
| 84 DCHECK(!rand_int_cb.is_null()); | 85 DCHECK(!rand_int_cb.is_null()); |
| 85 } | 86 } |
| 86 | 87 |
| 87 UDPSocketLibevent::~UDPSocketLibevent() { | 88 UDPSocketLibevent::~UDPSocketLibevent() { |
| 88 Close(); | 89 Close(); |
| 89 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); | 90 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); |
| 90 } | 91 } |
| 91 | 92 |
| 93 int UDPSocketLibevent::Open(AddressFamily address_family) { |
| 94 DCHECK(CalledOnValidThread()); |
| 95 DCHECK_EQ(socket_, kInvalidSocket); |
| 96 |
| 97 addr_family_ = ConvertAddressFamily(address_family); |
| 98 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); |
| 99 if (socket_ == kInvalidSocket) |
| 100 return MapSystemError(errno); |
| 101 if (SetNonBlocking(socket_)) { |
| 102 const int err = MapSystemError(errno); |
| 103 Close(); |
| 104 return err; |
| 105 } |
| 106 return OK; |
| 107 } |
| 108 |
| 92 void UDPSocketLibevent::Close() { | 109 void UDPSocketLibevent::Close() { |
| 93 DCHECK(CalledOnValidThread()); | 110 DCHECK(CalledOnValidThread()); |
| 94 | 111 |
| 95 if (!is_connected()) | 112 if (socket_ == kInvalidSocket) |
| 96 return; | 113 return; |
| 97 | 114 |
| 98 // Zero out any pending read/write callback state. | 115 // Zero out any pending read/write callback state. |
| 99 read_buf_ = NULL; | 116 read_buf_ = NULL; |
| 100 read_buf_len_ = 0; | 117 read_buf_len_ = 0; |
| 101 read_callback_.Reset(); | 118 read_callback_.Reset(); |
| 102 recv_from_address_ = NULL; | 119 recv_from_address_ = NULL; |
| 103 write_buf_ = NULL; | 120 write_buf_ = NULL; |
| 104 write_buf_len_ = 0; | 121 write_buf_len_ = 0; |
| 105 write_callback_.Reset(); | 122 write_callback_.Reset(); |
| 106 send_to_address_.reset(); | 123 send_to_address_.reset(); |
| 107 | 124 |
| 108 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); | 125 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); |
| 109 DCHECK(ok); | 126 DCHECK(ok); |
| 110 ok = write_socket_watcher_.StopWatchingFileDescriptor(); | 127 ok = write_socket_watcher_.StopWatchingFileDescriptor(); |
| 111 DCHECK(ok); | 128 DCHECK(ok); |
| 112 | 129 |
| 113 if (IGNORE_EINTR(close(socket_)) < 0) | 130 if (IGNORE_EINTR(close(socket_)) < 0) |
| 114 PLOG(ERROR) << "close"; | 131 PLOG(ERROR) << "close"; |
| 115 | 132 |
| 116 socket_ = kInvalidSocket; | 133 socket_ = kInvalidSocket; |
| 117 addr_family_ = 0; | 134 addr_family_ = 0; |
| 135 is_connected_ = false; |
| 118 } | 136 } |
| 119 | 137 |
| 120 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const { | 138 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const { |
| 121 DCHECK(CalledOnValidThread()); | 139 DCHECK(CalledOnValidThread()); |
| 122 DCHECK(address); | 140 DCHECK(address); |
| 123 if (!is_connected()) | 141 if (!is_connected()) |
| 124 return ERR_SOCKET_NOT_CONNECTED; | 142 return ERR_SOCKET_NOT_CONNECTED; |
| 125 | 143 |
| 126 if (!remote_address_.get()) { | 144 if (!remote_address_.get()) { |
| 127 SockaddrStorage storage; | 145 SockaddrStorage storage; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 write_buf_len_ = buf_len; | 254 write_buf_len_ = buf_len; |
| 237 DCHECK(!send_to_address_.get()); | 255 DCHECK(!send_to_address_.get()); |
| 238 if (address) { | 256 if (address) { |
| 239 send_to_address_.reset(new IPEndPoint(*address)); | 257 send_to_address_.reset(new IPEndPoint(*address)); |
| 240 } | 258 } |
| 241 write_callback_ = callback; | 259 write_callback_ = callback; |
| 242 return ERR_IO_PENDING; | 260 return ERR_IO_PENDING; |
| 243 } | 261 } |
| 244 | 262 |
| 245 int UDPSocketLibevent::Connect(const IPEndPoint& address) { | 263 int UDPSocketLibevent::Connect(const IPEndPoint& address) { |
| 264 DCHECK_NE(socket_, kInvalidSocket); |
| 246 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT, | 265 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT, |
| 247 CreateNetLogUDPConnectCallback(&address)); | 266 CreateNetLogUDPConnectCallback(&address)); |
| 248 int rv = InternalConnect(address); | 267 int rv = InternalConnect(address); |
| 249 if (rv != OK) | |
| 250 Close(); | |
| 251 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv); | 268 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv); |
| 269 is_connected_ = (rv == OK); |
| 252 return rv; | 270 return rv; |
| 253 } | 271 } |
| 254 | 272 |
| 255 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) { | 273 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) { |
| 256 DCHECK(CalledOnValidThread()); | 274 DCHECK(CalledOnValidThread()); |
| 257 DCHECK(!is_connected()); | 275 DCHECK(!is_connected()); |
| 258 DCHECK(!remote_address_.get()); | 276 DCHECK(!remote_address_.get()); |
| 259 int addr_family = address.GetSockAddrFamily(); | |
| 260 int rv = CreateSocket(addr_family); | |
| 261 if (rv < 0) | |
| 262 return rv; | |
| 263 | 277 |
| 278 int rv = 0; |
| 264 if (bind_type_ == DatagramSocket::RANDOM_BIND) { | 279 if (bind_type_ == DatagramSocket::RANDOM_BIND) { |
| 265 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, | 280 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, |
| 266 // representing INADDR_ANY or in6addr_any. | 281 // representing INADDR_ANY or in6addr_any. |
| 267 size_t addr_size = | 282 size_t addr_size = address.GetSockAddrFamily() == AF_INET ? |
| 268 addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize; | 283 kIPv4AddressSize : kIPv6AddressSize; |
| 269 IPAddressNumber addr_any(addr_size); | 284 IPAddressNumber addr_any(addr_size); |
| 270 rv = RandomBind(addr_any); | 285 rv = RandomBind(addr_any); |
| 271 } | 286 } |
| 272 // else connect() does the DatagramSocket::DEFAULT_BIND | 287 // else connect() does the DatagramSocket::DEFAULT_BIND |
| 273 | 288 |
| 274 if (rv < 0) { | 289 if (rv < 0) { |
| 275 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); | 290 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); |
| 276 Close(); | |
| 277 return rv; | 291 return rv; |
| 278 } | 292 } |
| 279 | 293 |
| 280 SockaddrStorage storage; | 294 SockaddrStorage storage; |
| 281 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) { | 295 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) |
| 282 Close(); | |
| 283 return ERR_ADDRESS_INVALID; | 296 return ERR_ADDRESS_INVALID; |
| 284 } | |
| 285 | 297 |
| 286 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len)); | 298 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len)); |
| 287 if (rv < 0) { | 299 if (rv < 0) |
| 288 // Close() may change the current errno. Map errno beforehand. | 300 return MapSystemError(errno); |
| 289 int result = MapSystemError(errno); | |
| 290 Close(); | |
| 291 return result; | |
| 292 } | |
| 293 | 301 |
| 294 remote_address_.reset(new IPEndPoint(address)); | 302 remote_address_.reset(new IPEndPoint(address)); |
| 295 return rv; | 303 return rv; |
| 296 } | 304 } |
| 297 | 305 |
| 298 int UDPSocketLibevent::Bind(const IPEndPoint& address) { | 306 int UDPSocketLibevent::Bind(const IPEndPoint& address) { |
| 307 DCHECK_NE(socket_, kInvalidSocket); |
| 299 DCHECK(CalledOnValidThread()); | 308 DCHECK(CalledOnValidThread()); |
| 300 DCHECK(!is_connected()); | 309 DCHECK(!is_connected()); |
| 301 int rv = CreateSocket(address.GetSockAddrFamily()); | 310 |
| 311 int rv = SetMulticastOptions(); |
| 302 if (rv < 0) | 312 if (rv < 0) |
| 303 return rv; | 313 return rv; |
| 304 | 314 |
| 305 rv = SetSocketOptions(); | 315 rv = DoBind(address); |
| 306 if (rv < 0) { | 316 if (rv < 0) |
| 307 Close(); | |
| 308 return rv; | 317 return rv; |
| 309 } | 318 |
| 310 rv = DoBind(address); | 319 is_connected_ = true; |
| 311 if (rv < 0) { | |
| 312 Close(); | |
| 313 return rv; | |
| 314 } | |
| 315 local_address_.reset(); | 320 local_address_.reset(); |
| 316 return rv; | 321 return rv; |
| 317 } | 322 } |
| 318 | 323 |
| 319 int UDPSocketLibevent::SetReceiveBufferSize(int32 size) { | 324 int UDPSocketLibevent::SetReceiveBufferSize(int32 size) { |
| 325 DCHECK_NE(socket_, kInvalidSocket); |
| 320 DCHECK(CalledOnValidThread()); | 326 DCHECK(CalledOnValidThread()); |
| 321 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | 327 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, |
| 322 reinterpret_cast<const char*>(&size), sizeof(size)); | 328 reinterpret_cast<const char*>(&size), sizeof(size)); |
| 323 int last_error = errno; | 329 return rv == 0 ? OK : MapSystemError(errno); |
| 324 DCHECK(!rv) << "Could not set socket receive buffer size: " << last_error; | |
| 325 return rv == 0 ? OK : MapSystemError(last_error); | |
| 326 } | 330 } |
| 327 | 331 |
| 328 int UDPSocketLibevent::SetSendBufferSize(int32 size) { | 332 int UDPSocketLibevent::SetSendBufferSize(int32 size) { |
| 333 DCHECK_NE(socket_, kInvalidSocket); |
| 329 DCHECK(CalledOnValidThread()); | 334 DCHECK(CalledOnValidThread()); |
| 330 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | 335 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, |
| 331 reinterpret_cast<const char*>(&size), sizeof(size)); | 336 reinterpret_cast<const char*>(&size), sizeof(size)); |
| 332 int last_error = errno; | 337 return rv == 0 ? OK : MapSystemError(errno); |
| 333 DCHECK(!rv) << "Could not set socket send buffer size: " << last_error; | |
| 334 return rv == 0 ? OK : MapSystemError(last_error); | |
| 335 } | 338 } |
| 336 | 339 |
| 337 void UDPSocketLibevent::AllowAddressReuse() { | 340 int UDPSocketLibevent::AllowAddressReuse() { |
| 341 DCHECK_NE(socket_, kInvalidSocket); |
| 338 DCHECK(CalledOnValidThread()); | 342 DCHECK(CalledOnValidThread()); |
| 339 DCHECK(!is_connected()); | 343 DCHECK(!is_connected()); |
| 340 | 344 int true_value = 1; |
| 341 socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS; | 345 int rv = setsockopt( |
| 346 socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value)); |
| 347 return rv == 0 ? OK : MapSystemError(errno); |
| 342 } | 348 } |
| 343 | 349 |
| 344 void UDPSocketLibevent::AllowBroadcast() { | 350 int UDPSocketLibevent::SetBroadcast(bool broadcast) { |
| 351 DCHECK_NE(socket_, kInvalidSocket); |
| 345 DCHECK(CalledOnValidThread()); | 352 DCHECK(CalledOnValidThread()); |
| 346 DCHECK(!is_connected()); | 353 int value = broadcast ? 1 : 0; |
| 347 | 354 int rv; |
| 348 socket_options_ |= SOCKET_OPTION_BROADCAST; | 355 #if defined(OS_MACOSX) |
| 356 // SO_REUSEPORT on OSX permits multiple processes to each receive |
| 357 // UDP multicast or broadcast datagrams destined for the bound |
| 358 // port. |
| 359 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)); |
| 360 #else |
| 361 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)); |
| 362 #endif // defined(OS_MACOSX) |
| 363 return rv == 0 ? OK : MapSystemError(errno); |
| 349 } | 364 } |
| 350 | 365 |
| 351 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) { | 366 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) { |
| 352 if (!socket_->read_callback_.is_null()) | 367 if (!socket_->read_callback_.is_null()) |
| 353 socket_->DidCompleteRead(); | 368 socket_->DidCompleteRead(); |
| 354 } | 369 } |
| 355 | 370 |
| 356 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) { | 371 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) { |
| 357 if (!socket_->write_callback_.is_null()) | 372 if (!socket_->write_callback_.is_null()) |
| 358 socket_->DidCompleteWrite(); | 373 socket_->DidCompleteWrite(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 411 CreateNetLogUDPDataTranferCallback( | 426 CreateNetLogUDPDataTranferCallback( |
| 412 result, bytes, | 427 result, bytes, |
| 413 is_address_valid ? &address : NULL)); | 428 is_address_valid ? &address : NULL)); |
| 414 } | 429 } |
| 415 | 430 |
| 416 base::StatsCounter read_bytes("udp.read_bytes"); | 431 base::StatsCounter read_bytes("udp.read_bytes"); |
| 417 read_bytes.Add(result); | 432 read_bytes.Add(result); |
| 418 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result); | 433 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result); |
| 419 } | 434 } |
| 420 | 435 |
| 421 int UDPSocketLibevent::CreateSocket(int addr_family) { | |
| 422 addr_family_ = addr_family; | |
| 423 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); | |
| 424 if (socket_ == kInvalidSocket) | |
| 425 return MapSystemError(errno); | |
| 426 if (SetNonBlocking(socket_)) { | |
| 427 const int err = MapSystemError(errno); | |
| 428 Close(); | |
| 429 return err; | |
| 430 } | |
| 431 return OK; | |
| 432 } | |
| 433 | |
| 434 void UDPSocketLibevent::DidCompleteWrite() { | 436 void UDPSocketLibevent::DidCompleteWrite() { |
| 435 int result = | 437 int result = |
| 436 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get()); | 438 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get()); |
| 437 | 439 |
| 438 if (result != ERR_IO_PENDING) { | 440 if (result != ERR_IO_PENDING) { |
| 439 write_buf_ = NULL; | 441 write_buf_ = NULL; |
| 440 write_buf_len_ = 0; | 442 write_buf_len_ = 0; |
| 441 send_to_address_.reset(); | 443 send_to_address_.reset(); |
| 442 write_socket_watcher_.StopWatchingFileDescriptor(); | 444 write_socket_watcher_.StopWatchingFileDescriptor(); |
| 443 DoWriteCallback(result); | 445 DoWriteCallback(result); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 0, | 513 0, |
| 512 addr, | 514 addr, |
| 513 storage.addr_len)); | 515 storage.addr_len)); |
| 514 if (result < 0) | 516 if (result < 0) |
| 515 result = MapSystemError(errno); | 517 result = MapSystemError(errno); |
| 516 if (result != ERR_IO_PENDING) | 518 if (result != ERR_IO_PENDING) |
| 517 LogWrite(result, buf->data(), address); | 519 LogWrite(result, buf->data(), address); |
| 518 return result; | 520 return result; |
| 519 } | 521 } |
| 520 | 522 |
| 521 int UDPSocketLibevent::SetSocketOptions() { | 523 int UDPSocketLibevent::SetMulticastOptions() { |
| 522 int true_value = 1; | |
| 523 if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) { | |
| 524 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, | |
| 525 sizeof(true_value)); | |
| 526 if (rv < 0) | |
| 527 return MapSystemError(errno); | |
| 528 } | |
| 529 if (socket_options_ & SOCKET_OPTION_BROADCAST) { | |
| 530 int rv; | |
| 531 #if defined(OS_MACOSX) | |
| 532 // SO_REUSEPORT on OSX permits multiple processes to each receive | |
| 533 // UDP multicast or broadcast datagrams destined for the bound | |
| 534 // port. | |
| 535 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, | |
| 536 sizeof(true_value)); | |
| 537 #else | |
| 538 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, | |
| 539 sizeof(true_value)); | |
| 540 #endif // defined(OS_MACOSX) | |
| 541 if (rv < 0) | |
| 542 return MapSystemError(errno); | |
| 543 } | |
| 544 | |
| 545 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { | 524 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { |
| 546 int rv; | 525 int rv; |
| 547 if (addr_family_ == AF_INET) { | 526 if (addr_family_ == AF_INET) { |
| 548 u_char loop = 0; | 527 u_char loop = 0; |
| 549 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP, | 528 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP, |
| 550 &loop, sizeof(loop)); | 529 &loop, sizeof(loop)); |
| 551 } else { | 530 } else { |
| 552 u_int loop = 0; | 531 u_int loop = 0; |
| 553 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, | 532 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, |
| 554 &loop, sizeof(loop)); | 533 &loop, sizeof(loop)); |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 return MapSystemError(errno); | 749 return MapSystemError(errno); |
| 771 | 750 |
| 772 return OK; | 751 return OK; |
| 773 } | 752 } |
| 774 | 753 |
| 775 void UDPSocketLibevent::DetachFromThread() { | 754 void UDPSocketLibevent::DetachFromThread() { |
| 776 base::NonThreadSafe::DetachFromThread(); | 755 base::NonThreadSafe::DetachFromThread(); |
| 777 } | 756 } |
| 778 | 757 |
| 779 } // namespace net | 758 } // namespace net |
| OLD | NEW |