public IqEventArgs(Iq stanza) { stanza.ThrowIfNull <Iq>("stanza"); this.Stanza = stanza; }
/// <summary> /// Initializes a new instance of the IqEventArgs class. /// </summary> /// <param name="stanza">The IQ stanza on whose behalf the event is /// raised.</param> /// <exception cref="ArgumentNullException">The stanza parameter is null.</exception> public IqEventArgs(Iq stanza) { stanza.ThrowIfNull("stanza"); Stanza = stanza; }
/// <summary> /// Listens for incoming XML stanzas and raises the appropriate events. /// </summary> /// <remarks>This runs in the context of a separate thread. In case of an /// exception, the Error event is raised and the thread is shutdown.</remarks> void ReadXmlStream() { try { while (true) { XmlElement elem = parser.NextElement("iq", "message", "presence"); // Parse element and dispatch. switch (elem.Name) { case "iq": Iq iq = new Iq(elem); if (iq.IsRequest) stanzaQueue.Add(iq); else HandleIqResponse(iq); break; case "message": stanzaQueue.Add(new Message(elem)); break; case "presence": stanzaQueue.Add(new Presence(elem)); break; } } } catch (Exception e) { // Shut down the dispatcher task. cancelDispatch.Cancel(); cancelDispatch = new CancellationTokenSource(); // Unblock any threads blocking on pending IQ requests. cancelIq.Cancel(); cancelIq = new CancellationTokenSource(); // Raise the error event. if(!disposed) Error.Raise(this, new ErrorEventArgs(e)); } }
/// <summary> /// Sends an IQ response for the IQ request with the specified id. /// </summary> /// <param name="response">The IQ response to send.</param> /// <exception cref="ArgumentNullException">The response parameter is /// null.</exception> /// <exception cref="ArgumentException">The Type property of the response /// parameter is not IqType.Result or IqType.Error.</exception> /// <exception cref="ObjectDisposedException">The XmppCore object has been /// disposed.</exception> /// <exception cref="InvalidOperationException">The XmppCore instance is not /// connected to a remote host.</exception> /// <exception cref="IOException">There was a failure while writing to the /// network.</exception> public void IqResponse(Iq response) { AssertValid(); response.ThrowIfNull("response"); if (response.Type != IqType.Result && response.Type != IqType.Error) throw new ArgumentException("The IQ type must be either 'result' or 'error'."); Send(response); }
/// <summary> /// Performs an IQ set/get request asynchronously and optionally invokes a /// callback method when the IQ response comes in. /// </summary> /// <param name="request">The IQ request to send.</param> /// <param name="callback">A callback method which is invoked once the /// IQ response from the server comes in.</param> /// <returns>The ID value of the pending IQ stanza request.</returns> /// <exception cref="ArgumentNullException">The request parameter is null.</exception> /// <exception cref="ArgumentException">The type parameter is not IqType.Set /// or IqType.Get.</exception> /// <exception cref="ObjectDisposedException">The XmppCore object has been /// disposed.</exception> /// <exception cref="InvalidOperationException">The XmppCore instance is not /// connected to a remote host.</exception> /// <exception cref="IOException">There was a failure while writing to the /// network.</exception> public string IqRequestAsync(Iq request, Action<string, Iq> callback = null) { AssertValid(); request.ThrowIfNull("request"); if (request.Type != IqType.Set && request.Type != IqType.Get) throw new ArgumentException("The IQ type must be either 'set' or 'get'."); request.Id = GetId(); // Register the callback. if (callback != null) iqCallbacks[request.Id] = callback; Send(request); return request.Id; }
/// <summary> /// Performs an IQ set/get request and blocks until the response IQ comes in. /// </summary> /// <param name="request">The IQ request to send.</param> /// <param name="millisecondsTimeout">The number of milliseconds to wait /// for the arrival of the IQ response or -1 to wait indefinitely.</param> /// <returns>The IQ response sent by the server.</returns> /// <exception cref="ArgumentNullException">The request parameter is null.</exception> /// <exception cref="ArgumentException">The type parameter is not IqType.Set /// or IqType.Get.</exception> /// <exception cref="ArgumentOutOfRangeException">The value of millisecondsTimeout /// is a negative number other than -1, which represents an indefinite /// timeout.</exception> /// <exception cref="ObjectDisposedException">The XmppCore object has been /// disposed.</exception> /// <exception cref="InvalidOperationException">The XmppCore instance is not /// connected to a remote host.</exception> /// <exception cref="IOException">There was a failure while writing to the /// network, or there was a failure reading from the network.</exception> /// <exception cref="TimeoutException">A timeout was specified and it /// expired.</exception> public Iq IqRequest(Iq request, int millisecondsTimeout = -1) { AssertValid(); request.ThrowIfNull("request"); if (request.Type != IqType.Set && request.Type != IqType.Get) throw new ArgumentException("The IQ type must be either 'set' or 'get'."); // Generate a unique ID for the IQ request. request.Id = GetId(); AutoResetEvent ev = new AutoResetEvent(false); Send(request); // Wait for event to be signaled by task that processes the incoming // XML stream. waitHandles[request.Id] = ev; int index = WaitHandle.WaitAny(new WaitHandle[] { ev, cancelIq.Token.WaitHandle }, millisecondsTimeout); if (index == WaitHandle.WaitTimeout) throw new TimeoutException(); // Reader task errored out. if (index == 1) throw new IOException("The incoming XML stream could not read."); // Fetch response stanza. Iq response; if (iqResponses.TryRemove(request.Id, out response)) return response; // Shouldn't happen. throw new InvalidOperationException(); }
/// <summary> /// Handles incoming IQ responses for previously issued IQ requests. /// </summary> /// <param name="iq">The received IQ response stanza.</param> void HandleIqResponse(Iq iq) { string id = iq.Id; AutoResetEvent ev; Action<string, Iq> cb; iqResponses[id] = iq; // Signal the event if it's a blocking call. if (waitHandles.TryRemove(id, out ev)) ev.Set(); // Call the callback if it's an asynchronous call. else if (iqCallbacks.TryRemove(id, out cb)) Task.Factory.StartNew(() => { cb(id, iq); }); }