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.

1145 lines
24 KiB

  1. #include "std.h"
  2. // This is the communications mask used by our serial port. More may be
  3. // necessary, but for right now, this seems to work.
  4. #define EV_SERIAL EV_RXCHAR | EV_ERR | EV_BREAK
  5. #define TCPIP_NAME L"TCP/IP"
  6. // This GUID is used to identify objects opened by this library. It is
  7. // placed in the m_Secret member of the SOCKET structure. Any external
  8. // interface accepting a SOCKET object as a parameter should check this
  9. // out before using the structure.
  10. // {29566A75-BCDE-4bba-BC6A-EA652C0651D9}
  11. static const GUID uuidTCPIPObjectGuid =
  12. { 0x29566a75, 0xbcde, 0x4bba, { 0xbc, 0x6a, 0xea, 0x65, 0x2c, 0x6, 0x51, 0xd9 } };
  13. // Structure defining an open serial port object. All external users of this
  14. // library will only have a void pointer to one of these, and the structure is
  15. // not published anywhere. This abstration makes it more difficult for the
  16. // user to mess things up.
  17. typedef struct __TCPIP
  18. {
  19. GUID m_Secret; // Identifies this as a tcpip socket
  20. SOCKET m_Socket; // SOCKET handle
  21. HANDLE m_hAbort; // Event signalled when port is closing
  22. HANDLE m_hReadMutex; // Only one thread allowed to read a port
  23. HANDLE m_hWriteMutex; // Only one thread allowed to read a port
  24. HANDLE m_hCloseMutex; // Only one thread allowed to close a port
  25. HANDLE m_hReadComplete; // Event to signal read completion
  26. HANDLE m_hWriteComplete; // Event to signal write completion
  27. } TCPIP, *PTCPIP;
  28. extern PVOID APIENTRY lhcOpen(
  29. PCWSTR pcszPortSpec);
  30. extern BOOL APIENTRY lhcRead(
  31. PVOID pObject,
  32. PVOID pBuffer,
  33. DWORD dwSize,
  34. PDWORD pdwBytesRead);
  35. extern BOOL APIENTRY lhcWrite(
  36. PVOID pObject,
  37. PVOID pBuffer,
  38. DWORD dwSize);
  39. extern BOOL APIENTRY lhcClose(
  40. PVOID pObject);
  41. extern DWORD APIENTRY lhcGetLibraryName(
  42. PWSTR pszBuffer,
  43. DWORD dwSize);
  44. BOOL lhcpAcquireWithAbort(
  45. HANDLE hMutex,
  46. HANDLE hAbort);
  47. BOOL lhcpAcquireReadWithAbort(
  48. PTCPIP pObject);
  49. BOOL lhcpAcquireWriteWithAbort(
  50. PTCPIP pObject);
  51. BOOL lhcpAcquireCloseWithAbort(
  52. PTCPIP pObject);
  53. BOOL lhcpAcquireReadAndWrite(
  54. PTCPIP pObject);
  55. BOOL lhcpReleaseRead(
  56. PTCPIP pObject);
  57. BOOL lhcpReleaseWrite(
  58. PTCPIP pObject);
  59. BOOL lhcpReleaseClose(
  60. PTCPIP pObject);
  61. BOOL lhcpIsValidObject(
  62. PTCPIP pObject);
  63. PTCPIP lhcpCreateNewObject();
  64. void lhcpDeleteObject(
  65. PTCPIP pObject);
  66. BOOL lhcpParseParameters(
  67. PCWSTR pcszPortSpec,
  68. PWSTR* pszHostName,
  69. PWSTR* pszInetAddress,
  70. SOCKADDR_IN** Address);
  71. void lhcpParseParametersFree(
  72. PWSTR* pszHostName,
  73. PWSTR* pszInetAddress,
  74. SOCKADDR_IN** Address);
  75. BOOL lhcpSetCommState(
  76. HANDLE hPort,
  77. DWORD dwBaudRate);
  78. BOOL lhcpReadTCPIP(
  79. PTCPIP pObject,
  80. PVOID pBuffer,
  81. DWORD dwSize,
  82. PDWORD pdwBytesRead);
  83. BOOL lhcpWriteTCPIP(
  84. PTCPIP pObject,
  85. PVOID pBuffer,
  86. DWORD dwSize);
  87. BOOL WINAPI DllEntryPoint(
  88. HINSTANCE hinstDLL, // handle to the DLL module
  89. DWORD fdwReason, // reason for calling function
  90. LPVOID lpvReserved) // reserved
  91. {
  92. WSADATA WsaData;
  93. int dResult;
  94. switch (fdwReason)
  95. {
  96. case DLL_PROCESS_ATTACH:
  97. dResult = WSAStartup(
  98. MAKEWORD(2,0),
  99. &WsaData);
  100. if (dResult!=ERROR_SUCCESS)
  101. {
  102. SetLastError(
  103. dResult);
  104. return FALSE;
  105. }
  106. break;
  107. case DLL_PROCESS_DETACH:
  108. dResult = WSACleanup();
  109. if (dResult!=ERROR_SUCCESS)
  110. {
  111. SetLastError(
  112. dResult);
  113. return FALSE;
  114. }
  115. break;
  116. case DLL_THREAD_ATTACH:
  117. case DLL_THREAD_DETACH:
  118. default:
  119. break;
  120. }
  121. return TRUE;
  122. }
  123. BOOL lhcpAcquireWithAbort(HANDLE hMutex, HANDLE hAbort)
  124. {
  125. HANDLE hWaiters[2];
  126. DWORD dwWaitResult;
  127. hWaiters[0] = hAbort;
  128. hWaiters[1] = hMutex;
  129. // We should honour the m_hAbort event, since this is signalled when the
  130. // port is closed by another thread
  131. dwWaitResult = WaitForMultipleObjects(
  132. 2,
  133. hWaiters,
  134. FALSE,
  135. INFINITE);
  136. if (WAIT_OBJECT_0==dwWaitResult)
  137. {
  138. goto Error;
  139. }
  140. else if ((WAIT_OBJECT_0+1)!=dwWaitResult)
  141. {
  142. // This should never, ever happen - so I will put a debug breapoint
  143. // in here (checked only).
  144. #ifdef DBG
  145. DebugBreak();
  146. #endif
  147. goto Error;
  148. }
  149. return TRUE; // We have acquired the write mutex
  150. Error:
  151. return FALSE; // We have aborted
  152. }
  153. BOOL lhcpAcquireReadWithAbort(PTCPIP pObject)
  154. {
  155. return lhcpAcquireWithAbort(
  156. pObject->m_hReadMutex,
  157. pObject->m_hAbort);
  158. }
  159. BOOL lhcpAcquireWriteWithAbort(PTCPIP pObject)
  160. {
  161. return lhcpAcquireWithAbort(
  162. pObject->m_hWriteMutex,
  163. pObject->m_hAbort);
  164. }
  165. BOOL lhcpAcquireCloseWithAbort(PTCPIP pObject)
  166. {
  167. return lhcpAcquireWithAbort(
  168. pObject->m_hCloseMutex,
  169. pObject->m_hAbort);
  170. }
  171. BOOL lhcpAcquireReadAndWrite(PTCPIP pObject)
  172. {
  173. HANDLE hWaiters[2];
  174. DWORD dwWaitResult;
  175. hWaiters[0] = pObject->m_hReadMutex;
  176. hWaiters[1] = pObject->m_hWriteMutex;
  177. dwWaitResult = WaitForMultipleObjects(
  178. 2,
  179. hWaiters,
  180. TRUE,
  181. 1000); // Timeout after 1 second
  182. if (WAIT_OBJECT_0!=dwWaitResult)
  183. {
  184. goto Error;
  185. }
  186. return TRUE; // We have acquired the write mutex
  187. Error:
  188. return FALSE; // We have aborted
  189. }
  190. BOOL lhcpReleaseRead(PTCPIP pObject)
  191. {
  192. return ReleaseMutex(
  193. pObject->m_hReadMutex);
  194. }
  195. BOOL lhcpReleaseWrite(PTCPIP pObject)
  196. {
  197. return ReleaseMutex(
  198. pObject->m_hWriteMutex);
  199. }
  200. BOOL lhcpReleaseClose(PTCPIP pObject)
  201. {
  202. return ReleaseMutex(
  203. pObject->m_hCloseMutex);
  204. }
  205. BOOL lhcpIsValidObject(PTCPIP pObject)
  206. {
  207. BOOL bResult;
  208. __try
  209. {
  210. bResult = IsEqualGUID(
  211. &uuidTCPIPObjectGuid,
  212. &pObject->m_Secret);
  213. }
  214. __except(EXCEPTION_EXECUTE_HANDLER)
  215. {
  216. SetLastError(
  217. ERROR_INVALID_HANDLE);
  218. bResult = FALSE;
  219. goto Done;
  220. }
  221. Done:
  222. return bResult;
  223. }
  224. PTCPIP lhcpCreateNewObject()
  225. {
  226. PTCPIP pObject = (PTCPIP)malloc(
  227. sizeof(TCPIP));
  228. pObject->m_Secret = uuidTCPIPObjectGuid;
  229. pObject->m_Socket = INVALID_SOCKET;
  230. pObject->m_hAbort = NULL;
  231. pObject->m_hReadMutex = NULL; // Only one thread allowed to read a port
  232. pObject->m_hWriteMutex = NULL; // Only one thread allowed to read a port
  233. pObject->m_hCloseMutex = NULL; // Only one thread allowed to read a port
  234. pObject->m_hReadComplete = NULL; // Event to signal read completion
  235. pObject->m_hWriteComplete = NULL; // Event to signal write completion
  236. return pObject;
  237. }
  238. void lhcpDeleteObject(PTCPIP pObject)
  239. {
  240. if (pObject==NULL)
  241. {
  242. return;
  243. }
  244. ZeroMemory(
  245. &(pObject->m_Secret),
  246. sizeof(pObject->m_Secret));
  247. if (pObject->m_Socket!=INVALID_SOCKET)
  248. {
  249. closesocket(
  250. pObject->m_Socket);
  251. }
  252. if (pObject->m_hAbort!=NULL)
  253. {
  254. CloseHandle(
  255. pObject->m_hAbort);
  256. }
  257. if (pObject->m_hReadMutex!=NULL)
  258. {
  259. CloseHandle(
  260. pObject->m_hReadMutex);
  261. }
  262. if (pObject->m_hWriteMutex!=NULL)
  263. {
  264. CloseHandle(
  265. pObject->m_hWriteMutex);
  266. }
  267. if (pObject->m_hCloseMutex!=NULL)
  268. {
  269. CloseHandle(
  270. pObject->m_hCloseMutex);
  271. }
  272. if (pObject->m_hReadComplete!=NULL)
  273. {
  274. CloseHandle(
  275. pObject->m_hReadComplete);
  276. }
  277. if (pObject->m_hWriteComplete!=NULL)
  278. {
  279. CloseHandle(
  280. pObject->m_hWriteComplete);
  281. }
  282. FillMemory(
  283. pObject,
  284. sizeof(TCPIP),
  285. 0x00);
  286. free(
  287. pObject);
  288. }
  289. BOOL lhcpParseParameters(
  290. PCWSTR pcszPortSpec,
  291. PWSTR* pszHostName,
  292. PWSTR* pszInetAddress,
  293. SOCKADDR_IN** Address)
  294. {
  295. DWORD dwPort;
  296. DWORD dwAddress;
  297. PSTR pszAddress = NULL;
  298. PSTR pszPort = NULL;
  299. struct hostent* pHost = NULL;
  300. int dStringLength = 0;
  301. PWSTR pszCount = (PWSTR)pcszPortSpec;
  302. *pszHostName = NULL;
  303. *pszInetAddress = NULL;
  304. *Address = NULL;
  305. // First off, we need to do a quick check for a valid looking target. If
  306. // we are definitely looking at something invalid, why make the user wait?
  307. while (*pszCount!='\0')
  308. {
  309. if (!(iswalpha(*pszCount) || iswdigit(*pszCount) || (*pszCount==L'_') ||
  310. (*pszCount==L'.') || (*pszCount==L':') || (*pszCount==L'-')))
  311. {
  312. SetLastError(
  313. ERROR_NOT_ENOUGH_MEMORY);
  314. goto Error;
  315. }
  316. pszCount++;
  317. }
  318. dStringLength = WideCharToMultiByte(
  319. CP_ACP,
  320. 0,
  321. pcszPortSpec,
  322. -1,
  323. NULL,
  324. 0,
  325. NULL,
  326. NULL);
  327. if (0==dStringLength)
  328. {
  329. goto Error;
  330. }
  331. pszAddress = (PSTR)malloc(
  332. dStringLength);
  333. if (NULL==pszAddress)
  334. {
  335. SetLastError(
  336. ERROR_NOT_ENOUGH_MEMORY);
  337. goto Error;
  338. }
  339. dStringLength = WideCharToMultiByte(
  340. CP_ACP,
  341. 0,
  342. pcszPortSpec,
  343. -1,
  344. pszAddress,
  345. dStringLength,
  346. NULL,
  347. NULL);
  348. if (0==dStringLength)
  349. {
  350. goto Error;
  351. }
  352. // Let's see if there is a port specified
  353. pszPort = strchr(
  354. pszAddress,
  355. ':');
  356. if (NULL==pszPort)
  357. {
  358. // No port was specified, so what we have here is an attempt to
  359. // connect to the default telnet port (23). I will point the port
  360. // pointer at a null character.
  361. pszPort = pszAddress + strlen(pszAddress);
  362. dwPort = 23;
  363. }
  364. else
  365. {
  366. *pszPort++ = '\0';
  367. dwPort = 0;
  368. }
  369. while ((*pszPort)!='\0')
  370. {
  371. if ('0'<=(*pszPort) && (*pszPort)<='9')
  372. {
  373. dwPort *= 10;
  374. dwPort += ((*pszPort) - '0');
  375. if (dwPort>0xffff) // Check for maximum port number
  376. {
  377. dwPort=0; // The port number is not valid
  378. break;
  379. }
  380. pszPort++; // Look at the next character
  381. }
  382. else
  383. {
  384. dwPort = 0; // The port number is not valid
  385. break;
  386. }
  387. }
  388. if (dwPort==0)
  389. {
  390. SetLastError(
  391. ERROR_INVALID_PARAMETER);
  392. goto Error;
  393. }
  394. // We have decoded the port, now we need to get the hostentry for
  395. // the target server.
  396. // Firstly check whether this is a dotted internet address.
  397. dwAddress = (DWORD)inet_addr(
  398. pszAddress);
  399. dwAddress = (dwAddress==0) ? INADDR_NONE : dwAddress;
  400. if (dwAddress==INADDR_NONE)
  401. {
  402. // This is not a dotted address, or is invalid.
  403. // Check for a machine name
  404. pHost = gethostbyname(
  405. pszAddress);
  406. if (pHost==NULL)
  407. {
  408. // This is not a valid address, so we need to return an error
  409. SetLastError(WSAGetLastError());
  410. goto Error;
  411. }
  412. else
  413. {
  414. dwAddress = *((DWORD*)(pHost->h_addr));
  415. }
  416. }
  417. else
  418. {
  419. pHost = NULL;
  420. }
  421. // This takes too long. If the user has used a dotted address, then
  422. // that is all that he will see.
  423. /*
  424. else
  425. {
  426. // Attempt to get the host name (for prettyness)
  427. pHost = gethostbyaddr(
  428. (char*)&dwAddress,
  429. sizeof(IN_ADDR),
  430. AF_INET);
  431. }
  432. */
  433. *Address = malloc(
  434. sizeof(SOCKADDR_IN));
  435. if (NULL==*Address)
  436. {
  437. SetLastError(
  438. ERROR_NOT_ENOUGH_MEMORY);
  439. goto Error;
  440. }
  441. ZeroMemory(
  442. *Address,
  443. sizeof(SOCKADDR_IN));
  444. if (pHost==NULL)
  445. {
  446. // This address does not resolve to a name, so we must just go
  447. // the IP number passed to us.
  448. *pszHostName = NULL;
  449. }
  450. else
  451. {
  452. // We have a hostent entry to populate this with
  453. dStringLength = MultiByteToWideChar(
  454. CP_ACP,
  455. 0,
  456. pHost->h_name,
  457. -1,
  458. NULL,
  459. 0);
  460. if (dStringLength==0)
  461. {
  462. goto Error;
  463. }
  464. *pszHostName = malloc(
  465. (dStringLength + 7) * sizeof(WCHAR));
  466. if (NULL==*pszHostName)
  467. {
  468. SetLastError(
  469. ERROR_NOT_ENOUGH_MEMORY);
  470. goto Error;
  471. }
  472. dStringLength = MultiByteToWideChar(
  473. CP_ACP,
  474. 0,
  475. pHost->h_name,
  476. -1,
  477. *pszHostName,
  478. dStringLength);
  479. if (dStringLength==0)
  480. {
  481. goto Error;
  482. }
  483. if (dwPort==23)
  484. {
  485. wcscat(
  486. *pszHostName,
  487. L":telnet");
  488. }
  489. else
  490. {
  491. PWSTR pszPort = *pszHostName + wcslen(*pszHostName);
  492. swprintf(
  493. pszPort,
  494. L":%u",
  495. dwPort & 0xFFFF);
  496. }
  497. }
  498. (**Address).sin_family = AF_INET;
  499. (**Address).sin_port = htons((USHORT)dwPort);
  500. (**Address).sin_addr.S_un.S_addr = (ULONG)dwAddress;
  501. *pszInetAddress = malloc(
  502. 22 * sizeof(WCHAR));
  503. if (*pszInetAddress==NULL)
  504. {
  505. goto Error;
  506. }
  507. swprintf(
  508. *pszInetAddress,
  509. L"%u.%u.%u.%u:%u",
  510. (DWORD)((**Address).sin_addr.S_un.S_un_b.s_b1),
  511. (DWORD)((**Address).sin_addr.S_un.S_un_b.s_b2),
  512. (DWORD)((**Address).sin_addr.S_un.S_un_b.s_b3),
  513. (DWORD)((**Address).sin_addr.S_un.S_un_b.s_b4),
  514. (DWORD)ntohs((**Address).sin_port));
  515. free(pszAddress);
  516. return TRUE;
  517. Error:
  518. lhcpParseParametersFree(
  519. pszHostName,
  520. pszInetAddress,
  521. Address);
  522. if (pszAddress!=NULL)
  523. {
  524. free(pszAddress);
  525. }
  526. return FALSE;
  527. }
  528. void lhcpParseParametersFree(
  529. PWSTR* pszHostName,
  530. PWSTR* pszInetAddress,
  531. SOCKADDR_IN** Address)
  532. {
  533. if (*pszHostName!=NULL)
  534. {
  535. free(*pszHostName);
  536. *pszHostName = NULL;
  537. }
  538. if (*pszInetAddress!=NULL)
  539. {
  540. free(*pszInetAddress);
  541. *pszInetAddress = NULL;
  542. }
  543. if (*Address!=NULL)
  544. {
  545. free(*Address);
  546. *Address = NULL;
  547. }
  548. }
  549. BOOL lhcpReadTCPIP(
  550. PTCPIP pObject,
  551. PVOID pBuffer,
  552. DWORD dwSize,
  553. PDWORD pdwBytesRead)
  554. {
  555. int dBytesRead;
  556. dBytesRead = recv(
  557. pObject->m_Socket,
  558. (char*)pBuffer,
  559. (int)dwSize,
  560. 0);
  561. if (dBytesRead==SOCKET_ERROR)
  562. {
  563. SetLastError(WSAGetLastError());
  564. return FALSE;
  565. }
  566. else if (dBytesRead==0) // graceful closure has occurred
  567. {
  568. SetLastError(
  569. ERROR_INVALID_HANDLE);
  570. return FALSE;
  571. }
  572. else
  573. {
  574. *pdwBytesRead = (DWORD)dBytesRead;
  575. return TRUE;
  576. }
  577. }
  578. BOOL lhcpWriteTCPIP(
  579. PTCPIP pObject,
  580. PVOID pBuffer,
  581. DWORD dwSize)
  582. {
  583. int dBytesSent;
  584. dBytesSent = send(
  585. pObject->m_Socket,
  586. (char FAR*)pBuffer,
  587. (int)dwSize,
  588. 0);
  589. if (dBytesSent==SOCKET_ERROR)
  590. {
  591. SetLastError(WSAGetLastError());
  592. wprintf(L"SEND error: %u\n", GetLastError());
  593. return FALSE;
  594. }
  595. else
  596. {
  597. return TRUE;
  598. }
  599. }
  600. extern PVOID APIENTRY lhcOpen(PCWSTR pcszPortSpec)
  601. {
  602. BOOL bResult;
  603. int dResult;
  604. PWSTR pszHostName;
  605. PWSTR pszInetAddr;
  606. SOCKADDR_IN* SockAddr;
  607. SOCKADDR_IN saLocal;
  608. PTCPIP pObject = NULL;
  609. int On = 1;
  610. bResult = lhcpParseParameters(
  611. pcszPortSpec,
  612. &pszHostName,
  613. &pszInetAddr,
  614. &SockAddr);
  615. if (!bResult)
  616. {
  617. goto Error;
  618. }
  619. // Allocate space and initialize the serial port object
  620. pObject = lhcpCreateNewObject();
  621. if (NULL==pObject)
  622. {
  623. goto Error;
  624. }
  625. // Open the serial port
  626. pObject->m_Socket = socket(
  627. SockAddr->sin_family,
  628. SOCK_STREAM,
  629. 0);
  630. if (INVALID_SOCKET==pObject->m_Socket)
  631. {
  632. goto Error;
  633. }
  634. ZeroMemory(
  635. &saLocal,
  636. sizeof(saLocal));
  637. if (pszHostName==NULL)
  638. {
  639. // wprintf(
  640. // L"Connecting to %s\n",
  641. // pszInetAddr);
  642. }
  643. else
  644. {
  645. // wprintf(
  646. // L"Connecting to %s (%s)\n",
  647. // pszHostName,
  648. // pszInetAddr);
  649. }
  650. ZeroMemory(
  651. &saLocal,
  652. sizeof(saLocal));
  653. saLocal.sin_family = AF_INET;
  654. saLocal.sin_port = 0;
  655. saLocal.sin_addr.S_un.S_addr = INADDR_ANY;
  656. dResult = bind(
  657. pObject->m_Socket,
  658. (SOCKADDR*)&saLocal,
  659. sizeof(SOCKADDR_IN));
  660. if (dResult==SOCKET_ERROR)
  661. {
  662. SetLastError(
  663. WSAGetLastError());
  664. wprintf(L"BIND error: %u\n", GetLastError());
  665. Sleep(1000);
  666. goto Error;
  667. }
  668. dResult = setsockopt(
  669. pObject->m_Socket,
  670. IPPROTO_TCP,
  671. TCP_NODELAY,
  672. (char *)&On,
  673. sizeof(On));
  674. if (dResult==SOCKET_ERROR)
  675. {
  676. SetLastError(
  677. WSAGetLastError());
  678. wprintf(L"SETSOCKOPT error: %u\n", GetLastError());
  679. Sleep(1000);
  680. goto Error;
  681. }
  682. dResult = connect(
  683. pObject->m_Socket,
  684. (SOCKADDR*)SockAddr,
  685. sizeof(SOCKADDR_IN));
  686. if (dResult==SOCKET_ERROR)
  687. {
  688. SetLastError(
  689. WSAGetLastError());
  690. if (dResult==SOCKET_ERROR)
  691. {
  692. SetLastError(
  693. WSAGetLastError());
  694. wprintf(L"CONNECT error: %u\n", GetLastError());
  695. Sleep(1000);
  696. goto Error;
  697. }
  698. goto Error;
  699. }
  700. // This event will be set when we want to close the port
  701. pObject->m_hAbort = CreateEvent(
  702. NULL,
  703. TRUE,
  704. FALSE,
  705. NULL);
  706. if (NULL==pObject->m_hAbort)
  707. {
  708. goto Error;
  709. }
  710. // This event will be used for overlapped reading from the port
  711. pObject->m_hReadComplete = CreateEvent(
  712. NULL,
  713. TRUE,
  714. FALSE,
  715. NULL);
  716. if (NULL==pObject->m_hReadComplete)
  717. {
  718. goto Error;
  719. }
  720. // This event will be used for overlapped writing to the port
  721. pObject->m_hWriteComplete = CreateEvent(
  722. NULL,
  723. TRUE,
  724. FALSE,
  725. NULL);
  726. if (NULL==pObject->m_hWriteComplete)
  727. {
  728. goto Error;
  729. }
  730. // This mutex will ensure that only one thread can read at a time
  731. pObject->m_hReadMutex = CreateMutex(
  732. NULL,
  733. FALSE,
  734. NULL);
  735. if (NULL==pObject->m_hReadMutex)
  736. {
  737. goto Error;
  738. }
  739. // This mutex will ensure that only one thread can write at a time
  740. pObject->m_hWriteMutex = CreateMutex(
  741. NULL,
  742. FALSE,
  743. NULL);
  744. if (NULL==pObject->m_hWriteMutex)
  745. {
  746. goto Error;
  747. }
  748. // This mutex will ensure that only one thread can close the port
  749. pObject->m_hCloseMutex = CreateMutex(
  750. NULL,
  751. FALSE,
  752. NULL);
  753. if (NULL==pObject->m_hCloseMutex)
  754. {
  755. goto Error;
  756. }
  757. // Free up the temporary memory used to parse the parameters
  758. lhcpParseParametersFree(
  759. &pszHostName,
  760. &pszInetAddr,
  761. &SockAddr);
  762. // Return a pointer to the new object
  763. return pObject;
  764. Error:
  765. lhcpParseParametersFree(
  766. &pszHostName,
  767. &pszInetAddr,
  768. &SockAddr);
  769. lhcpDeleteObject(
  770. pObject);
  771. return NULL;
  772. }
  773. extern BOOL APIENTRY lhcRead(
  774. PVOID pObject,
  775. PVOID pBuffer,
  776. DWORD dwSize,
  777. PDWORD pdwBytesRead)
  778. {
  779. OVERLAPPED Overlapped;
  780. DWORD dwEventMask;
  781. BOOL bResult;
  782. // Firstly, we need to check whether the pointer that got passed in
  783. // points to a valid TCPIP object
  784. if (!lhcpIsValidObject(pObject))
  785. {
  786. goto NoMutex;
  787. }
  788. bResult = lhcpAcquireReadWithAbort(
  789. (PTCPIP)pObject);
  790. if (!bResult)
  791. {
  792. SetLastError(
  793. ERROR_INVALID_HANDLE);
  794. goto NoMutex;
  795. }
  796. // We should now have a valid serial port event, so let's read the port.
  797. bResult = lhcpReadTCPIP(
  798. (PTCPIP)pObject,
  799. pBuffer,
  800. dwSize,
  801. pdwBytesRead);
  802. if (!bResult)
  803. {
  804. goto Error;
  805. }
  806. lhcpReleaseRead(
  807. (PTCPIP)pObject);
  808. return TRUE;
  809. Error:
  810. lhcpReleaseRead(
  811. (PTCPIP)pObject);
  812. NoMutex:
  813. return FALSE;
  814. }
  815. extern BOOL APIENTRY lhcWrite(
  816. PVOID pObject,
  817. PVOID pBuffer,
  818. DWORD dwSize)
  819. {
  820. OVERLAPPED Overlapped;
  821. BOOL bResult;
  822. // Firstly, we need to check whether the pointer that got passed in
  823. // points to a valid TCPIP object
  824. if (!lhcpIsValidObject(pObject))
  825. {
  826. goto NoMutex;
  827. }
  828. // Block until it is your turn
  829. bResult = lhcpAcquireWriteWithAbort(
  830. pObject);
  831. if (!bResult)
  832. {
  833. SetLastError(
  834. ERROR_INVALID_HANDLE);
  835. goto NoMutex;
  836. }
  837. // Wait for something to happen to the serial port
  838. bResult = lhcpWriteTCPIP(
  839. (PTCPIP)pObject,
  840. pBuffer,
  841. dwSize);
  842. if (!bResult)
  843. {
  844. goto Error;
  845. }
  846. lhcpReleaseWrite(
  847. (PTCPIP)pObject);
  848. return TRUE;
  849. Error:
  850. lhcpReleaseWrite(
  851. (PTCPIP)pObject);
  852. NoMutex:
  853. return FALSE;
  854. }
  855. extern BOOL APIENTRY lhcClose(PVOID pObject)
  856. {
  857. BOOL bResult;
  858. int dSockResult;
  859. // Firstly, we need to check whether the pointer that got passed in
  860. // points to a valid TCPIP object
  861. if (!lhcpIsValidObject(pObject))
  862. {
  863. goto Error;
  864. }
  865. // We need to ensure that we are the only thread closing this object
  866. bResult = lhcpAcquireCloseWithAbort(
  867. pObject);
  868. if (!bResult)
  869. {
  870. SetLastError(
  871. ERROR_INVALID_HANDLE);
  872. goto NoMutex;
  873. }
  874. // Signal everyone to quit doing what they're doing. Any new threads
  875. // calling lhcRead and lhcWrite will be immediately sent packing, since
  876. // the m_hAbort event is waited on along with the relevant mutex.
  877. bResult = SetEvent(
  878. ((PTCPIP)pObject)->m_hAbort);
  879. // This abort flag will not cause blocking socket reads and writes to quit
  880. // immediately. The only way to make this happen is to close the socket
  881. // gracefully. So here we go...
  882. dSockResult = closesocket(
  883. ((PTCPIP)pObject)->m_Socket);
  884. if (dSockResult==SOCKET_ERROR)
  885. {
  886. SetLastError(WSAGetLastError());
  887. goto Error;
  888. }
  889. else
  890. {
  891. // This will cause all subsequent attempts to use the socket to fail
  892. ((PTCPIP)pObject)->m_Socket = INVALID_SOCKET;
  893. }
  894. // Now acquire the read and write mutexes so that no-one else will try to
  895. // access this object to read or write. Abort does not apply, since we
  896. // have already signalled it. We know that we are closing, and we need
  897. // the read and write mutexes.
  898. bResult = lhcpAcquireReadAndWrite(
  899. (PTCPIP)pObject);
  900. if (!bResult)
  901. {
  902. SetLastError(
  903. ERROR_INVALID_HANDLE);
  904. goto Error;
  905. }
  906. // Closes all of the open handles, erases the secret and frees up the
  907. // memory associated with the object. We can close the mutex objects,
  908. // even though we are the owners, since we can guarantee that no-one
  909. // else is waiting on them. The m_hAbort event being signalled will
  910. // ensure this.
  911. lhcpDeleteObject(
  912. (PTCPIP)pObject);
  913. return TRUE;
  914. Error:
  915. lhcpReleaseClose(
  916. (PTCPIP)pObject);
  917. NoMutex:
  918. return FALSE;
  919. }
  920. extern DWORD APIENTRY lhcGetLibraryName(
  921. PWSTR pszBuffer,
  922. DWORD dwSize)
  923. {
  924. DWORD dwNameSize = wcslen(TCPIP_NAME)+1;
  925. // If zero is passed in as the buffer length, we will return the
  926. // required buffer size in characters, as calulated above. If the
  927. // incoming buffer size is not zero, and smaller than the required
  928. // buffer size, we return 0 (failure) with a valid error code. Notice
  929. // that in the case where the incoming size is zero, we don't touch
  930. // the buffer pointer at all.
  931. if (dwSize!=0 && dwSize < dwNameSize)
  932. {
  933. SetLastError(
  934. ERROR_INSUFFICIENT_BUFFER);
  935. dwNameSize = 0;
  936. }
  937. else
  938. {
  939. wcscpy(
  940. pszBuffer,
  941. TCPIP_NAME);
  942. }
  943. return dwNameSize;
  944. }