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.

583 lines
15 KiB

  1. /*++
  2. Copyright (c) 1997-2003 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. irda.c
  6. Abstract:
  7. IRDA printing support in localmon
  8. // @@BEGIN_DDKSPLIT
  9. Author:
  10. Muhunthan Sivapragasam (MuhuntS) 27-Oct-97
  11. Environment:
  12. User Mode -Win32
  13. Revision History:
  14. // @@END_DDKSPLIT
  15. --*/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include <af_irda.h>
  19. #include "irda.h"
  20. #define PRINTER_HINT_BIT 0x08
  21. #define DEVICE_LIST_LEN 5
  22. #define WRITE_TIMEOUT 60000 // 60 seconds
  23. #define BUF_SIZE sizeof(DEVICELIST) + (DEVICE_LIST_LEN - 1) * sizeof(IRDA_DEVICE_INFO)
  24. typedef struct _IRDA_INFO {
  25. DWORD dwBeginTime;
  26. DWORD dwSendPduLen;
  27. WSAOVERLAPPED WsaOverlapped;
  28. WSABUF WsaBuf;
  29. LPBYTE pBuf;
  30. } IRDA_INFO, *PIRDA_INFO;
  31. BOOL
  32. IsIRDAInstalled(
  33. )
  34. {
  35. BOOL bRet = FALSE;
  36. WORD WSAVerReq = MAKEWORD(1,1);
  37. SOCKET hSock;
  38. WSADATA WSAData;
  39. if ( WSAStartup(WSAVerReq, &WSAData) == ERROR_SUCCESS &&
  40. (hSock = socket(AF_IRDA, SOCK_STREAM, 0)) != INVALID_SOCKET ) {
  41. closesocket(hSock);
  42. bRet = TRUE;
  43. }
  44. WSACleanup();
  45. return bRet;
  46. }
  47. VOID
  48. CheckAndAddIrdaPort(
  49. PINILOCALMON pIniLocalMon
  50. )
  51. {
  52. PINIPORT pIniPort;
  53. LcmEnterSplSem();
  54. for ( pIniPort = pIniLocalMon->pIniPort ;
  55. pIniPort && !IS_IRDA_PORT(pIniPort->pName) ;
  56. pIniPort = pIniPort->pNext )
  57. ;
  58. LcmLeaveSplSem();
  59. if ( pIniPort || !IsIRDAInstalled() )
  60. return;
  61. //
  62. // Add the port to the list and write to registry
  63. //
  64. LcmCreatePortEntry(pIniLocalMon, szIRDA);
  65. // @@BEGIN_DDKSPLIT
  66. /*
  67. if ( (pIniPort = LcmCreatePortEntry(pIniLocalMon, szIRDA)) &&
  68. !WriteProfileString(szPorts, szIRDA, L"") ) {
  69. DeletePortNode(pIniLocalMon, pIniPort);
  70. }
  71. */
  72. // @@END_DDKSPLIT
  73. }
  74. VOID
  75. CloseIrdaConnection(
  76. PINIPORT pIniPort
  77. )
  78. {
  79. PIRDA_INFO pIrda = (PIRDA_INFO) pIniPort->pExtra;
  80. if ( pIrda ) {
  81. if ( pIrda->WsaOverlapped.hEvent )
  82. WSACloseEvent(pIrda->WsaOverlapped.hEvent);
  83. FreeSplMem(pIrda);
  84. pIniPort->pExtra = NULL;
  85. }
  86. if ( (SOCKET)pIniPort->hFile != INVALID_SOCKET ) {
  87. closesocket((SOCKET)pIniPort->hFile);
  88. pIniPort->hFile = (HANDLE)INVALID_SOCKET;
  89. }
  90. }
  91. DWORD
  92. IrdaConnect(
  93. PINIPORT pIniPort
  94. )
  95. {
  96. BOOL bRet = FALSE;
  97. WORD WSAVerReq = MAKEWORD(1,1);
  98. DWORD dwIndex, dwNeeded = BUF_SIZE, dwEnableIrLPT = TRUE,
  99. dwLastError = ERROR_SUCCESS, dwSendPduLen;
  100. LPSTR pBuf = NULL;
  101. WSADATA WSAData;
  102. SOCKET Socket = INVALID_SOCKET;
  103. IAS_QUERY IasQuery;
  104. PIRDA_INFO pIrda;
  105. PDEVICELIST pDevList;
  106. SOCKADDR_IRDA PrinterAddr = { AF_IRDA, 0, 0, 0, 0, "IrLPT" };
  107. SPLASSERT(pIniPort->hFile == (HANDLE)INVALID_SOCKET && pIniPort->pExtra == NULL);
  108. if ( dwLastError = WSAStartup(WSAVerReq, &WSAData) )
  109. goto Done;
  110. if ( !(pBuf = AllocSplMem(dwNeeded)) ) {
  111. dwLastError = GetLastError();
  112. goto Done;
  113. }
  114. if ( (Socket = WSASocket(AF_IRDA, SOCK_STREAM, 0, NULL, 0,
  115. WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET ||
  116. getsockopt(Socket, SOL_IRLMP, IRLMP_ENUMDEVICES,
  117. (LPSTR)pBuf, &dwNeeded) == SOCKET_ERROR ) {
  118. dwLastError = WSAGetLastError();
  119. goto Done;
  120. }
  121. if ( dwNeeded > BUF_SIZE ) {
  122. FreeSplMem(pBuf);
  123. if ( !(pBuf = AllocSplMem(dwNeeded)) ) {
  124. dwLastError = GetLastError();
  125. goto Done;
  126. }
  127. if ( getsockopt(Socket, SOL_IRLMP, IRLMP_ENUMDEVICES,
  128. (LPSTR)pBuf, &dwNeeded) == SOCKET_ERROR ) {
  129. dwLastError = WSAGetLastError();
  130. goto Done;
  131. }
  132. }
  133. pDevList = (PDEVICELIST) pBuf;
  134. //
  135. // Any of the devices a printer?
  136. //
  137. for ( dwIndex = 0 ; dwIndex < pDevList->numDevice ; ++dwIndex ) {
  138. if ( (pDevList->Device[dwIndex].irdaDeviceHints1 & PRINTER_HINT_BIT) ||
  139. (pDevList->Device[dwIndex].irdaDeviceHints2 & PRINTER_HINT_BIT) )
  140. break;
  141. }
  142. //
  143. // Any printers found?
  144. //
  145. if ( dwIndex == pDevList->numDevice ) {
  146. dwLastError = ERROR_PRINTER_NOT_FOUND;
  147. goto Done;
  148. }
  149. //
  150. // Move printer's address into the socket address
  151. //
  152. memcpy(PrinterAddr.irdaDeviceID,
  153. pDevList->Device[dwIndex].irdaDeviceID,
  154. sizeof(PrinterAddr.irdaDeviceID));
  155. dwIndex = 0;
  156. dwNeeded = sizeof(dwSendPduLen);
  157. bRet = SOCKET_ERROR != setsockopt(Socket,
  158. SOL_IRLMP,
  159. IRLMP_IRLPT_MODE,
  160. (LPCSTR)&dwEnableIrLPT,
  161. sizeof(dwEnableIrLPT)) &&
  162. SOCKET_ERROR != connect(Socket,
  163. (const struct sockaddr *)&PrinterAddr,
  164. sizeof(PrinterAddr)) &&
  165. // @@BEGIN_DDKSPLIT
  166. //
  167. // What size should we use for sends?
  168. //
  169. // @@END_DDKSPLIT
  170. SOCKET_ERROR != getsockopt(Socket,
  171. SOL_IRLMP,
  172. IRLMP_SEND_PDU_LEN,
  173. (char *)&dwSendPduLen,
  174. &dwNeeded) &&
  175. // @@BEGIN_DDKSPLIT
  176. //
  177. // No buffering (i.e. buffer size of 0)
  178. //
  179. // @@END_DDKSPLIT
  180. SOCKET_ERROR != setsockopt(Socket,
  181. SOL_SOCKET,
  182. SO_SNDBUF,
  183. (LPCSTR)&dwIndex,
  184. sizeof(dwIndex));
  185. if ( bRet ) {
  186. SPLASSERT(pIniPort->pExtra == NULL);
  187. dwNeeded = sizeof(IRDA_INFO) + dwSendPduLen;
  188. if ( !(pIrda = (PIRDA_INFO) AllocSplMem(dwNeeded)) ) {
  189. bRet = FALSE;
  190. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  191. goto Done;
  192. }
  193. pIniPort->hFile = (HANDLE)Socket;
  194. pIniPort->pExtra = (LPBYTE)pIrda;
  195. pIrda->dwSendPduLen = dwSendPduLen;
  196. pIrda->pBuf = ((LPBYTE) pIrda) + sizeof(IRDA_INFO);
  197. } else
  198. dwLastError = WSAGetLastError();
  199. Done:
  200. FreeSplMem(pBuf);
  201. if ( !bRet ) {
  202. if ( Socket != INVALID_SOCKET )
  203. closesocket(Socket);
  204. FreeSplMem(pIniPort->pExtra);
  205. pIniPort->pExtra = NULL;
  206. }
  207. return bRet ? ERROR_SUCCESS : dwLastError;
  208. }
  209. BOOL
  210. AbortThisJob(
  211. PINIPORT pIniPort
  212. )
  213. /*++
  214. Tells if the job should be aborted. A job should be aborted if it has
  215. been deleted or it needs to be restarted.
  216. --*/
  217. {
  218. BOOL bRet = FALSE;
  219. DWORD dwNeeded;
  220. LPJOB_INFO_1 pJobInfo = NULL;
  221. dwNeeded = 0;
  222. GetJob(pIniPort->hPrinter, pIniPort->JobId, 1, NULL, 0, &dwNeeded);
  223. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  224. goto Done;
  225. if ( !(pJobInfo = (LPJOB_INFO_1) AllocSplMem(dwNeeded)) ||
  226. !GetJob(pIniPort->hPrinter, pIniPort->JobId,
  227. 1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded)
  228. )
  229. goto Done;
  230. bRet = (pJobInfo->Status & JOB_STATUS_DELETING) ||
  231. (pJobInfo->Status & JOB_STATUS_DELETED) ||
  232. (pJobInfo->Status & JOB_STATUS_RESTART);
  233. Done:
  234. if ( pJobInfo )
  235. FreeSplMem(pJobInfo);
  236. return bRet;
  237. }
  238. VOID
  239. IrdaDisconnect(
  240. PINIPORT pIniPort
  241. )
  242. {
  243. BOOL bRet;
  244. DWORD dwRet, dwSent, dwFlags;
  245. SOCKET Socket = (SOCKET) pIniPort->hFile;
  246. PIRDA_INFO pIrda = (PIRDA_INFO) pIniPort->pExtra;
  247. //
  248. // If the job has already been cancelled close socket and quit
  249. //
  250. if ( Socket == INVALID_SOCKET )
  251. goto Done;
  252. //
  253. // If a send is pending wait for all the data to go through indefinitly
  254. //
  255. if ( pIrda->WsaOverlapped.hEvent ) {
  256. do {
  257. dwRet = WaitForSingleObject(pIrda->WsaOverlapped.hEvent,
  258. WRITE_TIMEOUT);
  259. if ( dwRet == WAIT_TIMEOUT ) {
  260. //
  261. // If user has cancelled the job close connection
  262. //
  263. if ( AbortThisJob(pIniPort) )
  264. goto Done;
  265. } else if ( dwRet != WAIT_OBJECT_0 )
  266. goto Done;
  267. } while ( dwRet == WAIT_TIMEOUT );
  268. //
  269. // IRDA can only send the whole packet so we do not check dwSent
  270. //
  271. }
  272. //
  273. // No more sends
  274. //
  275. shutdown(Socket, SD_SEND);
  276. Done:
  277. CloseIrdaConnection(pIniPort);
  278. }
  279. BOOL
  280. IrdaStartDocPort(
  281. IN OUT PINIPORT pIniPort
  282. )
  283. {
  284. HANDLE hToken;
  285. DWORD dwLastError;
  286. //
  287. // If remote guest is the first user to print, then the connect fails.
  288. // Thus we need to revert to system context before calling IrdaConnect
  289. //
  290. hToken = RevertToPrinterSelf();
  291. if (!hToken) {
  292. return FALSE;
  293. }
  294. dwLastError = IrdaConnect(pIniPort);
  295. ImpersonatePrinterClient(hToken);
  296. if ( dwLastError ) {
  297. SetLastError(dwLastError);
  298. return FALSE;
  299. } else
  300. return TRUE;
  301. }
  302. BOOL
  303. IrdaWritePort(
  304. IN HANDLE hPort,
  305. IN LPBYTE pBuf,
  306. IN DWORD cbBuf,
  307. IN LPDWORD pcbWritten
  308. )
  309. {
  310. INT iRet = ERROR_SUCCESS;
  311. DWORD dwSent, dwFlags, dwTimeout, dwBuffered;
  312. PINIPORT pIniPort = (PINIPORT)hPort;
  313. SOCKET Socket = (SOCKET) pIniPort->hFile;
  314. PIRDA_INFO pIrda = (PIRDA_INFO)pIniPort->pExtra;
  315. *pcbWritten = 0;
  316. //
  317. // When we have to close socket we fail the write.
  318. // If anothe write comes through it is because user wanted to retry
  319. //
  320. if ( Socket == INVALID_SOCKET ) {
  321. SPLASSERT(pIrda == NULL);
  322. SetJob(pIniPort->hPrinter, pIniPort->JobId, 0, NULL, JOB_CONTROL_RESTART);
  323. iRet = WSAENOTSOCK;
  324. goto Done;
  325. }
  326. SPLASSERT(pIrda != NULL);
  327. //
  328. // This is the time spooler issued the write to us
  329. //
  330. pIrda->dwBeginTime = GetTickCount();
  331. do {
  332. //
  333. // If event is non-NULL at the beginning we have a pending write from
  334. // last WritePort call
  335. //
  336. if ( pIrda->WsaOverlapped.hEvent ) {
  337. dwTimeout = GetTickCount() - pIrda->dwBeginTime;
  338. //
  339. // We want to wait for WRITE_TIMEOUT time from the time spooler
  340. // issued the WritePort.
  341. // If it is already more than that still check what happened to the
  342. // write before returning
  343. //
  344. if ( dwTimeout > WRITE_TIMEOUT )
  345. dwTimeout = 0;
  346. else
  347. dwTimeout = WRITE_TIMEOUT - dwTimeout;
  348. //
  349. // Let's wait for the timeout period for the last send to complete
  350. //
  351. if ( WAIT_OBJECT_0 != WaitForSingleObject(pIrda->WsaOverlapped.hEvent,
  352. dwTimeout) ) {
  353. iRet = ERROR_TIMEOUT;
  354. goto Done;
  355. }
  356. //
  357. // What happened to the last send?
  358. //
  359. if ( WSAGetOverlappedResult(Socket, &pIrda->WsaOverlapped,
  360. &dwSent, FALSE, &dwFlags) == FALSE ) {
  361. iRet = WSAGetLastError();
  362. CloseIrdaConnection(pIniPort);
  363. goto Done;
  364. }
  365. //
  366. // IRDA can only send the whole packet so we do not check dwSent
  367. //
  368. //
  369. // Reset the manual reset event and do the next send
  370. //
  371. WSAResetEvent(pIrda->WsaOverlapped.hEvent);
  372. //
  373. // Have we already sent all the data?
  374. //
  375. if ( cbBuf == 0 ) {
  376. WSACloseEvent(pIrda->WsaOverlapped.hEvent);
  377. pIrda->WsaOverlapped.hEvent = NULL;
  378. goto Done;
  379. }
  380. } else {
  381. pIrda->WsaOverlapped.hEvent = WSACreateEvent();
  382. if ( !pIrda->WsaOverlapped.hEvent ) {
  383. iRet = GetLastError();
  384. CloseIrdaConnection(pIniPort);
  385. goto Done;
  386. }
  387. }
  388. do {
  389. //
  390. // Have we already sent all the data?
  391. //
  392. if ( cbBuf == 0 ) {
  393. WSACloseEvent(pIrda->WsaOverlapped.hEvent);
  394. pIrda->WsaOverlapped.hEvent = NULL;
  395. goto Done;
  396. }
  397. //
  398. // Send no more than pIrda->dwSendPduLen
  399. //
  400. if ( cbBuf < pIrda->dwSendPduLen )
  401. dwBuffered = cbBuf;
  402. else
  403. dwBuffered = pIrda->dwSendPduLen;
  404. pIrda->WsaBuf.len = dwBuffered;
  405. pIrda->WsaBuf.buf = pIrda->pBuf;
  406. CopyMemory(pIrda->pBuf, pBuf, dwBuffered);
  407. //
  408. // We are asking a non-blocking send. Typically this will
  409. // return with I/O pending
  410. //
  411. if ( WSASend(Socket, &pIrda->WsaBuf, 1, &dwSent,
  412. MSG_PARTIAL, &pIrda->WsaOverlapped, NULL) != NO_ERROR ) {
  413. iRet = WSAGetLastError();
  414. break;
  415. }
  416. pBuf += dwSent;
  417. cbBuf -= dwSent;
  418. *pcbWritten += dwSent;
  419. } while ( iRet == NO_ERROR );
  420. if ( iRet == WSA_IO_PENDING ) {
  421. //
  422. // Lie to spooler we sent the whole data. Next time we will find out
  423. //
  424. pBuf += dwBuffered;
  425. cbBuf -= dwBuffered;
  426. *pcbWritten += dwBuffered;
  427. iRet = NO_ERROR;
  428. } else {
  429. DBGMSG(DBG_ERROR, ("IrdaWritePort: WSASend failed %d\n", iRet));
  430. CloseIrdaConnection(pIniPort);
  431. }
  432. } while ( cbBuf && iRet == NO_ERROR );
  433. Done:
  434. if ( iRet != ERROR_SUCCESS )
  435. SetLastError(iRet);
  436. return iRet == ERROR_SUCCESS;
  437. }
  438. VOID
  439. IrdaEndDocPort(
  440. PINIPORT pIniPort
  441. )
  442. {
  443. IrdaDisconnect(pIniPort);
  444. }