diff options
author | 2018-06-08 18:25:39 -0500 | |
---|---|---|
committer | 2018-06-08 19:25:39 -0400 | |
commit | a99407afb50a9c08f2c6ea7857452da8ad0cb484 (patch) | |
tree | cfe085e2e2f08001656a141d564c0bbb67023e7b /src/osd/modules/file | |
parent | eee8d0d2d999d564162e803a57536855120ec51d (diff) |
Discord plugin try 2 (#3640)
* plugins/discord: discord presence plugin [Carl]
* plugins/discord: use domain sockets and pipes [Carl]
* winptty: fix connecting to existing socket (nw)
plugins/discord: show pause state (nw)
* plugins/discord: fix pause behavior (nw)
Diffstat (limited to 'src/osd/modules/file')
-rw-r--r-- | src/osd/modules/file/posixdomain.cpp | 207 | ||||
-rw-r--r-- | src/osd/modules/file/posixfile.cpp | 2 | ||||
-rw-r--r-- | src/osd/modules/file/posixfile.h | 3 | ||||
-rw-r--r-- | src/osd/modules/file/winptty.cpp | 13 |
4 files changed, 223 insertions, 2 deletions
diff --git a/src/osd/modules/file/posixdomain.cpp b/src/osd/modules/file/posixdomain.cpp new file mode 100644 index 00000000000..633187819a7 --- /dev/null +++ b/src/osd/modules/file/posixdomain.cpp @@ -0,0 +1,207 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdldomain.c - SDL socket (unix) access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + +#include "posixfile.h" + +#include <cassert> +#include <cerrno> +#include <cstdio> + +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/time.h> +#include <unistd.h> +#include <fcntl.h> + + +namespace { +char const *const posixfile_domain_identifier = "domain."; + + +class posix_osd_domain : public osd_file +{ +public: + posix_osd_domain(posix_osd_domain const &) = delete; + posix_osd_domain(posix_osd_domain &&) = delete; + posix_osd_domain& operator=(posix_osd_domain const &) = delete; + posix_osd_domain& operator=(posix_osd_domain &&) = delete; + + posix_osd_domain(int sock, bool listening) + : m_sock(sock) + , m_listening(listening) + { + assert(m_sock >= 0); + } + + virtual ~posix_osd_domain() + { + ::close(m_sock); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + fd_set readfds; + FD_ZERO(&readfds); + FD_SET(m_sock, &readfds); + + struct timeval timeout; + timeout.tv_sec = timeout.tv_usec = 0; + + if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 0) + { + char line[80]; + std::sprintf(line, "%s : %s : %d ", __func__, __FILE__, __LINE__); + std::perror(line); + return errno_to_file_error(errno); + } + else if (FD_ISSET(m_sock, &readfds)) + { + if (!m_listening) + { + // connected socket + ssize_t const result = ::read(m_sock, buffer, count); + if (result < 0) + { + return errno_to_file_error(errno); + } + else + { + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + } + else + { + // listening socket + int const accepted = ::accept(m_sock, nullptr, nullptr); + if (accepted < 0) + { + return errno_to_file_error(errno); + } + else + { + ::close(m_sock); + m_sock = accepted; + m_listening = false; + actual = 0; + + return error::NONE; + } + } + } + else + { + return error::FAILURE; + } + } + + virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { + ssize_t const result = ::write(m_sock, buffer, count); + if (result < 0) + return errno_to_file_error(errno); + + actual = std::uint32_t(size_t(result)); + return error::NONE; + } + + virtual error truncate(std::uint64_t offset) override + { + // doesn't make sense on socket + return error::INVALID_ACCESS; + } + + virtual error flush() override + { + // there's no simple way to flush buffers on a socket anyway + return error::NONE; + } + +private: + int m_sock; + bool m_listening; +}; + +} // anonymous namespace + + +bool posix_check_domain_path(std::string const &path) +{ + if (strncmp(path.c_str(), posixfile_domain_identifier, strlen(posixfile_domain_identifier)) == 0) + return true; + return false; +} + + +osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +{ + struct sockaddr_un sau; + memset(&sau, 0, sizeof(sau)); + sau.sun_family = AF_UNIX; + strncpy(sau.sun_path, &path.c_str()[strlen(posixfile_domain_identifier)], sizeof(sau.sun_path)-1); + + int const sock = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return errno_to_file_error(errno); + + fcntl(sock, F_SETFL, O_NONBLOCK); + + // listening socket support + if (openflags & OPEN_FLAG_CREATE) + { + if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sau), sizeof(struct sockaddr_un)) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // start to listen... + if (::listen(sock, 1) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // mark socket as "listening" + try + { + file = std::make_unique<posix_osd_domain>(sock, true); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } + else + { + if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sau), sizeof(struct sockaddr_un)) < 0) + { + ::close(sock); + return osd_file::error::ACCESS_DENIED; // have to return this value or bitb won't try to bind on connect failure + } + try + { + file = std::make_unique<posix_osd_domain>(sock, false); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } +} diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp index 967202eb61c..832b6810db4 100644 --- a/src/osd/modules/file/posixfile.cpp +++ b/src/osd/modules/file/posixfile.cpp @@ -217,6 +217,8 @@ osd_file::error osd_file::open(std::string const &path, std::uint32_t openflags, return posix_open_socket(path, openflags, file, filesize); else if (posix_check_ptty_path(path)) return posix_open_ptty(openflags, file, filesize, dst); + else if (posix_check_domain_path(path)) + return posix_open_domain(path, openflags, file, filesize); // select the file open modes int access; diff --git a/src/osd/modules/file/posixfile.h b/src/osd/modules/file/posixfile.h index 2339a52ceec..6f585ff827a 100644 --- a/src/osd/modules/file/posixfile.h +++ b/src/osd/modules/file/posixfile.h @@ -22,6 +22,9 @@ bool posix_check_socket_path(std::string const &path); osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); +bool posix_check_domain_path(std::string const &path); +osd_file::error posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize); + bool posix_check_ptty_path(std::string const &path); osd_file::error posix_open_ptty(std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize, std::string &name); diff --git a/src/osd/modules/file/winptty.cpp b/src/osd/modules/file/winptty.cpp index ab0efae37ff..943f1fbaa52 100644 --- a/src/osd/modules/file/winptty.cpp +++ b/src/osd/modules/file/winptty.cpp @@ -88,10 +88,19 @@ osd_file::error win_open_ptty(std::string const &path, std::uint32_t openflags, { osd::text::tstring t_name = osd::text::to_tstring(path); - HANDLE pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr); + HANDLE pipe = CreateFileW(t_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); if (INVALID_HANDLE_VALUE == pipe) - return osd_file::error::ACCESS_DENIED; + { + pipe = CreateNamedPipe(t_name.c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, 1, 32, 32, 0, nullptr); + if (INVALID_HANDLE_VALUE == pipe) + return osd_file::error::ACCESS_DENIED; + } + else + { + DWORD state = PIPE_NOWAIT; + SetNamedPipeHandleState(pipe, &state, NULL, NULL); + } try { |