0

Add NetLog support to UDP sockets.

BUG=99508
TEST=UDPSocketTest.Connect


Review URL: http://codereview.chromium.org/8200011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106109 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
mmenke@chromium.org
2011-10-18 20:08:10 +00:00
parent def979a39b
commit 8866f623df
18 changed files with 507 additions and 100 deletions

@ -80,6 +80,7 @@ PassiveLogCollector::PassiveLogCollector()
trackers_[net::NetLog::SOURCE_DNS_TRANSACTION] = &dns_transaction_tracker_;
trackers_[net::NetLog::SOURCE_ASYNC_HOST_RESOLVER_REQUEST] =
&async_host_resolver_request_tracker_;
trackers_[net::NetLog::SOURCE_UDP_SOCKET] = &udp_socket_tracker_;
// Make sure our mapping is up-to-date.
for (size_t i = 0; i < arraysize(trackers_); ++i)
DCHECK(trackers_[i]) << "Unhandled SourceType: " << i;
@ -724,3 +725,33 @@ PassiveLogCollector::AsyncHostResolverRequestTracker::DoAddEntry(
}
return ACTION_NONE;
}
//----------------------------------------------------------------------------
// UDPSocketTracker
//----------------------------------------------------------------------------
const size_t PassiveLogCollector::UDPSocketTracker::kMaxNumSources = 200;
const size_t PassiveLogCollector::UDPSocketTracker::kMaxGraveyardSize = 15;
PassiveLogCollector::UDPSocketTracker::UDPSocketTracker()
: SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
}
PassiveLogCollector::UDPSocketTracker::Action
PassiveLogCollector::UDPSocketTracker::DoAddEntry(
const ChromeNetLog::Entry& entry,
SourceInfo* out_info) {
if (entry.type == net::NetLog::TYPE_UDP_BYTES_SENT ||
entry.type == net::NetLog::TYPE_UDP_BYTES_RECEIVED) {
return ACTION_NONE;
}
AddEntryToSourceInfo(entry, out_info);
if (entry.type == net::NetLog::TYPE_SOCKET_ALIVE &&
entry.phase == net::NetLog::PHASE_END) {
return ACTION_MOVE_TO_GRAVEYARD;
}
return ACTION_NONE;
}

@ -384,6 +384,22 @@ class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserverImpl {
DISALLOW_COPY_AND_ASSIGN(AsyncHostResolverRequestTracker);
};
// Tracks the log entries for the last seen SOURCE_UDP_SOCKET.
class UDPSocketTracker : public SourceTracker {
public:
static const size_t kMaxNumSources;
static const size_t kMaxGraveyardSize;
UDPSocketTracker();
private:
virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
SourceInfo* out_info);
DISALLOW_COPY_AND_ASSIGN(UDPSocketTracker);
};
PassiveLogCollector();
virtual ~PassiveLogCollector();
@ -426,6 +442,7 @@ class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserverImpl {
ExponentialBackoffThrottlingTracker exponential_backoff_throttling_tracker_;
DnsTransactionTracker dns_transaction_tracker_;
AsyncHostResolverRequestTracker async_host_resolver_request_tracker_;
UDPSocketTracker udp_socket_tracker_;
// This array maps each NetLog::SourceType to one of the tracker instances
// defined above. Use of this array avoid duplicating the list of trackers

@ -73,7 +73,9 @@ found in the LICENSE file.
}
#events-view-source-list-tbody .source_HOST_RESOLVER_IMPL_JOB,
#events-view-source-list-tbody .source_HOST_RESOLVER_IMPL_REQUEST {
#events-view-source-list-tbody .source_HOST_RESOLVER_IMPL_REQUEST,
#events-view-source-list-tbody .source_ASYNC_HOST_RESOLVER_REQUEST,
#events-view-source-list-tbody .source_DNS_TRANSACTION {
color: #206060;
}
@ -86,6 +88,10 @@ found in the LICENSE file.
color: purple;
}
#events-view-source-list-tbody .source_UDP_SOCKET {
color: #803030;
}
#events-view-source-list-tbody .source_INIT_PROXY_RESOLVER {
color: green;
}

