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
3// found in the LICENSE file.
4
5#include "net/udp/udp_socket_win.h"
6
7#include <mstcpip.h>
8
9#include "base/callback.h"
10#include "base/logging.h"
11#include "base/message_loop/message_loop.h"
12#include "base/metrics/histogram.h"
13#include "base/metrics/stats_counters.h"
14#include "base/posix/eintr_wrapper.h"
15#include "base/rand_util.h"
16#include "net/base/io_buffer.h"
17#include "net/base/ip_endpoint.h"
18#include "net/base/net_errors.h"
19#include "net/base/net_log.h"
20#include "net/base/net_util.h"
21#include "net/base/winsock_init.h"
22#include "net/base/winsock_util.h"
23#include "net/udp/udp_net_log_parameters.h"
24
25namespace {
26
27const int kBindRetries = 10;
28const int kPortStart = 1024;
29const int kPortEnd = 65535;
30
31}  // namespace
32
33namespace net {
34
35// This class encapsulates all the state that has to be preserved as long as
36// there is a network IO operation in progress. If the owner UDPSocketWin
37// is destroyed while an operation is in progress, the Core is detached and it
38// lives until the operation completes and the OS doesn't reference any resource
39// declared on this class anymore.
40class UDPSocketWin::Core : public base::RefCounted<Core> {
41 public:
42  explicit Core(UDPSocketWin* socket);
43
44  // Start watching for the end of a read or write operation.
45  void WatchForRead();
46  void WatchForWrite();
47
48  // The UDPSocketWin is going away.
49  void Detach() { socket_ = NULL; }
50
51  // The separate OVERLAPPED variables for asynchronous operation.
52  OVERLAPPED read_overlapped_;
53  OVERLAPPED write_overlapped_;
54
55  // The buffers used in Read() and Write().
56  scoped_refptr<IOBuffer> read_iobuffer_;
57  scoped_refptr<IOBuffer> write_iobuffer_;
58
59  // The address storage passed to WSARecvFrom().
60  SockaddrStorage recv_addr_storage_;
61
62 private:
63  friend class base::RefCounted<Core>;
64
65  class ReadDelegate : public base::win::ObjectWatcher::Delegate {
66   public:
67    explicit ReadDelegate(Core* core) : core_(core) {}
68    virtual ~ReadDelegate() {}
69
70    // base::ObjectWatcher::Delegate methods:
71    virtual void OnObjectSignaled(HANDLE object);
72
73   private:
74    Core* const core_;
75  };
76
77  class WriteDelegate : public base::win::ObjectWatcher::Delegate {
78   public:
79    explicit WriteDelegate(Core* core) : core_(core) {}
80    virtual ~WriteDelegate() {}
81
82    // base::ObjectWatcher::Delegate methods:
83    virtual void OnObjectSignaled(HANDLE object);
84
85   private:
86    Core* const core_;
87  };
88
89  ~Core();
90
91  // The socket that created this object.
92  UDPSocketWin* socket_;
93
94  // |reader_| handles the signals from |read_watcher_|.
95  ReadDelegate reader_;
96  // |writer_| handles the signals from |write_watcher_|.
97  WriteDelegate writer_;
98
99  // |read_watcher_| watches for events from Read().
100  base::win::ObjectWatcher read_watcher_;
101  // |write_watcher_| watches for events from Write();
102  base::win::ObjectWatcher write_watcher_;
103
104  DISALLOW_COPY_AND_ASSIGN(Core);
105};
106
107UDPSocketWin::Core::Core(UDPSocketWin* socket)
108    : socket_(socket),
109      reader_(this),
110      writer_(this) {
111  memset(&read_overlapped_, 0, sizeof(read_overlapped_));
112  memset(&write_overlapped_, 0, sizeof(write_overlapped_));
113
114  read_overlapped_.hEvent = WSACreateEvent();
115  write_overlapped_.hEvent = WSACreateEvent();
116}
117
118UDPSocketWin::Core::~Core() {
119  // Make sure the message loop is not watching this object anymore.
120  read_watcher_.StopWatching();
121  write_watcher_.StopWatching();
122
123  WSACloseEvent(read_overlapped_.hEvent);
124  memset(&read_overlapped_, 0xaf, sizeof(read_overlapped_));
125  WSACloseEvent(write_overlapped_.hEvent);
126  memset(&write_overlapped_, 0xaf, sizeof(write_overlapped_));
127}
128
129void UDPSocketWin::Core::WatchForRead() {
130  // We grab an extra reference because there is an IO operation in progress.
131  // Balanced in ReadDelegate::OnObjectSignaled().
132  AddRef();
133  read_watcher_.StartWatching(read_overlapped_.hEvent, &reader_);
134}
135
136void UDPSocketWin::Core::WatchForWrite() {
137  // We grab an extra reference because there is an IO operation in progress.
138  // Balanced in WriteDelegate::OnObjectSignaled().
139  AddRef();
140  write_watcher_.StartWatching(write_overlapped_.hEvent, &writer_);
141}
142
143void UDPSocketWin::Core::ReadDelegate::OnObjectSignaled(HANDLE object) {
144  DCHECK_EQ(object, core_->read_overlapped_.hEvent);
145  if (core_->socket_)
146    core_->socket_->DidCompleteRead();
147
148  core_->Release();
149}
150
151void UDPSocketWin::Core::WriteDelegate::OnObjectSignaled(HANDLE object) {
152  DCHECK_EQ(object, core_->write_overlapped_.hEvent);
153  if (core_->socket_)
154    core_->socket_->DidCompleteWrite();
155
156  core_->Release();
157}
158
159//-----------------------------------------------------------------------------
160
161UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
162                           const RandIntCallback& rand_int_cb,
163                           net::NetLog* net_log,
164                           const net::NetLog::Source& source)
165    : socket_(INVALID_SOCKET),
166      addr_family_(0),
167      socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
168      multicast_time_to_live_(1),
169      bind_type_(bind_type),
170      rand_int_cb_(rand_int_cb),
171      recv_from_address_(NULL),
172      net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
173  EnsureWinsockInit();
174  net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
175                      source.ToEventParametersCallback());
176  if (bind_type == DatagramSocket::RANDOM_BIND)
177    DCHECK(!rand_int_cb.is_null());
178}
179
180UDPSocketWin::~UDPSocketWin() {
181  Close();
182  net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
183}
184
185void UDPSocketWin::Close() {
186  DCHECK(CalledOnValidThread());
187
188  if (!is_connected())
189    return;
190
191  // Zero out any pending read/write callback state.
192  read_callback_.Reset();
193  recv_from_address_ = NULL;
194  write_callback_.Reset();
195
196  base::TimeTicks start_time = base::TimeTicks::Now();
197  closesocket(socket_);
198  UMA_HISTOGRAM_TIMES("Net.UDPSocketWinClose",
199                      base::TimeTicks::Now() - start_time);
200  socket_ = INVALID_SOCKET;
201  addr_family_ = 0;
202
203  core_->Detach();
204  core_ = NULL;
205}
206
207int UDPSocketWin::GetPeerAddress(IPEndPoint* address) const {
208  DCHECK(CalledOnValidThread());
209  DCHECK(address);
210  if (!is_connected())
211    return ERR_SOCKET_NOT_CONNECTED;
212
213  // TODO(szym): Simplify. http://crbug.com/126152
214  if (!remote_address_.get()) {
215    SockaddrStorage storage;
216    if (getpeername(socket_, storage.addr, &storage.addr_len))
217      return MapSystemError(WSAGetLastError());
218    scoped_ptr<IPEndPoint> address(new IPEndPoint());
219    if (!address->FromSockAddr(storage.addr, storage.addr_len))
220      return ERR_ADDRESS_INVALID;
221    remote_address_.reset(address.release());
222  }
223
224  *address = *remote_address_;
225  return OK;
226}
227
228int UDPSocketWin::GetLocalAddress(IPEndPoint* address) const {
229  DCHECK(CalledOnValidThread());
230  DCHECK(address);
231  if (!is_connected())
232    return ERR_SOCKET_NOT_CONNECTED;
233
234  // TODO(szym): Simplify. http://crbug.com/126152
235  if (!local_address_.get()) {
236    SockaddrStorage storage;
237    if (getsockname(socket_, storage.addr, &storage.addr_len))
238      return MapSystemError(WSAGetLastError());
239    scoped_ptr<IPEndPoint> address(new IPEndPoint());
240    if (!address->FromSockAddr(storage.addr, storage.addr_len))
241      return ERR_ADDRESS_INVALID;
242    local_address_.reset(address.release());
243    net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
244                      CreateNetLogUDPConnectCallback(local_address_.get()));
245  }
246
247  *address = *local_address_;
248  return OK;
249}
250
251int UDPSocketWin::Read(IOBuffer* buf,
252                       int buf_len,
253                       const CompletionCallback& callback) {
254  return RecvFrom(buf, buf_len, NULL, callback);
255}
256
257int UDPSocketWin::RecvFrom(IOBuffer* buf,
258                           int buf_len,
259                           IPEndPoint* address,
260                           const CompletionCallback& callback) {
261  DCHECK(CalledOnValidThread());
262  DCHECK_NE(INVALID_SOCKET, socket_);
263  DCHECK(read_callback_.is_null());
264  DCHECK(!recv_from_address_);
265  DCHECK(!callback.is_null());  // Synchronous operation not supported.
266  DCHECK_GT(buf_len, 0);
267
268  int nread = InternalRecvFrom(buf, buf_len, address);
269  if (nread != ERR_IO_PENDING)
270    return nread;
271
272  read_callback_ = callback;
273  recv_from_address_ = address;
274  return ERR_IO_PENDING;
275}
276
277int UDPSocketWin::Write(IOBuffer* buf,
278                        int buf_len,
279                        const CompletionCallback& callback) {
280  return SendToOrWrite(buf, buf_len, NULL, callback);
281}
282
283int UDPSocketWin::SendTo(IOBuffer* buf,
284                         int buf_len,
285                         const IPEndPoint& address,
286                         const CompletionCallback& callback) {
287  return SendToOrWrite(buf, buf_len, &address, callback);
288}
289
290int UDPSocketWin::SendToOrWrite(IOBuffer* buf,
291                                int buf_len,
292                                const IPEndPoint* address,
293                                const CompletionCallback& callback) {
294  DCHECK(CalledOnValidThread());
295  DCHECK_NE(INVALID_SOCKET, socket_);
296  DCHECK(write_callback_.is_null());
297  DCHECK(!callback.is_null());  // Synchronous operation not supported.
298  DCHECK_GT(buf_len, 0);
299  DCHECK(!send_to_address_.get());
300
301  int nwrite = InternalSendTo(buf, buf_len, address);
302  if (nwrite != ERR_IO_PENDING)
303    return nwrite;
304
305  if (address)
306    send_to_address_.reset(new IPEndPoint(*address));
307  write_callback_ = callback;
308  return ERR_IO_PENDING;
309}
310
311int UDPSocketWin::Connect(const IPEndPoint& address) {
312  net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
313                      CreateNetLogUDPConnectCallback(&address));
314  int rv = InternalConnect(address);
315  if (rv != OK)
316    Close();
317  net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
318  return rv;
319}
320
321int UDPSocketWin::InternalConnect(const IPEndPoint& address) {
322  DCHECK(!is_connected());
323  DCHECK(!remote_address_.get());
324  int rv = CreateSocket(address);
325  if (rv < 0)
326    return rv;
327
328  if (bind_type_ == DatagramSocket::RANDOM_BIND)
329    rv = RandomBind(address);
330  // else connect() does the DatagramSocket::DEFAULT_BIND
331
332  if (rv < 0) {
333    Close();
334    return rv;
335  }
336
337  SockaddrStorage storage;
338  if (!address.ToSockAddr(storage.addr, &storage.addr_len))
339    return ERR_ADDRESS_INVALID;
340
341  rv = connect(socket_, storage.addr, storage.addr_len);
342  if (rv < 0) {
343    // Close() may change the last error. Map it beforehand.
344    int result = MapSystemError(WSAGetLastError());
345    Close();
346    return result;
347  }
348
349  remote_address_.reset(new IPEndPoint(address));
350  return rv;
351}
352
353int UDPSocketWin::Bind(const IPEndPoint& address) {
354  DCHECK(!is_connected());
355  int rv = CreateSocket(address);
356  if (rv < 0)
357    return rv;
358  rv = SetSocketOptions();
359  if (rv < 0) {
360    Close();
361    return rv;
362  }
363  rv = DoBind(address);
364  if (rv < 0) {
365    Close();
366    return rv;
367  }
368  local_address_.reset();
369  return rv;
370}
371
372int UDPSocketWin::CreateSocket(const IPEndPoint& address) {
373  addr_family_ = address.GetSockAddrFamily();
374  socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, IPPROTO_UDP);
375  if (socket_ == INVALID_SOCKET)
376    return MapSystemError(WSAGetLastError());
377  core_ = new Core(this);
378  return OK;
379}
380
381bool UDPSocketWin::SetReceiveBufferSize(int32 size) {
382  DCHECK(CalledOnValidThread());
383  int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
384                      reinterpret_cast<const char*>(&size), sizeof(size));
385  DCHECK(!rv) << "Could not set socket receive buffer size: " << errno;
386  return rv == 0;
387}
388
389bool UDPSocketWin::SetSendBufferSize(int32 size) {
390  DCHECK(CalledOnValidThread());
391  int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
392                      reinterpret_cast<const char*>(&size), sizeof(size));
393  DCHECK(!rv) << "Could not set socket send buffer size: " << errno;
394  return rv == 0;
395}
396
397void UDPSocketWin::AllowAddressReuse() {
398  DCHECK(CalledOnValidThread());
399  DCHECK(!is_connected());
400
401  socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
402}
403
404void UDPSocketWin::AllowBroadcast() {
405  DCHECK(CalledOnValidThread());
406  DCHECK(!is_connected());
407
408  socket_options_ |= SOCKET_OPTION_BROADCAST;
409}
410
411void UDPSocketWin::DoReadCallback(int rv) {
412  DCHECK_NE(rv, ERR_IO_PENDING);
413  DCHECK(!read_callback_.is_null());
414
415  // since Run may result in Read being called, clear read_callback_ up front.
416  CompletionCallback c = read_callback_;
417  read_callback_.Reset();
418  c.Run(rv);
419}
420
421void UDPSocketWin::DoWriteCallback(int rv) {
422  DCHECK_NE(rv, ERR_IO_PENDING);
423  DCHECK(!write_callback_.is_null());
424
425  // since Run may result in Write being called, clear write_callback_ up front.
426  CompletionCallback c = write_callback_;
427  write_callback_.Reset();
428  c.Run(rv);
429}
430
431void UDPSocketWin::DidCompleteRead() {
432  DWORD num_bytes, flags;
433  BOOL ok = WSAGetOverlappedResult(socket_, &core_->read_overlapped_,
434                                   &num_bytes, FALSE, &flags);
435  WSAResetEvent(core_->read_overlapped_.hEvent);
436  int result = ok ? num_bytes : MapSystemError(WSAGetLastError());
437  // Convert address.
438  if (recv_from_address_ && result >= 0) {
439    if (!ReceiveAddressToIPEndpoint(recv_from_address_))
440      result = ERR_ADDRESS_INVALID;
441  }
442  LogRead(result, core_->read_iobuffer_->data());
443  core_->read_iobuffer_ = NULL;
444  recv_from_address_ = NULL;
445  DoReadCallback(result);
446}
447
448void UDPSocketWin::LogRead(int result, const char* bytes) const {
449  if (result < 0) {
450    net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
451    return;
452  }
453
454  if (net_log_.IsLoggingAllEvents()) {
455    // Get address for logging, if |address| is NULL.
456    IPEndPoint address;
457    bool is_address_valid = ReceiveAddressToIPEndpoint(&address);
458    net_log_.AddEvent(
459        NetLog::TYPE_UDP_BYTES_RECEIVED,
460        CreateNetLogUDPDataTranferCallback(
461            result, bytes,
462            is_address_valid ? &address : NULL));
463  }
464
465  base::StatsCounter read_bytes("udp.read_bytes");
466  read_bytes.Add(result);
467}
468
469void UDPSocketWin::DidCompleteWrite() {
470  DWORD num_bytes, flags;
471  BOOL ok = WSAGetOverlappedResult(socket_, &core_->write_overlapped_,
472                                   &num_bytes, FALSE, &flags);
473  WSAResetEvent(core_->write_overlapped_.hEvent);
474  int result = ok ? num_bytes : MapSystemError(WSAGetLastError());
475  LogWrite(result, core_->write_iobuffer_->data(), send_to_address_.get());
476
477  send_to_address_.reset();
478  core_->write_iobuffer_ = NULL;
479  DoWriteCallback(result);
480}
481
482void UDPSocketWin::LogWrite(int result,
483                            const char* bytes,
484                            const IPEndPoint* address) const {
485  if (result < 0) {
486    net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
487    return;
488  }
489
490  if (net_log_.IsLoggingAllEvents()) {
491    net_log_.AddEvent(
492        NetLog::TYPE_UDP_BYTES_SENT,
493        CreateNetLogUDPDataTranferCallback(result, bytes, address));
494  }
495
496  base::StatsCounter write_bytes("udp.write_bytes");
497  write_bytes.Add(result);
498}
499
500int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
501                                   IPEndPoint* address) {
502  DCHECK(!core_->read_iobuffer_);
503  SockaddrStorage& storage = core_->recv_addr_storage_;
504  storage.addr_len = sizeof(storage.addr_storage);
505
506  WSABUF read_buffer;
507  read_buffer.buf = buf->data();
508  read_buffer.len = buf_len;
509
510  DWORD flags = 0;
511  DWORD num;
512  CHECK_NE(INVALID_SOCKET, socket_);
513  AssertEventNotSignaled(core_->read_overlapped_.hEvent);
514  int rv = WSARecvFrom(socket_, &read_buffer, 1, &num, &flags, storage.addr,
515                       &storage.addr_len, &core_->read_overlapped_, NULL);
516  if (rv == 0) {
517    if (ResetEventIfSignaled(core_->read_overlapped_.hEvent)) {
518      int result = num;
519      // Convert address.
520      if (address && result >= 0) {
521        if (!ReceiveAddressToIPEndpoint(address))
522          result = ERR_FAILED;
523      }
524      LogRead(result, buf->data());
525      return result;
526    }
527  } else {
528    int os_error = WSAGetLastError();
529    if (os_error != WSA_IO_PENDING) {
530      int result = MapSystemError(os_error);
531      LogRead(result, NULL);
532      return result;
533    }
534  }
535  core_->WatchForRead();
536  core_->read_iobuffer_ = buf;
537  return ERR_IO_PENDING;
538}
539
540int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
541                                 const IPEndPoint* address) {
542  DCHECK(!core_->write_iobuffer_);
543  SockaddrStorage storage;
544  struct sockaddr* addr = storage.addr;
545  // Convert address.
546  if (!address) {
547    addr = NULL;
548    storage.addr_len = 0;
549  } else {
550    if (!address->ToSockAddr(addr, &storage.addr_len)) {
551      int result = ERR_FAILED;
552      LogWrite(result, NULL, NULL);
553      return result;
554    }
555  }
556
557  WSABUF write_buffer;
558  write_buffer.buf = buf->data();
559  write_buffer.len = buf_len;
560
561  DWORD flags = 0;
562  DWORD num;
563  AssertEventNotSignaled(core_->write_overlapped_.hEvent);
564  int rv = WSASendTo(socket_, &write_buffer, 1, &num, flags,
565                     addr, storage.addr_len, &core_->write_overlapped_, NULL);
566  if (rv == 0) {
567    if (ResetEventIfSignaled(core_->write_overlapped_.hEvent)) {
568      int result = num;
569      LogWrite(result, buf->data(), address);
570      return result;
571    }
572  } else {
573    int os_error = WSAGetLastError();
574    if (os_error != WSA_IO_PENDING) {
575      int result = MapSystemError(os_error);
576      LogWrite(result, NULL, NULL);
577      return result;
578    }
579  }
580
581  core_->WatchForWrite();
582  core_->write_iobuffer_ = buf;
583  return ERR_IO_PENDING;
584}
585
586int UDPSocketWin::SetSocketOptions() {
587  BOOL true_value = 1;
588  if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
589    int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
590                        reinterpret_cast<const char*>(&true_value),
591                        sizeof(true_value));
592    if (rv < 0)
593      return MapSystemError(WSAGetLastError());
594  }
595  if (socket_options_ & SOCKET_OPTION_BROADCAST) {
596    int rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST,
597                        reinterpret_cast<const char*>(&true_value),
598                        sizeof(true_value));
599    if (rv < 0)
600      return MapSystemError(WSAGetLastError());
601  }
602  if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
603    DWORD loop = 0;
604    int protocol_level =
605        addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
606    int option =
607        addr_family_ == AF_INET ? IP_MULTICAST_LOOP: IPV6_MULTICAST_LOOP;
608    int rv = setsockopt(socket_, protocol_level, option,
609                        reinterpret_cast<const char*>(&loop), sizeof(loop));
610    if (rv < 0)
611      return MapSystemError(WSAGetLastError());
612  }
613  if (multicast_time_to_live_ != 1) {
614    DWORD hops = multicast_time_to_live_;
615    int protocol_level =
616        addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
617    int option =
618        addr_family_ == AF_INET ? IP_MULTICAST_TTL: IPV6_MULTICAST_HOPS;
619    int rv = setsockopt(socket_, protocol_level, option,
620                        reinterpret_cast<const char*>(&hops), sizeof(hops));
621    if (rv < 0)
622      return MapSystemError(WSAGetLastError());
623  }
624  return OK;
625}
626
627int UDPSocketWin::DoBind(const IPEndPoint& address) {
628  SockaddrStorage storage;
629  if (!address.ToSockAddr(storage.addr, &storage.addr_len))
630    return ERR_ADDRESS_INVALID;
631  int rv = bind(socket_, storage.addr, storage.addr_len);
632  return rv < 0 ? MapSystemError(WSAGetLastError()) : rv;
633}
634
635int UDPSocketWin::RandomBind(const IPEndPoint& address) {
636  DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
637
638  // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s.
639  IPAddressNumber ip(address.address().size());
640
641  for (int i = 0; i < kBindRetries; ++i) {
642    int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd)));
643    if (rv == OK || rv != ERR_ADDRESS_IN_USE)
644      return rv;
645  }
646  return DoBind(IPEndPoint(ip, 0));
647}
648
649bool UDPSocketWin::ReceiveAddressToIPEndpoint(IPEndPoint* address) const {
650  SockaddrStorage& storage = core_->recv_addr_storage_;
651  return address->FromSockAddr(storage.addr, storage.addr_len);
652}
653
654int UDPSocketWin::JoinGroup(
655    const IPAddressNumber& group_address) const {
656  DCHECK(CalledOnValidThread());
657  if (!is_connected())
658    return ERR_SOCKET_NOT_CONNECTED;
659
660  switch (group_address.size()) {
661    case kIPv4AddressSize: {
662      if (addr_family_ != AF_INET)
663        return ERR_ADDRESS_INVALID;
664      ip_mreq mreq;
665      mreq.imr_interface.s_addr = INADDR_ANY;
666      memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
667      int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
668                          reinterpret_cast<const char*>(&mreq),
669                          sizeof(mreq));
670      if (rv)
671        return MapSystemError(WSAGetLastError());
672      return OK;
673    }
674    case kIPv6AddressSize: {
675      if (addr_family_ != AF_INET6)
676        return ERR_ADDRESS_INVALID;
677      ipv6_mreq mreq;
678      mreq.ipv6mr_interface = 0;  // 0 indicates default multicast interface.
679      memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
680      int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
681                          reinterpret_cast<const char*>(&mreq),
682                          sizeof(mreq));
683      if (rv)
684        return MapSystemError(WSAGetLastError());
685      return OK;
686    }
687    default:
688      NOTREACHED() << "Invalid address family";
689      return ERR_ADDRESS_INVALID;
690  }
691}
692
693int UDPSocketWin::LeaveGroup(
694    const IPAddressNumber& group_address) const {
695  DCHECK(CalledOnValidThread());
696  if (!is_connected())
697    return ERR_SOCKET_NOT_CONNECTED;
698
699  switch (group_address.size()) {
700    case kIPv4AddressSize: {
701      if (addr_family_ != AF_INET)
702        return ERR_ADDRESS_INVALID;
703      ip_mreq mreq;
704      mreq.imr_interface.s_addr = INADDR_ANY;
705      memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
706      int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
707                      reinterpret_cast<const char*>(&mreq),
708                      sizeof(mreq));
709      if (rv)
710        return MapSystemError(WSAGetLastError());
711      return OK;
712    }
713    case kIPv6AddressSize: {
714      if (addr_family_ != AF_INET6)
715        return ERR_ADDRESS_INVALID;
716      ipv6_mreq mreq;
717      mreq.ipv6mr_interface = 0;  // 0 indicates default multicast interface.
718      memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
719      int rv = setsockopt(socket_, IPPROTO_IPV6, IP_DROP_MEMBERSHIP,
720                      reinterpret_cast<const char*>(&mreq),
721                      sizeof(mreq));
722      if (rv)
723        return MapSystemError(WSAGetLastError());
724      return OK;
725    }
726    default:
727      NOTREACHED() << "Invalid address family";
728      return ERR_ADDRESS_INVALID;
729  }
730}
731
732int UDPSocketWin::SetMulticastTimeToLive(int time_to_live) {
733  DCHECK(CalledOnValidThread());
734  if (is_connected())
735    return ERR_SOCKET_IS_CONNECTED;
736
737  if (time_to_live < 0 || time_to_live > 255)
738    return ERR_INVALID_ARGUMENT;
739  multicast_time_to_live_ = time_to_live;
740  return OK;
741}
742
743int UDPSocketWin::SetMulticastLoopbackMode(bool loopback) {
744  DCHECK(CalledOnValidThread());
745  if (is_connected())
746    return ERR_SOCKET_IS_CONNECTED;
747
748  if (loopback)
749    socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
750  else
751    socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
752  return OK;
753}
754
755}  // namespace net
756