Merge "wifi(vts): Set the iface up as a part of setup"
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
index 8aa1d6b..ee2e92b 100644
--- a/automotive/can/1.0/default/Android.bp
+++ b/automotive/can/1.0/default/Android.bp
@@ -39,6 +39,7 @@
"CanBus.cpp",
"CanBusNative.cpp",
"CanBusVirtual.cpp",
+ "CanBusSlcan.cpp",
"CanController.cpp",
"CanSocket.cpp",
"CloseHandle.cpp",
diff --git a/automotive/can/1.0/default/CanBus.cpp b/automotive/can/1.0/default/CanBus.cpp
index 38a9974..42d2e3c 100644
--- a/automotive/can/1.0/default/CanBus.cpp
+++ b/automotive/can/1.0/default/CanBus.cpp
@@ -30,9 +30,7 @@
namespace V1_0 {
namespace implementation {
-/**
- * Whether to log sent/received packets.
- */
+/** Whether to log sent/received packets. */
static constexpr bool kSuperVerbose = false;
Return<Result> CanBus::send(const CanMessage& message) {
@@ -85,6 +83,8 @@
return {};
}
+CanBus::CanBus() {}
+
CanBus::CanBus(const std::string& ifname) : mIfname(ifname) {}
CanBus::~CanBus() {
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
index 30a2924..365e90c 100644
--- a/automotive/can/1.0/default/CanBus.h
+++ b/automotive/can/1.0/default/CanBus.h
@@ -48,12 +48,22 @@
bool down();
protected:
+ /**
+ * Blank constructor, since some interface types (such as SLCAN) don't get a name until after
+ * being initialized.
+ *
+ * If using this constructor, you MUST initialize mIfname prior to the completion of preUp().
+ */
+ CanBus();
+
CanBus(const std::string& ifname);
/**
* Prepare the SocketCAN interface.
*
* After calling this method, mIfname network interface is available and ready to be brought up.
+ *
+ * \return OK on success, or an error state on failure. See ICanController::Result
*/
virtual ICanController::Result preUp();
@@ -61,11 +71,13 @@
* Cleanup after bringing the interface down.
*
* This is a counterpart to preUp().
+ *
+ * \return true upon success and false upon failure
*/
virtual bool postDown();
/** Network interface name. */
- const std::string mIfname;
+ std::string mIfname;
private:
struct CanMessageListener {
diff --git a/automotive/can/1.0/default/CanBusSlcan.cpp b/automotive/can/1.0/default/CanBusSlcan.cpp
new file mode 100644
index 0000000..7dce838
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanBusSlcan.h"
+
+#include <android-base/logging.h>
+#include <libnetdevice/can.h>
+#include <libnetdevice/libnetdevice.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <termios.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+namespace slcanprotocol {
+static const std::string kOpenCommand = "O\r";
+static const std::string kCloseCommand = "C\r";
+static constexpr int kSlcanDiscipline = N_SLCAN;
+static constexpr int kDefaultDiscipline = N_TTY;
+
+static const std::map<uint32_t, std::string> kBitrateCommands = {
+ {10000, "C\rS0\r"}, {20000, "C\rS1\r"}, {50000, "C\rS2\r"},
+ {100000, "C\rS3\r"}, {125000, "C\rS4\r"}, {250000, "C\rS5\r"},
+ {500000, "C\rS6\r"}, {800000, "C\rS7\r"}, {1000000, "C\rS8\r"}};
+} // namespace slcanprotocol
+
+/**
+ * Serial Line CAN constructor
+ * \param string uartName - name of slcan device (e.x. /dev/ttyUSB0)
+ * \param uint32_t bitrate - speed of the CAN bus (125k = MSCAN, 500k = HSCAN)
+ */
+CanBusSlcan::CanBusSlcan(const std::string& uartName, uint32_t bitrate)
+ : CanBus(), mUartName(uartName), kBitrate(bitrate) {}
+
+ICanController::Result CanBusSlcan::preUp() {
+ // verify valid bitrate and translate to serial command format
+ const auto lookupIt = slcanprotocol::kBitrateCommands.find(kBitrate);
+ if (lookupIt == slcanprotocol::kBitrateCommands.end()) {
+ return ICanController::Result::BAD_BAUDRATE;
+ }
+ const auto canBitrateCommand = lookupIt->second;
+
+ /* Attempt to open the uart in r/w without blocking or becoming the
+ * controlling terminal */
+ mFd = base::unique_fd(open(mUartName.c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY));
+ if (!mFd.ok()) {
+ LOG(ERROR) << "SLCAN Failed to open " << mUartName << ": " << strerror(errno);
+ return ICanController::Result::BAD_ADDRESS;
+ }
+
+ // blank terminal settings and pull them from the device
+ struct termios terminalSettings = {};
+ if (tcgetattr(mFd.get(), &terminalSettings) < 0) {
+ LOG(ERROR) << "Failed to read attrs of" << mUartName << ": " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // change settings to raw mode
+ cfmakeraw(&terminalSettings);
+
+ // disable software flow control
+ terminalSettings.c_iflag &= ~IXOFF;
+ // enable hardware flow control
+ terminalSettings.c_cflag |= CRTSCTS;
+
+ struct serial_struct serialSettings;
+ // get serial settings
+ if (ioctl(mFd.get(), TIOCGSERIAL, &serialSettings) < 0) {
+ LOG(ERROR) << "Failed to read serial settings from " << mUartName << ": "
+ << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+ // set low latency mode
+ serialSettings.flags |= ASYNC_LOW_LATENCY;
+ // apply serial settings
+ if (ioctl(mFd.get(), TIOCSSERIAL, &serialSettings) < 0) {
+ LOG(ERROR) << "Failed to set low latency mode on " << mUartName << ": " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ /* TCSADRAIN applies settings after we finish writing the rest of our
+ * changes (as opposed to TCSANOW, which changes immediately) */
+ if (tcsetattr(mFd.get(), TCSADRAIN, &terminalSettings) < 0) {
+ LOG(ERROR) << "Failed to apply terminal settings to " << mUartName << ": "
+ << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // apply speed setting for CAN
+ if (write(mFd.get(), canBitrateCommand.c_str(), canBitrateCommand.length()) <= 0) {
+ LOG(ERROR) << "Failed to apply CAN bitrate: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // set open flag TODO: also support listen only
+ if (write(mFd.get(), slcanprotocol::kOpenCommand.c_str(),
+ slcanprotocol::kOpenCommand.length()) <= 0) {
+ LOG(ERROR) << "Failed to set open flag: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // set line discipline to slcan
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kSlcanDiscipline) < 0) {
+ LOG(ERROR) << "Failed to set line discipline to slcan: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // get the name of the device we created
+ struct ifreq ifrequest = {};
+ if (ioctl(mFd.get(), SIOCGIFNAME, ifrequest.ifr_name) < 0) {
+ LOG(ERROR) << "Failed to get the name of the created device: " << strerror(errno);
+ return ICanController::Result::UNKNOWN_ERROR;
+ }
+
+ // Update the CanBus object with name that was assigned to it
+ mIfname = ifrequest.ifr_name;
+
+ return ICanController::Result::OK;
+}
+
+bool CanBusSlcan::postDown() {
+ // reset the line discipline to TTY mode
+ if (ioctl(mFd.get(), TIOCSETD, &slcanprotocol::kDefaultDiscipline) < 0) {
+ LOG(ERROR) << "Failed to reset line discipline!";
+ return false;
+ }
+
+ // issue the close command
+ if (write(mFd.get(), slcanprotocol::kCloseCommand.c_str(),
+ slcanprotocol::kCloseCommand.length()) <= 0) {
+ LOG(ERROR) << "Failed to close tty!";
+ return false;
+ }
+
+ // close our unique_fd
+ mFd.reset();
+
+ return true;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace can
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/can/1.0/default/CanBusSlcan.h b/automotive/can/1.0/default/CanBusSlcan.h
new file mode 100644
index 0000000..2713da8
--- /dev/null
+++ b/automotive/can/1.0/default/CanBusSlcan.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <net/if.h>
+#include <termios.h>
+#include "CanBus.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace can {
+namespace V1_0 {
+namespace implementation {
+
+struct CanBusSlcan : public CanBus {
+ CanBusSlcan(const std::string& uartName, uint32_t bitrate);
+
+ protected:
+ virtual ICanController::Result preUp() override;
+ virtual bool postDown() override;
+
+ private:
+ const std::string mUartName;
+ const uint32_t kBitrate;
+ base::unique_fd mFd;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace can
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
index 3b63fe4..ffdc912 100644
--- a/automotive/can/1.0/default/CanController.cpp
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -17,6 +17,7 @@
#include "CanController.h"
#include "CanBusNative.h"
+#include "CanBusSlcan.h"
#include "CanBusVirtual.h"
#include <android-base/logging.h>
@@ -34,10 +35,8 @@
using IfaceIdDisc = ICanController::BusConfiguration::InterfaceIdentifier::hidl_discriminator;
Return<void> CanController::getSupportedInterfaceTypes(getSupportedInterfaceTypes_cb _hidl_cb) {
- _hidl_cb({
- ICanController::InterfaceType::VIRTUAL,
- ICanController::InterfaceType::SOCKETCAN,
- });
+ _hidl_cb({ICanController::InterfaceType::VIRTUAL, ICanController::InterfaceType::SOCKETCAN,
+ ICanController::InterfaceType::SLCAN});
return {};
}
@@ -77,6 +76,12 @@
} else {
return ICanController::Result::BAD_ADDRESS;
}
+ } else if (config.iftype == ICanController::InterfaceType::SLCAN) {
+ if (config.interfaceId.getDiscriminator() == IfaceIdDisc::address) {
+ busService = new CanBusSlcan(config.interfaceId.address(), config.baudrate);
+ } else {
+ return ICanController::Result::BAD_ADDRESS;
+ }
} else {
return ICanController::Result::NOT_SUPPORTED;
}
diff --git a/automotive/can/1.0/default/CanSocket.cpp b/automotive/can/1.0/default/CanSocket.cpp
index ecf4044..86e12d1 100644
--- a/automotive/can/1.0/default/CanSocket.cpp
+++ b/automotive/can/1.0/default/CanSocket.cpp
@@ -33,12 +33,10 @@
using namespace std::chrono_literals;
-/**
- * How frequently the read thread checks whether the interface was asked to be down.
+/* How frequently the read thread checks whether the interface was asked to be down.
*
* Note: This does *not* affect read timing or bandwidth, just CPU load vs time to
- * down the interface.
- */
+ * down the interface. */
static constexpr auto kReadPooling = 100ms;
std::unique_ptr<CanSocket> CanSocket::open(const std::string& ifname, ReadCallback rdcb,
@@ -105,8 +103,7 @@
while (!mStopReaderThread) {
/* The ideal would be to have a blocking read(3) call and interrupt it with shutdown(3).
- * This is unfortunately not supported for SocketCAN, so we need to rely on select(3).
- */
+ * This is unfortunately not supported for SocketCAN, so we need to rely on select(3). */
const auto sel = selectRead(mSocket, kReadPooling);
if (sel == 0) continue; // timeout
if (sel == -1) {
@@ -127,8 +124,7 @@
* Apart from the added complexity, it's possible the added calculations and system calls
* would add so much time to the processing pipeline so the precision of the reported time
* was buried under the subsystem latency. Let's just use a local time since boot here and
- * leave precise hardware timestamps for custom proprietary implementations (if needed).
- */
+ * leave precise hardware timestamps for custom proprietary implementations (if needed). */
const std::chrono::nanoseconds ts(elapsedRealtimeNano());
if (nbytes != CAN_MTU) {
diff --git a/automotive/can/1.0/default/CanSocket.h b/automotive/can/1.0/default/CanSocket.h
index 284e1ea..c98330b 100644
--- a/automotive/can/1.0/default/CanSocket.h
+++ b/automotive/can/1.0/default/CanSocket.h
@@ -31,9 +31,7 @@
namespace V1_0 {
namespace implementation {
-/**
- * Wrapper around SocketCAN socket.
- */
+/** Wrapper around SocketCAN socket. */
struct CanSocket {
using ReadCallback = std::function<void(const struct canfd_frame&, std::chrono::nanoseconds)>;
using ErrorCallback = std::function<void(int errnoVal)>;
diff --git a/automotive/can/1.0/default/CloseHandle.h b/automotive/can/1.0/default/CloseHandle.h
index 5191739..eade109 100644
--- a/automotive/can/1.0/default/CloseHandle.h
+++ b/automotive/can/1.0/default/CloseHandle.h
@@ -26,9 +26,7 @@
namespace V1_0 {
namespace implementation {
-/**
- * Generic ICloseHandle implementation ignoring double-close events.
- */
+/** Generic ICloseHandle implementation ignoring double-close events. */
struct CloseHandle : public ICloseHandle {
using Callback = std::function<void()>;
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
index 21202e3..ba9b65b 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkRequest.h
@@ -27,9 +27,7 @@
typedef unsigned short rtattrtype_t; // as in rtnetlink.h
typedef __u16 nlmsgtype_t; // as in netlink.h
-/**
- * Implementation details, do not use outside NetlinkRequest template.
- */
+/** Implementation details, do not use outside NetlinkRequest template. */
namespace impl {
struct rtattr* addattr_l(struct nlmsghdr* n, size_t maxLen, rtattrtype_t type, const void* data,
@@ -59,7 +57,7 @@
mRequest.nlmsg.nlmsg_flags = flags;
}
- /** Returns pointer to raw netlink message header. */
+ /** \return pointer to raw netlink message header. */
struct nlmsghdr* header() {
return &mRequest.nlmsg;
}
@@ -89,9 +87,7 @@
if (ap == nullptr) mIsGood = false;
}
- /**
- * Guard class to frame nested attributes. See nest(int).
- */
+ /** Guard class to frame nested attributes. See nest(int). */
struct Nest {
Nest(NetlinkRequest& req, rtattrtype_t type) : mReq(req), mAttr(req.nestStart(type)) {}
~Nest() { mReq.nestEnd(mAttr); }
diff --git a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
index 81d6224..90e1f3f 100644
--- a/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
+++ b/automotive/can/1.0/default/libnetdevice/NetlinkSocket.h
@@ -38,8 +38,8 @@
/**
* Send Netlink message to Kernel.
*
- * @param msg Message to send, nlmsg_seq will be set to next sequence number
- * @return true, if succeeded
+ * \param msg Message to send, nlmsg_seq will be set to next sequence number
+ * \return true, if succeeded
*/
template <class T, unsigned int BUFSIZE>
bool send(NetlinkRequest<T, BUFSIZE>& req) {
@@ -50,7 +50,7 @@
/**
* Receive Netlink ACK message from Kernel.
*
- * @return true if received ACK message, false in case of error
+ * \return true if received ACK message, false in case of error
*/
bool receiveAck();
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
index ec3f962..d75361e 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/can.h
@@ -27,13 +27,16 @@
/**
* Opens and binds SocketCAN socket.
*
- * @param ifname Interface to open a socket against
- * @return Socket's FD or -1 in case of failure
+ * \param ifname Interface to open a socket against
+ * \return Socket's FD or -1 in case of failure
*/
base::unique_fd socket(const std::string& ifname);
/**
* Sets CAN interface bitrate.
+ *
+ * \param ifname Interface for which the bitrate is to be set
+ * \return true on success, false on failure
*/
bool setBitrate(std::string ifname, uint32_t bitrate);
diff --git a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
index 33d5de5..e22eafb 100644
--- a/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
+++ b/automotive/can/1.0/default/libnetdevice/include/libnetdevice/libnetdevice.h
@@ -25,49 +25,49 @@
/**
* Checks, if the network interface exists.
*
- * @param ifname Interface to check
- * @return true if it exists, false otherwise
+ * \param ifname Interface to check
+ * \return true if it exists, false otherwise
*/
bool exists(std::string ifname);
/**
* Checks if network interface is up.
*
- * @param ifname Interface to check
- * @return true/false if the check succeeded, nullopt otherwise
+ * \param ifname Interface to check
+ * \return true/false if the check succeeded, nullopt otherwise
*/
std::optional<bool> isUp(std::string ifname);
/**
* Brings network interface up.
*
- * @param ifname Interface to bring up
- * @return true in case of success, false otherwise
+ * \param ifname Interface to bring up
+ * \return true in case of success, false otherwise
*/
bool up(std::string ifname);
/**
* Brings network interface down.
*
- * @param ifname Interface to bring down
- * @return true in case of success, false otherwise
+ * \param ifname Interface to bring down
+ * \return true in case of success, false otherwise
*/
bool down(std::string ifname);
/**
* Adds virtual link.
*
- * @param dev the name of the new virtual device
- * @param type the type of the new device
- * @return true in case of success, false otherwise
+ * \param dev the name of the new virtual device
+ * \param type the type of the new device
+ * \return true in case of success, false otherwise
*/
bool add(std::string dev, std::string type);
/**
* Deletes virtual link.
*
- * @param dev the name of the device to remove
- * @return true in case of success, false otherwise
+ * \param dev the name of the device to remove
+ * \return true in case of success, false otherwise
*/
bool del(std::string dev);
diff --git a/automotive/can/1.0/tools/canhaldump.cpp b/automotive/can/1.0/tools/canhaldump.cpp
index 5713d17..99fd14a 100644
--- a/automotive/can/1.0/tools/canhaldump.cpp
+++ b/automotive/can/1.0/tools/canhaldump.cpp
@@ -49,7 +49,7 @@
} else {
std::cout << " [" << message.payload.size() << "] ";
for (const auto byte : message.payload) {
- std::cout << " " << unsigned(byte);
+ std::cout << " " << std::setfill('0') << std::setw(2) << unsigned(byte);
}
}
std::cout << std::nouppercase << std::dec << std::endl;
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
index ba29c29..225984d 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanBusVirtualV1_0TargetTest.cpp
@@ -91,8 +91,7 @@
EXPECT_EQ(ICanController::Result::OK, result);
/* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
- * file -- this is a test, so we don't want to add dummy services to a device manifest.
- */
+ * file -- this is a test, so we don't want to add dummy services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto service = manager->get(ICanBus::descriptor, config.name);
mBus = ICanBus::castFrom(service);
diff --git a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
index 70f9fe4..64e7a96 100644
--- a/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
+++ b/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0TargetTest.cpp
@@ -95,8 +95,7 @@
void CanControllerHalTest::assertRegistered(std::string srvname, bool expectRegistered) {
/* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
- * file -- this is a test, so we don't want to add dummy services to a device manifest.
- */
+ * file -- this is a test, so we don't want to add dummy services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto busService = manager->get(ICanBus::descriptor, srvname);
ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
index 9eb8894..068333c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/SocketComm.cpp
@@ -92,7 +92,10 @@
}
ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET);
- ::listen(mListenFd, 1);
+ if (::listen(mListenFd, 1) == -1) {
+ ALOGE("%s: Error on listening: errno: %d: %s", __FUNCTION__, errno, strerror(errno));
+ return false;
+ }
return true;
}