/// <summary> /// Start receiving /// </summary> /// <returns></returns> public uint StartReceive() { SNIPacket packet = null; if (ReceiveAsync(ref packet) == TdsEnums.SNI_SUCCESS_IO_PENDING) { return(TdsEnums.SNI_SUCCESS_IO_PENDING); } return(SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnNotUsableError, string.Empty)); }
/// <summary> /// Enable SSL on a connection /// </summary> /// <param name="handle">Connection handle</param> /// <returns>SNI error code</returns> public uint EnableSsl(SNIHandle handle, uint options) { try { return(handle.EnableSsl(options)); } catch (Exception e) { return(SNICommon.ReportSNIError(SNIProviders.SSL_PROV, SNICommon.HandshakeFailureError, e)); } }
public SNINpHandle(string serverName, string pipeName, long timerExpire, object callbackObject) { _targetServer = serverName; _callbackObject = callbackObject; _writeScheduler = new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler; _writeTaskFactory = new TaskFactory(_writeScheduler); try { _pipeStream = new NamedPipeClientStream( serverName, pipeName, PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough); bool isInfiniteTimeOut = long.MaxValue == timerExpire; if (isInfiniteTimeOut) { _pipeStream.Connect(Threading.Timeout.Infinite); } else { TimeSpan ts = DateTime.FromFileTime(timerExpire) - DateTime.Now; ts = ts.Ticks < 0 ? TimeSpan.FromTicks(0) : ts; _pipeStream.Connect((int)ts.TotalMilliseconds); } } catch (TimeoutException te) { SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.ConnTimeoutError, te); _status = TdsEnums.SNI_WAIT_TIMEOUT; return; } catch (IOException ioe) { SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.ConnOpenFailedError, ioe); _status = TdsEnums.SNI_ERROR; return; } if (!_pipeStream.IsConnected || !_pipeStream.CanWrite || !_pipeStream.CanRead) { SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.ConnOpenFailedError, string.Empty); _status = TdsEnums.SNI_ERROR; return; } _sslOverTdsStream = new SslOverTdsStream(_pipeStream); _sslStream = new SslStream(_sslOverTdsStream, true, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); _stream = _pipeStream; _status = TdsEnums.SNI_SUCCESS; }
/// <summary> /// Dispose object /// </summary> public override void Dispose() { try { SendControlPacket(SNISMUXFlags.SMUX_FIN); } catch (Exception e) { SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, SNICommon.InternalExceptionError, e); throw; } }
/// <summary> /// Receive a packet synchronously /// </summary> /// <param name="packet">SNI packet</param> /// <param name="timeoutInMilliseconds">Timeout in Milliseconds</param> /// <returns>SNI error code</returns> public override uint Receive(out SNIPacket packet, int timeoutInMilliseconds) { packet = null; int queueCount; uint result = TdsEnums.SNI_SUCCESS_IO_PENDING; while (true) { lock (_receivedPacketQueue) { if (_connectionError != null) { return(SNICommon.ReportSNIError(_connectionError)); } queueCount = _receivedPacketQueue.Count; if (queueCount > 0) { packet = _receivedPacketQueue.Dequeue(); if (queueCount == 1) { _packetEvent.Reset(); } result = TdsEnums.SNI_SUCCESS; } } if (result == TdsEnums.SNI_SUCCESS) { lock (this) { _receiveHighwater++; } SendAckIfNecessary(); return(result); } if (!_packetEvent.Wait(timeoutInMilliseconds)) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.ConnTimeoutError, string.Empty); return(TdsEnums.SNI_WAIT_TIMEOUT); } } }
/// <summary> /// Creates an SNINpHandle object /// </summary> /// <param name="fullServerName">Server string representing a UNC pipe path.</param> /// <param name="timerExpire">Timer expiration</param> /// <param name="callbackObject">Asynchronous I/O callback object</param> /// <param name="parallel">Should MultiSubnetFailover be used. Only returns an error for named pipes.</param> /// <returns>SNINpHandle</returns> private SNINpHandle CreateNpHandle(string fullServerName, long timerExpire, object callbackObject, bool parallel) { if (parallel) { SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, string.Empty); return(null); } if (fullServerName.Length == 0 || fullServerName.Contains("/")) // Pipe paths only allow back slashes { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.NP_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); return(null); } string serverName, pipeName; if (!fullServerName.Contains(@"\")) { serverName = fullServerName; pipeName = SNINpHandle.DefaultPipePath; } else { try { Uri pipeURI = new Uri(fullServerName); string resourcePath = pipeURI.AbsolutePath; string pipeToken = "/pipe/"; if (!resourcePath.StartsWith(pipeToken)) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.NP_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); return(null); } pipeName = resourcePath.Substring(pipeToken.Length); serverName = pipeURI.Host; } catch (UriFormatException) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.NP_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); return(null); } } return(new SNINpHandle(serverName, pipeName, timerExpire, callbackObject)); }
public override uint SendAsync(SNIPacket packet, SNIAsyncCallback callback = null) { SNIPacket newPacket = packet; _writeTaskFactory.StartNew(() => { try { lock (this) { packet.WriteToStream(_stream); } } catch (Exception e) { SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.InternalExceptionError, e); if (callback != null) { callback(packet, TdsEnums.SNI_ERROR); } else { _sendCallback(packet, TdsEnums.SNI_ERROR); } return; } if (callback != null) { callback(packet, TdsEnums.SNI_SUCCESS); } else { _sendCallback(packet, TdsEnums.SNI_SUCCESS); } }); return(TdsEnums.SNI_SUCCESS_IO_PENDING); }
public override uint EnableSsl(uint options) { _validateCert = (options & TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE) != 0; try { _sslStream.AuthenticateAsClientAsync(_targetServer).GetAwaiter().GetResult(); _sslOverTdsStream.FinishHandshake(); } catch (AuthenticationException aue) { return(SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.InternalExceptionError, aue)); } catch (InvalidOperationException ioe) { return(SNICommon.ReportSNIError(SNIProviders.NP_PROV, SNICommon.InternalExceptionError, ioe)); } _stream = _sslStream; return(TdsEnums.SNI_SUCCESS); }
/// <summary> /// Create a SNI connection handle /// </summary> /// <param name="callbackObject">Asynchronous I/O callback object</param> /// <param name="fullServerName">Full server name from connection string</param> /// <param name="ignoreSniOpenTimeout">Ignore open timeout</param> /// <param name="timerExpire">Timer expiration</param> /// <param name="instanceName">Instance name</param> /// <param name="spnBuffer">SPN</param> /// <param name="flushCache">Flush packet cache</param> /// <param name="async">Asynchronous connection</param> /// <param name="parallel">Attempt parallel connects</param> /// <returns>SNI handle</returns> public SNIHandle CreateConnectionHandle(object callbackObject, string fullServerName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, byte[] spnBuffer, bool flushCache, bool async, bool parallel) { instanceName = new byte[1]; instanceName[0] = 0; string[] serverNameParts = fullServerName.Split(':'); if (serverNameParts.Length > 2) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); return(null); } // Default to using tcp if no protocol is provided if (serverNameParts.Length == 1) { return(CreateTcpHandle(serverNameParts[0], timerExpire, callbackObject, parallel)); } switch (serverNameParts[0]) { case TdsEnums.TCP: return(CreateTcpHandle(serverNameParts[1], timerExpire, callbackObject, parallel)); case TdsEnums.NP: return(CreateNpHandle(serverNameParts[1], timerExpire, callbackObject, parallel)); default: if (parallel) { SNICommon.ReportSNIError(SNIProviders.INVALID_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, string.Empty); } else { SNICommon.ReportSNIError(SNIProviders.INVALID_PROV, 0, SNICommon.ProtocolNotSupportedError, string.Empty); } return(null); } }
/// <summary> /// Creates an SNINpHandle object /// </summary> /// <param name="fullServerName">Server string representing a UNC pipe path.</param> /// <param name="timerExpire">Timer expiration</param> /// <param name="callbackObject">Asynchronous I/O callback object</param> /// <param name="parallel">Should MultiSubnetFailover be used. Only returns an error for named pipes.</param> /// <returns>SNINpHandle</returns> private SNINpHandle CreateNpHandle(string fullServerName, long timerExpire, object callbackObject, bool parallel) { if (parallel) { SNICommon.ReportSNIError(SNIProviders.INVALID_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, string.Empty); return(null); } // Named Pipe Format: np:\\<host name>\pipe\<pipe name> const int minPipeLength = 10; // eg: //./pipe/a string pipePath = fullServerName.Trim(); if (pipePath.Length < minPipeLength) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.NP_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); return(null); } if (pipePath[0] != '\\' || pipePath[1] != '\\') { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.NP_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); return(null); } int endofServerName = pipePath.IndexOf('\\', 2); string pipeToken = @"\pipe\"; if (0 != string.Compare(pipeToken, 0, pipePath, endofServerName, pipeToken.Length)) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.NP_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); return(null); } string serverName = pipePath.Substring(2, endofServerName - 2); string pipeName = pipePath.Substring(endofServerName + pipeToken.Length); return(new SNINpHandle(serverName, pipeName, timerExpire, callbackObject)); }
/// <summary> /// Create a SNI connection handle /// </summary> /// <param name="callbackObject">Asynchronous I/O callback object</param> /// <param name="fullServerName">Full server name from connection string</param> /// <param name="ignoreSniOpenTimeout">Ignore open timeout</param> /// <param name="timerExpire">Timer expiration</param> /// <param name="instanceName">Instance name</param> /// <param name="spnBuffer">SPN</param> /// <param name="flushCache">Flush packet cache</param> /// <param name="async">Asynchronous connection</param> /// <param name="parallel">Attempt parallel connects</param> /// <returns>SNI handle</returns> public SNIHandle CreateConnectionHandle(object callbackObject, string fullServerName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, byte[] spnBuffer, bool flushCache, bool async, bool parallel) { instanceName = new byte[1]; instanceName[0] = 0; string[] serverNameParts = fullServerName.Split(':'); if (serverNameParts.Length > 2) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, 0, "Connection string is not formatted correctly"); return(null); } // Default to using tcp if no protocol is provided if (serverNameParts.Length == 1) { return(ConstructTcpHandle(serverNameParts[0], timerExpire, callbackObject, parallel)); } switch (serverNameParts[0]) { case TdsEnums.TCP: return(ConstructTcpHandle(serverNameParts[1], timerExpire, callbackObject, parallel)); default: if (parallel) { SNICommon.ReportSNIError(SNIProviders.INVALID_PROV, 0, (int)SNINativeMethodWrapper.SniSpecialErrors.MultiSubnetFailoverWithNonTcpProtocol, SR.SNI_ERROR_49); } else { SNICommon.ReportSNIError(SNIProviders.INVALID_PROV, 0, 8, SR.SNI_ERROR_8); } return(null); } }
private uint ReportTcpSNIError(uint nativeError, uint sniError, string errorMessage) { _status = TdsEnums.SNI_ERROR; return(SNICommon.ReportSNIError(SNIProviders.TCP_PROV, nativeError, sniError, errorMessage)); }
private uint ReportTcpSNIError(Exception sniException) { _status = TdsEnums.SNI_ERROR; return(SNICommon.ReportSNIError(SNIProviders.TCP_PROV, SNICommon.InternalExceptionError, sniException)); }
/// <summary> /// Process a receive completion /// </summary> /// <param name="packet">SNI packet</param> /// <param name="sniErrorCode">SNI error code</param> public void HandleReceiveComplete(SNIPacket packet, uint sniErrorCode) { SNISMUXHeader currentHeader = null; SNIPacket currentPacket = null; SNIMarsHandle currentSession = null; if (sniErrorCode != TdsEnums.SNI_SUCCESS) { lock (this) { HandleReceiveError(); return; } } while (true) { lock (this) { if (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { currentHeader = null; currentPacket = null; currentSession = null; while (_currentHeaderByteCount != SNISMUXHeader.HEADER_LENGTH) { int bytesTaken = packet.TakeData(_headerBytes, _currentHeaderByteCount, SNISMUXHeader.HEADER_LENGTH - _currentHeaderByteCount); _currentHeaderByteCount += bytesTaken; if (bytesTaken == 0) { sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(); return; } } _currentHeader = new SNISMUXHeader() { SMID = _headerBytes[0], flags = _headerBytes[1], sessionId = BitConverter.ToUInt16(_headerBytes, 2), length = BitConverter.ToUInt32(_headerBytes, 4) - SNISMUXHeader.HEADER_LENGTH, sequenceNumber = BitConverter.ToUInt32(_headerBytes, 8), highwater = BitConverter.ToUInt32(_headerBytes, 12) }; _dataBytesLeft = (int)_currentHeader.length; _currentPacket = new SNIPacket(null); _currentPacket.Allocate((int)_currentHeader.length); } currentHeader = _currentHeader; currentPacket = _currentPacket; if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { if (_dataBytesLeft > 0) { int length = packet.TakeData(_currentPacket, _dataBytesLeft); _dataBytesLeft -= length; if (_dataBytesLeft > 0) { sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(); return; } } } _currentHeaderByteCount = 0; if (!_sessions.ContainsKey(_currentHeader.sessionId)) { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.SMUX_PROV, 0, SNICommon.InvalidParameterError, string.Empty); HandleReceiveError(); _lowerHandle.Dispose(); _lowerHandle = null; return; } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_FIN) { _sessions.Remove(_currentHeader.sessionId); } else { currentSession = _sessions[_currentHeader.sessionId]; } } if (currentHeader.flags == (byte)SNISMUXFlags.SMUX_DATA) { currentSession.HandleReceiveComplete(currentPacket, currentHeader); } if (_currentHeader.flags == (byte)SNISMUXFlags.SMUX_ACK) { try { currentSession.HandleAck(currentHeader.highwater); } catch (Exception e) { SNICommon.ReportSNIError(SNIProviders.SMUX_PROV, SNICommon.InternalExceptionError, e); } } lock (this) { if (packet.DataLeft == 0) { sniErrorCode = ReceiveAsync(ref packet); if (sniErrorCode == TdsEnums.SNI_SUCCESS_IO_PENDING) { return; } HandleReceiveError(); return; } } } }
/// <summary> /// Create a SNI connection handle /// </summary> /// <param name="callbackObject">Asynchronous I/O callback object</param> /// <param name="fullServerName">Full server name from connection string</param> /// <param name="ignoreSniOpenTimeout">Ignore open timeout</param> /// <param name="timerExpire">Timer expiration</param> /// <param name="instanceName">Instance name</param> /// <param name="spnBuffer">SPN</param> /// <param name="flushCache">Flush packet cache</param> /// <param name="async">Asynchronous connection</param> /// <param name="parallel">Attempt parallel connects</param> /// <returns>SNI handle</returns> public SNIHandle CreateConnectionHandle(object callbackObject, string fullServerName, bool ignoreSniOpenTimeout, long timerExpire, out byte[] instanceName, ref byte[] spnBuffer, bool flushCache, bool async, bool parallel, bool isIntegratedSecurity) { instanceName = new byte[1]; SNIHandle sniHandle = null; if (fullServerName.IndexOf(':') == -1) { // default to using tcp if no protocol is provided sniHandle = CreateTcpHandle(fullServerName, timerExpire, callbackObject, parallel, ref spnBuffer, isIntegratedSecurity); } else { string serverNameWithOutProtocol = null; // when tcp protocol is specified if ((serverNameWithOutProtocol = GetServerNameWithOutProtocol(fullServerName, TdsEnums.TCP + ":")) != null) { sniHandle = CreateTcpHandle(serverNameWithOutProtocol, timerExpire, callbackObject, parallel, ref spnBuffer, isIntegratedSecurity); } // when np protocol is specified else if ((serverNameWithOutProtocol = GetServerNameWithOutProtocol(fullServerName, TdsEnums.NP + ":\\\\")) != null || (serverNameWithOutProtocol = GetServerNameWithOutProtocol(fullServerName, "\\\\")) != null) { sniHandle = CreateNpHandle(serverNameWithOutProtocol, timerExpire, callbackObject, parallel); } // possibly error case else { int portOrInstanceNameIndex = Math.Max(fullServerName.LastIndexOf(','), fullServerName.LastIndexOf('\\')); string serverNameWithOutPortOrInstanceName = portOrInstanceNameIndex > 0 ? fullServerName.Substring(0, portOrInstanceNameIndex) : fullServerName; IPAddress address = null; // when no protocol is specified, and fullServerName is IPv6 if (IPAddress.TryParse(serverNameWithOutPortOrInstanceName, out address) && address.AddressFamily == AddressFamily.InterNetworkV6) { // default to using tcp if no protocol is provided sniHandle = CreateTcpHandle(fullServerName, timerExpire, callbackObject, parallel, ref spnBuffer, isIntegratedSecurity); } // error case for sure else { // when invalid protocol is specified if (IsOccursOnce(fullServerName, ':')) { SNICommon.ReportSNIError( SNIProviders.INVALID_PROV, 0, (uint)(parallel ? SNICommon.MultiSubnetFailoverWithNonTcpProtocol : SNICommon.ProtocolNotSupportedError), string.Empty); } // when fullServerName is in invalid format else { SNILoadHandle.SingletonInstance.LastError = new SNIError(SNIProviders.INVALID_PROV, 0, SNICommon.InvalidConnStringError, string.Empty); } } } } return(sniHandle); }