blob: 3e5e2b07124602c6a0bc2e84632f54c0e491e434 [file] [log] [blame]
// Copyright (c) 2012 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/dial/dial_udp_socket_factory.h"
#if !defined(OS_STARBOARD)
#include <arpa/inet.h>
#endif
#include "base/logging.h"
#include "net/base/net_util.h"
#include "net/base/ip_endpoint.h"
#include "net/udp/udp_listen_socket.h"
#if defined(OS_STARBOARD)
#include "starboard/socket.h"
#endif
namespace net {
namespace { // anonymous
// static methods
#if defined(OS_POSIX)
SocketDescriptor NativeCreateUdpSocket(int family) {
return ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}
bool NativeBind(const SocketDescriptor s, const IPEndPoint& address) {
SockaddrStorage addr;
if (!address.ToSockAddr(addr.addr, &addr.addr_len)) {
LOG(ERROR) << "Failed to resolve IPEndPoint. " << address.ToString();
return false;
}
if (0 != ::bind(s, addr.addr, addr.addr_len)) {
PLOG(ERROR) << "Failed to bind address: " << address.ToString();
return false;
}
return true;
}
#elif defined(OS_STARBOARD)
SocketDescriptor NativeCreateUdpSocket(int family) {
return SbSocketCreate(kSbSocketAddressTypeIpv4, kSbSocketProtocolUdp);
}
bool NativeBind(const SocketDescriptor s, const IPEndPoint& address) {
SbSocketAddress sb_address;
if (!address.ToSbSocketAddress(&sb_address)) {
DLOG(ERROR) << "Failed to convert address: " << address.ToString();
return false;
}
SbSocketError error = SbSocketBind(s, &sb_address);
if (error != kSbSocketOk) {
DLOG(ERROR) << "Failed to bind address: " << address.ToString();
return false;
}
return true;
}
#endif
} // anonymous namespace
scoped_refptr<UDPListenSocket> UdpSocketFactory::CreateAndBind(
const IPEndPoint& address, UDPListenSocket::Delegate* del) {
SocketDescriptor s = NativeCreateUdpSocket(address.GetFamily());
if (s == UDPListenSocket::kInvalidSocket)
return NULL;
SetupSocketAfterCreate(s);
if (!NativeBind(s, address))
return NULL;
SetupSocketAfterBind(s);
scoped_refptr<UDPListenSocket> sock(new UDPListenSocket(s, del));
return sock;
}
void DialUdpSocketFactory::SetupSocketAfterCreate(SocketDescriptor s) {
#if defined(OS_STARBOARD)
if (!SbSocketSetReuseAddress(s, true)) {
LOG(WARNING) << "SbSocketSetReuseAddress failed on DIAL UDP socket.";
}
#elif defined(SO_REUSEADDR)
int on = 1;
if (::setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
LOG(WARNING) << "Failed to set SO_REUSEADDR on dial UDP socket.";
}
#else
NOTIMPLEMENTED() << "Cannot SO_REUSEADDR on this platform.";
#endif
SetNonBlocking(s);
}
// Enable Multicast and join group if multicast is enabled.
void DialUdpSocketFactory::SetupSocketAfterBind(SocketDescriptor s) {
#if defined(OS_STARBOARD)
SbSocketAddress address = {0};
address.type = kSbSocketAddressTypeIpv4;
address.address[0] = 239;
address.address[1] = 255;
address.address[2] = 255;
address.address[3] = 250;
if (!SbSocketJoinMulticastGroup(s, &address)) {
LOG(WARNING) << "SbSocketJoinMulticastGroup failed on DIAL UDP socket.";
}
#elif defined(IP_ADD_MEMBERSHIP)
struct ip_mreq imreq;
imreq.imr_multiaddr.s_addr = ::inet_addr("239.255.255.250");
imreq.imr_interface.s_addr = INADDR_ANY;
if (::setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(imreq)) < 0) {
LOG(WARNING) << "Failed to join multicast group on dial UDP socket.";
}
#else
NOTIMPLEMENTED() << "No Multicast support on this platform.";
#endif
}
} // namespace net