Index: runtime/bin/socket.h |
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h |
index d4e0c6aead0de713cd0fdf0d89e4d99b5734138d..7b8a03df6f01026ecc83f5c179d4a53b40ded8f3 100644 |
--- a/runtime/bin/socket.h |
+++ b/runtime/bin/socket.h |
@@ -9,10 +9,25 @@ |
#error "socket.h can only be included on builds with IO enabled" |
#endif |
+#include "platform/globals.h" |
+// Declare the OS-specific types ahead of defining the generic class. |
+#if defined(HOST_OS_ANDROID) |
+#include "bin/socket_android.h" |
+#elif defined(HOST_OS_FUCHSIA) |
+#include "bin/socket_fuchsia.h" |
+#elif defined(HOST_OS_LINUX) |
+#include "bin/socket_linux.h" |
+#elif defined(HOST_OS_MACOS) |
+#include "bin/socket_macos.h" |
+#elif defined(HOST_OS_WINDOWS) |
+#include "bin/socket_win.h" |
+#else |
+#error Unknown target os. |
+#endif |
+ |
#include "bin/builtin.h" |
#include "bin/dartutils.h" |
#include "bin/reference_counting.h" |
-#include "bin/socket_base.h" |
#include "bin/thread.h" |
#include "bin/utils.h" |
#include "platform/hashmap.h" |
@@ -20,8 +35,218 @@ |
namespace dart { |
namespace bin { |
-// TODO(bkonyi): Socket should also inherit from SocketBase once it is |
-// refactored to use instance methods when possible. |
+union RawAddr { |
+ struct sockaddr_in in; |
+ struct sockaddr_in6 in6; |
+ struct sockaddr_storage ss; |
+ struct sockaddr addr; |
+}; |
+ |
+class SocketAddress { |
+ public: |
+ enum { |
+ TYPE_ANY = -1, |
+ TYPE_IPV4, |
+ TYPE_IPV6, |
+ }; |
+ |
+ enum { |
+ ADDRESS_LOOPBACK_IP_V4, |
+ ADDRESS_LOOPBACK_IP_V6, |
+ ADDRESS_ANY_IP_V4, |
+ ADDRESS_ANY_IP_V6, |
+ ADDRESS_FIRST = ADDRESS_LOOPBACK_IP_V4, |
+ ADDRESS_LAST = ADDRESS_ANY_IP_V6, |
+ }; |
+ |
+ explicit SocketAddress(struct sockaddr* sa); |
+ |
+ ~SocketAddress() {} |
+ |
+ int GetType() { |
+ if (addr_.ss.ss_family == AF_INET6) { |
+ return TYPE_IPV6; |
+ } |
+ return TYPE_IPV4; |
+ } |
+ |
+ const char* as_string() const { return as_string_; } |
+ const RawAddr& addr() const { return addr_; } |
+ |
+ static intptr_t GetAddrLength(const RawAddr& addr) { |
+ ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6)); |
+ return (addr.ss.ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) |
+ : sizeof(struct sockaddr_in); |
+ } |
+ |
+ static intptr_t GetInAddrLength(const RawAddr& addr) { |
+ ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6)); |
+ return (addr.ss.ss_family == AF_INET6) ? sizeof(struct in6_addr) |
+ : sizeof(struct in_addr); |
+ } |
+ |
+ static bool AreAddressesEqual(const RawAddr& a, const RawAddr& b) { |
+ if (a.ss.ss_family == AF_INET) { |
+ if (b.ss.ss_family != AF_INET) { |
+ return false; |
+ } |
+ return memcmp(&a.in.sin_addr, &b.in.sin_addr, sizeof(a.in.sin_addr)) == 0; |
+ } else if (a.ss.ss_family == AF_INET6) { |
+ if (b.ss.ss_family != AF_INET6) { |
+ return false; |
+ } |
+ return memcmp(&a.in6.sin6_addr, &b.in6.sin6_addr, |
+ sizeof(a.in6.sin6_addr)) == 0; |
+ } else { |
+ UNREACHABLE(); |
+ return false; |
+ } |
+ } |
+ |
+ static void GetSockAddr(Dart_Handle obj, RawAddr* addr) { |
+ Dart_TypedData_Type data_type; |
+ uint8_t* data = NULL; |
+ intptr_t len; |
+ Dart_Handle result = Dart_TypedDataAcquireData( |
+ obj, &data_type, reinterpret_cast<void**>(&data), &len); |
+ if (Dart_IsError(result)) { |
+ Dart_PropagateError(result); |
+ } |
+ if ((data_type != Dart_TypedData_kUint8) || |
+ ((len != sizeof(in_addr)) && (len != sizeof(in6_addr)))) { |
+ Dart_PropagateError( |
+ Dart_NewApiError("Unexpected type for socket address")); |
+ } |
+ memset(reinterpret_cast<void*>(addr), 0, sizeof(RawAddr)); |
+ if (len == sizeof(in_addr)) { |
+ addr->in.sin_family = AF_INET; |
+ memmove(reinterpret_cast<void*>(&addr->in.sin_addr), data, len); |
+ } else { |
+ ASSERT(len == sizeof(in6_addr)); |
+ addr->in6.sin6_family = AF_INET6; |
+ memmove(reinterpret_cast<void*>(&addr->in6.sin6_addr), data, len); |
+ } |
+ Dart_TypedDataReleaseData(obj); |
+ } |
+ |
+ static int16_t FromType(int type) { |
+ if (type == TYPE_ANY) { |
+ return AF_UNSPEC; |
+ } |
+ if (type == TYPE_IPV4) { |
+ return AF_INET; |
+ } |
+ ASSERT((type == TYPE_IPV6) && "Invalid type"); |
+ return AF_INET6; |
+ } |
+ |
+ static void SetAddrPort(RawAddr* addr, intptr_t port) { |
+ if (addr->ss.ss_family == AF_INET) { |
+ addr->in.sin_port = htons(port); |
+ } else { |
+ addr->in6.sin6_port = htons(port); |
+ } |
+ } |
+ |
+ static intptr_t GetAddrPort(const RawAddr& addr) { |
+ if (addr.ss.ss_family == AF_INET) { |
+ return ntohs(addr.in.sin_port); |
+ } else { |
+ return ntohs(addr.in6.sin6_port); |
+ } |
+ } |
+ |
+ static Dart_Handle ToTypedData(const RawAddr& addr) { |
+ int len = GetInAddrLength(addr); |
+ Dart_Handle result = Dart_NewTypedData(Dart_TypedData_kUint8, len); |
+ if (Dart_IsError(result)) { |
+ Dart_PropagateError(result); |
+ } |
+ Dart_Handle err; |
+ if (addr.addr.sa_family == AF_INET6) { |
+ err = Dart_ListSetAsBytes( |
+ result, 0, reinterpret_cast<const uint8_t*>(&addr.in6.sin6_addr), |
+ len); |
+ } else { |
+ err = Dart_ListSetAsBytes( |
+ result, 0, reinterpret_cast<const uint8_t*>(&addr.in.sin_addr), len); |
+ } |
+ if (Dart_IsError(err)) { |
+ Dart_PropagateError(err); |
+ } |
+ return result; |
+ } |
+ |
+ static CObjectUint8Array* ToCObject(const RawAddr& addr) { |
+ int in_addr_len = SocketAddress::GetInAddrLength(addr); |
+ const void* in_addr; |
+ CObjectUint8Array* data = |
+ new CObjectUint8Array(CObject::NewUint8Array(in_addr_len)); |
+ if (addr.addr.sa_family == AF_INET6) { |
+ in_addr = reinterpret_cast<const void*>(&addr.in6.sin6_addr); |
+ } else { |
+ in_addr = reinterpret_cast<const void*>(&addr.in.sin_addr); |
+ } |
+ memmove(data->Buffer(), in_addr, in_addr_len); |
+ return data; |
+ } |
+ |
+ private: |
+ char as_string_[INET6_ADDRSTRLEN]; |
+ RawAddr addr_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SocketAddress); |
+}; |
+ |
+ |
+class InterfaceSocketAddress { |
+ public: |
+ InterfaceSocketAddress(struct sockaddr* sa, |
+ const char* interface_name, |
+ intptr_t interface_index) |
+ : socket_address_(new SocketAddress(sa)), |
+ interface_name_(interface_name), |
+ interface_index_(interface_index) {} |
+ |
+ ~InterfaceSocketAddress() { delete socket_address_; } |
+ |
+ SocketAddress* socket_address() const { return socket_address_; } |
+ const char* interface_name() const { return interface_name_; } |
+ int interface_index() const { return interface_index_; } |
+ |
+ private: |
+ SocketAddress* socket_address_; |
+ const char* interface_name_; |
+ intptr_t interface_index_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(InterfaceSocketAddress); |
+}; |
+ |
+ |
+template <typename T> |
+class AddressList { |
+ public: |
+ explicit AddressList(intptr_t count) |
+ : count_(count), addresses_(new T*[count_]) {} |
+ |
+ ~AddressList() { |
+ for (intptr_t i = 0; i < count_; i++) { |
+ delete addresses_[i]; |
+ } |
+ delete[] addresses_; |
+ } |
+ |
+ intptr_t count() const { return count_; } |
+ T* GetAt(intptr_t i) const { return addresses_[i]; } |
+ void SetAt(intptr_t i, T* addr) { addresses_[i] = addr; } |
+ |
+ private: |
+ const intptr_t count_; |
+ T** addresses_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AddressList); |
+}; |
+ |
// We write Sockets into the native field of the _NativeSocket object |
// on the Dart side. They are allocated in SetSocketIdNativeField(), and are |
@@ -43,8 +268,22 @@ class Socket : public ReferenceCounted<Socket> { |
Dart_Port port() const { return port_; } |
void set_port(Dart_Port port) { port_ = port; } |
+ // TODO(dart:io): Convert these to instance methods where possible. |
static bool Initialize(); |
- |
+ static intptr_t Available(intptr_t fd); |
+ static intptr_t Read(intptr_t fd, void* buffer, intptr_t num_bytes); |
+ static intptr_t Write(intptr_t fd, const void* buffer, intptr_t num_bytes); |
+ // Send data on a socket. The port to send to is specified in the port |
+ // component of the passed RawAddr structure. The RawAddr structure is only |
+ // used for datagram sockets. |
+ static intptr_t SendTo(intptr_t fd, |
+ const void* buffer, |
+ intptr_t num_bytes, |
+ const RawAddr& addr); |
+ static intptr_t RecvFrom(intptr_t fd, |
+ void* buffer, |
+ intptr_t num_bytes, |
+ RawAddr* addr); |
// Creates a socket which is bound and connected. The port to connect to is |
// specified as the port component of the passed RawAddr structure. |
static intptr_t CreateConnect(const RawAddr& addr); |
@@ -52,9 +291,55 @@ class Socket : public ReferenceCounted<Socket> { |
// specified as the port component of the passed RawAddr structure. |
static intptr_t CreateBindConnect(const RawAddr& addr, |
const RawAddr& source_addr); |
+ // Returns true if the given error-number is because the system was not able |
+ // to bind the socket to a specific IP. |
+ static bool IsBindError(intptr_t error_number); |
// Creates a datagram socket which is bound. The port to bind |
// to is specified as the port component of the RawAddr structure. |
static intptr_t CreateBindDatagram(const RawAddr& addr, bool reuseAddress); |
+ static intptr_t GetPort(intptr_t fd); |
+ static SocketAddress* GetRemotePeer(intptr_t fd, intptr_t* port); |
+ static void GetError(intptr_t fd, OSError* os_error); |
+ static int GetType(intptr_t fd); |
+ static intptr_t GetStdioHandle(intptr_t num); |
+ static void Close(intptr_t fd); |
+ static bool GetNoDelay(intptr_t fd, bool* enabled); |
+ static bool SetNoDelay(intptr_t fd, bool enabled); |
+ static bool GetMulticastLoop(intptr_t fd, intptr_t protocol, bool* enabled); |
+ static bool SetMulticastLoop(intptr_t fd, intptr_t protocol, bool enabled); |
+ static bool GetMulticastHops(intptr_t fd, intptr_t protocol, int* value); |
+ static bool SetMulticastHops(intptr_t fd, intptr_t protocol, int value); |
+ static bool GetBroadcast(intptr_t fd, bool* value); |
+ static bool SetBroadcast(intptr_t fd, bool value); |
+ static bool JoinMulticast(intptr_t fd, |
+ const RawAddr& addr, |
+ const RawAddr& interface, |
+ int interfaceIndex); |
+ static bool LeaveMulticast(intptr_t fd, |
+ const RawAddr& addr, |
+ const RawAddr& interface, |
+ int interfaceIndex); |
+ |
+ // Perform a hostname lookup. Returns a AddressList of SocketAddress's. |
+ static AddressList<SocketAddress>* LookupAddress(const char* host, |
+ int type, |
+ OSError** os_error); |
+ |
+ static bool ReverseLookup(const RawAddr& addr, |
+ char* host, |
+ intptr_t host_len, |
+ OSError** os_error); |
+ |
+ static bool ParseAddress(int type, const char* address, RawAddr* addr); |
+ static bool FormatNumericAddress(const RawAddr& addr, char* address, int len); |
+ |
+ // Whether ListInterfaces is supported. |
+ static bool ListInterfacesSupported(); |
+ |
+ // List interfaces. Returns a AddressList of InterfaceSocketAddress's. |
+ static AddressList<InterfaceSocketAddress>* ListInterfaces( |
+ int type, |
+ OSError** os_error); |
static CObject* LookupRequest(const CObjectArray& request); |
static CObject* ListInterfacesRequest(const CObjectArray& request); |