OpenShot Audio Library | OpenShotAudio: juce_Socket.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.0

Loading...
Searching...
No Matches
juce_Socket.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26#if JUCE_MSVC
27 #pragma warning (push)
28 #pragma warning (disable : 4127 4389 4018)
29#endif
30
31#ifndef AI_NUMERICSERV // (missing in older Mac SDKs)
32 #define AI_NUMERICSERV 0x1000
33#endif
34
35#if JUCE_WINDOWS
36 using juce_socklen_t = int;
37 using juce_recvsend_size_t = int;
38 using SocketHandle = SOCKET;
39 static const SocketHandle invalidSocket = INVALID_SOCKET;
40#elif JUCE_ANDROID
41 using juce_socklen_t = socklen_t;
42 using juce_recvsend_size_t = size_t;
43 using SocketHandle = int;
44 static const SocketHandle invalidSocket = -1;
45#else
46 using juce_socklen_t = socklen_t;
47 using juce_recvsend_size_t = socklen_t;
48 using SocketHandle = int;
49 static const SocketHandle invalidSocket = -1;
50#endif
51
52//==============================================================================
53namespace SocketHelpers
54{
55 static void initSockets()
56 {
57 #if JUCE_WINDOWS
58 static bool socketsStarted = false;
59
60 if (! socketsStarted)
61 {
62 socketsStarted = true;
63
64 WSADATA wsaData;
65 const WORD wVersionRequested = MAKEWORD (1, 1);
66 WSAStartup (wVersionRequested, &wsaData);
67 }
68 #endif
69 }
70
71 inline bool isValidPortNumber (int port) noexcept
72 {
73 return isPositiveAndBelow (port, 65536);
74 }
75
76 template <typename Type>
77 static bool setOption (SocketHandle handle, int mode, int property, Type value) noexcept
78 {
79 return setsockopt (handle, mode, property, reinterpret_cast<const char*> (&value), sizeof (value)) == 0;
80 }
81
82 template <typename Type>
83 static bool setOption (SocketHandle handle, int property, Type value) noexcept
84 {
85 return setOption (handle, SOL_SOCKET, property, value);
86 }
87
88 static bool resetSocketOptions (SocketHandle handle, bool isDatagram, bool allowBroadcast) noexcept
89 {
90 return handle != invalidSocket
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));
95 }
96
97 static void closeSocket (std::atomic<int>& handle, CriticalSection& readLock,
98 bool isListener, int portNumber, std::atomic<bool>& connected) noexcept
99 {
100 const SocketHandle h = handle.load();
101 handle = -1;
102
103 #if JUCE_WINDOWS
104 ignoreUnused (portNumber, isListener, readLock);
105
106 if (h != invalidSocket || connected)
107 closesocket (h);
108
109 // make sure any read process finishes before we delete the socket
110 CriticalSection::ScopedLockType lock (readLock);
111 connected = false;
112 #else
113 if (connected)
114 {
115 connected = false;
116
117 if (isListener)
118 {
119 // need to do this to interrupt the accept() function..
120 StreamingSocket temp;
121 temp.connect (IPAddress::local().toString(), portNumber, 1000);
122 }
123 }
124
125 if (h >= 0)
126 {
127 // unblock any pending read requests
128 ::shutdown (h, SHUT_RDWR);
129
130 {
131 // see man-page of recv on linux about a race condition where the
132 // shutdown command is lost if the receiving thread does not have
133 // a chance to process before close is called. On Mac OS X shutdown
134 // does not unblock a select call, so using a lock here will dead-lock
135 // both threads.
136 #if JUCE_LINUX || JUCE_ANDROID
137 CriticalSection::ScopedLockType lock (readLock);
138 ::close (h);
139 #else
140 ::close (h);
141 CriticalSection::ScopedLockType lock (readLock);
142 #endif
143 }
144 }
145 #endif
146 }
147
148 static bool bindSocket (SocketHandle handle, int port, const String& address) noexcept
149 {
150 if (handle == invalidSocket || ! isValidPortNumber (port))
151 return false;
152
153 struct sockaddr_in addr;
154 zerostruct (addr); // (can't use "= { 0 }" on this object because it's typedef'ed as a C struct)
155
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);
160
161 return ::bind (handle, (struct sockaddr*) &addr, sizeof (addr)) >= 0;
162 }
163
164 static int getBoundPort (SocketHandle handle) noexcept
165 {
166 if (handle != invalidSocket)
167 {
168 struct sockaddr_in addr;
169 socklen_t len = sizeof (addr);
170
171 if (getsockname (handle, (struct sockaddr*) &addr, &len) == 0)
172 return ntohs (addr.sin_port);
173 }
174
175 return -1;
176 }
177
178 static String getConnectedAddress (SocketHandle handle) noexcept
179 {
180 struct sockaddr_in addr;
181 socklen_t len = sizeof (addr);
182
183 if (getpeername (handle, (struct sockaddr*) &addr, &len) >= 0)
184 return inet_ntoa (addr.sin_addr);
185
186 return "0.0.0.0";
187 }
188
189 static bool setSocketBlockingState (SocketHandle handle, bool shouldBlock) noexcept
190 {
191 #if JUCE_WINDOWS
192 u_long nonBlocking = shouldBlock ? 0 : (u_long) 1;
193 return ioctlsocket (handle, FIONBIO, &nonBlocking) == 0;
194 #else
195 int socketFlags = fcntl (handle, F_GETFL, 0);
196
197 if (socketFlags == -1)
198 return false;
199
200 if (shouldBlock)
201 socketFlags &= ~O_NONBLOCK;
202 else
203 socketFlags |= O_NONBLOCK;
204
205 return fcntl (handle, F_SETFL, socketFlags) == 0;
206 #endif
207 }
208
209 #if ! JUCE_WINDOWS
210 static bool getSocketBlockingState (SocketHandle handle)
211 {
212 return (fcntl (handle, F_GETFL, 0) & O_NONBLOCK) == 0;
213 }
214 #endif
215
216 static int readSocket (SocketHandle handle,
217 void* destBuffer, int maxBytesToRead,
218 std::atomic<bool>& connected,
219 bool blockUntilSpecifiedAmountHasArrived,
220 CriticalSection& readLock,
221 String* senderIP = nullptr,
222 int* senderPort = nullptr) noexcept
223 {
224 #if ! JUCE_WINDOWS
225 if (blockUntilSpecifiedAmountHasArrived != getSocketBlockingState (handle))
226 #endif
227 setSocketBlockingState (handle, blockUntilSpecifiedAmountHasArrived);
228
229 int bytesRead = 0;
230
231 while (bytesRead < maxBytesToRead)
232 {
233 long bytesThisTime = -1;
234 auto buffer = static_cast<char*> (destBuffer) + bytesRead;
235 auto numToRead = (juce_recvsend_size_t) (maxBytesToRead - bytesRead);
236
237 {
238 // avoid race-condition
239 CriticalSection::ScopedTryLockType lock (readLock);
240
241 if (lock.isLocked())
242 {
243 if (senderIP == nullptr || senderPort == nullptr)
244 {
245 bytesThisTime = ::recv (handle, buffer, numToRead, 0);
246 }
247 else
248 {
249 sockaddr_in client;
250 socklen_t clientLen = sizeof (sockaddr);
251
252 bytesThisTime = ::recvfrom (handle, buffer, numToRead, 0, (sockaddr*) &client, &clientLen);
253
254 *senderIP = String::fromUTF8 (inet_ntoa (client.sin_addr), 16);
255 *senderPort = ntohs (client.sin_port);
256 }
257 }
258 }
259
260 if (bytesThisTime <= 0 || ! connected)
261 {
262 if (bytesRead == 0 && blockUntilSpecifiedAmountHasArrived)
263 bytesRead = -1;
264
265 break;
266 }
267
268 bytesRead += bytesThisTime;
269
270 if (! blockUntilSpecifiedAmountHasArrived)
271 break;
272 }
273
274 return (int) bytesRead;
275 }
276
277 static int waitForReadiness (std::atomic<int>& handle, CriticalSection& readLock,
278 bool forReading, int timeoutMsecs) noexcept
279 {
280 // avoid race-condition
281 CriticalSection::ScopedTryLockType lock (readLock);
282
283 if (! lock.isLocked())
284 return -1;
285
286 auto hasErrorOccurred = [&handle] () -> bool
287 {
288 auto h = handle.load();
289
290 if (h == invalidSocket)
291 return true;
292
293 int opt;
294 juce_socklen_t len = sizeof (opt);
295
296 if (getsockopt (h, SOL_SOCKET, SO_ERROR, (char*) &opt, &len) < 0 || opt != 0)
297 return true;
298
299 return false;
300 };
301
302 auto h = handle.load();
303
304 #if JUCE_WINDOWS || JUCE_MINGW
305 struct timeval timeout;
306 struct timeval* timeoutp;
307
308 if (timeoutMsecs >= 0)
309 {
310 timeout.tv_sec = timeoutMsecs / 1000;
311 timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
312 timeoutp = &timeout;
313 }
314 else
315 {
316 timeoutp = nullptr;
317 }
318
319 fd_set rset, wset;
320 FD_ZERO (&rset);
321 FD_SET (h, &rset);
322 FD_ZERO (&wset);
323 FD_SET (h, &wset);
324
325 fd_set* prset = forReading ? &rset : nullptr;
326 fd_set* pwset = forReading ? nullptr : &wset;
327
328 // NB - need to use select() here as WSAPoll is broken on Windows
329 if (select ((int) h + 1, prset, pwset, nullptr, timeoutp) < 0 || hasErrorOccurred())
330 return -1;
331
332 return FD_ISSET (h, forReading ? &rset : &wset) ? 1 : 0;
333 #else
334 short eventsFlag = (forReading ? POLLIN : POLLOUT);
335 pollfd pfd { (SocketHandle) h, eventsFlag, 0 };
336
337 int result = 0;
338
339 for (;;)
340 {
341 result = poll (&pfd, 1, timeoutMsecs);
342
343 if (result >= 0 || errno != EINTR)
344 break;
345 }
346
347 if (result < 0 || hasErrorOccurred())
348 return -1;
349
350 return (pfd.revents & eventsFlag) != 0;
351 #endif
352 }
353
354 static addrinfo* getAddressInfo (bool isDatagram, const String& hostName, int portNumber)
355 {
356 struct addrinfo hints;
357 zerostruct (hints);
358
359 hints.ai_family = AF_UNSPEC;
360 hints.ai_socktype = isDatagram ? SOCK_DGRAM : SOCK_STREAM;
361 hints.ai_flags = AI_NUMERICSERV;
362
363 struct addrinfo* info = nullptr;
364
365 if (getaddrinfo (hostName.toRawUTF8(), String (portNumber).toRawUTF8(), &hints, &info) == 0)
366 return info;
367
368 return nullptr;
369 }
370
371 static bool connectSocket (std::atomic<int>& handle,
372 CriticalSection& readLock,
373 const String& hostName,
374 int portNumber,
375 int timeOutMillisecs) noexcept
376 {
377 bool success = false;
378
379 if (auto* info = getAddressInfo (false, hostName, portNumber))
380 {
381 for (auto* i = info; i != nullptr; i = i->ai_next)
382 {
383 auto newHandle = socket (i->ai_family, i->ai_socktype, 0);
384
385 if (newHandle != invalidSocket)
386 {
387 setSocketBlockingState (newHandle, false);
388 auto result = ::connect (newHandle, i->ai_addr, (socklen_t) i->ai_addrlen);
389 success = (result >= 0);
390
391 if (! success)
392 {
393 #if JUCE_WINDOWS
394 if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
395 #else
396 if (errno == EINPROGRESS)
397 #endif
398 {
399 std::atomic<int> cvHandle { (int) newHandle };
400
401 if (waitForReadiness (cvHandle, readLock, false, timeOutMillisecs) == 1)
402 success = true;
403 }
404 }
405
406 if (success)
407 {
408 handle = (int) newHandle;
409 break;
410 }
411
412 #if JUCE_WINDOWS
413 closesocket (newHandle);
414 #else
415 ::close (newHandle);
416 #endif
417 }
418 }
419
420 freeaddrinfo (info);
421
422 if (success)
423 {
424 setSocketBlockingState (handle, true);
425 resetSocketOptions (handle, false, false);
426 }
427 }
428
429 return success;
430 }
431
432 static void makeReusable (int handle) noexcept
433 {
434 setOption (handle, SO_REUSEADDR, (int) 1);
435 }
436
437 static bool multicast (int handle, const String& multicastIPAddress,
438 const String& interfaceIPAddress, bool join) noexcept
439 {
440 struct ip_mreq mreq;
441
442 zerostruct (mreq);
443 mreq.imr_multiaddr.s_addr = inet_addr (multicastIPAddress.toRawUTF8());
444 mreq.imr_interface.s_addr = INADDR_ANY;
445
446 if (interfaceIPAddress.isNotEmpty())
447 mreq.imr_interface.s_addr = inet_addr (interfaceIPAddress.toRawUTF8());
448
449 return setsockopt (handle, IPPROTO_IP,
450 join ? IP_ADD_MEMBERSHIP
451 : IP_DROP_MEMBERSHIP,
452 (const char*) &mreq, sizeof (mreq)) == 0;
453 }
454}
455
456//==============================================================================
457StreamingSocket::StreamingSocket()
458{
459 SocketHelpers::initSockets();
460}
461
462 StreamingSocket::StreamingSocket (const String& host, int portNum, int h)
463 : hostName (host),
464 portNumber (portNum),
465 handle (h),
466 connected (true)
467{
468 jassert (SocketHelpers::isValidPortNumber (portNum));
469
470 SocketHelpers::initSockets();
471 SocketHelpers::resetSocketOptions (h, false, false);
472}
473
474StreamingSocket::~StreamingSocket()
475{
476 close();
477}
478
479//==============================================================================
480 int StreamingSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock)
481{
482 return (connected && ! isListener) ? SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
483 connected, shouldBlock, readLock)
484 : -1;
485}
486
487 int StreamingSocket::write (const void* sourceBuffer, int numBytesToWrite)
488{
489 if (isListener || ! connected)
490 return -1;
491
492 return (int) ::send (handle, (const char*) sourceBuffer, (juce_recvsend_size_t) numBytesToWrite, 0);
493}
494
495//==============================================================================
496 int StreamingSocket::waitUntilReady (bool readyForReading, int timeoutMsecs)
497{
498 return connected ? SocketHelpers::waitForReadiness (handle, readLock, readyForReading, timeoutMsecs)
499 : -1;
500}
501
502//==============================================================================
503 bool StreamingSocket::bindToPort (int port)
504{
505 return bindToPort (port, String());
506}
507
508 bool StreamingSocket::bindToPort (int port, const String& addr)
509{
510 jassert (SocketHelpers::isValidPortNumber (port));
511
512 return SocketHelpers::bindSocket (handle, port, addr);
513}
514
515 int StreamingSocket::getBoundPort() const noexcept
516{
517 return SocketHelpers::getBoundPort (handle);
518}
519
520 bool StreamingSocket::connect (const String& remoteHostName, int remotePortNumber, int timeOutMillisecs)
521{
522 jassert (SocketHelpers::isValidPortNumber (remotePortNumber));
523
524 if (isListener)
525 {
526 // a listener socket can't connect to another one!
527 jassertfalse;
528 return false;
529 }
530
531 if (connected)
532 close();
533
534 hostName = remoteHostName;
535 portNumber = remotePortNumber;
536 isListener = false;
537
538 connected = SocketHelpers::connectSocket (handle, readLock, remoteHostName,
539 remotePortNumber, timeOutMillisecs);
540
541 if (! connected)
542 return false;
543
544 if (! SocketHelpers::resetSocketOptions (handle, false, false))
545 {
546 close();
547 return false;
548 }
549
550 return true;
551}
552
553 void StreamingSocket::close()
554{
555 if (handle >= 0)
556 SocketHelpers::closeSocket (handle, readLock, isListener, portNumber, connected);
557
558 hostName.clear();
559 portNumber = 0;
560 handle = -1;
561 isListener = false;
562}
563
564//==============================================================================
565 bool StreamingSocket::createListener (int newPortNumber, const String& localHostName)
566{
567 jassert (SocketHelpers::isValidPortNumber (newPortNumber));
568
569 if (connected)
570 close();
571
572 hostName = "listener";
573 portNumber = newPortNumber;
574 isListener = true;
575
576 handle = (int) socket (AF_INET, SOCK_STREAM, 0);
577
578 if (handle < 0)
579 return false;
580
581 #if ! JUCE_WINDOWS // on windows, adding this option produces behaviour different to posix
582 SocketHelpers::makeReusable (handle);
583 #endif
584
585 if (SocketHelpers::bindSocket (handle, portNumber, localHostName)
586 && listen (handle, SOMAXCONN) >= 0)
587 {
588 connected = true;
589 return true;
590 }
591
592 close();
593 return false;
594}
595
596 StreamingSocket* StreamingSocket::waitForNextConnection() const
597{
598 // To call this method, you first have to use createListener() to
599 // prepare this socket as a listener.
600 jassert (isListener || ! connected);
601
602 if (connected && isListener)
603 {
604 struct sockaddr_storage address;
605 juce_socklen_t len = sizeof (address);
606 auto newSocket = (int) accept (handle, (struct sockaddr*) &address, &len);
607
608 if (newSocket >= 0 && connected)
609 return new StreamingSocket (inet_ntoa (((struct sockaddr_in*) &address)->sin_addr),
610 portNumber, newSocket);
611 }
612
613 return nullptr;
614}
615
616 bool StreamingSocket::isLocal() const noexcept
617{
618 if (! isConnected())
619 return false;
620
621 IPAddress currentIP (SocketHelpers::getConnectedAddress (handle));
622
623 for (auto& a : IPAddress::getAllAddresses())
624 if (a == currentIP)
625 return true;
626
627 return hostName == "127.0.0.1";
628}
629
630
631//==============================================================================
632//==============================================================================
633DatagramSocket::DatagramSocket (bool canBroadcast)
634{
635 SocketHelpers::initSockets();
636
637 handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
638
639 if (handle >= 0)
640 {
641 SocketHelpers::resetSocketOptions (handle, true, canBroadcast);
642 SocketHelpers::makeReusable (handle);
643 }
644}
645
646DatagramSocket::~DatagramSocket()
647{
648 if (lastServerAddress != nullptr)
649 freeaddrinfo (static_cast<struct addrinfo*> (lastServerAddress));
650
651 shutdown();
652}
653
654 void DatagramSocket::shutdown()
655{
656 if (handle < 0)
657 return;
658
659 std::atomic<int> handleCopy { handle.load() };
660 handle = -1;
661
662 std::atomic<bool> connected { false };
663 SocketHelpers::closeSocket (handleCopy, readLock, false, 0, connected);
664
665 isBound = false;
666}
667
668 bool DatagramSocket::bindToPort (int port)
669{
670 return bindToPort (port, String());
671}
672
673 bool DatagramSocket::bindToPort (int port, const String& addr)
674{
675 jassert (SocketHelpers::isValidPortNumber (port));
676
677 if (handle < 0)
678 return false;
679
680 if (SocketHelpers::bindSocket (handle, port, addr))
681 {
682 isBound = true;
683 lastBindAddress = addr;
684 return true;
685 }
686
687 return false;
688}
689
690 int DatagramSocket::getBoundPort() const noexcept
691{
692 return (handle >= 0 && isBound) ? SocketHelpers::getBoundPort (handle) : -1;
693}
694
695//==============================================================================
696 int DatagramSocket::waitUntilReady (bool readyForReading, int timeoutMsecs)
697{
698 if (handle < 0)
699 return -1;
700
701 return SocketHelpers::waitForReadiness (handle, readLock, readyForReading, timeoutMsecs);
702}
703
704 int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock)
705{
706 if (handle < 0 || ! isBound)
707 return -1;
708
709 std::atomic<bool> connected { true };
710 return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead,
711 connected, shouldBlock, readLock);
712}
713
714 int DatagramSocket::read (void* destBuffer, int maxBytesToRead, bool shouldBlock, String& senderIPAddress, int& senderPort)
715{
716 if (handle < 0 || ! isBound)
717 return -1;
718
719 std::atomic<bool> connected { true };
720 return SocketHelpers::readSocket (handle, destBuffer, maxBytesToRead, connected,
721 shouldBlock, readLock, &senderIPAddress, &senderPort);
722}
723
724 int DatagramSocket::write (const String& remoteHostname, int remotePortNumber,
725 const void* sourceBuffer, int numBytesToWrite)
726{
727 jassert (SocketHelpers::isValidPortNumber (remotePortNumber));
728
729 if (handle < 0)
730 return -1;
731
732 struct addrinfo*& info = reinterpret_cast<struct addrinfo*&> (lastServerAddress);
733
734 // getaddrinfo can be quite slow so cache the result of the address lookup
735 if (info == nullptr || remoteHostname != lastServerHost || remotePortNumber != lastServerPort)
736 {
737 if (info != nullptr)
738 freeaddrinfo (info);
739
740 if ((info = SocketHelpers::getAddressInfo (true, remoteHostname, remotePortNumber)) == nullptr)
741 return -1;
742
743 lastServerHost = remoteHostname;
744 lastServerPort = remotePortNumber;
745 }
746
747 return (int) ::sendto (handle, (const char*) sourceBuffer,
748 (juce_recvsend_size_t) numBytesToWrite, 0,
749 info->ai_addr, (socklen_t) info->ai_addrlen);
750}
751
752 bool DatagramSocket::joinMulticast (const String& multicastIPAddress)
753{
754 if (handle < 0 || ! isBound)
755 return false;
756
757 return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress, true);
758}
759
760 bool DatagramSocket::leaveMulticast (const String& multicastIPAddress)
761{
762 if (handle < 0 || ! isBound)
763 return false;
764
765 return SocketHelpers::multicast (handle, multicastIPAddress, lastBindAddress, false);
766}
767
768 bool DatagramSocket::setMulticastLoopbackEnabled (bool enable)
769{
770 if (handle < 0 || ! isBound)
771 return false;
772
773 return SocketHelpers::setOption<bool> (handle, IPPROTO_IP, IP_MULTICAST_LOOP, enable);
774}
775
776 bool DatagramSocket::setEnablePortReuse (bool enabled)
777{
778 #if JUCE_ANDROID
779 ignoreUnused (enabled);
780 #else
781 if (handle >= 0)
782 return SocketHelpers::setOption (handle,
783 #if JUCE_WINDOWS || JUCE_LINUX
784 SO_REUSEADDR, // port re-use is implied by addr re-use on these platforms
785 #else
786 SO_REUSEPORT,
787 #endif
788 (int) (enabled ? 1 : 0));
789 #endif
790
791 return false;
792}
793
794#if JUCE_MSVC
795 #pragma warning (pop)
796#endif
797
798
799//==============================================================================
800//==============================================================================
801#if JUCE_UNIT_TESTS
802
803struct SocketTests : public UnitTest
804{
805 SocketTests()
806 : UnitTest ("Sockets", UnitTestCategories::networking)
807 {
808 }
809
810 void runTest() override
811 {
812 auto localHost = IPAddress::local();
813 int portNum = 12345;
814
815 beginTest ("StreamingSocket");
816 {
817 StreamingSocket socketServer;
818
819 expect (socketServer.isConnected() == false);
820 expect (socketServer.getHostName().isEmpty());
821 expect (socketServer.getBoundPort() == -1);
822 expect (socketServer.getRawSocketHandle() == invalidSocket);
823
824 expect (socketServer.createListener (portNum, localHost.toString()));
825
826 StreamingSocket socket;
827
828 expect (socket.connect (localHost.toString(), portNum));
829
830 expect (socket.isConnected() == true);
831 expect (socket.getHostName() == localHost.toString());
832 expect (socket.getBoundPort() != -1);
833 expect (socket.getRawSocketHandle() != invalidSocket);
834
835 socket.close();
836
837 expect (socket.isConnected() == false);
838 expect (socket.getHostName().isEmpty());
839 expect (socket.getBoundPort() == -1);
840 expect (socket.getRawSocketHandle() == invalidSocket);
841 }
842
843 beginTest ("DatagramSocket");
844 {
845 DatagramSocket socket;
846
847 expect (socket.getBoundPort() == -1);
848 expect (socket.getRawSocketHandle() != invalidSocket);
849
850 expect (socket.bindToPort (portNum, localHost.toString()));
851
852 expect (socket.getBoundPort() == portNum);
853 expect (socket.getRawSocketHandle() != invalidSocket);
854
855 socket.shutdown();
856
857 expect (socket.getBoundPort() == -1);
858 expect (socket.getRawSocketHandle() == invalidSocket);
859 }
860 }
861};
862
863static SocketTests socketTests;
864
865#endif
866
867} // namespace juce
juce::CriticalSection::ScopedLockType
GenericScopedLock< CriticalSection > ScopedLockType
Definition: juce_CriticalSection.h:93
juce::CriticalSection::ScopedTryLockType
GenericScopedTryLock< CriticalSection > ScopedTryLockType
Definition: juce_CriticalSection.h:99
juce::DatagramSocket::shutdown
void shutdown()
Definition: juce_Socket.cpp:654
juce::DatagramSocket::DatagramSocket
DatagramSocket(bool enableBroadcasting=false)
Definition: juce_Socket.cpp:633
juce::DatagramSocket::write
int write(const String &remoteHostname, int remotePortNumber, const void *sourceBuffer, int numBytesToWrite)
Definition: juce_Socket.cpp:724
juce::DatagramSocket::read
int read(void *destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived)
Definition: juce_Socket.cpp:704
juce::DatagramSocket::setMulticastLoopbackEnabled
bool setMulticastLoopbackEnabled(bool enableLoopback)
Definition: juce_Socket.cpp:768
juce::DatagramSocket::bindToPort
bool bindToPort(int localPortNumber)
Definition: juce_Socket.cpp:668
juce::DatagramSocket::leaveMulticast
bool leaveMulticast(const String &multicastIPAddress)
Definition: juce_Socket.cpp:760
juce::DatagramSocket::~DatagramSocket
~DatagramSocket()
Definition: juce_Socket.cpp:646
juce::DatagramSocket::setEnablePortReuse
bool setEnablePortReuse(bool enabled)
Definition: juce_Socket.cpp:776
juce::DatagramSocket::waitUntilReady
int waitUntilReady(bool readyForReading, int timeoutMsecs)
Definition: juce_Socket.cpp:696
juce::DatagramSocket::joinMulticast
bool joinMulticast(const String &multicastIPAddress)
Definition: juce_Socket.cpp:752
juce::DatagramSocket::getBoundPort
int getBoundPort() const noexcept
Definition: juce_Socket.cpp:690
juce::IPAddress
Definition: juce_IPAddress.h:33
juce::IPAddress::getAllAddresses
static Array< IPAddress > getAllAddresses(bool includeIPv6=false)
Definition: juce_IPAddress.cpp:368
juce::StreamingSocket
Definition: juce_Socket.h:38
juce::StreamingSocket::read
int read(void *destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived)
Definition: juce_Socket.cpp:480
juce::StreamingSocket::waitForNextConnection
StreamingSocket * waitForNextConnection() const
Definition: juce_Socket.cpp:596
juce::StreamingSocket::write
int write(const void *sourceBuffer, int numBytesToWrite)
Definition: juce_Socket.cpp:487
juce::StreamingSocket::isLocal
bool isLocal() const noexcept
Definition: juce_Socket.cpp:616
juce::StreamingSocket::~StreamingSocket
~StreamingSocket()
Definition: juce_Socket.cpp:474
juce::StreamingSocket::waitUntilReady
int waitUntilReady(bool readyForReading, int timeoutMsecs)
Definition: juce_Socket.cpp:496
juce::StreamingSocket::createListener
bool createListener(int portNumber, const String &localHostName=String())
Definition: juce_Socket.cpp:565
juce::StreamingSocket::getBoundPort
int getBoundPort() const noexcept
Definition: juce_Socket.cpp:515
juce::StreamingSocket::StreamingSocket
StreamingSocket()
Definition: juce_Socket.cpp:457
juce::StreamingSocket::bindToPort
bool bindToPort(int localPortNumber)
Definition: juce_Socket.cpp:503
juce::StreamingSocket::close
void close()
Definition: juce_Socket.cpp:553
juce::StreamingSocket::connect
bool connect(const String &remoteHostname, int remotePortNumber, int timeOutMillisecs=3000)
Definition: juce_Socket.cpp:520
juce::StreamingSocket::isConnected
bool isConnected() const noexcept
Definition: juce_Socket.h:99
juce::String
Definition: juce_String.h:39
juce::String::fromUTF8
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)
Definition: juce_String.cpp:2128
juce::UnitTest
Definition: juce_UnitTest.h:70