40 , command(std::move(command_)), id(id_)
57 const auto& otherCmdEvent = checked_cast<const CliCommandEvent&>(other);
58 return getCommand() < otherCmdEvent.getCommand();
70 : parser([this](const std::string& cmd) { execute(cmd); })
71 , commandController(commandController_)
72 , eventDistributor(eventDistributor_)
84 void CliConnection::log(
CliComm::LogLevel level, std::string_view message) noexcept
87 output(
tmpStrCat(
"<log level=\"", levelStr[level],
"\">",
92 std::string_view name, std::string_view value) noexcept
94 if (!getUpdateEnable(type))
return;
97 string tmp =
strCat(
"<update type=\"", updateStr[type],
'\"');
98 if (!machine.empty()) {
99 strAppend(tmp,
" machine=\"", machine,
'\"');
111 output(
"<openmsx-output>\n");
116 thread = std::thread([
this]() { run(); });
121 output(
"</openmsx-output>\n");
126 if (thread.joinable()) {
131 void CliConnection::execute(
const string& command)
134 std::make_shared<CliCommandEvent>(command,
this));
139 return tmpStrCat(
"<reply result=\"", (status ?
"ok" :
"nok"),
"\">",
143 int CliConnection::signalEvent(
const std::shared_ptr<const Event>& event) noexcept
145 const auto& commandEvent = checked_cast<const CliCommandEvent&>(*event);
146 if (commandEvent.getId() ==
this) {
148 auto result = commandController.executeCommand(
149 commandEvent.getCommand(),
this).getString();
150 output(reply(result,
true));
151 }
catch (CommandException& e) {
152 string result = std::move(e).getMessage() +
'\n';
153 output(reply(result,
false));
175 void StdioConnection::run()
185 int n = read(STDIN_FILENO, buf,
sizeof(buf));
196 std::cout << message << std::flush;
199 void StdioConnection::close()
210 static const HANDLE OPENMSX_INVALID_HANDLE_VALUE =
reinterpret_cast<HANDLE
>(-1);
212 PipeConnection::PipeConnection(CommandController& commandController_,
213 EventDistributor& eventDistributor_,
214 std::string_view name)
215 : CliConnection(commandController_, eventDistributor_)
217 string pipeName =
strCat(
"\\\\.\\pipe\\", name);
218 pipeHandle = CreateFileA(pipeName.c_str(), GENERIC_READ, 0,
nullptr,
219 OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
nullptr);
220 if (pipeHandle == OPENMSX_INVALID_HANDLE_VALUE) {
221 throw FatalError(
"Error reopening pipefile '", pipeName,
"': error ",
222 unsigned(GetLastError()));
225 shutdownEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
226 if (!shutdownEvent) {
227 throw FatalError(
"Error creating shutdown event: ", GetLastError());
233 PipeConnection::~PipeConnection()
237 assert(pipeHandle == OPENMSX_INVALID_HANDLE_VALUE);
238 CloseHandle(shutdownEvent);
241 static void InitOverlapped(LPOVERLAPPED overlapped)
243 ZeroMemory(overlapped,
sizeof(*overlapped));
244 overlapped->hEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
245 if (!overlapped->hEvent) {
246 throw FatalError(
"Error creating overlapped event: ", GetLastError());
250 static void ClearOverlapped(LPOVERLAPPED overlapped)
252 if (overlapped->hEvent) {
253 CloseHandle(overlapped->hEvent);
254 overlapped->hEvent =
nullptr;
258 void PipeConnection::run()
261 OVERLAPPED overlapped;
262 InitOverlapped(&overlapped);
263 HANDLE waitHandles[2] = { shutdownEvent, overlapped.hEvent };
265 while (pipeHandle != OPENMSX_INVALID_HANDLE_VALUE) {
267 if (!ReadFile(pipeHandle, buf,
BUF_SIZE,
nullptr, &overlapped) &&
268 GetLastError() != ERROR_IO_PENDING) {
271 DWORD wait = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
272 if (wait == WAIT_OBJECT_0 + 1) {
274 if (!GetOverlappedResult(pipeHandle, &overlapped, &bytesRead, TRUE)) {
277 parser.parse(buf, bytesRead);
278 }
else if (wait == WAIT_OBJECT_0) {
282 "WaitForMultipleObjects returned unexpectedly: ", wait);
286 ClearOverlapped(&overlapped);
289 CloseHandle(pipeHandle);
290 pipeHandle = OPENMSX_INVALID_HANDLE_VALUE;
293 void PipeConnection::output(std::string_view message)
295 if (pipeHandle != OPENMSX_INVALID_HANDLE_VALUE) {
296 std::cout << message << std::flush;
300 void PipeConnection::close()
302 SetEvent(shutdownEvent);
313 , sd(sd_), established(false)
322 void SocketConnection::run()
328 std::lock_guard<std::mutex> lock(sdMutex);
330 SocketStreamWrapper stream(sd);
331 SspiNegotiateServer server(stream);
332 ok = server.Authenticate() && server.Authorize();
371 const char* data = message.data();
373 size_t bytesLeft = message.size();
377 std::lock_guard<std::mutex> lock(sdMutex);
379 bytesSend =
sock_send(sd, &data[pos], bytesLeft);
382 bytesLeft -= bytesSend;
395 void SocketConnection::closeSocket()
397 std::lock_guard<std::mutex> lock(sdMutex);
405 void SocketConnection::close()
void parse(const char *buf, size_t n)
static span< const char *const > getLevelStrings()
static span< const char *const > getUpdateStrings()
TclObject toTclList() const override
Similar to toString(), but retains the structure of the event.
CliCommandEvent(string command_, const CliConnection *id_)
const string & getCommand() const
bool lessImpl(const Event &other) const override
const CliConnection * getId() const
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(const EventPtr &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)
static std::string XMLEscape(std::string_view str)
This file implemented 3 utility functions:
int sock_recv(SOCKET sd, char *buf, size_t count)
constexpr int OPENMSX_INVALID_SOCKET
@ OPENMSX_CLICOMMAND_EVENT
Command received on CliComm connection.
void sock_close(SOCKET sd)
int sock_send(SOCKET sd, const char *buf, size_t count)
TclObject makeTclList(Args &&... args)
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)