Leaked source code of windows server 2003
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.

700 lines
20 KiB

  1. #define UNICODE
  2. #include <nt.h>
  3. #include <ntrtl.h>
  4. #include <nturtl.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <windows.h>
  8. #include <mmsystem.h>
  9. #include <winsock2.h>
  10. #include <af_irda.h>
  11. #include <irioctl.h>
  12. #include <irtypes.h>
  13. #include <resrc1.h>
  14. #include "internal.h"
  15. #define MAX_ATTRIB_LEN 64
  16. #define DEVICE_LIST_LEN 5
  17. #define DISCOVERY_BUFFER_SIZE (sizeof(DEVICELIST) - \
  18. sizeof(IRDA_DEVICE_INFO) + \
  19. (sizeof(IRDA_DEVICE_INFO) * DEVICE_LIST_LEN))
  20. typedef struct _IR_DISCOVERY_OBJECT {
  21. BOOL Closing;
  22. BOOL UseLazyDisc;
  23. LONG ReferenceCount;
  24. HANDLE DeviceHandle;
  25. HANDLE EventHandle;
  26. SOCKET Socket;
  27. HWND WindowHandle;
  28. UINT DiscoveryWindowMessage;
  29. UINT LinkWindowMessage;
  30. HANDLE TimerHandle;
  31. IO_STATUS_BLOCK DiscoveryStatusBlock;
  32. IO_STATUS_BLOCK LinkStateStatusBlock;
  33. BYTE IoDeviceListBuffer[DISCOVERY_BUFFER_SIZE];
  34. BYTE CurrentDeviceListBuffer[DISCOVERY_BUFFER_SIZE];
  35. IRLINK_STATUS IoLinkStatus;
  36. IRLINK_STATUS CurrentLinkStatus;
  37. } IR_DISCOVERY_OBJECT, *PIR_DISCOVERY_OBJECT;
  38. VOID WINAPI
  39. TimerApcRoutine(
  40. PIR_DISCOVERY_OBJECT DiscoveryObject,
  41. DWORD LowTime,
  42. DWORD HighTime
  43. );
  44. VOID
  45. WINAPI
  46. DiscoverComplete(
  47. PVOID ApcContext,
  48. PIO_STATUS_BLOCK IoStatusBlock,
  49. DWORD Reserved
  50. );
  51. VOID
  52. WINAPI
  53. LinkStatusComplete(
  54. PVOID ApcContext,
  55. PIO_STATUS_BLOCK IoStatusBlock,
  56. DWORD Reserved
  57. );
  58. int
  59. QueryIASForInteger(SOCKET QuerySock,
  60. u_char *pirdaDeviceID,
  61. char *pClassName,
  62. int ClassNameLen, // including trailing NULL
  63. char *pAttribute,
  64. int AttributeLen, // including trailing NULL
  65. int *pValue)
  66. {
  67. BYTE IASQueryBuff[sizeof(IAS_QUERY) - 3 + MAX_ATTRIB_LEN];
  68. int IASQueryLen = sizeof(IASQueryBuff);
  69. PIAS_QUERY pIASQuery = (PIAS_QUERY) &IASQueryBuff[0];
  70. #if DBG
  71. if (!((ClassNameLen > 0 && ClassNameLen <= IAS_MAX_CLASSNAME) &&
  72. (AttributeLen > 0 && AttributeLen <= IAS_MAX_ATTRIBNAME)))
  73. {
  74. DEBUGMSG(("IRMON-FTP: QueryIASForInteger, bad parms\n"));
  75. return(SOCKET_ERROR);
  76. }
  77. #endif
  78. RtlCopyMemory(&pIASQuery->irdaDeviceID[0], pirdaDeviceID, 4);
  79. RtlCopyMemory(&pIASQuery->irdaClassName[0], pClassName, ClassNameLen);
  80. RtlCopyMemory(&pIASQuery->irdaAttribName[0], pAttribute, AttributeLen);
  81. if (getsockopt(QuerySock, SOL_IRLMP, IRLMP_IAS_QUERY,
  82. (char *) pIASQuery, &IASQueryLen) == SOCKET_ERROR)
  83. {
  84. #if 0
  85. DEBUGMSG(("IRMON-FTP: IAS Query [\"%s\",\"%s\"] failed %ws\n",
  86. pIASQuery->irdaClassName,
  87. pIASQuery->irdaAttribName,
  88. GetLastErrorText()));
  89. #endif
  90. return SOCKET_ERROR;
  91. }
  92. if (pIASQuery->irdaAttribType != IAS_ATTRIB_INT)
  93. {
  94. DEBUGMSG(("IRMON-FTP: IAS Query [\"%s\",\"%s\"] irdaAttribType not int (%d)\n",
  95. pIASQuery->irdaClassName,
  96. pIASQuery->irdaAttribName,
  97. pIASQuery->irdaAttribType));
  98. return SOCKET_ERROR;
  99. }
  100. *pValue = pIASQuery->irdaAttribute.irdaAttribInt;
  101. return(0);
  102. }
  103. HANDLE
  104. CreateIrDiscoveryObject(
  105. HWND WindowHandle,
  106. UINT DiscoveryWindowMessage,
  107. UINT LinkWindowMessage
  108. )
  109. {
  110. PIR_DISCOVERY_OBJECT DiscoveryObject;
  111. LONGLONG DueTime=Int32x32To64(1000,-10000);
  112. DiscoveryObject=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*DiscoveryObject));
  113. if (DiscoveryObject == NULL) {
  114. return NULL;
  115. }
  116. DiscoveryObject->WindowHandle=WindowHandle;
  117. DiscoveryObject->DiscoveryWindowMessage=DiscoveryWindowMessage;
  118. DiscoveryObject->LinkWindowMessage=LinkWindowMessage;
  119. DiscoveryObject->DeviceHandle=INVALID_HANDLE_VALUE;
  120. DiscoveryObject->Socket=INVALID_SOCKET;
  121. DiscoveryObject->TimerHandle=CreateWaitableTimer(NULL,FALSE,NULL);
  122. if (DiscoveryObject->TimerHandle == NULL) {
  123. HeapFree(GetProcessHeap(),0,DiscoveryObject);
  124. return NULL;
  125. }
  126. DiscoveryObject->EventHandle=CreateEvent(
  127. NULL,
  128. TRUE,
  129. FALSE,
  130. NULL
  131. );
  132. if (DiscoveryObject->EventHandle == NULL) {
  133. CloseHandle(DiscoveryObject->TimerHandle);
  134. HeapFree(GetProcessHeap(),0,DiscoveryObject);
  135. return NULL;
  136. }
  137. DiscoveryObject->ReferenceCount=1;
  138. SetWaitableTimer(
  139. DiscoveryObject->TimerHandle,
  140. (LARGE_INTEGER*)&DueTime,
  141. 0,
  142. TimerApcRoutine,
  143. DiscoveryObject,
  144. FALSE
  145. );
  146. return (HANDLE)DiscoveryObject;
  147. }
  148. VOID
  149. RemoveRefCount(
  150. PIR_DISCOVERY_OBJECT DiscoveryObject
  151. )
  152. {
  153. LONG Count=InterlockedDecrement(&DiscoveryObject->ReferenceCount);
  154. if (Count == 0) {
  155. CancelWaitableTimer(DiscoveryObject->TimerHandle);
  156. CloseHandle(DiscoveryObject->TimerHandle);
  157. CloseHandle(DiscoveryObject->EventHandle);
  158. if (DiscoveryObject->DeviceHandle != INVALID_HANDLE_VALUE) {
  159. CancelIo(DiscoveryObject->DeviceHandle);
  160. CloseHandle(DiscoveryObject->DeviceHandle);
  161. }
  162. if (DiscoveryObject->Socket != INVALID_SOCKET) {
  163. closesocket(DiscoveryObject->Socket);
  164. }
  165. DbgPrint("IRMON-FTP: discovery object closed\n");
  166. HeapFree(GetProcessHeap(),0,DiscoveryObject);
  167. }
  168. return;
  169. }
  170. VOID
  171. CloseIrDiscoveryObject(
  172. HANDLE Object
  173. )
  174. {
  175. PIR_DISCOVERY_OBJECT DiscoveryObject=Object;
  176. DiscoveryObject->Closing=TRUE;
  177. if (DiscoveryObject->DeviceHandle != INVALID_HANDLE_VALUE) {
  178. CancelIo(DiscoveryObject->DeviceHandle);
  179. }
  180. return;
  181. }
  182. VOID WINAPI
  183. TimerApcRoutine(
  184. PIR_DISCOVERY_OBJECT DiscoveryObject,
  185. DWORD LowTime,
  186. DWORD HighTime
  187. )
  188. {
  189. IO_STATUS_BLOCK IoStatusBlock;
  190. UNICODE_STRING DeviceName;
  191. OBJECT_ATTRIBUTES ObjAttr;
  192. NTSTATUS Status;
  193. LONGLONG DueTime=Int32x32To64(10000,-10000);
  194. if (DiscoveryObject->Closing) {
  195. RemoveRefCount(DiscoveryObject);
  196. return;
  197. }
  198. if (DiscoveryObject->DeviceHandle == INVALID_HANDLE_VALUE) {
  199. // Open the stack and issue lazy discovery and status ioctls
  200. #define IRDA_DEVICE_NAME TEXT("\\Device\\IrDA")
  201. RtlInitUnicodeString(&DeviceName, IRDA_DEVICE_NAME);
  202. InitializeObjectAttributes(
  203. &ObjAttr,
  204. &DeviceName,
  205. OBJ_INHERIT | OBJ_CASE_INSENSITIVE,
  206. NULL,
  207. NULL
  208. );
  209. Status = NtCreateFile(
  210. &DiscoveryObject->DeviceHandle, // PHANDLE FileHandle
  211. SYNCHRONIZE | GENERIC_EXECUTE ,
  212. &ObjAttr, // POBJECT_ATTRIBUTES ObjAttr
  213. &IoStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  214. NULL, // PLARGE_INTEGER AllocationSize
  215. 0, // ULONG FileAttributes
  216. FILE_SHARE_READ |
  217. FILE_SHARE_WRITE, // ULONG ShareAccess
  218. FILE_OPEN_IF, // ULONG CreateDisposition
  219. 0, // ULONG CreateOptions
  220. NULL, // PVOID EaBuffer
  221. 0); // ULONG EaLength
  222. if (!NT_SUCCESS(Status)) {
  223. DEBUGMSG(("IRMON-FTP: NtCreateFile irda.sys failed %08lx\n",Status));
  224. DiscoveryObject->DeviceHandle=INVALID_HANDLE_VALUE;
  225. SetWaitableTimer(
  226. DiscoveryObject->TimerHandle,
  227. (LARGE_INTEGER*)&DueTime,
  228. 0,
  229. TimerApcRoutine,
  230. DiscoveryObject,
  231. FALSE
  232. );
  233. return;
  234. }
  235. DiscoveryObject->Socket = socket(AF_IRDA, SOCK_STREAM, 0);
  236. if (DiscoveryObject->Socket == INVALID_SOCKET) {
  237. // DEBUGMSG(("IRMON-FTP: socket() error: %ws\n", GetLastErrorText()));
  238. CloseHandle(DiscoveryObject->DeviceHandle);
  239. DiscoveryObject->DeviceHandle=INVALID_HANDLE_VALUE;
  240. SetWaitableTimer(
  241. DiscoveryObject->TimerHandle,
  242. (LARGE_INTEGER*)&DueTime,
  243. 0,
  244. TimerApcRoutine,
  245. DiscoveryObject,
  246. FALSE
  247. );
  248. return;
  249. } else {
  250. DEBUGMSG(("IRMON-FTP: socket created (%d).\n", DiscoveryObject->Socket));
  251. }
  252. }
  253. Status = NtDeviceIoControlFile(
  254. DiscoveryObject->DeviceHandle, // HANDLE FileHandle
  255. NULL, // HANDLE Event OPTIONAL
  256. DiscoverComplete,// PIO_APC_ROUTINE ApcRoutine
  257. DiscoveryObject, // PVOID ApcContext
  258. &DiscoveryObject->DiscoveryStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  259. DiscoveryObject->UseLazyDisc ? IOCTL_IRDA_LAZY_DISCOVERY : IOCTL_IRDA_GET_INFO_ENUM_DEV,
  260. NULL, // PVOID InputBuffer
  261. 0, // ULONG InputBufferLength
  262. &DiscoveryObject->IoDeviceListBuffer[0], // PVOID OutputBuffer
  263. sizeof(DiscoveryObject->IoDeviceListBuffer) // ULONG OutputBufferLength
  264. );
  265. if (!NT_SUCCESS(Status)) {
  266. SetWaitableTimer(
  267. DiscoveryObject->TimerHandle,
  268. (LARGE_INTEGER*)&DueTime,
  269. 0,
  270. TimerApcRoutine,
  271. DiscoveryObject,
  272. FALSE
  273. );
  274. }
  275. DiscoveryObject->UseLazyDisc=TRUE;
  276. InterlockedIncrement(&DiscoveryObject->ReferenceCount);
  277. Status = NtDeviceIoControlFile(
  278. DiscoveryObject->DeviceHandle, // HANDLE FileHandle
  279. NULL, // HANDLE Event OPTIONAL
  280. LinkStatusComplete,// PIO_APC_ROUTINE ApcRoutine
  281. DiscoveryObject, // PVOID ApcContext
  282. &DiscoveryObject->LinkStateStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  283. IOCTL_IRDA_LINK_STATUS, // ULONG IoControlCode
  284. NULL, // PVOID InputBuffer
  285. 0, // ULONG InputBufferLength
  286. &DiscoveryObject->IoLinkStatus, // PVOID OutputBuffer
  287. sizeof(DiscoveryObject->IoLinkStatus) // ULONG OutputBufferLength
  288. );
  289. if (!NT_SUCCESS(Status)) {
  290. RemoveRefCount(DiscoveryObject);
  291. }
  292. return;
  293. }
  294. VOID
  295. WINAPI
  296. DiscoverComplete(
  297. PVOID ApcContext,
  298. PIO_STATUS_BLOCK IoStatusBlock,
  299. DWORD Reserved
  300. )
  301. {
  302. NTSTATUS Status;
  303. LONGLONG DueTime=Int32x32To64(10000,-10000);
  304. PIR_DISCOVERY_OBJECT DiscoveryObject=ApcContext;
  305. PDEVICELIST devices=(PDEVICELIST)&DiscoveryObject->CurrentDeviceListBuffer[0];
  306. CopyMemory(
  307. &DiscoveryObject->CurrentDeviceListBuffer[0],
  308. &DiscoveryObject->IoDeviceListBuffer[0],
  309. sizeof(DiscoveryObject->IoDeviceListBuffer)
  310. );
  311. if (DiscoveryObject->Closing) {
  312. RemoveRefCount(DiscoveryObject);
  313. return;
  314. }
  315. if (NT_SUCCESS(IoStatusBlock->Status) && (IoStatusBlock->Information >= sizeof(ULONG))) {
  316. PostMessage(
  317. DiscoveryObject->WindowHandle,
  318. DiscoveryObject->DiscoveryWindowMessage,
  319. 0,
  320. 0
  321. );
  322. } else {
  323. devices->numDevice=0;
  324. }
  325. Status = NtDeviceIoControlFile(
  326. DiscoveryObject->DeviceHandle, // HANDLE FileHandle
  327. NULL, // HANDLE Event OPTIONAL
  328. DiscoverComplete,// PIO_APC_ROUTINE ApcRoutine
  329. DiscoveryObject, // PVOID ApcContext
  330. &DiscoveryObject->DiscoveryStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  331. IOCTL_IRDA_LAZY_DISCOVERY,
  332. NULL, // PVOID InputBuffer
  333. 0, // ULONG InputBufferLength
  334. &DiscoveryObject->IoDeviceListBuffer[0], // PVOID OutputBuffer
  335. sizeof(DiscoveryObject->IoDeviceListBuffer) // ULONG OutputBufferLength
  336. );
  337. if (!NT_SUCCESS(Status)) {
  338. SetWaitableTimer(
  339. DiscoveryObject->TimerHandle,
  340. (LARGE_INTEGER*)&DueTime,
  341. 0,
  342. TimerApcRoutine,
  343. DiscoveryObject,
  344. FALSE
  345. );
  346. }
  347. return;
  348. }
  349. VOID
  350. WINAPI
  351. LinkStatusComplete(
  352. PVOID ApcContext,
  353. PIO_STATUS_BLOCK IoStatusBlock,
  354. DWORD Reserved
  355. )
  356. {
  357. NTSTATUS Status;
  358. PIR_DISCOVERY_OBJECT DiscoveryObject=ApcContext;
  359. CopyMemory(
  360. &DiscoveryObject->CurrentLinkStatus,
  361. &DiscoveryObject->IoLinkStatus,
  362. sizeof(DiscoveryObject->IoLinkStatus)
  363. );
  364. PostMessage(
  365. DiscoveryObject->WindowHandle,
  366. DiscoveryObject->LinkWindowMessage,
  367. 0,
  368. 0
  369. );
  370. Status = NtDeviceIoControlFile(
  371. DiscoveryObject->DeviceHandle, // HANDLE FileHandle
  372. NULL, // HANDLE Event OPTIONAL
  373. LinkStatusComplete,// PIO_APC_ROUTINE ApcRoutine
  374. DiscoveryObject, // PVOID ApcContext
  375. &DiscoveryObject->LinkStateStatusBlock, // PIO_STATUS_BLOCK IoStatusBlock
  376. IOCTL_IRDA_LINK_STATUS, // ULONG IoControlCode
  377. NULL, // PVOID InputBuffer
  378. 0, // ULONG InputBufferLength
  379. &DiscoveryObject->IoLinkStatus, // PVOID OutputBuffer
  380. sizeof(DiscoveryObject->IoLinkStatus) // ULONG OutputBufferLength
  381. );
  382. if (!NT_SUCCESS(Status)) {
  383. RemoveRefCount(DiscoveryObject);
  384. }
  385. }
  386. LONG
  387. GetDeviceList(
  388. HANDLE Object,
  389. OBEX_DEVICE_LIST * List,
  390. ULONG *ListBufferSize
  391. )
  392. {
  393. PIR_DISCOVERY_OBJECT DiscoveryObject=Object;
  394. ULONG BufferSizeNeeded;
  395. ULONG i;
  396. NTSTATUS Status;
  397. IO_STATUS_BLOCK IoStatus;
  398. PDEVICELIST devices=(PDEVICELIST)&DiscoveryObject->CurrentDeviceListBuffer[0];
  399. //
  400. // get the list as it current exists
  401. //
  402. Status = NtDeviceIoControlFile(
  403. DiscoveryObject->DeviceHandle, // HANDLE FileHandle
  404. DiscoveryObject->EventHandle, // HANDLE Event OPTIONAL
  405. NULL, // PIO_APC_ROUTINE ApcRoutine
  406. NULL, // PVOID ApcContext
  407. &IoStatus, // PIO_STATUS_BLOCK IoStatusBlock
  408. IOCTL_IRDA_GET_INFO_ENUM_DEV,
  409. NULL, // PVOID InputBuffer
  410. 0, // ULONG InputBufferLength
  411. &DiscoveryObject->CurrentDeviceListBuffer[0], // PVOID OutputBuffer
  412. sizeof(DiscoveryObject->CurrentDeviceListBuffer) // ULONG OutputBufferLength
  413. );
  414. if (Status == STATUS_PENDING) {
  415. WaitForSingleObject(DiscoveryObject->EventHandle,INFINITE);
  416. Status=IoStatus.Status;
  417. }
  418. if (!NT_SUCCESS(Status)) {
  419. //
  420. // failed, just no devices
  421. //
  422. devices->numDevice=0;
  423. }
  424. BufferSizeNeeded=(devices->numDevice * sizeof(OBEX_DEVICE)) + FIELD_OFFSET(OBEX_DEVICE_LIST,DeviceList);
  425. if (*ListBufferSize < BufferSizeNeeded) {
  426. *ListBufferSize= BufferSizeNeeded;
  427. return ERROR_INSUFFICIENT_BUFFER;
  428. }
  429. ZeroMemory(List,*ListBufferSize);
  430. for (i=0; i<devices->numDevice; i++) {
  431. //
  432. // the irda device name buffer is 23 bytes in size and may ahve either ascii or
  433. // unicode chars. Add enough bytes to round up the an even number of unicode chars
  434. // plus a null terminator.
  435. //
  436. UCHAR TempBuffer[sizeof(devices->Device[i].irdaDeviceName)+3];
  437. unsigned MaxCharCount;
  438. CopyMemory(
  439. &List->DeviceList[i].DeviceSpecific.s.Irda.DeviceId,
  440. &devices->Device[i].irdaDeviceID,
  441. sizeof(ULONG)
  442. );
  443. List->DeviceList[i].DeviceType=TYPE_IRDA;
  444. //
  445. // zero out the whole buffer and then copy the string from the device to make sure it
  446. // is null terminated
  447. //
  448. ZeroMemory(&TempBuffer[0],sizeof(TempBuffer));
  449. CopyMemory(&TempBuffer[0],devices->Device[i].irdaDeviceName,sizeof(devices->Device[i].irdaDeviceName));
  450. //
  451. // get the character count of unicode destination buffer
  452. //
  453. MaxCharCount = sizeof(List->DeviceList[i].DeviceName)/sizeof(wchar_t);
  454. if (devices->Device[i].irdaCharSet != LmCharSetUNICODE) {
  455. MultiByteToWideChar(CP_ACP, 0,
  456. &TempBuffer[0],
  457. -1, // NULL terminated string
  458. List->DeviceList[i].DeviceName,
  459. MaxCharCount
  460. );
  461. } else {
  462. //
  463. // the name is in unicode
  464. //
  465. wcsncpy( List->DeviceList[i].DeviceName,
  466. (wchar_t *)&TempBuffer[0],
  467. MaxCharCount
  468. );
  469. //
  470. // Assure that it is NULL-terminated.
  471. //
  472. List->DeviceList[i].DeviceName[ MaxCharCount-1 ] = 0;
  473. }
  474. {
  475. int LSapSel;
  476. int Attempt;
  477. LONG status;
  478. for (Attempt=1; Attempt < 5; ++Attempt) {
  479. status = QueryIASForInteger(DiscoveryObject->Socket,
  480. devices->Device[i].irdaDeviceID,
  481. "OBEX:IrXfer", 12,
  482. "IrDA:TinyTP:LsapSel", 20,
  483. &LSapSel);
  484. if (status != ERROR_SUCCESS)
  485. {
  486. status = QueryIASForInteger(DiscoveryObject->Socket,
  487. devices->Device[i].irdaDeviceID,
  488. "OBEX", 5,
  489. "IrDA:TinyTP:LsapSel", 20,
  490. &LSapSel);
  491. }
  492. if (status == WSAETIMEDOUT || status == WSAECONNRESET)
  493. {
  494. Sleep(250);
  495. continue;
  496. }
  497. break;
  498. }
  499. if (!status) {
  500. List->DeviceList[i].DeviceSpecific.s.Irda.ObexSupport=TRUE;
  501. }
  502. }
  503. List->DeviceCount++;
  504. }
  505. return ERROR_SUCCESS;
  506. }
  507. VOID
  508. GetLinkStatus(
  509. HANDLE Object,
  510. IRLINK_STATUS *LinkStatus
  511. )
  512. {
  513. PIR_DISCOVERY_OBJECT DiscoveryObject=Object;
  514. *LinkStatus=DiscoveryObject->CurrentLinkStatus;
  515. return;
  516. }