From 42fbb9c3967fcda37f2d9ae17d5796a79cf027b9 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Sun, 13 Mar 2016 13:54:57 +1100 Subject: Make osd_file a polymorphic class that's held with smart pointers Make avi_file a class that's held with smart pointers, encapsulate various AVI I/O structures Make zip_file and _7z_file classes rather than having free functions everywhere Hide zip/7z class implementation behind an interface, no longer need to call close() to send back to the cache Don't dump as much crap in global namespace Add solaris PTY implementation Improve variable expansion for SDL OSD - supports ~/$FOO/${BAR} syntax Rearrange stuff so the same things are in file module for all OSDs Move file stuff into its own module 7z/zip open and destruct are still not thread-safe due to lack of interlocks around cache access Directory functions still need to be moved to file module SDL OSD may not initialise WinSock on Windows --- src/osd/modules/file/posixsocket.cpp | 236 +++++++++++++++++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 src/osd/modules/file/posixsocket.cpp (limited to 'src/osd/modules/file/posixsocket.cpp') diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp new file mode 100644 index 00000000000..e50d0636489 --- /dev/null +++ b/src/osd/modules/file/posixsocket.cpp @@ -0,0 +1,236 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert, R. Belmont, Vas Crabb +//============================================================ +// +// sdlsocket.c - SDL socket (inet) access functions +// +// SDLMAME by Olivier Galibert and R. Belmont +// +//============================================================ + +#include "posixfile.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace { +char const *const posixfile_socket_identifier = "socket."; + + +class posix_osd_socket : public osd_file +{ +public: + posix_osd_socket(posix_osd_socket const &) = delete; + posix_osd_socket(posix_osd_socket &&) = delete; + posix_osd_socket& operator=(posix_osd_socket const &) = delete; + posix_osd_socket& operator=(posix_osd_socket &&) = delete; + + posix_osd_socket(int sock, bool listening) + : m_sock(sock) + , m_listening(listening) + { + assert(m_sock >= 0); + } + + virtual ~posix_osd_socket() + { + ::close(m_sock); + } + + virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override + { +#if defined(EMSCRIPTEN) + return error::FAILED; // TODO: work out what it dislikes about emscripten +#else + 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; + } +#endif + } + + 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 + + +/* + Checks whether the path is a socket specification. A valid socket + 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) +{ + if (strncmp(path.c_str(), posixfile_socket_identifier, strlen(posixfile_socket_identifier)) == 0 && + strchr(path.c_str(), ':') != nullptr) return true; + return false; +} + + +osd_file::error posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) +{ + char hostname[256]; + int port; + std::sscanf(&path[strlen(posixfile_socket_identifier)], "%255[^:]:%d", hostname, &port); + + struct hostent const *const localhost = ::gethostbyname(hostname); + if (!localhost) + return osd_file::error::NOT_FOUND; + + struct sockaddr_in sai; + memset(&sai, 0, sizeof(sai)); + sai.sin_family = AF_INET; + sai.sin_port = htons(port); + sai.sin_addr = *reinterpret_cast(localhost->h_addr); + + int const sock = ::socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) + return errno_to_file_error(errno); + + int const flag = 1; + if (::setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&flag), sizeof(flag)) < 0) + { + int const err = errno; + ::close(sock); + return errno_to_file_error(err); + } + + // 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(&sai), sizeof(struct sockaddr)) < 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(sock, true); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } + else + { + //printf("Connecting to server '%s' on port '%d'\n", hostname, port); + if (::connect(sock, reinterpret_cast(&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(sock, false); + filesize = 0; + return osd_file::error::NONE; + } + catch (...) + { + ::close(sock); + return osd_file::error::OUT_OF_MEMORY; + } + } +} -- cgit v1.2.3-70-g09d2 From 92357bdff202c8effe167fe389accd1ccdec1777 Mon Sep 17 00:00:00 2001 From: Justin Kerk Date: Mon, 14 Mar 2016 14:34:52 +0000 Subject: Fix Emscripten build (nw) --- src/osd/modules/file/posixsocket.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/osd/modules/file/posixsocket.cpp') diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp index e50d0636489..f6f465dd5d7 100644 --- a/src/osd/modules/file/posixsocket.cpp +++ b/src/osd/modules/file/posixsocket.cpp @@ -51,7 +51,8 @@ public: virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override { #if defined(EMSCRIPTEN) - return error::FAILED; // TODO: work out what it dislikes about emscripten + m_listening = false; + return error::FAILURE; // TODO: work out what it dislikes about emscripten #else fd_set readfds; FD_ZERO(&readfds); -- cgit v1.2.3-70-g09d2 From 4cc9dd016a15cb562070c8be42036e0368a1f87c Mon Sep 17 00:00:00 2001 From: Justin Kerk Date: Thu, 17 Mar 2016 02:04:19 +0000 Subject: Don't need to ifdef this out anymore either (nw) --- src/osd/modules/file/posixsocket.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/osd/modules/file/posixsocket.cpp') diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp index f6f465dd5d7..d6655e4cf15 100644 --- a/src/osd/modules/file/posixsocket.cpp +++ b/src/osd/modules/file/posixsocket.cpp @@ -50,10 +50,6 @@ public: virtual error read(void *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override { -#if defined(EMSCRIPTEN) - m_listening = false; - return error::FAILURE; // TODO: work out what it dislikes about emscripten -#else fd_set readfds; FD_ZERO(&readfds); FD_SET(m_sock, &readfds); @@ -107,7 +103,6 @@ public: { return error::FAILURE; } -#endif } virtual error write(void const *buffer, std::uint64_t offset, std::uint32_t count, std::uint32_t &actual) override -- cgit v1.2.3-70-g09d2