1 /*
2 * Copyright (c) 2025, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #define OTBR_LOG_TAG "CLI_DAEMON"
30
31 #include "cli_daemon.hpp"
32
33 #include <fcntl.h>
34 #include <signal.h>
35 #include <stdarg.h>
36 #include <string.h>
37 #include <sys/file.h>
38 #include <sys/socket.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/un.h>
42 #include <unistd.h>
43
44 #include <openthread/cli.h>
45
46 #include "utils/socket_utils.hpp"
47
48 namespace otbr {
49
50 static constexpr char kDefaultNetIfName[] = "wpan0";
51 static constexpr char kSocketBaseName[] = "/run/openthread-";
52 static constexpr char kSocketSuffix[] = ".sock";
53 static constexpr char kSocketLockSuffix[] = ".lock";
54
55 static constexpr size_t kMaxSocketFilenameLength = sizeof(sockaddr_un::sun_path) - 1;
56
GetSocketFilename(const char * aSuffix) const57 std::string CliDaemon::GetSocketFilename(const char *aSuffix) const
58 {
59 std::string fileName;
60 std::string netIfName = mNetifName.empty() ? kDefaultNetIfName : mNetifName;
61
62 fileName = kSocketBaseName + netIfName + aSuffix;
63 VerifyOrDie(fileName.size() <= kMaxSocketFilenameLength, otbrErrorString(OTBR_ERROR_INVALID_ARGS));
64
65 return fileName;
66 }
67
CliDaemon(void)68 CliDaemon::CliDaemon(void)
69 : mListenSocket(-1)
70 , mDaemonLock(-1)
71 {
72 }
73
CreateListenSocketOrDie(void)74 void CliDaemon::CreateListenSocketOrDie(void)
75 {
76 struct sockaddr_un sockname;
77
78 mListenSocket = SocketWithCloseExec(AF_UNIX, SOCK_STREAM, 0, kSocketNonBlock);
79 VerifyOrDie(mListenSocket != -1, strerror(errno));
80
81 std::string lockfile = GetSocketFilename(kSocketLockSuffix);
82 mDaemonLock = open(lockfile.c_str(), O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
83 VerifyOrDie(mDaemonLock != -1, strerror(errno));
84
85 VerifyOrDie(flock(mDaemonLock, LOCK_EX | LOCK_NB) != -1, strerror(errno));
86
87 std::string socketfile = GetSocketFilename(kSocketSuffix);
88 memset(&sockname, 0, sizeof(struct sockaddr_un));
89
90 sockname.sun_family = AF_UNIX;
91 strncpy(sockname.sun_path, socketfile.c_str(), sizeof(sockname.sun_path) - 1);
92 OTBR_UNUSED_VARIABLE(unlink(sockname.sun_path));
93
94 VerifyOrDie(bind(mListenSocket, reinterpret_cast<const struct sockaddr *>(&sockname), sizeof(struct sockaddr_un)) !=
95 -1,
96 strerror(errno));
97 }
98
Init(const std::string & aNetIfName)99 void CliDaemon::Init(const std::string &aNetIfName)
100 {
101 // This allows implementing pseudo reset.
102 VerifyOrExit(mListenSocket == -1);
103
104 mNetifName = aNetIfName;
105 CreateListenSocketOrDie();
106
107 //
108 // only accept 1 connection.
109 //
110 VerifyOrDie(listen(mListenSocket, 1) != -1, strerror(errno));
111
112 exit:
113 return;
114 }
115
116 } // namespace otbr
117