OpenShot Audio Library | OpenShotAudio  0.3.3
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 
23 namespace 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 //==============================================================================
53 namespace 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 //==============================================================================
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 
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 //==============================================================================
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 
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 
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 //==============================================================================
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 
647 {
648  if (lastServerAddress != nullptr)
649  freeaddrinfo (static_cast<struct addrinfo*> (lastServerAddress));
650 
651  shutdown();
652 }
653 
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 
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 
769 {
770  if (handle < 0 || ! isBound)
771  return false;
772 
773  return SocketHelpers::setOption<bool> (handle, IPPROTO_IP, IP_MULTICAST_LOOP, enable);
774 }
775 
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 
803 struct 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 
863 static SocketTests socketTests;
864 
865 #endif
866 
867 } // namespace juce
GenericScopedLock< CriticalSection > ScopedLockType
GenericScopedTryLock< CriticalSection > ScopedTryLockType
DatagramSocket(bool enableBroadcasting=false)
int write(const String &remoteHostname, int remotePortNumber, const void *sourceBuffer, int numBytesToWrite)
int read(void *destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived)
bool setMulticastLoopbackEnabled(bool enableLoopback)
bool bindToPort(int localPortNumber)
bool leaveMulticast(const String &multicastIPAddress)
bool setEnablePortReuse(bool enabled)
int waitUntilReady(bool readyForReading, int timeoutMsecs)
bool joinMulticast(const String &multicastIPAddress)
int getBoundPort() const noexcept
static Array< IPAddress > getAllAddresses(bool includeIPv6=false)
int read(void *destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived)
StreamingSocket * waitForNextConnection() const
int write(const void *sourceBuffer, int numBytesToWrite)
bool isLocal() const noexcept
int waitUntilReady(bool readyForReading, int timeoutMsecs)
bool createListener(int portNumber, const String &localHostName=String())
int getBoundPort() const noexcept
bool bindToPort(int localPortNumber)
bool connect(const String &remoteHostname, int remotePortNumber, int timeOutMillisecs=3000)
bool isConnected() const noexcept
Definition: juce_Socket.h:99
static String fromUTF8(const char *utf8buffer, int bufferSizeBytes=-1)