28 [[nodiscard]]
static string getUserName()
33 struct passwd* pw = getpwuid(getuid());
34 return pw->pw_name ? pw->pw_name :
string{};
38 [[nodiscard]]
static bool checkSocketDir(
zstring_view dir)
41 if (stat(dir.
c_str(), &st)) {
45 if (!S_ISDIR(st.st_mode)) {
51 if ((st.st_mode & 0777) != 0700) {
55 if (st.st_uid != getuid()) {
63 [[nodiscard]]
static bool checkSocket(
zstring_view socket)
71 if (stat(socket.
c_str(), &st)) {
76 if (!S_ISREG(st.st_mode)) {
81 if (!S_ISSOCK(st.st_mode)) {
88 if ((st.st_mode & 0777) != 0600) {
93 if (st.st_uid != getuid()) {
103 [[nodiscard]]
static int openPort(
SOCKET listenSock)
105 const int BASE = 9938;
106 const int RANGE = 64;
110 for (
auto n :
xrange(RANGE)) {
111 int port = BASE + ((first + n) % RANGE);
112 sockaddr_in server_address;
113 memset(&server_address, 0,
sizeof(server_address));
114 server_address.sin_family = AF_INET;
115 server_address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
116 server_address.sin_port = htons(port);
117 if (bind(listenSock,
reinterpret_cast<sockaddr*
>(&server_address),
118 sizeof(server_address)) != -1) {
122 throw MSXException(
"Couldn't open socket.");
126 SOCKET CliServer::createSocket()
130 if (!checkSocketDir(dir)) {
131 throw MSXException(
"Couldn't create socket directory.");
133 socketName =
strCat(dir,
"/socket.",
int(getpid()));
136 SOCKET sd = socket(AF_INET, SOCK_STREAM, 0);
140 int portNumber = openPort(sd);
146 out << portNumber <<
'\n';
149 throw MSXException(
"Couldn't write socket port file.");
153 SOCKET sd = socket(AF_UNIX, SOCK_STREAM, 0);
161 strncpy(addr.sun_path, socketName.c_str(),
sizeof(addr.sun_path) - 1);
162 addr.sun_path[
sizeof(addr.sun_path) - 1] =
'\0';
163 addr.sun_family = AF_UNIX;
165 if (bind(sd,
reinterpret_cast<sockaddr*
>(&addr),
sizeof(addr)) == -1) {
167 throw MSXException(
"Couldn't bind socket.");
169 if (chmod(socketName.c_str(), 0600) == -1) {
171 throw MSXException(
"Couldn't set socket permissions.");
175 if (!checkSocket(socketName)) {
177 throw MSXException(
"Opened socket fails sanity check.");
181 throw MSXException(
"Couldn't listen to socket: ",
sock_error());
186 void CliServer::exitAcceptLoop()
192 static void deleteSocket(
const string& socket)
195 string dir = socket.
substr(0, socket.find_last_of(
'/'));
203 : commandController(commandController_)
204 , eventDistributor(eventDistributor_)
210 listenSock = createSocket();
211 thread = std::thread([
this]() { mainLoop(); });
224 deleteSocket(socketName);
228 void CliServer::mainLoop()
233 fcntl(listenSock, F_SETFL, O_NONBLOCK);
240 if (poller.
poll(listenSock)) {
244 SOCKET sd = accept(listenSock,
nullptr,
nullptr);
252 if (errno ==
one_of(EAGAIN, EWOULDBLOCK)) {
261 fcntl(sd, F_SETFL, 0);
263 cliComm.
addListener(std::make_unique<SocketConnection>(
264 commandController, eventDistributor, sd));
void printWarning(std::string_view message)
CliServer(CommandController &commandController, EventDistributor &eventDistributor, GlobalCliComm &cliComm)
void addListener(std::unique_ptr< CliListener > listener)
const std::string & getMessage() const &
bool poll(int fd)
Waits for an event to occur on the given file descriptor.
bool aborted()
Returns true iff abort() was called.
void abort()
Aborts a poll in progress and any future poll attempts.
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
constexpr const char * c_str() const
constexpr zstring_view substr(size_type pos) const
bool startsWith(string_view total, string_view part)
void mkdir(zstring_view path, mode_t mode)
Create the specified directory.
void openofstream(std::ofstream &stream, zstring_view filename)
Open an ofstream in a platform-independent manner.
int rmdir(zstring_view path)
Call rmdir() in a platform-independent manner.
string getTempDir()
Get the name of the temp directory on the system.
string_view getFilename(string_view path)
Returns the file portion of a path name.
int unlink(zstring_view path)
Call unlink() in a platform-independent manner.
This file implemented 3 utility functions:
constexpr int OPENMSX_INVALID_SOCKET
constexpr int SOCKET_ERROR
void sock_close(SOCKET sd)
int random_int(int from, int thru)
Return a random integer in the range [from, thru] (note: closed interval).
TemporaryString tmpStrCat(Ts &&... ts)
std::string strCat(Ts &&...ts)
constexpr auto xrange(T e)