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.

253 lines
6.6 KiB

4 years ago
  1. #if MYSQL_6_9
  2. // Copyright (c) 2004-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
  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 Externals.MySql.Data.MySqlClient;
  26. using Externals.MySql.Data.MySqlClient.Properties;
  27. using Microsoft.Win32.SafeHandles;
  28. using System.Threading;
  29. using System.Diagnostics;
  30. using System.Runtime.InteropServices;
  31. using System.ComponentModel;
  32. using System.Security.Permissions;
  33. using System.Security;
  34. namespace Externals.MySql.Data.Common
  35. {
  36. /// <summary>
  37. /// Summary description for API.
  38. /// </summary>
  39. [SuppressUnmanagedCodeSecurity()]
  40. internal class NamedPipeStream : Stream
  41. {
  42. SafeFileHandle handle;
  43. Stream fileStream;
  44. int readTimeout = Timeout.Infinite;
  45. int writeTimeout = Timeout.Infinite;
  46. const int ERROR_PIPE_BUSY = 231;
  47. const int ERROR_SEM_TIMEOUT = 121;
  48. public NamedPipeStream(string path, FileAccess mode, uint timeout)
  49. {
  50. Open(path, mode, timeout);
  51. }
  52. void CancelIo()
  53. {
  54. bool ok = NativeMethods.CancelIo(handle.DangerousGetHandle());
  55. if (!ok)
  56. throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
  57. }
  58. public void Open(string path, FileAccess mode, uint timeout)
  59. {
  60. IntPtr nativeHandle;
  61. for (; ; )
  62. {
  63. NativeMethods.SecurityAttributes security = new NativeMethods.SecurityAttributes();
  64. security.inheritHandle = true;
  65. security.Length = Marshal.SizeOf(security);
  66. nativeHandle = NativeMethods.CreateFile(path, NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE,
  67. 0, security, NativeMethods.OPEN_EXISTING, NativeMethods.FILE_FLAG_OVERLAPPED, 0);
  68. if (nativeHandle != IntPtr.Zero)
  69. break;
  70. if (Marshal.GetLastWin32Error() != ERROR_PIPE_BUSY)
  71. {
  72. throw new Win32Exception(Marshal.GetLastWin32Error(),
  73. "Error opening pipe");
  74. }
  75. LowResolutionStopwatch sw = LowResolutionStopwatch.StartNew();
  76. bool success = NativeMethods.WaitNamedPipe(path, timeout);
  77. sw.Stop();
  78. if (!success)
  79. {
  80. if (timeout < sw.ElapsedMilliseconds ||
  81. Marshal.GetLastWin32Error() == ERROR_SEM_TIMEOUT)
  82. {
  83. throw new TimeoutException("Timeout waiting for named pipe");
  84. }
  85. else
  86. {
  87. throw new Win32Exception(Marshal.GetLastWin32Error(),
  88. "Error waiting for pipe");
  89. }
  90. }
  91. timeout -= (uint)sw.ElapsedMilliseconds;
  92. }
  93. handle = new SafeFileHandle(nativeHandle, true);
  94. fileStream = new FileStream(handle, mode, 4096, true);
  95. }
  96. public override bool CanRead
  97. {
  98. get { return fileStream.CanRead; }
  99. }
  100. public override bool CanWrite
  101. {
  102. get { return fileStream.CanWrite; }
  103. }
  104. public override bool CanSeek
  105. {
  106. get { throw new NotSupportedException(Resources.NamedPipeNoSeek); }
  107. }
  108. public override long Length
  109. {
  110. get { throw new NotSupportedException(Resources.NamedPipeNoSeek); }
  111. }
  112. public override long Position
  113. {
  114. get { throw new NotSupportedException(Resources.NamedPipeNoSeek); }
  115. set { }
  116. }
  117. public override void Flush()
  118. {
  119. fileStream.Flush();
  120. }
  121. public override int Read(byte[] buffer, int offset, int count)
  122. {
  123. if (readTimeout == Timeout.Infinite)
  124. {
  125. return fileStream.Read(buffer, offset, count);
  126. }
  127. IAsyncResult result = fileStream.BeginRead(buffer, offset, count, null, null);
  128. if (result.CompletedSynchronously)
  129. return fileStream.EndRead(result);
  130. if (!result.AsyncWaitHandle.WaitOne(readTimeout))
  131. {
  132. CancelIo();
  133. throw new TimeoutException("Timeout in named pipe read");
  134. }
  135. return fileStream.EndRead(result);
  136. }
  137. public override void Write(byte[] buffer, int offset, int count)
  138. {
  139. if (writeTimeout == Timeout.Infinite)
  140. {
  141. fileStream.Write(buffer, offset, count);
  142. return;
  143. }
  144. IAsyncResult result = fileStream.BeginWrite(buffer, offset, count, null, null);
  145. if (result.CompletedSynchronously)
  146. {
  147. fileStream.EndWrite(result);
  148. }
  149. if (!result.AsyncWaitHandle.WaitOne(readTimeout))
  150. {
  151. CancelIo();
  152. throw new TimeoutException("Timeout in named pipe write");
  153. }
  154. fileStream.EndWrite(result);
  155. }
  156. public override void Close()
  157. {
  158. if (handle != null && !handle.IsInvalid && !handle.IsClosed)
  159. {
  160. fileStream.Close();
  161. try
  162. {
  163. handle.Close();
  164. }
  165. catch (Exception)
  166. {
  167. }
  168. }
  169. }
  170. public override void SetLength(long length)
  171. {
  172. throw new NotSupportedException(Resources.NamedPipeNoSetLength);
  173. }
  174. public override bool CanTimeout
  175. {
  176. get
  177. {
  178. return true;
  179. }
  180. }
  181. public override int ReadTimeout
  182. {
  183. get
  184. {
  185. return readTimeout;
  186. }
  187. set
  188. {
  189. readTimeout = value;
  190. }
  191. }
  192. public override int WriteTimeout
  193. {
  194. get
  195. {
  196. return writeTimeout;
  197. }
  198. set
  199. {
  200. writeTimeout = value;
  201. }
  202. }
  203. public override long Seek(long offset, SeekOrigin origin)
  204. {
  205. throw new NotSupportedException(Resources.NamedPipeNoSeek);
  206. }
  207. internal static Stream Create(string pipeName, string hostname, uint timeout)
  208. {
  209. string pipePath;
  210. if (0 == String.Compare(hostname, "localhost", true))
  211. pipePath = @"\\.\pipe\" + pipeName;
  212. else
  213. pipePath = String.Format(@"\\{0}\pipe\{1}", hostname, pipeName);
  214. return new NamedPipeStream(pipePath, FileAccess.ReadWrite, timeout);
  215. }
  216. }
  217. }
  218. #endif