mukesh agrawal | ec533e0 | 2016-09-30 19:04:33 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <algorithm> |
mukesh agrawal | 960c8a8 | 2016-10-27 17:39:18 -0700 | [diff] [blame] | 18 | #include <cerrno> |
mukesh agrawal | ec533e0 | 2016-09-30 19:04:33 -0700 | [diff] [blame] | 19 | #include <cstdint> |
mukesh agrawal | 960c8a8 | 2016-10-27 17:39:18 -0700 | [diff] [blame] | 20 | #include <cstring> |
mukesh agrawal | ec533e0 | 2016-09-30 19:04:33 -0700 | [diff] [blame] | 21 | |
| 22 | #include "android-base/logging.h" |
| 23 | |
| 24 | #include "wifilogd/local_utils.h" |
| 25 | #include "wifilogd/os.h" |
| 26 | |
| 27 | namespace android { |
| 28 | namespace wifilogd { |
| 29 | |
| 30 | using local_utils::GetMaxVal; |
| 31 | |
| 32 | namespace { |
| 33 | constexpr auto kMaxNanoSeconds = 1000 * 1000 * 1000 - 1; |
| 34 | } |
| 35 | |
mukesh agrawal | a5bb08c | 2016-10-26 14:38:52 -0700 | [diff] [blame] | 36 | constexpr int Os::kInvalidFd; |
| 37 | |
mukesh agrawal | ec533e0 | 2016-09-30 19:04:33 -0700 | [diff] [blame] | 38 | Os::Os() : raw_os_(new RawOs()) {} |
| 39 | Os::Os(std::unique_ptr<RawOs> raw_os) : raw_os_(std::move(raw_os)) {} |
| 40 | Os::~Os() {} |
| 41 | |
mukesh agrawal | a5bb08c | 2016-10-26 14:38:52 -0700 | [diff] [blame] | 42 | std::tuple<int, Os::Errno> Os::GetControlSocket( |
| 43 | const std::string& socket_name) { |
| 44 | int sock_fd = raw_os_->GetControlSocket(socket_name.c_str()); |
| 45 | if (sock_fd < 0) { |
| 46 | return {kInvalidFd, errno}; |
| 47 | } else { |
| 48 | return {sock_fd, 0}; |
| 49 | } |
| 50 | } |
| 51 | |
mukesh agrawal | ec533e0 | 2016-09-30 19:04:33 -0700 | [diff] [blame] | 52 | Os::Timestamp Os::GetTimestamp(clockid_t clock_id) const { |
| 53 | struct timespec now_timespec; |
| 54 | int failed = raw_os_->ClockGettime(clock_id, &now_timespec); |
| 55 | if (failed) { |
| 56 | LOG(FATAL) << "Unexpected error: " << std::strerror(errno); |
| 57 | } |
| 58 | CHECK(now_timespec.tv_nsec <= kMaxNanoSeconds); |
| 59 | |
| 60 | Timestamp now_timestamp; |
| 61 | now_timestamp.secs = SAFELY_CLAMP( |
| 62 | now_timespec.tv_sec, uint32_t, 0, |
| 63 | // The upper-bound comes from the source-type on 32-bit platforms, |
| 64 | // and the dest-type on 64-bit platforms. Using min(), we can figure out |
| 65 | // which type to use for the upper bound, without resorting to macros. |
| 66 | std::min(static_cast<uintmax_t>(GetMaxVal(now_timestamp.secs)), |
| 67 | static_cast<uintmax_t>(GetMaxVal(now_timespec.tv_sec)))); |
| 68 | now_timestamp.nsecs = |
| 69 | SAFELY_CLAMP(now_timespec.tv_nsec, uint32_t, 0, kMaxNanoSeconds); |
| 70 | return now_timestamp; |
| 71 | } |
| 72 | |
mukesh agrawal | 960c8a8 | 2016-10-27 17:39:18 -0700 | [diff] [blame] | 73 | void Os::Nanosleep(uint32_t sleep_time_nsec) { |
| 74 | struct timespec sleep_timespec = { |
| 75 | 0, // tv_sec |
| 76 | SAFELY_CLAMP(sleep_time_nsec, decltype(timespec::tv_nsec), 0, kMaxNanos)}; |
| 77 | |
| 78 | int failed = 0; |
| 79 | do { |
| 80 | struct timespec remaining_timespec; |
| 81 | failed = raw_os_->Nanosleep(&sleep_timespec, &remaining_timespec); |
| 82 | sleep_timespec = remaining_timespec; |
| 83 | } while (failed && errno == EINTR && sleep_timespec.tv_nsec > 0); |
| 84 | |
| 85 | if (failed && errno != EINTR) { |
| 86 | // The only other documented errors for the underlying nanosleep() call are |
| 87 | // EFAULT and EINVAL. But we always pass valid pointers, and the values in |
| 88 | // |sleep_timespec| are always valid. |
| 89 | LOG(FATAL) << "Unexpected error: " << std::strerror(errno); |
| 90 | } |
| 91 | } |
| 92 | |
mukesh agrawal | d75fd9e | 2016-10-26 16:34:04 -0700 | [diff] [blame] | 93 | std::tuple<size_t, Os::Errno> Os::ReceiveDatagram(int fd, void* buf, |
| 94 | size_t buflen) { |
| 95 | // recv() takes a size_t, but returns an ssize_t. That means that the largest |
| 96 | // successful read that recv() can report is the maximal ssize_t. Passing a |
| 97 | // larger |buflen| risks mistakenly reporting a truncated read. |
| 98 | CHECK(buflen <= GetMaxVal<ssize_t>()); |
| 99 | |
| 100 | const ssize_t res = raw_os_->Recv(fd, buf, buflen, MSG_TRUNC); |
| 101 | if (res < 0) { |
| 102 | return {0, errno}; |
| 103 | } |
| 104 | |
| 105 | // Due to the MSG_TRUNC flag, |res| may reasonably be larger than |
| 106 | // |buflen|. In such cases, |res| indicates the full size of the datagram, |
| 107 | // before being truncated to fit our buffer. Hence, we omit the |
| 108 | // buffer-overflow CHECK that exists in Write(). |
| 109 | return {res, 0}; |
| 110 | } |
| 111 | |
mukesh agrawal | b8f8f6a | 2016-10-06 15:11:59 -0700 | [diff] [blame] | 112 | std::tuple<size_t, Os::Errno> Os::Write(int fd, const void* buf, |
| 113 | size_t buflen) { |
| 114 | // write() takes a size_t, but returns an ssize_t. That means that the |
| 115 | // largest successful write that write() can report is the maximal ssize_t. |
| 116 | // Passing a larger |buflen| risks mistakenly reporting a truncated write. |
| 117 | CHECK(buflen <= GetMaxVal<ssize_t>()); |
| 118 | |
| 119 | const ssize_t res = raw_os_->Write(fd, buf, buflen); |
| 120 | if (res < 0) { |
| 121 | return {0, errno}; |
| 122 | } |
| 123 | |
| 124 | CHECK(res <= |
| 125 | SAFELY_CLAMP(buflen, ssize_t, 0, |
| 126 | GetMaxVal<ssize_t>())); // Abort on buffer overflow. |
| 127 | |
| 128 | // Note that |res| may be less than buflen. However, a) a short write is |
| 129 | // not an error, and b) |errno| may be stale, as |errno| is only guaranteed to |
| 130 | // be set if an error occurred. Hence, we return Errno of 0 unconditionally. |
| 131 | // See http://yarchive.net/comp/linux/write_error_return.html |
| 132 | return {res, 0}; |
| 133 | } |
| 134 | |
mukesh agrawal | ec533e0 | 2016-09-30 19:04:33 -0700 | [diff] [blame] | 135 | } // namespace wifilogd |
| 136 | } // namespace android |