| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2010 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 "chrome/browser/sync/notifier/base/async_network_alive.h" |
| 6 |
| 7 #include <sys/socket.h> |
| 8 #include <asm/types.h> |
| 9 #include <linux/netlink.h> |
| 10 #include <linux/rtnetlink.h> |
| 11 |
| 12 #include "base/logging.h" |
| 13 #include "talk/base/physicalsocketserver.h" |
| 14 |
| 15 namespace notifier { |
| 16 |
| 17 class AsyncNetworkAliveLinux : public AsyncNetworkAlive { |
| 18 public: |
| 19 AsyncNetworkAliveLinux() { |
| 20 if (pipe(exit_pipe_) == -1) { |
| 21 PLOG(ERROR) << "Could not create pipe for exit signal."; |
| 22 exit_pipe_[0] = 0; |
| 23 exit_pipe_[1] = 0; |
| 24 } |
| 25 } |
| 26 |
| 27 virtual ~AsyncNetworkAliveLinux() { |
| 28 if (exit_pipe_[1]) { |
| 29 close(exit_pipe_[1]); |
| 30 } |
| 31 } |
| 32 |
| 33 protected: |
| 34 // SignalThread Interface |
| 35 virtual void DoWork() { |
| 36 if (!exit_pipe_[0]) { |
| 37 // If we don't have an exit flag to listen for, set the error flag and |
| 38 // abort. |
| 39 error_ = true; |
| 40 return; |
| 41 } |
| 42 |
| 43 // This function listens for changes to network interfaces, and link state. |
| 44 // It's copied from syncapi.cc. |
| 45 struct sockaddr_nl socket_address; |
| 46 |
| 47 memset(&socket_address, 0, sizeof(socket_address)); |
| 48 socket_address.nl_family = AF_NETLINK; |
| 49 socket_address.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; |
| 50 |
| 51 // NETLINK_ROUTE is the protocol used to update the kernel routing table. |
| 52 int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); |
| 53 bind(fd, (struct sockaddr *) &socket_address, sizeof(socket_address)); |
| 54 |
| 55 fd_set rdfs; |
| 56 FD_ZERO(&rdfs); |
| 57 FD_SET(fd, &rdfs); |
| 58 FD_SET(exit_pipe_[0], &rdfs); |
| 59 |
| 60 int max_fd = fd > exit_pipe_[0] ? fd : exit_pipe_[0]; |
| 61 |
| 62 int result = select(max_fd + 1, &rdfs, NULL, NULL, NULL); |
| 63 |
| 64 if (result <= 0) { |
| 65 error_ = true; |
| 66 PLOG(ERROR) << "select() returned unexpected result " << result; |
| 67 close(fd); |
| 68 close(exit_pipe_[0]); |
| 69 return; |
| 70 } |
| 71 |
| 72 // Since we recieved a change from the socket, read the change in. |
| 73 if (FD_ISSET(fd, &rdfs)) { |
| 74 char buf[4096]; |
| 75 struct iovec iov = { buf, sizeof(buf) }; |
| 76 struct sockaddr_nl sa; |
| 77 |
| 78 struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 }; |
| 79 recvmsg(fd, &msg, 0); |
| 80 } |
| 81 |
| 82 close(fd); |
| 83 |
| 84 // If exit_pipe was written to, we must be shutting down. |
| 85 if (FD_ISSET(exit_pipe_[0], &rdfs)) { |
| 86 alive_ = false; |
| 87 error_ = true; |
| 88 close(exit_pipe_[0]); |
| 89 return; |
| 90 } |
| 91 |
| 92 // If there is an active connection, check that talk.google.com:5222 |
| 93 // is reachable. |
| 94 talk_base::PhysicalSocketServer physical; |
| 95 scoped_ptr<talk_base::Socket> socket(physical.CreateSocket(SOCK_STREAM)); |
| 96 if (socket->Connect(talk_base::SocketAddress("talk.google.com", 5222))) { |
| 97 alive_ = false; |
| 98 } else { |
| 99 alive_ = true; |
| 100 } |
| 101 } |
| 102 |
| 103 virtual void OnWorkStop() { |
| 104 if (exit_pipe_[1]) { |
| 105 char data = 0; |
| 106 // We can't ignore the return value on write(), since that generates a |
| 107 // compile warning. However, since we're exiting, there's nothing we can |
| 108 // do if this fails except to log it. |
| 109 if (write(exit_pipe_[1], &data, 1) == -1) { |
| 110 PLOG(WARNING) << "Error sending error signal to AsyncNetworkAliveLinux"; |
| 111 } |
| 112 } |
| 113 } |
| 114 |
| 115 private: |
| 116 int exit_pipe_[2]; |
| 117 DISALLOW_COPY_AND_ASSIGN(AsyncNetworkAliveLinux); |
| 118 }; |
| 119 |
| 120 AsyncNetworkAlive* AsyncNetworkAlive::Create() { |
| 121 return new AsyncNetworkAliveLinux(); |
| 122 } |
| 123 |
| 124 } // namespace notifier |
| OLD | NEW |