SocketMode ISocketCallback.Connected(Stream stream, TextWriter log) { try { var socketMode = SocketManager.DefaultSocketMode; // disallow connection in some cases OnDebugAbort(); // the order is important here: // [network]<==[ssl]<==[logging]<==[buffered] var config = multiplexer.RawConfig; if (config.Ssl) { multiplexer.LogLocked(log, "Configuring SSL"); var host = config.SslHost; if (string.IsNullOrWhiteSpace(host)) { host = Format.ToStringHostOnly(bridge.ServerEndPoint.EndPoint); } var ssl = new SslStream(stream, false, config.CertificateValidationCallback, config.CertificateSelectionCallback ?? GetAmbientCertificateCallback() #if !__MonoCS__ , EncryptionPolicy.RequireEncryption #endif ); ssl.AuthenticateAsClient(host); if (!ssl.IsEncrypted) { RecordConnectionFailed(ConnectionFailureType.AuthenticationFailure); multiplexer.Trace("Encryption failure"); return(SocketMode.Abort); } stream = ssl; socketMode = SocketMode.Async; } OnWrapForLogging(ref stream, physicalName); int bufferSize = config.WriteBuffer; this.netStream = stream; this.outStream = bufferSize <= 0 ? stream : new BufferedStream(stream, bufferSize); multiplexer.LogLocked(log, "Connected {0}", bridge); bridge.OnConnected(this, log); return(socketMode); } catch (Exception ex) { RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex); // includes a bridge.OnDisconnected multiplexer.Trace("Could not connect: " + ex.Message, physicalName); return(SocketMode.Abort); } }
#pragma warning disable 1998 // NET40 is sync, not async, currently internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, TextWriter log) { Dictionary <string, IPAddress> cache = new Dictionary <string, IPAddress>(StringComparer.InvariantCultureIgnoreCase); for (int i = 0; i < endpoints.Count; i++) { var dns = endpoints[i] as DnsEndPoint; if (dns != null) { try { IPAddress ip; if (dns.Host == ".") { endpoints[i] = new IPEndPoint(IPAddress.Loopback, dns.Port); } else if (cache.TryGetValue(dns.Host, out ip)) { // use cache endpoints[i] = new IPEndPoint(ip, dns.Port); } else { multiplexer.LogLocked(log, "Using DNS to resolve '{0}'...", dns.Host); #if NET40 var ips = Dns.GetHostAddresses(dns.Host); #else var ips = await Dns.GetHostAddressesAsync(dns.Host).ObserveErrors().ForAwait(); #endif if (ips.Length == 1) { ip = ips[0]; multiplexer.LogLocked(log, "'{0}' => {1}", dns.Host, ip); cache[dns.Host] = ip; endpoints[i] = new IPEndPoint(ip, dns.Port); } } } catch (Exception ex) { multiplexer.OnInternalError(ex); multiplexer.LogLocked(log, ex.Message); } } } }
internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, TextWriter log) { var cache = new Dictionary <string, IPAddress>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < EndPoints.Count; i++) { if (EndPoints[i] is DnsEndPoint dns) { try { if (dns.Host == ".") { EndPoints[i] = new IPEndPoint(IPAddress.Loopback, dns.Port); } else if (cache.TryGetValue(dns.Host, out IPAddress ip)) { // use cache EndPoints[i] = new IPEndPoint(ip, dns.Port); } else { multiplexer.LogLocked(log, "Using DNS to resolve '{0}'...", dns.Host); var ips = await Dns.GetHostAddressesAsync(dns.Host).ObserveErrors().ForAwait(); if (ips.Length == 1) { ip = ips[0]; multiplexer.LogLocked(log, "'{0}' => {1}", dns.Host, ip); cache[dns.Host] = ip; EndPoints[i] = new IPEndPoint(ip, dns.Port); } } } catch (Exception ex) { multiplexer.OnInternalError(ex); multiplexer.LogLocked(log, ex.Message); } } } }
internal SocketToken BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log) { var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); SetFastLoopbackOption(socket); socket.NoDelay = true; try { CompletionType connectCompletionType = CompletionType.Any; this.ShouldForceConnectCompletionType(ref connectCompletionType); var formattedEndpoint = Format.ToString(endpoint); if (endpoint is DnsEndPoint) { // A work-around for a Mono bug in BeginConnect(EndPoint endpoint, AsyncCallback callback, object state) DnsEndPoint dnsEndpoint = (DnsEndPoint)endpoint; CompletionTypeHelper.RunWithCompletionType( (cb) => { multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); return(socket.BeginConnect(dnsEndpoint.Host, dnsEndpoint.Port, cb, Tuple.Create(socket, callback))); }, (ar) => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }, connectCompletionType); } else { CompletionTypeHelper.RunWithCompletionType( (cb) => { multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); return(socket.BeginConnect(endpoint, cb, Tuple.Create(socket, callback))); }, (ar) => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }, connectCompletionType); } } catch (NotImplementedException ex) { if (!(endpoint is IPEndPoint)) { throw new InvalidOperationException("BeginConnect failed with NotImplementedException; consider using IP endpoints, or enable ResolveDns in the configuration", ex); } throw; } var token = new SocketToken(socket); return(token); }
#pragma warning disable 1998 // NET40 is sync, not async, currently internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, TextWriter log) { Dictionary<string, IPAddress> cache = new Dictionary<string, IPAddress>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < endpoints.Count; i++) { var dns = endpoints[i] as DnsEndPoint; if (dns != null) { try { IPAddress ip; if (dns.Host == ".") { endpoints[i] = new IPEndPoint(IPAddress.Loopback, dns.Port); } else if (cache.TryGetValue(dns.Host, out ip)) { // use cache endpoints[i] = new IPEndPoint(ip, dns.Port); } else { multiplexer.LogLocked(log, "Using DNS to resolve '{0}'...", dns.Host); #if NET40 var ips = Dns.GetHostAddresses(dns.Host); #else var ips = await Dns.GetHostAddressesAsync(dns.Host).ObserveErrors().ForAwait(); #endif if (ips.Length == 1) { ip = ips[0]; multiplexer.LogLocked(log, "'{0}' => {1}", dns.Host, ip); cache[dns.Host] = ip; endpoints[i] = new IPEndPoint(ip, dns.Port); } } } catch (Exception ex) { multiplexer.OnInternalError(ex); multiplexer.LogLocked(log, ex.Message); } } } }
private void EndConnectImpl(IAsyncResult ar, ConnectionMultiplexer multiplexer, TextWriter log) { Tuple<Socket, ISocketCallback> tuple = null; try { tuple = (Tuple<Socket, ISocketCallback>)ar.AsyncState; bool ignoreConnect = false; ShouldIgnoreConnect(tuple.Item2, ref ignoreConnect); if (ignoreConnect) return; var socket = tuple.Item1; var callback = tuple.Item2; socket.EndConnect(ar); var netStream = new NetworkStream(socket, false); var socketMode = callback == null ? SocketMode.Abort : callback.Connected(netStream, log); switch (socketMode) { case SocketMode.Poll: multiplexer.LogLocked(log, "Starting poll"); OnAddRead(socket, callback); break; case SocketMode.Async: multiplexer.LogLocked(log, "Starting read"); try { callback.StartReading(); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); Shutdown(socket); } break; default: ConnectionMultiplexer.TraceWithoutContext("Aborting socket"); Shutdown(socket); break; } } catch(ObjectDisposedException) { multiplexer.LogLocked(log, "(socket shutdown)"); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } catch(Exception outer) { ConnectionMultiplexer.TraceWithoutContext(outer.Message); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } }
internal SocketToken BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log) { var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); SetFastLoopbackOption(socket); socket.NoDelay = true; try { CompletionType connectCompletionType = CompletionType.Any; this.ShouldForceConnectCompletionType(ref connectCompletionType); var formattedEndpoint = Format.ToString(endpoint); if (endpoint is DnsEndPoint) { // A work-around for a Mono bug in BeginConnect(EndPoint endpoint, AsyncCallback callback, object state) DnsEndPoint dnsEndpoint = (DnsEndPoint)endpoint; CompletionTypeHelper.RunWithCompletionType( (cb) => { multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); return socket.BeginConnect(dnsEndpoint.Host, dnsEndpoint.Port, cb, Tuple.Create(socket, callback)); }, (ar) => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }, connectCompletionType); } else { CompletionTypeHelper.RunWithCompletionType( (cb) => { multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); return socket.BeginConnect(endpoint, cb, Tuple.Create(socket, callback)); }, (ar) => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }, connectCompletionType); } } catch (NotImplementedException ex) { if (!(endpoint is IPEndPoint)) { throw new InvalidOperationException("BeginConnect failed with NotImplementedException; consider using IP endpoints, or enable ResolveDns in the configuration", ex); } throw; } var token = new SocketToken(socket); return token; }
void Handshake(PhysicalConnection connection, TextWriter log) { multiplexer.LogLocked(log, "Server handshake"); if (connection == null) { multiplexer.Trace("No connection!?"); return; } Message msg; string password = multiplexer.RawConfig.Password; if (!StringExtensions.IsNullOrWhiteSpace(password)) { multiplexer.LogLocked(log, "Authenticating (password)"); msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.AUTH, (RedisValue)password); msg.SetInternalCall(); WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.DemandOK); } if (multiplexer.CommandMap.IsAvailable(RedisCommand.CLIENT)) { string name = multiplexer.ClientName; if (!StringExtensions.IsNullOrWhiteSpace(name)) { name = nameSanitizer.Replace(name, ""); if (!StringExtensions.IsNullOrWhiteSpace(name)) { multiplexer.LogLocked(log, "Setting client name: {0}", name); msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, RedisLiterals.SETNAME, (RedisValue)name); msg.SetInternalCall(); WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.DemandOK); } } } var connType = connection.Bridge.ConnectionType; if (connType == ConnectionType.Interactive) { multiplexer.LogLocked(log, "Auto-configure..."); AutoConfigure(connection); } multiplexer.LogLocked(log, "Sending critical tracer: {0}", connection.Bridge); var tracer = GetTracerMessage(true); tracer = LoggingMessage.Create(log, tracer); WriteDirectOrQueueFireAndForget(connection, tracer, ResultProcessor.EstablishConnection); // note: this **must** be the last thing on the subscription handshake, because after this // we will be in subscriber mode: regular commands cannot be sent if (connType == ConnectionType.Subscription) { var configChannel = multiplexer.ConfigurationChangedChannel; if (configChannel != null) { msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.SUBSCRIBE, (RedisChannel)configChannel); WriteDirectOrQueueFireAndForget(connection, msg, ResultProcessor.TrackSubscriptions); } } multiplexer.LogLocked(log, "Flushing outbound buffer"); connection.Flush(); }
private void EndConnectImpl(IAsyncResult ar, ConnectionMultiplexer multiplexer, TextWriter log, Tuple <Socket, ISocketCallback> tuple) { try { bool ignoreConnect = false; ShouldIgnoreConnect(tuple.Item2, ref ignoreConnect); if (ignoreConnect) { return; } var socket = tuple.Item1; var callback = tuple.Item2; #if CORE_CLR multiplexer.Wait((Task)ar); // make it explode if invalid (note: already complete at this point) #else socket.EndConnect(ar); #endif var netStream = new NetworkStream(socket, false); var socketMode = callback?.Connected(netStream, log) ?? SocketMode.Abort; switch (socketMode) { case SocketMode.Poll: multiplexer.LogLocked(log, "Starting poll"); OnAddRead(socket, callback); break; case SocketMode.Async: multiplexer.LogLocked(log, "Starting read"); try { callback.StartReading(); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); Shutdown(socket); } break; default: ConnectionMultiplexer.TraceWithoutContext("Aborting socket"); Shutdown(socket); break; } } catch (ObjectDisposedException) { multiplexer.LogLocked(log, "(socket shutdown)"); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } catch (Exception outer) { ConnectionMultiplexer.TraceWithoutContext(outer.Message); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } }
private void EndConnectImpl(IAsyncResult ar, ConnectionMultiplexer multiplexer, TextWriter log) { Tuple <Socket, ISocketCallback> tuple = null; try { tuple = (Tuple <Socket, ISocketCallback>)ar.AsyncState; bool ignoreConnect = false; ShouldIgnoreConnect(tuple.Item2, ref ignoreConnect); if (ignoreConnect) { return; } var socket = tuple.Item1; var callback = tuple.Item2; socket.EndConnect(ar); var netStream = new NetworkStream(socket, false); var socketMode = callback == null ? SocketMode.Abort : callback.Connected(netStream, log); switch (socketMode) { case SocketMode.Poll: multiplexer.LogLocked(log, "Starting poll"); OnAddRead(socket, callback); break; case SocketMode.Async: multiplexer.LogLocked(log, "Starting read"); try { callback.StartReading(); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); Shutdown(socket); } break; default: ConnectionMultiplexer.TraceWithoutContext("Aborting socket"); Shutdown(socket); break; } } catch (ObjectDisposedException) { multiplexer.LogLocked(log, "(socket shutdown)"); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } catch (Exception outer) { ConnectionMultiplexer.TraceWithoutContext(outer.Message); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } }
internal SocketToken BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log) { var addressFamily = endpoint.AddressFamily == AddressFamily.Unspecified ? AddressFamily.InterNetwork : endpoint.AddressFamily; var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); SetFastLoopbackOption(socket); socket.NoDelay = true; try { var connectCompletionType = CompletionType.Any; ShouldForceConnectCompletionType(ref connectCompletionType); var formattedEndpoint = Format.ToString(endpoint); var tuple = Tuple.Create(socket, callback); if (endpoint is DnsEndPoint dnsEndpoint) { // A work-around for a Mono bug in BeginConnect(EndPoint endpoint, AsyncCallback callback, object state) #if !FEATURE_THREADPOOL multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); socket.ConnectAsync(dnsEndpoint.Host, dnsEndpoint.Port).ContinueWith(t => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(t, multiplexer, log, tuple); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }); #else CompletionTypeHelper.RunWithCompletionType( cb => { multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); return(socket.BeginConnect(dnsEndpoint.Host, dnsEndpoint.Port, cb, tuple)); }, ar => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log, tuple); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }, connectCompletionType); #endif } else { #if !FEATURE_THREADPOOL multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); socket.ConnectAsync(endpoint).ContinueWith(t => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(t, multiplexer, log, tuple); }); #else CompletionTypeHelper.RunWithCompletionType( cb => { multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); return(socket.BeginConnect(endpoint, cb, tuple)); }, ar => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log, tuple); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }, connectCompletionType); #endif } } catch (NotImplementedException ex) { if (!(endpoint is IPEndPoint)) { throw new InvalidOperationException("BeginConnect failed with NotImplementedException; consider using IP endpoints, or enable ResolveDns in the configuration", ex); } throw; } var token = new SocketToken(socket); return(token); }
internal SocketToken BeginConnect(EndPoint endpoint, ISocketCallback callback, ConnectionMultiplexer multiplexer, TextWriter log) { void RunWithCompletionType(Func <AsyncCallback, IAsyncResult> beginAsync, AsyncCallback asyncCallback) { void proxyCallback(IAsyncResult ar) { if (!ar.CompletedSynchronously) { asyncCallback(ar); } } var result = beginAsync(proxyCallback); if (result.CompletedSynchronously) { result.AsyncWaitHandle.WaitOne(); asyncCallback(result); } } var addressFamily = endpoint.AddressFamily == AddressFamily.Unspecified ? AddressFamily.InterNetwork : endpoint.AddressFamily; var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp); SetFastLoopbackOption(socket); socket.NoDelay = true; try { var formattedEndpoint = Format.ToString(endpoint); var tuple = Tuple.Create(socket, callback); multiplexer.LogLocked(log, "BeginConnect: {0}", formattedEndpoint); // A work-around for a Mono bug in BeginConnect(EndPoint endpoint, AsyncCallback callback, object state) if (endpoint is DnsEndPoint dnsEndpoint) { RunWithCompletionType( cb => socket.BeginConnect(dnsEndpoint.Host, dnsEndpoint.Port, cb, tuple), ar => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log, tuple); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }); } else { RunWithCompletionType( cb => socket.BeginConnect(endpoint, cb, tuple), ar => { multiplexer.LogLocked(log, "EndConnect: {0}", formattedEndpoint); EndConnectImpl(ar, multiplexer, log, tuple); multiplexer.LogLocked(log, "Connect complete: {0}", formattedEndpoint); }); } } catch (NotImplementedException ex) { if (!(endpoint is IPEndPoint)) { throw new InvalidOperationException("BeginConnect failed with NotImplementedException; consider using IP endpoints, or enable ResolveDns in the configuration", ex); } throw; } var token = new SocketToken(socket); return(token); }
private void EndConnectImpl(IAsyncResult ar, ConnectionMultiplexer multiplexer, TextWriter log, Tuple<Socket, ISocketCallback> tuple) { try { bool ignoreConnect = false; ShouldIgnoreConnect(tuple.Item2, ref ignoreConnect); if (ignoreConnect) return; var socket = tuple.Item1; var callback = tuple.Item2; #if CORE_CLR multiplexer.Wait((Task)ar); // make it explode if invalid (note: already complete at this point) #else socket.EndConnect(ar); #endif var netStream = new NetworkStream(socket, false); var socketMode = callback?.Connected(netStream, log) ?? SocketMode.Abort; switch (socketMode) { case SocketMode.Poll: multiplexer.LogLocked(log, "Starting poll"); OnAddRead(socket, callback); break; case SocketMode.Async: multiplexer.LogLocked(log, "Starting read"); try { callback.StartReading(); } catch (Exception ex) { ConnectionMultiplexer.TraceWithoutContext(ex.Message); Shutdown(socket); } break; default: ConnectionMultiplexer.TraceWithoutContext("Aborting socket"); Shutdown(socket); break; } } catch (ObjectDisposedException) { multiplexer.LogLocked(log, "(socket shutdown)"); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } catch(Exception outer) { ConnectionMultiplexer.TraceWithoutContext(outer.Message); if (tuple != null) { try { tuple.Item2.Error(); } catch (Exception inner) { ConnectionMultiplexer.TraceWithoutContext(inner.Message); } } } }