Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

492 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: C O N T R O L . C P P
  7. //
  8. // Contents: Functions dealing with UPnP service control
  9. //
  10. // Notes:
  11. //
  12. // Author: danielwe 28 Oct 1999
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "ncbase.h"
  18. #include "oleauto.h"
  19. #include "updiagp.h"
  20. #include "media.h"
  21. #include "ncinet.h"
  22. #include "util.h"
  23. extern const STANDARD_OPERATION_LIST c_Ops;
  24. //
  25. // Global service control structure for demo services
  26. //
  27. extern const DEMO_SERVICE_CTL c_rgSvc[] =
  28. {
  29. {
  30. TEXT("app"),
  31. 6,
  32. {
  33. { TEXT("VolumeUp"), Val_VolumeUp, Do_VolumeUp },
  34. { TEXT("VolumeDown"), Val_VolumeDown, Do_VolumeDown },
  35. { TEXT("SetVolume"), Val_SetVolume, Do_SetVolume },
  36. { TEXT("Mute"), Val_Mute, Do_Mute },
  37. { TEXT("Power"), Val_Power, Do_Power },
  38. { TEXT("LoadFile"), Val_LoadFile, Do_LoadFile },
  39. },
  40. },
  41. {
  42. TEXT("xport"),
  43. 4,
  44. {
  45. { TEXT("Play"), Val_Play, Do_Play },
  46. { TEXT("Stop"), Val_Stop, Do_Stop },
  47. { TEXT("Pause"), Val_Pause, Do_Pause },
  48. { TEXT("SetPos"), Val_SetPos, Do_SetPos },
  49. }
  50. },
  51. {
  52. TEXT("clock"),
  53. 1,
  54. {
  55. { TEXT("SetDateTime"), Val_SetTime, Do_SetTime },
  56. }
  57. },
  58. };
  59. extern const DWORD c_cDemoSvc = celems(c_rgSvc);
  60. ACTION *PActFromSz(ACTION_SET * pActionSet, LPCTSTR szAction)
  61. {
  62. for (DWORD iAction = 0; iAction < pActionSet->cActions; iAction++)
  63. {
  64. if (!_tcsicmp(pActionSet->rgActions[iAction].szActionName, szAction))
  65. return &pActionSet->rgActions[iAction];
  66. }
  67. return NULL;
  68. }
  69. const DEMO_ACTION *PDemoActFromSz(const DEMO_SERVICE_CTL *psvc, LPCTSTR szAction)
  70. {
  71. DWORD iAction;
  72. Assert(psvc);
  73. for (iAction = 0; iAction < psvc->cActions; iAction++)
  74. {
  75. if (!_tcsicmp(psvc->rgActions[iAction].szAction, szAction))
  76. return &psvc->rgActions[iAction];
  77. }
  78. return NULL;
  79. }
  80. UPNPSVC *PSvcFromIdDev(UPNPDEV *pdev, LPCTSTR szId)
  81. {
  82. DWORD isvc;
  83. DWORD idev;
  84. UPNPSVC * psvc;
  85. // First look thru all local services
  86. //
  87. for (isvc = 0; isvc < pdev->cSvcs; isvc++)
  88. {
  89. psvc = pdev->rgSvcs[isvc];
  90. if (!_tcsicmp(psvc->szControlId, szId))
  91. {
  92. return psvc;
  93. }
  94. }
  95. // If not found there, recurse for each sub-device
  96. //
  97. for (idev = 0; idev < pdev->cDevs; idev++)
  98. {
  99. psvc = PSvcFromIdDev(pdev->rgDevs[idev], szId);
  100. if (psvc)
  101. {
  102. return psvc;
  103. }
  104. }
  105. return NULL;
  106. }
  107. //+---------------------------------------------------------------------------
  108. //
  109. // Function: PSvcFromId
  110. //
  111. // Purpose: Given a service identifier, return the service for which a
  112. // valid control handler exists
  113. //
  114. // Arguments:
  115. // szId [in] Service identifier
  116. //
  117. // Returns: Matching service
  118. //
  119. // Author: danielwe 6 Nov 1999
  120. //
  121. // Notes:
  122. //
  123. UPNPSVC *PSvcFromId(LPCTSTR szId)
  124. {
  125. DWORD idev;
  126. // Loop thru all devices and all services within those devices looking
  127. // for a service that implements the control handler identified by szId
  128. //
  129. for (idev = 0; idev < g_params.cCd; idev++)
  130. {
  131. UPNPSVC * psvc;
  132. psvc = PSvcFromIdDev(g_params.rgCd[idev], szId);
  133. if (psvc)
  134. {
  135. return psvc;
  136. }
  137. }
  138. TraceTag(ttidUpdiag, "Can't find a service matching id: '%s'.", szId);
  139. return NULL;
  140. }
  141. // BUGBUG
  142. /*
  143. DWORD ValidateActionArguments(ACTION * pAction,
  144. g_pdata->cArgs,
  145. (ARG *) &g_pdata->rgArgs)
  146. {
  147. return 1;
  148. }
  149. */
  150. const STANDARD_OPERATION * PStdOpFromSz(LPTSTR szOpName)
  151. {
  152. const STANDARD_OPERATION * pStdOperation = NULL;
  153. for (DWORD iOps = 0; iOps < c_Ops.cOperations; iOps++)
  154. {
  155. if (!_tcsicmp(c_Ops.rgOperations[iOps].szOperation, szOpName))
  156. {
  157. pStdOperation = &c_Ops.rgOperations[iOps];
  158. break;
  159. }
  160. }
  161. return pStdOperation;
  162. }
  163. DWORD dwArgsFromOpName(LPTSTR szOpName)
  164. {
  165. DWORD dwArgs=0;
  166. const STANDARD_OPERATION * pStdOperation = PStdOpFromSz(szOpName);
  167. if (pStdOperation)
  168. {
  169. dwArgs = pStdOperation->nArguments;
  170. }
  171. return dwArgs;
  172. }
  173. DWORD DwPerformOperation(UPNPSVC * psvc, OPERATION_DATA * pOpData,
  174. DWORD cArgs, ARG *rgArgs)
  175. {
  176. const STANDARD_OPERATION * pStdOperation = PStdOpFromSz(pOpData->szOpName);
  177. if(pStdOperation)
  178. {
  179. return pStdOperation->pfnOperation(psvc, pOpData, cArgs, rgArgs);
  180. }
  181. else
  182. {
  183. TraceTag(ttidUpdiag, "Operation %s is not supported by the emulated device.",
  184. pOpData->szOpName);
  185. return 1;
  186. }
  187. }
  188. // BUGBUG: separate the demo stuff from the generic stuff
  189. VOID PerformActionForDemoService(UPNPSVC * psvc);
  190. //+---------------------------------------------------------------------------
  191. //
  192. // Function: ProcessControlRequest
  193. //
  194. // Purpose: Main control request handler
  195. //
  196. // Arguments:
  197. // (none)
  198. //
  199. // Returns: Nothing
  200. //
  201. // Author: danielwe 6 Nov 1999
  202. //
  203. // tongl 11/20/99
  204. // added the state table change and moved the functionality
  205. // to play midi files to PerformActionForDemoService
  206. //
  207. // Notes: This ISAPICTL extension will signal an event telling us
  208. // to process a request that it has received. This function
  209. // determines which UPnP service the request was meant for,
  210. // and if a control handler for that service exists,
  211. // it calls the appropriate code to process the request
  212. // to make service state table changes and notify user
  213. // control points
  214. //
  215. //
  216. VOID ProcessControlRequest()
  217. {
  218. if (WAIT_OBJECT_0 == WaitForSingleObject(g_hMutex, INFINITE))
  219. {
  220. DWORD dwReturn = 0;
  221. UPNPSVC * psvc;
  222. ACTION * pAction;
  223. LPTSTR pszEventSource;
  224. pszEventSource = TszFromSz(g_pdata->szEventSource);
  225. if (pszEventSource)
  226. {
  227. TraceTag(ttidUpdiag, "Processing a control request for %s!",
  228. g_pdata->szEventSource);
  229. psvc = PSvcFromId(pszEventSource);
  230. if (psvc)
  231. {
  232. LPTSTR pszAction;
  233. // Validate arguments and set action return value
  234. pszAction = TszFromSz(g_pdata->szAction);
  235. if (pszAction)
  236. {
  237. pAction = PActFromSz(&(psvc->action_set), pszAction);
  238. if (pAction)
  239. {
  240. /*
  241. // NYI
  242. dwReturn = ValidateActionArguments(pAction,
  243. g_pdata->cArgs,
  244. (ARG *) &g_pdata->rgArgs);
  245. */
  246. dwReturn = 1;
  247. if (!dwReturn)
  248. {
  249. TraceTag(ttidUpdiag, "Failed to validate action '%s'.",
  250. pAction->szActionName);
  251. }
  252. }
  253. delete [] pszAction;
  254. }
  255. else
  256. {
  257. TraceTag(ttidUpdiag, "ProcessControlRequest: TszFromSz failed");
  258. }
  259. }
  260. g_pdata->dwReturn = dwReturn;
  261. TraceTag(ttidUpdiag, "Signalling event for ISAPICTL to continue...");
  262. // Release the ISAPI DLL so it can return to the UCP
  263. SetEvent(g_hEventRet);
  264. if (dwReturn)
  265. {
  266. HRESULT hr;
  267. DWORD dwActionResult;
  268. AssertSz(pAction, "Good return but no action?");
  269. // Now perform the action
  270. TraceTag(ttidUpdiag, "Performing action %s.", pAction->szActionName);
  271. OPERATION_DATA * pOperation;
  272. DWORD iArgs =0;
  273. DWORD cArgs;
  274. ARG rgArgs[MAX_PROP_CHANGES];
  275. for (DWORD iOp=0; iOp<pAction->cOperations; iOp++)
  276. {
  277. pOperation = &pAction->rgOperations[iOp];
  278. // get the arguments for this operation
  279. cArgs = dwArgsFromOpName(pOperation->szOpName);
  280. Assert(iArgs+cArgs <= g_pdata->cArgs);
  281. for(DWORD i=0; i<cArgs; i++)
  282. {
  283. lstrcpy(rgArgs[i].szValue, g_pdata->rgArgs[iArgs].szValue);
  284. iArgs++;
  285. }
  286. // perform the operation
  287. dwActionResult = DwPerformOperation(psvc, pOperation, cArgs, rgArgs);
  288. if (dwActionResult)
  289. break;
  290. }
  291. if (!dwActionResult)
  292. {
  293. TraceTag(ttidUpdiag, "Successfully completed action %s.",
  294. pAction->szActionName);
  295. }
  296. else
  297. {
  298. TraceTag(ttidUpdiag, "Failed to complete action %s.",
  299. pAction->szActionName);
  300. }
  301. }
  302. else
  303. {
  304. TraceTag(ttidUpdiag, "Did not perform action for %s.",
  305. g_pdata->szEventSource);
  306. }
  307. if (psvc && psvc->psvcDemoCtl)
  308. {
  309. PerformActionForDemoService(psvc);
  310. }
  311. ReleaseMutex(g_hMutex);
  312. }
  313. delete [] pszEventSource;
  314. }
  315. }
  316. //+---------------------------------------------------------------------------
  317. //
  318. // Function: PerformActionForDemoService
  319. //
  320. // Purpose: Perform the action on the demo services (midi-player)
  321. //
  322. // Arguments:
  323. // (none)
  324. //
  325. // Returns: Nothing
  326. //
  327. // Author: danielwe 6 Nov 1999
  328. //
  329. // Notes: For the two demo services, this function calls the
  330. // appropriate code to process the request.
  331. //
  332. VOID PerformActionForDemoService(UPNPSVC * psvc)
  333. {
  334. const DEMO_ACTION * pAct;
  335. DWORD dwReturn = 0;
  336. // Validate arguments and set action return value
  337. LPTSTR pszAction = TszFromSz(g_pdata->szAction);
  338. if (pszAction)
  339. {
  340. pAct = PDemoActFromSz(psvc->psvcDemoCtl, pszAction);
  341. if (pAct)
  342. {
  343. dwReturn = pAct->pfnValidate(g_pdata->cArgs,
  344. (ARG *) &g_pdata->rgArgs);
  345. if (!dwReturn)
  346. {
  347. TraceTag(ttidUpdiag, "Failed to validate demo action '%s'.",
  348. pAct->szAction);
  349. }
  350. }
  351. delete [] pszAction;
  352. }
  353. else
  354. {
  355. TraceTag(ttidUpdiag, "PerformActionForDemoService: TszFromSz");
  356. }
  357. g_pdata->dwReturn = dwReturn;
  358. TraceTag(ttidUpdiag, "Signalling event for ISAPICTL to continue...");
  359. // Release the ISAPI DLL so it can return to the UCP
  360. SetEvent(g_hEventRet);
  361. if (dwReturn)
  362. {
  363. DWORD dwActionResult;
  364. AssertSz(pAct, "Good return but no action?");
  365. // Now perform the action
  366. TraceTag(ttidUpdiag, "Performing action %s.", pAct->szAction);
  367. dwActionResult = pAct->pfnAction(g_pdata->cArgs,
  368. (ARG *) &g_pdata->rgArgs);
  369. if (dwActionResult)
  370. {
  371. TraceTag(ttidUpdiag, "Successfully completed action %s.",
  372. pAct->szAction);
  373. }
  374. else
  375. {
  376. TraceTag(ttidUpdiag, "Failed to complete action %s. Result = %d.",
  377. pAct->szAction, dwActionResult);
  378. }
  379. }
  380. else
  381. {
  382. TraceTag(ttidUpdiag, "Did not perform action for %s.",
  383. g_pdata->szEventSource);
  384. }
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // Function: RequestHandlerThreadStart
  389. //
  390. // Purpose: Start routine for the request handler thread
  391. //
  392. // Arguments:
  393. // pvParam []
  394. //
  395. // Returns: Always 0
  396. //
  397. // Author: danielwe 6 Nov 1999
  398. //
  399. // Notes:
  400. //
  401. DWORD WINAPI RequestHandlerThreadStart(LPVOID pvParam)
  402. {
  403. HRESULT hr;
  404. hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  405. if (SUCCEEDED(hr))
  406. {
  407. TraceTag(ttidUpdiag, "COM initialized.");
  408. while (TRUE)
  409. {
  410. TraceTag(ttidUpdiag, "Awaiting control request...");
  411. if (WAIT_OBJECT_0 == WaitForSingleObject(g_hEvent, INFINITE))
  412. {
  413. TraceTag(ttidUpdiag, "Event was signalled...");
  414. // When the event is signalled, a control request is ready
  415. ProcessControlRequest();
  416. }
  417. }
  418. // Right now this will never be called because this thread never
  419. // exits, but eventually we may want it to.
  420. //
  421. CoUninitialize();
  422. }
  423. else
  424. {
  425. TraceError("RequestHandlerThreadStart - CoInitializeEx", hr);
  426. }
  427. return 0;
  428. }