private void ActivateNewRequest(SafeCurlMultiHandle multiHandle, EasyRequest easy) { Debug.Assert(easy != null, "We should never get a null request"); Debug.Assert(easy._associatedMultiAgent == null, "New requests should not be associated with an agent yet"); // If cancellation has been requested, complete the request proactively if (easy._cancellationToken.IsCancellationRequested) { easy.FailRequest(new OperationCanceledException(easy._cancellationToken)); easy.Cleanup(); // no active processing remains, so cleanup return; } // Otherwise, configure it. Most of the configuration was already done when the EasyRequest // was created, but there's additional configuration we need to do specific to this // multi agent, specifically telling the easy request about its own GCHandle and setting // up callbacks for data processing. Once it's configured, add it to the multi handle. GCHandle gcHandle = GCHandle.Alloc(easy); IntPtr gcHandlePtr = GCHandle.ToIntPtr(gcHandle); try { easy._associatedMultiAgent = this; easy.SetCurlOption(CURLoption.CURLOPT_PRIVATE, gcHandlePtr); easy.SetCurlCallbacks(gcHandlePtr, s_receiveHeadersCallback, s_sendCallback, s_seekCallback, s_receiveBodyCallback); ThrowIfCURLMError(Interop.Http.MultiAddHandle(multiHandle, easy._easyHandle)); } catch (Exception exc) { gcHandle.Free(); easy.FailRequest(exc); easy.Cleanup(); // no active processing remains, so cleanup return; } // And if cancellation can be requested, hook up a cancellation callback. // This callback will put the easy request back into the queue, which will // ensure that a wake-up request has been issued. When we pull // the easy request out of the request queue, we'll see that it's already // associated with this agent, meaning that it's a cancellation request, // and we'll deal with it appropriately. var cancellationReg = default(CancellationTokenRegistration); if (easy._cancellationToken.CanBeCanceled) { cancellationReg = easy._cancellationToken.Register(s => { var state = (Tuple<MultiAgent, EasyRequest>)s; state.Item1.Queue(new IncomingRequest { Easy = state.Item2, Type = IncomingRequestType.Cancel }); }, Tuple.Create<MultiAgent, EasyRequest>(this, easy)); } // Finally, add it to our map. _activeOperations.Add( gcHandlePtr, new ActiveRequest { Easy = easy, CancellationRegistration = cancellationReg }); }