private unsafe IPEndPoint Start(QuicListenerOptions options) { List <SslApplicationProtocol> applicationProtocols = options.ServerAuthenticationOptions !.ApplicationProtocols !; IPEndPoint listenEndPoint = options.ListenEndPoint !; SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet(listenEndPoint); uint status; Debug.Assert(_stateHandle.IsAllocated); MemoryHandle[]? handles = null; QuicBuffer[]? buffers = null; try { MsQuicAlpnHelper.Prepare(applicationProtocols, out handles, out buffers); status = MsQuicApi.Api.ListenerStartDelegate(_state.Handle, (QuicBuffer *)Marshal.UnsafeAddrOfPinnedArrayElement(buffers, 0), (uint)applicationProtocols.Count, ref address); } catch { _stateHandle.Free(); throw; } finally { MsQuicAlpnHelper.Return(ref handles, ref buffers); } QuicExceptionHelpers.ThrowIfFailed(status, "ListenerStart failed."); SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS); return(MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress)); }
internal override unsafe void Start() { ThrowIfDisposed(); SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet(_listenEndPoint); uint status; MemoryHandle[]? handles = null; QuicBuffer[]? buffers = null; try { MsQuicAlpnHelper.Prepare(_applicationProtocols, out handles, out buffers); status = MsQuicApi.Api.ListenerStartDelegate(_state.Handle, (QuicBuffer *)Marshal.UnsafeAddrOfPinnedArrayElement(buffers, 0), (uint)_applicationProtocols.Count, ref address); } finally { MsQuicAlpnHelper.Return(ref handles, ref buffers); } QuicExceptionHelpers.ThrowIfFailed(status, "ListenerStart failed."); SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _state.Handle, QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS); _listenEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress); }
internal unsafe uint ListenerCallbackHandler( ref ListenerEvent evt) { try { switch (evt.Type) { case QUIC_LISTENER_EVENT.NEW_CONNECTION: { NewConnectionInfo connectionInfo = *(NewConnectionInfo *)evt.Data.NewConnection.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(*(SOCKADDR_INET *)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(*(SOCKADDR_INET *)connectionInfo.RemoteAddress); MsQuicConnection msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, evt.Data.NewConnection.Connection); _acceptConnectionQueue.Writer.TryWrite(msQuicConnection); } // Always pend the new connection to wait for the security config to be resolved // TODO this doesn't need to be async always return(MsQuicStatusCodes.Pending); default: return(MsQuicStatusCodes.InternalError); } } catch (Exception ex) { Console.WriteLine(ex.Message); return(MsQuicStatusCodes.InternalError); } }
internal override void Start() { ThrowIfDisposed(); SetCallbackHandler(); SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet(_listenEndPoint); MsQuicStatusException.ThrowIfFailed(MsQuicApi.Api.ListenerStartDelegate( _ptr, ref address)); SetListenPort(); }
private uint HandleEventConnected(ConnectionEvent connectionEvent) { SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS); _localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(inetAddress); _connected = true; // I don't believe we need to lock here because // handle event connected will not be called at the same time as // handle event shutdown initiated by transport _connectTcs.Complete(MsQuicStatusCodes.Success); return(MsQuicStatusCodes.Success); }
private static uint HandleEventConnected(State state, ref ConnectionEvent connectionEvent) { if (state.Connected) { return(MsQuicStatusCodes.Success); } if (state.IsServer) { state.Connected = true; MsQuicListener.State?listenerState = state.ListenerState; state.ListenerState = null; if (listenerState != null) { if (listenerState.PendingConnections.TryRemove(state.Handle.DangerousGetHandle(), out MsQuicConnection? connection)) { // Move connection from pending to Accept queue and hand it out. if (listenerState.AcceptConnectionQueue.Writer.TryWrite(connection)) { return(MsQuicStatusCodes.Success); } // Listener is closed connection.Dispose(); } } return(MsQuicStatusCodes.UserCanceled); } else { // Connected will already be true for connections accepted from a listener. Debug.Assert(!Monitor.IsEntered(state)); SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS); Debug.Assert(state.Connection != null); state.Connection._localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress); state.Connection.SetNegotiatedAlpn(connectionEvent.Data.Connected.NegotiatedAlpn, connectionEvent.Data.Connected.NegotiatedAlpnLength); state.Connection = null; state.Connected = true; state.ConnectTcs !.SetResult(MsQuicStatusCodes.Success); state.ConnectTcs = null; } return(MsQuicStatusCodes.Success); }
private uint HandleEventConnected(ref ConnectionEvent connectionEvent) { if (!_connected) { // _connected will already be true for connections accepted from a listener. SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS); _localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress); SetNegotiatedAlpn(connectionEvent.Data.Connected.NegotiatedAlpn, connectionEvent.Data.Connected.NegotiatedAlpnLength); _connected = true; _connectTcs.SetResult(MsQuicStatusCodes.Success); } return(MsQuicStatusCodes.Success); }
private static unsafe uint NativeCallbackHandler( IntPtr listener, IntPtr context, ref ListenerEvent evt) { if (evt.Type != QUIC_LISTENER_EVENT.NEW_CONNECTION) { return(MsQuicStatusCodes.InternalError); } GCHandle gcHandle = GCHandle.FromIntPtr(context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; SafeMsQuicConnectionHandle?connectionHandle = null; try { ref NewConnectionInfo connectionInfo = ref *evt.Data.NewConnection.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.RemoteAddress); connectionHandle = new SafeMsQuicConnectionHandle(evt.Data.NewConnection.Connection); uint status = MsQuicApi.Api.ConnectionSetConfigurationDelegate(connectionHandle, state.ConnectionConfiguration); QuicExceptionHelpers.ThrowIfFailed(status, "ConnectionSetConfiguration failed."); var msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, connectionHandle, state.RemoteCertificateRequired, state.RevocationMode, state.RemoteCertificateValidationCallback); msQuicConnection.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength); if (!state.AcceptConnectionQueue.Writer.TryWrite(msQuicConnection)) { // This handle will be cleaned up by MsQuic. connectionHandle.SetHandleAsInvalid(); msQuicConnection.Dispose(); return(MsQuicStatusCodes.InternalError); } return(MsQuicStatusCodes.Success); }
private static uint HandleEventConnected(State state, ref ConnectionEvent connectionEvent) { if (!state.Connected) { // Connected will already be true for connections accepted from a listener. Debug.Assert(!Monitor.IsEntered(state)); SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.LOCAL_ADDRESS); Debug.Assert(state.Connection != null); state.Connection._localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress); state.Connection.SetNegotiatedAlpn(connectionEvent.Data.Connected.NegotiatedAlpn, connectionEvent.Data.Connected.NegotiatedAlpnLength); state.Connection = null; state.Connected = true; state.ConnectTcs !.SetResult(MsQuicStatusCodes.Success); state.ConnectTcs = null; } return(MsQuicStatusCodes.Success); }
internal unsafe uint ListenerCallbackHandler(ref ListenerEvent evt) { try { switch (evt.Type) { case QUIC_LISTENER_EVENT.NEW_CONNECTION: { ref NewConnectionInfo connectionInfo = ref *(NewConnectionInfo *)evt.Data.NewConnection.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.RemoteAddress); MsQuicConnection msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, evt.Data.NewConnection.Connection, _options.IdleTimeout); msQuicConnection.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength); _acceptConnectionQueue.Writer.TryWrite(msQuicConnection); } // Always pend the new connection to wait for the security config to be resolved // TODO this doesn't need to be async always return(MsQuicStatusCodes.Pending);
internal override void Start() { ThrowIfDisposed(); // protect against double starts. if (_started) { throw new QuicException("Cannot start Listener multiple times"); } _started = true; SetCallbackHandler(); SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet(_listenEndPoint); QuicExceptionHelpers.ThrowIfFailed(MsQuicApi.Api.ListenerStartDelegate( _ptr, ref address), "Failed to start listener."); SetListenPort(); }
internal override ValueTask ConnectAsync(CancellationToken cancellationToken = default) { ThrowIfDisposed(); if (_configuration is null) { throw new Exception($"{nameof(ConnectAsync)} must not be called on a connection obtained from a listener."); } QUIC_ADDRESS_FAMILY af = _remoteEndPoint.AddressFamily switch { AddressFamily.Unspecified => QUIC_ADDRESS_FAMILY.UNSPEC, AddressFamily.InterNetwork => QUIC_ADDRESS_FAMILY.INET, AddressFamily.InterNetworkV6 => QUIC_ADDRESS_FAMILY.INET6, _ => throw new Exception(SR.Format(SR.net_quic_unsupported_address_family, _remoteEndPoint.AddressFamily)) }; Debug.Assert(_state.StateGCHandle.IsAllocated); _state.Connection = this; uint status; string targetHost; int port; if (_remoteEndPoint is IPEndPoint) { SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet((IPEndPoint)_remoteEndPoint); unsafe { Debug.Assert(!Monitor.IsEntered(_state)); status = MsQuicApi.Api.SetParamDelegate(_state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, (uint)sizeof(SOCKADDR_INET), (byte *)&address); QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer."); } targetHost = _state.TargetHost ?? ((IPEndPoint)_remoteEndPoint).Address.ToString(); port = ((IPEndPoint)_remoteEndPoint).Port; } else if (_remoteEndPoint is DnsEndPoint) { // We don't have way how to set separate SNI and name for connection at this moment. targetHost = ((DnsEndPoint)_remoteEndPoint).Host; port = ((DnsEndPoint)_remoteEndPoint).Port; } else { throw new Exception($"Unsupported remote endpoint type '{_remoteEndPoint.GetType()}'."); } // We store TCS to local variable to avoid NRE if callbacks finish fast and set _state.ConnectTcs to null. var tcs = _state.ConnectTcs = new TaskCompletionSource <uint>(TaskCreationOptions.RunContinuationsAsynchronously); try { Debug.Assert(!Monitor.IsEntered(_state)); status = MsQuicApi.Api.ConnectionStartDelegate( _state.Handle, _configuration, af, targetHost, (ushort)port); QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer."); // this handle is ref counted by MsQuic, so safe to dispose here. _configuration.Dispose(); _configuration = null; } catch { _state.StateGCHandle.Free(); _state.Connection = null; throw; } return(new ValueTask(tcs.Task)); }
private void SetListenPort() { SOCKADDR_INET inetAddress = MsQuicParameterHelpers.GetINetParam(MsQuicApi.Api, _ptr, (uint)QUIC_PARAM_LEVEL.LISTENER, (uint)QUIC_PARAM_LISTENER.LOCAL_ADDRESS); _listenEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref inetAddress); }
private static unsafe uint NativeCallbackHandler( IntPtr listener, IntPtr context, ListenerEvent *evt) { GCHandle gcHandle = GCHandle.FromIntPtr(context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; if (evt->Type != QUIC_LISTENER_EVENT.NEW_CONNECTION) { return(MsQuicStatusCodes.InternalError); } SafeMsQuicConnectionHandle?connectionHandle = null; MsQuicConnection? msQuicConnection = null; try { ref NewConnectionInfo connectionInfo = ref *evt->Data.NewConnection.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint(ref *(SOCKADDR_INET *)connectionInfo.RemoteAddress); string targetHost = string.Empty; // compat with SslStream if (connectionInfo.ServerNameLength > 0 && connectionInfo.ServerName != IntPtr.Zero) { // TBD We should figure out what to do with international names. targetHost = Marshal.PtrToStringAnsi(connectionInfo.ServerName, connectionInfo.ServerNameLength); } SafeMsQuicConfigurationHandle?connectionConfiguration = state.ConnectionConfiguration; if (connectionConfiguration == null) { Debug.Assert(state.AuthenticationOptions.ServerCertificateSelectionCallback != null); try { // ServerCertificateSelectionCallback is synchronous. We will call it as needed when building configuration connectionConfiguration = SafeMsQuicConfigurationHandle.Create(state.ConnectionOptions, state.AuthenticationOptions, targetHost); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(state, $"[Listener#{state.GetHashCode()}] Exception occurred during creating configuration in connection callback: {ex}"); } } if (connectionConfiguration == null) { // We don't have safe handle yet so MsQuic will cleanup new connection. return(MsQuicStatusCodes.InternalError); } } connectionHandle = new SafeMsQuicConnectionHandle(evt->Data.NewConnection.Connection); uint status = MsQuicApi.Api.ConnectionSetConfigurationDelegate(connectionHandle, connectionConfiguration); if (MsQuicStatusHelper.SuccessfulStatusCode(status)) { msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, state, connectionHandle, state.AuthenticationOptions.ClientCertificateRequired, state.AuthenticationOptions.CertificateRevocationCheckMode, state.AuthenticationOptions.RemoteCertificateValidationCallback); msQuicConnection.SetNegotiatedAlpn(connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength); if (!state.PendingConnections.TryAdd(connectionHandle.DangerousGetHandle(), msQuicConnection)) { msQuicConnection.Dispose(); } return(MsQuicStatusCodes.Success); } // If we fall-through here something wrong happened. }
internal override ValueTask ConnectAsync(CancellationToken cancellationToken = default) { ThrowIfDisposed(); if (_configuration is null) { throw new InvalidOperationException($"{nameof(ConnectAsync)} must not be called on a connection obtained from a listener."); } QUIC_ADDRESS_FAMILY af = _remoteEndPoint.AddressFamily switch { AddressFamily.Unspecified => QUIC_ADDRESS_FAMILY.UNSPEC, AddressFamily.InterNetwork => QUIC_ADDRESS_FAMILY.INET, AddressFamily.InterNetworkV6 => QUIC_ADDRESS_FAMILY.INET6, _ => throw new ArgumentException(SR.Format(SR.net_quic_unsupported_address_family, _remoteEndPoint.AddressFamily)) }; Debug.Assert(_state.StateGCHandle.IsAllocated); _state.Connection = this; uint status; string targetHost; int port; if (_remoteEndPoint is IPEndPoint) { SOCKADDR_INET address = MsQuicAddressHelpers.IPEndPointToINet((IPEndPoint)_remoteEndPoint); unsafe { Debug.Assert(!Monitor.IsEntered(_state)); status = MsQuicApi.Api.SetParamDelegate(_state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, (uint)sizeof(SOCKADDR_INET), (byte *)&address); QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer."); } targetHost = _state.TargetHost ?? ((IPEndPoint)_remoteEndPoint).Address.ToString(); port = ((IPEndPoint)_remoteEndPoint).Port; } else if (_remoteEndPoint is DnsEndPoint) { port = ((DnsEndPoint)_remoteEndPoint).Port; string dnsHost = ((DnsEndPoint)_remoteEndPoint).Host !; // We don't have way how to set separate SNI and name for connection at this moment. // If the name is actually IP address we can use it to make at least some cases work for people // who want to bypass DNS but connect to specific virtual host. if (!string.IsNullOrEmpty(_state.TargetHost) && !dnsHost.Equals(_state.TargetHost, StringComparison.InvariantCultureIgnoreCase) && IPAddress.TryParse(dnsHost, out IPAddress? address)) { // This is form of IPAddress and _state.TargetHost is set to different string SOCKADDR_INET quicAddress = MsQuicAddressHelpers.IPEndPointToINet(new IPEndPoint(address, port)); unsafe { Debug.Assert(!Monitor.IsEntered(_state)); status = MsQuicApi.Api.SetParamDelegate(_state.Handle, QUIC_PARAM_LEVEL.CONNECTION, (uint)QUIC_PARAM_CONN.REMOTE_ADDRESS, (uint)sizeof(SOCKADDR_INET), (byte *)&quicAddress); QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer."); } targetHost = _state.TargetHost !; } else { targetHost = dnsHost; } } else { throw new ArgumentException($"Unsupported remote endpoint type '{_remoteEndPoint.GetType()}'."); } // We store TCS to local variable to avoid NRE if callbacks finish fast and set _state.ConnectTcs to null. var tcs = _state.ConnectTcs = new TaskCompletionSource <uint>(TaskCreationOptions.RunContinuationsAsynchronously); try { Debug.Assert(!Monitor.IsEntered(_state)); status = MsQuicApi.Api.ConnectionStartDelegate( _state.Handle, _configuration, af, targetHost, (ushort)port); QuicExceptionHelpers.ThrowIfFailed(status, "Failed to connect to peer."); // this handle is ref counted by MsQuic, so safe to dispose here. _configuration.Dispose(); _configuration = null; } catch { _state.StateGCHandle.Free(); _state.Connection = null; throw; } return(new ValueTask(tcs.Task)); }
#pragma warning restore CS3016 private static unsafe int NativeCallback(QUIC_HANDLE *listener, void *context, QUIC_LISTENER_EVENT *listenerEvent) { GCHandle gcHandle = GCHandle.FromIntPtr((IntPtr)context); Debug.Assert(gcHandle.IsAllocated); Debug.Assert(gcHandle.Target is not null); var state = (State)gcHandle.Target; if (listenerEvent->Type == QUIC_LISTENER_EVENT_TYPE.STOP_COMPLETE) { state.StopCompletion.TrySetResult(); return(QUIC_STATUS_SUCCESS); } if (listenerEvent->Type != QUIC_LISTENER_EVENT_TYPE.NEW_CONNECTION) { return(QUIC_STATUS_INTERNAL_ERROR); } SafeMsQuicConnectionHandle?connectionHandle = null; MsQuicConnection? msQuicConnection = null; try { ref QUIC_NEW_CONNECTION_INFO connectionInfo = ref *listenerEvent->NEW_CONNECTION.Info; IPEndPoint localEndPoint = MsQuicAddressHelpers.INetToIPEndPoint((IntPtr)connectionInfo.LocalAddress); IPEndPoint remoteEndPoint = MsQuicAddressHelpers.INetToIPEndPoint((IntPtr)connectionInfo.RemoteAddress); string targetHost = string.Empty; // compat with SslStream if (connectionInfo.ServerNameLength > 0 && (IntPtr)connectionInfo.ServerName != IntPtr.Zero) { // TBD We should figure out what to do with international names. targetHost = Marshal.PtrToStringAnsi((IntPtr)connectionInfo.ServerName, connectionInfo.ServerNameLength); } SafeMsQuicConfigurationHandle?connectionConfiguration = state.ConnectionConfiguration; if (connectionConfiguration == null) { Debug.Assert(state.AuthenticationOptions.ServerCertificateSelectionCallback != null); try { // ServerCertificateSelectionCallback is synchronous. We will call it as needed when building configuration connectionConfiguration = SafeMsQuicConfigurationHandle.Create(state.ConnectionOptions, state.AuthenticationOptions, targetHost); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(state, $"[Listener#{state.GetHashCode()}] Exception occurred during creating configuration in connection callback: {ex}"); } } if (connectionConfiguration == null) { // We don't have safe handle yet so MsQuic will cleanup new connection. return(QUIC_STATUS_INTERNAL_ERROR); } } connectionHandle = new SafeMsQuicConnectionHandle(listenerEvent->NEW_CONNECTION.Connection); Debug.Assert(!Monitor.IsEntered(state), "!Monitor.IsEntered(state)"); int status = MsQuicApi.Api.ApiTable->ConnectionSetConfiguration(connectionHandle.QuicHandle, connectionConfiguration.QuicHandle); if (StatusSucceeded(status)) { msQuicConnection = new MsQuicConnection(localEndPoint, remoteEndPoint, state, connectionHandle, state.AuthenticationOptions.ClientCertificateRequired, state.AuthenticationOptions.CertificateRevocationCheckMode, state.AuthenticationOptions.RemoteCertificateValidationCallback); msQuicConnection.SetNegotiatedAlpn((IntPtr)connectionInfo.NegotiatedAlpn, connectionInfo.NegotiatedAlpnLength); if (!state.PendingConnections.TryAdd(connectionHandle.DangerousGetHandle(), msQuicConnection)) { msQuicConnection.Dispose(); } return(QUIC_STATUS_SUCCESS); } // If we fall-through here something wrong happened. }