34 : parser([this](const
std::string& cmd) { execute(cmd); })
35 , commandController(commandController_)
36 , eventDistributor(eventDistributor_)
48void CliConnection::log(
CliComm::LogLevel level, std::string_view message,
float fraction)
noexcept
50 std::string fullMessage{message};
52 strAppend(fullMessage,
"... ",
int(100.0f * fraction),
'%');
59 std::string_view name, std::string_view value)
noexcept
61 if (!getUpdateEnable(type))
return;
64 if (!machine.empty()) {
65 strAppend(tmp,
" machine=\"", machine,
'\"');
77 output(
"<openmsx-output>\n");
82 thread = std::thread([
this]() { run(); });
87 output(
"</openmsx-output>\n");
92 if (thread.joinable()) {
97void CliConnection::execute(
const std::string& command)
104 return tmpStrCat(
"<reply result=\"", (status ?
"ok" :
"nok"),
"\">",
108bool CliConnection::signalEvent(
const Event& event)
111 if (
const auto& commandEvent = get_event<CliCommandEvent>(event);
112 commandEvent.getId() ==
this) {
115 commandEvent.getCommand(),
this).
getString();
116 output(reply(result,
true));
117 }
catch (CommandException& e) {
118 std::string result = std::move(e).getMessage() +
'\n';
119 output(reply(result,
false));
128static constexpr int BUF_SIZE = 4096;
141void StdioConnection::run()
150 std::array<char, BUF_SIZE> buf;
151 auto n = read(STDIN_FILENO, buf.data(),
sizeof(buf));
162 std::cout << message << std::flush;
165void StdioConnection::close()
176static const HANDLE OPENMSX_INVALID_HANDLE_VALUE =
reinterpret_cast<HANDLE
>(-1);
178PipeConnection::PipeConnection(CommandController& commandController_,
179 EventDistributor& eventDistributor_,
180 std::string_view name)
181 : CliConnection(commandController_, eventDistributor_)
183 auto pipeName =
strCat(
"\\\\.\\pipe\\", name);
184 pipeHandle = CreateFileA(pipeName.c_str(), GENERIC_READ, 0,
nullptr,
185 OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
nullptr);
186 if (pipeHandle == OPENMSX_INVALID_HANDLE_VALUE) {
187 throw FatalError(
"Error reopening pipefile '", pipeName,
"': error ",
188 unsigned(GetLastError()));
191 shutdownEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
192 if (!shutdownEvent) {
193 throw FatalError(
"Error creating shutdown event: ", GetLastError());
199PipeConnection::~PipeConnection()
203 assert(pipeHandle == OPENMSX_INVALID_HANDLE_VALUE);
204 CloseHandle(shutdownEvent);
207static void InitOverlapped(LPOVERLAPPED overlapped)
209 ZeroMemory(overlapped,
sizeof(*overlapped));
210 overlapped->hEvent = CreateEventW(
nullptr, FALSE, FALSE,
nullptr);
211 if (!overlapped->hEvent) {
212 throw FatalError(
"Error creating overlapped event: ", GetLastError());
216static void ClearOverlapped(LPOVERLAPPED overlapped)
218 if (overlapped->hEvent) {
219 CloseHandle(overlapped->hEvent);
220 overlapped->hEvent =
nullptr;
224void PipeConnection::run()
227 OVERLAPPED overlapped;
228 InitOverlapped(&overlapped);
229 HANDLE waitHandles[2] = { shutdownEvent, overlapped.hEvent };
231 while (pipeHandle != OPENMSX_INVALID_HANDLE_VALUE) {
233 if (!ReadFile(pipeHandle, buf, BUF_SIZE,
nullptr, &overlapped) &&
234 GetLastError() != ERROR_IO_PENDING) {
237 DWORD wait = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
238 if (wait == WAIT_OBJECT_0 + 1) {
240 if (!GetOverlappedResult(pipeHandle, &overlapped, &bytesRead, TRUE)) {
243 parser.parse(std::span{buf, bytesRead});
244 }
else if (wait == WAIT_OBJECT_0) {
248 "WaitForMultipleObjects returned unexpectedly: ", wait);
252 ClearOverlapped(&overlapped);
255 CloseHandle(pipeHandle);
256 pipeHandle = OPENMSX_INVALID_HANDLE_VALUE;
259void PipeConnection::output(std::string_view message)
261 if (pipeHandle != OPENMSX_INVALID_HANDLE_VALUE) {
262 std::cout << message << std::flush;
266void PipeConnection::close()
268 SetEvent(shutdownEvent);
288void SocketConnection::run()
294 std::scoped_lock lock(sdMutex);
296 SocketStreamWrapper stream(sd);
297 SspiNegotiateServer server(stream);
298 ok = server.Authenticate() && server.Authorize();
319 std::array<char, BUF_SIZE> buf;
320 auto n =
sock_recv(sd, buf.data(),
sizeof(buf));
338 std::span message{message_.begin(), message_.end()};
339 while (!message.empty()) {
342 std::scoped_lock lock(sdMutex);
344 bytesSend =
sock_send(sd, message.data(), message.size());
347 message = message.subspan(bytesSend);
359void SocketConnection::closeSocket()
361 std::scoped_lock lock(sdMutex);
369void SocketConnection::close()
void XMLEscape(std::string_view s, Output output)
void parse(std::span< const char > buf)
Command received on CliComm connection.
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)
virtual TclObject executeCommand(zstring_view command, CliConnection *connection=nullptr)=0
Execute the given command.
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() const
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)
zstring_view getString() const
This file implemented 3 utility functions:
constexpr int OPENMSX_INVALID_SOCKET
ptrdiff_t sock_send(SOCKET sd, const char *buf, size_t count)
void sock_close(SOCKET sd)
EventType getType(const Event &event)
std::string toString(const BooleanInput &input)
std::variant< KeyUpEvent, KeyDownEvent, MouseMotionEvent, MouseButtonUpEvent, MouseButtonDownEvent, MouseWheelEvent, JoystickAxisMotionEvent, JoystickHatEvent, JoystickButtonUpEvent, JoystickButtonDownEvent, OsdControlReleaseEvent, OsdControlPressEvent, WindowEvent, TextEvent, FileDropEvent, QuitEvent, FinishFrameEvent, CliCommandEvent, GroupEvent, BootEvent, FrameDrawnEvent, BreakEvent, SwitchRendererEvent, TakeReverseSnapshotEvent, AfterTimedEvent, MachineLoadedEvent, MachineActivatedEvent, MachineDeactivatedEvent, MidiInReaderEvent, MidiInWindowsEvent, MidiInCoreMidiEvent, MidiInCoreMidiVirtualEvent, MidiInALSAEvent, Rs232TesterEvent, Rs232NetEvent, ImGuiDelayedActionEvent, ImGuiActiveEvent > Event
ptrdiff_t sock_recv(SOCKET sd, char *buf, size_t count)
constexpr void fill(ForwardRange &&range, const T &value)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
TemporaryString tmpStrCat(Ts &&... ts)
void strAppend(std::string &result, Ts &&...ts)
constexpr auto end(const zstring_view &x)