// // Summary: // Removes the first occurrence of a specific object from the eventsink list. // // Parameters: // subscription: // The eventsink object to remove from the eventsink list. The value // can be null. // public void Remove(DpwsWseEventSink eventSink) { lock (m_threadLock) { m_sinkList.Remove(eventSink); } }
/// <summary> /// Used by the subscription manager to send a subscription end message to a listening client. /// </summary> /// <param name="eventSink">An event sink object containing the client endpoint information.</param> /// <param name="subEndType">A string that specifies the reason fot the subscription end.</param> /// <param name="subMangerID">A id used by the client to identify this subcription.</param> /// <remarks>If an error occures when sending an event message this method is called to tell /// the client this subscription has been expired. /// </remarks> private void SendSubscriptionEnd(DpwsWseEventSink eventSink, string subEndType, string subMangerID) { // if we weren't given an EndTo, don't send if (eventSink.EndTo == null) { return; } SendEvent(SubscriptionEndResponse(eventSink, subEndType, subMangerID), eventSink.EndTo.Address); }
/// <summary> /// Use this method to raise an event. /// </summary> /// <param name="hostedService">The hosted service that contains the event source.</param> /// <param name="eventSource">The event source that define the event.</param> /// <param name="eventMessage">The event message buffer.</param> /// <remarks> /// A device developer is responsible for building the event message buffer sent /// to clients that have an active event subscription with an event source. The subscription manager /// uses the hosted service parameter to access various properties of the service. The event source /// parameter is used to access the event sinks collection of the event source. Note: This method /// requires special provisions in order to properly build event message headers for each event sink. /// In order to send an event to a listening client the soap.header.To property must be changed for /// each listening client. In the future custom attribute support will solve this problem. For now /// however a search and replace mechanism is used to modifiy the header.To property. When a device /// developer builds the event message buffer they must use the search string WSDNOTIFYTOADDRESS for /// the To header property. /// </remarks> public void FireEvent(DpwsHostedService hostedService, DpwsWseEventSource eventSource, WsMessage msgEvt) { // Find the specified event source if (eventSource == null) { throw new ArgumentNullException(); } DpwsWseEventSinks eventSinks = eventSource.EventSinks; // if there are event sources display message int count = eventSinks.Count; if (count > 0) { System.Ext.Console.Write(""); System.Ext.Console.Write("Firing " + eventSource.Name); System.Ext.Console.Write(""); } // Loop through event sinks and send the event message for (int i = count - 1; i >= 0; i--) { DpwsWseEventSink eventSink = eventSinks[i]; // Try to send event. If attempt fails delete the subscription/eventSink try { msgEvt.Header = new WsWsaHeader(msgEvt.Header.Action, msgEvt.Header.RelatesTo, eventSink.NotifyTo.Address.AbsoluteUri, null, null, eventSink.NotifyTo.RefParameters); SendEvent(msgEvt, eventSink.NotifyTo.Address); } catch (Exception e) { System.Ext.Console.Write(""); System.Ext.Console.Write("FireEvent failed. Deleting EventSink! NotifyToAddress = " + eventSink.NotifyTo.Address + " Exception: " + e.Message); System.Ext.Console.Write(""); if (!(e is WebException)) { try { // Send oneway subscription end message SendSubscriptionEnd(eventSink, "DeliveryFailure", hostedService.ServiceID); } catch { } } // Remove event sink from event source list eventSinks.RemoveAt(i); } } }
/// <summary> /// Used by the subscription manager to send a subscription end message to a listening client. /// </summary> /// <param name="eventSink">An event sink object containing the client endpoint information.</param> /// <param name="subEndType">A string that specifies the reason fot the subscription end.</param> /// <param name="subMangerID">A id used by the client to identify this subcription.</param> /// <remarks>If an error occures when sending an event message this method is called to tell /// the client this subscription has been expired. /// </remarks> private void SendSubscriptionEnd(DpwsWseEventSink eventSink, string subEndType, string subMangerID) { // if we weren't given an EndTo, don't send if (eventSink.EndTo == null) { return; } if (m_persistEventConnections) { eventSink.RequestChannel.Request(SubscriptionEndResponse(eventSink, subEndType, subMangerID)); } else { eventSink.RequestChannel.Open(); eventSink.RequestChannel.Request(SubscriptionEndResponse(eventSink, subEndType, subMangerID)); eventSink.RequestChannel.Close(); } }
// // Summary: // Adds an object to the end of the eventsink list. // // Parameters: // value: // The System.Object to be added to the end of the eventlist. // The value can be null. // // Returns: // The eventsink index at which the value has been added. // public int Add(DpwsWseEventSink value) { lock (m_threadLock) { // Ignore duplicate event sinks. Delete the current sink and add the new event sink. int count = m_sinkList.Count; String valueUri = value.NotifyTo.Address.AbsoluteUri.ToLower(); for (int i = 0; i < count; i++) { if (((DpwsWseEventSink)m_sinkList[i]).NotifyTo.Address.AbsoluteUri.ToLower() == valueUri) { m_sinkList.RemoveAt(i); break; } } return(m_sinkList.Add(value)); } }
/// <summary> /// This method build a subscription end message. /// </summary> /// <param name="eventSink">An event sink containing client endpoint information.</param> /// <param name="shutdownMessage">A string containing reason why the subscription is ending.</param> /// <param name="subMangerID">An id sent by the client that they use to reference a subscription.</param> /// <returns></returns> private byte[] SubscriptionEndResponse(DpwsWseEventSink eventSink, string shutdownMessage, string subMangerID) { MemoryStream soapStream = new MemoryStream(); XmlWriter xmlWriter = XmlWriter.Create(soapStream); WsWsaHeader responseHeader = new WsWsaHeader( WsWellKnownUri.WseNamespaceUri + "/SubscriptionEnd", // Action null, // RelatesTo eventSink.EndTo.Address.AbsoluteUri, // To null, null, eventSink.EndTo.RefProperties); // ReplyTo, From, Any WsSoapMessageWriter.WriteSoapMessageStart(xmlWriter, WsSoapMessageWriter.Prefixes.Wse, // Prefix null, // Additional Prefix responseHeader, // Header null); // AppSequence // write body xmlWriter.WriteStartElement("wse", "SubscriptionEnd", null); xmlWriter.WriteStartElement("wse", "SubscriptionManager", null); xmlWriter.WriteStartElement("wsa", "Address", null); xmlWriter.WriteString("http://" + Device.IPV4Address + ":" + Device.Port + "/" + subMangerID); xmlWriter.WriteEndElement(); // End Address xmlWriter.WriteStartElement("wsa", "ReferenceParameters", null); xmlWriter.WriteStartElement("wse", "Identifier", null); xmlWriter.WriteString(eventSink.ID); xmlWriter.WriteEndElement(); // End Identifier xmlWriter.WriteEndElement(); // End ReferenceParameters xmlWriter.WriteEndElement(); // End SubscriptionManager xmlWriter.WriteStartElement("wse", "Code", null); xmlWriter.WriteString("wse:" + shutdownMessage); xmlWriter.WriteEndElement(); // End Code xmlWriter.WriteEndElement(); // End SubscriptionEnd WsSoapMessageWriter.WriteSoapMessageEnd(xmlWriter); // Flush and close writer. Return stream buffer xmlWriter.Flush(); xmlWriter.Close(); return(soapStream.ToArray()); }
/// <summary> /// This method build a subscription end message. /// </summary> /// <param name="eventSink">An event sink containing client endpoint information.</param> /// <param name="shutdownMessage">A string containing reason why the subscription is ending.</param> /// <param name="subMangerID">An id sent by the client that they use to reference a subscription.</param> /// <returns></returns> private WsMessage SubscriptionEndResponse(DpwsWseEventSink eventSink, string shutdownMessage, string subMangerID) { using (XmlMemoryWriter xmlWriter = XmlMemoryWriter.Create()) { WsWsaHeader responseHeader = new WsWsaHeader( WsWellKnownUri.WseNamespaceUri + "/SubscriptionEnd", // Action null, // RelatesTo eventSink.EndTo.Address.AbsoluteUri, // To null, null, eventSink.EndTo.RefProperties); // ReplyTo, From, Any WsMessage msg = new WsMessage(responseHeader, null, WsPrefix.Wse, null, null); WsSoapMessageWriter smw = new WsSoapMessageWriter(m_version); smw.WriteSoapMessageStart(xmlWriter, msg); // write body xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscriptionEnd", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscriptionManager", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "Address", null); xmlWriter.WriteString("http://" + Device.IPV4Address + ":" + Device.Port + "/" + subMangerID); xmlWriter.WriteEndElement(); // End Address xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "ReferenceParameters", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Identifier", null); xmlWriter.WriteString(eventSink.ID); xmlWriter.WriteEndElement(); // End Identifier xmlWriter.WriteEndElement(); // End ReferenceParameters xmlWriter.WriteEndElement(); // End SubscriptionManager xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Code", null); xmlWriter.WriteString(WsNamespacePrefix.Wse + ":" + shutdownMessage); xmlWriter.WriteEndElement(); // End Code xmlWriter.WriteEndElement(); // End SubscriptionEnd smw.WriteSoapMessageEnd(xmlWriter); msg.Body = xmlWriter.ToArray(); // Return stream buffer return(msg); } }
/// <summary> /// Method used to expire events and send EndTo notification to an event sink /// </summary> public void EventService(object arg) { DateTime curDateTime = DateTime.Now; try { // Loop through hosted services int servicesCount = Device.HostedServices.Count; for (int i = 0; i < servicesCount; i++) { DpwsHostedService hostedService = (DpwsHostedService)Device.HostedServices[i]; // Loop through event sources int eventSourcesCount = hostedService.EventSources.Count; for (int j = 0; j < eventSourcesCount; j++) { DpwsWseEventSource eventSource = hostedService.EventSources[j]; // Loop through event sinks. Check expiration time. If an event has // expired send subscription end message and delete event sink. int eventSinkCount = eventSource.EventSinks.Count; for (int k = eventSinkCount - 1; k >= 0; k--) { DpwsWseEventSink eventSink = eventSource.EventSinks[k]; // If time has expired delete event sink if (eventSink.StartTime + eventSink.Expires > curDateTime.Ticks) { eventSource.EventSinks.RemoveAt(k); } } } } } catch (Exception e) { System.Ext.Console.Write("Event Queue Manager threw and exception. " + e.Message); } }
/// <summary> /// Used by the subscription manager to send a subscription end message to a listening client. /// </summary> /// <param name="eventSink">An event sink object containing the client endpoint information.</param> /// <param name="subEndType">A string that specifies the reason fot the subscription end.</param> /// <param name="subMangerID">A id used by the client to identify this subcription.</param> /// <remarks>If an error occures when sending an event message this method is called to tell /// the client this subscription has been expired. /// </remarks> private void SendSubscriptionEnd(DpwsWseEventSink eventSink, string subEndType, string subMangerID) { // if we weren't given an EndTo, don't send if (eventSink.EndTo == null) { return; } // Parse the http transport address if (eventSink.EndTo.Address.Scheme == "http") { WsHttpClient httpClient = new WsHttpClient(); httpClient.SendRequest(SubscriptionEndResponse(eventSink, subEndType, subMangerID), eventSink.EndTo.Address.AbsoluteUri, true, false); } else { System.Ext.Console.Write(""); System.Ext.Console.Write("Unsupported transport address Subscription EndTo.Address: " + eventSink.EndTo.Address); System.Ext.Console.Write(""); return; } }
/// <summary> /// Use this method to raise an event. /// </summary> /// <param name="hostedService">The hosted service that contains the event source.</param> /// <param name="eventSource">The event source that define the event.</param> /// <param name="eventMessage">The event message buffer.</param> /// <remarks> /// A device developer is responsible for building the event message buffer sent /// to clients that have an active event subscription with an event source. The subscription manager /// uses the hosted service parameter to access various properties of the service. The event source /// parameter is used to access the event sinks collection of the event source. Note: This method /// requires special provisions in order to properly build event message headers for each event sink. /// In order to send an event to a listening client the soap.header.To property must be changed for /// each listening client. In the future custom attribute support will solve this problem. For now /// however a search and replace mechanism is used to modifiy the header.To property. When a device /// developer builds the event message buffer they must use the search string WSDNOTIFYTOADDRESS for /// the To header property. /// </remarks> public void FireEvent(DpwsHostedService hostedService, DpwsWseEventSource eventSource, WsWsaHeader eventHeader, String eventMessageBody) { // Find the specified event source if (eventSource == null) { throw new ArgumentNullException("FireEvent could not locate specified hosted service"); } DpwsWseEventSinks eventSinks = eventSource.EventSinks; // if there are event sources display message int count = eventSinks.Count; if (count > 0) { System.Ext.Console.Write(""); System.Ext.Console.Write("Firing " + eventSource.Name); System.Ext.Console.Write(""); } // Loop through event sinks and send the event message for (int i = 0; i < count; i++) { DpwsWseEventSink eventSink = eventSinks[i]; // Try to send event. If attempt fails delete the subscription/eventSink try { MemoryStream soapStream = new MemoryStream(); XmlWriter xmlWriter = XmlWriter.Create(soapStream); WsWsaHeader header = new WsWsaHeader(eventHeader.Action, eventHeader.RelatesTo, eventSink.NotifyTo.Address.AbsoluteUri, null, null, eventSink.NotifyTo.RefParameters); WsSoapMessageWriter.WriteSoapMessageStart(xmlWriter, WsSoapMessageWriter.Prefixes.Wse, null, header, null); if (eventMessageBody != null) { xmlWriter.WriteRaw(eventMessageBody); } WsSoapMessageWriter.WriteSoapMessageEnd(xmlWriter); xmlWriter.Flush(); xmlWriter.Close(); SendEvent(soapStream.ToArray(), eventSink.NotifyTo.Address.AbsoluteUri); } catch (Exception e) { System.Ext.Console.Write(""); System.Ext.Console.Write("FireEvent failed. Deleting EventSink! NotifyToAddress = " + eventSink.NotifyTo.Address + " Exception: " + e.Message); System.Ext.Console.Write(""); // Send oneway subscription end message try { SendSubscriptionEnd(eventSink, "DeliveryFailure", hostedService.ServiceID); } catch { } // Remove event sink from event source list eventSinks.Remove(eventSink); } } }
/// <summary> /// Global eventing Subscribe stub. /// </summary> /// <param name="header">Header object.</param> /// <param name="reader">An XmlReader positioned at the begining of the Subscribe request body element.</param> /// <param name="serviceEndpoints">A Collection of serviceEndpoints used to determine what services contain the event source specified in the filter.</param> /// <returns>Byte array containing a Subscribe response.</returns> internal WsMessage Subscribe(WsWsaHeader header, XmlReader reader, WsServiceEndpoints serviceEndpoints) { WsMessage msg = null; // Parse Subscribe Request ///////////////////////////// DpwsWseEventSink eventSink = new DpwsWseEventSink(); try { reader.ReadStartElement("Subscribe", WsWellKnownUri.WseNamespaceUri); if (reader.IsStartElement("EndTo", WsWellKnownUri.WseNamespaceUri)) { eventSink.EndTo = new WsWsaEndpointRef(reader, m_version.AddressingNamespace); } reader.ReadStartElement("Delivery", WsWellKnownUri.WseNamespaceUri); if (reader.IsStartElement("NotifyTo", WsWellKnownUri.WseNamespaceUri)) { eventSink.NotifyTo = new WsWsaEndpointRef(reader, m_version.AddressingNamespace); } else { throw new WsFaultException(header, WsFaultType.WseDeliverModeRequestedUnavailable); } reader.ReadEndElement(); if (reader.IsStartElement("Expires", WsWellKnownUri.WseNamespaceUri)) { long expires = new WsDuration(reader.ReadElementString()).DurationInSeconds; if (expires > 0) { eventSink.Expires = expires; } else { throw new WsFaultException(header, WsFaultType.WseInvalidExpirationTime); } } else { // Never Expires eventSink.Expires = -1; } if (reader.IsStartElement("Filter", WsWellKnownUri.WseNamespaceUri)) { if (reader.MoveToAttribute("Dialect") == false || reader.Value != m_version.WsdpNamespaceUri + "/Action") { throw new WsFaultException(header, WsFaultType.WseFilteringRequestedUnavailable); } reader.MoveToElement(); String filters = reader.ReadElementString(); if (filters != String.Empty) { eventSink.Filters = filters.Split(' '); } } XmlReaderHelper.SkipAllSiblings(reader); reader.ReadEndElement(); // Subscribe } catch (XmlException e) { throw new WsFaultException(header, WsFaultType.WseInvalidMessage, e.ToString()); } // Parse urn:uuid from the To address string endpointAddress = FixToAddress(header.To); // Build a temporary collection of device services that match the specified endpoint address. WsServiceEndpoints matchingServices = new WsServiceEndpoints(); for (int i = 0; i < serviceEndpoints.Count; ++i) { if (serviceEndpoints[i].EndpointAddress == endpointAddress) { matchingServices.Add(serviceEndpoints[i]); } } // For each service with a matching endpoint and event sources add an event sink to the // event source collection for (int i = 0; i < matchingServices.Count; ++i) { DpwsWseEventSources eventSources = ((DpwsHostedService)matchingServices[i]).EventSources; // Set the EventSinkID eventSink.ID = "urn:uuid:" + Guid.NewGuid().ToString(); // If subscribing to all event sources if (eventSink.Filters == null) { int count = eventSources.Count; for (int ii = 0; i < count; i++) { DpwsWseEventSource eventSource = eventSources[ii]; eventSink.StartTime = DateTime.Now.Ticks; eventSource.EventSinks.Add(eventSink); } } else { // If subscribing to a specific event based on an event filter. DpwsWseEventSource eventSource; string[] filterList = eventSink.Filters; int length = filterList.Length; for (int ii = 0; i < length; i++) { if ((eventSource = eventSources[filterList[ii]]) != null) { eventSink.StartTime = DateTime.Now.Ticks; eventSource.EventSinks.Add(eventSink); } else { throw new Exception("Event source " + filterList[ii] + " was not found."); } } } } // Generate Response ////////////////////////// using (XmlMemoryWriter xmlWriter = XmlMemoryWriter.Create()) { WsWsaHeader responseHeader = new WsWsaHeader( WsWellKnownUri.WseNamespaceUri + "/SubscribeResponse", // Action header.MessageID, // RelatesTo header.ReplyTo.Address.AbsoluteUri, // To null, null, null); // ReplyTo, From, Any msg = new WsMessage(responseHeader, null, WsPrefix.Wse, null, new WsAppSequence(Device.AppSequence, Device.SequenceID, Device.MessageID)); WsSoapMessageWriter smw = new WsSoapMessageWriter(m_version); smw.WriteSoapMessageStart(xmlWriter, msg); // write body xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscribeResponse", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscriptionManager", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "Address", null); // Create a uri. Use the path (by default will be a uuid) for the sub manager endpoint Uri subMgrUri = new Uri(((DpwsHostedService)matchingServices[0]).EndpointAddress); xmlWriter.WriteString("http://" + Device.IPV4Address + ":" + Device.Port + "/" + subMgrUri.AbsolutePath); xmlWriter.WriteEndElement(); // End Address xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "ReferenceParameters", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Identifier", null); xmlWriter.WriteString(eventSink.ID); xmlWriter.WriteEndElement(); // End Identifier xmlWriter.WriteEndElement(); // End ReferenceParameters xmlWriter.WriteEndElement(); // End SubscriptionManager xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Expires", null); xmlWriter.WriteString(new WsDuration(eventSink.Expires).DurationString); xmlWriter.WriteEndElement(); // End Expires xmlWriter.WriteEndElement(); // End SubscribeResponse smw.WriteSoapMessageEnd(xmlWriter); // Return stream buffer msg.Body = xmlWriter.ToArray(); } return(msg); }
/// <summary> /// This method build a subscription end message. /// </summary> /// <param name="eventSink">An event sink containing client endpoint information.</param> /// <param name="shutdownMessage">A string containing reason why the subscription is ending.</param> /// <param name="subMangerID">An id sent by the client that they use to reference a subscription.</param> /// <returns></returns> private WsMessage SubscriptionEndResponse(DpwsWseEventSink eventSink, string shutdownMessage, string subMangerID) { using(XmlMemoryWriter xmlWriter = XmlMemoryWriter.Create()) { WsWsaHeader responseHeader = new WsWsaHeader( WsWellKnownUri.WseNamespaceUri + "/SubscriptionEnd", // Action null, // RelatesTo eventSink.EndTo.Address.AbsoluteUri, // To null, null, eventSink.EndTo.RefProperties); // ReplyTo, From, Any WsMessage msg = new WsMessage(responseHeader, null, WsPrefix.Wse, null, null); WsSoapMessageWriter smw = new WsSoapMessageWriter(m_version); smw.WriteSoapMessageStart(xmlWriter, msg); // write body xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscriptionEnd", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscriptionManager", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "Address", null); xmlWriter.WriteString("http://" + Device.IPV4Address + ":" + Device.Port + "/" + subMangerID); xmlWriter.WriteEndElement(); // End Address xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "ReferenceParameters", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Identifier", null); xmlWriter.WriteString(eventSink.ID); xmlWriter.WriteEndElement(); // End Identifier xmlWriter.WriteEndElement(); // End ReferenceParameters xmlWriter.WriteEndElement(); // End SubscriptionManager xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Code", null); xmlWriter.WriteString(WsNamespacePrefix.Wse + ":" + shutdownMessage); xmlWriter.WriteEndElement(); // End Code xmlWriter.WriteEndElement(); // End SubscriptionEnd smw.WriteSoapMessageEnd(xmlWriter); msg.Body = xmlWriter.ToArray(); // Return stream buffer return msg; } }
// // Summary: // Adds an object to the end of the eventsink list. // // Parameters: // value: // The System.Object to be added to the end of the eventlist. // The value can be null. // // Returns: // The eventsink index at which the value has been added. // public int Add(DpwsWseEventSink value) { lock (m_threadLock) { // Ignore duplicate event sinks. Delete the current sink and add the new event sink. int count = m_sinkList.Count; String valueUri = value.NotifyTo.Address.AbsoluteUri.ToLower(); for (int i = 0; i < count; i++) { if (((DpwsWseEventSink)m_sinkList[i]).NotifyTo.Address.AbsoluteUri.ToLower() == valueUri) { m_sinkList.RemoveAt(i); break; } } return m_sinkList.Add(value); } }
/// <summary> /// Used by the subscription manager to send a subscription end message to a listening client. /// </summary> /// <param name="eventSink">An event sink object containing the client endpoint information.</param> /// <param name="subEndType">A string that specifies the reason fot the subscription end.</param> /// <param name="subMangerID">A id used by the client to identify this subcription.</param> /// <remarks>If an error occures when sending an event message this method is called to tell /// the client this subscription has been expired. /// </remarks> private void SendSubscriptionEnd(DpwsWseEventSink eventSink, string subEndType, string subMangerID) { // if we weren't given an EndTo, don't send if (eventSink.EndTo == null) { return; } if(m_persistEventConnections) { eventSink.RequestChannel.Request(SubscriptionEndResponse(eventSink, subEndType, subMangerID)); } else { eventSink.RequestChannel.Open(); eventSink.RequestChannel.Request(SubscriptionEndResponse(eventSink, subEndType, subMangerID)); eventSink.RequestChannel.Close(); } }
/// <summary> /// This method build a subscription end message. /// </summary> /// <param name="eventSink">An event sink containing client endpoint information.</param> /// <param name="shutdownMessage">A string containing reason why the subscription is ending.</param> /// <param name="subMangerID">An id sent by the client that they use to reference a subscription.</param> /// <returns></returns> private byte[] SubscriptionEndResponse(DpwsWseEventSink eventSink, string shutdownMessage, string subMangerID) { MemoryStream soapStream = new MemoryStream(); XmlWriter xmlWriter = XmlWriter.Create(soapStream); WsWsaHeader responseHeader = new WsWsaHeader( WsWellKnownUri.WseNamespaceUri + "/SubscriptionEnd", // Action null, // RelatesTo eventSink.EndTo.Address.AbsoluteUri, // To null, null, eventSink.EndTo.RefProperties); // ReplyTo, From, Any WsSoapMessageWriter.WriteSoapMessageStart(xmlWriter, WsSoapMessageWriter.Prefixes.Wse, // Prefix null, // Additional Prefix responseHeader, // Header null); // AppSequence // write body xmlWriter.WriteStartElement("wse", "SubscriptionEnd", null); xmlWriter.WriteStartElement("wse", "SubscriptionManager", null); xmlWriter.WriteStartElement("wsa", "Address", null); xmlWriter.WriteString("http://" + Device.IPV4Address + ":" + Device.Port + "/" + subMangerID); xmlWriter.WriteEndElement(); // End Address xmlWriter.WriteStartElement("wsa", "ReferenceParameters", null); xmlWriter.WriteStartElement("wse", "Identifier", null); xmlWriter.WriteString(eventSink.ID); xmlWriter.WriteEndElement(); // End Identifier xmlWriter.WriteEndElement(); // End ReferenceParameters xmlWriter.WriteEndElement(); // End SubscriptionManager xmlWriter.WriteStartElement("wse", "Code", null); xmlWriter.WriteString("wse:" + shutdownMessage); xmlWriter.WriteEndElement(); // End Code xmlWriter.WriteEndElement(); // End SubscriptionEnd WsSoapMessageWriter.WriteSoapMessageEnd(xmlWriter); // Flush and close writer. Return stream buffer xmlWriter.Flush(); xmlWriter.Close(); return soapStream.ToArray(); }
/// <summary> /// Global eventing Subscribe stub. /// </summary> /// <param name="header">Header object.</param> /// <param name="reader">An XmlReader positioned at the begining of the Subscribe request body element.</param> /// <param name="serviceEndpoints">A Collection of serviceEndpoints used to determine what services contain the event source specified in the filter.</param> /// <returns>Byte array containing a Subscribe response.</returns> internal WsMessage Subscribe(WsWsaHeader header, XmlReader reader, WsServiceEndpoints serviceEndpoints) { WsMessage msg = null; // Parse Subscribe Request ///////////////////////////// DpwsWseEventSink eventSink = new DpwsWseEventSink(); try { reader.ReadStartElement("Subscribe", WsWellKnownUri.WseNamespaceUri); if (reader.IsStartElement("EndTo", WsWellKnownUri.WseNamespaceUri)) { eventSink.EndTo = new WsWsaEndpointRef(reader, m_version.AddressingNamespace); } reader.ReadStartElement("Delivery", WsWellKnownUri.WseNamespaceUri); if (reader.IsStartElement("NotifyTo", WsWellKnownUri.WseNamespaceUri)) { eventSink.NotifyTo = new WsWsaEndpointRef(reader, m_version.AddressingNamespace); } else { throw new WsFaultException(header, WsFaultType.WseDeliverModeRequestedUnavailable); } reader.ReadEndElement(); if (reader.IsStartElement("Expires", WsWellKnownUri.WseNamespaceUri)) { long expires = new WsDuration(reader.ReadElementString()).DurationInSeconds; if (expires > 0) { eventSink.Expires = expires; } else { throw new WsFaultException(header, WsFaultType.WseInvalidExpirationTime); } } else { // Never Expires eventSink.Expires = -1; } if (reader.IsStartElement("Filter", WsWellKnownUri.WseNamespaceUri)) { if (reader.MoveToAttribute("Dialect") == false || reader.Value != m_version.WsdpNamespaceUri + "/Action") { throw new WsFaultException(header, WsFaultType.WseFilteringRequestedUnavailable); } reader.MoveToElement(); String filters = reader.ReadElementString(); if (filters != String.Empty) { eventSink.Filters = filters.Split(' '); } } XmlReaderHelper.SkipAllSiblings(reader); reader.ReadEndElement(); // Subscribe } catch (XmlException e) { throw new WsFaultException(header, WsFaultType.WseInvalidMessage, e.ToString()); } // Parse urn:uuid from the To address string endpointAddress = FixToAddress(header.To); // Build a temporary collection of device services that match the specified endpoint address. WsServiceEndpoints matchingServices = new WsServiceEndpoints(); for (int i = 0; i < serviceEndpoints.Count; ++i) { if (serviceEndpoints[i].EndpointAddress == endpointAddress) matchingServices.Add(serviceEndpoints[i]); } // For each service with a matching endpoint and event sources add an event sink to the // event source collection for (int i = 0; i < matchingServices.Count; ++i) { DpwsWseEventSources eventSources = ((DpwsHostedService)matchingServices[i]).EventSources; // Set the EventSinkID eventSink.ID = "urn:uuid:" + Guid.NewGuid().ToString(); // If subscribing to all event sources if (eventSink.Filters == null) { int count = eventSources.Count; for (int ii = 0; i < count; i++) { DpwsWseEventSource eventSource = eventSources[ii]; eventSink.StartTime = DateTime.Now.Ticks; eventSource.EventSinks.Add(eventSink); } } else { // If subscribing to a specific event based on an event filter. DpwsWseEventSource eventSource; string[] filterList = eventSink.Filters; int length = filterList.Length; for (int ii = 0; i < length; i++) { if ((eventSource = eventSources[filterList[ii]]) != null) { eventSink.StartTime = DateTime.Now.Ticks; eventSource.EventSinks.Add(eventSink); } else { throw new Exception("Event source " + filterList[ii] + " was not found."); } } } } // Generate Response ////////////////////////// using(XmlMemoryWriter xmlWriter = XmlMemoryWriter.Create()) { WsWsaHeader responseHeader = new WsWsaHeader( WsWellKnownUri.WseNamespaceUri + "/SubscribeResponse", // Action header.MessageID, // RelatesTo header.ReplyTo.Address.AbsoluteUri, // To null, null, null); // ReplyTo, From, Any msg = new WsMessage(responseHeader, null, WsPrefix.Wse, null, new WsAppSequence(Device.AppSequence, Device.SequenceID, Device.MessageID)); WsSoapMessageWriter smw = new WsSoapMessageWriter(m_version); smw.WriteSoapMessageStart(xmlWriter, msg); // write body xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscribeResponse", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "SubscriptionManager", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "Address", null); // Create a uri. Use the path (by default will be a uuid) for the sub manager endpoint Uri subMgrUri = new Uri(((DpwsHostedService)matchingServices[0]).EndpointAddress); xmlWriter.WriteString("http://" + Device.IPV4Address + ":" + Device.Port + "/" + subMgrUri.AbsolutePath); xmlWriter.WriteEndElement(); // End Address xmlWriter.WriteStartElement(WsNamespacePrefix.Wsa, "ReferenceParameters", null); xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Identifier", null); xmlWriter.WriteString(eventSink.ID); xmlWriter.WriteEndElement(); // End Identifier xmlWriter.WriteEndElement(); // End ReferenceParameters xmlWriter.WriteEndElement(); // End SubscriptionManager xmlWriter.WriteStartElement(WsNamespacePrefix.Wse, "Expires", null); xmlWriter.WriteString(new WsDuration(eventSink.Expires).DurationString); xmlWriter.WriteEndElement(); // End Expires xmlWriter.WriteEndElement(); // End SubscribeResponse smw.WriteSoapMessageEnd(xmlWriter); // Return stream buffer msg.Body = xmlWriter.ToArray(); } return msg; }
/// <summary> /// Method used to expire events and send EndTo notification to an event sink /// </summary> public void EventService() { DateTime curDateTime; while (m_requestStop == false) { curDateTime = DateTime.Now; try { // Loop through hosted services int servicesCount = Device.HostedServices.Count; for (int i = 0; i < servicesCount; i++) { if (m_requestStop == true) { break; } DpwsHostedService hostedService = (DpwsHostedService)Device.HostedServices[i]; // Loop through event sources int eventSourcesCount = hostedService.EventSources.Count; for (int j = 0; j < eventSourcesCount; j++) { if (m_requestStop == true) { break; } DpwsWseEventSource eventSource = hostedService.EventSources[j]; // Loop through event sinks. Check expiration time. If an event has // expired send subscription end message and delete event sink. int eventSinkCount = eventSource.EventSinks.Count; for (int k = 0; k < eventSinkCount; k++) { if (m_requestStop == true) { break; } DpwsWseEventSink eventSink = eventSource.EventSinks[k]; // If time has expired delete event sink if (eventSink.StartTime + eventSink.Expires > curDateTime.Ticks) { eventSource.EventSinks.Remove(eventSink); } } } } } catch (Exception e) { System.Ext.Console.Write(""); System.Ext.Console.Write("Event Queue Manager threw and exception. " + e.Message); System.Ext.Console.Write(""); } Thread.Sleep(5000); } }