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.

615 lines
16 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Non-network I/O support.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000-2002.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include "pch.hpp"
  9. #include <ws2tcpip.h>
  10. #ifndef _WIN32_WCE
  11. #include <kdbg1394.h>
  12. #include <ntdd1394.h>
  13. #endif
  14. //----------------------------------------------------------------------------
  15. //
  16. // COM.
  17. //
  18. //----------------------------------------------------------------------------
  19. HRESULT
  20. CreateOverlappedPair(LPOVERLAPPED Read, LPOVERLAPPED Write)
  21. {
  22. ZeroMemory(Read, sizeof(*Read));
  23. ZeroMemory(Write, sizeof(*Write));
  24. Read->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  25. if (Read->hEvent == NULL)
  26. {
  27. return WIN32_LAST_STATUS();
  28. }
  29. Write->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  30. if (Write->hEvent == NULL)
  31. {
  32. CloseHandle(Read->hEvent);
  33. return WIN32_LAST_STATUS();
  34. }
  35. return S_OK;
  36. }
  37. BOOL
  38. ComPortRead(HANDLE Port, COM_PORT_TYPE Type, ULONG Timeout,
  39. PVOID Buffer, ULONG Len, PULONG Done,
  40. LPOVERLAPPED Olap)
  41. {
  42. BOOL Status;
  43. if (Type == COM_PORT_SOCKET)
  44. {
  45. #if defined(NT_NATIVE) || defined(_WIN32_WCE)
  46. return FALSE;
  47. #else
  48. WSABUF Buf;
  49. DWORD Flags;
  50. // Handle timeouts first.
  51. if (Timeout != 0 && Timeout != INFINITE)
  52. {
  53. FD_SET FdSet;
  54. struct timeval TimeVal;
  55. FD_ZERO(&FdSet);
  56. FD_SET((SOCKET)Port, &FdSet);
  57. TimeVal.tv_sec = Timeout / 1000;
  58. TimeVal.tv_usec = (Timeout % 1000) * 1000;
  59. if (select(1, &FdSet, NULL, NULL, &TimeVal) < 1)
  60. {
  61. return FALSE;
  62. }
  63. }
  64. Buf.len = Len;
  65. Buf.buf = (PSTR)Buffer;
  66. Flags = 0;
  67. if (WSARecv((SOCKET)Port, &Buf, 1, Done, &Flags,
  68. (LPWSAOVERLAPPED)Olap, NULL) != SOCKET_ERROR)
  69. {
  70. return TRUE;
  71. }
  72. if (WSAGetLastError() != WSA_IO_PENDING)
  73. {
  74. return FALSE;
  75. }
  76. return WSAGetOverlappedResult((SOCKET)Port, (LPWSAOVERLAPPED)Olap,
  77. Done, Timeout > 0 ? TRUE : FALSE,
  78. &Flags);
  79. #endif // #if defined(NT_NATIVE) || defined(_WIN32_WCE)
  80. }
  81. Status = ReadFile(Port, Buffer, Len, Done, Olap);
  82. if (!Status)
  83. {
  84. if (GetLastError() == ERROR_IO_PENDING)
  85. {
  86. if (Type == COM_PORT_PIPE)
  87. {
  88. // We need to explicitly handle timeouts for
  89. // pipe reading. First we wait for the I/O to
  90. // complete. There's no need to check for
  91. // success or failure as I/O success will
  92. // be checked later.
  93. WaitForSingleObject(Olap->hEvent, Timeout);
  94. // Cancel any pending I/Os. If the I/O already
  95. // completed this won't do anything.
  96. CancelIo(Port);
  97. // Now query the resulting I/O status. If it was
  98. // cancelled this will return an error.
  99. Status = GetOverlappedResult(Port, Olap, Done, FALSE);
  100. }
  101. else
  102. {
  103. Status = GetOverlappedResult(Port, Olap, Done, TRUE);
  104. }
  105. }
  106. else if (Type != COM_PORT_PIPE)
  107. {
  108. DWORD TrashErr;
  109. COMSTAT TrashStat;
  110. // Device could be locked up. Clear it just in case.
  111. ClearCommError(Port, &TrashErr, &TrashStat);
  112. }
  113. }
  114. return Status;
  115. }
  116. BOOL
  117. ComPortWrite(HANDLE Port, COM_PORT_TYPE Type,
  118. PVOID Buffer, ULONG Len, PULONG Done,
  119. LPOVERLAPPED Olap)
  120. {
  121. BOOL Status;
  122. if (Type == COM_PORT_SOCKET)
  123. {
  124. #if defined(NT_NATIVE) || defined(_WIN32_WCE)
  125. return FALSE;
  126. #else
  127. WSABUF Buf;
  128. DWORD Flags;
  129. Buf.len = Len;
  130. Buf.buf = (PSTR)Buffer;
  131. if (WSASend((SOCKET)Port, &Buf, 1, Done, 0,
  132. (LPWSAOVERLAPPED)Olap, NULL) != SOCKET_ERROR)
  133. {
  134. return TRUE;
  135. }
  136. if (WSAGetLastError() != WSA_IO_PENDING)
  137. {
  138. return FALSE;
  139. }
  140. return WSAGetOverlappedResult((SOCKET)Port, (LPWSAOVERLAPPED)Olap,
  141. Done, TRUE, &Flags);
  142. #endif // #if defined(NT_NATIVE) || defined(_WIN32_WCE)
  143. }
  144. Status = WriteFile(Port, Buffer, Len, Done, Olap);
  145. if (!Status)
  146. {
  147. if (GetLastError() == ERROR_IO_PENDING)
  148. {
  149. Status = GetOverlappedResult(Port, Olap, Done, TRUE);
  150. }
  151. else if (Type != COM_PORT_PIPE)
  152. {
  153. DWORD TrashErr;
  154. COMSTAT TrashStat;
  155. // Device could be locked up. Clear it just in case.
  156. ClearCommError(Port, &TrashErr, &TrashStat);
  157. }
  158. }
  159. return Status;
  160. }
  161. BOOL
  162. SetComPortName(PCSTR Name, PSTR Buffer, ULONG BufferSize)
  163. {
  164. if (*Name == 'c' || *Name == 'C')
  165. {
  166. return
  167. CopyString(Buffer, "\\\\.\\", BufferSize) &&
  168. CatString(Buffer, Name, BufferSize);
  169. }
  170. else if (*Name >= '0' && *Name <= '9')
  171. {
  172. PCSTR Scan = Name + 1;
  173. while (*Scan >= '0' && *Scan <= '9')
  174. {
  175. Scan++;
  176. }
  177. if (*Scan == 0)
  178. {
  179. // The name was all digits so assume it's
  180. // a plain com port number.
  181. #ifndef NT_NATIVE
  182. if (!CopyString(Buffer, "\\\\.\\com", BufferSize))
  183. {
  184. return FALSE;
  185. }
  186. #else
  187. if (!CopyString(Buffer, "\\Device\\Serial", BufferSize))
  188. {
  189. return FALSE;
  190. }
  191. #endif
  192. return CatString(Buffer, Name, BufferSize);
  193. }
  194. else
  195. {
  196. return CopyString(Buffer, Name, BufferSize);
  197. }
  198. }
  199. else
  200. {
  201. return CopyString(Buffer, Name, BufferSize);
  202. }
  203. }
  204. ULONG
  205. SelectComPortBaud(ULONG NewRate)
  206. {
  207. #define NUM_RATES 4
  208. static DWORD s_Rates[NUM_RATES] = {19200, 38400, 57600, 115200};
  209. static DWORD s_CurRate = NUM_RATES;
  210. DWORD i;
  211. if (NewRate > 0)
  212. {
  213. for (i = 0; NewRate > s_Rates[i] && i < NUM_RATES - 1; i++)
  214. {
  215. // Empty.
  216. }
  217. s_CurRate = (NewRate < s_Rates[i]) ? i : i + 1;
  218. }
  219. else
  220. {
  221. s_CurRate++;
  222. }
  223. if (s_CurRate >= NUM_RATES)
  224. {
  225. s_CurRate = 0;
  226. }
  227. return s_Rates[s_CurRate];
  228. }
  229. HRESULT
  230. SetComPortBaud(HANDLE Port, ULONG NewRate, PULONG RateSet)
  231. {
  232. ULONG OldRate;
  233. DCB LocalDcb;
  234. if (Port == NULL)
  235. {
  236. return E_FAIL;
  237. }
  238. if (!GetCommState(Port, &LocalDcb))
  239. {
  240. return WIN32_LAST_STATUS();
  241. }
  242. OldRate = LocalDcb.BaudRate;
  243. if (!NewRate)
  244. {
  245. NewRate = SelectComPortBaud(OldRate);
  246. }
  247. LocalDcb.BaudRate = NewRate;
  248. LocalDcb.ByteSize = 8;
  249. LocalDcb.Parity = NOPARITY;
  250. LocalDcb.StopBits = ONESTOPBIT;
  251. LocalDcb.fDtrControl = DTR_CONTROL_ENABLE;
  252. LocalDcb.fRtsControl = RTS_CONTROL_ENABLE;
  253. LocalDcb.fBinary = TRUE;
  254. LocalDcb.fOutxCtsFlow = FALSE;
  255. LocalDcb.fOutxDsrFlow = FALSE;
  256. LocalDcb.fOutX = FALSE;
  257. LocalDcb.fInX = FALSE;
  258. if (!SetCommState(Port, &LocalDcb))
  259. {
  260. return WIN32_LAST_STATUS();
  261. }
  262. *RateSet = NewRate;
  263. return S_OK;
  264. }
  265. HRESULT
  266. OpenComPort(PCOM_PORT_PARAMS Params,
  267. PHANDLE Handle, PULONG BaudSet)
  268. {
  269. HRESULT Status;
  270. HANDLE ComHandle;
  271. if (Params->Type == COM_PORT_SOCKET)
  272. {
  273. #if defined(NT_NATIVE) || defined(_WIN32_WCE)
  274. return E_NOTIMPL;
  275. #else
  276. WSADATA WsData;
  277. SOCKET Sock;
  278. SOCKADDR_STORAGE Addr;
  279. int AddrLen;
  280. if (WSAStartup(MAKEWORD(2, 0), &WsData) != 0)
  281. {
  282. return E_FAIL;
  283. }
  284. if ((Status = InitIpAddress(Params->PortName, Params->IpPort,
  285. &Addr, &AddrLen)) != S_OK)
  286. {
  287. return Status;
  288. }
  289. Sock = WSASocket(Addr.ss_family, SOCK_STREAM, 0, NULL, 0,
  290. WSA_FLAG_OVERLAPPED);
  291. if (Sock == INVALID_SOCKET)
  292. {
  293. return E_FAIL;
  294. }
  295. if (connect(Sock, (struct sockaddr *)&Addr, AddrLen) == SOCKET_ERROR)
  296. {
  297. closesocket(Sock);
  298. return E_FAIL;
  299. }
  300. int On = TRUE;
  301. setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY,
  302. (PSTR)&On, sizeof(On));
  303. *Handle = (HANDLE)Sock;
  304. return S_OK;
  305. #endif // #if defined(NT_NATIVE) || defined(_WIN32_WCE)
  306. }
  307. #ifndef NT_NATIVE
  308. ComHandle = CreateFile(Params->PortName,
  309. GENERIC_READ | GENERIC_WRITE,
  310. 0,
  311. NULL,
  312. OPEN_ALWAYS,
  313. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  314. NULL);
  315. #else
  316. ComHandle = NtNativeCreateFileA(Params->PortName,
  317. GENERIC_READ | GENERIC_WRITE,
  318. 0,
  319. NULL,
  320. OPEN_ALWAYS,
  321. FILE_ATTRIBUTE_NORMAL |
  322. FILE_FLAG_OVERLAPPED,
  323. NULL,
  324. FALSE);
  325. #endif
  326. if (ComHandle == INVALID_HANDLE_VALUE)
  327. {
  328. return WIN32_LAST_STATUS();
  329. }
  330. if (Params->Type == COM_PORT_PIPE)
  331. {
  332. *Handle = ComHandle;
  333. return S_OK;
  334. }
  335. if (!SetupComm(ComHandle, 4096, 4096))
  336. {
  337. CloseHandle(ComHandle);
  338. return WIN32_LAST_STATUS();
  339. }
  340. if ((Status = SetComPortBaud(ComHandle, Params->BaudRate,
  341. BaudSet)) != S_OK)
  342. {
  343. CloseHandle(ComHandle);
  344. return Status;
  345. }
  346. COMMTIMEOUTS To;
  347. if (Params->Timeout)
  348. {
  349. To.ReadIntervalTimeout = 0;
  350. To.ReadTotalTimeoutMultiplier = 0;
  351. To.ReadTotalTimeoutConstant = Params->Timeout;
  352. To.WriteTotalTimeoutMultiplier = 0;
  353. To.WriteTotalTimeoutConstant = Params->Timeout;
  354. }
  355. else
  356. {
  357. To.ReadIntervalTimeout = 0;
  358. To.ReadTotalTimeoutMultiplier = 0xffffffff;
  359. To.ReadTotalTimeoutConstant = 0xffffffff;
  360. To.WriteTotalTimeoutMultiplier = 0xffffffff;
  361. To.WriteTotalTimeoutConstant = 0xffffffff;
  362. }
  363. if (!SetCommTimeouts(ComHandle, &To))
  364. {
  365. CloseHandle(ComHandle);
  366. return WIN32_LAST_STATUS();
  367. }
  368. *Handle = ComHandle;
  369. return S_OK;
  370. }
  371. //----------------------------------------------------------------------------
  372. //
  373. // 1394.
  374. //
  375. //----------------------------------------------------------------------------
  376. HRESULT
  377. Create1394Channel(PSTR Symlink, ULONG Channel,
  378. PSTR Name, ULONG NameSize, PHANDLE Handle)
  379. {
  380. #ifdef _WIN32_WCE
  381. return E_NOTIMPL;
  382. #else
  383. char BusName[] = "\\\\.\\1394BUS0";
  384. HANDLE hDevice;
  385. //
  386. // we need to make sure the 1394vdbg driver is up and loaded.
  387. // send the ADD_DEVICE ioctl to eject the VDO
  388. // Assume one 1394 host controller...
  389. //
  390. hDevice = CreateFile(BusName,
  391. GENERIC_READ | GENERIC_WRITE,
  392. FILE_SHARE_READ | FILE_SHARE_WRITE,
  393. NULL,
  394. OPEN_ALWAYS,
  395. FILE_ATTRIBUTE_NORMAL,
  396. NULL
  397. );
  398. if (hDevice != INVALID_HANDLE_VALUE)
  399. {
  400. PSTR DeviceId;
  401. ULONG ulStrLen;
  402. PIEEE1394_API_REQUEST pApiReq;
  403. PIEEE1394_VDEV_PNP_REQUEST pDevPnpReq;
  404. DWORD dwBytesRet;
  405. DRPC(("%s open sucessful\n", BusName));
  406. if (!_stricmp(Symlink, "channel"))
  407. {
  408. DeviceId = "VIRTUAL_HOST_DEBUGGER";
  409. }
  410. else
  411. {
  412. DeviceId = "HOST_DEBUGGER";
  413. }
  414. ulStrLen = strlen(DeviceId) + 1;
  415. pApiReq = (PIEEE1394_API_REQUEST)
  416. malloc(sizeof(IEEE1394_API_REQUEST) + ulStrLen);
  417. if (pApiReq == NULL)
  418. {
  419. CloseHandle(hDevice);
  420. return E_OUTOFMEMORY;
  421. }
  422. pApiReq->RequestNumber = IEEE1394_API_ADD_VIRTUAL_DEVICE;
  423. pApiReq->Flags = IEEE1394_REQUEST_FLAG_PERSISTENT |
  424. IEEE1394_REQUEST_FLAG_USE_LOCAL_HOST_EUI;
  425. pDevPnpReq = &pApiReq->u.RemoveVirtualDevice;
  426. pDevPnpReq->fulFlags = 0;
  427. pDevPnpReq->Reserved = 0;
  428. pDevPnpReq->InstanceId.QuadPart = 0;
  429. memcpy(&pDevPnpReq->DeviceId, DeviceId, ulStrLen);
  430. // Failure of this call is not fatal.
  431. DeviceIoControl( hDevice,
  432. IOCTL_IEEE1394_API_REQUEST,
  433. pApiReq,
  434. sizeof(IEEE1394_API_REQUEST) + ulStrLen,
  435. NULL,
  436. 0,
  437. &dwBytesRet,
  438. NULL
  439. );
  440. if (pApiReq)
  441. {
  442. free(pApiReq);
  443. }
  444. CloseHandle(hDevice);
  445. }
  446. else
  447. {
  448. DRPC(("%s open failed\n", BusName));
  449. return WIN32_LAST_STATUS();
  450. }
  451. return Open1394Channel(Symlink, Channel, Name, NameSize, Handle);
  452. #endif // #ifdef _WIN32_WCE
  453. }
  454. HRESULT
  455. Open1394Channel(PSTR Symlink, ULONG Channel,
  456. PSTR Name, ULONG NameSize, PHANDLE Handle)
  457. {
  458. if (_snprintf(Name, NameSize, "\\\\.\\DBG1394_%s%02d",
  459. Symlink, Channel) < 0)
  460. {
  461. return E_INVALIDARG;
  462. }
  463. _strupr(Name);
  464. *Handle = CreateFile(Name,
  465. GENERIC_READ | GENERIC_WRITE,
  466. FILE_SHARE_READ | FILE_SHARE_WRITE,
  467. NULL,
  468. OPEN_ALWAYS,
  469. FILE_ATTRIBUTE_NORMAL,
  470. NULL
  471. );
  472. if (*Handle == INVALID_HANDLE_VALUE)
  473. {
  474. DRPC(("%s open failed\n", Name));
  475. *Handle = NULL;
  476. return WIN32_LAST_STATUS();
  477. }
  478. DRPC(("%s open Successful\n", Name));
  479. return S_OK;
  480. }
  481. //----------------------------------------------------------------------------
  482. //
  483. // Sockets.
  484. //
  485. //----------------------------------------------------------------------------
  486. HRESULT
  487. InitIpAddress(PCSTR MachineName, ULONG Port,
  488. PSOCKADDR_STORAGE Addr, int* AddrLen)
  489. {
  490. #ifdef NT_NATIVE
  491. return E_NOTIMPL;
  492. #else
  493. ADDRINFO *Info;
  494. int Err;
  495. if (Port)
  496. {
  497. ZeroMemory(Addr, sizeof(*Addr));
  498. }
  499. else
  500. {
  501. // If a port wasn't given save the existing
  502. // one so it doesn't get lost when we update
  503. // the address.
  504. Port = ntohs(SS_PORT(Addr));
  505. }
  506. // Skip leading \\ if they were given.
  507. if (MachineName[0] == '\\' && MachineName[1] == '\\')
  508. {
  509. MachineName += 2;
  510. }
  511. //
  512. // Note that this file has a problem in some cases since when a
  513. // hostname is specified, it throws away all the addresses after
  514. // the first one. Instead, when connecting, each should be tried
  515. // in order until one succeeds.
  516. //
  517. if ((Err = getaddrinfo(MachineName, NULL, NULL, &Info)) != NO_ERROR)
  518. {
  519. return HRESULT_FROM_WIN32(Err);
  520. }
  521. CopyMemory(Addr, Info->ai_addr, Info->ai_addrlen);
  522. *AddrLen = Info->ai_addrlen;
  523. freeaddrinfo(Info);
  524. // Restore original port or put in passed-in port.
  525. SS_PORT(Addr) = htons((USHORT)Port);
  526. return S_OK;
  527. #endif // #ifdef NT_NATIVE
  528. }