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.

2258 lines
55 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // DbgRpc transports.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000-2001.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.hpp"
  9. // Crypto hashing requires a crypto provider to be available
  10. // (this may not always be the case on Win9x or NT4) so just go with Base64.
  11. #define HashPassword(Password, Buffer) Base64HashPassword(Password, Buffer)
  12. #ifndef NT_NATIVE
  13. BOOL
  14. CryptoHashPassword(PCSTR Password, PUCHAR Buffer)
  15. {
  16. BOOL Status = FALSE;
  17. HCRYPTPROV Prov;
  18. HCRYPTHASH Hash;
  19. ULONG HashSize;
  20. if (!CryptAcquireContext(&Prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
  21. CRYPT_VERIFYCONTEXT))
  22. {
  23. goto EH_Fail;
  24. }
  25. if (!CryptCreateHash(Prov, CALG_MD5, NULL, 0, &Hash))
  26. {
  27. goto EH_Prov;
  28. }
  29. if (!CryptHashData(Hash, (PBYTE)Password, strlen(Password), 0))
  30. {
  31. goto EH_Hash;
  32. }
  33. ZeroMemory(Buffer, MAX_PASSWORD_BUFFER);
  34. HashSize = MAX_PASSWORD_BUFFER;
  35. if (!CryptGetHashParam(Hash, HP_HASHVAL, Buffer, &HashSize, 0))
  36. {
  37. goto EH_Hash;
  38. }
  39. Status = TRUE;
  40. EH_Hash:
  41. CryptDestroyHash(Hash);
  42. EH_Prov:
  43. CryptReleaseContext(Prov, 0);
  44. EH_Fail:
  45. if (!Status)
  46. {
  47. DRPC_ERR(("Unable to hash password, %d\n", GetLastError()));
  48. }
  49. return Status;
  50. }
  51. #endif // #ifndef NT_NATIVE
  52. UCHAR g_Base64Table[64] =
  53. {
  54. 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
  55. 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
  56. 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
  57. 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
  58. };
  59. BOOL
  60. Base64HashPassword(PCSTR Password, PUCHAR Buffer)
  61. {
  62. ULONG Len = strlen(Password);
  63. if ((Len * 4 + 2) / 3 > MAX_PASSWORD_BUFFER)
  64. {
  65. DRPC_ERR(("Unable to hash password\n"));
  66. return FALSE;
  67. }
  68. ZeroMemory(Buffer, MAX_PASSWORD_BUFFER);
  69. ULONG Collect;
  70. while (Len >= 3)
  71. {
  72. //
  73. // Collect three characters and turn them
  74. // into four output bytes.
  75. //
  76. Collect = *Password++;
  77. Collect = (Collect << 8) | *Password++;
  78. Collect = (Collect << 8) | *Password++;
  79. *Buffer++ = g_Base64Table[(Collect >> 18) & 0x3f];
  80. *Buffer++ = g_Base64Table[(Collect >> 12) & 0x3f];
  81. *Buffer++ = g_Base64Table[(Collect >> 6) & 0x3f];
  82. *Buffer++ = g_Base64Table[(Collect >> 0) & 0x3f];
  83. Len -= 3;
  84. }
  85. switch(Len)
  86. {
  87. case 2:
  88. Collect = *Password++;
  89. Collect = (Collect << 8) | *Password++;
  90. Collect <<= 8;
  91. *Buffer++ = g_Base64Table[(Collect >> 18) & 0x3f];
  92. *Buffer++ = g_Base64Table[(Collect >> 12) & 0x3f];
  93. *Buffer++ = g_Base64Table[(Collect >> 6) & 0x3f];
  94. *Buffer++ = '=';
  95. break;
  96. case 1:
  97. Collect = *Password++;
  98. Collect <<= 16;
  99. *Buffer++ = g_Base64Table[(Collect >> 18) & 0x3f];
  100. *Buffer++ = g_Base64Table[(Collect >> 12) & 0x3f];
  101. *Buffer++ = '=';
  102. *Buffer++ = '=';
  103. break;
  104. }
  105. return TRUE;
  106. }
  107. //----------------------------------------------------------------------------
  108. //
  109. // DbgRpcTransport.
  110. //
  111. //----------------------------------------------------------------------------
  112. PCSTR g_DbgRpcTransportNames[TRANS_COUNT] =
  113. {
  114. "tcp", "npipe", "ssl", "spipe", "1394", "com",
  115. };
  116. DbgRpcTransport::~DbgRpcTransport(void)
  117. {
  118. // Nothing to do.
  119. }
  120. ULONG
  121. DbgRpcTransport::GetNumberParameters(void)
  122. {
  123. return 2;
  124. }
  125. void
  126. DbgRpcTransport::GetParameter(ULONG Index, PSTR Name, PSTR Value)
  127. {
  128. switch(Index)
  129. {
  130. case 0:
  131. if (m_ServerName[0])
  132. {
  133. strcpy(Name, "Server");
  134. strcpy(Value, m_ServerName);
  135. }
  136. break;
  137. case 1:
  138. if (m_PasswordGiven)
  139. {
  140. strcpy(Name, "Password");
  141. strcpy(Value, "*");
  142. }
  143. break;
  144. }
  145. }
  146. void
  147. DbgRpcTransport::ResetParameters(void)
  148. {
  149. m_PasswordGiven = FALSE;
  150. m_ServerName[0] = 0;
  151. }
  152. BOOL
  153. DbgRpcTransport::SetParameter(PCSTR Name, PCSTR Value)
  154. {
  155. if (!_stricmp(Name, "Password"))
  156. {
  157. if (Value == NULL)
  158. {
  159. DbgRpcError("Remoting password was not specified correctly\n");
  160. return FALSE;
  161. }
  162. if (!HashPassword(Value, m_HashedPassword))
  163. {
  164. return FALSE;
  165. }
  166. m_PasswordGiven = TRUE;
  167. }
  168. else
  169. {
  170. return FALSE;
  171. }
  172. return TRUE;
  173. }
  174. void
  175. DbgRpcTransport::CloneData(DbgRpcTransport* Trans)
  176. {
  177. strcpy(Trans->m_ServerName, m_ServerName);
  178. Trans->m_PasswordGiven = m_PasswordGiven;
  179. memcpy(Trans->m_HashedPassword, m_HashedPassword,
  180. sizeof(m_HashedPassword));
  181. }
  182. //----------------------------------------------------------------------------
  183. //
  184. // DbgRpcTcpTransport.
  185. //
  186. //----------------------------------------------------------------------------
  187. #ifndef NT_NATIVE
  188. DbgRpcTcpTransport::~DbgRpcTcpTransport(void)
  189. {
  190. if (m_Sock != INVALID_SOCKET)
  191. {
  192. shutdown(m_Sock, 2);
  193. closesocket(m_Sock);
  194. m_Sock = INVALID_SOCKET;
  195. }
  196. if (m_OlRead.hEvent != NULL)
  197. {
  198. WSACloseEvent(m_OlRead.hEvent);
  199. ZeroMemory(&m_OlRead, sizeof(m_OlRead));
  200. }
  201. if (m_OlWrite.hEvent != NULL)
  202. {
  203. WSACloseEvent(m_OlWrite.hEvent);
  204. ZeroMemory(&m_OlWrite, sizeof(m_OlWrite));
  205. }
  206. }
  207. ULONG
  208. DbgRpcTcpTransport::GetNumberParameters(void)
  209. {
  210. return 1 + DbgRpcTransport::GetNumberParameters();
  211. }
  212. void
  213. DbgRpcTcpTransport::GetParameter(ULONG Index, PSTR Name, PSTR Value)
  214. {
  215. switch(Index)
  216. {
  217. case 0:
  218. if (m_Addr.sin_port)
  219. {
  220. strcpy(Name, "Port");
  221. sprintf(Value, "%d", ntohs(m_Addr.sin_port));
  222. if (m_TopPort)
  223. {
  224. sprintf(Value + strlen(Value), ":%d", m_TopPort);
  225. }
  226. }
  227. break;
  228. default:
  229. DbgRpcTransport::GetParameter(Index - 1, Name, Value);
  230. break;
  231. }
  232. }
  233. void
  234. DbgRpcTcpTransport::ResetParameters(void)
  235. {
  236. ZeroMemory(&m_Addr, sizeof(m_Addr));
  237. m_Addr.sin_family = AF_INET;
  238. m_Addr.sin_addr.s_addr = INADDR_ANY;
  239. m_TopPort = 0;
  240. DbgRpcTransport::ResetParameters();
  241. }
  242. BOOL
  243. DbgRpcTcpTransport::SetParameter(PCSTR Name, PCSTR Value)
  244. {
  245. if (!_stricmp(Name, "server"))
  246. {
  247. if (Value == NULL)
  248. {
  249. DbgRpcError("TCP parameters: "
  250. "the server name was not specified correctly\n");
  251. return FALSE;
  252. }
  253. // Skip leading \\ if they were given.
  254. if (Value[0] == '\\' && Value[1] == '\\')
  255. {
  256. Value += 2;
  257. }
  258. m_Addr.sin_addr.s_addr = inet_addr(Value);
  259. if (m_Addr.sin_addr.s_addr == INADDR_NONE)
  260. {
  261. struct hostent *Host = gethostbyname(Value);
  262. if (Host == NULL)
  263. {
  264. DbgRpcError("TCP parameters: "
  265. "the specified server (%s) does not exist\n",
  266. Value);
  267. return FALSE;
  268. }
  269. m_Addr.sin_family = Host->h_addrtype;
  270. memcpy(&m_Addr.sin_addr, Host->h_addr, Host->h_length);
  271. }
  272. strcpy(m_ServerName, Value);
  273. }
  274. else if (!_stricmp(Name, "port"))
  275. {
  276. if (Value == NULL)
  277. {
  278. DbgRpcError("TCP parameters: "
  279. "the port number was not specified correctly\n");
  280. return FALSE;
  281. }
  282. ULONG Port;
  283. // Allow a range of ports to be specified if so desired.
  284. switch(sscanf(Value, "%i:%i", &Port, &m_TopPort))
  285. {
  286. case 0:
  287. Port = 0;
  288. // Fall through.
  289. case 1:
  290. m_TopPort = 0;
  291. break;
  292. }
  293. if (Port > 0xffff || m_TopPort > 0xffff)
  294. {
  295. DbgRpcError("TCP parameters: port numbers are "
  296. "limited to 16 bits\n");
  297. return FALSE;
  298. }
  299. m_Addr.sin_port = htons((USHORT)Port);
  300. }
  301. else
  302. {
  303. if (!DbgRpcTransport::SetParameter(Name, Value))
  304. {
  305. DbgRpcError("TCP parameters: %s is not a valid parameter\n", Name);
  306. return FALSE;
  307. }
  308. }
  309. return TRUE;
  310. }
  311. DbgRpcTransport*
  312. DbgRpcTcpTransport::Clone(void)
  313. {
  314. DbgRpcTcpTransport* Trans = new DbgRpcTcpTransport;
  315. if (Trans != NULL)
  316. {
  317. DbgRpcTransport::CloneData(Trans);
  318. memcpy(&Trans->m_Addr, &m_Addr, sizeof(m_Addr));
  319. Trans->m_TopPort = m_TopPort;
  320. }
  321. return Trans;
  322. }
  323. HRESULT
  324. DbgRpcTcpTransport::CreateServer(void)
  325. {
  326. HRESULT Status;
  327. //
  328. // We must create our sockets overlapped so that
  329. // we can control waiting for I/O completion.
  330. // If we leave the waiting to Winsock by using
  331. // synchronous sockets it uses an alertable wait
  332. // which can cause our event notification APCs to
  333. // be received in the middle of reading packets.
  334. //
  335. m_Sock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
  336. WSA_FLAG_OVERLAPPED);
  337. if (m_Sock == INVALID_SOCKET)
  338. {
  339. Status = WIN32_STATUS(WSAGetLastError());
  340. goto EH_Fail;
  341. }
  342. for (;;)
  343. {
  344. if (bind(m_Sock, (struct sockaddr *)&m_Addr,
  345. sizeof(m_Addr)) != SOCKET_ERROR)
  346. {
  347. break;
  348. }
  349. ULONG Port = ntohs(m_Addr.sin_port);
  350. Status = WIN32_STATUS(WSAGetLastError());
  351. if (Status == HRESULT_FROM_WIN32(WSAEADDRINUSE) &&
  352. m_TopPort > Port)
  353. {
  354. // The user has given a range of ports and
  355. // we haven't checked them all yet, so go
  356. // around again.
  357. m_Addr.sin_port = htons((USHORT)(Port + 1));
  358. }
  359. else
  360. {
  361. goto EH_Sock;
  362. }
  363. }
  364. //
  365. // Retrieve the port actually used in case port
  366. // zero was used to let TCP pick a port.
  367. //
  368. struct sockaddr_in Name;
  369. int Len;
  370. Len = sizeof(Name);
  371. if (getsockname(m_Sock, (struct sockaddr *)&Name, &Len) != 0)
  372. {
  373. Status = WIN32_STATUS(WSAGetLastError());
  374. goto EH_Sock;
  375. }
  376. // Copy just the port as we do not want
  377. // to update the rest of the address.
  378. m_Addr.sin_port = Name.sin_port;
  379. // Turn off linger-on-close.
  380. int On;
  381. On = TRUE;
  382. setsockopt(m_Sock, SOL_SOCKET, SO_DONTLINGER,
  383. (char *)&On, sizeof(On));
  384. if (listen(m_Sock, SOMAXCONN) == SOCKET_ERROR)
  385. {
  386. Status = WIN32_STATUS(WSAGetLastError());
  387. goto EH_Sock;
  388. }
  389. return S_OK;
  390. EH_Sock:
  391. closesocket(m_Sock);
  392. m_Sock = INVALID_SOCKET;
  393. EH_Fail:
  394. return Status;
  395. }
  396. HRESULT
  397. DbgRpcTcpTransport::AcceptConnection(DbgRpcTransport** ClientTrans,
  398. PSTR Identity)
  399. {
  400. DbgRpcTcpTransport* Trans = new DbgRpcTcpTransport;
  401. if (Trans == NULL)
  402. {
  403. return E_OUTOFMEMORY;
  404. }
  405. DbgRpcTransport::CloneData(Trans);
  406. DRPC(("%X: Waiting to accept connection on socket %p\n",
  407. GetCurrentThreadId(), m_Sock));
  408. int AddrLen = sizeof(Trans->m_Addr);
  409. Trans->m_Sock = accept(m_Sock, (struct sockaddr *)&Trans->m_Addr,
  410. &AddrLen);
  411. if (Trans->m_Sock == INVALID_SOCKET)
  412. {
  413. DRPC(("%X: Accept failed, %X\n",
  414. GetCurrentThreadId(), WSAGetLastError()));
  415. delete Trans;
  416. return HRESULT_FROM_WIN32(WSAGetLastError());
  417. }
  418. HRESULT Status = Trans->InitOl();
  419. if (Status != S_OK)
  420. {
  421. DRPC(("%X: InitOl failed, %X\n",
  422. GetCurrentThreadId(), Status));
  423. delete Trans;
  424. return Status;
  425. }
  426. int On = TRUE;
  427. setsockopt(Trans->m_Sock, IPPROTO_TCP, TCP_NODELAY,
  428. (PSTR)&On, sizeof(On));
  429. DRPC(("%X: Accept connection on socket %p\n",
  430. GetCurrentThreadId(), Trans->m_Sock));
  431. *ClientTrans = Trans;
  432. if (Trans->m_Addr.sin_family == AF_INET)
  433. {
  434. strcpy(Identity, "tcp ");
  435. struct hostent* Host =
  436. #if 0
  437. // This lookup is really slow and doesn't seem to work
  438. // very often so just don't bother.
  439. gethostbyaddr((PCSTR)&Trans->m_Addr, AddrLen, AF_INET);
  440. #else
  441. NULL;
  442. #endif
  443. if (Host != NULL)
  444. {
  445. strcat(Identity, Host->h_name);
  446. strcat(Identity, " ");
  447. }
  448. sprintf(Identity + strlen(Identity), "%s, port %d",
  449. inet_ntoa(Trans->m_Addr.sin_addr), ntohs(m_Addr.sin_port));
  450. }
  451. else
  452. {
  453. sprintf(Identity, "tcp family %d, bytes %d",
  454. Trans->m_Addr.sin_family, AddrLen);
  455. }
  456. return S_OK;
  457. }
  458. HRESULT
  459. DbgRpcTcpTransport::ConnectServer(void)
  460. {
  461. //
  462. // We must create our sockets overlapped so that
  463. // we can control waiting for I/O completion.
  464. // If we leave the waiting to Winsock by using
  465. // synchronous sockets it uses an alertable wait
  466. // which can cause our event notification APCs to
  467. // be received in the middle of reading packets.
  468. //
  469. m_Sock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,
  470. WSA_FLAG_OVERLAPPED);
  471. if (m_Sock != INVALID_SOCKET)
  472. {
  473. if (connect(m_Sock, (struct sockaddr *)&m_Addr,
  474. sizeof(m_Addr)) == SOCKET_ERROR ||
  475. InitOl() != S_OK)
  476. {
  477. closesocket(m_Sock);
  478. m_Sock = INVALID_SOCKET;
  479. }
  480. else
  481. {
  482. int On = TRUE;
  483. setsockopt(m_Sock, IPPROTO_TCP, TCP_NODELAY,
  484. (PSTR)&On, sizeof(On));
  485. DRPC(("%X: Connect on socket %p\n",
  486. GetCurrentThreadId(), m_Sock));
  487. }
  488. }
  489. return m_Sock != INVALID_SOCKET ? S_OK : RPC_E_SERVER_DIED;
  490. }
  491. ULONG
  492. DbgRpcTcpTransport::Read(ULONG Seq, PVOID Buffer, ULONG Len)
  493. {
  494. ULONG Done;
  495. Done = 0;
  496. while (Len > 0)
  497. {
  498. if (!WSAResetEvent(m_OlRead.hEvent))
  499. {
  500. break;
  501. }
  502. WSABUF SockBuf;
  503. ULONG SockDone;
  504. ULONG SockFlags;
  505. SockBuf.buf = (PSTR)Buffer;
  506. SockBuf.len = Len;
  507. SockFlags = 0;
  508. if (WSARecv(m_Sock, &SockBuf, 1, &SockDone, &SockFlags,
  509. &m_OlRead, NULL) == SOCKET_ERROR)
  510. {
  511. if (WSAGetLastError() == WSA_IO_PENDING)
  512. {
  513. if (!WSAGetOverlappedResult(m_Sock, &m_OlRead, &SockDone,
  514. TRUE, &SockFlags))
  515. {
  516. break;
  517. }
  518. }
  519. else
  520. {
  521. break;
  522. }
  523. }
  524. else if (SockDone == 0)
  525. {
  526. // Socket connection was broken.
  527. break;
  528. }
  529. Buffer = (PVOID)((PUCHAR)Buffer + SockDone);
  530. Len -= SockDone;
  531. Done += SockDone;
  532. }
  533. return Done;
  534. }
  535. ULONG
  536. DbgRpcTcpTransport::Write(ULONG Seq, PVOID Buffer, ULONG Len)
  537. {
  538. ULONG Done;
  539. Done = 0;
  540. while (Len > 0)
  541. {
  542. if (!WSAResetEvent(m_OlWrite.hEvent))
  543. {
  544. break;
  545. }
  546. WSABUF SockBuf;
  547. ULONG SockDone;
  548. ULONG SockFlags;
  549. SockBuf.buf = (PSTR)Buffer;
  550. SockBuf.len = Len;
  551. SockFlags = 0;
  552. if (WSASend(m_Sock, &SockBuf, 1, &SockDone, SockFlags,
  553. &m_OlWrite, NULL) == SOCKET_ERROR)
  554. {
  555. if (WSAGetLastError() == WSA_IO_PENDING)
  556. {
  557. if (!WSAGetOverlappedResult(m_Sock, &m_OlWrite, &SockDone,
  558. TRUE, &SockFlags))
  559. {
  560. break;
  561. }
  562. }
  563. else
  564. {
  565. break;
  566. }
  567. }
  568. Buffer = (PVOID)((PUCHAR)Buffer + SockDone);
  569. Len -= SockDone;
  570. Done += SockDone;
  571. }
  572. return Done;
  573. }
  574. HRESULT
  575. DbgRpcTcpTransport::InitOl(void)
  576. {
  577. m_OlRead.hEvent = WSACreateEvent();
  578. if (m_OlRead.hEvent == NULL)
  579. {
  580. return HRESULT_FROM_WIN32(WSAGetLastError());
  581. }
  582. m_OlWrite.hEvent = WSACreateEvent();
  583. if (m_OlWrite.hEvent == NULL)
  584. {
  585. WSACloseEvent(m_OlRead.hEvent);
  586. m_OlRead.hEvent = NULL;
  587. return HRESULT_FROM_WIN32(WSAGetLastError());
  588. }
  589. return S_OK;
  590. }
  591. #endif // #ifndef NT_NATIVE
  592. //----------------------------------------------------------------------------
  593. //
  594. // DbgRpcNamedPipeTransport.
  595. //
  596. //----------------------------------------------------------------------------
  597. DbgRpcNamedPipeTransport::~DbgRpcNamedPipeTransport(void)
  598. {
  599. if (m_Handle != NULL)
  600. {
  601. CloseHandle(m_Handle);
  602. m_Handle = NULL;
  603. }
  604. if (m_ReadOlap.hEvent != NULL)
  605. {
  606. CloseHandle(m_ReadOlap.hEvent);
  607. }
  608. if (m_WriteOlap.hEvent != NULL)
  609. {
  610. CloseHandle(m_WriteOlap.hEvent);
  611. }
  612. }
  613. ULONG
  614. DbgRpcNamedPipeTransport::GetNumberParameters(void)
  615. {
  616. return 1 + DbgRpcTransport::GetNumberParameters();
  617. }
  618. void
  619. DbgRpcNamedPipeTransport::GetParameter(ULONG Index, PSTR Name, PSTR Value)
  620. {
  621. switch(Index)
  622. {
  623. case 0:
  624. if (m_Pipe[0])
  625. {
  626. strcpy(Name, "Pipe");
  627. strcpy(Value, m_Pipe);
  628. }
  629. break;
  630. default:
  631. DbgRpcTransport::GetParameter(Index - 1, Name, Value);
  632. break;
  633. }
  634. }
  635. void
  636. DbgRpcNamedPipeTransport::ResetParameters(void)
  637. {
  638. m_Pipe[0] = 0;
  639. m_Handle = NULL;
  640. DbgRpcTransport::ResetParameters();
  641. }
  642. BOOL
  643. DbgRpcNamedPipeTransport::SetParameter(PCSTR Name, PCSTR Value)
  644. {
  645. if (!_stricmp(Name, "server"))
  646. {
  647. if (Value == NULL)
  648. {
  649. DbgRpcError("NPIPE parameters: "
  650. "the server name was not specified correctly\n");
  651. return FALSE;
  652. }
  653. // Skip leading \\ if they were given.
  654. if (Value[0] == '\\' && Value[1] == '\\')
  655. {
  656. Value += 2;
  657. }
  658. strcpy(m_ServerName, Value);
  659. }
  660. else if (!_stricmp(Name, "pipe"))
  661. {
  662. if (Value == NULL)
  663. {
  664. DbgRpcError("NPIPE parameters: "
  665. "the pipe name was not specified correctly\n");
  666. return FALSE;
  667. }
  668. // Use the value as a printf format string so that
  669. // users can create unique names using the process and
  670. // thread IDs in their own format.
  671. _snprintf(m_Pipe, sizeof(m_Pipe), Value,
  672. GetCurrentProcessId(), GetCurrentThreadId());
  673. m_Pipe[sizeof(m_Pipe) - 1] = 0;
  674. }
  675. else
  676. {
  677. if (!DbgRpcTransport::SetParameter(Name, Value))
  678. {
  679. DbgRpcError("NPIPE parameters: %s is not a valid parameter\n",
  680. Name);
  681. return FALSE;
  682. }
  683. }
  684. return TRUE;
  685. }
  686. DbgRpcTransport*
  687. DbgRpcNamedPipeTransport::Clone(void)
  688. {
  689. DbgRpcNamedPipeTransport* Trans = new DbgRpcNamedPipeTransport;
  690. if (Trans != NULL)
  691. {
  692. DbgRpcTransport::CloneData(Trans);
  693. strcpy(Trans->m_Pipe, m_Pipe);
  694. }
  695. return Trans;
  696. }
  697. HRESULT
  698. DbgRpcNamedPipeTransport::CreateServer(void)
  699. {
  700. HANDLE Pipe;
  701. char PipeName[MAX_PARAM_VALUE + 16];
  702. #ifndef NT_NATIVE
  703. strcpy(PipeName, "\\\\.\\pipe\\");
  704. #else
  705. strcpy(PipeName, "\\Device\\NamedPipe\\");
  706. #endif
  707. strcat(PipeName, m_Pipe);
  708. // Check and see if this pipe already exists.
  709. // This might mess up whoever created the pipe if
  710. // there is one but it's better than creating a
  711. // duplicate pipe and having clients get messed up.
  712. #ifndef NT_NATIVE
  713. Pipe = CreateFile(PipeName, GENERIC_READ | GENERIC_WRITE,
  714. 0, NULL, OPEN_EXISTING, 0, NULL);
  715. #else
  716. Pipe = NtNativeCreateFileA(PipeName, GENERIC_READ | GENERIC_WRITE,
  717. 0, NULL, OPEN_EXISTING, 0, NULL, FALSE);
  718. #endif
  719. if (Pipe != INVALID_HANDLE_VALUE)
  720. {
  721. // Pipe is already in use.
  722. DRPC_ERR(("%X: Pipe %s is already in use\n",
  723. GetCurrentThreadId(), PipeName));
  724. CloseHandle(Pipe);
  725. return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
  726. }
  727. return S_OK;
  728. }
  729. HRESULT
  730. DbgRpcNamedPipeTransport::AcceptConnection(DbgRpcTransport** ClientTrans,
  731. PSTR Identity)
  732. {
  733. DbgRpcNamedPipeTransport* Trans = new DbgRpcNamedPipeTransport;
  734. if (Trans == NULL)
  735. {
  736. return E_OUTOFMEMORY;
  737. }
  738. DbgRpcTransport::CloneData(Trans);
  739. char PipeName[MAX_PARAM_VALUE + 16];
  740. #ifndef NT_NATIVE
  741. strcpy(PipeName, "\\\\.\\pipe\\");
  742. #else
  743. strcpy(PipeName, "\\Device\\NamedPipe\\");
  744. #endif
  745. strcat(PipeName, m_Pipe);
  746. #ifndef NT_NATIVE
  747. Trans->m_Handle =
  748. CreateNamedPipe(PipeName,
  749. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  750. PIPE_WAIT | PIPE_READMODE_BYTE | PIPE_TYPE_BYTE,
  751. PIPE_UNLIMITED_INSTANCES, 4096, 4096, INFINITE,
  752. &g_AllAccessSecAttr);
  753. #else
  754. Trans->m_Handle =
  755. NtNativeCreateNamedPipeA(PipeName,
  756. PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
  757. PIPE_WAIT | PIPE_READMODE_BYTE |
  758. PIPE_TYPE_BYTE,
  759. PIPE_UNLIMITED_INSTANCES, 4096, 4096,
  760. INFINITE,
  761. &g_AllAccessSecAttr, FALSE);
  762. #endif
  763. if (Trans->m_Handle == INVALID_HANDLE_VALUE)
  764. {
  765. Trans->m_Handle = NULL;
  766. delete Trans;
  767. return WIN32_LAST_STATUS();
  768. }
  769. HRESULT Status;
  770. if ((Status = CreateOverlappedPair(&Trans->m_ReadOlap,
  771. &Trans->m_WriteOlap)) != S_OK)
  772. {
  773. delete Trans;
  774. return Status;
  775. }
  776. DRPC(("%X: Waiting to accept connection on pipe %s\n",
  777. GetCurrentThreadId(), m_Pipe));
  778. if (!ConnectNamedPipe(Trans->m_Handle, &Trans->m_ReadOlap))
  779. {
  780. if (GetLastError() == ERROR_PIPE_CONNECTED)
  781. {
  782. goto Connected;
  783. }
  784. else if (GetLastError() == ERROR_IO_PENDING)
  785. {
  786. DWORD Unused;
  787. if (GetOverlappedResult(Trans->m_Handle, &Trans->m_ReadOlap,
  788. &Unused, TRUE))
  789. {
  790. goto Connected;
  791. }
  792. }
  793. DRPC(("%X: Accept failed, %d\n",
  794. GetCurrentThreadId(), GetLastError()));
  795. delete Trans;
  796. return WIN32_LAST_STATUS();
  797. }
  798. Connected:
  799. DRPC(("%X: Accept connection on pipe %s\n",
  800. GetCurrentThreadId(), m_Pipe));
  801. *ClientTrans = Trans;
  802. _snprintf(Identity, DBGRPC_MAX_IDENTITY, "npipe %s", m_Pipe);
  803. Identity[DBGRPC_MAX_IDENTITY - 1] = 0;
  804. return S_OK;
  805. }
  806. HRESULT
  807. DbgRpcNamedPipeTransport::ConnectServer(void)
  808. {
  809. HRESULT Status;
  810. char PipeName[2 * MAX_PARAM_VALUE + 16];
  811. sprintf(PipeName, "\\\\%s\\pipe\\%s", m_ServerName, m_Pipe);
  812. if ((Status = CreateOverlappedPair(&m_ReadOlap, &m_WriteOlap)) != S_OK)
  813. {
  814. return Status;
  815. }
  816. for (;;)
  817. {
  818. m_Handle = CreateFile(PipeName, GENERIC_READ | GENERIC_WRITE,
  819. 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
  820. NULL);
  821. if (m_Handle != INVALID_HANDLE_VALUE)
  822. {
  823. break;
  824. }
  825. m_Handle = NULL;
  826. if (GetLastError() != ERROR_PIPE_BUSY)
  827. {
  828. return WIN32_LAST_STATUS();
  829. }
  830. if (!WaitNamedPipe(PipeName, NMPWAIT_WAIT_FOREVER))
  831. {
  832. return WIN32_LAST_STATUS();
  833. }
  834. }
  835. DRPC(("%X: Connect on pipe %s\n",
  836. GetCurrentThreadId(), m_Pipe));
  837. return S_OK;
  838. }
  839. ULONG
  840. DbgRpcNamedPipeTransport::Read(ULONG Seq, PVOID Buffer, ULONG Len)
  841. {
  842. ULONG Done = 0;
  843. ULONG Ret;
  844. while (Len > 0)
  845. {
  846. if (!ReadFile(m_Handle, Buffer, Len, &Ret, &m_ReadOlap))
  847. {
  848. if (GetLastError() != ERROR_IO_PENDING ||
  849. !GetOverlappedResult(m_Handle, &m_ReadOlap, &Ret, TRUE))
  850. {
  851. break;
  852. }
  853. }
  854. Buffer = (PVOID)((PUCHAR)Buffer + Ret);
  855. Len -= Ret;
  856. Done += Ret;
  857. }
  858. return Done;
  859. }
  860. ULONG
  861. DbgRpcNamedPipeTransport::Write(ULONG Seq, PVOID Buffer, ULONG Len)
  862. {
  863. ULONG Done = 0;
  864. ULONG Ret;
  865. while (Len > 0)
  866. {
  867. if (!WriteFile(m_Handle, Buffer, Len, &Ret, &m_WriteOlap))
  868. {
  869. if (GetLastError() != ERROR_IO_PENDING ||
  870. !GetOverlappedResult(m_Handle, &m_WriteOlap, &Ret, TRUE))
  871. {
  872. break;
  873. }
  874. }
  875. Buffer = (PVOID)((PUCHAR)Buffer + Ret);
  876. Len -= Ret;
  877. Done += Ret;
  878. }
  879. return Done;
  880. }
  881. //----------------------------------------------------------------------------
  882. //
  883. // DbgRpc1394Transport.
  884. //
  885. //----------------------------------------------------------------------------
  886. DbgRpc1394Transport::~DbgRpc1394Transport(void)
  887. {
  888. if (m_Handle != NULL)
  889. {
  890. CloseHandle(m_Handle);
  891. m_Handle = NULL;
  892. }
  893. }
  894. ULONG
  895. DbgRpc1394Transport::GetNumberParameters(void)
  896. {
  897. return 1 + DbgRpcTransport::GetNumberParameters();
  898. }
  899. void
  900. DbgRpc1394Transport::GetParameter(ULONG Index, PSTR Name, PSTR Value)
  901. {
  902. switch(Index)
  903. {
  904. case 0:
  905. if (m_AcceptChannel != 0)
  906. {
  907. strcpy(Name, "Channel");
  908. sprintf(Value, "%d", m_AcceptChannel);
  909. }
  910. break;
  911. default:
  912. DbgRpcTransport::GetParameter(Index - 1, Name, Value);
  913. break;
  914. }
  915. }
  916. void
  917. DbgRpc1394Transport::ResetParameters(void)
  918. {
  919. m_AcceptChannel = 0;
  920. m_StreamChannel = 0;
  921. m_Handle = NULL;
  922. DbgRpcTransport::ResetParameters();
  923. }
  924. BOOL
  925. DbgRpc1394Transport::SetParameter(PCSTR Name, PCSTR Value)
  926. {
  927. if (!_stricmp(Name, "Channel"))
  928. {
  929. if (Value == NULL)
  930. {
  931. DbgRpcError("1394 parameters: "
  932. "the channel was not specified correctly\n");
  933. return FALSE;
  934. }
  935. m_AcceptChannel = atol(Value);
  936. }
  937. else
  938. {
  939. if (!DbgRpcTransport::SetParameter(Name, Value))
  940. {
  941. DbgRpcError("1394 parameters: %s is not a valid parameter\n",
  942. Name);
  943. return FALSE;
  944. }
  945. }
  946. return TRUE;
  947. }
  948. DbgRpcTransport*
  949. DbgRpc1394Transport::Clone(void)
  950. {
  951. DbgRpc1394Transport* Trans = new DbgRpc1394Transport;
  952. if (Trans != NULL)
  953. {
  954. DbgRpcTransport::CloneData(Trans);
  955. Trans->m_AcceptChannel = m_AcceptChannel;
  956. }
  957. return Trans;
  958. }
  959. HRESULT
  960. DbgRpc1394Transport::CreateServer(void)
  961. {
  962. char Name[64];
  963. m_StreamChannel = m_AcceptChannel;
  964. return Create1394Channel(m_AcceptChannel, Name, &m_Handle);
  965. }
  966. #define DBGRPC_1394_CONNECT '4931'
  967. struct DbgRpc1394Connect
  968. {
  969. ULONG Signature;
  970. ULONG Flags;
  971. ULONG StreamChannel;
  972. ULONG Reserved[5];
  973. };
  974. HRESULT
  975. DbgRpc1394Transport::AcceptConnection(DbgRpcTransport** ClientTrans,
  976. PSTR Identity)
  977. {
  978. DbgRpc1394Transport* Trans = new DbgRpc1394Transport;
  979. if (Trans == NULL)
  980. {
  981. return E_OUTOFMEMORY;
  982. }
  983. DbgRpcTransport::CloneData(Trans);
  984. DRPC(("%X: Waiting to accept connection on channel %d\n",
  985. GetCurrentThreadId(), m_AcceptChannel));
  986. DbgRpc1394Connect Conn, CheckConn;
  987. ULONG Done;
  988. ZeroMemory(&CheckConn, sizeof(CheckConn));
  989. CheckConn.Signature = DBGRPC_1394_CONNECT;
  990. if (!ReadFile(m_Handle, &Conn, sizeof(Conn), &Done, NULL) ||
  991. Done != sizeof(Conn))
  992. {
  993. DRPC(("%X: Accept failed, %d\n",
  994. GetCurrentThreadId(), GetLastError()));
  995. delete Trans;
  996. return WIN32_LAST_STATUS();
  997. }
  998. if (memcmp(&Conn, &CheckConn, sizeof(Conn)) != 0)
  999. {
  1000. DRPC(("%X: Accept information invalid\n",
  1001. GetCurrentThreadId()));
  1002. delete Trans;
  1003. return E_FAIL;
  1004. }
  1005. char StreamName[64];
  1006. HRESULT Status;
  1007. Conn.StreamChannel = m_StreamChannel + 1;
  1008. if ((Status = Open1394Channel(Conn.StreamChannel, StreamName,
  1009. &Trans->m_Handle)) != S_OK)
  1010. {
  1011. DRPC(("%X: Accept failed, 0x%X\n",
  1012. GetCurrentThreadId(), Status));
  1013. delete Trans;
  1014. return Status;
  1015. }
  1016. if (!WriteFile(m_Handle, &Conn, sizeof(Conn), &Done, NULL) ||
  1017. Done != sizeof(Conn))
  1018. {
  1019. DRPC(("%X: Accept failed, %d\n",
  1020. GetCurrentThreadId(), GetLastError()));
  1021. delete Trans;
  1022. return WIN32_LAST_STATUS();
  1023. }
  1024. Trans->m_AcceptChannel = m_AcceptChannel;
  1025. Trans->m_StreamChannel = Conn.StreamChannel;
  1026. m_StreamChannel++;
  1027. DRPC(("%X: Accept connection on channel %d, route to channel %d\n",
  1028. GetCurrentThreadId(), m_AcceptChannel, Conn.StreamChannel));
  1029. *ClientTrans = Trans;
  1030. _snprintf(Identity, DBGRPC_MAX_IDENTITY, "1394 %d", m_AcceptChannel);
  1031. Identity[DBGRPC_MAX_IDENTITY - 1] = 0;
  1032. return S_OK;
  1033. }
  1034. HRESULT
  1035. DbgRpc1394Transport::ConnectServer(void)
  1036. {
  1037. char Name[64];
  1038. HRESULT Status;
  1039. HANDLE Handle;
  1040. ULONG Done;
  1041. if ((Status = Create1394Channel(m_AcceptChannel, Name, &Handle)) != S_OK)
  1042. {
  1043. return Status;
  1044. }
  1045. DbgRpc1394Connect Conn, CheckConn;
  1046. ZeroMemory(&Conn, sizeof(Conn));
  1047. Conn.Signature = DBGRPC_1394_CONNECT;
  1048. CheckConn = Conn;
  1049. if (!WriteFile(Handle, &Conn, sizeof(Conn), &Done, NULL) ||
  1050. Done != sizeof(Conn))
  1051. {
  1052. CloseHandle(Handle);
  1053. return WIN32_LAST_STATUS();
  1054. }
  1055. if (!ReadFile(Handle, &Conn, sizeof(Conn), &Done, NULL) ||
  1056. Done != sizeof(Conn))
  1057. {
  1058. CloseHandle(Handle);
  1059. return WIN32_LAST_STATUS();
  1060. }
  1061. CloseHandle(Handle);
  1062. CheckConn.StreamChannel = Conn.StreamChannel;
  1063. if (memcmp(&Conn, &CheckConn, sizeof(Conn)) != 0)
  1064. {
  1065. return E_FAIL;
  1066. }
  1067. if ((Status = Open1394Channel(Conn.StreamChannel, Name,
  1068. &m_Handle)) != S_OK)
  1069. {
  1070. return Status;
  1071. }
  1072. m_StreamChannel = Conn.StreamChannel;
  1073. DRPC(("%X: Connect on channel %d, route to channel %d\n",
  1074. GetCurrentThreadId(), m_AcceptChannel, m_StreamChannel));
  1075. return S_OK;
  1076. }
  1077. ULONG
  1078. DbgRpc1394Transport::Read(ULONG Seq, PVOID Buffer, ULONG Len)
  1079. {
  1080. ULONG Done = 0;
  1081. ULONG Ret;
  1082. while (Len > 0)
  1083. {
  1084. if (!ReadFile(m_Handle, Buffer, Len, &Ret, NULL))
  1085. {
  1086. break;
  1087. }
  1088. Buffer = (PVOID)((PUCHAR)Buffer + Ret);
  1089. Len -= Ret;
  1090. Done += Ret;
  1091. }
  1092. return Done;
  1093. }
  1094. ULONG
  1095. DbgRpc1394Transport::Write(ULONG Seq, PVOID Buffer, ULONG Len)
  1096. {
  1097. ULONG Done = 0;
  1098. ULONG Ret;
  1099. while (Len > 0)
  1100. {
  1101. if (!WriteFile(m_Handle, Buffer, Len, &Ret, NULL))
  1102. {
  1103. break;
  1104. }
  1105. Buffer = (PVOID)((PUCHAR)Buffer + Ret);
  1106. Len -= Ret;
  1107. Done += Ret;
  1108. }
  1109. return Done;
  1110. }
  1111. //----------------------------------------------------------------------------
  1112. //
  1113. // DbgRpcComTransport.
  1114. //
  1115. //----------------------------------------------------------------------------
  1116. DbgRpcComTransport::~DbgRpcComTransport(void)
  1117. {
  1118. if (m_Handle != NULL)
  1119. {
  1120. CloseHandle(m_Handle);
  1121. }
  1122. if (m_ReadOlap.hEvent != NULL)
  1123. {
  1124. CloseHandle(m_ReadOlap.hEvent);
  1125. }
  1126. if (m_WriteOlap.hEvent != NULL)
  1127. {
  1128. CloseHandle(m_WriteOlap.hEvent);
  1129. }
  1130. }
  1131. ULONG
  1132. DbgRpcComTransport::GetNumberParameters(void)
  1133. {
  1134. return 3 + DbgRpcTransport::GetNumberParameters();
  1135. }
  1136. void
  1137. DbgRpcComTransport::GetParameter(ULONG Index, PSTR Name, PSTR Value)
  1138. {
  1139. switch(Index)
  1140. {
  1141. case 0:
  1142. if (m_PortName[0])
  1143. {
  1144. strcpy(Name, "Port");
  1145. strcpy(Value, m_PortName);
  1146. }
  1147. break;
  1148. case 1:
  1149. if (m_BaudRate)
  1150. {
  1151. strcpy(Name, "Baud");
  1152. sprintf(Value, "%d", m_BaudRate);
  1153. }
  1154. break;
  1155. case 2:
  1156. if (m_AcceptChannel)
  1157. {
  1158. strcpy(Name, "Channel");
  1159. sprintf(Value, "%d", m_AcceptChannel);
  1160. }
  1161. break;
  1162. default:
  1163. DbgRpcTransport::GetParameter(Index - 1, Name, Value);
  1164. break;
  1165. }
  1166. }
  1167. void
  1168. DbgRpcComTransport::ResetParameters(void)
  1169. {
  1170. m_PortName[0] = 0;
  1171. m_BaudRate = 0;
  1172. m_AcceptChannel = 0;
  1173. m_StreamChannel = 0;
  1174. m_Handle = NULL;
  1175. DbgRpcTransport::ResetParameters();
  1176. }
  1177. BOOL
  1178. DbgRpcComTransport::SetParameter(PCSTR Name, PCSTR Value)
  1179. {
  1180. if (!_stricmp(Name, "Port"))
  1181. {
  1182. if (Value == NULL)
  1183. {
  1184. DbgRpcError("COM parameters: "
  1185. "the port was not specified correctly\n");
  1186. return FALSE;
  1187. }
  1188. SetComPortName(Value, m_PortName);
  1189. }
  1190. else if (!_stricmp(Name, "Baud"))
  1191. {
  1192. if (Value == NULL)
  1193. {
  1194. DbgRpcError("COM parameters: "
  1195. "the baud rate was not specified correctly\n");
  1196. return FALSE;
  1197. }
  1198. m_BaudRate = atol(Value);
  1199. }
  1200. else if (!_stricmp(Name, "Channel"))
  1201. {
  1202. ULONG ValChan;
  1203. if (Value == NULL ||
  1204. (ValChan = atol(Value)) > 0xfe)
  1205. {
  1206. DbgRpcError("COM parameters: "
  1207. "the channel was not specified correctly\n");
  1208. return FALSE;
  1209. }
  1210. m_AcceptChannel = (UCHAR)ValChan;
  1211. }
  1212. else
  1213. {
  1214. if (!DbgRpcTransport::SetParameter(Name, Value))
  1215. {
  1216. DbgRpcError("COM parameters: %s is not a valid parameter\n", Name);
  1217. return FALSE;
  1218. }
  1219. }
  1220. return TRUE;
  1221. }
  1222. DbgRpcTransport*
  1223. DbgRpcComTransport::Clone(void)
  1224. {
  1225. DbgRpcComTransport* Trans = new DbgRpcComTransport;
  1226. if (Trans != NULL)
  1227. {
  1228. DbgRpcTransport::CloneData(Trans);
  1229. strcpy(Trans->m_PortName, m_PortName);
  1230. Trans->m_BaudRate = m_BaudRate;
  1231. Trans->m_AcceptChannel = m_AcceptChannel;
  1232. // The serial port can only be opened once so
  1233. // just dup the handle for the new transport.
  1234. if (!DuplicateHandle(GetCurrentProcess(), m_Handle,
  1235. GetCurrentProcess(), &Trans->m_Handle,
  1236. 0, FALSE, DUPLICATE_SAME_ACCESS))
  1237. {
  1238. delete Trans;
  1239. Trans = NULL;
  1240. }
  1241. }
  1242. return Trans;
  1243. }
  1244. HRESULT
  1245. DbgRpcComTransport::CreateServer(void)
  1246. {
  1247. HRESULT Status;
  1248. if ((Status = InitializeChannels()) != S_OK)
  1249. {
  1250. return Status;
  1251. }
  1252. if ((Status = CreateOverlappedPair(&m_ReadOlap, &m_WriteOlap)) != S_OK)
  1253. {
  1254. return Status;
  1255. }
  1256. m_StreamChannel = m_AcceptChannel;
  1257. return OpenComPort(m_PortName, m_BaudRate, 0, &m_Handle, &m_BaudRate);
  1258. }
  1259. #define DBGRPC_COM_CONNECT 'mCrD'
  1260. struct DbgRpcComConnect
  1261. {
  1262. ULONG Signature;
  1263. ULONG Flags;
  1264. ULONG StreamChannel;
  1265. ULONG Reserved[5];
  1266. };
  1267. HRESULT
  1268. DbgRpcComTransport::AcceptConnection(DbgRpcTransport** ClientTrans,
  1269. PSTR Identity)
  1270. {
  1271. // Check for channel number overflow.
  1272. if (m_StreamChannel == 0xff)
  1273. {
  1274. return E_OUTOFMEMORY;
  1275. }
  1276. DbgRpcComTransport* Trans = new DbgRpcComTransport;
  1277. if (Trans == NULL)
  1278. {
  1279. return E_OUTOFMEMORY;
  1280. }
  1281. DbgRpcTransport::CloneData(Trans);
  1282. DRPC(("%X: Waiting to accept connection on port %s baud %d channel %d\n",
  1283. GetCurrentThreadId(), m_PortName, m_BaudRate, m_AcceptChannel));
  1284. DbgRpcComConnect Conn, CheckConn;
  1285. ZeroMemory(&CheckConn, sizeof(CheckConn));
  1286. CheckConn.Signature = DBGRPC_COM_CONNECT;
  1287. if (ChanRead(m_AcceptChannel, &Conn, sizeof(Conn)) != sizeof(Conn))
  1288. {
  1289. DRPC(("%X: Accept failed, %d\n",
  1290. GetCurrentThreadId(), GetLastError()));
  1291. delete Trans;
  1292. return WIN32_LAST_STATUS();
  1293. }
  1294. if (memcmp(&Conn, &CheckConn, sizeof(Conn)) != 0)
  1295. {
  1296. DRPC(("%X: Accept information invalid\n",
  1297. GetCurrentThreadId()));
  1298. delete Trans;
  1299. return E_FAIL;
  1300. }
  1301. Conn.StreamChannel = m_StreamChannel + 1;
  1302. if (ChanWrite(m_AcceptChannel, &Conn, sizeof(Conn)) != sizeof(Conn))
  1303. {
  1304. DRPC(("%X: Accept failed, %d\n",
  1305. GetCurrentThreadId(), GetLastError()));
  1306. delete Trans;
  1307. return WIN32_LAST_STATUS();
  1308. }
  1309. // Duplicate the handle so that every transport instance
  1310. // has its own to close.
  1311. if (!DuplicateHandle(GetCurrentProcess(), m_Handle,
  1312. GetCurrentProcess(), &Trans->m_Handle,
  1313. 0, FALSE, DUPLICATE_SAME_ACCESS))
  1314. {
  1315. DRPC(("%X: Accept failed, %d\n",
  1316. GetCurrentThreadId(), GetLastError()));
  1317. delete Trans;
  1318. return WIN32_LAST_STATUS();
  1319. }
  1320. HRESULT Status;
  1321. if ((Status = CreateOverlappedPair(&Trans->m_ReadOlap,
  1322. &Trans->m_WriteOlap)) != S_OK)
  1323. {
  1324. DRPC(("%X: Accept failed, 0x%X\n",
  1325. GetCurrentThreadId(), Status));
  1326. delete Trans;
  1327. return Status;
  1328. }
  1329. strcpy(Trans->m_PortName, m_PortName);
  1330. Trans->m_BaudRate = m_BaudRate;
  1331. Trans->m_AcceptChannel = m_AcceptChannel;
  1332. Trans->m_StreamChannel = (UCHAR)Conn.StreamChannel;
  1333. m_StreamChannel++;
  1334. DRPC(("%X: Accept connection on channel %d, route to channel %d\n",
  1335. GetCurrentThreadId(), m_AcceptChannel, Conn.StreamChannel));
  1336. *ClientTrans = Trans;
  1337. _snprintf(Identity, DBGRPC_MAX_IDENTITY, "COM %s@%d chan %d",
  1338. m_PortName, m_BaudRate, m_AcceptChannel);
  1339. Identity[DBGRPC_MAX_IDENTITY - 1] = 0;
  1340. return S_OK;
  1341. }
  1342. HRESULT
  1343. DbgRpcComTransport::ConnectServer(void)
  1344. {
  1345. HRESULT Status;
  1346. if ((Status = InitializeChannels()) != S_OK)
  1347. {
  1348. return Status;
  1349. }
  1350. if ((Status = CreateOverlappedPair(&m_ReadOlap, &m_WriteOlap)) != S_OK)
  1351. {
  1352. return Status;
  1353. }
  1354. // If this is a clone it'll already have a handle.
  1355. // Otherwise this is the first connecting transport
  1356. // so it needs to really open the COM port.
  1357. if (m_Handle == NULL)
  1358. {
  1359. if ((Status = OpenComPort(m_PortName, m_BaudRate, 0,
  1360. &m_Handle, &m_BaudRate)) != S_OK)
  1361. {
  1362. return Status;
  1363. }
  1364. }
  1365. DbgRpcComConnect Conn, CheckConn;
  1366. ZeroMemory(&Conn, sizeof(Conn));
  1367. Conn.Signature = DBGRPC_COM_CONNECT;
  1368. CheckConn = Conn;
  1369. if (ChanWrite(m_AcceptChannel, &Conn, sizeof(Conn)) != sizeof(Conn))
  1370. {
  1371. CloseHandle(m_Handle);
  1372. m_Handle = NULL;
  1373. return WIN32_LAST_STATUS();
  1374. }
  1375. if (ChanRead(m_AcceptChannel, &Conn, sizeof(Conn)) != sizeof(Conn))
  1376. {
  1377. CloseHandle(m_Handle);
  1378. m_Handle = NULL;
  1379. return WIN32_LAST_STATUS();
  1380. }
  1381. CheckConn.StreamChannel = Conn.StreamChannel;
  1382. if (memcmp(&Conn, &CheckConn, sizeof(Conn)) != 0)
  1383. {
  1384. CloseHandle(m_Handle);
  1385. m_Handle = NULL;
  1386. return E_FAIL;
  1387. }
  1388. m_StreamChannel = (UCHAR)Conn.StreamChannel;
  1389. DRPC(("%X: Connect on channel %d, route to channel %d\n",
  1390. GetCurrentThreadId(), m_AcceptChannel, m_StreamChannel));
  1391. return S_OK;
  1392. }
  1393. #if 0
  1394. #define DCOM(Args) g_NtDllCalls.DbgPrint Args
  1395. #else
  1396. #define DCOM(Args)
  1397. #endif
  1398. #define DBGRPC_COM_FAILURE 0xffff
  1399. #define DBGRPC_COM_HEAD_SIG 0xdc
  1400. #define DBGRPC_COM_TAIL_SIG 0xcd
  1401. // In order to avoid overflowing the serial port when
  1402. // used at boot time, restrict the maximum size of
  1403. // a single chunk of data written. This must be
  1404. // less than 0xffff.
  1405. #ifdef NT_NATIVE
  1406. #define DBGRPC_COM_MAX_CHUNK (16 - sizeof(DbgRpcComStream))
  1407. #else
  1408. #define DBGRPC_COM_MAX_CHUNK 0xfffe
  1409. #endif
  1410. struct DbgRpcComStream
  1411. {
  1412. UCHAR Signature;
  1413. UCHAR Channel;
  1414. USHORT Len;
  1415. };
  1416. struct DbgRpcComQueue
  1417. {
  1418. DbgRpcComQueue* Next;
  1419. PUCHAR Data;
  1420. UCHAR Channel;
  1421. USHORT Len;
  1422. };
  1423. BOOL DbgRpcComTransport::s_ChanInitialized;
  1424. CRITICAL_SECTION DbgRpcComTransport::s_QueueLock;
  1425. HANDLE DbgRpcComTransport::s_QueueChangedEvent;
  1426. LONG DbgRpcComTransport::s_PortReadOwned;
  1427. CRITICAL_SECTION DbgRpcComTransport::s_PortWriteLock;
  1428. CRITICAL_SECTION DbgRpcComTransport::s_WriteAckLock;
  1429. HANDLE DbgRpcComTransport::s_WriteAckEvent;
  1430. DbgRpcComQueue* DbgRpcComTransport::s_QueueHead;
  1431. DbgRpcComQueue* DbgRpcComTransport::s_QueueTail;
  1432. ULONG
  1433. DbgRpcComTransport::Read(ULONG Seq, PVOID Buffer, ULONG Len)
  1434. {
  1435. ULONG Done = 0;
  1436. while (Len > 0)
  1437. {
  1438. USHORT Chunk = (USHORT)min(Len, DBGRPC_COM_MAX_CHUNK);
  1439. USHORT ChunkDone = ChanRead(m_StreamChannel, Buffer, Chunk);
  1440. Done += ChunkDone;
  1441. Buffer = (PUCHAR)Buffer + ChunkDone;
  1442. Len -= ChunkDone;
  1443. if (ChunkDone < Chunk)
  1444. {
  1445. break;
  1446. }
  1447. }
  1448. return Done;
  1449. }
  1450. ULONG
  1451. DbgRpcComTransport::Write(ULONG Seq, PVOID Buffer, ULONG Len)
  1452. {
  1453. ULONG Done = 0;
  1454. while (Len > 0)
  1455. {
  1456. USHORT Chunk = (USHORT)min(Len, DBGRPC_COM_MAX_CHUNK);
  1457. USHORT ChunkDone = ChanWrite(m_StreamChannel, Buffer, Chunk);
  1458. Done += ChunkDone;
  1459. Buffer = (PUCHAR)Buffer + ChunkDone;
  1460. Len -= ChunkDone;
  1461. if (ChunkDone < Chunk)
  1462. {
  1463. break;
  1464. }
  1465. }
  1466. return Done;
  1467. }
  1468. USHORT
  1469. DbgRpcComTransport::ScanQueue(UCHAR Chan, PVOID Buffer, USHORT Len)
  1470. {
  1471. USHORT Done = 0;
  1472. EnterCriticalSection(&s_QueueLock);
  1473. DbgRpcComQueue* Ent;
  1474. DbgRpcComQueue* Next;
  1475. DbgRpcComQueue* Prev;
  1476. Prev = NULL;
  1477. for (Ent = s_QueueHead; Ent != NULL && Len > 0; Ent = Next)
  1478. {
  1479. Next = Ent->Next;
  1480. DCOM(("%03X: Queue entry %p->%p %d,%d\n",
  1481. GetCurrentThreadId(),
  1482. Ent, Next, Ent->Channel, Ent->Len));
  1483. if (Ent->Channel == Chan)
  1484. {
  1485. // Found some input for this channel.
  1486. if (Len < Ent->Len)
  1487. {
  1488. DCOM(("%03X: Eat %d, leave %d\n",
  1489. GetCurrentThreadId(), Len, Ent->Len - Len));
  1490. memcpy(Buffer, Ent->Data, Len);
  1491. Ent->Data += Len;
  1492. Ent->Len -= Len;
  1493. Done += Len;
  1494. Len = 0;
  1495. }
  1496. else
  1497. {
  1498. DCOM(("%03X: Eat all %d\n",
  1499. GetCurrentThreadId(), Len));
  1500. memcpy(Buffer, Ent->Data, Ent->Len);
  1501. Buffer = (PVOID)((PUCHAR)Buffer + Ent->Len);
  1502. Done += Ent->Len;
  1503. Len -= Ent->Len;
  1504. // Remove used-up entry from list.
  1505. if (Prev == NULL)
  1506. {
  1507. s_QueueHead = Ent->Next;
  1508. }
  1509. else
  1510. {
  1511. Prev->Next = Ent->Next;
  1512. }
  1513. if (s_QueueTail == Ent)
  1514. {
  1515. s_QueueTail = Prev;
  1516. }
  1517. free(Ent);
  1518. continue;
  1519. }
  1520. }
  1521. Prev = Ent;
  1522. }
  1523. LeaveCriticalSection(&s_QueueLock);
  1524. return Done;
  1525. }
  1526. USHORT
  1527. DbgRpcComTransport::ScanPort(UCHAR Chan, PVOID Buffer, USHORT Len,
  1528. BOOL ScanForAck, UCHAR AckChan)
  1529. {
  1530. DbgRpcComStream Stream;
  1531. ULONG ReadDone;
  1532. USHORT Ret = 0;
  1533. if (ScanForAck)
  1534. {
  1535. DCOM(("%03X: Waiting to read header (ack chan %d)\n",
  1536. GetCurrentThreadId(), AckChan));
  1537. }
  1538. else
  1539. {
  1540. DCOM(("%03X: Waiting to read header\n",
  1541. GetCurrentThreadId()));
  1542. }
  1543. Rescan:
  1544. for (;;)
  1545. {
  1546. if (!ComPortRead(m_Handle, &Stream, sizeof(Stream), &ReadDone,
  1547. &m_ReadOlap) ||
  1548. ReadDone != sizeof(Stream))
  1549. {
  1550. return DBGRPC_COM_FAILURE;
  1551. }
  1552. // If a write ack came through release the waiting writer.
  1553. if (Stream.Signature == DBGRPC_COM_TAIL_SIG &&
  1554. Stream.Len == DBGRPC_COM_FAILURE)
  1555. {
  1556. DCOM(("%03X: Read write ack for chan %d\n",
  1557. GetCurrentThreadId(), Stream.Channel));
  1558. if (ScanForAck)
  1559. {
  1560. if (AckChan == Stream.Channel)
  1561. {
  1562. return (USHORT)ReadDone;
  1563. }
  1564. else
  1565. {
  1566. DCOM(("%03X: Read mismatched write ack, "
  1567. "read chan %d waiting for chan %d\n",
  1568. GetCurrentThreadId(), Stream.Channel, AckChan));
  1569. return DBGRPC_COM_FAILURE;
  1570. }
  1571. }
  1572. SetEvent(s_WriteAckEvent);
  1573. }
  1574. else if (Stream.Signature != DBGRPC_COM_HEAD_SIG ||
  1575. Stream.Len == DBGRPC_COM_FAILURE)
  1576. {
  1577. return DBGRPC_COM_FAILURE;
  1578. }
  1579. else
  1580. {
  1581. break;
  1582. }
  1583. }
  1584. DCOM(("%03X: Read %d,%d\n",
  1585. GetCurrentThreadId(), Stream.Channel, Stream.Len));
  1586. // If the data available is for this channel
  1587. // read it directly into the buffer.
  1588. if (!ScanForAck && Stream.Channel == Chan)
  1589. {
  1590. Ret = min(Stream.Len, Len);
  1591. DCOM(("%03X: Read direct body %d\n",
  1592. GetCurrentThreadId(), Ret));
  1593. if (!ComPortRead(m_Handle, Buffer, Ret, &ReadDone, &m_ReadOlap) ||
  1594. ReadDone != Ret)
  1595. {
  1596. return DBGRPC_COM_FAILURE;
  1597. }
  1598. Stream.Len -= Ret;
  1599. }
  1600. // If the data is for another channel or there's
  1601. // more than we need queue the remainder for
  1602. // later use.
  1603. if (Stream.Len > 0)
  1604. {
  1605. DbgRpcComQueue* Ent =
  1606. (DbgRpcComQueue*)malloc(sizeof(*Ent) + Stream.Len);
  1607. if (Ent == NULL)
  1608. {
  1609. return DBGRPC_COM_FAILURE;
  1610. }
  1611. Ent->Next = NULL;
  1612. Ent->Channel = Stream.Channel;
  1613. Ent->Len = Stream.Len;
  1614. Ent->Data = (PUCHAR)Ent + sizeof(*Ent);
  1615. DCOM(("%03X: Read queue body %d\n",
  1616. GetCurrentThreadId(), Ent->Len));
  1617. if (!ComPortRead(m_Handle, Ent->Data, Ent->Len, &ReadDone,
  1618. &m_ReadOlap) ||
  1619. ReadDone != Ent->Len)
  1620. {
  1621. free(Ent);
  1622. return DBGRPC_COM_FAILURE;
  1623. }
  1624. DCOM(("%03X: Queue add %p %d,%d\n",
  1625. GetCurrentThreadId(), Ent, Ent->Channel, Ent->Len));
  1626. EnterCriticalSection(&s_QueueLock);
  1627. if (s_QueueHead == NULL)
  1628. {
  1629. s_QueueHead = Ent;
  1630. }
  1631. else
  1632. {
  1633. s_QueueTail->Next = Ent;
  1634. }
  1635. s_QueueTail = Ent;
  1636. LeaveCriticalSection(&s_QueueLock);
  1637. }
  1638. //
  1639. // Acknowledge full receipt of the data.
  1640. //
  1641. Stream.Signature = DBGRPC_COM_TAIL_SIG;
  1642. Stream.Channel = Stream.Channel;
  1643. Stream.Len = DBGRPC_COM_FAILURE;
  1644. EnterCriticalSection(&s_PortWriteLock);
  1645. if (!ComPortWrite(m_Handle, &Stream, sizeof(Stream),
  1646. &ReadDone, &m_ReadOlap))
  1647. {
  1648. ReadDone = 0;
  1649. }
  1650. else
  1651. {
  1652. DCOM(("%03X: Wrote write ack for chan %d\n",
  1653. GetCurrentThreadId(), Stream.Channel));
  1654. }
  1655. LeaveCriticalSection(&s_PortWriteLock);
  1656. if (ReadDone != sizeof(Stream))
  1657. {
  1658. return DBGRPC_COM_FAILURE;
  1659. }
  1660. // Don't exit if we're waiting for an ack as
  1661. // we haven't received it yet.
  1662. if (ScanForAck)
  1663. {
  1664. SetEvent(s_QueueChangedEvent);
  1665. goto Rescan;
  1666. }
  1667. return Ret;
  1668. }
  1669. USHORT
  1670. DbgRpcComTransport::ChanRead(UCHAR Chan, PVOID Buffer, USHORT InLen)
  1671. {
  1672. USHORT Done = 0;
  1673. USHORT Len = InLen;
  1674. // The virtual channels require that all reads and writes
  1675. // be complete. A partial read or write will not match
  1676. // its channel header and will throw everything off.
  1677. DCOM(("%03X:ChanRead %d,%d\n",
  1678. GetCurrentThreadId(), Chan, Len));
  1679. while (Len > 0)
  1680. {
  1681. USHORT Queued;
  1682. // First check and see if input for this channel
  1683. // is already present in the queue.
  1684. Queued = ScanQueue(Chan, Buffer, Len);
  1685. Done += Queued;
  1686. Buffer = (PVOID)((PUCHAR)Buffer + Queued);
  1687. Len -= Queued;
  1688. if (Queued > 0)
  1689. {
  1690. DCOM(("%03X: Scan pass 1 gets %d from queue\n",
  1691. GetCurrentThreadId(), Queued));
  1692. }
  1693. if (Len == 0)
  1694. {
  1695. break;
  1696. }
  1697. //
  1698. // There wasn't enough queued input so try and
  1699. // read some more from the port.
  1700. //
  1701. if (InterlockedExchange(&s_PortReadOwned, TRUE) == TRUE)
  1702. {
  1703. // Somebody else owns the port so we can't
  1704. // read it. Just wait for the queue to change
  1705. // so we can check for data again.
  1706. // Set things to wait.
  1707. ResetEvent(s_QueueChangedEvent);
  1708. // There's a chance that the queue changed just before
  1709. // the event was reset and therefore that event set
  1710. // has been lost. Time out of this wait to ensure
  1711. // that nothing ever gets hung up indefinitely here.
  1712. if (WaitForSingleObject(s_QueueChangedEvent, 250) ==
  1713. WAIT_FAILED)
  1714. {
  1715. DCOM(("%03X: Change wait failed\n",
  1716. GetCurrentThreadId()));
  1717. return 0;
  1718. }
  1719. continue;
  1720. }
  1721. // We now own the port. The queue may have changed
  1722. // during the time we were acquiring ownership, though,
  1723. // so check it again.
  1724. Queued = ScanQueue(Chan, Buffer, Len);
  1725. Done += Queued;
  1726. Buffer = (PVOID)((PUCHAR)Buffer + Queued);
  1727. Len -= Queued;
  1728. if (Queued > 0)
  1729. {
  1730. DCOM(("%03X: Scan pass 2 gets %d from queue\n",
  1731. GetCurrentThreadId(), Queued));
  1732. }
  1733. if (Len > 0)
  1734. {
  1735. // Still need more input and we're now the
  1736. // owner of the port, so read.
  1737. USHORT Port = ScanPort(Chan, Buffer, Len, FALSE, 0);
  1738. if (Port == DBGRPC_COM_FAILURE)
  1739. {
  1740. // Critical error, fail immediately.
  1741. InterlockedExchange(&s_PortReadOwned, FALSE);
  1742. SetEvent(s_QueueChangedEvent);
  1743. DCOM(("%03X: Critical failure\n",
  1744. GetCurrentThreadId()));
  1745. return 0;
  1746. }
  1747. Done += Port;
  1748. Buffer = (PVOID)((PUCHAR)Buffer + Port);
  1749. Len -= Port;
  1750. if (Port > 0)
  1751. {
  1752. DCOM(("%03X: Scan %d from port\n",
  1753. GetCurrentThreadId(), Port));
  1754. }
  1755. }
  1756. InterlockedExchange(&s_PortReadOwned, FALSE);
  1757. SetEvent(s_QueueChangedEvent);
  1758. }
  1759. DCOM(("%03X: ChanRead %d,%d returns %d\n",
  1760. GetCurrentThreadId(), Chan, InLen, Done));
  1761. return Done;
  1762. }
  1763. USHORT
  1764. DbgRpcComTransport::ChanWrite(UCHAR Chan, PVOID Buffer, USHORT InLen)
  1765. {
  1766. USHORT Len = InLen;
  1767. DCOM(("%03X:ChanWrite %d,%d\n",
  1768. GetCurrentThreadId(), Chan, Len));
  1769. ULONG Done;
  1770. DbgRpcComStream Stream;
  1771. // The virtual channels require that all reads and writes
  1772. // be complete. A partial read or write will not match
  1773. // its channel header and will throw everything off.
  1774. Stream.Signature = DBGRPC_COM_HEAD_SIG;
  1775. Stream.Channel = Chan;
  1776. Stream.Len = Len;
  1777. // The write ack lock restricts things to a single
  1778. // unacknowledged write. The port write lock
  1779. // ensures that the multiple pieces of a write
  1780. // are sequential in the stream.
  1781. EnterCriticalSection(&s_WriteAckLock);
  1782. EnterCriticalSection(&s_PortWriteLock);
  1783. if (!ComPortWrite(m_Handle, &Stream, sizeof(Stream), &Done,
  1784. &m_WriteOlap) ||
  1785. Done != sizeof(Stream) ||
  1786. !ComPortWrite(m_Handle, Buffer, Len, &Done, &m_WriteOlap) ||
  1787. Done != Len)
  1788. {
  1789. Done = 0;
  1790. }
  1791. LeaveCriticalSection(&s_PortWriteLock);
  1792. //
  1793. // Wait for data ack. This prevents too much data from
  1794. // being written to the serial port at once by limiting
  1795. // the amount of outstanding data to a single chunk's worth.
  1796. //
  1797. for (;;)
  1798. {
  1799. if (InterlockedExchange(&s_PortReadOwned, TRUE) == TRUE)
  1800. {
  1801. HANDLE Waits[2];
  1802. ULONG Wait;
  1803. // Somebody else owns the port so wait for their signal.
  1804. // Also wait for a port ownership change as we may
  1805. // need to switch to a direct port read.
  1806. Waits[0] = s_WriteAckEvent;
  1807. Waits[1] = s_QueueChangedEvent;
  1808. // Set things to wait.
  1809. ResetEvent(s_QueueChangedEvent);
  1810. Wait = WaitForMultipleObjects(2, Waits, FALSE, 250);
  1811. if (Wait == WAIT_OBJECT_0)
  1812. {
  1813. break;
  1814. }
  1815. else if (Wait == WAIT_FAILED)
  1816. {
  1817. DCOM(("%03X: Write ack wait failed, %d\n",
  1818. GetCurrentThreadId(), GetLastError()));
  1819. Done = 0;
  1820. break;
  1821. }
  1822. }
  1823. else
  1824. {
  1825. USHORT AckDone;
  1826. // We now own the port so directly read the ack.
  1827. // However, before we do we need to make one last
  1828. // check and see if somebody else read our ack
  1829. // in the time leading up to us acquiring port
  1830. // ownership.
  1831. if (WaitForSingleObject(s_WriteAckEvent, 0) != WAIT_OBJECT_0)
  1832. {
  1833. AckDone = ScanPort(Chan, &Stream, sizeof(Stream),
  1834. TRUE, Chan);
  1835. if (AckDone == DBGRPC_COM_FAILURE)
  1836. {
  1837. DCOM(("%03X: Failed scan for write ack\n",
  1838. GetCurrentThreadId()));
  1839. Done = 0;
  1840. }
  1841. }
  1842. InterlockedExchange(&s_PortReadOwned, FALSE);
  1843. SetEvent(s_QueueChangedEvent);
  1844. break;
  1845. }
  1846. }
  1847. LeaveCriticalSection(&s_WriteAckLock);
  1848. DCOM(("%03X: ChanWrite %d,%d returns %d\n",
  1849. GetCurrentThreadId(), Chan, InLen, Done));
  1850. return (USHORT)Done;
  1851. }
  1852. HRESULT
  1853. DbgRpcComTransport::InitializeChannels(void)
  1854. {
  1855. if (s_ChanInitialized)
  1856. {
  1857. return S_OK;
  1858. }
  1859. if ((s_QueueChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
  1860. {
  1861. return WIN32_LAST_STATUS();
  1862. }
  1863. if ((s_WriteAckEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  1864. {
  1865. return WIN32_LAST_STATUS();
  1866. }
  1867. __try
  1868. {
  1869. InitializeCriticalSection(&s_QueueLock);
  1870. InitializeCriticalSection(&s_PortWriteLock);
  1871. InitializeCriticalSection(&s_WriteAckLock);
  1872. }
  1873. __except(EXCEPTION_EXECUTE_HANDLER)
  1874. {
  1875. return E_OUTOFMEMORY;
  1876. }
  1877. s_ChanInitialized = TRUE;
  1878. return S_OK;
  1879. }
  1880. //----------------------------------------------------------------------------
  1881. //
  1882. // Transport functions.
  1883. //
  1884. //----------------------------------------------------------------------------
  1885. DbgRpcTransport*
  1886. DbgRpcNewTransport(ULONG Trans)
  1887. {
  1888. switch(Trans)
  1889. {
  1890. #ifndef NT_NATIVE
  1891. case TRANS_TCP:
  1892. return new DbgRpcTcpTransport;
  1893. case TRANS_SSL:
  1894. return new DbgRpcSecureChannelTransport(Trans, TRANS_TCP);
  1895. case TRANS_SPIPE:
  1896. return new DbgRpcSecureChannelTransport(Trans, TRANS_NPIPE);
  1897. #endif
  1898. case TRANS_NPIPE:
  1899. return new DbgRpcNamedPipeTransport;
  1900. case TRANS_1394:
  1901. return new DbgRpc1394Transport;
  1902. case TRANS_COM:
  1903. return new DbgRpcComTransport;
  1904. default:
  1905. return NULL;
  1906. }
  1907. }
  1908. DbgRpcTransport*
  1909. DbgRpcCreateTransport(PCSTR Options)
  1910. {
  1911. ULONG Trans = ParameterStringParser::
  1912. GetParser(Options, TRANS_COUNT, g_DbgRpcTransportNames);
  1913. return DbgRpcNewTransport(Trans);
  1914. }
  1915. DbgRpcTransport*
  1916. DbgRpcInitializeTransport(PCSTR Options)
  1917. {
  1918. DbgRpcTransport* Trans = DbgRpcCreateTransport(Options);
  1919. if (Trans != NULL)
  1920. {
  1921. // Clean out any old parameter state.
  1922. Trans->ResetParameters();
  1923. if (!Trans->ParseParameters(Options))
  1924. {
  1925. delete Trans;
  1926. return NULL;
  1927. }
  1928. }
  1929. return Trans;
  1930. }