-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnet_poll_tool.cc
105 lines (87 loc) · 2.93 KB
/
net_poll_tool.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <errno.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sysexits.h>
#include <time.h>
#include <unistd.h>
#include <base/files/file_path.h>
#include <base/files/scoped_file.h>
#include <base/logging.h>
#include <brillo/flag_helper.h>
#include <brillo/syslog_logging.h>
namespace {
// A flag for the busy loops below to check.
volatile bool timedout = false;
void SigalarmHandler(int sig) {
timedout = true;
}
// Sleep for a very short period of time. We want the kernel to schedule
// something else (hopefully whatever we're waiting for) before coming back.
void Yield(const std::string& desc) {
const struct timespec ts = {
.tv_sec = 0,
.tv_nsec = 1000 * 1000, // 1 millisecond.
};
nanosleep(&ts, nullptr);
if (timedout) {
LOG(ERROR) << "Request timed out: " << desc;
exit(EX_UNAVAILABLE);
}
}
// Poll a UNIX socket until it's usable.
bool PollUnixSocket(const base::FilePath& path) {
base::ScopedFD s(
socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
if (!s.is_valid()) {
PLOG(ERROR) << "Could not create a UNIX socket";
return false;
}
struct sockaddr_un sa;
// We want > here and not >= as Linux supports a path that is not explicitly
// NUL terminated if the path fills the entire buffer.
if (path.value().length() > sizeof(sa.sun_path)) {
LOG(ERROR) << "Path is too long for a UNIX socket: " << path.value();
return false;
}
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
// The memset above took care of NUL terminating, and we already verified
// the length before that.
memcpy(sa.sun_path, path.value().data(), path.value().length());
while (connect(s.get(), reinterpret_cast<struct sockaddr*>(&sa),
sizeof(sa)) == -1) {
if (errno != ECONNREFUSED && errno != ENOENT && errno != EAGAIN) {
PLOG(ERROR) << "connect(" << path.value() << ") failed";
return false;
}
Yield(path.value());
}
return true;
}
} // namespace
int main(int argc, char* argv[]) {
DEFINE_int32(timeout, 0, "How many seconds to wait (0 for forever)");
DEFINE_string(unix_socket, "", "Path to a UNIX socket");
brillo::FlagHelper::Init(argc, argv, "Chromium OS Network Poller");
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty);
// Check for conflicting options.
if (FLAGS_unix_socket.empty()) {
LOG(ERROR) << "Missing socket to poll; please see --help";
return EX_USAGE;
}
// Do the actual polling now.
if (FLAGS_timeout > 0) {
signal(SIGALRM, SigalarmHandler);
alarm(FLAGS_timeout);
}
if (!FLAGS_unix_socket.empty()) {
base::FilePath unix_socket(FLAGS_unix_socket);
return PollUnixSocket(unix_socket) ? EX_OK : 1;
}
NOTREACHED() << "Parsing logic error";
}