< Summary

Information
Class: Ice.Internal.ConnectRequestHandler
Assembly: Ice
File(s): /_/csharp/src/Ice/Internal/ConnectRequestHandler.cs
Tag: 125_37167941578
Line coverage
72%
Covered lines: 67
Uncovered lines: 25
Coverable lines: 92
Total lines: 237
Line coverage: 72.8%
Branch coverage
63%
Covered branches: 23
Total branches: 36
Branch coverage: 63.8%
Method coverage
88%
Covered methods: 8
Fully covered methods: 5
Total methods: 9
Method coverage: 88.8%
Full method coverage: 55.5%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
sendAsyncRequest(...)100%44100%
asyncRequestCanceled(...)0%110100%
getConnection()100%11100%
setConnection(...)100%44100%
setException(...)100%44100%
addedProxy()100%11100%
initialized()87.5%8888.89%
flushRequests()66.67%7666.67%

File(s)

/_/csharp/src/Ice/Internal/ConnectRequestHandler.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Diagnostics;
 4
 5namespace Ice.Internal;
 6
 7internal class ConnectRequestHandler : RequestHandler, Reference.GetConnectionCallback, RouterInfo.AddProxyCallback
 8{
 19    internal ConnectRequestHandler(Reference reference)
 10    {
 111        _reference = reference;
 112        _response = reference.isTwoway;
 113    }
 14
 15    public int sendAsyncRequest(ProxyOutgoingAsyncBase outAsync)
 16    {
 117        lock (_mutex)
 18        {
 119            if (!_initialized)
 20            {
 121                outAsync.cancelable(this); // This will throw if the request is canceled
 22            }
 23
 124            if (!initialized())
 25            {
 126                _requests.AddLast(outAsync);
 127                return OutgoingAsyncBase.AsyncStatusQueued;
 28            }
 129        }
 130        return outAsync.invokeRemote(_connection, _compress, _response);
 131    }
 32
 33    public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
 34    {
 035        lock (_mutex)
 36        {
 037            if (_exception != null)
 38            {
 039                return; // The request has been notified of a failure already.
 40            }
 41
 042            if (!initialized())
 43            {
 044                LinkedListNode<ProxyOutgoingAsyncBase> p = _requests.First;
 045                while (p != null)
 46                {
 047                    if (p.Value == outAsync)
 48                    {
 049                        _requests.Remove(p);
 050                        if (outAsync.exception(ex))
 51                        {
 052                            outAsync.invokeExceptionAsync();
 53                        }
 054                        return;
 55                    }
 056                    p = p.Next;
 57                }
 58                Debug.Assert(false); // The request has to be queued if it timed out and we're not initialized yet.
 59            }
 060        }
 061        _connection.asyncRequestCanceled(outAsync, ex);
 062    }
 63
 64    public Ice.ConnectionI getConnection()
 65    {
 166        lock (_mutex)
 67        {
 68            // Return the connection in whatever state it is; if the connection establishment failed, return null.
 69            // Like all getConnection implementations, this method never throws: a null return is how the absence of a
 70            // connection is reported.
 171            return _connection;
 72        }
 173    }
 74
 75    //
 76    // Implementation of Reference.GetConnectionCallback
 77    //
 78
 79    public void setConnection(Ice.ConnectionI connection, bool compress)
 80    {
 181        lock (_mutex)
 82        {
 83            Debug.Assert(!_flushing && _exception == null && _connection == null);
 184            _connection = connection;
 185            _compress = compress;
 186        }
 87
 88        //
 89        // If this proxy is for a non-local object, and we are using a router, then
 90        // add this proxy to the router info object.
 91        //
 192        RouterInfo ri = _reference.getRouterInfo();
 193        if (ri != null && !ri.addProxy(_reference, this))
 94        {
 195            return; // The request handler will be initialized once addProxy returns.
 96        }
 97
 98        //
 99        // We can now send the queued requests.
 100        //
 1101        flushRequests();
 1102    }
 103
 104    public void setException(Ice.LocalException ex)
 105    {
 1106        lock (_mutex)
 107        {
 108            Debug.Assert(!_flushing && !_initialized && _exception == null);
 1109            _exception = ex;
 1110            _flushing = true; // Ensures request handler is removed before processing new requests.
 1111        }
 112
 1113        foreach (ProxyOutgoingAsyncBase outAsync in _requests)
 114        {
 1115            if (outAsync.exception(_exception))
 116            {
 1117                outAsync.invokeExceptionAsync();
 118            }
 119        }
 1120        _requests.Clear();
 121
 1122        lock (_mutex)
 123        {
 1124            _flushing = false;
 1125            Monitor.PulseAll(_mutex);
 1126        }
 1127    }
 128
 129    //
 130    // Implementation of RouterInfo.AddProxyCallback
 131    //
 132    public void addedProxy() =>
 133        //
 134        // The proxy was added to the router info, we're now ready to send the
 135        // queued requests.
 136        //
 1137        flushRequests();
 138
 139    private bool initialized()
 140    {
 1141        if (_initialized)
 142        {
 143            Debug.Assert(_connection != null);
 1144            return true;
 145        }
 146        else
 147        {
 1148            while (_flushing)
 149            {
 1150                Monitor.Wait(_mutex);
 151            }
 152
 1153            if (_exception != null)
 154            {
 1155                if (_connection != null)
 156                {
 157                    //
 158                    // Only throw if the connection didn't get established. If
 159                    // it died after being established, we allow the caller to
 160                    // retry the connection establishment by not throwing here
 161                    // (the connection will throw RetryException).
 162                    //
 0163                    return true;
 164                }
 1165                throw _exception;
 166            }
 167            else
 168            {
 1169                return _initialized;
 170            }
 171        }
 172    }
 173
 174    private void flushRequests()
 175    {
 1176        lock (_mutex)
 177        {
 178            Debug.Assert(_connection != null && !_initialized);
 179
 180            //
 181            // We set the _flushing flag to true to prevent any additional queuing. Callers
 182            // might block for a little while as the queued requests are being sent but this
 183            // shouldn't be an issue as the request sends are non-blocking.
 184            //
 1185            _flushing = true;
 1186        }
 187
 1188        Ice.LocalException exception = null;
 1189        foreach (ProxyOutgoingAsyncBase outAsync in _requests)
 190        {
 191            try
 192            {
 1193                if (
 1194                    (outAsync.invokeRemote(_connection, _compress, _response) &
 1195                    OutgoingAsyncBase.AsyncStatusInvokeSentCallback) != 0)
 196                {
 1197                    outAsync.invokeSentAsync();
 198                }
 1199            }
 0200            catch (RetryException ex)
 201            {
 0202                exception = ex.get();
 0203                outAsync.retryException();
 0204            }
 0205            catch (Ice.LocalException ex)
 206            {
 0207                exception = ex;
 0208                if (outAsync.exception(ex))
 209                {
 0210                    outAsync.invokeExceptionAsync();
 211                }
 0212            }
 213        }
 1214        _requests.Clear();
 215
 1216        lock (_mutex)
 217        {
 218            Debug.Assert(!_initialized);
 1219            _exception = exception;
 1220            _initialized = _exception == null;
 1221            _flushing = false;
 1222            Monitor.PulseAll(_mutex);
 1223        }
 1224    }
 225
 226    private readonly Reference _reference;
 227    private readonly bool _response;
 228
 229    private Ice.ConnectionI _connection;
 230    private bool _compress;
 231    private Ice.LocalException _exception;
 232    private bool _initialized;
 233    private bool _flushing;
 234
 1235    private readonly LinkedList<ProxyOutgoingAsyncBase> _requests = new();
 1236    private readonly object _mutex = new();
 237}