1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.protocol.async;
17
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.Random;
22 import java.util.logging.Level;
23 import java.util.logging.Logger;
24
25 import org.fourthline.cling.UpnpService;
26 import org.fourthline.cling.model.DiscoveryOptions;
27 import org.fourthline.cling.model.Location;
28 import org.fourthline.cling.model.NetworkAddress;
29 import org.fourthline.cling.model.message.IncomingDatagramMessage;
30 import org.fourthline.cling.model.message.UpnpRequest;
31 import org.fourthline.cling.model.message.discovery.IncomingSearchRequest;
32 import org.fourthline.cling.model.message.discovery.OutgoingSearchResponse;
33 import org.fourthline.cling.model.message.discovery.OutgoingSearchResponseDeviceType;
34 import org.fourthline.cling.model.message.discovery.OutgoingSearchResponseRootDevice;
35 import org.fourthline.cling.model.message.discovery.OutgoingSearchResponseServiceType;
36 import org.fourthline.cling.model.message.discovery.OutgoingSearchResponseUDN;
37 import org.fourthline.cling.model.message.header.DeviceTypeHeader;
38 import org.fourthline.cling.model.message.header.MXHeader;
39 import org.fourthline.cling.model.message.header.RootDeviceHeader;
40 import org.fourthline.cling.model.message.header.STAllHeader;
41 import org.fourthline.cling.model.message.header.ServiceTypeHeader;
42 import org.fourthline.cling.model.message.header.UDNHeader;
43 import org.fourthline.cling.model.message.header.UpnpHeader;
44 import org.fourthline.cling.model.meta.Device;
45 import org.fourthline.cling.model.meta.LocalDevice;
46 import org.fourthline.cling.model.types.DeviceType;
47 import org.fourthline.cling.model.types.ServiceType;
48 import org.fourthline.cling.model.types.UDN;
49 import org.fourthline.cling.protocol.ReceivingAsync;
50 import org.fourthline.cling.transport.RouterException;
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public class ReceivingSearch extends ReceivingAsync<IncomingSearchRequest> {
67
68 final private static Logger log = Logger.getLogger(ReceivingSearch.class.getName());
69
70 private static final boolean LOG_ENABLED = log.isLoggable(Level.FINE);
71
72 final protected Random randomGenerator = new Random();
73
74 public ReceivingSearch(UpnpService upnpService, IncomingDatagramMessage<UpnpRequest> inputMessage) {
75 super(upnpService, new IncomingSearchRequest(inputMessage));
76 }
77
78 protected void execute() throws RouterException {
79 if (getUpnpService().getRouter() == null) {
80
81 log.fine("Router hasn't completed initialization, ignoring received search message");
82 return;
83 }
84
85 if (!getInputMessage().isMANSSDPDiscover()) {
86 log.fine("Invalid search request, no or invalid MAN ssdp:discover header: " + getInputMessage());
87 return;
88 }
89
90 UpnpHeader searchTarget = getInputMessage().getSearchTarget();
91
92 if (searchTarget == null) {
93 log.fine("Invalid search request, did not contain ST header: " + getInputMessage());
94 return;
95 }
96
97 List<NetworkAddress> activeStreamServers =
98 getUpnpService().getRouter().getActiveStreamServers(getInputMessage().getLocalAddress());
99 if (activeStreamServers.size() == 0) {
100 log.fine("Aborting search response, no active stream servers found (network disabled?)");
101 return;
102 }
103
104 for (NetworkAddress activeStreamServer : activeStreamServers) {
105 sendResponses(searchTarget, activeStreamServer);
106 }
107 }
108
109 @Override
110 protected boolean waitBeforeExecution() throws InterruptedException {
111
112 Integer mx = getInputMessage().getMX();
113
114 if (mx == null) {
115 log.fine("Invalid search request, did not contain MX header: " + getInputMessage());
116 return false;
117 }
118
119
120
121
122 if (mx > 120 || mx <= 0) mx = MXHeader.DEFAULT_VALUE;
123
124
125 if (getUpnpService().getRegistry().getLocalDevices().size() > 0) {
126 int sleepTime = randomGenerator.nextInt(mx * 1000);
127 log.fine("Sleeping " + sleepTime + " milliseconds to avoid flooding with search responses");
128 Thread.sleep(sleepTime);
129 }
130
131 return true;
132 }
133
134 protected void sendResponses(UpnpHeader searchTarget, NetworkAddress activeStreamServer) throws RouterException {
135 if (searchTarget instanceof STAllHeader) {
136
137 sendSearchResponseAll(activeStreamServer);
138
139 } else if (searchTarget instanceof RootDeviceHeader) {
140
141 sendSearchResponseRootDevices(activeStreamServer);
142
143 } else if (searchTarget instanceof UDNHeader) {
144
145 sendSearchResponseUDN((UDN) searchTarget.getValue(), activeStreamServer);
146
147 } else if (searchTarget instanceof DeviceTypeHeader) {
148
149 sendSearchResponseDeviceType((DeviceType) searchTarget.getValue(), activeStreamServer);
150
151 } else if (searchTarget instanceof ServiceTypeHeader) {
152
153 sendSearchResponseServiceType((ServiceType) searchTarget.getValue(), activeStreamServer);
154
155 } else {
156 log.warning("Non-implemented search request target: " + searchTarget.getClass());
157 }
158 }
159
160 protected void sendSearchResponseAll(NetworkAddress activeStreamServer) throws RouterException {
161 if (LOG_ENABLED) {
162 log.fine("Responding to 'all' search with advertisement messages for all local devices");
163 }
164 for (LocalDevice localDevice : getUpnpService().getRegistry().getLocalDevices()) {
165
166 if (isAdvertisementDisabled(localDevice))
167 continue;
168
169
170 if (LOG_ENABLED) {
171 log.finer("Sending root device messages: " + localDevice);
172 }
173 List<OutgoingSearchResponse> rootDeviceMsgs =
174 createDeviceMessages(localDevice, activeStreamServer);
175 for (OutgoingSearchResponse upnpMessage : rootDeviceMsgs) {
176 getUpnpService().getRouter().send(upnpMessage);
177 }
178
179 if (localDevice.hasEmbeddedDevices()) {
180 for (LocalDevice embeddedDevice : localDevice.findEmbeddedDevices()) {
181 if (LOG_ENABLED) {
182 log.finer("Sending embedded device messages: " + embeddedDevice);
183 }
184 List<OutgoingSearchResponse> embeddedDeviceMsgs =
185 createDeviceMessages(embeddedDevice, activeStreamServer);
186 for (OutgoingSearchResponse upnpMessage : embeddedDeviceMsgs) {
187 getUpnpService().getRouter().send(upnpMessage);
188 }
189 }
190 }
191
192 List<OutgoingSearchResponse> serviceTypeMsgs =
193 createServiceTypeMessages(localDevice, activeStreamServer);
194 if (serviceTypeMsgs.size() > 0) {
195 if (LOG_ENABLED) {
196 log.finer("Sending service type messages");
197 }
198 for (OutgoingSearchResponse upnpMessage : serviceTypeMsgs) {
199 getUpnpService().getRouter().send(upnpMessage);
200 }
201 }
202
203 }
204 }
205
206 protected List<OutgoingSearchResponse> createDeviceMessages(LocalDevice device,
207 NetworkAddress activeStreamServer) {
208 List<OutgoingSearchResponse> msgs = new ArrayList<>();
209
210
211
212 if (device.isRoot()) {
213 msgs.add(
214 new OutgoingSearchResponseRootDevice(
215 getInputMessage(),
216 getDescriptorLocation(activeStreamServer, device),
217 device
218 )
219 );
220 }
221
222 msgs.add(
223 new OutgoingSearchResponseUDN(
224 getInputMessage(),
225 getDescriptorLocation(activeStreamServer, device),
226 device
227 )
228 );
229
230 msgs.add(
231 new OutgoingSearchResponseDeviceType(
232 getInputMessage(),
233 getDescriptorLocation(activeStreamServer, device),
234 device
235 )
236 );
237
238 for (OutgoingSearchResponse msg : msgs) {
239 prepareOutgoingSearchResponse(msg);
240 }
241
242 return msgs;
243 }
244
245 protected List<OutgoingSearchResponse> createServiceTypeMessages(LocalDevice device,
246 NetworkAddress activeStreamServer) {
247 List<OutgoingSearchResponse> msgs = new ArrayList<>();
248 for (ServiceType serviceType : device.findServiceTypes()) {
249 OutgoingSearchResponse message =
250 new OutgoingSearchResponseServiceType(
251 getInputMessage(),
252 getDescriptorLocation(activeStreamServer, device),
253 device,
254 serviceType
255 );
256 prepareOutgoingSearchResponse(message);
257 msgs.add(message);
258 }
259 return msgs;
260 }
261
262 protected void sendSearchResponseRootDevices(NetworkAddress activeStreamServer) throws RouterException {
263 log.fine("Responding to root device search with advertisement messages for all local root devices");
264 for (LocalDevice device : getUpnpService().getRegistry().getLocalDevices()) {
265
266 if (isAdvertisementDisabled(device))
267 continue;
268
269 OutgoingSearchResponse message =
270 new OutgoingSearchResponseRootDevice(
271 getInputMessage(),
272 getDescriptorLocation(activeStreamServer, device),
273 device
274 );
275 prepareOutgoingSearchResponse(message);
276 getUpnpService().getRouter().send(message);
277 }
278 }
279
280 protected void sendSearchResponseUDN(UDN udn, NetworkAddress activeStreamServer) throws RouterException {
281 Device device = getUpnpService().getRegistry().getDevice(udn, false);
282 if (device != null && device instanceof LocalDevice) {
283
284 if (isAdvertisementDisabled((LocalDevice)device))
285 return;
286
287 log.fine("Responding to UDN device search: " + udn);
288 OutgoingSearchResponse message =
289 new OutgoingSearchResponseUDN(
290 getInputMessage(),
291 getDescriptorLocation(activeStreamServer, (LocalDevice) device),
292 (LocalDevice) device
293 );
294 prepareOutgoingSearchResponse(message);
295 getUpnpService().getRouter().send(message);
296 }
297 }
298
299 protected void sendSearchResponseDeviceType(DeviceType deviceType, NetworkAddress activeStreamServer) throws RouterException{
300 log.fine("Responding to device type search: " + deviceType);
301 Collection<Device> devices = getUpnpService().getRegistry().getDevices(deviceType);
302 for (Device device : devices) {
303 if (device instanceof LocalDevice) {
304
305 if (isAdvertisementDisabled((LocalDevice)device))
306 continue;
307
308 log.finer("Sending matching device type search result for: " + device);
309 OutgoingSearchResponse message =
310 new OutgoingSearchResponseDeviceType(
311 getInputMessage(),
312 getDescriptorLocation(activeStreamServer, (LocalDevice) device),
313 (LocalDevice) device
314 );
315 prepareOutgoingSearchResponse(message);
316 getUpnpService().getRouter().send(message);
317 }
318 }
319 }
320
321 protected void sendSearchResponseServiceType(ServiceType serviceType, NetworkAddress activeStreamServer) throws RouterException {
322 log.fine("Responding to service type search: " + serviceType);
323 Collection<Device> devices = getUpnpService().getRegistry().getDevices(serviceType);
324 for (Device device : devices) {
325 if (device instanceof LocalDevice) {
326
327 if (isAdvertisementDisabled((LocalDevice)device))
328 continue;
329
330 log.finer("Sending matching service type search result: " + device);
331 OutgoingSearchResponse message =
332 new OutgoingSearchResponseServiceType(
333 getInputMessage(),
334 getDescriptorLocation(activeStreamServer, (LocalDevice) device),
335 (LocalDevice) device,
336 serviceType
337 );
338 prepareOutgoingSearchResponse(message);
339 getUpnpService().getRouter().send(message);
340 }
341 }
342 }
343
344 protected Location getDescriptorLocation(NetworkAddress activeStreamServer, LocalDevice device) {
345 return new Location(
346 activeStreamServer,
347 getUpnpService().getConfiguration().getNamespace().getDescriptorPathString(device)
348 );
349 }
350
351 protected boolean isAdvertisementDisabled(LocalDevice device) {
352 DiscoveryOptions options =
353 getUpnpService().getRegistry().getDiscoveryOptions(device.getIdentity().getUdn());
354 return options != null && !options.isAdvertised();
355 }
356
357
358
359
360 protected void prepareOutgoingSearchResponse(OutgoingSearchResponse message) {
361 }
362
363 }