@ -99,12 +99,28 @@ var SourceEntry = (function() {
this.description_ = e.params.host + ' (' + e.params.proxy + ')';
break;
case LogSourceType.SOCKET:
// Use description of parent source, if any.
if (e.params.source_dependency != undefined) {
var connectJobId = e.params.source_dependency.id;
var connectJob =
g_browser.sourceTracker.getSourceEntry(connectJobId);
if (connectJob)
this.description_ = connectJob.getDescription();
var parentId = e.params.source_dependency.id;
this.description_ =
g_browser.sourceTracker.getDescription(parentId);
}
break;
case LogSourceType.UDP_SOCKET:
if (e.params.address != undefined) {
this.description_ = e.params.address;
// If the parent of |this| is a DNS_TRANSACTION, use
// '<DNS Server IP> [<DNS we're resolving>]'.
if (this.entries_[0].type == LogEventType.SOCKET_ALIVE &&
this.entries_[0].params.source_dependency != undefined) {
var parentId = this.entries_[0].params.source_dependency.id;
var parent = g_browser.sourceTracker.getSourceEntry(parentId);
if (parent &&
parent.getSourceType() == LogSourceType.DNS_TRANSACTION &&
parent.getDescription().length > 0) {
this.description_ += ' [' + parent.getDescription() + ']';
}
}
}
break;
case LogSourceType.ASYNC_HOST_RESOLVER_REQUEST:
@ -137,8 +153,10 @@ var SourceEntry = (function() {
return undefined;
if (this.entries_.length >= 2) {
if (this.entries_[0].type == LogEventType.REQUEST_ALIVE ||
this.entries_[0].type == LogEventType.SOCKET_POOL_CONNECT_JOB)
this.entries_[0].type == LogEventType.SOCKET_POOL_CONNECT_JOB ||
this.entries_[1].type == LogEventType.UDP_CONNECT) {
return this.entries_[1];
}
}
return this.entries_[0];
},

@ -74,6 +74,17 @@ var SourceTracker = (function() {
return this.numPassivelyCapturedEvents_;
},
/**
* Returns the description of the specified SourceEntry, or an empty string
* if it doesn't exist.
*/
getDescription: function(id) {
var entry = this.getSourceEntry(id);
if (entry)
return entry.getDescription();
return '';
},
/**
* Returns the specified SourceEntry.
*/

@ -192,9 +192,18 @@ void BoundNetLog::EndEvent(
AddEntry(event_type, NetLog::PHASE_END, params);
}
void BoundNetLog::AddEventWithNetErrorCode(NetLog::EventType event_type,
int net_error) const {
DCHECK_GT(0, net_error);
DCHECK_NE(ERR_IO_PENDING, net_error);
AddEvent(
event_type,
make_scoped_refptr(new NetLogIntegerParameter("net_error", net_error)));
}
void BoundNetLog::EndEventWithNetErrorCode(NetLog::EventType event_type,
int net_error) const {
DCHECK_NE(net_error, ERR_IO_PENDING);
DCHECK_NE(ERR_IO_PENDING, net_error);
if (net_error >= 0) {
EndEvent(event_type, NULL);
} else {
@ -205,7 +214,8 @@ void BoundNetLog::EndEventWithNetErrorCode(NetLog::EventType event_type,
}
void BoundNetLog::AddByteTransferEvent(NetLog::EventType event_type,
int byte_count, char* bytes) const {
int byte_count,
const char* bytes) const {
scoped_refptr<NetLog::EventParameters> params;
if (IsLoggingBytes()) {
params = new NetLogBytesTransferredParameter(byte_count, bytes);

@ -243,6 +243,13 @@ class NET_EXPORT BoundNetLog {
void EndEvent(NetLog::EventType event_type,
const scoped_refptr<NetLog::EventParameters>& params) const;
// Just like AddEvent, except |net_error| is a net error code. A parameter
// called "net_error" with the indicated value will be recorded for the event.
// |net_error| must be negative, and not ERR_IO_PENDING, as it's not a true
// error.
void AddEventWithNetErrorCode(NetLog::EventType event_type,
int net_error) const;
// Just like EndEvent, except |net_error| is a net error code. If it's
// negative, a parameter called "net_error" with a value of |net_error| is
// associated with the event. Otherwise, the end event has no parameters.
@ -253,7 +260,7 @@ class NET_EXPORT BoundNetLog {
// Logs a byte transfer event to the NetLog. Determines whether to log the
// received bytes or not based on the current logging level.
void AddByteTransferEvent(NetLog::EventType event_type,
int byte_count, char* bytes) const;
int byte_count, const char* bytes) const;
NetLog::LogLevel GetLogLevel() const;

@ -287,6 +287,19 @@ EVENT_TYPE(WAITING_FOR_PROXY_RESOLVER_THREAD)
// }
EVENT_TYPE(SUBMITTED_TO_RESOLVER_THREAD)
// ------------------------------------------------------------------------
// Socket (Shared by stream and datagram sockets)
// ------------------------------------------------------------------------
// Marks the begin/end of a socket (TCP/SOCKS/SSL/UDP).
//
// The BEGIN phase contains the following parameters:
//
// {
// "source_dependency": <Source identifier for the controlling entity>,
// }
EVENT_TYPE(SOCKET_ALIVE)
// ------------------------------------------------------------------------
// StreamSocket
// ------------------------------------------------------------------------
@ -300,10 +313,11 @@ EVENT_TYPE(SUBMITTED_TO_RESOLVER_THREAD)
// "address_list": <List of network address strings>,
// }
//
// And the END event will contain the following parameters on failure:
// And the END event will contain the following parameters:
//
// {
// "net_error": <Net integer error code>,
// "net_error": <Net integer error code, on error>,
// "source_address": <Local source address of the connection, on success>,
// }
EVENT_TYPE(TCP_CONNECT)
@ -335,9 +349,6 @@ EVENT_TYPE(TCP_CONNECT_ATTEMPT)
// }
EVENT_TYPE(TCP_ACCEPT)
// Marks the begin/end of a socket (TCP/SOCKS/SSL).
EVENT_TYPE(SOCKET_ALIVE)
// This event is logged to the socket stream whenever the socket is
// acquired/released via a ClientSocketHandle.
//
@ -475,6 +486,45 @@ EVENT_TYPE(SSL_SOCKET_BYTES_SENT)
EVENT_TYPE(SOCKET_BYTES_RECEIVED)
EVENT_TYPE(SSL_SOCKET_BYTES_RECEIVED)
// ------------------------------------------------------------------------
// DatagramSocket
// ------------------------------------------------------------------------
// The start/end of a UDP client connecting.
//
// The START event contains these parameters:
//
// {
// "address": <Remote address being connected to>,
// }
//
// And the END event will contain the following parameter:
//
// {
// "net_error": <Net integer error code, on failure>,
// }
EVENT_TYPE(UDP_CONNECT)
// The specified number of bytes were transferred on the socket.
// The following parameters are attached:
// {
// "address": <Remote address of data transfer. Not present when not
// specified for UDP_BYTES_SENT events>,
// "byte_count": <Number of bytes that were just received>,
// "hex_encoded_bytes": <The exact bytes received, as a hexadecimal string.
// Only present when byte logging is enabled>,
// }
EVENT_TYPE(UDP_BYTES_RECEIVED)
EVENT_TYPE(UDP_BYTES_SENT)
// Logged when an error occurs while reading or writing to/from a UDP socket.
// The following parameters are attached:
// {
// "net_error": <Net error code>,
// }
EVENT_TYPE(UDP_RECEIVE_ERROR)
EVENT_TYPE(UDP_SEND_ERROR)
// ------------------------------------------------------------------------
// ClientSocketPoolBase::ConnectJob
// ------------------------------------------------------------------------
@ -1141,9 +1191,9 @@ EVENT_TYPE(THROTTLING_GOT_CUSTOM_RETRY_AFTER)
// The END phase contains the following parameters:
//
// {
// "net_error": <The net error code for the failure>,
// "ip_address_list": <The result of the resolution process,
// an IPAddressList>
// "net_error": <The net error code for the failure, if any>,
// }
EVENT_TYPE(DNS_TRANSACTION)

@ -22,5 +22,6 @@ SOURCE_TYPE(HTTP_STREAM_JOB, 11)
SOURCE_TYPE(EXPONENTIAL_BACKOFF_THROTTLING, 12)
SOURCE_TYPE(DNS_TRANSACTION, 13)
SOURCE_TYPE(ASYNC_HOST_RESOLVER_REQUEST, 14)
SOURCE_TYPE(UDP_SOCKET, 15)
SOURCE_TYPE(COUNT, 15) // Always keep this as the last entry.
SOURCE_TYPE(COUNT, 16) // Always keep this as the last entry.

@ -631,6 +631,8 @@
'udp/datagram_socket.h',
'udp/udp_client_socket.cc',
'udp/udp_client_socket.h',
'udp/udp_data_transfer_param.cc',
'udp/udp_data_transfer_param.h',
'udp/udp_server_socket.cc',
'udp/udp_server_socket.h',
'udp/udp_socket.h',

@ -805,7 +805,7 @@ void TCPClientSocketWin::LogConnectCompletion(int net_error) {
sizeof(source_address));
net_log_.EndEvent(NetLog::TYPE_TCP_CONNECT,
make_scoped_refptr(new NetLogStringParameter(
"source address",
"source_address",
source_address_str)));
}

@ -0,0 +1,36 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/string_number_conversions.h"
#include "base/values.h"
#include "net/base/ip_endpoint.h"
#include "net/udp/udp_data_transfer_param.h"
namespace net {
UDPDataTransferNetLogParam::UDPDataTransferNetLogParam(
int byte_count,
const char* bytes,
bool log_bytes,
const IPEndPoint* address)
: byte_count_(byte_count),
hex_encoded_bytes_(log_bytes ? base::HexEncode(bytes, byte_count) : "") {
if (address)
address_.reset(new IPEndPoint(*address));
}
UDPDataTransferNetLogParam::~UDPDataTransferNetLogParam() {
}
Value* UDPDataTransferNetLogParam::ToValue() const {
DictionaryValue* dict = new DictionaryValue();
dict->SetInteger("byte_count", byte_count_);
if (!hex_encoded_bytes_.empty())
dict->SetString("hex_encoded_bytes", hex_encoded_bytes_);
if (address_.get())
dict->SetString("address", address_->ToString());
return dict;
}
} // namespace net

@ -0,0 +1,40 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_UDP_UDP_DATA_TRANSFER_PARAM_H_
#define NET_UDP_UDP_DATA_TRANSFER_PARAM_H_
#pragma once
#include <string>
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/net_log.h"
namespace net {
class IPEndPoint;
// NetLog parameter to describe a UDP receive/send event. Each event has a
// byte count, and may optionally have transferred bytes and an IPEndPoint as
// well.
class UDPDataTransferNetLogParam : public NetLog::EventParameters {
public:
// |bytes| are only logged when |log_bytes| is non-NULL.
// |address| may be NULL.
UDPDataTransferNetLogParam(int byte_count, const char* bytes, bool log_bytes,
const IPEndPoint* address);
virtual ~UDPDataTransferNetLogParam();
virtual base::Value* ToValue() const OVERRIDE;
private:
const int byte_count_;
const std::string hex_encoded_bytes_;
scoped_ptr<IPEndPoint> address_;
};
} // namespace net
#endif // NET_BASE_ADDRESS_LIST_NET_LOG_PARAM_H_

@ -19,6 +19,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
#include "net/udp/udp_data_transfer_param.h"
#if defined(OS_POSIX)
#include <netinet/in.h>
#endif
@ -48,7 +49,7 @@ UDPSocketLibevent::UDPSocketLibevent(
write_buf_len_(0),
read_callback_(NULL),
write_callback_(NULL),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
params = new NetLogSourceParameter("source_dependency", source);
@ -158,7 +159,9 @@ int UDPSocketLibevent::RecvFrom(IOBuffer* buf,
socket_, true, MessageLoopForIO::WATCH_READ,
&read_socket_watcher_, &read_watcher_)) {
PLOG(ERROR) << "WatchFileDescriptor failed on read";
return MapSystemError(errno);
int result = MapSystemError(errno);
LogRead(result, NULL, 0, NULL);
return result;
}
read_buf_ = buf;
@ -191,20 +194,17 @@ int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf,
DCHECK(callback); // Synchronous operation not supported
DCHECK_GT(buf_len, 0);
int nwrite = InternalSendTo(buf, buf_len, address);
if (nwrite >= 0) {
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(nwrite);
return nwrite;
}
if (errno != EAGAIN && errno != EWOULDBLOCK)
return MapSystemError(errno);
int result = InternalSendTo(buf, buf_len, address);
if (result != ERR_IO_PENDING)
return result;
if (!MessageLoopForIO::current()->WatchFileDescriptor(
socket_, true, MessageLoopForIO::WATCH_WRITE,
&write_socket_watcher_, &write_watcher_)) {
DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
return MapSystemError(errno);
int result = MapSystemError(errno);
LogWrite(result, NULL, NULL);
return result;
}
write_buf_ = buf;
@ -218,6 +218,16 @@ int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf,
}
int UDPSocketLibevent::Connect(const IPEndPoint& address) {
net_log_.BeginEvent(
NetLog::TYPE_UDP_CONNECT,
make_scoped_refptr(new NetLogStringParameter("address",
address.ToString())));
int rv = InternalConnect(address);
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
return rv;
}
int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) {
DCHECK(CalledOnValidThread());
DCHECK(!is_connected());
DCHECK(!remote_address_.get());
@ -307,6 +317,33 @@ void UDPSocketLibevent::DidCompleteRead() {
}
}
void UDPSocketLibevent::LogRead(int result,
const char* bytes,
socklen_t addr_len,
const sockaddr* addr) const {
if (result < 0) {
net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
return;
}
if (net_log_.IsLoggingAllEvents()) {
DCHECK(addr_len > 0);
DCHECK(addr);
IPEndPoint address;
bool is_address_valid = address.FromSockAddr(addr, addr_len);
net_log_.AddEvent(
NetLog::TYPE_UDP_BYTES_RECEIVED,
make_scoped_refptr(
new UDPDataTransferNetLogParam(
result, bytes, net_log_.IsLoggingBytes(),
is_address_valid ? &address : NULL)));
}
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(result);
}
int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) {
socket_ = socket(address.GetFamily(), SOCK_DGRAM, 0);
if (socket_ == kInvalidSocket)
@ -322,12 +359,6 @@ int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) {
void UDPSocketLibevent::DidCompleteWrite() {
int result = InternalSendTo(write_buf_, write_buf_len_,
send_to_address_.get());
if (result >= 0) {
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(result);
} else {
result = MapSystemError(errno);
}
if (result != ERR_IO_PENDING) {
write_buf_ = NULL;
@ -338,6 +369,27 @@ void UDPSocketLibevent::DidCompleteWrite() {
}
}
void UDPSocketLibevent::LogWrite(int result,
const char* bytes,
const IPEndPoint* address) const {
if (result < 0) {
net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
return;
}
if (net_log_.IsLoggingAllEvents()) {
net_log_.AddEvent(
NetLog::TYPE_UDP_BYTES_SENT,
make_scoped_refptr(
new UDPDataTransferNetLogParam(result, bytes,
net_log_.IsLoggingBytes(),
address)));
}
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(result);
}
int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
IPEndPoint* address) {
int bytes_transferred;
@ -357,15 +409,13 @@ int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
int result;
if (bytes_transferred >= 0) {
result = bytes_transferred;
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(bytes_transferred);
if (address) {
if (!address->FromSockAddr(addr, addr_len))
result = ERR_FAILED;
}
if (address && !address->FromSockAddr(addr, addr_len))
result = ERR_FAILED;
} else {
result = MapSystemError(errno);
}
if (result != ERR_IO_PENDING)
LogRead(result, buf->data(), addr_len, addr);
return result;
}
@ -379,16 +429,24 @@ int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
addr = NULL;
addr_len = 0;
} else {
if (!address->ToSockAddr(addr, &addr_len))
return ERR_FAILED;
if (!address->ToSockAddr(addr, &addr_len)) {
int result = ERR_FAILED;
LogWrite(result, NULL, NULL);
return result;
}
}
return HANDLE_EINTR(sendto(socket_,
buf->data(),
buf_len,
0,
addr,
addr_len));
int result = HANDLE_EINTR(sendto(socket_,
buf->data(),
buf_len,
0,
addr,
addr_len));
if (result < 0)
result = MapSystemError(errno);
if (result != ERR_IO_PENDING)
LogWrite(result, buf->data(), address);
return result;
}
int UDPSocketLibevent::DoBind(const IPEndPoint& address) {

@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/threading/non_thread_safe.h"
#include "net/base/address_list_net_log_param.h"
#include "net/base/completion_callback.h"
#include "net/base/rand_callback.h"
#include "net/base/io_buffer.h"
@ -19,8 +20,6 @@
namespace net {
class BoundNetLog;
class UDPSocketLibevent : public base::NonThreadSafe {
public:
UDPSocketLibevent(DatagramSocket::BindType bind_type,
@ -151,6 +150,14 @@ class UDPSocketLibevent : public base::NonThreadSafe {
void DidCompleteRead();
void DidCompleteWrite();
// Handles stats and logging. |result| is the number of bytes transferred, on
// success, or the net error code on failure. On success, LogRead takes in a
// sockaddr and its length, which are mandatory, while LogWrite takes in an
// optional IPEndPoint.
void LogRead(int result, const char* bytes, socklen_t addr_len,
const sockaddr* addr) const;
void LogWrite(int result, const char* bytes, const IPEndPoint* address) const;
// Returns the OS error code (or 0 on success).
int CreateSocket(const IPEndPoint& address);
@ -162,6 +169,7 @@ class UDPSocketLibevent : public base::NonThreadSafe {
const IPEndPoint* address,
OldCompletionCallback* callback);
int InternalConnect(const IPEndPoint& address);
int InternalRecvFrom(IOBuffer* buf, int buf_len, IPEndPoint* address);
int InternalSendTo(IOBuffer* buf, int buf_len, const IPEndPoint* address);

@ -12,6 +12,7 @@
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_log_unittest.h"
#include "net/base/net_test_suite.h"
#include "net/base/net_util.h"
#include "net/base/sys_addrinfo.h"
@ -131,35 +132,73 @@ TEST_F(UDPSocketTest, Connect) {
// Setup the server to listen.
IPEndPoint bind_address;
CreateUDPAddress("0.0.0.0", kPort, &bind_address);
UDPServerSocket server(NULL, NetLog::Source());
int rv = server.Listen(bind_address);
CapturingNetLog server_log(CapturingNetLog::kUnbounded);
scoped_ptr<UDPServerSocket> server(
new UDPServerSocket(&server_log, NetLog::Source()));
int rv = server->Listen(bind_address);
EXPECT_EQ(OK, rv);
// Setup the client.
IPEndPoint server_address;
CreateUDPAddress("127.0.0.1", kPort, &server_address);
UDPClientSocket client(DatagramSocket::DEFAULT_BIND,
RandIntCallback(),
NULL,
NetLog::Source());
rv = client.Connect(server_address);
CapturingNetLog client_log(CapturingNetLog::kUnbounded);
scoped_ptr<UDPClientSocket> client(
new UDPClientSocket(DatagramSocket::DEFAULT_BIND,
RandIntCallback(),
&client_log,
NetLog::Source()));
rv = client->Connect(server_address);
EXPECT_EQ(OK, rv);
// Client sends to the server.
rv = WriteSocket(&client, simple_message);
rv = WriteSocket(client.get(), simple_message);
EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv));
// Server waits for message.
std::string str = RecvFromSocket(&server);
std::string str = RecvFromSocket(server.get());
DCHECK(simple_message == str);
// Server echoes reply.
rv = SendToSocket(&server, simple_message);
rv = SendToSocket(server.get(), simple_message);
EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv));
// Client waits for response.
str = ReadSocket(&client);
str = ReadSocket(client.get());
DCHECK(simple_message == str);
// Delete sockets so they log their final events.
server.reset();
client.reset();
// Check the server's log.
CapturingNetLog::EntryList server_entries;
server_log.GetEntries(&server_entries);
EXPECT_EQ(4u, server_entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
server_entries, 0, NetLog::TYPE_SOCKET_ALIVE));
EXPECT_TRUE(LogContainsEvent(
server_entries, 1, NetLog::TYPE_UDP_BYTES_RECEIVED, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEvent(
server_entries, 2, NetLog::TYPE_UDP_BYTES_SENT, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
server_entries, 3, NetLog::TYPE_SOCKET_ALIVE));
// Check the client's log.
CapturingNetLog::EntryList client_entries;
client_log.GetEntries(&client_entries);
EXPECT_EQ(6u, client_entries.size());
EXPECT_TRUE(LogContainsBeginEvent(
client_entries, 0, NetLog::TYPE_SOCKET_ALIVE));
EXPECT_TRUE(LogContainsBeginEvent(
client_entries, 1, NetLog::TYPE_UDP_CONNECT));
EXPECT_TRUE(LogContainsEndEvent(
client_entries, 2, NetLog::TYPE_UDP_CONNECT));
EXPECT_TRUE(LogContainsEvent(
client_entries, 3, NetLog::TYPE_UDP_BYTES_SENT, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEvent(
client_entries, 4, NetLog::TYPE_UDP_BYTES_RECEIVED, NetLog::PHASE_NONE));
EXPECT_TRUE(LogContainsEndEvent(
client_entries, 5, NetLog::TYPE_SOCKET_ALIVE));
}
// In this test, we verify that random binding logic works, which attempts
@ -321,11 +360,11 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
SCOPED_TRACE(std::string("Connecting from ") + tests[i].local_address +
std::string(" to ") + tests[i].remote_address);
net::IPAddressNumber ip_number;
net::ParseIPLiteralToNumber(tests[i].remote_address, &ip_number);
net::IPEndPoint remote_address(ip_number, 80);
net::ParseIPLiteralToNumber(tests[i].local_address, &ip_number);
net::IPEndPoint local_address(ip_number, 80);
IPAddressNumber ip_number;
ParseIPLiteralToNumber(tests[i].remote_address, &ip_number);
IPEndPoint remote_address(ip_number, 80);
ParseIPLiteralToNumber(tests[i].local_address, &ip_number);
IPEndPoint local_address(ip_number, 80);
UDPClientSocket client(DatagramSocket::DEFAULT_BIND,
RandIntCallback(),

@ -11,6 +11,7 @@
#include "base/message_loop.h"
#include "base/metrics/stats_counters.h"
#include "base/rand_util.h"
#include "net/base/address_list_net_log_param.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
@ -18,6 +19,7 @@
#include "net/base/net_util.h"
#include "net/base/winsock_init.h"
#include "net/base/winsock_util.h"
#include "net/udp/udp_data_transfer_param.h"
namespace {
@ -51,7 +53,7 @@ UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
recv_from_address_(NULL),
read_callback_(NULL),
write_callback_(NULL),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
EnsureWinsockInit();
scoped_refptr<NetLog::EventParameters> params;
if (source.is_valid())
@ -181,17 +183,30 @@ int UDPSocketWin::SendToOrWrite(IOBuffer* buf,
DCHECK(!write_callback_);
DCHECK(callback); // Synchronous operation not supported.
DCHECK_GT(buf_len, 0);
DCHECK(!send_to_address_.get());
int nwrite = InternalSendTo(buf, buf_len, address);
if (nwrite != ERR_IO_PENDING)
return nwrite;
if (address)
send_to_address_.reset(new IPEndPoint(*address));
write_iobuffer_ = buf;
write_callback_ = callback;
return ERR_IO_PENDING;
}
int UDPSocketWin::Connect(const IPEndPoint& address) {
net_log_.BeginEvent(
NetLog::TYPE_UDP_CONNECT,
make_scoped_refptr(new NetLogStringParameter("address",
address.ToString())));
int rv = InternalConnect(address);
net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
return rv;
}
int UDPSocketWin::InternalConnect(const IPEndPoint& address) {
DCHECK(!is_connected());
DCHECK(!remote_address_.get());
int rv = CreateSocket(address);
@ -281,28 +296,37 @@ void UDPSocketWin::DidCompleteRead() {
&num_bytes, FALSE, &flags);
WSAResetEvent(read_overlapped_.hEvent);
int result = ok ? num_bytes : MapSystemError(WSAGetLastError());
if (ok) {
if (!ProcessSuccessfulRead(num_bytes, recv_from_address_))
// Convert address.
if (recv_from_address_ && result >= 0) {
if (!ReceiveAddressToIPEndpoint(recv_from_address_))
result = ERR_FAILED;
}
LogRead(result, read_iobuffer_->data());
read_iobuffer_ = NULL;
recv_from_address_ = NULL;
DoReadCallback(result);
}
bool UDPSocketWin::ProcessSuccessfulRead(int num_bytes, IPEndPoint* address) {
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(num_bytes);
// Convert address.
if (address) {
struct sockaddr* addr =
reinterpret_cast<struct sockaddr*>(&recv_addr_storage_);
if (!address->FromSockAddr(addr, recv_addr_len_))
return false;
void UDPSocketWin::LogRead(int result, const char* bytes) const {
if (result < 0) {
net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
return;
}
return true;
if (net_log_.IsLoggingAllEvents()) {
// Get address for logging, if |address| is NULL.
IPEndPoint address;
bool is_address_valid = ReceiveAddressToIPEndpoint(&address);
net_log_.AddEvent(
NetLog::TYPE_UDP_BYTES_RECEIVED,
make_scoped_refptr(
new UDPDataTransferNetLogParam(
result, bytes, net_log_.IsLoggingBytes(),
is_address_valid ? &address : NULL)));
}
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(result);
}
void UDPSocketWin::DidCompleteWrite() {
@ -311,15 +335,32 @@ void UDPSocketWin::DidCompleteWrite() {
&num_bytes, FALSE, &flags);
WSAResetEvent(write_overlapped_.hEvent);
int result = ok ? num_bytes : MapSystemError(WSAGetLastError());
if (ok)
ProcessSuccessfulWrite(num_bytes);
LogWrite(result, write_iobuffer_->data(), send_to_address_.get());
send_to_address_.reset();
write_iobuffer_ = NULL;
DoWriteCallback(result);
}
void UDPSocketWin::ProcessSuccessfulWrite(int num_bytes) {
void UDPSocketWin::LogWrite(int result,
const char* bytes,
const IPEndPoint* address) const {
if (result < 0) {
net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
return;
}
if (net_log_.IsLoggingAllEvents()) {
net_log_.AddEvent(
NetLog::TYPE_UDP_BYTES_SENT,
make_scoped_refptr(
new UDPDataTransferNetLogParam(result, bytes,
net_log_.IsLoggingBytes(),
address)));
}
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(num_bytes);
write_bytes.Add(result);
}
int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
@ -339,14 +380,22 @@ int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
&recv_addr_len_, &read_overlapped_, NULL);
if (rv == 0) {
if (ResetEventIfSignaled(read_overlapped_.hEvent)) {
if (!ProcessSuccessfulRead(num, address))
return ERR_FAILED;
return static_cast<int>(num);
int result = num;
// Convert address.
if (address && result >= 0) {
if (!ReceiveAddressToIPEndpoint(address))
result = ERR_FAILED;
}
LogRead(result, buf->data());
return result;
}
} else {
int os_error = WSAGetLastError();
if (os_error != WSA_IO_PENDING)
return MapSystemError(os_error);
if (os_error != WSA_IO_PENDING) {
int result = MapSystemError(os_error);
LogRead(result, NULL);
return result;
}
}
read_watcher_.StartWatching(read_overlapped_.hEvent, &read_delegate_);
return ERR_IO_PENDING;
@ -363,8 +412,11 @@ int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
addr = NULL;
addr_len = 0;
} else {
if (!address->ToSockAddr(addr, &addr_len))
return ERR_FAILED;
if (!address->ToSockAddr(addr, &addr_len)) {
int result = ERR_FAILED;
LogWrite(result, NULL, NULL);
return result;
}
}
WSABUF write_buffer;
@ -378,13 +430,17 @@ int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
addr, addr_len, &write_overlapped_, NULL);
if (rv == 0) {
if (ResetEventIfSignaled(write_overlapped_.hEvent)) {
ProcessSuccessfulWrite(num);
return static_cast<int>(num);
int result = num;
LogWrite(result, buf->data(), address);
return result;
}
} else {
int os_error = WSAGetLastError();
if (os_error != WSA_IO_PENDING)
return MapSystemError(os_error);
if (os_error != WSA_IO_PENDING) {
int result = MapSystemError(os_error);
LogWrite(result, NULL, NULL);
return result;
}
}
write_watcher_.StartWatching(write_overlapped_.hEvent, &write_delegate_);
@ -415,4 +471,10 @@ int UDPSocketWin::RandomBind(const IPEndPoint& address) {
return DoBind(IPEndPoint(ip, 0));
}
bool UDPSocketWin::ReceiveAddressToIPEndpoint(IPEndPoint* address) const {
const struct sockaddr* addr =
reinterpret_cast<const struct sockaddr*>(&recv_addr_storage_);
return address->FromSockAddr(addr, recv_addr_len_);
}
} // namespace net

@ -21,8 +21,6 @@
namespace net {
class BoundNetLog;
class UDPSocketWin : public base::NonThreadSafe {
public:
UDPSocketWin(DatagramSocket::BindType bind_type,
@ -136,8 +134,12 @@ class UDPSocketWin : public base::NonThreadSafe {
void DoWriteCallback(int rv);
void DidCompleteRead();
void DidCompleteWrite();
bool ProcessSuccessfulRead(int num_bytes, IPEndPoint* address);
void ProcessSuccessfulWrite(int num_bytes);
// Handles stats and logging. |result| is the number of bytes transferred, on
// success, or the net error code on failure. LogRead retrieves the address
// from |recv_addr_storage_|, while LogWrite takes it as an optional argument.
void LogRead(int result, const char* bytes) const;
void LogWrite(int result, const char* bytes, const IPEndPoint* address) const;
// Returns the OS error code (or 0 on success).
int CreateSocket(const IPEndPoint& address);
@ -150,12 +152,17 @@ class UDPSocketWin : public base::NonThreadSafe {
const IPEndPoint* address,
OldCompletionCallback* callback);
int InternalConnect(const IPEndPoint& address);
int InternalRecvFrom(IOBuffer* buf, int buf_len, IPEndPoint* address);
int InternalSendTo(IOBuffer* buf, int buf_len, const IPEndPoint* address);
int DoBind(const IPEndPoint& address);
int RandomBind(const IPEndPoint& address);
// Attempts to convert the data in |recv_addr_storage_| and |recv_addr_len_|
// to an IPEndPoint and writes it to |address|. Returns true on success.
bool ReceiveAddressToIPEndpoint(IPEndPoint* address) const;
SOCKET socket_;
// How to do source port binding, used only when UDPSocket is part of
@ -188,6 +195,10 @@ class UDPSocketWin : public base::NonThreadSafe {
socklen_t recv_addr_len_;
IPEndPoint* recv_from_address_;
// Cached copy of the current address we're sending to, if any. Used for
// logging.
scoped_ptr<IPEndPoint> send_to_address_;
// The buffer used by InternalWrite() to retry Write requests
scoped_refptr<IOBuffer> write_iobuffer_;