28JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4127 4389 4018)
31 #define AI_NUMERICSERV 0x1000
35 using juce_socklen_t =
int;
36 using juce_recvsend_size_t =
int;
37 using SocketHandle =
SOCKET;
41 using juce_recvsend_size_t =
size_t;
42 using SocketHandle =
int;
43 static const SocketHandle invalidSocket = -1;
47 using SocketHandle =
int;
48 static const SocketHandle invalidSocket = -1;
52namespace SocketHelpers
54 static void initSockets()
68 inline bool isValidPortNumber (
int port)
noexcept
73 template <
typename Type>
74 static bool setOption (SocketHandle handle,
int mode,
int property, Type value)
noexcept
76 return setsockopt (handle, mode, property,
reinterpret_cast<const char*
> (&value),
sizeof (value)) == 0;
79 template <
typename Type>
80 static bool setOption (SocketHandle handle,
int property, Type value)
noexcept
82 return setOption (handle,
SOL_SOCKET, property, value);
99 static bool resetSocketOptions (SocketHandle handle,
bool isDatagram,
bool allowBroadcast,
const SocketOptions& options)
noexcept
114 return handle != invalidSocket
115 && setOption (handle,
SO_RCVBUF, receiveBufferSize)
116 && setOption (handle,
SO_SNDBUF, sendBufferSize)
127 const auto h = (SocketHandle) handle.load();
131 if (h != invalidSocket || connected)
145 StreamingSocket temp;
161 #if JUCE_LINUX || JUCE_BSD || JUCE_ANDROID
173 static bool bindSocket (SocketHandle handle,
int port,
const String& address)
noexcept
175 if (handle == invalidSocket || ! isValidPortNumber (port))
183 addr.sin_addr.s_addr = address.isNotEmpty() ? ::inet_addr (address.toRawUTF8())
189 static int getBoundPort (SocketHandle handle)
noexcept
191 if (handle != invalidSocket)
196 if (getsockname (handle, (
struct sockaddr*) &
addr, &len) == 0)
197 return ntohs (
addr.sin_port);
203 static String getConnectedAddress (SocketHandle handle)
noexcept
208 if (getpeername (handle, (
struct sockaddr*) &
addr, &len) >= 0)
209 return inet_ntoa (
addr.sin_addr);
214 static bool setSocketBlockingState (SocketHandle handle,
bool shouldBlock)
noexcept
235 static bool getSocketBlockingState (SocketHandle handle)
241 static int readSocket (SocketHandle handle,
245 CriticalSection& readLock,
259 auto buffer =
static_cast<char*
> (
destBuffer) + bytesRead;
299 return (
int) bytesRead;
302 static int waitForReadiness (
std::atomic<int>& handle, CriticalSection& readLock,
308 if (!
lock.isLocked())
313 auto h = (SocketHandle) handle.load();
315 if (h == invalidSocket)
319 juce_socklen_t len =
sizeof (opt);
327 auto h = handle.load();
329 #if JUCE_WINDOWS || JUCE_MINGW
368 if (result >= 0 || errno != EINTR)
379 static addrinfo* getAddressInfo (
bool isDatagram,
const String& hostName,
int portNumber)
386 hints.ai_flags = AI_NUMERICSERV;
390 if (getaddrinfo (hostName.toRawUTF8(), String (portNumber).toRawUTF8(), &
hints, &info) == 0)
397 CriticalSection& readLock,
398 const String& hostName,
401 const SocketOptions& options)
noexcept
403 bool success =
false;
405 if (
auto* info = getAddressInfo (
false, hostName, portNumber))
407 for (
auto* i = info; i !=
nullptr; i = i->ai_next)
413 setSocketBlockingState (
newHandle,
false);
415 success = (result >= 0);
422 if (errno == EINPROGRESS)
450 auto h = (SocketHandle) handle.load();
451 setSocketBlockingState (h,
true);
452 resetSocketOptions (h,
false,
false, options);
459 static void makeReusable (
int handle)
noexcept
461 setOption ((SocketHandle) handle,
SO_REUSEADDR, (
int) 1);
486 SocketHelpers::initSockets();
498 SocketHelpers::initSockets();
499 SocketHelpers::resetSocketOptions ((SocketHandle) h,
false,
false, options);
510 return (connected && ! isListener) ? SocketHelpers::readSocket ((SocketHandle) handle.load(),
destBuffer,
maxBytesToRead,
517 if (isListener || ! connected)
538 jassert (SocketHelpers::isValidPortNumber (port));
540 return SocketHelpers::bindSocket ((SocketHandle) handle.load(), port,
addr);
545 return SocketHelpers::getBoundPort ((SocketHandle) handle.load());
566 connected = SocketHelpers::connectSocket (handle, readLock,
remoteHostName,
572 if (! SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(),
false,
false, options))
584 SocketHelpers::closeSocket (handle, readLock, isListener, portNumber, connected);
600 hostName =
"listener";
610 SocketHelpers::makeReusable (handle);
613 if (SocketHelpers::bindSocket ((SocketHandle) handle.load(), portNumber,
localHostName)
628 jassert (isListener || ! connected);
630 if (connected && isListener)
633 juce_socklen_t len =
sizeof (address);
649 IPAddress currentIP (SocketHelpers::getConnectedAddress ((SocketHandle) handle.load()));
655 return hostName ==
"127.0.0.1";
664 SocketHelpers::initSockets();
670 SocketHelpers::resetSocketOptions ((SocketHandle) handle.load(),
true,
canBroadcast, options);
671 SocketHelpers::makeReusable (handle);
677 if (lastServerAddress !=
nullptr)
692 SocketHelpers::closeSocket (
handleCopy, readLock,
false, 0, connected);
704 jassert (SocketHelpers::isValidPortNumber (port));
709 if (SocketHelpers::bindSocket ((SocketHandle) handle.load(), port,
addr))
712 lastBindAddress =
addr;
721 return (handle >= 0 && isBound) ? SocketHelpers::getBoundPort ((SocketHandle) handle.load()) : -1;
735 if (handle < 0 || ! isBound)
745 if (handle < 0 || ! isBound)
776 return (
int) ::sendto ((SocketHandle) handle.load(), (
const char*)
sourceBuffer,
778 info->ai_addr, (
socklen_t) info->ai_addrlen);
783 if (handle < 0 || ! isBound)
791 if (handle < 0 || ! isBound)
799 if (handle < 0 || ! isBound)
809 return SocketHelpers::setOption ((SocketHandle) handle.load(),
815 (
int) (enabled ? 1 : 0));
821JUCE_END_IGNORE_WARNINGS_MSVC
834 void runTest()
override
839 beginTest (
"StreamingSocket");
846 expect (
static_cast<SocketHandle
> (
socketServer.getRawSocketHandle()) == invalidSocket);
854 expect (
socket.isConnected() ==
true);
856 expect (
socket.getBoundPort() != -1);
857 expect (
static_cast<SocketHandle
> (
socket.getRawSocketHandle()) != invalidSocket);
861 expect (
socket.isConnected() ==
false);
862 expect (
socket.getHostName().isEmpty());
863 expect (
socket.getBoundPort() == -1);
864 expect (
static_cast<SocketHandle
> (
socket.getRawSocketHandle()) == invalidSocket);
867 beginTest (
"DatagramSocket");
871 expect (
socket.getBoundPort() == -1);
872 expect (
static_cast<SocketHandle
> (
socket.getRawSocketHandle()) != invalidSocket);
877 expect (
static_cast<SocketHandle
> (
socket.getRawSocketHandle()) != invalidSocket);
881 expect (
socket.getBoundPort() == -1);
882 expect (
static_cast<SocketHandle
> (
socket.getRawSocketHandle()) == invalidSocket);
GenericScopedLock< CriticalSection > ScopedLockType
Provides the type of scoped lock to use with a CriticalSection.
GenericScopedTryLock< CriticalSection > ScopedTryLockType
Provides the type of scoped try-locker to use with a CriticalSection.
void shutdown()
Closes the underlying socket object.
int write(const String &remoteHostname, int remotePortNumber, const void *sourceBuffer, int numBytesToWrite)
Writes bytes to the socket from a buffer.
int read(void *destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived)
Reads bytes from the socket.
bool setMulticastLoopbackEnabled(bool enableLoopback)
Enables or disables multicast loopback.
bool bindToPort(int localPortNumber)
Binds the socket to the specified local port.
bool leaveMulticast(const String &multicastIPAddress)
Leave a multicast group.
~DatagramSocket()
Destructor.
bool setEnablePortReuse(bool enabled)
Allow other applications to re-use the port.
int waitUntilReady(bool readyForReading, int timeoutMsecs)
Waits until the socket is ready for reading or writing.
bool joinMulticast(const String &multicastIPAddress)
Join a multicast group.
int getBoundPort() const noexcept
Returns the local port number to which this socket is currently bound.
DatagramSocket()
Creates a datagram socket.
Represents an IP address.
static Array< IPAddress > getAllAddresses(bool includeIPv6=false)
Populates a list of all the IP addresses that this machine is using.
static IPAddress local(bool IPv6=false) noexcept
Returns an IPv4 or IPv6 address meaning "localhost", equivalent to 127.0.0.1 (IPv4) or ::1 (IPv6)
Options used for the configuration of the underlying system socket in the StreamingSocket and Datagra...
A wrapper for a streaming (TCP) socket.
int read(void *destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived)
Reads bytes from the socket.
StreamingSocket * waitForNextConnection() const
When in "listener" mode, this waits for a connection and spawns it as a new socket.
int write(const void *sourceBuffer, int numBytesToWrite)
Writes bytes to the socket from a buffer.
bool isLocal() const noexcept
True if the socket is connected to this machine rather than over the network.
~StreamingSocket()
Destructor.
int waitUntilReady(bool readyForReading, int timeoutMsecs)
Waits until the socket is ready for reading or writing.
bool createListener(int portNumber, const String &localHostName=String())
Puts this socket into "listener" mode.
int getBoundPort() const noexcept
Returns the local port number to which this socket is currently bound.
StreamingSocket()
Creates an uninitialised socket.
bool bindToPort(int localPortNumber)
Binds the socket to the specified local port.
void close()
Closes the connection.
bool connect(const String &remoteHostname, int remotePortNumber, int timeOutMillisecs=3000)
Tries to connect the socket to hostname:port.
bool isConnected() const noexcept
True if the socket is currently connected.
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Creates a String from a UTF-8 encoded buffer.
This is a base class for classes that perform a unit test.
void zerostruct(Type &structure) noexcept
Overwrites a structure or object with zeros.
unsigned short uint16
A platform-independent 16-bit unsigned integer type.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
bool isPositiveAndBelow(Type1 valueToTest, Type2 upperLimit) noexcept
Returns true if a value is at least zero, and also below a specified upper limit.
std::u16string toString(NumberT value)
convert an number to an UTF-16 string