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.

730 lines
15 KiB

  1. #include "precomp.h"
  2. #ifdef IP_OBEX
  3. //#include <atlconv.h>
  4. #include "dynamlnk.h"
  5. #include <malloc.h>
  6. #include <ssdp.h>
  7. #define IMPL
  8. // dynamic DLL stuff for SSDP
  9. typedef enum _SsdpApiIndex
  10. {
  11. SSDP_REGISTER_SERVICE = 0,
  12. SSDP_DEREGISTER_SERVICE,
  13. SSDP_STARTUP,
  14. SSDP_FIND_SERVICES,
  15. SSDP_GET_FIRST_SERVICE,
  16. SSDP_GET_NEXT_SERVICE,
  17. SSDP_FIND_SERVICES_CLOSE,
  18. SSDP_CLEANUP,
  19. SSDP_REGISTER_NOTIFICATION,
  20. SSDP_DEREGISTER_NOTIFICATION,
  21. SSDP_CLEANUP_CACHE,
  22. };
  23. // not subject to localization
  24. static LPCSTR g_apchFunctionNames[] = {
  25. "RegisterService",
  26. "DeregisterService",
  27. "SsdpStartup",
  28. "FindServices",
  29. "GetFirstService",
  30. "GetNextService",
  31. "FindServicesClose",
  32. "SsdpCleanup",
  33. "RegisterNotification",
  34. "DeregisterNotification",
  35. "CleanupCache",
  36. NULL
  37. };
  38. //
  39. // NOTE: i have copied the following structs and defines
  40. // so that we are not dependant on the SSDP headers, most of
  41. // which we weren't using.
  42. //
  43. // from ssdp.h
  44. //
  45. typedef struct _SSDP_MESSAGE
  46. {
  47. /* [string] */ LPSTR szType;
  48. /* [string] */ LPSTR szLocHeader;
  49. /* [string] */ LPSTR szAltHeaders;
  50. /* [string] */ LPSTR szUSN;
  51. /* [string] */ LPSTR szSid;
  52. DWORD iSeq;
  53. UINT iLifeTime;
  54. /* [string] */ LPSTR szContent;
  55. } SSDP_MESSAGE;
  56. typedef struct _SSDP_MESSAGE *PSSDP_MESSAGE;
  57. typedef enum _NOTIFY_TYPE {
  58. NOTIFY_ALIVE,
  59. NOTIFY_PROP_CHANGE
  60. } NOTIFY_TYPE;
  61. typedef enum _SSDP_CALLBACK_TYPE {
  62. SSDP_FOUND = 0,
  63. SSDP_ALIVE = 1,
  64. SSDP_BYEBYE = 2,
  65. SSDP_DONE = 3,
  66. SSDP_EVENT = 4,
  67. SSDP_DEAD = 5,
  68. } SSDP_CALLBACK_TYPE, *PSSDP_CALLBACK_TYPE;
  69. typedef void (WINAPI *SERVICE_CALLBACK_FUNC)(SSDP_CALLBACK_TYPE CallbackType,
  70. CONST SSDP_MESSAGE *pSsdpService,
  71. void *pContext);
  72. //
  73. // from ssdperror.h
  74. //
  75. #define SSDP_ERROR_BASE 18000
  76. #define ERROR_NO_MORE_SERVICES SSDP_ERROR_BASE+1
  77. //
  78. // end copy header
  79. //
  80. typedef HANDLE (*REGISTERSERVICE) (PSSDP_MESSAGE, DWORD);
  81. typedef BOOL (*DEREGISTERSERVICE) (HANDLE, BOOL);
  82. typedef BOOL (*SSDPSTARTUP) ();
  83. typedef HANDLE (*FINDSERVICES) (char *, void *, BOOL);
  84. typedef BOOL (*GETFIRSTSERVICE) (HANDLE, PSSDP_MESSAGE *);
  85. typedef BOOL (*GETNEXTSERVICE) (HANDLE, PSSDP_MESSAGE *);
  86. typedef BOOL (*FINDSERVICESCLOSE) (HANDLE);
  87. typedef void (*SSDPCLEANUP) ();
  88. typedef HANDLE (*REGISTERNOTIFICAION) (NOTIFY_TYPE, char *, char *, SERVICE_CALLBACK_FUNC,void *);
  89. typedef BOOL (*DEREGISTERNOTIFICAION) (HANDLE);
  90. typedef BOOL (*CLEANUPCACHE) ();
  91. DynamicDLL g_SsdpDLL( TEXT("SSDPAPI.DLL"), g_apchFunctionNames );
  92. #define USES_CONVERSION int _convert = 0; _convert; UINT _acp = CP_ACP; _acp; LPCWSTR _lpw = NULL; _lpw; LPCSTR _lpa = NULL; _lpa
  93. inline LPSTR WINAPI AtlW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars, UINT acp)
  94. {
  95. // verify that no illegal character present
  96. // since lpa was allocated based on the size of lpw
  97. // don't worry about the number of chars
  98. lpa[0] = '\0';
  99. WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL);
  100. return lpa;
  101. }
  102. #define W2A(lpw) (\
  103. ((_lpw = lpw) == NULL) ? NULL : (\
  104. _convert = (lstrlenW(_lpw)+1)*2,\
  105. AtlW2AHelper((LPSTR) alloca(_convert), _lpw, _convert, _acp)))
  106. #define Trace0 DbgPrint
  107. #define Trace1 DbgPrint
  108. #define Trace2 DbgPrint
  109. #define Trace3 DbgPrint
  110. #define Trace4 DbgPrint
  111. DWORD
  112. DeviceChangeWorker(
  113. PVOID Context
  114. );
  115. #define T2A W2A
  116. const WCHAR *c_szObex= TEXT("OBEX");
  117. BOOL
  118. RegisterWithSsdp(
  119. const in_addr *IpAddress,
  120. SOCKET *listenSocket,
  121. HANDLE *SsdpHandle,
  122. DWORD dwPort
  123. )
  124. {
  125. SOCKET sock = INVALID_SOCKET;
  126. sockaddr_in saListen = {0};
  127. int nRet = 0;
  128. TCHAR szHostNameW[MAX_PATH];
  129. SSDP_MESSAGE message = {0};
  130. DWORD dwFlags = 0, dwSize;
  131. HRESULT hr;
  132. char szPort[MAX_PATH];
  133. char * pszAddr;
  134. USES_CONVERSION;
  135. //
  136. // establish listen socket
  137. //
  138. sock = socket( AF_INET, SOCK_STREAM, 0 );
  139. if ( sock == INVALID_SOCKET )
  140. {
  141. Trace2( "RegisterWithSsdp - socket() for port 0x%lx failed! 0x%lx\n", dwPort);
  142. goto Error;
  143. }
  144. //
  145. // now get ready to bind it to the address
  146. //
  147. saListen.sin_addr=*IpAddress;
  148. saListen.sin_family = AF_INET;
  149. saListen.sin_port = (short) dwPort;
  150. nRet = bind( sock, (const struct sockaddr *)&saListen, sizeof(saListen) );
  151. if( nRet == SOCKET_ERROR ) {
  152. Trace2( "RegisterWithSsdp - bind on port 0x%lx failed! 0x%lx\n", dwPort, WSAGetLastError());
  153. goto Error;
  154. }
  155. // set socket into listening mode
  156. nRet = listen( sock, 2 );
  157. if ( nRet == SOCKET_ERROR ) {
  158. Trace2( "RegisterWithSsdp - listen on port 0x%lx failed! 0x%lx\n", dwPort, WSAGetLastError());
  159. goto Error;
  160. }
  161. // register with SSDP so other people can find us
  162. _itoa(dwPort, szPort, 10);
  163. // gethostname(szHostName, sizeof(szHostName));
  164. dwSize = sizeof(szHostNameW);
  165. GetComputerNameEx(ComputerNameDnsFullyQualified, szHostNameW, &dwSize);
  166. pszAddr = inet_ntoa(*IpAddress);
  167. // now fill in the struct
  168. message.szType = T2A(c_szObex);
  169. message.szLocHeader = T2A(szHostNameW);
  170. message.szAltHeaders = szPort;
  171. message.szUSN = pszAddr;
  172. message.szSid = "";
  173. message.iLifeTime = 1 * 60;
  174. dwFlags = 0;//SSDP_SERVICE_PERSISTENT;
  175. // call the SSDP api
  176. if ( g_SsdpDLL.LoadFunctionPointers() )
  177. {
  178. // init SSDP
  179. //
  180. (SSDPSTARTUP) g_SsdpDLL[SSDP_STARTUP]();
  181. *SsdpHandle = ((REGISTERSERVICE) g_SsdpDLL[SSDP_REGISTER_SERVICE])(&message, dwFlags);
  182. if (SsdpHandle == INVALID_HANDLE_VALUE) {
  183. Trace2( "SSDP RegisterService on port 0x%lx failed! 0x%lx\n", dwPort, GetLastError());
  184. goto Error;
  185. } else {
  186. Trace3("RegisterWithSsdp - host name %ws, addr %s, port %d\n", szHostNameW, pszAddr, dwPort);
  187. }
  188. }
  189. *listenSocket = sock;
  190. return TRUE;
  191. Error:
  192. closesocket(sock);
  193. sock = INVALID_SOCKET;
  194. return FALSE;
  195. }
  196. VOID
  197. UnregisterWithSsdp(
  198. HANDLE SsdpHandle
  199. )
  200. {
  201. // call the SSDP api
  202. if ( g_SsdpDLL.LoadFunctionPointers() ) {
  203. ((DEREGISTERSERVICE) g_SsdpDLL[SSDP_DEREGISTER_SERVICE])(SsdpHandle, 0);
  204. //
  205. // shutdown ssdp
  206. //
  207. (SSDPCLEANUP) g_SsdpDLL[SSDP_CLEANUP]();
  208. }
  209. return;
  210. }
  211. typedef struct _SSDP_CONTROL {
  212. HANDLE hNotify;
  213. HWND hWnd;
  214. UINT Msg;
  215. LONG ReferenceCount;
  216. BOOL Closing;
  217. SOCKET Socket;
  218. WSAOVERLAPPED WsOverlapped;
  219. TCHAR HostName[256];
  220. CRITICAL_SECTION Lock;
  221. } SSDP_CONTROL, *PSSDP_CONTROL;
  222. VOID
  223. RemoveReferenceOnSsdpControl(
  224. PSSDP_CONTROL Control
  225. );
  226. void
  227. SsdpCallbackHandler(
  228. SSDP_CALLBACK_TYPE ct,
  229. CONST SSDP_MESSAGE *pSsdpMessage,
  230. HANDLE Context
  231. )
  232. {
  233. PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
  234. DbgPrint("SsdpCallbackHandler: %d\n",ct);
  235. switch (ct) {
  236. case SSDP_DONE:
  237. case SSDP_ALIVE:
  238. case SSDP_FOUND:
  239. case SSDP_EVENT:
  240. DbgPrint("SsdpCallabck: Name=%s, Address=%s\n",pSsdpMessage->szLocHeader,pSsdpMessage->szUSN);
  241. break;
  242. default:
  243. break;
  244. }
  245. PostMessage(
  246. Control->hWnd,
  247. Control->Msg,
  248. ct,
  249. NULL
  250. );
  251. return;
  252. }
  253. LONG
  254. RefreshSsdp(
  255. VOID
  256. )
  257. {
  258. USES_CONVERSION;
  259. g_SsdpDLL.LoadFunctionPointers();
  260. // init SSDP
  261. //
  262. (SSDPSTARTUP) g_SsdpDLL[SSDP_STARTUP]();
  263. (CLEANUPCACHE) g_SsdpDLL[SSDP_CLEANUP_CACHE]();
  264. HANDLE hSearch;
  265. hSearch = ((FINDSERVICES) g_SsdpDLL[SSDP_FIND_SERVICES])(T2A(c_szObex), NULL, TRUE);
  266. if (hSearch != INVALID_HANDLE_VALUE) {
  267. ((FINDSERVICESCLOSE) g_SsdpDLL[SSDP_FIND_SERVICES_CLOSE])(hSearch);
  268. }
  269. // shutdown ssdp
  270. (SSDPCLEANUP) g_SsdpDLL[SSDP_CLEANUP]();
  271. return ERROR_SUCCESS;
  272. }
  273. VOID
  274. SsdpAddressListChangeHandler(
  275. DWORD Error,
  276. DWORD BytesTransfered,
  277. LPWSAOVERLAPPED WsOverlapped,
  278. DWORD Flags
  279. )
  280. {
  281. PSSDP_CONTROL Control=(PSSDP_CONTROL)WsOverlapped->hEvent;
  282. RefreshSsdp();
  283. PostMessage(
  284. Control->hWnd,
  285. Control->Msg,
  286. -1,
  287. NULL
  288. );
  289. DeviceChangeWorker(Control);
  290. }
  291. DWORD
  292. DeviceChangeWorker(
  293. PVOID Context
  294. )
  295. {
  296. PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
  297. int err;
  298. DWORD BytesReturned;
  299. if (!Control->Closing) {
  300. ZeroMemory(&Control->WsOverlapped,sizeof(Control->WsOverlapped));
  301. Control->WsOverlapped.hEvent=Control;
  302. err=WSAIoctl(
  303. Control->Socket,
  304. SIO_ADDRESS_LIST_CHANGE,
  305. NULL,
  306. 0,
  307. NULL,
  308. 0,
  309. &BytesReturned,
  310. &Control->WsOverlapped,
  311. SsdpAddressListChangeHandler
  312. );
  313. if (err == SOCKET_ERROR) {
  314. if (WSAGetLastError() != WSA_IO_PENDING) {
  315. //
  316. // the call failed and return value was not pending
  317. //
  318. RemoveReferenceOnSsdpControl(Control);
  319. }
  320. }
  321. } else {
  322. RemoveReferenceOnSsdpControl(Control);
  323. }
  324. return 0;
  325. }
  326. HANDLE
  327. CreateSsdpDiscoveryObject(
  328. LPSTR Service,
  329. HWND hWnd,
  330. UINT Msg
  331. )
  332. {
  333. PSSDP_CONTROL Control;
  334. ULONG dwSize;
  335. BOOL bResult;
  336. USES_CONVERSION;
  337. Control = new SSDP_CONTROL;
  338. if (Control == NULL) {
  339. return NULL;
  340. }
  341. InitializeCriticalSection(&Control->Lock);
  342. dwSize=sizeof(Control->HostName)/sizeof(TCHAR);
  343. GetComputerNameEx(ComputerNameDnsFullyQualified, Control->HostName, &dwSize);
  344. Control->Closing =FALSE;
  345. Control->Socket = INVALID_SOCKET;
  346. Control->ReferenceCount=1;
  347. Control->hWnd=hWnd;
  348. Control->Msg=Msg;
  349. g_SsdpDLL.LoadFunctionPointers();
  350. // init SSDP
  351. //
  352. (SSDPSTARTUP) g_SsdpDLL[SSDP_STARTUP]();
  353. #if 1
  354. // Tell SSDP to start notifying us of devices
  355. //
  356. (CLEANUPCACHE) g_SsdpDLL[SSDP_CLEANUP_CACHE]();
  357. #endif
  358. // register for notification as devices come and go
  359. //
  360. Control->hNotify = ((REGISTERNOTIFICAION) g_SsdpDLL[SSDP_REGISTER_NOTIFICATION])(
  361. NOTIFY_ALIVE,
  362. T2A(c_szObex),
  363. NULL,
  364. SsdpCallbackHandler,
  365. Control
  366. );
  367. if ((Control->hNotify == INVALID_HANDLE_VALUE) || (Control->hNotify == NULL)) {
  368. Trace1("CIpTransport::InitiateDiscovery - RegisterNotification failed! %d", GetLastError());
  369. goto CleanUp;
  370. }
  371. #if 1
  372. HANDLE hSearch;
  373. hSearch = ((FINDSERVICES) g_SsdpDLL[SSDP_FIND_SERVICES])(T2A(c_szObex), NULL, TRUE);
  374. if (hSearch != INVALID_HANDLE_VALUE) {
  375. ((FINDSERVICESCLOSE) g_SsdpDLL[SSDP_FIND_SERVICES_CLOSE])(hSearch);
  376. }
  377. #endif
  378. // RefreshSsdp();
  379. Control->Socket=socket(AF_INET,SOCK_STREAM,0);
  380. if (Control->Socket == INVALID_SOCKET) {
  381. goto CleanUp;
  382. }
  383. //
  384. // add one refcount for the workitem
  385. //
  386. InterlockedIncrement(&Control->ReferenceCount);
  387. bResult=QueueUserWorkItem(
  388. DeviceChangeWorker,
  389. Control,
  390. WT_EXECUTEINIOTHREAD
  391. );
  392. if (bResult) {
  393. return Control;
  394. } else {
  395. RemoveReferenceOnSsdpControl(Control);
  396. }
  397. CleanUp:
  398. RemoveReferenceOnSsdpControl(Control);
  399. return NULL;
  400. }
  401. VOID
  402. RemoveReferenceOnSsdpControl(
  403. PSSDP_CONTROL Control
  404. )
  405. {
  406. LONG CurrentCount;
  407. CurrentCount=InterlockedDecrement(&Control->ReferenceCount);
  408. if (CurrentCount == 0) {
  409. //
  410. // cleanup notifications with SSDP
  411. //
  412. if (Control->hNotify != INVALID_HANDLE_VALUE) {
  413. ((DEREGISTERNOTIFICAION) g_SsdpDLL[SSDP_DEREGISTER_NOTIFICATION])(Control->hNotify);
  414. }
  415. (SSDPCLEANUP) g_SsdpDLL[SSDP_CLEANUP]();
  416. DeleteCriticalSection(&Control->Lock);
  417. delete Control;
  418. }
  419. return;
  420. }
  421. VOID
  422. CloseSsdpDiscoveryObject(
  423. HANDLE Context
  424. )
  425. {
  426. PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
  427. Control->Closing=TRUE;
  428. closesocket(Control->Socket);
  429. RemoveReferenceOnSsdpControl(Control);
  430. }
  431. LONG
  432. GetSsdpDevices(
  433. HANDLE Context,
  434. POBEX_DEVICE_LIST DeviceList,
  435. ULONG *ListLength
  436. )
  437. {
  438. PSSDP_CONTROL Control=(PSSDP_CONTROL)Context;
  439. HANDLE hSearch = NULL;
  440. LPSTR pszTypeURI;
  441. ULONG BytesAvailible=*ListLength;
  442. ULONG BytesUsed=0;
  443. POBEX_DEVICE CurrentDevice=&DeviceList->DeviceList[0];
  444. USES_CONVERSION;
  445. ZeroMemory(DeviceList,BytesAvailible);
  446. if (BytesAvailible < FIELD_OFFSET(OBEX_DEVICE_LIST,DeviceList)) {
  447. return ERROR_INSUFFICIENT_BUFFER;
  448. }
  449. BytesUsed+=FIELD_OFFSET(OBEX_DEVICE_LIST,DeviceList);
  450. DeviceList->DeviceCount=0;
  451. pszTypeURI = T2A(c_szObex);
  452. hSearch = ((FINDSERVICES) g_SsdpDLL[SSDP_FIND_SERVICES])(pszTypeURI, NULL, FALSE);
  453. if (hSearch != INVALID_HANDLE_VALUE) {
  454. SSDP_MESSAGE * pSsdpMessage = NULL;
  455. BOOL fContinue = ((GETFIRSTSERVICE) g_SsdpDLL[SSDP_GET_FIRST_SERVICE])(hSearch, &pSsdpMessage);
  456. ASSERT(DeviceList->DeviceCount == 0);
  457. while (fContinue) {
  458. ULONG Address = inet_addr(pSsdpMessage->szUSN);
  459. int Port = atoi(pSsdpMessage->szAltHeaders);
  460. if (BytesAvailible >= BytesUsed + sizeof(OBEX_DEVICE)) {
  461. //
  462. // we have enough romm in the buffer for this one
  463. //
  464. MultiByteToWideChar(
  465. CP_ACP,
  466. 0,
  467. pSsdpMessage->szLocHeader,
  468. -1,
  469. CurrentDevice->DeviceName,
  470. sizeof(CurrentDevice->DeviceName)/sizeof(WCHAR)
  471. );
  472. DbgPrint("irmon: count=%d, remote=%ws, host=%ws\n",DeviceList->DeviceCount,CurrentDevice->DeviceName,Control->HostName);
  473. if (lstrcmpi(CurrentDevice->DeviceName,Control->HostName) != 0) {
  474. //
  475. // not this machine
  476. //
  477. CurrentDevice->DeviceType=TYPE_IP;
  478. CurrentDevice->DeviceName[sizeof(CurrentDevice->DeviceName)/sizeof(WCHAR)]=L'\0';
  479. CurrentDevice->DeviceSpecific.s.Ip.IpAddress=Address;
  480. CurrentDevice->DeviceSpecific.s.Ip.Port=(USHORT)Port;
  481. CurrentDevice++;
  482. DeviceList->DeviceCount++;
  483. }
  484. }
  485. BytesUsed+=sizeof(OBEX_DEVICE);
  486. fContinue = ((GETNEXTSERVICE) g_SsdpDLL[SSDP_GET_NEXT_SERVICE])(hSearch, &pSsdpMessage);
  487. }
  488. ((FINDSERVICESCLOSE) g_SsdpDLL[SSDP_FIND_SERVICES_CLOSE])(hSearch);
  489. if (BytesUsed > BytesAvailible) {
  490. *ListLength=BytesUsed;
  491. return ERROR_INSUFFICIENT_BUFFER;
  492. }
  493. DbgPrint("irmon: %d ip device found\n",DeviceList->DeviceCount);
  494. return ERROR_SUCCESS;
  495. } else {
  496. //
  497. // Check to see if the handle is invalid merely because no devices
  498. // are present
  499. //
  500. DWORD dwError = GetLastError();
  501. if (dwError == ERROR_NO_MORE_SERVICES) {
  502. Trace0("FindServices failed because no devices were present. This is OK");
  503. dwError=ERROR_SUCCESS;
  504. } else {
  505. Trace1("FindServices call failed in FindByDeviceType %lx", dwError);
  506. }
  507. return dwError;
  508. }
  509. }
  510. #endif //IP_OBEX