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 a6c1b72b50ac651c8a711c568c042e0d9ddcd504..85032cede648fdbc4868b1cbe3505a2c5a590b3e 100644 |
| --- a/net/udp/udp_socket_libevent.cc |
| +++ b/net/udp/udp_socket_libevent.cc |
| @@ -6,8 +6,8 @@ |
| #include <errno.h> |
| #include <fcntl.h> |
| -#include <netdb.h> |
| #include <net/if.h> |
| +#include <netdb.h> |
| #include <netinet/in.h> |
| #include <sys/ioctl.h> |
| #include <sys/socket.h> |
| @@ -28,6 +28,12 @@ |
| #include "net/socket/socket_descriptor.h" |
| #include "net/udp/udp_net_log_parameters.h" |
| +#if defined(OS_MACOSX) |
| +// 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) |
| namespace net { |
| @@ -56,6 +62,66 @@ int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){ |
| return OK; |
| } |
| +// On OSX the file descriptor is guarded to detect the cause of |
| +// crbug.com/461246. sys/guarded.h is not included in the SDK, so the API needs |
| +// to be defined here. |
| +// 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); |
| + |
| +void* g_libsystem_handle = nullptr; |
|
Mark Mentovai
2015/04/02 18:21:57
This is only used in InitGuardedFunctions, make it
Sergey Ulanov
2015/04/02 18:28:19
Done. It doesn't need to be static.
|
| +GuardedCloseNpFunction g_guarded_close_np = nullptr; |
| +ChangeFdguardNpFunction g_change_fdguard_np = nullptr; |
| + |
| +static pthread_once_t g_guarded_functions_once = PTHREAD_ONCE_INIT; |
|
Mark Mentovai
2015/04/02 18:21:57
You’re in an unnamed namespace, you shouldn’t have
Sergey Ulanov
2015/04/02 18:28:18
Done.
|
| + |
| +static void InitGuardedFunctions() { |
| + g_libsystem_handle = dlopen("/usr/lib/libSystem.dylib", 0); |
|
Mark Mentovai
2015/04/02 18:21:57
Use RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD, not 0.
Sergey Ulanov
2015/04/02 18:28:18
Done.
|
| + if (g_libsystem_handle) { |
| + g_guarded_close_np = reinterpret_cast<GuardedCloseNpFunction>( |
| + dlsym(g_libsystem_handle, "guarded_close_np")); |
| + g_change_fdguard_np = reinterpret_cast<ChangeFdguardNpFunction>( |
| + dlsym(g_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 // OS_MACOSX |
| } // namespace |
| @@ -98,6 +164,10 @@ int UDPSocketLibevent::Open(AddressFamily address_family) { |
| socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); |
| if (socket_ == kInvalidSocket) |
| return MapSystemError(errno); |
| +#if defined(OS_MACOSX) |
| + 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 +197,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; |