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.

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