summaryrefslogtreecommitdiffstats
path: root/net/udp
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-11 22:01:17 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-03-11 22:01:17 +0000
commit02c5bc44bfa08094433251681ece311d78bc29b6 (patch)
tree14003726acc1447b7865cc4e2c8e7215546098db /net/udp
parent9e497dd1a3174372eda0d4322a959f576415a8c9 (diff)
downloadchromium_src-02c5bc44bfa08094433251681ece311d78bc29b6.zip
chromium_src-02c5bc44bfa08094433251681ece311d78bc29b6.tar.gz
chromium_src-02c5bc44bfa08094433251681ece311d78bc29b6.tar.bz2
UDP sockets implementation for windows.
BUG=None TEST=Unittests Review URL: http://codereview.chromium.org/6658027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@77870 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/udp')
-rw-r--r--net/udp/datagram_server_socket.h2
-rw-r--r--net/udp/udp_socket.h19
-rw-r--r--net/udp/udp_socket_libevent.cc42
-rw-r--r--net/udp/udp_socket_libevent.h24
-rw-r--r--net/udp/udp_socket_unittest.cc62
-rw-r--r--net/udp/udp_socket_win.cc366
-rw-r--r--net/udp/udp_socket_win.h178
7 files changed, 642 insertions, 51 deletions
diff --git a/net/udp/datagram_server_socket.h b/net/udp/datagram_server_socket.h
index 30286e5..9841d53 100644
--- a/net/udp/datagram_server_socket.h
+++ b/net/udp/datagram_server_socket.h
@@ -6,8 +6,6 @@
#define NET_UDP_DATAGRAM_SERVER_SOCKET_H_
#pragma once
-#include <sys/socket.h>
-
#include "net/base/completion_callback.h"
#include "net/udp/datagram_socket.h"
diff --git a/net/udp/udp_socket.h b/net/udp/udp_socket.h
index 9e5f826..15ba76c 100644
--- a/net/udp/udp_socket.h
+++ b/net/udp/udp_socket.h
@@ -16,7 +16,24 @@
namespace net {
-// A client socket that uses UDP as the transport layer.
+// UDPSocket
+// Accessor API for a UDP socket in either client or server form.
+//
+// Client form:
+// In this case, we're connecting to a specific server, so the client will
+// usually use:
+// Connect(address) // Connect to a UDP server
+// Read/Write // Reads/Writes all go to a single destination
+//
+// Server form:
+// In this case, we want to read/write to many clients which are connecting
+// to this server. First the server 'binds' to an addres, then we read from
+// clients and write responses to them.
+// Example:
+// Bind(address/port) // Binds to port for reading from clients
+// RecvFrom/SendTo // Each read can come from a different client
+// // Writes need to be directed to a specific
+// // address.
#if defined(OS_WIN)
typedef UDPSocketWin UDPSocket;
#elif defined(OS_POSIX)
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 7c75ce3..de24253 100644
--- a/net/udp/udp_socket_libevent.cc
+++ b/net/udp/udp_socket_libevent.cc
@@ -63,6 +63,8 @@ int MapPosixError(int os_error) {
return ERR_ADDRESS_INVALID;
case EMSGSIZE:
return ERR_MSG_TOO_BIG;
+ case ENOTCONN:
+ return ERR_SOCKET_NOT_CONNECTED;
case 0:
return OK;
default:
@@ -99,9 +101,21 @@ UDPSocketLibevent::~UDPSocketLibevent() {
}
void UDPSocketLibevent::Close() {
+ DCHECK(CalledOnValidThread());
+
+ if (read_callback_)
+ DoReadCallback(ERR_ABORTED);
+ if (write_callback_)
+ DoReadCallback(ERR_ABORTED);
+
if (!is_connected())
return;
+ bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
+ DCHECK(ok);
+ ok = write_socket_watcher_.StopWatchingFileDescriptor();
+ DCHECK(ok);
+
if (HANDLE_EINTR(close(socket_)) < 0)
PLOG(ERROR) << "close";
@@ -161,10 +175,7 @@ int UDPSocketLibevent::Read(IOBuffer* buf,
DCHECK(callback); // Synchronous operation not supported
DCHECK_GT(buf_len, 0);
- read_buf_ = buf;
- read_buf_len_ = buf_len;
-
- int nread = InternalRead();
+ int nread = InternalRead(buf, buf_len);
if (nread != ERR_IO_PENDING)
return nread;
@@ -175,6 +186,8 @@ int UDPSocketLibevent::Read(IOBuffer* buf,
return MapPosixError(errno);
}
+ read_buf_ = buf;
+ read_buf_len_ = buf_len;
read_callback_ = callback;
return ERR_IO_PENDING;
}
@@ -232,7 +245,7 @@ int UDPSocketLibevent::Connect(const IPEndPoint& address) {
DCHECK(!remote_address_.get());
int rv = CreateSocket(address);
if (rv < 0)
- return MapPosixError(rv);
+ return rv;
struct sockaddr_storage addr_storage;
size_t addr_len = sizeof(addr_storage);
@@ -242,7 +255,7 @@ int UDPSocketLibevent::Connect(const IPEndPoint& address) {
rv = HANDLE_EINTR(connect(socket_, addr, addr_len));
if (rv < 0)
- return MapPosixError(rv);
+ return MapPosixError(errno);
remote_address_.reset(new IPEndPoint(address));
return rv;
@@ -253,7 +266,7 @@ int UDPSocketLibevent::Bind(const IPEndPoint& address) {
DCHECK(!local_address_.get());
int rv = CreateSocket(address);
if (rv < 0)
- return MapPosixError(rv);
+ return rv;
struct sockaddr_storage addr_storage;
size_t addr_len = sizeof(addr_storage);
@@ -263,7 +276,7 @@ int UDPSocketLibevent::Bind(const IPEndPoint& address) {
rv = bind(socket_, addr, addr_len);
if (rv < 0)
- return MapPosixError(rv);
+ return MapPosixError(errno);
local_address_.reset(new IPEndPoint(address));
return rv;
@@ -292,7 +305,7 @@ void UDPSocketLibevent::DoWriteCallback(int rv) {
}
void UDPSocketLibevent::DidCompleteRead() {
- int result = InternalRead();
+ int result = InternalRead(read_buf_, read_buf_len_);
if (result != ERR_IO_PENDING) {
read_buf_ = NULL;
read_buf_len_ = 0;
@@ -305,9 +318,9 @@ void UDPSocketLibevent::DidCompleteRead() {
int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) {
socket_ = socket(address.GetFamily(), SOCK_DGRAM, 0);
if (socket_ == kInvalidSocket)
- return errno;
+ return MapPosixError(errno);
if (SetNonBlocking(socket_)) {
- const int err = errno;
+ const int err = MapPosixError(errno);
Close();
return err;
}
@@ -331,7 +344,7 @@ void UDPSocketLibevent::DidCompleteWrite() {
}
}
-int UDPSocketLibevent::InternalRead() {
+int UDPSocketLibevent::InternalRead(IOBuffer* buf, int buf_len) {
int bytes_transferred;
int flags = 0;
@@ -341,8 +354,8 @@ int UDPSocketLibevent::InternalRead() {
bytes_transferred =
HANDLE_EINTR(recvfrom(socket_,
- read_buf_->data(),
- read_buf_len_,
+ buf->data(),
+ buf_len,
flags,
addr,
&addr_len));
@@ -360,6 +373,7 @@ int UDPSocketLibevent::InternalRead() {
}
return result;
}
+
int UDPSocketLibevent::InternalWrite(IOBuffer* buf, int buf_len) {
struct sockaddr_storage addr_storage;
size_t addr_len = sizeof(addr_storage);
diff --git a/net/udp/udp_socket_libevent.h b/net/udp/udp_socket_libevent.h
index ebe01b2..1a9fd6e 100644
--- a/net/udp/udp_socket_libevent.h
+++ b/net/udp/udp_socket_libevent.h
@@ -6,25 +6,6 @@
#define NET_UDP_UDP_SOCKET_LIBEVENT_H_
#pragma once
-// UDPSocketLibevent
-// Accessor API for a UDP socket in either client or server form.
-//
-// Client form:
-// In this case, we're connecting to a specific server, so the client will
-// usually use:
-// Connect(address) // Connect to a UDP server
-// Read/Write // Reads/Writes all go to a single destination
-//
-// Server form:
-// In this case, we want to read/write to many clients which are connecting
-// to this server. First the server 'binds' to an addres, then we read from
-// clients and write responses to them.
-// Example:
-// Bind(address/port) // Binds to port for reading from clients
-// RecvFrom/SendTo // Each read can come from a different client
-// // Writes need to be directed to a specific
-// // address.
-
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
@@ -33,7 +14,6 @@
#include "net/base/ip_endpoint.h"
#include "net/base/net_log.h"
#include "net/socket/client_socket.h"
-#include "net/udp/datagram_socket.h"
namespace net {
@@ -113,8 +93,6 @@ class UDPSocketLibevent : public base::NonThreadSafe {
// Returns true if the socket is already connected or bound.
bool is_connected() const { return socket_ != kInvalidSocket; }
- IPEndPoint* local_address() { return local_address_.get(); }
-
private:
static const int kInvalidSocket = -1;
@@ -164,7 +142,7 @@ class UDPSocketLibevent : public base::NonThreadSafe {
// Returns the OS error code (or 0 on success).
int CreateSocket(const IPEndPoint& address);
- int InternalRead();
+ int InternalRead(IOBuffer* buf, int buf_len);
int InternalWrite(IOBuffer* buf, int buf_len);
int socket_;
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index ef43731..23caf22 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -107,7 +107,7 @@ class UDPSocketTest : public PlatformTest {
return bytes_sent;
}
- private:
+ protected:
static const int kMaxRead = 1024;
scoped_refptr<IOBufferWithSize> buffer_;
IPEndPoint recv_from_address_;
@@ -223,7 +223,7 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
struct TestData {
std::string remote_address;
std::string local_address;
- bool is_ipv6;
+ bool may_fail;
} tests[] = {
{ "127.0.00.1", "127.0.0.1", false },
{ "192.168.1.1", "127.0.0.1", false },
@@ -231,6 +231,9 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
{ "2001:db8:0::42", "::1", true },
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); i++) {
+ 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);
@@ -239,6 +242,12 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
UDPClientSocket client(NULL, NetLog::Source());
int rv = client.Connect(remote_address);
+ if (tests[i].may_fail && rv == ERR_ADDRESS_UNREACHABLE) {
+ // Connect() may return ERR_ADDRESS_UNREACHABLE for IPv6
+ // addresses if IPv6 is not configured.
+ continue;
+ }
+
EXPECT_LE(ERR_IO_PENDING, rv);
IPEndPoint fetched_local_address;
@@ -260,21 +269,52 @@ TEST_F(UDPSocketTest, ClientGetLocalPeerAddresses) {
}
TEST_F(UDPSocketTest, ServerGetLocalAddress) {
- // TODO(mbelshe): implement me
+ IPEndPoint bind_address;
+ CreateUDPAddress("127.0.0.1", 0, &bind_address);
+ UDPServerSocket server(NULL, NetLog::Source());
+ int rv = server.Listen(bind_address);
+ EXPECT_EQ(OK, rv);
+
+ IPEndPoint local_address;
+ rv = server.GetLocalAddress(&local_address);
+ EXPECT_EQ(rv, 0);
+
+ // Verify that port was allocated.
+ EXPECT_GE(local_address.port(), 0);
+ EXPECT_EQ(local_address.address(), bind_address.address());
}
TEST_F(UDPSocketTest, ServerGetPeerAddress) {
- // TODO(mbelshe): implement me
+ IPEndPoint bind_address;
+ CreateUDPAddress("127.0.0.1", 0, &bind_address);
+ UDPServerSocket server(NULL, NetLog::Source());
+ int rv = server.Listen(bind_address);
+ EXPECT_EQ(OK, rv);
+
+ IPEndPoint peer_address;
+ rv = server.GetPeerAddress(&peer_address);
+ EXPECT_EQ(rv, ERR_SOCKET_NOT_CONNECTED);
}
-} // namespace
+// Close the socket while read is pending.
+TEST_F(UDPSocketTest, CloseWithPendingRead) {
+ IPEndPoint bind_address;
+ CreateUDPAddress("127.0.0.1", 0, &bind_address);
+ UDPServerSocket server(NULL, NetLog::Source());
+ int rv = server.Listen(bind_address);
+ EXPECT_EQ(OK, rv);
-} // namespace net
+ TestCompletionCallback callback;
+ IPEndPoint from;
+ rv = server.RecvFrom(buffer_, kMaxRead, &from, &callback);
+ EXPECT_EQ(rv, ERR_IO_PENDING);
-int main(int argc, char** argv) {
- // Record histograms, so we can get histograms data in tests.
- base::StatisticsRecorder recorder;
- NetTestSuite test_suite(argc, argv);
+ server.Close();
- return test_suite.Run();
+ EXPECT_TRUE(callback.have_result());
+ EXPECT_EQ(callback.GetResult(rv), ERR_ABORTED);
}
+
+} // namespace
+
+} // namespace net
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
new file mode 100644
index 0000000..8a180d2
--- /dev/null
+++ b/net/udp/udp_socket_win.cc
@@ -0,0 +1,366 @@
+// 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 "net/udp/udp_socket_win.h"
+
+#include <mstcpip.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/memory_debug.h"
+#include "base/metrics/stats_counters.h"
+#include "net/base/io_buffer.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_log.h"
+#include "net/base/net_util.h"
+#include "net/base/winsock_init.h"
+#include "net/base/winsock_util.h"
+
+namespace net {
+
+void UDPSocketWin::ReadDelegate::OnObjectSignaled(HANDLE object) {
+ DCHECK_EQ(object, socket_->read_overlapped_.hEvent);
+ socket_->DidCompleteRead();
+}
+
+void UDPSocketWin::WriteDelegate::OnObjectSignaled(HANDLE object) {
+ DCHECK_EQ(object, socket_->write_overlapped_.hEvent);
+ socket_->DidCompleteWrite();
+}
+
+UDPSocketWin::UDPSocketWin(net::NetLog* net_log,
+ const net::NetLog::Source& source)
+ : socket_(INVALID_SOCKET),
+ ALLOW_THIS_IN_INITIALIZER_LIST(read_delegate_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(write_delegate_(this)),
+ recv_from_address_(NULL),
+ read_callback_(NULL),
+ write_callback_(NULL),
+ net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_SOCKET)) {
+ EnsureWinsockInit();
+ scoped_refptr<NetLog::EventParameters> params;
+ if (source.is_valid())
+ params = new NetLogSourceParameter("source_dependency", source);
+ net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, params);
+ memset(&read_overlapped_, 0, sizeof(read_overlapped_));
+ read_overlapped_.hEvent = WSACreateEvent();
+ memset(&write_overlapped_, 0, sizeof(write_overlapped_));
+ write_overlapped_.hEvent = WSACreateEvent();
+}
+
+UDPSocketWin::~UDPSocketWin() {
+ Close();
+ net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE, NULL);
+}
+
+void UDPSocketWin::Close() {
+ DCHECK(CalledOnValidThread());
+
+ if (!is_connected())
+ return;
+
+ if (read_callback_)
+ DoReadCallback(ERR_ABORTED);
+ if (write_callback_)
+ DoReadCallback(ERR_ABORTED);
+
+ read_watcher_.StopWatching();
+ write_watcher_.StopWatching();
+
+ closesocket(socket_);
+ socket_ = INVALID_SOCKET;
+}
+
+int UDPSocketWin::GetPeerAddress(IPEndPoint* address) const {
+ DCHECK(CalledOnValidThread());
+ DCHECK(address);
+ if (!is_connected())
+ return ERR_SOCKET_NOT_CONNECTED;
+
+ if (!remote_address_.get()) {
+ struct sockaddr_storage addr_storage;
+ int addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (getpeername(socket_, addr, &addr_len))
+ return MapWinsockError(WSAGetLastError());
+ scoped_ptr<IPEndPoint> address(new IPEndPoint());
+ if (!address->FromSockAddr(addr, addr_len))
+ return ERR_FAILED;
+ remote_address_.reset(address.release());
+ }
+
+ *address = *remote_address_;
+ return OK;
+}
+
+int UDPSocketWin::GetLocalAddress(IPEndPoint* address) const {
+ DCHECK(CalledOnValidThread());
+ DCHECK(address);
+ if (!is_connected())
+ return ERR_SOCKET_NOT_CONNECTED;
+
+ if (!local_address_.get()) {
+ struct sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (getsockname(socket_, addr, &addr_len))
+ return MapWinsockError(WSAGetLastError());
+ scoped_ptr<IPEndPoint> address(new IPEndPoint());
+ if (!address->FromSockAddr(addr, addr_len))
+ return ERR_FAILED;
+ local_address_.reset(address.release());
+ }
+
+ *address = *local_address_;
+ return OK;
+}
+
+int UDPSocketWin::RecvFrom(IOBuffer* buf,
+ int buf_len,
+ IPEndPoint* address,
+ CompletionCallback* callback) {
+ DCHECK(!recv_from_address_);
+ recv_from_address_ = address;
+ return Read(buf, buf_len, callback);
+}
+
+int UDPSocketWin::Read(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_NE(INVALID_SOCKET, socket_);
+ DCHECK(!read_callback_);
+ DCHECK(callback); // Synchronous operation not supported.
+ DCHECK_GT(buf_len, 0);
+
+ int nread = InternalRead(buf, buf_len);
+ if (nread != ERR_IO_PENDING)
+ return nread;
+
+ read_iobuffer_ = buf;
+ read_callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+int UDPSocketWin::SendTo(IOBuffer* buf,
+ int buf_len,
+ const IPEndPoint& address,
+ CompletionCallback* callback) {
+ send_to_address_.reset(new IPEndPoint(address));
+ return Write(buf, buf_len, callback);
+}
+
+int UDPSocketWin::Write(IOBuffer* buf,
+ int buf_len,
+ CompletionCallback* callback) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_NE(INVALID_SOCKET, socket_);
+ DCHECK(!write_callback_);
+ DCHECK(callback); // Synchronous operation not supported.
+ DCHECK_GT(buf_len, 0);
+
+ int nwrite = InternalWrite(buf, buf_len);
+ if (nwrite != ERR_IO_PENDING)
+ return nwrite;
+
+ write_iobuffer_ = buf;
+ write_callback_ = callback;
+ return ERR_IO_PENDING;
+}
+
+int UDPSocketWin::Connect(const IPEndPoint& address) {
+ DCHECK(!is_connected());
+ DCHECK(!remote_address_.get());
+ int rv = CreateSocket(address);
+ if (rv < 0)
+ return rv;
+
+ struct sockaddr_storage addr_storage;
+ size_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (!address.ToSockAddr(addr, &addr_len))
+ return ERR_FAILED;
+
+ rv = connect(socket_, addr, addr_len);
+ if (rv < 0)
+ return MapWinsockError(WSAGetLastError());
+
+ remote_address_.reset(new IPEndPoint(address));
+ return rv;
+}
+
+int UDPSocketWin::Bind(const IPEndPoint& address) {
+ DCHECK(!is_connected());
+ DCHECK(!local_address_.get());
+ int rv = CreateSocket(address);
+ if (rv < 0)
+ return rv;
+
+ struct sockaddr_storage addr_storage;
+ size_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+ if (!address.ToSockAddr(addr, &addr_len))
+ return ERR_FAILED;
+
+ rv = bind(socket_, addr, addr_len);
+ if (rv < 0)
+ return MapWinsockError(WSAGetLastError());
+
+ local_address_.reset(new IPEndPoint(address));
+ return rv;
+}
+
+int UDPSocketWin::CreateSocket(const IPEndPoint& address) {
+ socket_ = WSASocket(address.GetFamily(), SOCK_DGRAM, IPPROTO_UDP, NULL, 0,
+ WSA_FLAG_OVERLAPPED);
+ if (socket_ == INVALID_SOCKET)
+ return MapWinsockError(WSAGetLastError());
+ return OK;
+}
+
+void UDPSocketWin::DoReadCallback(int rv) {
+ DCHECK_NE(rv, ERR_IO_PENDING);
+ DCHECK(read_callback_);
+
+ // since Run may result in Read being called, clear read_callback_ up front.
+ CompletionCallback* c = read_callback_;
+ read_callback_ = NULL;
+ recv_from_address_ = NULL;
+ c->Run(rv);
+}
+
+void UDPSocketWin::DoWriteCallback(int rv) {
+ DCHECK_NE(rv, ERR_IO_PENDING);
+ DCHECK(write_callback_);
+
+ // since Run may result in Write being called, clear write_callback_ up front.
+ CompletionCallback* c = write_callback_;
+ write_callback_ = NULL;
+ send_to_address_.reset();
+ c->Run(rv);
+}
+
+void UDPSocketWin::DidCompleteRead() {
+ DWORD num_bytes, flags;
+ BOOL ok = WSAGetOverlappedResult(socket_, &read_overlapped_,
+ &num_bytes, FALSE, &flags);
+ WSAResetEvent(read_overlapped_.hEvent);
+ int result = ok ? num_bytes : MapWinsockError(WSAGetLastError());
+ if (ok) {
+ if (!ProcessSuccessfulRead(num_bytes))
+ result = ERR_FAILED;
+ }
+ read_iobuffer_ = NULL;
+ DoReadCallback(result);
+}
+
+bool UDPSocketWin::ProcessSuccessfulRead(int num_bytes) {
+ static base::StatsCounter read_bytes("udp.read_bytes");
+ read_bytes.Add(num_bytes);
+
+ // Convert address.
+ if (recv_from_address_) {
+ struct sockaddr* addr =
+ reinterpret_cast<struct sockaddr*>(&recv_addr_storage_);
+ if (!recv_from_address_->FromSockAddr(addr, recv_addr_len_))
+ return false;
+ }
+
+ return true;
+}
+
+void UDPSocketWin::DidCompleteWrite() {
+ DWORD num_bytes, flags;
+ BOOL ok = WSAGetOverlappedResult(socket_, &write_overlapped_,
+ &num_bytes, FALSE, &flags);
+ WSAResetEvent(write_overlapped_.hEvent);
+ int result = ok ? num_bytes : MapWinsockError(WSAGetLastError());
+ if (ok)
+ ProcessSuccessfulWrite(num_bytes);
+ write_iobuffer_ = NULL;
+ DoWriteCallback(result);
+}
+
+void UDPSocketWin::ProcessSuccessfulWrite(int num_bytes) {
+ static base::StatsCounter write_bytes("udp.write_bytes");
+ write_bytes.Add(num_bytes);
+}
+
+int UDPSocketWin::InternalRead(IOBuffer* buf, int buf_len) {
+ recv_addr_len_ = sizeof(recv_addr_storage_);
+ struct sockaddr* addr =
+ reinterpret_cast<struct sockaddr*>(&recv_addr_storage_);
+
+ WSABUF read_buffer;
+ read_buffer.buf = buf->data();
+ read_buffer.len = buf_len;
+
+ DWORD flags = 0;
+ DWORD num;
+ AssertEventNotSignaled(read_overlapped_.hEvent);
+ int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, addr,
+ &recv_addr_len_, &read_overlapped_, NULL);
+ if (rv == 0) {
+ if (ResetEventIfSignaled(read_overlapped_.hEvent)) {
+ // Because of how WSARecv fills memory when used asynchronously, Purify
+ // isn't able to detect that it's been initialized, so it scans for 0xcd
+ // in the buffer and reports UMRs (uninitialized memory reads) for those
+ // individual bytes. We override that in PURIFY builds to avoid the
+ // false error reports.
+ // See bug 5297.
+ base::MemoryDebug::MarkAsInitialized(read_buffer.buf, num);
+ if (!ProcessSuccessfulRead(num))
+ return ERR_FAILED;
+ return static_cast<int>(num);
+ }
+ } else {
+ int os_error = WSAGetLastError();
+ if (os_error != WSA_IO_PENDING)
+ return MapWinsockError(os_error);
+ }
+ read_watcher_.StartWatching(read_overlapped_.hEvent, &read_delegate_);
+ return ERR_IO_PENDING;
+}
+
+int UDPSocketWin::InternalWrite(IOBuffer* buf, int buf_len) {
+ struct sockaddr_storage addr_storage;
+ size_t addr_len = sizeof(addr_storage);
+ struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addr_storage);
+
+ // Convert address.
+ if (!send_to_address_.get()) {
+ addr = NULL;
+ addr_len = 0;
+ } else {
+ if (!send_to_address_->ToSockAddr(addr, &addr_len))
+ return ERR_FAILED;
+ }
+
+ WSABUF write_buffer;
+ write_buffer.buf = buf->data();
+ write_buffer.len = buf_len;
+
+ DWORD flags = 0;
+ DWORD num;
+ AssertEventNotSignaled(write_overlapped_.hEvent);
+ int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags,
+ addr, addr_len, &write_overlapped_, NULL);
+ if (rv == 0) {
+ if (ResetEventIfSignaled(write_overlapped_.hEvent)) {
+ ProcessSuccessfulWrite(num);
+ return static_cast<int>(num);
+ }
+ } else {
+ int os_error = WSAGetLastError();
+ if (os_error != WSA_IO_PENDING)
+ return MapWinsockError(os_error);
+ }
+
+ write_watcher_.StartWatching(write_overlapped_.hEvent, &write_delegate_);
+ return ERR_IO_PENDING;
+}
+
+} // namespace net
diff --git a/net/udp/udp_socket_win.h b/net/udp/udp_socket_win.h
new file mode 100644
index 0000000..d9e1dee
--- /dev/null
+++ b/net/udp/udp_socket_win.h
@@ -0,0 +1,178 @@
+// 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_SOCKET_WIN_H_
+#define NET_UDP_UDP_SOCKET_WIN_H_
+#pragma once
+
+#include <winsock2.h>
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/win/object_watcher.h"
+#include "net/base/completion_callback.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_log.h"
+
+namespace net {
+
+class BoundNetLog;
+
+class UDPSocketWin : public base::NonThreadSafe {
+ public:
+ UDPSocketWin(net::NetLog* net_log,
+ const net::NetLog::Source& source);
+ virtual ~UDPSocketWin();
+
+ // Connect the socket to connect with a certain |address|.
+ // Returns a net error code.
+ int Connect(const IPEndPoint& address);
+
+ // Bind the address/port for this socket to |address|. This is generally
+ // only used on a server.
+ // Returns a net error code.
+ int Bind(const IPEndPoint& address);
+
+ // Close the socket.
+ void Close();
+
+ // Copy the remote udp address into |address| and return a network error code.
+ int GetPeerAddress(IPEndPoint* address) const;
+
+ // Copy the local udp address into |address| and return a network error code.
+ // (similar to getsockname)
+ int GetLocalAddress(IPEndPoint* address) const;
+
+ // IO:
+ // Multiple outstanding read requests are not supported.
+ // Full duplex mode (reading and writing at the same time) is supported
+
+ // Read from the socket.
+ // Only usable from the client-side of a UDP socket, after the socket
+ // has been connected.
+ int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+
+ // Write to the socket.
+ // Only usable from the client-side of a UDP socket, after the socket
+ // has been connected.
+ int Write(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+
+ // Read from a socket and receive sender address information.
+ // |buf| is the buffer to read data into.
+ // |buf_len| is the maximum amount of data to read.
+ // |address| is a buffer provided by the caller for receiving the sender
+ // address information about the received data. This buffer must be kept
+ // alive by the caller until the callback is placed.
+ // |address_length| is a ptr to the length of the |address| buffer. This
+ // is an input parameter containing the maximum size |address| can hold
+ // and also an output parameter for the size of |address| upon completion.
+ // |callback| the callback on completion of the Recv.
+ // Returns a net error code, or ERR_IO_PENDING if the IO is in progress.
+ // If ERR_IO_PENDING is returned, the caller must keep |buf|, |address|,
+ // and |address_length| alive until the callback is called.
+ int RecvFrom(IOBuffer* buf,
+ int buf_len,
+ IPEndPoint* address,
+ CompletionCallback* callback);
+
+ // Send to a socket with a particular destination.
+ // |buf| is the buffer to send
+ // |buf_len| is the number of bytes to send
+ // |address| is the recipient address.
+ // |address_length| is the size of the recipient address
+ // |callback| is the user callback function to call on complete.
+ // Returns a net error code, or ERR_IO_PENDING if the IO is in progress.
+ // If ERR_IO_PENDING is returned, the caller must keep |buf| and |address|
+ // alive until the callback is called.
+ int SendTo(IOBuffer* buf,
+ int buf_len,
+ const IPEndPoint& address,
+ CompletionCallback* callback);
+
+ // Returns true if the socket is already connected or bound.
+ bool is_connected() const { return socket_ != INVALID_SOCKET; }
+
+ private:
+ 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_;
+ };
+
+ void DoReadCallback(int rv);
+ void DoWriteCallback(int rv);
+ void DidCompleteRead();
+ void DidCompleteWrite();
+ bool ProcessSuccessfulRead(int num_bytes);
+ void ProcessSuccessfulWrite(int num_bytes);
+
+ // Returns the OS error code (or 0 on success).
+ int CreateSocket(const IPEndPoint& address);
+
+ int InternalRead(IOBuffer* buf, int buf_len);
+ int InternalWrite(IOBuffer* buf, int buf_len);
+
+ SOCKET socket_;
+
+ // These are mutable since they're just cached copies to make
+ // GetPeerAddress/GetLocalAddress smarter.
+ 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_;
+
+ // 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_;
+
+ // The buffer used by InternalWrite() to retry Write requests
+ scoped_refptr<IOBuffer> write_iobuffer_;
+ scoped_ptr<IPEndPoint> send_to_address_;
+
+ // External callback; called when read is complete.
+ CompletionCallback* read_callback_;
+
+ // External callback; called when write is complete.
+ CompletionCallback* write_callback_;
+
+ BoundNetLog net_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(UDPSocketWin);
+};
+
+} // namespace net
+
+#endif // NET_UDP_UDP_SOCKET_WIN_H_