Chromium Code Reviews| Index: net/udp/udp_socket_libevent.cc |
| diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc |
| index 9dc5c95e46d57e26f4e960cb8a34449e0d0ff003..25986c2ab571939d7687606c81e635017329054b 100644 |
| --- a/net/udp/udp_socket_libevent.cc |
| +++ b/net/udp/udp_socket_libevent.cc |
| @@ -28,6 +28,12 @@ |
| #include "net/socket/socket_descriptor.h" |
| #include "net/udp/udp_net_log_parameters.h" |
| +#if defined(OS_MACOSX) && !defined(OS_IOS) |
| +// Needed temporarily to debug crbug.com/461246. |
| +// TODO(sergeyu): Remove once the bug is resolved. |
| +#include <dlfcn.h> |
| +#include <pthread.h> |
| +#endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| namespace net { |
| @@ -58,6 +64,74 @@ int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){ |
| #endif // OS_MACOSX |
| +#ifdef defined(OS_MACOSX) && !defined(OS_IOS) |
| + |
| +// On OSX the file descriptor is guarded to detect the cause of |
| +// crbug.com/461246. guarded API is supported only on newer versions of OSX, |
| +// so the symbols need to be resolved dynamically. |
| +// TODO(sergeyu): Removed this code once the bug is resolved. |
| + |
| +typedef uint64_t guardid_t; |
| + |
| +typedef int (*GuardedCloseNpFunction)(int fd, const guardid_t* guard); |
| +typedef int (*ChangeFdguardNpFunction)(int fd, |
| + const guardid_t* guard, |
| + u_int flags, |
| + const guardid_t* nguard, |
| + u_int nflags, |
| + int* fdflagsp); |
| + |
| +GuardedCloseNpFunction g_guarded_close_np = nullptr; |
| +ChangeFdguardNpFunction g_change_fdguard_np = nullptr; |
| + |
| +pthread_once_t g_guarded_functions_once = PTHREAD_ONCE_INIT; |
| + |
| +void InitGuardedFunctions() { |
| + void* libsystem_handle = |
| + dlopen("/usr/lib/libSystem.dylib", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); |
| + if (libsystem_handle) { |
| + g_guarded_close_np = reinterpret_cast<GuardedCloseNpFunction>( |
| + dlsym(libsystem_handle, "guarded_close_np")); |
| + g_change_fdguard_np = reinterpret_cast<ChangeFdguardNpFunction>( |
| + dlsym(libsystem_handle, "change_fdguard_np")); |
| + |
| + // If for any reason only one of the functions is found, set both of them to |
| + // nullptr. |
| + if (!g_guarded_close_np || !g_change_fdguard_np) { |
| + g_guarded_close_np = nullptr; |
| + g_change_fdguard_np = nullptr; |
| + } |
| + } |
| +} |
| + |
| +int change_fdguard_np(int fd, |
| + const guardid_t* guard, |
| + u_int flags, |
| + const guardid_t* nguard, |
| + u_int nflags, |
| + int* fdflagsp) { |
| + CHECK_EQ(pthread_once(&g_guarded_functions_once, InitGuardedFunctions), 0); |
| + // Older version of OSX may not support guarded API. |
| + if (!g_change_fdguard_np) |
| + return 0; |
| + return g_change_fdguard_np(fd, guard, flags, nguard, nflags, fdflagsp); |
| +} |
| + |
| +int guarded_close_np(int fd, const guardid_t* guard) { |
| + // Older version of OSX may not support guarded API. |
| + if (!g_guarded_close_np) |
| + return close(fd); |
| + |
| + return g_guarded_close_np(fd, guard); |
| +} |
| + |
| +const unsigned int GUARD_CLOSE = 1u << 0; |
| +const unsigned int GUARD_DUP = 1u << 1; |
| + |
| +const guardid_t kSocketFdGuard = 0xD712BC0BC9A4EAD4; |
| + |
| +#endif // defined(OS_MACOSX) && !defined(OS_IOS) |
| + |
| } // namespace |
| UDPSocketLibevent::UDPSocketLibevent( |
| @@ -98,6 +172,10 @@ int UDPSocketLibevent::Open(AddressFamily address_family) { |
| socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); |
| if (socket_ == kInvalidSocket) |
| return MapSystemError(errno); |
| +#if defined(OS_MACOSX) |
|
Mark Mentovai
2015/04/02 21:00:57
&& !defined(OS_IOS) here and on line 208 too?
|
| + PCHECK(change_fdguard_np(socket_, NULL, 0, &kSocketFdGuard, |
| + GUARD_CLOSE | GUARD_DUP, NULL) == 0); |
| +#endif // OS_MACOSX |
| if (SetNonBlocking(socket_)) { |
| const int err = MapSystemError(errno); |
| Close(); |
| @@ -127,7 +205,11 @@ void UDPSocketLibevent::Close() { |
| ok = write_socket_watcher_.StopWatchingFileDescriptor(); |
| DCHECK(ok); |
| +#if defined(OS_MACOSX) |
| + PCHECK(IGNORE_EINTR(guarded_close_np(socket_, &kSocketFdGuard)) == 0); |
| +#else |
| PCHECK(IGNORE_EINTR(close(socket_)) == 0); |
| +#endif // OS_MACOSX |
| socket_ = kInvalidSocket; |
| addr_family_ = 0; |