// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "platform/globals.h" #if defined(DART_HOST_OS_MACOS) #include "bin/socket_base.h" #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include "bin/fdutils.h" #include "bin/file.h" #include "bin/socket_base_macos.h" #include "platform/signal_blocker.h" namespace dart { namespace bin { void SocketBase::GetError(intptr_t fd, OSError* os_error) { int len = sizeof(errno); getsockopt(fd, SOL_SOCKET, SO_ERROR, &errno, reinterpret_cast(&len)); os_error->SetCodeAndMessage(OSError::kSystem, errno); } int SocketBase::GetType(intptr_t fd) { struct stat buf; int result = fstat(fd, &buf); if (result == -1) { return -1; } if (S_ISCHR(buf.st_mode)) { return File::kTerminal; } if (S_ISFIFO(buf.st_mode)) { return File::kPipe; } if (S_ISREG(buf.st_mode)) { return File::kFile; } return File::kOther; } AddressList* SocketBase::LookupAddress(const char* host, int type, OSError** os_error) { // Perform a name lookup for a host name. struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = SocketAddress::FromType(type); hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = IPPROTO_TCP; struct addrinfo* info = nullptr; int status = getaddrinfo(host, nullptr, &hints, &info); if (status != 0) { ASSERT(*os_error == nullptr); *os_error = new OSError(status, gai_strerror(status), OSError::kGetAddressInfo); return nullptr; } intptr_t count = 0; for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) { if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { count++; } } intptr_t i = 0; AddressList* addresses = new AddressList(count); for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) { if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { addresses->SetAt(i, new SocketAddress(RawAddr::FromInet4or6(c->ai_addr))); i++; } } freeaddrinfo(info); return addresses; } bool SocketBase::SetMulticastLoop(intptr_t fd, intptr_t protocol, bool enabled) { u_int on = enabled ? 1 : 0; int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP; return NO_RETRY_EXPECTED(setsockopt( fd, level, optname, reinterpret_cast(&on), sizeof(on))) == 0; } bool SocketBase::GetOption(intptr_t fd, int level, int option, char* data, unsigned int* length) { return NO_RETRY_EXPECTED(getsockopt(fd, level, option, data, length)) == 0; } static bool JoinOrLeaveMulticast(intptr_t fd, const RawAddr& addr, const RawAddr& interface, int interfaceIndex, bool join) { if (addr.addr.sa_family == AF_INET) { ASSERT(interface.addr.sa_family == AF_INET); struct ip_mreq mreq; memmove(&mreq.imr_multiaddr, &addr.in.sin_addr, SocketAddress::GetInAddrLength(addr)); memmove(&mreq.imr_interface, &interface.in.sin_addr, SocketAddress::GetInAddrLength(interface)); if (join) { return NO_RETRY_EXPECTED(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) == 0; } else { return NO_RETRY_EXPECTED(setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq))) == 0; } } else { ASSERT(addr.addr.sa_family == AF_INET6); struct ipv6_mreq mreq; memmove(&mreq.ipv6mr_multiaddr, &addr.in6.sin6_addr, SocketAddress::GetInAddrLength(addr)); mreq.ipv6mr_interface = interfaceIndex; if (join) { return NO_RETRY_EXPECTED(setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq))) == 0; } else { return NO_RETRY_EXPECTED(setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq))) == 0; } } } bool SocketBase::JoinMulticast(intptr_t fd, const RawAddr& addr, const RawAddr& interface, int interfaceIndex) { return JoinOrLeaveMulticast(fd, addr, interface, interfaceIndex, true); } bool SocketBase::LeaveMulticast(intptr_t fd, const RawAddr& addr, const RawAddr& interface, int interfaceIndex) { return JoinOrLeaveMulticast(fd, addr, interface, interfaceIndex, false); } } // namespace bin } // namespace dart #endif // defined(DART_HOST_OS_MACOS)