OpenShot Library | libopenshot-audio  0.2.0
juce_NetworkServiceDiscovery.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 
27  const String& serviceDescription,
28  int broadcastPortToUse, int connectionPort,
29  RelativeTime minTimeBetweenBroadcasts)
30  : Thread ("Discovery_broadcast"),
31  message (serviceTypeUID), broadcastPort (broadcastPortToUse),
32  minInterval (minTimeBetweenBroadcasts)
33 {
34  message.setAttribute ("id", Uuid().toString());
35  message.setAttribute ("name", serviceDescription);
36  message.setAttribute ("address", String());
37  message.setAttribute ("port", connectionPort);
38 
39  startThread (2);
40 }
41 
43 {
44  stopThread (2000);
45  socket.shutdown();
46 }
47 
48 void NetworkServiceDiscovery::Advertiser::run()
49 {
50  if (! socket.bindToPort (0))
51  {
52  jassertfalse;
53  return;
54  }
55 
56  while (! threadShouldExit())
57  {
58  sendBroadcast();
59  wait ((int) minInterval.inMilliseconds());
60  }
61 }
62 
63 void NetworkServiceDiscovery::Advertiser::sendBroadcast()
64 {
65  auto localAddress = IPAddress::getLocalAddress();
66  message.setAttribute ("address", localAddress.toString());
67  auto broadcastAddress = IPAddress::getInterfaceBroadcastAddress (localAddress);
68  auto data = message.createDocument ({}, true, false);
69  socket.write (broadcastAddress.toString(), broadcastPort, data.toRawUTF8(), (int) data.getNumBytesAsUTF8());
70 }
71 
72 //==============================================================================
74  : Thread ("Discovery_listen"), serviceTypeUID (serviceType)
75 {
76  socket.bindToPort (broadcastPort);
77  startThread (2);
78 }
79 
81 {
82  socket.shutdown();
83  stopThread (2000);
84 }
85 
86 void NetworkServiceDiscovery::AvailableServiceList::run()
87 {
88  while (! threadShouldExit())
89  {
90  if (socket.waitUntilReady (true, 200) == 1)
91  {
92  char buffer[1024];
93  auto bytesRead = socket.read (buffer, sizeof (buffer) - 1, false);
94 
95  if (bytesRead > 10)
96  if (auto xml = parseXML (String (CharPointer_UTF8 (buffer),
97  CharPointer_UTF8 (buffer + bytesRead))))
98  if (xml->hasTagName (serviceTypeUID))
99  handleMessage (*xml);
100  }
101 
102  removeTimedOutServices();
103  }
104 }
105 
106 std::vector<NetworkServiceDiscovery::Service> NetworkServiceDiscovery::AvailableServiceList::getServices() const
107 {
108  const ScopedLock sl (listLock);
109  auto listCopy = services;
110  return listCopy;
111 }
112 
113 void NetworkServiceDiscovery::AvailableServiceList::handleAsyncUpdate()
114 {
115  if (onChange != nullptr)
116  onChange();
117 }
118 
119 void NetworkServiceDiscovery::AvailableServiceList::handleMessage (const XmlElement& xml)
120 {
121  Service service;
122  service.instanceID = xml.getStringAttribute ("id");
123 
124  if (service.instanceID.trim().isNotEmpty())
125  {
126  service.description = xml.getStringAttribute ("name");
127  service.address = IPAddress (xml.getStringAttribute ("address"));
128  service.port = xml.getIntAttribute ("port");
129  service.lastSeen = Time::getCurrentTime();
130 
131  handleMessage (service);
132  }
133 }
134 
135 static void sortServiceList (std::vector<NetworkServiceDiscovery::Service>& services)
136 {
137  auto compareServices = [] (const NetworkServiceDiscovery::Service& s1,
138  const NetworkServiceDiscovery::Service& s2)
139  {
140  return s1.instanceID < s2.instanceID;
141  };
142 
143  std::sort (services.begin(), services.end(), compareServices);
144 }
145 
146 void NetworkServiceDiscovery::AvailableServiceList::handleMessage (const Service& service)
147 {
148  const ScopedLock sl (listLock);
149 
150  for (auto& s : services)
151  {
152  if (s.instanceID == service.instanceID)
153  {
154  if (s.description != service.description
155  || s.address != service.address
156  || s.port != service.port)
157  {
158  s = service;
159  triggerAsyncUpdate();
160  }
161 
162  s.lastSeen = service.lastSeen;
163  return;
164  }
165  }
166 
167  services.push_back (service);
168  sortServiceList (services);
169  triggerAsyncUpdate();
170 }
171 
172 void NetworkServiceDiscovery::AvailableServiceList::removeTimedOutServices()
173 {
174  const double timeoutSeconds = 5.0;
175  auto oldestAllowedTime = Time::getCurrentTime() - RelativeTime::seconds (timeoutSeconds);
176 
177  const ScopedLock sl (listLock);
178 
179  auto oldEnd = std::end (services);
180  auto newEnd = std::remove_if (std::begin (services), oldEnd,
181  [=] (const Service& s) { return s.lastSeen < oldestAllowedTime; });
182 
183  if (newEnd != oldEnd)
184  {
185  services.erase (newEnd, oldEnd);
186  triggerAsyncUpdate();
187  }
188 }
189 
190 } // namespace juce
juce::RelativeTime::seconds
static RelativeTime seconds(double seconds) noexcept
Creates a new RelativeTime object representing a number of seconds.
Definition: juce_RelativeTime.cpp:33
juce::Thread::startThread
void startThread()
Starts the thread running.
Definition: juce_Thread.cpp:122
juce::NetworkServiceDiscovery::AvailableServiceList::~AvailableServiceList
~AvailableServiceList() override
Destructor.
Definition: juce_NetworkServiceDiscovery.cpp:80
juce::XmlElement::setAttribute
void setAttribute(const Identifier &attributeName, const String &newValue)
Adds a named attribute to the element.
Definition: juce_XmlElement.cpp:551
juce::Thread
Encapsulates a thread.
Definition: juce_Thread.h:46
juce::IPAddress
Represents an IP address.
Definition: juce_IPAddress.h:36
juce::Uuid
A universally unique 128-bit identifier.
Definition: juce_Uuid.h:42
juce::RelativeTime
A relative measure of time.
Definition: juce_RelativeTime.h:40
juce::NetworkServiceDiscovery::Advertiser::Advertiser
Advertiser(const String &serviceTypeUID, const String &serviceDescription, int broadcastPort, int connectionPort, RelativeTime minTimeBetweenBroadcasts=RelativeTime::seconds(1.5))
Creates and starts an Advertiser thread, broadcasting with the given properties.
Definition: juce_NetworkServiceDiscovery.cpp:26
juce::NetworkServiceDiscovery::AvailableServiceList::AvailableServiceList
AvailableServiceList(const String &serviceTypeUID, int broadcastPort)
Creates an AvailableServiceList that will bind to the given port number and watch the network for Adv...
Definition: juce_NetworkServiceDiscovery.cpp:73
juce::Time::getCurrentTime
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Returns a Time object that is set to the current system time.
Definition: juce_Time.cpp:218
juce::XmlElement
Used to build a tree of elements representing an XML document.
Definition: juce_XmlElement.h:141
juce::NetworkServiceDiscovery::Advertiser::~Advertiser
~Advertiser() override
Destructor.
Definition: juce_NetworkServiceDiscovery.cpp:42
juce::DatagramSocket::bindToPort
bool bindToPort(int localPortNumber)
Binds the socket to the specified local port.
Definition: juce_Socket.cpp:638
juce::NetworkServiceDiscovery::AvailableServiceList::getServices
std::vector< Service > getServices() const
Returns a list of the currently known services.
Definition: juce_NetworkServiceDiscovery.cpp:106
juce::IPAddress::getLocalAddress
static IPAddress getLocalAddress(bool includeIPv6=false)
Returns the first 'real' address for the local machine.
Definition: juce_IPAddress.cpp:357
juce::GenericScopedLock
Automatically locks and unlocks a mutex object.
Definition: juce_ScopedLock.h:58
juce::CharPointer_UTF8
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
Definition: juce_CharPointer_UTF8.h:38
juce::String
The JUCE String class!
Definition: juce_String.h:42
juce::XmlElement::getIntAttribute
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
Returns the value of a named attribute as an integer.
Definition: juce_XmlElement.cpp:507
juce::XmlElement::getStringAttribute
const String & getStringAttribute(StringRef attributeName) const noexcept
Returns the value of a named attribute.
Definition: juce_XmlElement.cpp:491
juce::IPAddress::getInterfaceBroadcastAddress
static IPAddress getInterfaceBroadcastAddress(const IPAddress &interfaceAddress)
If the IPAdress is the address of an interface on the machine, returns the associated broadcast addre...