summaryrefslogtreecommitdiffstats
path: root/net/udp
diff options
context:
space:
mode:
authorszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-12 17:59:44 +0000
committerszym@chromium.org <szym@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-12 17:59:44 +0000
commit71bf717122f36d5720423939bf10c3c4296576e7 (patch)
tree0903b3d23e1509eebb80473ae8f7371ccb84aacf /net/udp
parent2ab5c5bf770f10a7f0d39fd8fd44afd4f6e51470 (diff)
downloadchromium_src-71bf717122f36d5720423939bf10c3c4296576e7.zip
chromium_src-71bf717122f36d5720423939bf10c3c4296576e7.tar.gz
chromium_src-71bf717122f36d5720423939bf10c3c4296576e7.tar.bz2
[net/udp] Create UDPSocketWin::Core which persists until all network operations complete.
The Core pattern is copied from TCPClientSocketWin. BUG=121085 TEST=net_unittests --gtest_filter=UDP* Review URL: https://chromiumcodereview.appspot.com/10918158 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156328 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/udp')
-rw-r--r--net/udp/udp_socket_win.cc196
-rw-r--r--net/udp/udp_socket_win.h46
2 files changed, 156 insertions, 86 deletions
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index f67c010..f1b7afa 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -31,16 +31,132 @@ static const int kPortEnd = 65535;
namespace net {
-void UDPSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) {
- DCHECK_EQ(object, socket_->read_overlapped_.hEvent);
- socket_->DidCompleteRead();
+// This class encapsulates all the state that has to be preserved as long as
+// there is a network IO operation in progress. If the owner UDPSocketWin
+// is destroyed while an operation is in progress, the Core is detached and it
+// lives until the operation completes and the OS doesn't reference any resource
+// declared on this class anymore.
+class UDPSocketWin::Core : public base::RefCounted<Core> {
+ public:
+ explicit Core(UDPSocketWin* socket);
+
+ // Start watching for the end of a read or write operation.
+ void WatchForRead();
+ void WatchForWrite();
+
+ // The UDPSocketWin is going away.
+ void Detach() { socket_ = NULL; }
+
+ // The separate OVERLAPPED variables for asynchronous operation.
+ OVERLAPPED read_overlapped_;
+ OVERLAPPED write_overlapped_;
+
+ // The buffers used in Read() and Write().
+ scoped_refptr<IOBuffer> read_iobuffer_;
+ scoped_refptr<IOBuffer> write_iobuffer_;
+
+ // The address storage passed to WSARecvFrom().
+ SockaddrStorage recv_addr_storage_;
+
+ private:
+ friend class base::RefCounted<Core>;
+
+ class ReadDelegate : public base::win::ObjectWatcher::Delegate {
+ public:
+ explicit ReadDelegate(Core* core) : core_(core) {}
+ virtual ~ReadDelegate() {}
+
+ // base::ObjectWatcher::Delegate methods:
+ virtual void OnObjectSignaled(HANDLE object);
+
+ private:
+ Core* const core_;
+ };
+
+ class WriteDelegate : public base::win::ObjectWatcher::Delegate {
+ public:
+ explicit WriteDelegate(Core* core) : core_(core) {}
+ virtual ~WriteDelegate() {}
+
+ // base::ObjectWatcher::Delegate methods:
+ virtual void OnObjectSignaled(HANDLE object);
+
+ private:
+ Core* const core_;
+ };
+
+ ~Core();
+
+ // The socket that created this object.
+ UDPSocketWin* socket_;
+
+ // |reader_| handles the signals from |read_watcher_|.
+ ReadDelegate reader_;
+ // |writer_| handles the signals from |write_watcher_|.
+ WriteDelegate writer_;
+
+ // |read_watcher_| watches for events from Read().
+ base::win::ObjectWatcher read_watcher_;
+ // |write_watcher_| watches for events from Write();
+ base::win::ObjectWatcher write_watcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(Core);
+};
+
+UDPSocketWin::Core::Core(UDPSocketWin* socket)
+ : socket_(socket),
+ ALLOW_THIS_IN_INITIALIZER_LIST(reader_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(writer_(this)) {
+ memset(&read_overlapped_, 0, sizeof(read_overlapped_));
+ memset(&write_overlapped_, 0, sizeof(write_overlapped_));
+
+ read_overlapped_.hEvent = WSACreateEvent();
+ write_overlapped_.hEvent = WSACreateEvent();
+}
+
+UDPSocketWin::Core::~Core() {
+ // Make sure the message loop is not watching this object anymore.
+ read_watcher_.StopWatching();
+ write_watcher_.StopWatching();
+
+ WSACloseEvent(read_overlapped_.hEvent);
+ memset(&read_overlapped_, 0xaf, sizeof(read_overlapped_));
+ WSACloseEvent(write_overlapped_.hEvent);
+ memset(&write_overlapped_, 0xaf, sizeof(write_overlapped_));
+}
+
+void UDPSocketWin::Core::WatchForRead() {
+ // We grab an extra reference because there is an IO operation in progress.
+ // Balanced in ReadDelegate::OnObjectSignaled().
+ AddRef();
+ read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_);
+}
+
+void UDPSocketWin::Core::WatchForWrite() {
+ // We grab an extra reference because there is an IO operation in progress.
+ // Balanced in WriteDelegate::OnObjectSignaled().
+ AddRef();
+ write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_);
}
-void UDPSocketWin::WriteDelegate::OnObjectSignaled(HANDLE object) {
- DCHECK_EQ(object, socket_->write_overlapped_.hEvent);
- socket_->DidCompleteWrite();
+void UDPSocketWin::Core::ReadDelegate::OnObjectSignaled(HANDLE object) {
+ DCHECK_EQ(object, core_->read_overlapped_.hEvent);
+ if (core_->socket_)
+ core_->socket_->DidCompleteRead();
+
+ core_->Release();
}
+void UDPSocketWin::Core::WriteDelegate::OnObjectSignaled(HANDLE object) {
+ DCHECK_EQ(object, core_->write_overlapped_.hEvent);
+ if (core_->socket_)
+ core_->socket_->DidCompleteWrite();
+
+ core_->Release();
+}
+
+//-----------------------------------------------------------------------------
+
UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
const RandIntCallback& rand_int_cb,
net::NetLog* net_log,
@@ -49,17 +165,11 @@ UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
socket_options_(0),
bind_type_(bind_type),
rand_int_cb_(rand_int_cb),
- ALLOW_THIS_IN_INITIALIZER_LIST(read_delegate_(this)),
- ALLOW_THIS_IN_INITIALIZER_LIST(write_delegate_(this)),
recv_from_address_(NULL),
net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
EnsureWinsockInit();
net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
source.ToEventParametersCallback());
- memset(&read_overlapped_, 0, sizeof(read_overlapped_));
- read_overlapped_.hEvent = WSACreateEvent();
- memset(&write_overlapped_, 0, sizeof(write_overlapped_));
- write_overlapped_.hEvent = WSACreateEvent();
if (bind_type == DatagramSocket::RANDOM_BIND)
DCHECK(!rand_int_cb.is_null());
}
@@ -80,16 +190,11 @@ void UDPSocketWin::Close() {
recv_from_address_ = NULL;
write_callback_.Reset();
- read_watcher_.StopWatching();
- write_watcher_.StopWatching();
-
- WSACloseEvent(read_overlapped_.hEvent);
- memset(&read_overlapped_, 0xaf, sizeof(read_overlapped_));
- WSACloseEvent(write_overlapped_.hEvent);
- memset(&write_overlapped_, 0xaf, sizeof(write_overlapped_));
-
closesocket(socket_);
socket_ = INVALID_SOCKET;
+
+ core_->Detach();
+ core_ = NULL;
}
int UDPSocketWin::GetPeerAddress(IPEndPoint* address) const {
@@ -155,7 +260,6 @@ int UDPSocketWin::RecvFrom(IOBuffer* buf,
if (nread != ERR_IO_PENDING)
return nread;
- read_iobuffer_ = buf;
read_callback_ = callback;
recv_from_address_ = address;
return ERR_IO_PENDING;
@@ -191,7 +295,6 @@ int UDPSocketWin::SendToOrWrite(IOBuffer* buf,
if (address)
send_to_address_.reset(new IPEndPoint(*address));
- write_iobuffer_ = buf;
write_callback_ = callback;
return ERR_IO_PENDING;
}
@@ -250,6 +353,7 @@ int UDPSocketWin::CreateSocket(const IPEndPoint& address) {
WSA_FLAG_OVERLAPPED);
if (socket_ == INVALID_SOCKET)
return MapSystemError(WSAGetLastError());
+ core_ = new Core(this);
return OK;
}
@@ -305,17 +409,17 @@ void UDPSocketWin::DoWriteCallback(int rv) {
void UDPSocketWin::DidCompleteRead() {
DWORD num_bytes, flags;
- BOOL ok = WSAGetOverlappedResult(socket_, &read_overlapped_,
+ BOOL ok = WSAGetOverlappedResult(socket_, &core_->read_overlapped_,
&num_bytes, FALSE, &flags);
- WSAResetEvent(read_overlapped_.hEvent);
+ WSAResetEvent(core_->read_overlapped_.hEvent);
int result = ok ? num_bytes : MapSystemError(WSAGetLastError());
// Convert address.
if (recv_from_address_ && result >= 0) {
if (!ReceiveAddressToIPEndpoint(recv_from_address_))
result = ERR_FAILED;
}
- LogRead(result, read_iobuffer_->data());
- read_iobuffer_ = NULL;
+ LogRead(result, core_->read_iobuffer_->data());
+ core_->read_iobuffer_ = NULL;
recv_from_address_ = NULL;
DoReadCallback(result);
}
@@ -343,14 +447,14 @@ void UDPSocketWin::LogRead(int result, const char* bytes) const {
void UDPSocketWin::DidCompleteWrite() {
DWORD num_bytes, flags;
- BOOL ok = WSAGetOverlappedResult(socket_, &write_overlapped_,
+ BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_,
&num_bytes, FALSE, &flags);
- WSAResetEvent(write_overlapped_.hEvent);
+ WSAResetEvent(core_->write_overlapped_.hEvent);
int result = ok ? num_bytes : MapSystemError(WSAGetLastError());
- LogWrite(result, write_iobuffer_->data(), send_to_address_.get());
+ LogWrite(result, core_->write_iobuffer_->data(), send_to_address_.get());
send_to_address_.reset();
- write_iobuffer_ = NULL;
+ core_->write_iobuffer_ = NULL;
DoWriteCallback(result);
}
@@ -374,9 +478,9 @@ void UDPSocketWin::LogWrite(int result,
int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
IPEndPoint* address) {
- recv_addr_len_ = sizeof(recv_addr_storage_);
- struct sockaddr* addr =
- reinterpret_cast<struct sockaddr*>(&recv_addr_storage_);
+ DCHECK(!core_->read_iobuffer_);
+ SockaddrStorage& storage = core_->recv_addr_storage_;
+ storage.addr_len = sizeof(storage.addr_storage);
WSABUF read_buffer;
read_buffer.buf = buf->data();
@@ -385,11 +489,11 @@ int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
DWORD flags = 0;
DWORD num;
CHECK_NE(INVALID_SOCKET, socket_);
- AssertEventNotSignaled(read_overlapped_.hEvent);
- int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, addr,
- &recv_addr_len_, &read_overlapped_, NULL);
+ AssertEventNotSignaled(core_->read_overlapped_.hEvent);
+ int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, storage.addr,
+ &storage.addr_len, &core_->read_overlapped_, NULL);
if (rv == 0) {
- if (ResetEventIfSignaled(read_overlapped_.hEvent)) {
+ if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) {
int result = num;
// Convert address.
if (address && result >= 0) {
@@ -407,12 +511,14 @@ int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
return result;
}
}
- read_watcher_.StartWatching(read_overlapped_.hEvent, &read_delegate_);
+ core_->WatchForRead();
+ core_->read_iobuffer_ = buf;
return ERR_IO_PENDING;
}
int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
const IPEndPoint* address) {
+ DCHECK(!core_->write_iobuffer_);
SockaddrStorage storage;
struct sockaddr* addr = storage.addr;
// Convert address.
@@ -433,11 +539,11 @@ int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
DWORD flags = 0;
DWORD num;
- AssertEventNotSignaled(write_overlapped_.hEvent);
+ AssertEventNotSignaled(core_->write_overlapped_.hEvent);
int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags,
- addr, storage.addr_len, &write_overlapped_, NULL);
+ addr, storage.addr_len, &core_->write_overlapped_, NULL);
if (rv == 0) {
- if (ResetEventIfSignaled(write_overlapped_.hEvent)) {
+ if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) {
int result = num;
LogWrite(result, buf->data(), address);
return result;
@@ -451,7 +557,8 @@ int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
}
}
- write_watcher_.StartWatching(write_overlapped_.hEvent, &write_delegate_);
+ core_->WatchForWrite();
+ core_->write_iobuffer_ = buf;
return ERR_IO_PENDING;
}
@@ -497,9 +604,8 @@ int UDPSocketWin::RandomBind(const IPEndPoint& address) {
}
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_);
+ SockaddrStorage& storage = core_->recv_addr_storage_;
+ return address->FromSockAddr(storage.addr, storage.addr_len);
}
} // namespace net
diff --git a/net/udp/udp_socket_win.h b/net/udp/udp_socket_win.h
index 2185fbb..ce17050 100644
--- a/net/udp/udp_socket_win.h
+++ b/net/udp/udp_socket_win.h
@@ -121,29 +121,7 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
SOCKET_OPTION_BROADCAST = 1 << 1
};
- class ReadDelegate : public base::win::ObjectWatcher::Delegate {
- public:
- explicit ReadDelegate(UDPSocketWin* socket) : socket_(socket) {}
- virtual ~ReadDelegate() {}
-
- // base::ObjectWatcher::Delegate methods:
- virtual void OnObjectSignaled(HANDLE object);
-
- private:
- UDPSocketWin* const socket_;
- };
-
- class WriteDelegate : public base::win::ObjectWatcher::Delegate {
- public:
- explicit WriteDelegate(UDPSocketWin* socket) : socket_(socket) {}
- virtual ~WriteDelegate() {}
-
- // base::ObjectWatcher::Delegate methods:
- virtual void OnObjectSignaled(HANDLE object);
-
- private:
- UDPSocketWin* const socket_;
- };
+ class Core;
void DoReadCallback(int rv);
void DoWriteCallback(int rv);
@@ -199,31 +177,17 @@ class NET_EXPORT UDPSocketWin : NON_EXPORTED_BASE(public base::NonThreadSafe) {
mutable scoped_ptr<IPEndPoint> local_address_;
mutable scoped_ptr<IPEndPoint> remote_address_;
- // The socket's win wrappers
- ReadDelegate read_delegate_;
- WriteDelegate write_delegate_;
-
- // Watchers to watch for events from Read() and Write().
- base::win::ObjectWatcher read_watcher_;
- base::win::ObjectWatcher write_watcher_;
+ // The core of the socket that can live longer than the socket itself. We pass
+ // resources to the Windows async IO functions and we have to make sure that
+ // they are not destroyed while the OS still references them.
+ scoped_refptr<Core> core_;
- // OVERLAPPED for pending read and write operations.
- OVERLAPPED read_overlapped_;
- OVERLAPPED write_overlapped_;
-
- // The buffer used by InternalRead() to retry Read requests
- scoped_refptr<IOBuffer> read_iobuffer_;
- struct sockaddr_storage recv_addr_storage_;
- 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_;
-
// External callback; called when read is complete.
CompletionCallback read_callback_;