protected void SendMulticastEventNotification(DvService service, IEnumerable <DvStateVariable> variables) { DvDevice device = service.ParentDevice; EventingState eventingState = _serverData.GetMulticastEventKey(service); // First cluster variables by multicast event level so we can put variables of the same event level into a single message IDictionary <string, ICollection <DvStateVariable> > variablesByLevel = new Dictionary <string, ICollection <DvStateVariable> >(); foreach (DvStateVariable variable in variables) { ICollection <DvStateVariable> variablesCollection; if (!variablesByLevel.TryGetValue(variable.MulticastEventLevel, out variablesCollection)) { variablesByLevel[variable.MulticastEventLevel] = variablesCollection = new List <DvStateVariable>(); } variablesCollection.Add(variable); } foreach (KeyValuePair <string, ICollection <DvStateVariable> > varByLevel in variablesByLevel) { // Use a maximum cluster size of GENA_MAX_MULTICAST_EVENT_VAR_COUNT to keep UDP message small ICollection <IList <DvStateVariable> > variableClusters = CollectionUtils.Cluster( varByLevel.Value, UPnPConsts.GENA_MAX_MULTICAST_EVENT_VAR_COUNT); foreach (IList <DvStateVariable> cluster in variableClusters) { foreach (DvStateVariable variable in cluster) { eventingState.UpdateModerationData(variable); } eventingState.IncEventKey(); byte[] bodyData = UPnPConsts.UTF8_NO_BOM.GetBytes(GENAMessageBuilder.BuildEventNotificationMessage( cluster, false)); // Albert TODO: Is it correct not to force the simple string equivalent for extended data types here? SimpleHTTPRequest request = new SimpleHTTPRequest("NOTIFY", "*"); request.SetHeader("CONTENT-LENGTH", bodyData.Length.ToString()); request.SetHeader("CONTENT-TYPE", "text/xml; charset=\"utf-8\""); request.SetHeader("USN", device.UDN + "::" + service.ServiceTypeVersion_URN); request.SetHeader("SVCID", service.ServiceId); request.SetHeader("NT", "upnp:event"); request.SetHeader("NTS", "upnp:propchange"); request.SetHeader("SEQ", eventingState.EventKey.ToString()); request.SetHeader("LVL", varByLevel.Key); request.SetHeader("BOOTID.UPNP.ORG", _serverData.BootId.ToString()); foreach (EndpointConfiguration config in _serverData.UPnPEndPoints) { IPEndPoint ep = new IPEndPoint(config.GENAMulticastAddress, UPnPConsts.GENA_MULTICAST_PORT); request.SetHeader("HOST", NetworkHelper.IPEndPointToString(ep)); request.MessageBody = bodyData; byte[] bytes = request.Encode(); NetworkHelper.SendData(config.GENA_UDP_Socket, ep, bytes, 1); } } } }
/// <summary> /// Sends an event notification to our subscriber for the specified <paramref name="variables"/>. /// </summary> protected void SendEventNotification(IEnumerable <DvStateVariable> variables) { AsyncRequestState state; lock (_serverData.SyncObj) { foreach (DvStateVariable variable in variables) { _eventingState.UpdateModerationData(variable); } String body; lock (_serverData.SyncObj) body = GENAMessageBuilder.BuildEventNotificationMessage(variables, !_subscriberSupportsUPnP11); byte[] bodyData = UPnPConsts.UTF8_NO_BOM.GetBytes(body); state = new AsyncRequestState(_config, _sid, _callbackURLs, _eventingState.EventKey, bodyData); _pendingRequests.Add(state); _eventingState.IncEventKey(); } // Outside the lock ContinueEventNotification(state); }