1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/dns/notify_watcher_mac.h"
6
7#include <notify.h>
8
9#include "base/logging.h"
10#include "base/posix/eintr_wrapper.h"
11
12namespace net {
13
14NotifyWatcherMac::NotifyWatcherMac() : notify_fd_(-1), notify_token_(-1) {}
15
16NotifyWatcherMac::~NotifyWatcherMac() {
17  Cancel();
18}
19
20bool NotifyWatcherMac::Watch(const char* key, const CallbackType& callback) {
21  DCHECK(key);
22  DCHECK(!callback.is_null());
23  Cancel();
24  uint32_t status = notify_register_file_descriptor(
25      key, &notify_fd_, 0, &notify_token_);
26  if (status != NOTIFY_STATUS_OK)
27    return false;
28  DCHECK_GE(notify_fd_, 0);
29  if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
30          notify_fd_,
31          true,
32          base::MessageLoopForIO::WATCH_READ,
33          &watcher_,
34          this)) {
35    Cancel();
36    return false;
37  }
38  callback_ = callback;
39  return true;
40}
41
42void NotifyWatcherMac::Cancel() {
43  if (notify_fd_ >= 0) {
44    notify_cancel(notify_token_);  // Also closes |notify_fd_|.
45    notify_fd_ = -1;
46    callback_.Reset();
47    watcher_.StopWatchingFileDescriptor();
48  }
49}
50
51void NotifyWatcherMac::OnFileCanReadWithoutBlocking(int fd) {
52  int token;
53  int status = HANDLE_EINTR(read(notify_fd_, &token, sizeof(token)));
54  if (status != sizeof(token)) {
55    Cancel();
56    callback_.Run(false);
57    return;
58  }
59  // Ignoring |token| value to avoid possible endianness mismatch:
60  // http://openradar.appspot.com/8821081
61  callback_.Run(true);
62}
63
64}  // namespace net
65