diff options
author | 2021-08-22 09:06:15 +1000 | |
---|---|---|
committer | 2021-08-22 09:06:15 +1000 | |
commit | e8bbea1fc6e94e14768509d322f6c624403ffb36 (patch) | |
tree | 74dd1606a900d83de8aecff17a6737af4113308d /src/osd/modules/file/posixsocket.cpp | |
parent | e319bde5fc3696d7f48f62b15b6366c4377fe5d1 (diff) |
formats, osd, util: Started refactoring file I/O stuff. (#8456)
Added more modern generic I/O interfaces with implementation backed by stdio, osd_file and core_file, replacing io_generic. Also replaced core_file's build-in zlib compression with a filter.
unzip.cpp, un7z.cpp: Added option to supply abstract I/O interface rather than filename.
Converted osd_file, core_file, archive_file, chd_file and device_image_interface to use std::error_condition rather than their own error enums.
Allow mounting TI-99 RPK from inside archives.
Diffstat (limited to 'src/osd/modules/file/posixsocket.cpp')
-rw-r--r-- | src/osd/modules/file/posixsocket.cpp | 187 |
1 files changed, 105 insertions, 82 deletions
diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp index 2ce5ad05d5c..4770e91c6a9 100644 --- a/src/osd/modules/file/posixsocket.cpp +++ b/src/osd/modules/file/posixsocket.cpp @@ -2,7 +2,8 @@ // copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb //============================================================ // -// sdlsocket.c - SDL socket (inet) access functions +// sdlsocket.c - SDL socket (inet, unix domain) access +// functions // // SDLMAME by Olivier Galibert and R. Belmont // @@ -16,17 +17,21 @@ #include <cstring> #include <arpa/inet.h> +#include <fcntl.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <sys/select.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/un.h> #include <unistd.h> namespace { + char const *const posixfile_socket_identifier = "socket."; +char const *const posixfile_domain_identifier = "domain."; class posix_osd_socket : public osd_file @@ -37,7 +42,7 @@ public: posix_osd_socket& operator=(posix_osd_socket const &) = delete; posix_osd_socket& operator=(posix_osd_socket &&) = delete; - posix_osd_socket(int sock, bool listening) + posix_osd_socket(int sock, bool listening) noexcept : m_sock(sock) , m_listening(listening) { @@ -49,7 +54,7 @@ public: ::close(m_sock); } - virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { fd_set readfds; FD_ZERO(&readfds); @@ -58,12 +63,9 @@ public: struct timeval timeout; timeout.tv_sec = timeout.tv_usec = 0; - if (select(m_sock + 1, &readfds, nullptr, nullptr, &timeout) < 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); + return std::error_condition(errno, std::generic_category()); } else if (FD_ISSET(m_sock, &readfds)) { @@ -73,12 +75,12 @@ public: ssize_t const result = ::read(m_sock, buffer, count); if (result < 0) { - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); } else { actual = std::uint32_t(size_t(result)); - return error::NONE; + return std::error_condition(); } } else @@ -87,7 +89,7 @@ public: int const accepted = ::accept(m_sock, nullptr, nullptr); if (accepted < 0) { - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); } else { @@ -96,36 +98,38 @@ public: m_listening = false; actual = 0; - return error::NONE; + return std::error_condition(); } } } else { - return error::FAILURE; + // no data available + actual = 0; + return std::error_condition(); } } - virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) noexcept override { ssize_t const result = ::write(m_sock, buffer, count); if (result < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); actual = std::uint32_t(size_t(result)); - return error::NONE; + return std::error_condition(); } - virtual error truncate(std::uint64_t offset) override + virtual std::error_condition truncate(std::uint64_t offset) noexcept override { // doesn't make sense on socket - return error::INVALID_ACCESS; + return std::errc::bad_file_descriptor; } - virtual error flush() override + virtual std::error_condition flush() noexcept override { // there's no simple way to flush buffers on a socket anyway - return error::NONE; + return std::error_condition(); } private: @@ -133,6 +137,54 @@ private: bool m_listening; }; + +template <typename T> +std::error_condition create_socket(T const &sa, int sock, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept +{ + osd_file::ptr result; + if (openflags & OPEN_FLAG_CREATE) + { + // listening socket support + // bind socket... + if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sa), sizeof(sa)) < 0) + { + std::error_condition binderr(errno, std::generic_category()); + ::close(sock); + return binderr; + } + + // start to listen... + if (::listen(sock, 1) < 0) + { + std::error_condition lstnerr(errno, std::generic_category()); + ::close(sock); + return lstnerr; + } + + // mark socket as "listening" + result.reset(new (std::nothrow) posix_osd_socket(sock, true)); + } + else + { + if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sa), sizeof(sa)) < 0) + { + std::error_condition connerr(errno, std::generic_category()); + ::close(sock); + return connerr; + } + result.reset(new (std::nothrow) posix_osd_socket(sock, false)); + } + + if (!result) + { + ::close(sock); + return std::errc::not_enough_memory; + } + file = std::move(result); + filesize = 0; + return std::error_condition(); +} + } // anonymous namespace @@ -141,7 +193,7 @@ private: specification has the format "socket." host ":" port. Host may be simple or fully qualified. Port must be between 1 and 65535. */ -bool posix_check_socket_path(std::string const &path) +bool posix_check_socket_path(std::string const &path) noexcept { if (strncmp(path.c_str(), posixfile_socket_identifier, strlen(posixfile_socket_identifier)) == 0 && strchr(path.c_str(), ':') != nullptr) return true; @@ -149,7 +201,15 @@ 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) noexcept +{ + if (strncmp(path.c_str(), posixfile_domain_identifier, strlen(posixfile_domain_identifier)) == 0) + return true; + return false; +} + + +std::error_condition posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept { char hostname[256]; int port; @@ -157,7 +217,7 @@ osd_file::error posix_open_socket(std::string const &path, std::uint32_t openfla struct hostent const *const localhost = ::gethostbyname(hostname); if (!localhost) - return osd_file::error::NOT_FOUND; + return std::errc::no_such_file_or_directory; struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); @@ -167,75 +227,38 @@ osd_file::error posix_open_socket(std::string const &path, std::uint32_t openfla int const sock = ::socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) - return errno_to_file_error(errno); + return std::error_condition(errno, std::generic_category()); int const flag = 1; - if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) + if ((::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) || + (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0)) { - int const err = errno; + std::error_condition sockopterr(errno, std::generic_category()); ::close(sock); - return errno_to_file_error(err); + return sockopterr; } - if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&flag), sizeof(flag)) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } + return create_socket(sai, sock, openflags, file, filesize); +} - // listening socket support - if (openflags & OPEN_FLAG_CREATE) - { - //printf("Listening for client at '%s' on port '%d'\n", hostname, port); - // bind socket... - if (::bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } +std::error_condition posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept +{ + 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); - // start to listen... - if (::listen(sock, 1) < 0) - { - int const err = errno; - ::close(sock); - return errno_to_file_error(err); - } + int const sock = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + return std::error_condition(errno, std::generic_category()); - // mark socket as "listening" - try - { - file = std::make_unique<posix_osd_socket>(sock, true); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) - { - ::close(sock); - return osd_file::error::OUT_OF_MEMORY; - } - } - else + if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { - //printf("Connecting to server '%s' on port '%d'\n", hostname, port); - if (::connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(struct sockaddr)) < 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_socket>(sock, false); - filesize = 0; - return osd_file::error::NONE; - } - catch (...) - { - ::close(sock); - return osd_file::error::OUT_OF_MEMORY; - } + std::error_condition cntlerr(errno, std::generic_category()); + ::close(sock); + return cntlerr; } + + return create_socket(sau, sock, openflags, file, filesize); } |