1 | /* $Id: upnpdescgen.c,v 1.18 2011/05/02 23:50:52 jmaggard Exp $ */ |
---|
2 | /* MiniUPnP project |
---|
3 | * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ |
---|
4 | * |
---|
5 | * Copyright (c) 2006-2008, Thomas Bernard |
---|
6 | * All rights reserved. |
---|
7 | * |
---|
8 | * Redistribution and use in source and binary forms, with or without |
---|
9 | * modification, are permitted provided that the following conditions are met: |
---|
10 | * * Redistributions of source code must retain the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer. |
---|
12 | * * Redistributions in binary form must reproduce the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer in the |
---|
14 | * documentation and/or other materials provided with the distribution. |
---|
15 | * * The name of the author may not be used to endorse or promote products |
---|
16 | * derived from this software without specific prior written permission. |
---|
17 | * |
---|
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
---|
22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
28 | * POSSIBILITY OF SUCH DAMAGE. |
---|
29 | */ |
---|
30 | #include <stdio.h> |
---|
31 | #include <stdlib.h> |
---|
32 | #include <string.h> |
---|
33 | |
---|
34 | #include "config.h" |
---|
35 | #include "getifaddr.h" |
---|
36 | #include "upnpdescgen.h" |
---|
37 | #include "minidlnapath.h" |
---|
38 | #include "upnpglobalvars.h" |
---|
39 | #include "upnpdescstrings.h" |
---|
40 | |
---|
41 | #undef DESC_DEBUG |
---|
42 | |
---|
43 | static const char * const upnptypes[] = |
---|
44 | { |
---|
45 | "string", |
---|
46 | "boolean", |
---|
47 | "ui2", |
---|
48 | "ui4", |
---|
49 | "i4", |
---|
50 | "uri", |
---|
51 | "int", |
---|
52 | "bin.base64" |
---|
53 | }; |
---|
54 | |
---|
55 | static const char * const upnpdefaultvalues[] = |
---|
56 | { |
---|
57 | 0, |
---|
58 | "Unconfigured" |
---|
59 | }; |
---|
60 | |
---|
61 | static const char * const upnpallowedvalues[] = |
---|
62 | { |
---|
63 | 0, /* 0 */ |
---|
64 | "DSL", /* 1 */ |
---|
65 | "POTS", |
---|
66 | "Cable", |
---|
67 | "Ethernet", |
---|
68 | 0, |
---|
69 | "Up", /* 6 */ |
---|
70 | "Down", |
---|
71 | "Initializing", |
---|
72 | "Unavailable", |
---|
73 | 0, |
---|
74 | "TCP", /* 11 */ |
---|
75 | "UDP", |
---|
76 | 0, |
---|
77 | "Unconfigured", /* 14 */ |
---|
78 | "IP_Routed", |
---|
79 | "IP_Bridged", |
---|
80 | 0, |
---|
81 | "Unconfigured", /* 18 */ |
---|
82 | "Connecting", |
---|
83 | "Connected", |
---|
84 | "PendingDisconnect", |
---|
85 | "Disconnecting", |
---|
86 | "Disconnected", |
---|
87 | 0, |
---|
88 | "ERROR_NONE", /* 25 */ |
---|
89 | 0, |
---|
90 | "OK", /* 27 */ |
---|
91 | "ContentFormatMismatch", |
---|
92 | "InsufficientBandwidth", |
---|
93 | "UnreliableChannel", |
---|
94 | "Unknown", |
---|
95 | 0, |
---|
96 | "Input", /* 33 */ |
---|
97 | "Output", |
---|
98 | 0, |
---|
99 | "BrowseMetadata", /* 36 */ |
---|
100 | "BrowseDirectChildren", |
---|
101 | 0, |
---|
102 | "COMPLETED", /* 39 */ |
---|
103 | "ERROR", |
---|
104 | "IN_PROGRESS", |
---|
105 | "STOPPED", |
---|
106 | 0, |
---|
107 | RESOURCE_PROTOCOL_INFO_VALUES, /* 44 */ |
---|
108 | 0, |
---|
109 | "0", /* 46 */ |
---|
110 | 0, |
---|
111 | "", /* 48 */ |
---|
112 | 0 |
---|
113 | }; |
---|
114 | |
---|
115 | static const char xmlver[] = |
---|
116 | "<?xml version=\"1.0\"?>\r\n"; |
---|
117 | static const char root_service[] = |
---|
118 | "scpd xmlns=\"urn:schemas-upnp-org:service-1-0\""; |
---|
119 | static const char root_device[] = |
---|
120 | "root xmlns=\"urn:schemas-upnp-org:device-1-0\"" |
---|
121 | #if PNPX |
---|
122 | " xmlns:pnpx=\"http://schemas.microsoft.com/windows/pnpx/2005/11\"" |
---|
123 | " xmlns:df=\"http://schemas.microsoft.com/windows/2008/09/devicefoundation\"" |
---|
124 | #endif |
---|
125 | ; |
---|
126 | |
---|
127 | /* root Description of the UPnP Device */ |
---|
128 | static const struct XMLElt rootDesc[] = |
---|
129 | { |
---|
130 | {root_device, INITHELPER(1,2)}, |
---|
131 | {"specVersion", INITHELPER(3,2)}, |
---|
132 | {"device", INITHELPER(5,(14+PNPX))}, |
---|
133 | {"/major", "1"}, |
---|
134 | {"/minor", "0"}, |
---|
135 | {"/deviceType", "urn:schemas-upnp-org:device:MediaServer:1"}, |
---|
136 | #if PNPX == 5 |
---|
137 | {"/pnpx:X_hardwareId", pnpx_hwid}, |
---|
138 | {"/pnpx:X_compatibleId", "MS_DigitalMediaDeviceClass_DMS_V001"}, |
---|
139 | {"/pnpx:X_deviceCategory", "MediaDevices"}, |
---|
140 | {"/df:X_deviceCategory", "Multimedia.DMS"}, |
---|
141 | {"/microsoft:magicPacketWakeSupported xmlns:microsoft=\"urn:schemas-microsoft-com:WMPNSS-1-0\"", "0"}, |
---|
142 | #endif |
---|
143 | {"/friendlyName", friendly_name}, /* required */ |
---|
144 | {"/manufacturer", ROOTDEV_MANUFACTURER}, /* required */ |
---|
145 | {"/manufacturerURL", ROOTDEV_MANUFACTURERURL}, /* optional */ |
---|
146 | {"/modelDescription", ROOTDEV_MODELDESCRIPTION}, /* recommended */ |
---|
147 | {"/modelName", modelname}, /* required */ |
---|
148 | {"/modelNumber", modelnumber}, |
---|
149 | {"/modelURL", ROOTDEV_MODELURL}, |
---|
150 | {"/serialNumber", serialnumber}, |
---|
151 | {"/UDN", uuidvalue}, /* required */ |
---|
152 | {"/dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"", "DMS-1.50"}, |
---|
153 | {"/presentationURL", presentationurl}, /* recommended */ |
---|
154 | {"iconList", INITHELPER((19+PNPX),4)}, |
---|
155 | {"serviceList", INITHELPER((43+PNPX),3)}, |
---|
156 | {"icon", INITHELPER((23+PNPX),5)}, |
---|
157 | {"icon", INITHELPER((28+PNPX),5)}, |
---|
158 | {"icon", INITHELPER((33+PNPX),5)}, |
---|
159 | {"icon", INITHELPER((38+PNPX),5)}, |
---|
160 | {"/mimetype", "image/png"}, |
---|
161 | {"/width", "48"}, |
---|
162 | {"/height", "48"}, |
---|
163 | {"/depth", "24"}, |
---|
164 | {"/url", "/icons/sm.png"}, |
---|
165 | {"/mimetype", "image/png"}, |
---|
166 | {"/width", "120"}, |
---|
167 | {"/height", "120"}, |
---|
168 | {"/depth", "24"}, |
---|
169 | {"/url", "/icons/lrg.png"}, |
---|
170 | {"/mimetype", "image/jpeg"}, |
---|
171 | {"/width", "48"}, |
---|
172 | {"/height", "48"}, |
---|
173 | {"/depth", "24"}, |
---|
174 | {"/url", "/icons/sm.jpg"}, |
---|
175 | {"/mimetype", "image/jpeg"}, |
---|
176 | {"/width", "120"}, |
---|
177 | {"/height", "120"}, |
---|
178 | {"/depth", "24"}, |
---|
179 | {"/url", "/icons/lrg.jpg"}, |
---|
180 | {"service", INITHELPER((46+PNPX),5)}, |
---|
181 | {"service", INITHELPER((51+PNPX),5)}, |
---|
182 | {"service", INITHELPER((56+PNPX),5)}, |
---|
183 | {"/serviceType", "urn:schemas-upnp-org:service:ContentDirectory:1"}, |
---|
184 | {"/serviceId", "urn:upnp-org:serviceId:ContentDirectory"}, |
---|
185 | {"/controlURL", CONTENTDIRECTORY_CONTROLURL}, |
---|
186 | {"/eventSubURL", CONTENTDIRECTORY_EVENTURL}, |
---|
187 | {"/SCPDURL", CONTENTDIRECTORY_PATH}, |
---|
188 | {"/serviceType", "urn:schemas-upnp-org:service:ConnectionManager:1"}, |
---|
189 | {"/serviceId", "urn:upnp-org:serviceId:ConnectionManager"}, |
---|
190 | {"/controlURL", CONNECTIONMGR_CONTROLURL}, |
---|
191 | {"/eventSubURL", CONNECTIONMGR_EVENTURL}, |
---|
192 | {"/SCPDURL", CONNECTIONMGR_PATH}, |
---|
193 | {"/serviceType", "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"}, |
---|
194 | {"/serviceId", "urn:microsoft.com:serviceId:X_MS_MediaReceiverRegistrar"}, |
---|
195 | {"/controlURL", X_MS_MEDIARECEIVERREGISTRAR_CONTROLURL}, |
---|
196 | {"/eventSubURL", X_MS_MEDIARECEIVERREGISTRAR_EVENTURL}, |
---|
197 | {"/SCPDURL", X_MS_MEDIARECEIVERREGISTRAR_PATH}, |
---|
198 | {0, 0} |
---|
199 | }; |
---|
200 | |
---|
201 | static const struct argument AddPortMappingArgs[] = |
---|
202 | { |
---|
203 | {NULL, 1, 11}, |
---|
204 | {NULL, 1, 12}, |
---|
205 | {NULL, 1, 14}, |
---|
206 | {NULL, 1, 13}, |
---|
207 | {NULL, 1, 15}, |
---|
208 | {NULL, 1, 9}, |
---|
209 | {NULL, 1, 16}, |
---|
210 | {NULL, 1, 10}, |
---|
211 | {NULL, 0, 0} |
---|
212 | }; |
---|
213 | |
---|
214 | static const struct argument DeletePortMappingArgs[] = |
---|
215 | { |
---|
216 | {NULL, 1, 11}, |
---|
217 | {NULL, 1, 12}, |
---|
218 | {NULL, 1, 14}, |
---|
219 | {NULL, 0, 0} |
---|
220 | }; |
---|
221 | |
---|
222 | static const struct argument SetConnectionTypeArgs[] = |
---|
223 | { |
---|
224 | {NULL, 1, 0}, |
---|
225 | {NULL, 0, 0} |
---|
226 | }; |
---|
227 | |
---|
228 | static const struct argument GetConnectionTypeInfoArgs[] = |
---|
229 | { |
---|
230 | {NULL, 2, 0}, |
---|
231 | {NULL, 2, 1}, |
---|
232 | {NULL, 0, 0} |
---|
233 | }; |
---|
234 | |
---|
235 | static const struct argument GetNATRSIPStatusArgs[] = |
---|
236 | { |
---|
237 | {NULL, 2, 5}, |
---|
238 | {NULL, 2, 6}, |
---|
239 | {NULL, 0, 0} |
---|
240 | }; |
---|
241 | |
---|
242 | static const struct argument GetGenericPortMappingEntryArgs[] = |
---|
243 | { |
---|
244 | {NULL, 1, 8}, |
---|
245 | {NULL, 2, 11}, |
---|
246 | {NULL, 2, 12}, |
---|
247 | {NULL, 2, 14}, |
---|
248 | {NULL, 2, 13}, |
---|
249 | {NULL, 2, 15}, |
---|
250 | {NULL, 2, 9}, |
---|
251 | {NULL, 2, 16}, |
---|
252 | {NULL, 2, 10}, |
---|
253 | {NULL, 0, 0} |
---|
254 | }; |
---|
255 | |
---|
256 | static const struct argument GetSpecificPortMappingEntryArgs[] = |
---|
257 | { |
---|
258 | {NULL, 1, 11}, |
---|
259 | {NULL, 1, 12}, |
---|
260 | {NULL, 1, 14}, |
---|
261 | {NULL, 2, 13}, |
---|
262 | {NULL, 2, 15}, |
---|
263 | {NULL, 2, 9}, |
---|
264 | {NULL, 2, 16}, |
---|
265 | {NULL, 2, 10}, |
---|
266 | {NULL, 0, 0} |
---|
267 | }; |
---|
268 | |
---|
269 | /* For ConnectionManager */ |
---|
270 | static const struct argument GetProtocolInfoArgs[] = |
---|
271 | { |
---|
272 | {"Source", 2, 0}, |
---|
273 | {"Sink", 2, 1}, |
---|
274 | {NULL, 0, 0} |
---|
275 | }; |
---|
276 | |
---|
277 | static const struct argument PrepareForConnectionArgs[] = |
---|
278 | { |
---|
279 | {"RemoteProtocolInfo", 1, 6}, |
---|
280 | {"PeerConnectionManager", 1, 4}, |
---|
281 | {"PeerConnectionID", 1, 7}, |
---|
282 | {"Direction", 1, 5}, |
---|
283 | {"ConnectionID", 2, 7}, |
---|
284 | {"AVTransportID", 2, 8}, |
---|
285 | {"RcsID", 2, 9}, |
---|
286 | {NULL, 0, 0} |
---|
287 | }; |
---|
288 | |
---|
289 | static const struct argument ConnectionCompleteArgs[] = |
---|
290 | { |
---|
291 | {"ConnectionID", 1, 7}, |
---|
292 | {NULL, 0, 0} |
---|
293 | }; |
---|
294 | |
---|
295 | static const struct argument GetCurrentConnectionIDsArgs[] = |
---|
296 | { |
---|
297 | {"ConnectionIDs", 2, 2}, |
---|
298 | {NULL, 0, 0} |
---|
299 | }; |
---|
300 | |
---|
301 | static const struct argument GetCurrentConnectionInfoArgs[] = |
---|
302 | { |
---|
303 | {"ConnectionID", 1, 7}, |
---|
304 | {"RcsID", 2, 9}, |
---|
305 | {"AVTransportID", 2, 8}, |
---|
306 | {"ProtocolInfo", 2, 6}, |
---|
307 | {"PeerConnectionManager", 2, 4}, |
---|
308 | {"PeerConnectionID", 2, 7}, |
---|
309 | {"Direction", 2, 5}, |
---|
310 | {"Status", 2, 3}, |
---|
311 | {NULL, 0, 0} |
---|
312 | }; |
---|
313 | |
---|
314 | static const struct action ConnectionManagerActions[] = |
---|
315 | { |
---|
316 | {"GetProtocolInfo", GetProtocolInfoArgs}, /* R */ |
---|
317 | //OPTIONAL {"PrepareForConnection", PrepareForConnectionArgs}, /* R */ |
---|
318 | //OPTIONAL {"ConnectionComplete", ConnectionCompleteArgs}, /* R */ |
---|
319 | {"GetCurrentConnectionIDs", GetCurrentConnectionIDsArgs}, /* R */ |
---|
320 | {"GetCurrentConnectionInfo", GetCurrentConnectionInfoArgs}, /* R */ |
---|
321 | {0, 0} |
---|
322 | }; |
---|
323 | |
---|
324 | static const struct stateVar ConnectionManagerVars[] = |
---|
325 | { |
---|
326 | {"SourceProtocolInfo", 1<<7, 0, 0, 44}, /* required */ |
---|
327 | {"SinkProtocolInfo", 1<<7, 0, 0, 48}, /* required */ |
---|
328 | {"CurrentConnectionIDs", 1<<7, 0, 0, 46}, /* required */ |
---|
329 | {"A_ARG_TYPE_ConnectionStatus", 0, 0, 27}, /* required */ |
---|
330 | {"A_ARG_TYPE_ConnectionManager", 0, 0}, /* required */ |
---|
331 | {"A_ARG_TYPE_Direction", 0, 0, 33}, /* required */ |
---|
332 | {"A_ARG_TYPE_ProtocolInfo", 0, 0}, /* required */ |
---|
333 | {"A_ARG_TYPE_ConnectionID", 4, 0}, /* required */ |
---|
334 | {"A_ARG_TYPE_AVTransportID", 4, 0}, /* required */ |
---|
335 | {"A_ARG_TYPE_RcsID", 4, 0}, /* required */ |
---|
336 | {0, 0} |
---|
337 | }; |
---|
338 | |
---|
339 | static const struct argument GetSearchCapabilitiesArgs[] = |
---|
340 | { |
---|
341 | {"SearchCaps", 2, 10}, |
---|
342 | {0, 0} |
---|
343 | }; |
---|
344 | |
---|
345 | static const struct argument GetSortCapabilitiesArgs[] = |
---|
346 | { |
---|
347 | {"SortCaps", 2, 11}, |
---|
348 | {0, 0} |
---|
349 | }; |
---|
350 | |
---|
351 | static const struct argument GetSystemUpdateIDArgs[] = |
---|
352 | { |
---|
353 | {"Id", 2, 12}, |
---|
354 | {0, 0} |
---|
355 | }; |
---|
356 | |
---|
357 | static const struct argument BrowseArgs[] = |
---|
358 | { |
---|
359 | {"ObjectID", 1, 1}, |
---|
360 | {"BrowseFlag", 1, 4}, |
---|
361 | {"Filter", 1, 5}, |
---|
362 | {"StartingIndex", 1, 7}, |
---|
363 | {"RequestedCount", 1, 8}, |
---|
364 | {"SortCriteria", 1, 6}, |
---|
365 | {"Result", 2, 2}, |
---|
366 | {"NumberReturned", 2, 8}, |
---|
367 | {"TotalMatches", 2, 8}, |
---|
368 | {"UpdateID", 2, 9}, |
---|
369 | {0, 0} |
---|
370 | }; |
---|
371 | |
---|
372 | static const struct argument SearchArgs[] = |
---|
373 | { |
---|
374 | {"ContainerID", 1, 1}, |
---|
375 | {"SearchCriteria", 1, 3}, |
---|
376 | {"Filter", 1, 5}, |
---|
377 | {"StartingIndex", 1, 7}, |
---|
378 | {"RequestedCount", 1, 8}, |
---|
379 | {"SortCriteria", 1, 6}, |
---|
380 | {"Result", 2, 2}, |
---|
381 | {"NumberReturned", 2, 8}, |
---|
382 | {"TotalMatches", 2, 8}, |
---|
383 | {"UpdateID", 2, 9}, |
---|
384 | {0, 0} |
---|
385 | }; |
---|
386 | |
---|
387 | static const struct action ContentDirectoryActions[] = |
---|
388 | { |
---|
389 | {"GetSearchCapabilities", GetSearchCapabilitiesArgs}, /* R */ |
---|
390 | {"GetSortCapabilities", GetSortCapabilitiesArgs}, /* R */ |
---|
391 | {"GetSystemUpdateID", GetSystemUpdateIDArgs}, /* R */ |
---|
392 | {"Browse", BrowseArgs}, /* R */ |
---|
393 | {"Search", SearchArgs}, /* O */ |
---|
394 | #if 0 // Not implementing optional features yet... |
---|
395 | {"CreateObject", CreateObjectArgs}, /* O */ |
---|
396 | {"DestroyObject", DestroyObjectArgs}, /* O */ |
---|
397 | {"UpdateObject", UpdateObjectArgs}, /* O */ |
---|
398 | {"ImportResource", ImportResourceArgs}, /* O */ |
---|
399 | {"ExportResource", ExportResourceArgs}, /* O */ |
---|
400 | {"StopTransferResource", StopTransferResourceArgs}, /* O */ |
---|
401 | {"GetTransferProgress", GetTransferProgressArgs}, /* O */ |
---|
402 | {"DeleteResource", DeleteResourceArgs}, /* O */ |
---|
403 | {"CreateReference", CreateReferenceArgs}, /* O */ |
---|
404 | #endif |
---|
405 | {0, 0} |
---|
406 | }; |
---|
407 | |
---|
408 | static const struct stateVar ContentDirectoryVars[] = |
---|
409 | { |
---|
410 | {"TransferIDs", 1<<7, 0, 0, 48}, /* 0 */ |
---|
411 | {"A_ARG_TYPE_ObjectID", 0, 0}, |
---|
412 | {"A_ARG_TYPE_Result", 0, 0}, |
---|
413 | {"A_ARG_TYPE_SearchCriteria", 0, 0}, |
---|
414 | {"A_ARG_TYPE_BrowseFlag", 0, 0, 36}, |
---|
415 | /* Allowed Values : BrowseMetadata / BrowseDirectChildren */ |
---|
416 | {"A_ARG_TYPE_Filter", 0, 0}, /* 5 */ |
---|
417 | {"A_ARG_TYPE_SortCriteria", 0, 0}, |
---|
418 | {"A_ARG_TYPE_Index", 3, 0}, |
---|
419 | {"A_ARG_TYPE_Count", 3, 0}, |
---|
420 | {"A_ARG_TYPE_UpdateID", 3, 0}, |
---|
421 | //JM{"A_ARG_TYPE_TransferID", 3, 0}, /* 10 */ |
---|
422 | //JM{"A_ARG_TYPE_TransferStatus", 0, 0, 39}, |
---|
423 | /* Allowed Values : COMPLETED / ERROR / IN_PROGRESS / STOPPED */ |
---|
424 | //JM{"A_ARG_TYPE_TransferLength", 0, 0}, |
---|
425 | //JM{"A_ARG_TYPE_TransferTotal", 0, 0}, |
---|
426 | //JM{"A_ARG_TYPE_TagValueList", 0, 0}, |
---|
427 | //JM{"A_ARG_TYPE_URI", 5, 0}, /* 15 */ |
---|
428 | {"SearchCapabilities", 0, 0}, |
---|
429 | {"SortCapabilities", 0, 0}, |
---|
430 | {"SystemUpdateID", 3|0x80, 0, 0, 255}, |
---|
431 | //{"ContainerUpdateIDs", 0, 0}, |
---|
432 | {0, 0} |
---|
433 | }; |
---|
434 | |
---|
435 | static const struct argument GetIsAuthorizedArgs[] = |
---|
436 | { |
---|
437 | {"DeviceID", 1, 0}, |
---|
438 | {"Result", 2, 3}, |
---|
439 | {NULL, 0, 0} |
---|
440 | }; |
---|
441 | |
---|
442 | static const struct argument GetIsValidatedArgs[] = |
---|
443 | { |
---|
444 | {"DeviceID", 1, 0}, |
---|
445 | {"Result", 2, 3}, |
---|
446 | {NULL, 0, 0} |
---|
447 | }; |
---|
448 | |
---|
449 | static const struct argument GetRegisterDeviceArgs[] = |
---|
450 | { |
---|
451 | {"RegistrationReqMsg", 1, 1}, |
---|
452 | {"RegistrationRespMsg", 2, 2}, |
---|
453 | {NULL, 0, 0} |
---|
454 | }; |
---|
455 | |
---|
456 | static const struct action X_MS_MediaReceiverRegistrarActions[] = |
---|
457 | { |
---|
458 | {"IsAuthorized", GetIsAuthorizedArgs}, /* R */ |
---|
459 | {"IsValidated", GetIsValidatedArgs}, /* R */ |
---|
460 | #if 0 // Not needed? WMP12 still works. Need to check with 360 and WMP11. |
---|
461 | {"RegisterDevice", GetRegisterDeviceArgs}, /* R */ |
---|
462 | #endif |
---|
463 | {0, 0} |
---|
464 | }; |
---|
465 | |
---|
466 | static const struct stateVar X_MS_MediaReceiverRegistrarVars[] = |
---|
467 | { |
---|
468 | {"A_ARG_TYPE_DeviceID", 0, 0}, |
---|
469 | {"A_ARG_TYPE_RegistrationReqMsg", 7, 0}, |
---|
470 | {"A_ARG_TYPE_RegistrationRespMsg", 7, 0}, |
---|
471 | {"A_ARG_TYPE_Result", 6, 0}, |
---|
472 | {"AuthorizationDeniedUpdateID", 3, 0}, |
---|
473 | {"AuthorizationGrantedUpdateID", 3, 0}, |
---|
474 | {"ValidationRevokedUpdateID", 3, 0}, |
---|
475 | {"ValidationSucceededUpdateID", 3, 0}, |
---|
476 | {0, 0} |
---|
477 | }; |
---|
478 | |
---|
479 | /* WANCfg.xml */ |
---|
480 | /* See UPnP_IGD_WANCommonInterfaceConfig 1.0.pdf */ |
---|
481 | |
---|
482 | static const struct argument GetCommonLinkPropertiesArgs[] = |
---|
483 | { |
---|
484 | {NULL, 2, 0}, |
---|
485 | {NULL, 2, 1}, |
---|
486 | {NULL, 2, 2}, |
---|
487 | {NULL, 2, 3}, |
---|
488 | {NULL, 0, 0} |
---|
489 | }; |
---|
490 | |
---|
491 | static const struct argument GetTotalBytesSentArgs[] = |
---|
492 | { |
---|
493 | {NULL, 2, 4}, |
---|
494 | {NULL, 0, 0} |
---|
495 | }; |
---|
496 | |
---|
497 | static const struct argument GetTotalBytesReceivedArgs[] = |
---|
498 | { |
---|
499 | {NULL, 2, 5}, |
---|
500 | {NULL, 0, 0} |
---|
501 | }; |
---|
502 | |
---|
503 | static const struct argument GetTotalPacketsSentArgs[] = |
---|
504 | { |
---|
505 | {NULL, 2, 6}, |
---|
506 | {NULL, 0, 0} |
---|
507 | }; |
---|
508 | |
---|
509 | static const struct argument GetTotalPacketsReceivedArgs[] = |
---|
510 | { |
---|
511 | {NULL, 2, 7}, |
---|
512 | {NULL, 0, 0} |
---|
513 | }; |
---|
514 | |
---|
515 | static const struct serviceDesc scpdContentDirectory = |
---|
516 | { ContentDirectoryActions, ContentDirectoryVars }; |
---|
517 | |
---|
518 | static const struct serviceDesc scpdConnectionManager = |
---|
519 | { ConnectionManagerActions, ConnectionManagerVars }; |
---|
520 | |
---|
521 | static const struct serviceDesc scpdX_MS_MediaReceiverRegistrar = |
---|
522 | { X_MS_MediaReceiverRegistrarActions, X_MS_MediaReceiverRegistrarVars }; |
---|
523 | |
---|
524 | /* strcat_str() |
---|
525 | * concatenate the string and use realloc to increase the |
---|
526 | * memory buffer if needed. */ |
---|
527 | static char * |
---|
528 | strcat_str(char * str, int * len, int * tmplen, const char * s2) |
---|
529 | { |
---|
530 | char *p; |
---|
531 | int s2len; |
---|
532 | s2len = (int)strlen(s2); |
---|
533 | if(*tmplen <= (*len + s2len)) |
---|
534 | { |
---|
535 | if(s2len < 256) |
---|
536 | *tmplen += 256; |
---|
537 | else |
---|
538 | *tmplen += s2len + 1; |
---|
539 | p = realloc(str, *tmplen); |
---|
540 | if (!p) |
---|
541 | { |
---|
542 | if(s2len < 256) |
---|
543 | *tmplen -= 256; |
---|
544 | else |
---|
545 | *tmplen -= s2len + 1; |
---|
546 | return str; |
---|
547 | } |
---|
548 | else |
---|
549 | str = p; |
---|
550 | } |
---|
551 | /*strcpy(str + *len, s2); */ |
---|
552 | memcpy(str + *len, s2, s2len + 1); |
---|
553 | *len += s2len; |
---|
554 | return str; |
---|
555 | } |
---|
556 | |
---|
557 | /* strcat_char() : |
---|
558 | * concatenate a character and use realloc to increase the |
---|
559 | * size of the memory buffer if needed */ |
---|
560 | static char * |
---|
561 | strcat_char(char * str, int * len, int * tmplen, char c) |
---|
562 | { |
---|
563 | char *p; |
---|
564 | if(*tmplen <= (*len + 1)) |
---|
565 | { |
---|
566 | *tmplen += 256; |
---|
567 | p = (char *)realloc(str, *tmplen); |
---|
568 | if (!p) |
---|
569 | { |
---|
570 | *tmplen -= 256; |
---|
571 | return str; |
---|
572 | } |
---|
573 | else |
---|
574 | str = p; |
---|
575 | } |
---|
576 | str[*len] = c; |
---|
577 | (*len)++; |
---|
578 | return str; |
---|
579 | } |
---|
580 | |
---|
581 | /* iterative subroutine using a small stack |
---|
582 | * This way, the progam stack usage is kept low */ |
---|
583 | static char * |
---|
584 | genXML(char * str, int * len, int * tmplen, |
---|
585 | const struct XMLElt * p) |
---|
586 | { |
---|
587 | u_int16_t i, j, k; |
---|
588 | int top; |
---|
589 | const char * eltname, *s; |
---|
590 | char c; |
---|
591 | char element[64]; |
---|
592 | struct { |
---|
593 | unsigned short i; |
---|
594 | unsigned short j; |
---|
595 | const char * eltname; |
---|
596 | } pile[16]; /* stack */ |
---|
597 | top = -1; |
---|
598 | i = 0; /* current node */ |
---|
599 | j = 1; /* i + number of nodes*/ |
---|
600 | for(;;) |
---|
601 | { |
---|
602 | eltname = p[i].eltname; |
---|
603 | if(!eltname) |
---|
604 | return str; |
---|
605 | if(eltname[0] == '/') |
---|
606 | { |
---|
607 | #ifdef DESC_DEBUG |
---|
608 | printf("DBG: <%s>%s<%s>\n", eltname+1, p[i].data, eltname); |
---|
609 | #endif |
---|
610 | str = strcat_char(str, len, tmplen, '<'); |
---|
611 | str = strcat_str(str, len, tmplen, eltname+1); |
---|
612 | str = strcat_char(str, len, tmplen, '>'); |
---|
613 | str = strcat_str(str, len, tmplen, p[i].data); |
---|
614 | str = strcat_char(str, len, tmplen, '<'); |
---|
615 | sscanf(eltname, "%s", element); |
---|
616 | str = strcat_str(str, len, tmplen, element); |
---|
617 | str = strcat_char(str, len, tmplen, '>'); |
---|
618 | for(;;) |
---|
619 | { |
---|
620 | if(top < 0) |
---|
621 | return str; |
---|
622 | i = ++(pile[top].i); |
---|
623 | j = pile[top].j; |
---|
624 | #ifdef DESC_DEBUG |
---|
625 | printf("DBG: pile[%d]\t%d %d\n", top, i, j); |
---|
626 | #endif |
---|
627 | if(i==j) |
---|
628 | { |
---|
629 | #ifdef DESC_DEBUG |
---|
630 | printf("DBG: i==j, </%s>\n", pile[top].eltname); |
---|
631 | #endif |
---|
632 | str = strcat_char(str, len, tmplen, '<'); |
---|
633 | str = strcat_char(str, len, tmplen, '/'); |
---|
634 | s = pile[top].eltname; |
---|
635 | for(c = *s; c > ' '; c = *(++s)) |
---|
636 | str = strcat_char(str, len, tmplen, c); |
---|
637 | str = strcat_char(str, len, tmplen, '>'); |
---|
638 | top--; |
---|
639 | } |
---|
640 | else |
---|
641 | break; |
---|
642 | } |
---|
643 | } |
---|
644 | else |
---|
645 | { |
---|
646 | #ifdef DESC_DEBUG |
---|
647 | printf("DBG: [%d] <%s>\n", i, eltname); |
---|
648 | #endif |
---|
649 | str = strcat_char(str, len, tmplen, '<'); |
---|
650 | str = strcat_str(str, len, tmplen, eltname); |
---|
651 | str = strcat_char(str, len, tmplen, '>'); |
---|
652 | k = i; |
---|
653 | /*i = p[k].index; */ |
---|
654 | /*j = i + p[k].nchild; */ |
---|
655 | i = (unsigned long)p[k].data & 0xffff; |
---|
656 | j = i + ((unsigned long)p[k].data >> 16); |
---|
657 | top++; |
---|
658 | #ifdef DESC_DEBUG |
---|
659 | printf("DBG: +pile[%d]\t%d %d\n", top, i, j); |
---|
660 | #endif |
---|
661 | pile[top].i = i; |
---|
662 | pile[top].j = j; |
---|
663 | pile[top].eltname = eltname; |
---|
664 | } |
---|
665 | } |
---|
666 | } |
---|
667 | |
---|
668 | /* genRootDesc() : |
---|
669 | * - Generate the root description of the UPnP device. |
---|
670 | * - the len argument is used to return the length of |
---|
671 | * the returned string. |
---|
672 | * - tmp_uuid argument is used to build the uuid string */ |
---|
673 | char * |
---|
674 | genRootDesc(int * len) |
---|
675 | { |
---|
676 | char * str; |
---|
677 | int tmplen; |
---|
678 | tmplen = 2048; |
---|
679 | str = (char *)malloc(tmplen); |
---|
680 | if(str == NULL) |
---|
681 | return NULL; |
---|
682 | * len = strlen(xmlver); |
---|
683 | /*strcpy(str, xmlver); */ |
---|
684 | memcpy(str, xmlver, *len + 1); |
---|
685 | str = genXML(str, len, &tmplen, rootDesc); |
---|
686 | str[*len] = '\0'; |
---|
687 | return str; |
---|
688 | } |
---|
689 | |
---|
690 | /* genServiceDesc() : |
---|
691 | * Generate service description with allowed methods and |
---|
692 | * related variables. */ |
---|
693 | static char * |
---|
694 | genServiceDesc(int * len, const struct serviceDesc * s) |
---|
695 | { |
---|
696 | int i, j; |
---|
697 | const struct action * acts; |
---|
698 | const struct stateVar * vars; |
---|
699 | const struct argument * args; |
---|
700 | const char * p; |
---|
701 | char * str; |
---|
702 | int tmplen; |
---|
703 | tmplen = 2048; |
---|
704 | str = (char *)malloc(tmplen); |
---|
705 | if(str == NULL) |
---|
706 | return NULL; |
---|
707 | /*strcpy(str, xmlver); */ |
---|
708 | *len = strlen(xmlver); |
---|
709 | memcpy(str, xmlver, *len + 1); |
---|
710 | |
---|
711 | acts = s->actionList; |
---|
712 | vars = s->serviceStateTable; |
---|
713 | |
---|
714 | str = strcat_char(str, len, &tmplen, '<'); |
---|
715 | str = strcat_str(str, len, &tmplen, root_service); |
---|
716 | str = strcat_char(str, len, &tmplen, '>'); |
---|
717 | |
---|
718 | str = strcat_str(str, len, &tmplen, |
---|
719 | "<specVersion><major>1</major><minor>0</minor></specVersion>"); |
---|
720 | |
---|
721 | i = 0; |
---|
722 | str = strcat_str(str, len, &tmplen, "<actionList>"); |
---|
723 | while(acts[i].name) |
---|
724 | { |
---|
725 | str = strcat_str(str, len, &tmplen, "<action><name>"); |
---|
726 | str = strcat_str(str, len, &tmplen, acts[i].name); |
---|
727 | str = strcat_str(str, len, &tmplen, "</name>"); |
---|
728 | /* argument List */ |
---|
729 | args = acts[i].args; |
---|
730 | if(args) |
---|
731 | { |
---|
732 | str = strcat_str(str, len, &tmplen, "<argumentList>"); |
---|
733 | j = 0; |
---|
734 | while(args[j].dir) |
---|
735 | { |
---|
736 | str = strcat_str(str, len, &tmplen, "<argument><name>"); |
---|
737 | p = vars[args[j].relatedVar].name; |
---|
738 | str = strcat_str(str, len, &tmplen, (args[j].name ? args[j].name : p)); |
---|
739 | str = strcat_str(str, len, &tmplen, "</name><direction>"); |
---|
740 | str = strcat_str(str, len, &tmplen, args[j].dir==1?"in":"out"); |
---|
741 | str = strcat_str(str, len, &tmplen, |
---|
742 | "</direction><relatedStateVariable>"); |
---|
743 | str = strcat_str(str, len, &tmplen, p); |
---|
744 | str = strcat_str(str, len, &tmplen, |
---|
745 | "</relatedStateVariable></argument>"); |
---|
746 | j++; |
---|
747 | } |
---|
748 | str = strcat_str(str, len, &tmplen,"</argumentList>"); |
---|
749 | } |
---|
750 | str = strcat_str(str, len, &tmplen, "</action>"); |
---|
751 | /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */ |
---|
752 | i++; |
---|
753 | } |
---|
754 | str = strcat_str(str, len, &tmplen, "</actionList><serviceStateTable>"); |
---|
755 | i = 0; |
---|
756 | while(vars[i].name) |
---|
757 | { |
---|
758 | str = strcat_str(str, len, &tmplen, |
---|
759 | "<stateVariable sendEvents=\""); |
---|
760 | str = strcat_str(str, len, &tmplen, (vars[i].itype & 0x80)?"yes":"no"); |
---|
761 | str = strcat_str(str, len, &tmplen, "\"><name>"); |
---|
762 | str = strcat_str(str, len, &tmplen, vars[i].name); |
---|
763 | str = strcat_str(str, len, &tmplen, "</name><dataType>"); |
---|
764 | str = strcat_str(str, len, &tmplen, upnptypes[vars[i].itype & 0x0f]); |
---|
765 | str = strcat_str(str, len, &tmplen, "</dataType>"); |
---|
766 | if(vars[i].iallowedlist) |
---|
767 | { |
---|
768 | str = strcat_str(str, len, &tmplen, "<allowedValueList>"); |
---|
769 | for(j=vars[i].iallowedlist; upnpallowedvalues[j]; j++) |
---|
770 | { |
---|
771 | str = strcat_str(str, len, &tmplen, "<allowedValue>"); |
---|
772 | str = strcat_str(str, len, &tmplen, upnpallowedvalues[j]); |
---|
773 | str = strcat_str(str, len, &tmplen, "</allowedValue>"); |
---|
774 | } |
---|
775 | str = strcat_str(str, len, &tmplen, "</allowedValueList>"); |
---|
776 | } |
---|
777 | /*if(vars[i].defaultValue) */ |
---|
778 | if(vars[i].idefault) |
---|
779 | { |
---|
780 | str = strcat_str(str, len, &tmplen, "<defaultValue>"); |
---|
781 | /*str = strcat_str(str, len, &tmplen, vars[i].defaultValue); */ |
---|
782 | str = strcat_str(str, len, &tmplen, upnpdefaultvalues[vars[i].idefault]); |
---|
783 | str = strcat_str(str, len, &tmplen, "</defaultValue>"); |
---|
784 | } |
---|
785 | str = strcat_str(str, len, &tmplen, "</stateVariable>"); |
---|
786 | /*str = strcat_char(str, len, &tmplen, '\n'); // TEMP ! */ |
---|
787 | i++; |
---|
788 | } |
---|
789 | str = strcat_str(str, len, &tmplen, "</serviceStateTable></scpd>"); |
---|
790 | str[*len] = '\0'; |
---|
791 | return str; |
---|
792 | } |
---|
793 | |
---|
794 | /* genContentDirectory() : |
---|
795 | * Generate the ContentDirectory xml description */ |
---|
796 | char * |
---|
797 | genContentDirectory(int * len) |
---|
798 | { |
---|
799 | return genServiceDesc(len, &scpdContentDirectory); |
---|
800 | } |
---|
801 | |
---|
802 | /* genConnectionManager() : |
---|
803 | * Generate the ConnectionManager xml description */ |
---|
804 | char * |
---|
805 | genConnectionManager(int * len) |
---|
806 | { |
---|
807 | return genServiceDesc(len, &scpdConnectionManager); |
---|
808 | } |
---|
809 | |
---|
810 | /* genX_MS_MediaReceiverRegistrar() : |
---|
811 | * Generate the X_MS_MediaReceiverRegistrar xml description */ |
---|
812 | char * |
---|
813 | genX_MS_MediaReceiverRegistrar(int * len) |
---|
814 | { |
---|
815 | return genServiceDesc(len, &scpdX_MS_MediaReceiverRegistrar); |
---|
816 | } |
---|
817 | |
---|
818 | static char * |
---|
819 | genEventVars(int * len, const struct serviceDesc * s, const char * servns) |
---|
820 | { |
---|
821 | const struct stateVar * v; |
---|
822 | char * str; |
---|
823 | int tmplen; |
---|
824 | char buf[512]; |
---|
825 | tmplen = 512; |
---|
826 | str = (char *)malloc(tmplen); |
---|
827 | if(str == NULL) |
---|
828 | return NULL; |
---|
829 | *len = 0; |
---|
830 | v = s->serviceStateTable; |
---|
831 | snprintf(buf, sizeof(buf), "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\" xmlns:s=\"%s\">", servns); |
---|
832 | str = strcat_str(str, len, &tmplen, buf); |
---|
833 | while(v->name) { |
---|
834 | if(v->itype & 0x80) { |
---|
835 | snprintf(buf, sizeof(buf), "<e:property><%s>", v->name); |
---|
836 | str = strcat_str(str, len, &tmplen, buf); |
---|
837 | //printf("<e:property><s:%s>", v->name); |
---|
838 | switch(v->ieventvalue) { |
---|
839 | case 0: |
---|
840 | break; |
---|
841 | case 255: /* Magical values should go around here */ |
---|
842 | if( strcmp(v->name, "SystemUpdateID") == 0 ) |
---|
843 | { |
---|
844 | snprintf(buf, sizeof(buf), "%d", updateID); |
---|
845 | str = strcat_str(str, len, &tmplen, buf); |
---|
846 | } |
---|
847 | break; |
---|
848 | default: |
---|
849 | str = strcat_str(str, len, &tmplen, upnpallowedvalues[v->ieventvalue]); |
---|
850 | //printf("%s", upnpallowedvalues[v->ieventvalue]); |
---|
851 | } |
---|
852 | snprintf(buf, sizeof(buf), "</%s></e:property>", v->name); |
---|
853 | str = strcat_str(str, len, &tmplen, buf); |
---|
854 | //printf("</s:%s></e:property>\n", v->name); |
---|
855 | } |
---|
856 | v++; |
---|
857 | } |
---|
858 | str = strcat_str(str, len, &tmplen, "</e:propertyset>"); |
---|
859 | //printf("</e:propertyset>\n"); |
---|
860 | //printf("\n"); |
---|
861 | //printf("%d\n", tmplen); |
---|
862 | str[*len] = '\0'; |
---|
863 | return str; |
---|
864 | } |
---|
865 | |
---|
866 | char * |
---|
867 | getVarsContentDirectory(int * l) |
---|
868 | { |
---|
869 | return genEventVars(l, |
---|
870 | &scpdContentDirectory, |
---|
871 | "urn:schemas-upnp-org:service:ContentDirectory:1"); |
---|
872 | } |
---|
873 | |
---|
874 | char * |
---|
875 | getVarsConnectionManager(int * l) |
---|
876 | { |
---|
877 | return genEventVars(l, |
---|
878 | &scpdConnectionManager, |
---|
879 | "urn:schemas-upnp-org:service:ConnectionManager:1"); |
---|
880 | } |
---|
881 | |
---|
882 | char * |
---|
883 | getVarsX_MS_MediaReceiverRegistrar(int * l) |
---|
884 | { |
---|
885 | return genEventVars(l, |
---|
886 | &scpdX_MS_MediaReceiverRegistrar, |
---|
887 | "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"); |
---|
888 | } |
---|
889 | |
---|