33 : parser([this](const std::string& cmd) { execute(cmd); })
34 , commandController(commandController_)
35 , eventDistributor(eventDistributor_)
47 void CliConnection::log(
CliComm::LogLevel level, std::string_view message) noexcept
50 output(
tmpStrCat(
"<log level=\"", levelStr[level],
"\">",
55 std::string_view name, std::string_view value) noexcept
57 if (!getUpdateEnable(type))
return;
60 auto tmp =
strCat(
"<update type=\"", updateStr[type],
'\"');
61 if (!machine.empty()) {
62 strAppend(tmp,
" machine=\"", machine,
'\"');
74 output(
"<openmsx-output>\n");
79 thread = std::thread([
this]() { run(); });
84 output(
"</openmsx-output>\n");
89 if (thread.joinable()) {
94 void CliConnection::execute(
const std::string& command)
97 Event::create<CliCommandEvent>(command,
this));
102 return tmpStrCat(
"<reply result=\"", (status ?
"ok" :
"nok"),
"\">",
106 int CliConnection::signalEvent(
const Event& event) noexcept
109 const auto& commandEvent = get<CliCommandEvent>(event);
110 if (commandEvent.getId() ==
this) {
112 auto result = commandController.executeCommand(
113 commandEvent.getCommand(),
this).getString();
114 output(reply(result,
true));
115 }
catch (CommandException&
e) {
116 std::string result = std::move(
e).getMessage() +
'\n';
117 output(reply(result,
false));
139 void StdioConnection::run()
149 int n = read(STDIN_FILENO, buf,
sizeof(buf));
160 std::cout << message << std::flush;
163 void StdioConnection::close()
174 static const HANDLE OPENMSX_INVALID_HANDLE_VALUE =
reinterpret_cast<HANDLE
>(-1);
176 PipeConnection::PipeConnection(CommandController& commandController_,
177 EventDistributor& eventDistributor_,
178 std::string_view name)
179 : CliConnection(commandController_, eventDistributor_)
181 auto pipeName =
strCat(
"\\\\.\\pipe\\", name);
182 pipeHandle = CreateFileA(pipeName.c_str(), GENERIC_READ, 0,
nullptr,
183 OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
nullptr);
184 if (pipeHandle == OPENMSX_INVALID_HANDLE_VALUE) {
185 throw FatalError(
"Error reopening pipefile '", pipeName,
"': error ",
186 unsigned(GetLastError()));
189 shutdownEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
190 if (!shutdownEvent) {
191 throw FatalError(
"Error creating shutdown event: ", GetLastError());
197 PipeConnection::~PipeConnection()
201 assert(pipeHandle == OPENMSX_INVALID_HANDLE_VALUE);
202 CloseHandle(shutdownEvent);
205 static void InitOverlapped(LPOVERLAPPED overlapped)
207 ZeroMemory(overlapped,
sizeof(*overlapped));
208 overlapped->hEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
209 if (!overlapped->hEvent) {
210 throw FatalError(
"Error creating overlapped event: ", GetLastError());
214 static void ClearOverlapped(LPOVERLAPPED overlapped)
216 if (overlapped->hEvent) {
217 CloseHandle(overlapped->hEvent);
218 overlapped->hEvent =
nullptr;
222 void PipeConnection::run()
225 OVERLAPPED overlapped;
226 InitOverlapped(&overlapped);
227 HANDLE waitHandles[2] = { shutdownEvent, overlapped.hEvent };
229 while (pipeHandle != OPENMSX_INVALID_HANDLE_VALUE) {
231 if (!ReadFile(pipeHandle, buf,
BUF_SIZE,
nullptr, &overlapped) &&
232 GetLastError() != ERROR_IO_PENDING) {
235 DWORD wait = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
236 if (wait == WAIT_OBJECT_0 + 1) {
238 if (!GetOverlappedResult(pipeHandle, &overlapped, &bytesRead, TRUE)) {
241 parser.parse(buf, bytesRead);
242 }
else if (wait == WAIT_OBJECT_0) {
246 "WaitForMultipleObjects returned unexpectedly: ", wait);
250 ClearOverlapped(&overlapped);
253 CloseHandle(pipeHandle);
254 pipeHandle = OPENMSX_INVALID_HANDLE_VALUE;
257 void PipeConnection::output(std::string_view message)
259 if (pipeHandle != OPENMSX_INVALID_HANDLE_VALUE) {
260 std::cout << message << std::flush;
264 void PipeConnection::close()
266 SetEvent(shutdownEvent);
277 , sd(sd_), established(false)
286 void SocketConnection::run()
292 std::lock_guard<std::mutex> lock(sdMutex);
294 SocketStreamWrapper stream(sd);
295 SspiNegotiateServer server(stream);
296 ok = server.Authenticate() && server.Authorize();
335 const char* data = message.data();
337 size_t bytesLeft = message.size();
341 std::lock_guard<std::mutex> lock(sdMutex);
343 bytesSend =
sock_send(sd, &data[pos], bytesLeft);
346 bytesLeft -= bytesSend;
359 void SocketConnection::closeSocket()
361 std::lock_guard<std::mutex> lock(sdMutex);
369 void SocketConnection::close()
void XMLEscape(std::string_view s, Output output)
void parse(const char *buf, size_t n)
static std::span< const char *const > getLevelStrings()
static std::span< const char *const > getUpdateStrings()
void end()
End this connection by sending the closing tag and then closing the stream.
~CliConnection() override
virtual void close()=0
Close the connection.
void start()
Starts the helper thread.
AdhocCliCommParser parser
void startOutput()
Send opening XML tag, should be called exactly once by a subclass shortly after opening a connection.
virtual void output(std::string_view message)=0
CliConnection(CommandController &commandController, EventDistributor &eventDistributor)
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
void distributeEvent(Event &&event)
Schedule the given event for delivery.
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.
SocketConnection(CommandController &commandController, EventDistributor &eventDistributor, SOCKET sd)
~SocketConnection() override
void output(std::string_view message) override
void output(std::string_view message) override
~StdioConnection() override
StdioConnection(CommandController &commandController, EventDistributor &eventDistributor)
This file implemented 3 utility functions:
int sock_recv(SOCKET sd, char *buf, size_t count)
constexpr int OPENMSX_INVALID_SOCKET
void sock_close(SOCKET sd)
int sock_send(SOCKET sd, const char *buf, size_t count)
EventType getType(const Event &event)
constexpr void fill(ForwardRange &&range, const T &value)
TemporaryString tmpStrCat(Ts &&... ts)
std::string strCat(Ts &&...ts)
void strAppend(std::string &result, Ts &&...ts)
constexpr auto end(const zstring_view &x)