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.

245 lines
7.7 KiB

4 years ago
  1. #if MYSQL_6_10
  2. // Copyright ?2009, 2016 Oracle and/or its affiliates. All rights reserved.
  3. //
  4. // MySQL Connector/NET is licensed under the terms of the GPLv2
  5. // <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
  6. // MySQL Connectors. There are special exceptions to the terms and
  7. // conditions of the GPLv2 as it is applied to this software, see the
  8. // FLOSS License Exception
  9. // <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
  10. //
  11. // This program is free software; you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published
  13. // by the Free Software Foundation; version 2 of the License.
  14. //
  15. // This program is distributed in the hope that it will be useful, but
  16. // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  18. // for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License along
  21. // with this program; if not, write to the Free Software Foundation, Inc.,
  22. // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  23. using System;
  24. using System.IO;
  25. using Microsoft.Win32.SafeHandles;
  26. using System.Threading;
  27. using System.Runtime.InteropServices;
  28. using System.ComponentModel;
  29. using System.Security;
  30. using Externals.MySql.Data.Common;
  31. namespace Externals.MySql.Data.MySqlClient.Common
  32. {
  33. /// <summary>
  34. /// Summary description for API.
  35. /// </summary>
  36. [SuppressUnmanagedCodeSecurity()]
  37. internal class NamedPipeStream : Stream
  38. {
  39. SafeFileHandle handle;
  40. Stream fileStream;
  41. int readTimeout = Timeout.Infinite;
  42. int writeTimeout = Timeout.Infinite;
  43. const int ERROR_PIPE_BUSY = 231;
  44. const int ERROR_SEM_TIMEOUT = 121;
  45. public NamedPipeStream(string path, FileAccess mode, uint timeout)
  46. {
  47. Open(path, mode, timeout);
  48. }
  49. void CancelIo()
  50. {
  51. bool ok = NativeMethods.CancelIo(handle.DangerousGetHandle());
  52. if (!ok)
  53. throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
  54. }
  55. public void Open(string path, FileAccess mode, uint timeout)
  56. {
  57. IntPtr nativeHandle;
  58. for (; ; )
  59. {
  60. NativeMethods.SecurityAttributes security = new NativeMethods.SecurityAttributes();
  61. security.inheritHandle = true;
  62. security.Length = Marshal.SizeOf(security);
  63. nativeHandle = NativeMethods.CreateFile(path, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE,
  64. 0, security, NativeMethods.OPEN_EXISTING, NativeMethods.FILE_FLAG_OVERLAPPED, 0);
  65. if (nativeHandle != IntPtr.Zero)
  66. break;
  67. if (Marshal.GetLastWin32Error() != ERROR_PIPE_BUSY)
  68. {
  69. throw new Win32Exception(Marshal.GetLastWin32Error(),
  70. "Error opening pipe");
  71. }
  72. Externals.MySql.Data.Common.LowResolutionStopwatch sw = Externals.MySql.Data.Common.LowResolutionStopwatch.StartNew();
  73. bool success = NativeMethods.WaitNamedPipe(path, timeout);
  74. sw.Stop();
  75. if (!success)
  76. {
  77. if (timeout < sw.ElapsedMilliseconds ||
  78. Marshal.GetLastWin32Error() == ERROR_SEM_TIMEOUT)
  79. {
  80. throw new TimeoutException("Timeout waiting for named pipe");
  81. }
  82. else
  83. {
  84. throw new Win32Exception(Marshal.GetLastWin32Error(),
  85. "Error waiting for pipe");
  86. }
  87. }
  88. timeout -= (uint)sw.ElapsedMilliseconds;
  89. }
  90. handle = new SafeFileHandle(nativeHandle, true);
  91. fileStream = new FileStream(handle, mode, 4096, true);
  92. }
  93. public override bool CanRead
  94. {
  95. get { return fileStream.CanRead; }
  96. }
  97. public override bool CanWrite
  98. {
  99. get { return fileStream.CanWrite; }
  100. }
  101. public override bool CanSeek
  102. {
  103. get { throw new NotSupportedException(Resources.NamedPipeNoSeek); }
  104. }
  105. public override long Length
  106. {
  107. get { throw new NotSupportedException(Resources.NamedPipeNoSeek); }
  108. }
  109. public override long Position
  110. {
  111. get { throw new NotSupportedException(Resources.NamedPipeNoSeek); }
  112. set { }
  113. }
  114. public override void Flush()
  115. {
  116. fileStream.Flush();
  117. }
  118. public override int Read(byte[] buffer, int offset, int count)
  119. {
  120. if (readTimeout == Timeout.Infinite)
  121. {
  122. return fileStream.Read(buffer, offset, count);
  123. }
  124. IAsyncResult result = fileStream.BeginRead(buffer, offset, count, null, null);
  125. if (result.CompletedSynchronously)
  126. return fileStream.EndRead(result);
  127. if (!result.AsyncWaitHandle.WaitOne(readTimeout))
  128. {
  129. CancelIo();
  130. throw new TimeoutException("Timeout in named pipe read");
  131. }
  132. return fileStream.EndRead(result);
  133. }
  134. public override void Write(byte[] buffer, int offset, int count)
  135. {
  136. if (writeTimeout == Timeout.Infinite)
  137. {
  138. fileStream.Write(buffer, offset, count);
  139. return;
  140. }
  141. IAsyncResult result = fileStream.BeginWrite(buffer, offset, count, null, null);
  142. if (result.CompletedSynchronously)
  143. {
  144. fileStream.EndWrite(result);
  145. }
  146. if (!result.AsyncWaitHandle.WaitOne(readTimeout))
  147. {
  148. CancelIo();
  149. throw new TimeoutException("Timeout in named pipe write");
  150. }
  151. fileStream.EndWrite(result);
  152. }
  153. public override void Close()
  154. {
  155. if (handle != null && !handle.IsInvalid && !handle.IsClosed)
  156. {
  157. fileStream.Close();
  158. try
  159. {
  160. handle.Close();
  161. }
  162. catch (Exception)
  163. {
  164. }
  165. }
  166. }
  167. public override void SetLength(long length)
  168. {
  169. throw new NotSupportedException(Resources.NamedPipeNoSetLength);
  170. }
  171. public override bool CanTimeout
  172. {
  173. get
  174. {
  175. return true;
  176. }
  177. }
  178. public override int ReadTimeout
  179. {
  180. get
  181. {
  182. return readTimeout;
  183. }
  184. set
  185. {
  186. readTimeout = value;
  187. }
  188. }
  189. public override int WriteTimeout
  190. {
  191. get
  192. {
  193. return writeTimeout;
  194. }
  195. set
  196. {
  197. writeTimeout = value;
  198. }
  199. }
  200. public override long Seek(long offset, SeekOrigin origin)
  201. {
  202. throw new NotSupportedException(Resources.NamedPipeNoSeek);
  203. }
  204. internal static Stream Create(string pipeName, string hostname, uint timeout)
  205. {
  206. string pipePath;
  207. if (0 == String.Compare(hostname, "localhost", true))
  208. pipePath = @"\\.\pipe\" + pipeName;
  209. else
  210. pipePath = String.Format(@"\\{0}\pipe\{1}", hostname, pipeName);
  211. return new NamedPipeStream(pipePath, FileAccess.ReadWrite, timeout);
  212. }
  213. }
  214. }
  215. #endif