mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Add SocketOptions and avoid reducing the system default buffer sizes
This change affects the DatagramSocket and StreamingSocket classes.
This commit is contained in:
parent
005040da77
commit
62bba21655
2 changed files with 131 additions and 15 deletions
|
|
@ -82,11 +82,38 @@ namespace SocketHelpers
|
|||
return setOption (handle, SOL_SOCKET, property, value);
|
||||
}
|
||||
|
||||
static bool resetSocketOptions (SocketHandle handle, bool isDatagram, bool allowBroadcast) noexcept
|
||||
static std::optional<int> getBufferSize (SocketHandle handle, int property)
|
||||
{
|
||||
int result;
|
||||
socklen_t outParamSize = sizeof (result);
|
||||
|
||||
if (getsockopt (handle, SOL_SOCKET, property, reinterpret_cast<char*> (&result), &outParamSize) != 0
|
||||
|| outParamSize != sizeof (result))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool resetSocketOptions (SocketHandle handle, bool isDatagram, bool allowBroadcast, const SocketOptions& options) noexcept
|
||||
{
|
||||
auto getCurrentBufferSizeWithMinimum = [handle] (int property)
|
||||
{
|
||||
constexpr auto minBufferSize = 65536;
|
||||
|
||||
if (auto currentBufferSize = getBufferSize (handle, property))
|
||||
return std::max (*currentBufferSize, minBufferSize);
|
||||
|
||||
return minBufferSize;
|
||||
};
|
||||
|
||||
const auto receiveBufferSize = options.getReceiveBufferSize().value_or (getCurrentBufferSizeWithMinimum (SO_RCVBUF));
|
||||
const auto sendBufferSize = options.getSendBufferSize() .value_or (getCurrentBufferSizeWithMinimum (SO_SNDBUF));
|
||||
|
||||
return handle != invalidSocket
|
||||
&& setOption (handle, SO_RCVBUF, (int) 65536)
|
||||
&& setOption (handle, SO_SNDBUF, (int) 65536)
|
||||
&& setOption (handle, SO_RCVBUF, receiveBufferSize)
|
||||
&& setOption (handle, SO_SNDBUF, sendBufferSize)
|
||||
&& (isDatagram ? ((! allowBroadcast) || setOption (handle, SO_BROADCAST, (int) 1))
|
||||
: setOption (handle, IPPROTO_TCP, TCP_NODELAY, (int) 1));
|
||||
}
|
||||
|
|
@ -370,7 +397,8 @@ namespace SocketHelpers
|
|||
CriticalSection& readLock,
|
||||
const String& hostName,
|
||||
int portNumber,
|
||||
int timeOutMillisecs) noexcept
|
||||
int timeOutMillisecs,
|
||||
const SocketOptions& options) noexcept
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
|
|
@ -421,7 +449,7 @@ namespace SocketHelpers
|
|||
{
|
||||
auto h = (SocketHandle) handle.load();
|
||||
setSocketBlockingState (h, true);
|
||||
resetSocketOptions (h, false, false);
|
||||
resetSocketOptions (h, false, false, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -458,8 +486,9 @@ StreamingSocket::StreamingSocket()
|
|||
SocketHelpers::initSockets();
|
||||
}
|
||||
|
||||
StreamingSocket::StreamingSocket (const String& host, int portNum, int h)
|
||||
: hostName (host),
|
||||
StreamingSocket::StreamingSocket (const String& host, int portNum, int h, const SocketOptions& optionsIn)
|
||||
: options (optionsIn),
|
||||
hostName (host),
|
||||
portNumber (portNum),
|
||||
handle (h),
|
||||
connected (true)
|
||||
|
|
@ -467,7 +496,7 @@ StreamingSocket::StreamingSocket (const String& host, int portNum, int h)
|
|||
jassert (SocketHelpers::isValidPortNumber (portNum));
|
||||
|
||||
SocketHelpers::initSockets();
|
||||
SocketHelpers::resetSocketOptions ((SocketHandle) h, false, false);
|
||||
SocketHelpers::resetSocketOptions ((SocketHandle) h, false, false, options);
|
||||
}
|
||||
|
||||
StreamingSocket::~StreamingSocket()
|
||||
|
|
@ -535,12 +564,12 @@ bool StreamingSocket::connect (const String& remoteHostName, int remotePortNumbe
|
|||
isListener = false;
|
||||
|
||||
connected = SocketHelpers::connectSocket (handle, readLock, remoteHostName,
|
||||
remotePortNumber, timeOutMillisecs);
|
||||
remotePortNumber, timeOutMillisecs, options);
|
||||
|
||||
if (! connected)
|
||||
return false;
|
||||
|
||||
if (! SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(), false, false))
|
||||
if (! SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(), false, false, options))
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
|
|
@ -606,7 +635,7 @@ StreamingSocket* StreamingSocket::waitForNextConnection() const
|
|||
|
||||
if (newSocket >= 0 && connected)
|
||||
return new StreamingSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
|
||||
portNumber, newSocket);
|
||||
portNumber, newSocket, options);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
@ -629,7 +658,8 @@ bool StreamingSocket::isLocal() const noexcept
|
|||
|
||||
//==============================================================================
|
||||
//==============================================================================
|
||||
DatagramSocket::DatagramSocket (bool canBroadcast)
|
||||
DatagramSocket::DatagramSocket (bool canBroadcast, const SocketOptions& optionsIn)
|
||||
: options { optionsIn }
|
||||
{
|
||||
SocketHelpers::initSockets();
|
||||
|
||||
|
|
@ -637,7 +667,7 @@ DatagramSocket::DatagramSocket (bool canBroadcast)
|
|||
|
||||
if (handle >= 0)
|
||||
{
|
||||
SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(), true, canBroadcast);
|
||||
SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(), true, canBroadcast, options);
|
||||
SocketHelpers::makeReusable (handle);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,50 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
/**
|
||||
Options used for the configuration of the underlying system socket in the
|
||||
StreamingSocket and DatagramSocket classes.
|
||||
|
||||
@see StreamingSocket, DatagramSocket
|
||||
|
||||
@tags{Core}
|
||||
*/
|
||||
class JUCE_API SocketOptions
|
||||
{
|
||||
public:
|
||||
/** The provided size will be used to configure the socket's SO_RCVBUF property. Increasing the
|
||||
buffer size can reduce the number of lost packets with the DatagramSocket class, if the
|
||||
socket is to receive packets in large bursts.
|
||||
|
||||
If this property is not specified, the system default value will be used, but a minimum of
|
||||
65536 will be ensured.
|
||||
*/
|
||||
[[nodiscard]] SocketOptions withReceiveBufferSize (int size) const
|
||||
{
|
||||
return withMember (*this, &SocketOptions::receiveBufferSize, size);
|
||||
}
|
||||
|
||||
/** The provided size will be used to configure the socket's SO_SNDBUF property.
|
||||
|
||||
If this property is not specified, the system default value will be used, but a minimum of
|
||||
65536 will be ensured.
|
||||
*/
|
||||
[[nodiscard]] SocketOptions withSendBufferSize (int size) const
|
||||
{
|
||||
return withMember (*this, &SocketOptions::sendBufferSize, size);
|
||||
}
|
||||
|
||||
/** @see withReceiveBufferSize() */
|
||||
[[nodiscard]] auto getReceiveBufferSize() const { return receiveBufferSize; }
|
||||
|
||||
/** @see withSendBufferSize() */
|
||||
[[nodiscard]] auto getSendBufferSize() const { return sendBufferSize; }
|
||||
|
||||
private:
|
||||
std::optional<int> receiveBufferSize;
|
||||
std::optional<int> sendBufferSize;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A wrapper for a streaming (TCP) socket.
|
||||
|
|
@ -37,6 +81,8 @@ namespace juce
|
|||
class JUCE_API StreamingSocket final
|
||||
{
|
||||
public:
|
||||
using Options = SocketOptions;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an uninitialised socket.
|
||||
|
||||
|
|
@ -49,6 +95,20 @@ public:
|
|||
*/
|
||||
StreamingSocket();
|
||||
|
||||
/** Creates an uninitialised socket and allows specifying options related to the
|
||||
configuration of the underlying socket.
|
||||
|
||||
To connect it, use the connect() method, after which you can read() or write()
|
||||
to it.
|
||||
|
||||
To wait for other sockets to connect to this one, the createListener() method
|
||||
enters "listener" mode, and can be used to spawn new sockets for each connection
|
||||
that comes along.
|
||||
*/
|
||||
explicit StreamingSocket (const SocketOptions& optionsIn)
|
||||
: options { optionsIn }
|
||||
{}
|
||||
|
||||
/** Destructor. */
|
||||
~StreamingSocket();
|
||||
|
||||
|
|
@ -178,12 +238,13 @@ public:
|
|||
|
||||
private:
|
||||
//==============================================================================
|
||||
SocketOptions options;
|
||||
String hostName;
|
||||
std::atomic<int> portNumber { 0 }, handle { -1 };
|
||||
std::atomic<bool> connected { false }, isListener { false };
|
||||
mutable CriticalSection readLock;
|
||||
|
||||
StreamingSocket (const String& hostname, int portNumber, int handle);
|
||||
StreamingSocket (const String& hostname, int portNumber, int handle, const SocketOptions& options);
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StreamingSocket)
|
||||
};
|
||||
|
|
@ -203,7 +264,20 @@ private:
|
|||
class JUCE_API DatagramSocket final
|
||||
{
|
||||
public:
|
||||
using Options = SocketOptions;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a datagram socket and allows specifying options related to the
|
||||
configuration of the underlying socket.
|
||||
|
||||
You first need to bind this socket to a port with bindToPort if you intend to read
|
||||
from this socket.
|
||||
|
||||
If enableBroadcasting is true, the socket will be allowed to send broadcast messages
|
||||
(may require extra privileges on linux)
|
||||
*/
|
||||
DatagramSocket (bool enableBroadcasting, const SocketOptions& optionsIn);
|
||||
|
||||
/** Creates a datagram socket.
|
||||
|
||||
You first need to bind this socket to a port with bindToPort if you intend to read
|
||||
|
|
@ -212,8 +286,19 @@ public:
|
|||
If enableBroadcasting is true, the socket will be allowed to send broadcast messages
|
||||
(may require extra privileges on linux)
|
||||
*/
|
||||
DatagramSocket (bool enableBroadcasting = false);
|
||||
explicit DatagramSocket (bool enableBroadcasting)
|
||||
: DatagramSocket (enableBroadcasting, SocketOptions{})
|
||||
{}
|
||||
|
||||
/** Creates a datagram socket.
|
||||
|
||||
You first need to bind this socket to a port with bindToPort if you intend to read
|
||||
from this socket.
|
||||
|
||||
This constructor creates a socket that does not allow sending broadcast messages.
|
||||
*/
|
||||
DatagramSocket() : DatagramSocket (false)
|
||||
{}
|
||||
|
||||
/** Destructor. */
|
||||
~DatagramSocket();
|
||||
|
|
@ -354,6 +439,7 @@ public:
|
|||
|
||||
private:
|
||||
//==============================================================================
|
||||
SocketOptions options;
|
||||
std::atomic<int> handle { -1 };
|
||||
bool isBound = false;
|
||||
String lastBindAddress, lastServerHost;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue