blob: d58cd4a119f14d264b1586890d6b689aca9a6d50 [file] [log] [blame]
// Copyright 2017 The Fuchsia 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 "garnet/bin/mdns/service/mdns_interface_transceiver_v6.h"
#include <arpa/inet.h>
#include <errno.h>
#include <sys/socket.h>
#include "garnet/bin/mdns/service/mdns_addresses.h"
#include "src/lib/fxl/logging.h"
namespace mdns {
MdnsInterfaceTransceiverV6::MdnsInterfaceTransceiverV6(inet::IpAddress address,
const std::string& name,
uint32_t index)
: MdnsInterfaceTransceiver(address, name, index) {}
MdnsInterfaceTransceiverV6::~MdnsInterfaceTransceiverV6() {}
int MdnsInterfaceTransceiverV6::SetOptionDisableMulticastLoop() {
char param = 0;
int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
&param, sizeof(param));
if (result < 0) {
if (errno == ENOPROTOOPT) {
FXL_LOG(WARNING) << "NET-291 IPV6_MULTICAST_LOOP not supported "
"(ENOPROTOOPT), continuing anyway";
result = 0;
} else {
FXL_LOG(ERROR) << "Failed to set socket option IPV6_MULTICAST_LOOP, "
<< strerror(errno);
}
}
return result;
}
int MdnsInterfaceTransceiverV6::SetOptionJoinMulticastGroup() {
ipv6_mreq param;
param.ipv6mr_multiaddr =
MdnsAddresses::V6Multicast(mdns_port()).as_sockaddr_in6().sin6_addr;
param.ipv6mr_interface = index();
int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_JOIN_GROUP,
&param, sizeof(param));
if (result < 0) {
if (errno == ENODEV) {
FXL_LOG(WARNING) << "NET-2180 IPV6_JOIN_GROUP returned ENODEV, mDNS will "
"not communicate via IPV6";
} else {
FXL_LOG(ERROR) << "Failed to set socket option IPV6_JOIN_GROUP, "
<< strerror(errno);
}
}
return result;
}
int MdnsInterfaceTransceiverV6::SetOptionOutboundInterface() {
uint32_t index = this->index();
int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_MULTICAST_IF,
&index, sizeof(index));
if (result < 0) {
if (errno == EOPNOTSUPP) {
FXL_LOG(WARNING) << "NET-1901 IPV6_MULTICAST_IF not supported "
"(EOPNOTSUPP), continuing anyway";
result = 0;
} else {
FXL_LOG(ERROR) << "Failed to set socket option IPV6_MULTICAST_IF, "
<< strerror(errno);
}
}
return result;
}
int MdnsInterfaceTransceiverV6::SetOptionUnicastTtl() {
int param = kTimeToLive_;
int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_UNICAST_HOPS,
&param, sizeof(param));
if (result < 0) {
FXL_LOG(ERROR) << "Failed to set socket option IPV6_UNICAST_HOPS, "
<< strerror(errno);
}
return result;
}
int MdnsInterfaceTransceiverV6::SetOptionMulticastTtl() {
int param = kTimeToLive_;
int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
&param, sizeof(param));
if (result < 0) {
FXL_LOG(ERROR) << "Failed to set socket option IPV6_MULTICAST_HOPS, "
<< strerror(errno);
}
return result;
}
int MdnsInterfaceTransceiverV6::SetOptionFamilySpecific() {
// Set hop limit.
int param = 1;
int result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_HOPLIMIT,
&param, sizeof(param));
if (result < 0) {
FXL_LOG(ERROR) << "Failed to set socket option IPV6_HOPLIMIT, "
<< strerror(errno);
return result;
}
// Receive V6 packets only.
param = 1;
result = setsockopt(socket_fd().get(), IPPROTO_IPV6, IPV6_V6ONLY, &param,
sizeof(param));
if (result < 0) {
FXL_LOG(ERROR) << "Failed to set socket option IPV6_V6ONLY, "
<< strerror(errno);
return false;
}
return result;
}
int MdnsInterfaceTransceiverV6::Bind() {
int result =
bind(socket_fd().get(), MdnsAddresses::V6Bind(mdns_port()).as_sockaddr(),
MdnsAddresses::V6Bind(mdns_port()).socklen());
if (result < 0) {
FXL_LOG(ERROR) << "Failed to bind socket to V6 address, "
<< strerror(errno);
}
return result;
}
int MdnsInterfaceTransceiverV6::SendTo(const void* buffer, size_t size,
const inet::SocketAddress& address) {
if (address == MdnsAddresses::V4Multicast(mdns_port())) {
return sendto(socket_fd().get(), buffer, size, 0,
MdnsAddresses::V6Multicast(mdns_port()).as_sockaddr(),
MdnsAddresses::V6Multicast(mdns_port()).socklen());
}
return sendto(socket_fd().get(), buffer, size, 0, address.as_sockaddr(),
address.socklen());
}
} // namespace mdns