summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author tedgreen99 <tedgreen99@users.noreply.github.com>2022-05-12 21:10:35 -0600
committer GitHub <noreply@github.com>2022-05-12 23:10:35 -0400
commit5052eb307a959644677037be52b9a168a68775dd (patch)
tree9bd5a1a29e81d6cea632ea25449232d9bb62f50e /src
parentbdc0d0dea1f4113bca2ce5162dc044a026b43b58 (diff)
bitbanger: Add udp multicast support (#9744)
Example usage: -bitb udp.234.99.99.99:15122
Diffstat (limited to 'src')
-rw-r--r--src/devices/imagedev/bitbngr.cpp28
-rw-r--r--src/devices/imagedev/bitbngr.h2
-rw-r--r--src/osd/modules/file/posixfile.cpp14
-rw-r--r--src/osd/modules/file/posixfile.h5
-rw-r--r--src/osd/modules/file/posixsocket.cpp150
-rw-r--r--src/osd/modules/file/winfile.cpp15
-rw-r--r--src/osd/modules/file/winfile.h5
-rw-r--r--src/osd/modules/file/winsocket.cpp159
-rw-r--r--src/osd/osdfile.h13
9 files changed, 372 insertions, 19 deletions
diff --git a/src/devices/imagedev/bitbngr.cpp b/src/devices/imagedev/bitbngr.cpp
index dc31c4ccb83..b148b5b684a 100644
--- a/src/devices/imagedev/bitbngr.cpp
+++ b/src/devices/imagedev/bitbngr.cpp
@@ -45,6 +45,19 @@ void bitbanger_device::output(uint8_t data)
fwrite(&data, 1);
}
+/*-------------------------------------------------
+ native_output - outputs data buffer to a file
+-------------------------------------------------*/
+
+int bitbanger_device::send(uint8_t *buf, int len)
+{
+ if (exists())
+ {
+ return fwrite(buf, len);
+ }
+ // Announce we transfered everything
+ return len;
+}
/*-------------------------------------------------
native_input - inputs data from a file
@@ -58,6 +71,21 @@ uint32_t bitbanger_device::input(void *buffer, uint32_t length)
return 0;
}
+/*-------------------------------------------------
+ flush_rx - Flushes all receive data from stream
+-------------------------------------------------*/
+void bitbanger_device::flush_rx(void)
+{
+ if (exists())
+ {
+ int rx_bytes;
+ auto tmp_buf = std::make_unique<uint8_t[]>(512);
+ while ((rx_bytes = fread(tmp_buf.get(), 512)))
+ {
+ //printf("Flushing rx %d bytes\n", rx_bytes);
+ }
+ }
+}
/*-------------------------------------------------
diff --git a/src/devices/imagedev/bitbngr.h b/src/devices/imagedev/bitbngr.h
index 5b02417cfc3..2acca9b16ce 100644
--- a/src/devices/imagedev/bitbngr.h
+++ b/src/devices/imagedev/bitbngr.h
@@ -37,6 +37,8 @@ public:
void output(uint8_t data);
uint32_t input(void *buffer, uint32_t length);
+ int send(uint8_t *buf, int len);
+ void flush_rx();
protected:
// device_t implementation
diff --git a/src/osd/modules/file/posixfile.cpp b/src/osd/modules/file/posixfile.cpp
index 580288c7d10..69b7c60d4a0 100644
--- a/src/osd/modules/file/posixfile.cpp
+++ b/src/osd/modules/file/posixfile.cpp
@@ -226,7 +226,9 @@ std::error_condition osd_file::open(std::string const &path, std::uint32_t openf
{
std::string dst;
if (posix_check_socket_path(path))
- return posix_open_socket(path, openflags, file, filesize);
+ return posix_open_tcp_socket(path, openflags, file, filesize);
+ else if (posix_check_udp_path(path))
+ return posix_open_udp_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))
@@ -343,6 +345,16 @@ std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept
//============================================================
+// osd_open_udp_socket
+//============================================================
+
+std::error_condition osd_file::open_udp_socket(std::string const &path, uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept
+{
+ return posix_open_udp_socket(path, openflags, file, filesize);
+}
+
+
+//============================================================
// osd_file::remove
//============================================================
diff --git a/src/osd/modules/file/posixfile.h b/src/osd/modules/file/posixfile.h
index eb6f010859e..2b0358dc396 100644
--- a/src/osd/modules/file/posixfile.h
+++ b/src/osd/modules/file/posixfile.h
@@ -24,7 +24,10 @@
//============================================================
bool posix_check_socket_path(std::string const &path) noexcept;
-std::error_condition posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
+std::error_condition posix_open_tcp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
+
+bool posix_check_udp_path(std::string const &path) noexcept;
+std::error_condition posix_open_udp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
bool posix_check_domain_path(std::string const &path) noexcept;
std::error_condition posix_open_domain(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
diff --git a/src/osd/modules/file/posixsocket.cpp b/src/osd/modules/file/posixsocket.cpp
index 6a23e747ea1..f2f9c7a6b93 100644
--- a/src/osd/modules/file/posixsocket.cpp
+++ b/src/osd/modules/file/posixsocket.cpp
@@ -28,10 +28,13 @@
#include <unistd.h>
+#define DEBUG_SOCKET (0)
+
namespace {
char const *const posixfile_socket_identifier = "socket.";
char const *const posixfile_domain_identifier = "domain.";
+char const *const posixfile_udp_identifier = "udp.";
class posix_osd_socket : public osd_file
@@ -42,9 +45,11 @@ 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) noexcept
+ posix_osd_socket(int sock, bool listening, uint32_t dest = 0, uint32_t dport = 0) noexcept
: m_sock(sock)
, m_listening(listening)
+ , m_dest(dest)
+ , m_dport(dport)
{
assert(m_sock >= 0);
}
@@ -112,11 +117,26 @@ public:
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 std::error_condition(errno, std::generic_category());
+ if (!m_dest) {
+ ssize_t const result = ::write(m_sock, buffer, count);
+ if (result < 0)
+ return std::error_condition(errno, std::generic_category());
- actual = std::uint32_t(size_t(result));
+ actual = std::uint32_t(size_t(result));
+ }
+ else
+ {
+ sockaddr_in dest;
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = m_dest;
+ dest.sin_port = htons(m_dport);
+ //printf("Sending to %d bytes %s port %d\n", count, inet_ntoa(dest.sin_addr), m_dport);
+ ssize_t const result = ::sendto(m_sock, reinterpret_cast<const char*>(buffer), count, 0, reinterpret_cast <sockaddr*> (&dest), sizeof(dest));
+ if (result < 0)
+ return std::error_condition(errno, std::generic_category());
+ actual = std::uint32_t(size_t(result));
+
+ }
return std::error_condition();
}
@@ -135,6 +155,8 @@ public:
private:
int m_sock;
bool m_listening;
+ uint32_t m_dest;
+ uint32_t m_dport;
};
@@ -209,8 +231,19 @@ bool posix_check_domain_path(std::string const &path) noexcept
}
-std::error_condition posix_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+bool posix_check_udp_path(std::string const &path) noexcept
{
+ if (strncmp(path.c_str(), posixfile_udp_identifier, strlen(posixfile_udp_identifier)) == 0 &&
+ strchr(path.c_str(), ':') != nullptr) return true;
+ return false;
+}
+
+
+std::error_condition posix_open_tcp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+{
+ if (DEBUG_SOCKET)
+ printf("Trying to open tcp socket %s\n", path.c_str());
+
char hostname[256];
int port;
std::sscanf(&path[strlen(posixfile_socket_identifier)], "%255[^:]:%d", hostname, &port);
@@ -262,3 +295,108 @@ std::error_condition posix_open_domain(std::string const &path, std::uint32_t op
return create_socket(sau, sock, openflags, file, filesize);
}
+
+std::error_condition posix_open_udp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+{
+ if (DEBUG_SOCKET)
+ printf("Trying to open udp socket %s\n", path.c_str());
+
+ char hostname[256];
+ int port;
+ std::sscanf(&path[strlen(posixfile_udp_identifier)], "%255[^:]:%d", hostname, &port);
+
+ struct hostent const* const localhost = ::gethostbyname(hostname);
+ if (!localhost)
+ return std::errc::no_such_file_or_directory;
+
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(port);
+ sai.sin_addr = *reinterpret_cast<struct in_addr*>(localhost->h_addr);
+
+ int const sock = ::socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ {
+ if (DEBUG_SOCKET)
+ printf("socket() error\n");
+ return std::error_condition(errno, std::generic_category());
+ }
+
+ int const flag = 1;
+ if (::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&flag), sizeof(flag)) < 0)
+ {
+ if (DEBUG_SOCKET)
+ printf("SO_REUSEADDR error\n");
+ ::close(sock);
+ return std::error_condition(errno, std::generic_category());
+ }
+
+ // local socket support
+ osd_file::ptr result;
+ if (openflags & OPEN_FLAG_CREATE)
+ {
+ sai.sin_addr.s_addr = htonl(INADDR_ANY);
+ if (DEBUG_SOCKET)
+ printf("Listening on '%s' on port '%d'\n", hostname, port);
+
+ // bind socket...
+ if (::bind(sock, reinterpret_cast<struct sockaddr const*>(&sai), sizeof(struct sockaddr)) < 0)
+ {
+ printf("bind error\n");
+ std::error_condition sockbinderr(errno, std::generic_category());
+ ::close(sock);
+ return sockbinderr;
+ }
+
+ // Setup multicast
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = *reinterpret_cast<struct in_addr*>(localhost->h_addr);
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (DEBUG_SOCKET)
+ printf("imr_multaddr: %08x\n", mreq.imr_multiaddr.s_addr);
+ if ((mreq.imr_multiaddr.s_addr & 0xff) >= 224 && (mreq.imr_multiaddr.s_addr & 0xff) <= 239)
+ {
+ if (DEBUG_SOCKET)
+ printf("Setting up udp multicast %s\n", hostname);
+ if (::setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) < 0) {
+ if (DEBUG_SOCKET)
+ printf("IP_ADD_MEMBERSHIP error\n");
+ std::error_condition membererr(errno, std::generic_category());
+ ::close(sock);
+ return membererr;
+ }
+ }
+
+ // Disable loopback on multicast
+ char const loop = 0;
+ if (::setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)))
+ {
+ if (DEBUG_SOCKET)
+ printf("IP_MULTICAST_LOOP error\n");
+ std::error_condition multierr(errno, std::generic_category());
+ ::close(sock);
+ return multierr;
+ }
+
+ // Set ttl on multicast
+ char const ttl = 15;
+ if (::setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)))
+ {
+ if (DEBUG_SOCKET)
+ printf("IP_MULTICAST_TTL error\n");
+ std::error_condition multierr(errno, std::generic_category());
+ ::close(sock);
+ return multierr;
+ }
+ result.reset(new (std::nothrow) posix_osd_socket(sock, false, (*reinterpret_cast<struct in_addr*>(localhost->h_addr)).s_addr, port));
+ }
+ if (!result)
+ {
+ ::close(sock);
+ return std::errc::permission_denied;
+ }
+ file = std::move(result);
+ filesize = 0;
+ return std::error_condition();
+}
diff --git a/src/osd/modules/file/winfile.cpp b/src/osd/modules/file/winfile.cpp
index be4fa6f70c3..ff8146a3185 100644
--- a/src/osd/modules/file/winfile.cpp
+++ b/src/osd/modules/file/winfile.cpp
@@ -168,9 +168,11 @@ std::error_condition osd_file::open(std::string const &orig_path, uint32_t openf
catch (...) { return std::errc::not_enough_memory; }
if (win_check_socket_path(path))
- return win_open_socket(path, openflags, file, filesize);
+ return win_open_tcp_socket(path, openflags, file, filesize);
else if (win_check_ptty_path(path))
return win_open_ptty(path, openflags, file, filesize);
+ else if (win_check_udp_path(path))
+ return win_open_udp_socket(path, openflags, file, filesize);
// convert path to TCHAR
osd::text::tstring t_path;
@@ -288,6 +290,17 @@ std::error_condition osd_file::openpty(ptr &file, std::string &name) noexcept
//============================================================
+// osd_open_udp_socket
+//============================================================
+
+std::error_condition open_udp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+{
+ return win_open_udp_socket(path, openflags, file, filesize);
+}
+
+
+
+//============================================================
// osd_rmfile
//============================================================
diff --git a/src/osd/modules/file/winfile.h b/src/osd/modules/file/winfile.h
index 83f0814733d..0b332b314ad 100644
--- a/src/osd/modules/file/winfile.h
+++ b/src/osd/modules/file/winfile.h
@@ -17,6 +17,7 @@
#include <system_error>
#include <winsock2.h>
+#include <Ws2tcpip.h>
//============================================================
@@ -27,7 +28,9 @@ bool win_init_sockets() noexcept;
void win_cleanup_sockets() noexcept;
bool win_check_socket_path(std::string const &path) noexcept;
-std::error_condition win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
+std::error_condition win_open_tcp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
+bool win_check_udp_path(std::string const &path) noexcept;
+std::error_condition win_open_udp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
bool win_check_ptty_path(std::string const &path) noexcept;
std::error_condition win_open_ptty(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
diff --git a/src/osd/modules/file/winsocket.cpp b/src/osd/modules/file/winsocket.cpp
index d04538963ea..ff5977ed44d 100644
--- a/src/osd/modules/file/winsocket.cpp
+++ b/src/osd/modules/file/winsocket.cpp
@@ -25,10 +25,12 @@
#include <cstdlib>
#include <cctype>
+#define DEBUG_SOCKET (0)
namespace {
char const *const winfile_socket_identifier = "socket.";
+char const *const winfile_udp_identifier = "udp.";
class win_osd_socket : public osd_file
@@ -39,9 +41,11 @@ public:
win_osd_socket& operator=(win_osd_socket const &) = delete;
win_osd_socket& operator=(win_osd_socket &&) = delete;
- win_osd_socket(SOCKET s, bool l) noexcept
+ win_osd_socket(SOCKET s, bool l, uint32_t dest = 0, uint32_t dport = 0) noexcept
: m_socket(s)
, m_listening(l)
+ , m_dest(dest)
+ , m_dport(dport)
{
assert(INVALID_SOCKET != m_socket);
}
@@ -109,11 +113,24 @@ public:
virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept override
{
- auto const result = send(m_socket, reinterpret_cast<const char *>(buffer), length, 0);
- if (result < 0)
- return wsa_error_to_file_error(WSAGetLastError());
-
- actual = result;
+ if (!m_dest) {
+ auto const result = send(m_socket, reinterpret_cast<const char*>(buffer), length, 0);
+ if (result < 0)
+ return wsa_error_to_file_error(WSAGetLastError());
+ actual = result;
+ }
+ else
+ {
+ sockaddr_in dest;
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = m_dest;
+ dest.sin_port = htons(m_dport);
+ //printf("Sending to %d bytes %s port %d\n", length, inet_ntoa(dest.sin_addr), m_dport);
+ auto const result = sendto(m_socket, reinterpret_cast<const char*>(buffer), length, 0, reinterpret_cast <sockaddr*> (&dest), sizeof(dest));
+ if (result < 0)
+ return wsa_error_to_file_error(WSAGetLastError());
+ actual = result;
+ }
return std::error_condition();
}
@@ -177,6 +194,8 @@ public:
private:
SOCKET m_socket;
bool m_listening;
+ uint32_t m_dest;
+ uint32_t m_dport;
};
} // anonymous namespace
@@ -222,8 +241,11 @@ bool win_check_socket_path(std::string const &path) noexcept
}
-std::error_condition win_open_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+std::error_condition win_open_tcp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
{
+ if (DEBUG_SOCKET)
+ printf("Trying to open tcp socket %s\n", path.c_str());
+
char hostname[256];
int port;
std::sscanf(&path[strlen(winfile_socket_identifier)], "%255[^:]:%d", hostname, &port);
@@ -254,10 +276,13 @@ std::error_condition win_open_socket(std::string const &path, std::uint32_t open
osd_file::ptr result;
if (openflags & OPEN_FLAG_CREATE)
{
- //printf("Listening for client at '%s' on port '%d'\n", hostname, port);
+ if (DEBUG_SOCKET)
+ printf("Listening for client at '%s' on port '%d'\n", hostname, port);
// bind socket...
if (bind(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(sai)) == SOCKET_ERROR)
{
+ if (DEBUG_SOCKET)
+ printf("bind error\n");
int const err = WSAGetLastError();
closesocket(sock);
return win_osd_socket::wsa_error_to_file_error(err);
@@ -266,6 +291,8 @@ std::error_condition win_open_socket(std::string const &path, std::uint32_t open
// start to listen...
if (listen(sock, 1) == SOCKET_ERROR)
{
+ if (DEBUG_SOCKET)
+ printf("listen error\n");
int const err = WSAGetLastError();
closesocket(sock);
return win_osd_socket::wsa_error_to_file_error(err);
@@ -276,9 +303,12 @@ std::error_condition win_open_socket(std::string const &path, std::uint32_t open
}
else
{
- //printf("Connecting to server '%s' on port '%d'\n", hostname, port);
+ if (DEBUG_SOCKET)
+ printf("Connecting to server '%s' on port '%d'\n", hostname, port);
if (connect(sock, reinterpret_cast<struct sockaddr const *>(&sai), sizeof(sai)) == SOCKET_ERROR)
{
+ if (DEBUG_SOCKET)
+ printf("connect error\n");
int const err = WSAGetLastError();
closesocket(sock);
return win_osd_socket::wsa_error_to_file_error(err);
@@ -295,3 +325,114 @@ std::error_condition win_open_socket(std::string const &path, std::uint32_t open
filesize = 0;
return std::error_condition();
}
+
+bool win_check_udp_path(std::string const &path) noexcept
+{
+ if (strncmp(path.c_str(), winfile_udp_identifier, strlen(winfile_udp_identifier)) == 0 &&
+ strchr(path.c_str(), ':') != nullptr) return true;
+ return false;
+}
+
+
+std::error_condition win_open_udp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept
+{
+ if (DEBUG_SOCKET)
+ printf("Trying to open udp socket %s\n", path.c_str());
+ char hostname[256];
+ int port;
+ std::sscanf(&path[strlen(winfile_udp_identifier)], "%255[^:]:%d", hostname, &port);
+ //std::sscanf(path.c_str(), "%255[^:]:%d", hostname, &port);
+
+ struct hostent const* const localhost = gethostbyname(hostname);
+ if (!localhost)
+ return std::errc::no_such_file_or_directory;
+ struct sockaddr_in sai;
+ memset(&sai, 0, sizeof(sai));
+ sai.sin_family = AF_INET;
+ sai.sin_port = htons(port);
+ sai.sin_addr = *reinterpret_cast<struct in_addr*>(localhost->h_addr);
+ SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (INVALID_SOCKET == sock)
+ return win_osd_socket::wsa_error_to_file_error(WSAGetLastError());
+
+ int const flag = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&flag), sizeof(flag)) == SOCKET_ERROR)
+ {
+ if (DEBUG_SOCKET)
+ printf("SO_REUSEADDR error\n");
+ int const err = WSAGetLastError();
+ closesocket(sock);
+ return win_osd_socket::wsa_error_to_file_error(err);
+ }
+
+ // local socket support
+ osd_file::ptr result;
+ if (openflags & OPEN_FLAG_CREATE)
+ {
+ sai.sin_addr.s_addr = htonl(INADDR_ANY);
+ if (DEBUG_SOCKET)
+ printf("Listening on '%s' on port '%d'\n", hostname, port);
+ // bind socket...
+ if (bind(sock, reinterpret_cast<struct sockaddr const*>(&sai), sizeof(struct sockaddr)) == SOCKET_ERROR)
+ {
+ if (DEBUG_SOCKET)
+ printf("bind error\n");
+ int const err = WSAGetLastError();
+ closesocket(sock);
+ return win_osd_socket::wsa_error_to_file_error(err);
+ }
+ // Setup multicast
+ struct ip_mreq mreq;
+ mreq.imr_multiaddr = *reinterpret_cast<struct in_addr*>(localhost->h_addr);
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ if (mreq.imr_multiaddr.S_un.S_un_b.s_b1 >= 224 && mreq.imr_multiaddr.S_un.S_un_b.s_b1 <= 239)
+ {
+ if (DEBUG_SOCKET)
+ printf("Setting up udp multicast %s\n", hostname);
+ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) == SOCKET_ERROR) {
+ if (DEBUG_SOCKET)
+ printf("IP_ADD_MEMBERSHIP error\n");
+ int const err = WSAGetLastError();
+ closesocket(sock);
+ return win_osd_socket::wsa_error_to_file_error(err);
+ }
+ }
+ // Disable loopback on multicast
+ char const loop = 0;
+ if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)))
+ {
+ if (DEBUG_SOCKET)
+ printf("IP_MULTICAST_LOOP error\n");
+ int const err = WSAGetLastError();
+ closesocket(sock);
+ return win_osd_socket::wsa_error_to_file_error(err);
+ }
+ // Set ttl on multicast
+ char const ttl = 15;
+ if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)))
+ {
+ if (DEBUG_SOCKET)
+ printf("IP_MULTICAST_TTL error\n");
+ int const err = WSAGetLastError();
+ closesocket(sock);
+ return win_osd_socket::wsa_error_to_file_error(err);
+ }
+ result.reset(new (std::nothrow) win_osd_socket(sock, false, (*reinterpret_cast<struct in_addr*>(localhost->h_addr)).s_addr, port));
+ if (!result)
+ {
+ if (DEBUG_SOCKET)
+ printf("connect error\n");
+ int const err = WSAGetLastError();
+ closesocket(sock);
+ return win_osd_socket::wsa_error_to_file_error(err);
+ }
+ }
+ if (!result)
+ {
+ closesocket(sock);
+ return std::errc::permission_denied;
+ }
+ file = std::move(result);
+ filesize = 0;
+ return std::error_condition();
+}
diff --git a/src/osd/osdfile.h b/src/osd/osdfile.h
index bc3efbde805..2c984c0e3a9 100644
--- a/src/osd/osdfile.h
+++ b/src/osd/osdfile.h
@@ -102,6 +102,19 @@ public:
/// \return Result of the operation.
static std::error_condition openpty(ptr &file, std::string &name) noexcept;
+ /// \brief Create a UDP socket
+ ///
+ /// \param [in] path Address of the socket to open.
+ /// \param [in] openflags Combination of #OPEN_FLAG_READ,
+ /// #OPEN_FLAG_WRITE specifying the requested access mode
+ /// and open behaviour.
+ /// \param [out] file Receives the file handle if the operation
+ /// succeeds. Not valid if the operation fails.
+ /// \param [out] filesize Will be zero if the operation succeeded.
+ /// Not valid if the operation failed.
+ /// \return Result of the operation.
+ static std::error_condition open_udp_socket(std::string const &path, std::uint32_t openflags, osd_file::ptr &file, std::uint64_t &filesize) noexcept;
+
/// \brief Close an open file
virtual ~osd_file() { }