27 #pragma warning (push)
28 #pragma warning (disable : 4127 4389 4018)
31 #ifndef AI_NUMERICSERV // (missing in older Mac SDKs)
32 #define AI_NUMERICSERV 0x1000
36 typedef int juce_socklen_t;
37 typedef int juce_recvsend_size_t;
38 typedef SOCKET SocketHandle;
39 static const SocketHandle invalidSocket = INVALID_SOCKET;
41 typedef socklen_t juce_socklen_t;
42 typedef size_t juce_recvsend_size_t;
43 typedef int SocketHandle;
44 static const SocketHandle invalidSocket = -1;
46 typedef socklen_t juce_socklen_t;
47 typedef socklen_t juce_recvsend_size_t;
48 typedef int SocketHandle;
49 static const SocketHandle invalidSocket = -1;
53 namespace SocketHelpers
55 static void initSockets()
58 static bool socketsStarted =
false;
62 socketsStarted =
true;
65 const WORD wVersionRequested = MAKEWORD (1, 1);
66 WSAStartup (wVersionRequested, &wsaData);
71 inline bool isValidPortNumber (
int port) noexcept
73 return isPositiveAndBelow (port, 65536);
76 template <
typename Type>
77 static bool setOption (SocketHandle handle,
int mode,
int property, Type value) noexcept
79 return setsockopt (handle, mode, property,
reinterpret_cast<const char*
> (&value),
sizeof (value)) == 0;
82 template <
typename Type>
83 static bool setOption (SocketHandle handle,
int property, Type value) noexcept
85 return setOption (handle, SOL_SOCKET, property, value);
88 static bool resetSocketOptions (SocketHandle handle,
bool isDatagram,
bool allowBroadcast) noexcept
91 && setOption (handle, SO_RCVBUF, (
int) 65536)
92 && setOption (handle, SO_SNDBUF, (
int) 65536)
93 && (isDatagram ? ((! allowBroadcast) || setOption (handle, SO_BROADCAST, (
int) 1))
94 : setOption (handle, IPPROTO_TCP, TCP_NODELAY, (int) 1));
97 static void closeSocket (std::atomic<int>& handle, CriticalSection& readLock,
98 bool isListener,
int portNumber, std::atomic<bool>& connected) noexcept
100 const SocketHandle h = handle.load();
104 ignoreUnused (portNumber, isListener, readLock);
106 if (h != (
unsigned) SOCKET_ERROR || connected)
120 StreamingSocket temp;
121 temp.connect (IPAddress::local().toString(), portNumber, 1000);
128 ::shutdown (h, SHUT_RDWR);
136 #if JUCE_LINUX || JUCE_ANDROID
148 static bool bindSocket (SocketHandle handle,
int port,
const String& address) noexcept
150 if (handle <= 0 || ! isValidPortNumber (port))
153 struct sockaddr_in addr;
156 addr.sin_family = PF_INET;
157 addr.sin_port = htons ((uint16) port);
158 addr.sin_addr.s_addr = address.isNotEmpty() ? ::inet_addr (address.toRawUTF8())
159 : htonl (INADDR_ANY);
161 return ::bind (handle, (
struct sockaddr*) &addr,
sizeof (addr)) >= 0;
164 static int getBoundPort (SocketHandle handle) noexcept
168 struct sockaddr_in addr;
169 socklen_t len =
sizeof (addr);
171 if (getsockname (handle, (
struct sockaddr*) &addr, &len) == 0)
172 return ntohs (addr.sin_port);
178 static String getConnectedAddress (SocketHandle handle) noexcept
180 struct sockaddr_in addr;
181 socklen_t len =
sizeof (addr);
183 if (getpeername (handle, (
struct sockaddr*) &addr, &len) >= 0)
184 return inet_ntoa (addr.sin_addr);
186 return String (
"0.0.0.0");
189 static int readSocket (SocketHandle handle,
190 void* destBuffer,
int maxBytesToRead,
191 std::atomic<bool>& connected,
192 bool blockUntilSpecifiedAmountHasArrived,
193 CriticalSection& readLock,
194 String* senderIP =
nullptr,
195 int* senderPort =
nullptr) noexcept
199 while (bytesRead < maxBytesToRead)
201 long bytesThisTime = -1;
202 auto buffer =
static_cast<char*
> (destBuffer) + bytesRead;
203 auto numToRead = (juce_recvsend_size_t) (maxBytesToRead - bytesRead);
211 if (senderIP ==
nullptr || senderPort ==
nullptr)
213 bytesThisTime = ::recv (handle, buffer, numToRead, 0);
218 socklen_t clientLen =
sizeof (sockaddr);
220 bytesThisTime = ::recvfrom (handle, buffer, numToRead, 0, (sockaddr*) &client, &clientLen);
223 *senderPort = ntohs (client.sin_port);
228 if (bytesThisTime <= 0 || ! connected)
230 if (bytesRead == 0 && blockUntilSpecifiedAmountHasArrived)
236 bytesRead += bytesThisTime;
238 if (! blockUntilSpecifiedAmountHasArrived)
242 return (
int) bytesRead;
245 static int waitForReadiness (std::atomic<int>& handle, CriticalSection& readLock,
246 bool forReading,
int timeoutMsecs) noexcept
251 if (! lock.isLocked())
254 int h = handle.load();
256 struct timeval timeout;
257 struct timeval* timeoutp;
259 if (timeoutMsecs >= 0)
261 timeout.tv_sec = timeoutMsecs / 1000;
262 timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
276 fd_set*
const prset = forReading ? &rset :
nullptr;
277 fd_set*
const pwset = forReading ? nullptr : &wset;
280 if (select ((
int) h + 1, prset, pwset, 0, timeoutp) < 0)
286 while ((result = select (h + 1, prset, pwset,
nullptr, timeoutp)) < 0
297 if (handle.load() < 0)
302 juce_socklen_t len =
sizeof (opt);
304 if (getsockopt (h, SOL_SOCKET, SO_ERROR, (
char*) &opt, &len) < 0
309 return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0;
312 static bool setSocketBlockingState (SocketHandle handle,
bool shouldBlock) noexcept
315 u_long nonBlocking = shouldBlock ? 0 : (u_long) 1;
316 return ioctlsocket (handle, FIONBIO, &nonBlocking) == 0;
318 int socketFlags = fcntl (handle, F_GETFL, 0);
320 if (socketFlags == -1)
324 socketFlags &= ~O_NONBLOCK;
326 socketFlags |= O_NONBLOCK;
328 return fcntl (handle, F_SETFL, socketFlags) == 0;
332 static addrinfo* getAddressInfo (
bool isDatagram,
const String& hostName,
int portNumber)
334 struct addrinfo hints;
337 hints.ai_family = AF_UNSPEC;
338 hints.ai_socktype = isDatagram ? SOCK_DGRAM : SOCK_STREAM;
339 hints.ai_flags = AI_NUMERICSERV;
341 struct addrinfo* info =
nullptr;
343 if (getaddrinfo (hostName.toRawUTF8(), String (portNumber).toRawUTF8(), &hints, &info) == 0)
349 static bool connectSocket (std::atomic<int>& handle,
350 CriticalSection& readLock,
351 const String& hostName,
353 int timeOutMillisecs) noexcept
355 bool success =
false;
357 if (
auto* info = getAddressInfo (
false, hostName, portNumber))
359 for (
auto* i = info; i !=
nullptr; i = i->ai_next)
361 auto newHandle = socket (i->ai_family, i->ai_socktype, 0);
363 if (newHandle != invalidSocket)
365 setSocketBlockingState (newHandle,
false);
366 auto result = ::connect (newHandle, i->ai_addr, (socklen_t) i->ai_addrlen);
367 success = (result >= 0);
372 if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
374 if (errno == EINPROGRESS)
377 std::atomic<int> cvHandle { (int) newHandle };
379 if (waitForReadiness (cvHandle, readLock,
false, timeOutMillisecs) == 1)
386 handle = (int) newHandle;
391 closesocket (newHandle);
402 setSocketBlockingState (handle,
true);
403 resetSocketOptions (handle,
false,
false);
410 static void makeReusable (
int handle) noexcept
412 setOption (handle, SO_REUSEADDR, (
int) 1);
415 static bool multicast (
int handle,
const String& multicastIPAddress,
416 const String& interfaceIPAddress,
bool join) noexcept
421 mreq.imr_multiaddr.s_addr = inet_addr (multicastIPAddress.toRawUTF8());
422 mreq.imr_interface.s_addr = INADDR_ANY;
424 if (interfaceIPAddress.isNotEmpty())
425 mreq.imr_interface.s_addr = inet_addr (interfaceIPAddress.toRawUTF8());
427 return setsockopt (handle, IPPROTO_IP,
428 join ? IP_ADD_MEMBERSHIP
429 : IP_DROP_MEMBERSHIP,
430 (
const char*) &mreq,
sizeof (mreq)) == 0;
437 SocketHelpers::initSockets();
442 portNumber (portNum),
446 jassert (SocketHelpers::isValidPortNumber (portNum));
448 SocketHelpers::initSockets();
449 SocketHelpers::resetSocketOptions (h,
false,
false);
460 return (connected && ! isListener) ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
461 connected, shouldBlock, readLock)
467 if (isListener || ! connected)
470 return (
int) ::send (handle, (
const char*) sourceBuffer, (juce_recvsend_size_t) numBytesToWrite, 0);
476 return connected ? SocketHelpers::waitForReadiness (handle, readLock, readyForReading, timeoutMsecs)
488 jassert (SocketHelpers::isValidPortNumber (port));
490 return SocketHelpers::bindSocket (handle, port, addr);
495 return SocketHelpers::getBoundPort (handle);
500 jassert (SocketHelpers::isValidPortNumber (remotePortNumber));
511 hostName = remoteHostName;
512 portNumber = remotePortNumber;
515 connected = SocketHelpers::connectSocket (handle, readLock, remoteHostName,
516 remotePortNumber, timeOutMillisecs);
518 if (! (connected && SocketHelpers::resetSocketOptions (handle,
false,
false)))
529 SocketHelpers::closeSocket (handle, readLock, isListener, portNumber, connected);
540 jassert (SocketHelpers::isValidPortNumber (newPortNumber));
545 hostName =
"listener";
546 portNumber = newPortNumber;
549 handle = (int) socket (AF_INET, SOCK_STREAM, 0);
554 #if ! JUCE_WINDOWS // on windows, adding this option produces behaviour different to posix
555 SocketHelpers::makeReusable (handle);
558 if (SocketHelpers::bindSocket (handle, portNumber, localHostName)
559 && listen (handle, SOMAXCONN) >= 0)
573 jassert (isListener || ! connected);
575 if (connected && isListener)
577 struct sockaddr_storage address;
578 juce_socklen_t len =
sizeof (address);
579 auto newSocket = (int) accept (handle, (
struct sockaddr*) &address, &len);
581 if (newSocket >= 0 && connected)
582 return new StreamingSocket (inet_ntoa (((
struct sockaddr_in*) &address)->sin_addr),
583 portNumber, newSocket);
594 IPAddress currentIP (SocketHelpers::getConnectedAddress (handle));
600 return hostName ==
"127.0.0.1";
608 SocketHelpers::initSockets();
610 handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
614 SocketHelpers::resetSocketOptions (handle,
true, canBroadcast);
615 SocketHelpers::makeReusable (handle);
621 if (lastServerAddress !=
nullptr)
622 freeaddrinfo (
static_cast<struct addrinfo*
> (lastServerAddress));
632 std::atomic<int> handleCopy { handle.load() };
634 std::atomic<bool> connected {
false };
635 SocketHelpers::closeSocket (handleCopy, readLock,
false, 0, connected);
645 jassert (SocketHelpers::isValidPortNumber (port));
647 if (SocketHelpers::bindSocket (handle, port, addr))
650 lastBindAddress = addr;
659 return (handle >= 0 && isBound) ? SocketHelpers::getBoundPort (handle) : -1;
668 return SocketHelpers::waitForReadiness (handle, readLock, readyForReading, timeoutMsecs);
673 if (handle < 0 || ! isBound)
676 std::atomic<bool> connected {
true };
678 SocketHelpers::setSocketBlockingState (handle, shouldBlock);
679 return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
680 connected, shouldBlock, readLock);
685 if (handle < 0 || ! isBound)
688 std::atomic<bool> connected {
true };
690 SocketHelpers::setSocketBlockingState (handle, shouldBlock);
691 return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, connected,
692 shouldBlock, readLock, &senderIPAddress, &senderPort);
696 const void* sourceBuffer,
int numBytesToWrite)
698 jassert (SocketHelpers::isValidPortNumber (remotePortNumber));
703 struct addrinfo*& info =
reinterpret_cast<struct addrinfo*&
> (lastServerAddress);
706 if (info ==
nullptr || remoteHostname != lastServerHost || remotePortNumber != lastServerPort)
711 if ((info = SocketHelpers::getAddressInfo (
true, remoteHostname, remotePortNumber)) ==
nullptr)
714 lastServerHost = remoteHostname;
715 lastServerPort = remotePortNumber;
718 return (
int) ::sendto (handle, (
const char*) sourceBuffer,
719 (juce_recvsend_size_t) numBytesToWrite, 0,
720 info->ai_addr, (socklen_t) info->ai_addrlen);
725 if (! isBound || handle < 0)
728 return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress,
true);
733 if (! isBound || handle < 0)
736 return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress,
false);
741 if (! isBound || handle < 0)
744 return SocketHelpers::setOption<bool> (handle, IPPROTO_IP, IP_MULTICAST_LOOP, enable);
750 ignoreUnused (enabled);
753 return SocketHelpers::setOption (handle,
754 #
if JUCE_WINDOWS || JUCE_LINUX
759 (
int) (enabled ? 1 : 0));
766 #pragma warning (pop)