private void RequestAnsweredSink(HTTPSession ss) { lock (TagQueue) { if (!ReceivedFirstResponse) { ReceivedFirstResponse = true; IEnumerator en = TagQueue.GetEnumerator(); while (en.MoveNext()) { StateData sd = (StateData)en.Current; try { if (ProxySetting == null) { ss.Send(sd.Request); } else { HTTPMessage pr = (HTTPMessage)sd.Request.Clone(); pr.DirectiveObj = "http://" + sd.Dest + pr.DirectiveObj; pr.Version = "1.0"; ss.Send(pr); } } catch (Exception ex) { EventLogger.Log(ex); } } } } }
public StateData(HTTPMessage req, IPEndPoint d, object Tag, HeaderHandler HeaderCB) { Dest = d; Request = req; this.Tag = Tag; this.HeaderCB = HeaderCB; }
private void GetHostByNameSink(IAsyncResult result) { IPHostEntry e; try { e = Dns.EndGetHostEntry(result); } catch (Exception ex) { // Could not resolve? EventLogger.Log(ex); return; } object[] Args = (object[])result.AsyncState; Uri Resource = (Uri)Args[0]; object Tag = Args[1]; ContinueRequest( new IPEndPoint(e.AddressList[0], Resource.Port), HTTPMessage.UnEscapeString(Resource.PathAndQuery), Tag, null); }
private void SniffPacketSink(HTTPMessage Packet) { if (OnSniffPacket != null) { OnSniffPacket(Packet); } }
private void ReceiveSink(HTTPSession sender, HTTPMessage msg) { StateData sd = (StateData)sender.StateObject; object Tag = sd.Tag; if (msg.Version == "1.0" || msg.Version == "0.9") { sender.Close(); } else { if (msg.GetTag("Connection").ToUpper() == "CLOSE") { sender.Close(); } } if (OnResponse != null) { OnResponse(this, msg, Tag); } // If I don't set this to null, this holds a strong reference, resulting in // possible memory leaks sender.StateObject = null; lock (TagQueue) { if (TagQueue.Count == 0) { IdleTimeout = true; KeepAliveTimer.Add(GetHashCode(), 10); } } }
private void NonPipelinedSniffPacketSink(HTTPRequest sender, HTTPMessage Response, object Tag) { if (OnSniffPacket != null) { OnSniffPacket(this, Response, Tag); } }
private void OnReceiveSink(IAsyncResult result) { byte[] buffer; IPEndPoint ep = null; object[] args = (object[])result.AsyncState; UdpClient session = (UdpClient)args[0]; IPEndPoint local = (IPEndPoint)args[1]; try { buffer = session.EndReceive(result, ref ep); try { HTTPMessage Packet = HTTPMessage.ParseByteArray(buffer, 0, buffer.Length); if (Packet != null) { Packet.LocalEndPoint = local; Packet.RemoteEndPoint = ep; ProcessPacket(Packet, Packet.RemoteEndPoint, local); } } catch (Exception ex) { EventLogger.Log(ex); } session.BeginReceive(OnReceiveSink, args); } catch (Exception ex) { EventLogger.Log(ex); sessions.Remove(local.Address); } }
private void NonPipelinedResponseSink(HTTPRequest sender, HTTPMessage Response, object Tag) { // OpenSource.Utilities.EventLogger.Log(sender.s,System.Diagnostics.EventLogEntryType.Information,"TryingToDispose"); _Source = sender.Source; NotPipelinedTable.Remove(sender); sender.Dispose(); if (OnResponse != null) { OnResponse(this, Response, Tag); } }
/// <summary> /// Parses a URL /// </summary> /// <param name="ServiceURL">The URL to Parse</param> /// <param name="WebIP">The IPAddress</param> /// <param name="Port">The Port Number</param> /// <param name="ServiceName">The Object</param> static public void ParseURL(String ServiceURL, out String WebIP, out int Port, out String ServiceName) { Uri NewUri = new Uri(ServiceURL); WebIP = NewUri.Host; if (NewUri.HostNameType == UriHostNameType.Dns) { WebIP = Dns.GetHostEntry(WebIP).AddressList[0].ToString(); } Port = NewUri.Port; ServiceName = HTTPMessage.UnEscapeString(NewUri.PathAndQuery); }
private void OnReceiveSink2(byte[] buffer, IPEndPoint remote, IPEndPoint local) { HTTPMessage msg; try { msg = HTTPMessage.ParseByteArray(buffer, 0, buffer.Length); } catch (Exception ex) { EventLogger.Log(ex); msg = new HTTPMessage(); msg.Directive = "---"; msg.DirectiveObj = "---"; msg.BodyBuffer = buffer; } msg.LocalEndPoint = local; msg.RemoteEndPoint = remote; DText parser = new DText(); String Location = msg.GetTag("Location"); int MaxAge = 0; String ma = msg.GetTag("Cache-Control").Trim(); if (ma != "") { parser.ATTRMARK = ","; parser.MULTMARK = "="; parser[0] = ma; for (int i = 1; i <= parser.DCOUNT(); ++i) { if (parser[i, 1].Trim().ToUpper() == "MAX-AGE") { MaxAge = int.Parse(parser[i, 2].Trim()); break; } } } ma = msg.GetTag("USN"); String USN = ma.Substring(ma.IndexOf(":") + 1); String ST = msg.GetTag("ST"); if (USN.IndexOf("::") != -1) { USN = USN.Substring(0, USN.IndexOf("::")); } EventLogger.Log(this, EventLogEntryType.SuccessAudit, msg.RemoteEndPoint.ToString()); if (OnSearch != null) { OnSearch(msg.RemoteEndPoint, msg.LocalEndPoint, new Uri(Location), USN, ST, MaxAge); } }
private void SniffPacketSink(HTTPSession sender, HTTPMessage MSG) { if (OnSniffPacket != null) { if (sender.StateObject == null) { OnSniffPacket(this, MSG, null); return; } StateData sd = (StateData)sender.StateObject; object Tag = sd.Tag; OnSniffPacket(this, MSG, Tag); } }
/// <summary> /// Multicasts a HTTPMessage /// </summary> /// <param name="packet">The Packet to Multicast</param> /// <param name="netinterface"></param> public void BroadcastData(HTTPMessage packet, IPAddress netinterface) { UdpClient usession = (UdpClient)usessions[netinterface]; if (usession == null) { return; } byte[] buffer = Encoding.UTF8.GetBytes(packet.StringPacket); if (netinterface.AddressFamily == AddressFamily.InterNetwork) { try { usession.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, netinterface.GetAddressBytes()); usession.Send(buffer, buffer.Length, Utils.UpnpMulticastV4EndPoint); usession.Send(buffer, buffer.Length, Utils.UpnpMulticastV4EndPoint); } catch (SocketException ex) { EventLogger.Log(ex); } } else if (netinterface.AddressFamily == AddressFamily.InterNetworkV6 && netinterface.ScopeId != 0) { try { usession.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface, BitConverter.GetBytes((int)netinterface.ScopeId)); if (netinterface.IsIPv6LinkLocal) { usession.Send(buffer, buffer.Length, Utils.UpnpMulticastV6EndPoint2); usession.Send(buffer, buffer.Length, Utils.UpnpMulticastV6EndPoint2); } else { usession.Send(buffer, buffer.Length, Utils.UpnpMulticastV6EndPoint1); usession.Send(buffer, buffer.Length, Utils.UpnpMulticastV6EndPoint1); } } catch (SocketException ex) { EventLogger.Log(ex); } } }
/// <summary> /// Pipelines a Uri request /// </summary> /// <param name="Resource">Uri to GET</param> /// <param name="Tag">State Data</param> public void PipelineRequest(Uri Resource, object Tag) { object[] Args = { Resource, Tag }; string IP = Resource.Host; if (Resource.HostNameType == UriHostNameType.Dns) { Dns.BeginGetHostEntry(IP, GetHostByNameSink, Args); } else { ContinueRequest( new IPEndPoint(IPAddress.Parse(Resource.Host), Resource.Port), HTTPMessage.UnEscapeString(Resource.PathAndQuery), Tag, null); } }
private void CreateSink(HTTPSession ss) { lock (TagQueue) { ss.OnHeader += HeaderSink; ss.OnReceive += ReceiveSink; ss.OnClosed += CloseSink; ss.OnStreamDone += StreamDoneSink; ss.OnRequestAnswered += RequestAnsweredSink; if (OnSniff != null) { ss.OnSniff += SniffSink; } if (OnSniffPacket != null) { ss.OnSniffPacket += SniffPacketSink; } StateData sd = (StateData)TagQueue.Peek(); try { if (ProxySetting == null) { ss.Send(sd.Request); } else { HTTPMessage pr = (HTTPMessage)sd.Request.Clone(); pr.DirectiveObj = "http://" + sd.Dest + pr.DirectiveObj; pr.Version = "1.0"; ss.Send(pr); } } catch (Exception exc) { EventLogger.Log(exc); } } }
private bool ValidateSearchPacket(HTTPMessage msg) { int MX; if (msg.GetTag("MAN") != "\"ssdp:discover\"") { return(false); // { throw (new InvalidSearchPacketException("Invalid MAN")); } } if (msg.DirectiveObj != "*") { return(false); // { throw (new InvalidSearchPacketException("Expected * in RequestLine")); } } if (double.Parse(msg.Version, new CultureInfo("en-US").NumberFormat) < 1.1) { return(false); // { throw (new InvalidSearchPacketException("Version must be at least 1.1")); } } if (int.TryParse(msg.GetTag("MX"), out MX) == false || MX <= 0) { return(false); // { throw (new InvalidSearchPacketException("MX must be a positive integer")); } } return(true); }
/// <summary> /// Unicast a HTTPMessage /// </summary> /// <param name="msg">The Packet to Unicast</param> public void UnicastData(HTTPMessage msg) { UdpClient usession = (UdpClient)usessions[msg.LocalEndPoint.Address]; if (usession == null) { return; } if (OnSniffPacket != null) { OnSniffPacket(null, msg.RemoteEndPoint, msg); } byte[] buffer = msg.RawPacket; try { usession.Send(buffer, buffer.Length, msg.RemoteEndPoint); } catch (SocketException ex) { EventLogger.Log(ex); } }
private void HeaderSink(HTTPSession sender, HTTPMessage header, Stream TheStream) { _Source = sender.Source; StateData sd; if (TheStream != null) { // This is the result of post-headers in a chunked document sd = (StateData)sender.StateObject; object Tag = sd.Tag; if (sd.HeaderCB != null) { sd.HeaderCB(this, sender, header, TheStream, Tag); } sender.StateObject = null; KeepAliveTimer.Add(GetHashCode(), 10); } else { lock (TagQueue) { sd = (StateData)TagQueue.Dequeue(); } sender.StateObject = sd; object Tag = sd.Tag; if (sd.HeaderCB != null) { sd.HeaderCB(this, sender, header, null, Tag); if (sender.UserStream != null && !sender.IsChunked) { // If I don't set this to null, this holds a strong reference, resulting in // possible memory leaks sender.StateObject = null; } } } }
private void HandleHeader(HTTPSession sender, HTTPMessage Header, Stream StreamObject) { SessionTimer.Remove(sender); OnHeaderEvent.Fire(Header, sender); }
private void ProcessPacket(HTTPMessage msg, IPEndPoint src, IPEndPoint local) { if (OnSniffPacket != null) { OnSniffPacket(src, null, msg); } DText parser = new DText(); parser.ATTRMARK = "::"; bool Alive = false; String UDN = msg.GetTag("USN"); parser[0] = UDN; String USN = parser[1]; USN = USN.Substring(USN.IndexOf(":", StringComparison.Ordinal) + 1); String ST = parser[2]; int MaxAge = 0; String NTS = msg.GetTag("NTS").ToUpper(); if (NTS == "SSDP:ALIVE") { Alive = true; String ma = msg.GetTag("Cache-Control").Trim(); if (ma != "") { parser.ATTRMARK = ","; parser.MULTMARK = "="; parser[0] = ma; for (int i = 1; i <= parser.DCOUNT(); ++i) { if (parser[i, 1].Trim().ToUpper() == "MAX-AGE") { MaxAge = int.Parse(parser[i, 2].Trim()); break; } } } } if (msg.Directive == "NOTIFY" && OnNotify != null) { Uri locuri = null; string location = msg.GetTag("Location"); if (location != null && location.Length > 0) { try { locuri = new Uri(location); } catch (Exception ex) { EventLogger.Log(ex); } } OnNotify(src, msg.LocalEndPoint, locuri, Alive, USN, ST, MaxAge, msg); } else if (msg.Directive == "M-SEARCH" && OnSearch != null) { if (ValidateSearchPacket(msg) == false) { return; } int MaxTimer = int.Parse(msg.GetTag("MX")); SearchStruct SearchData = new SearchStruct(); SearchData.ST = msg.GetTag("ST"); SearchData.Source = src; SearchData.Local = local; SearchTimer.Add(SearchData, RandomGenerator.Next(0, MaxTimer)); } }
private void ContinueRequest(IPEndPoint dest, string PQ, object Tag, HTTPMessage MSG) { HTTPMessage r; if (MSG == null) { r = new HTTPMessage(); r.Directive = "GET"; r.DirectiveObj = PQ; if (dest.AddressFamily == AddressFamily.InterNetwork) { r.AddTag("Host", dest.ToString()); } if (dest.AddressFamily == AddressFamily.InterNetworkV6) { r.AddTag("Host", "[" + RemoveIPv6Scope(dest.ToString()) + "]"); } } else { r = MSG; } lock (TagQueue) { IdleTimeout = false; KeepAliveTimer.Remove(GetHashCode()); if ((PIPELINE == false && _PIPELINE == false) || (_PIPELINE == false)) { HTTPRequest TR = new HTTPRequest(); TR.ProxySetting = ProxySetting; TR._PIPELINE = true; if (OnSniff != null) { TR.OnSniff += NonPipelinedSniffSink; } if (OnSniffPacket != null) { TR.OnSniffPacket += NonPipelinedSniffPacketSink; } TR.OnResponse += NonPipelinedResponseSink; NotPipelinedTable[TR] = TR; TR.PipelineRequest(dest, r, Tag); return; } TagQueue.Enqueue(new StateData(r, dest, Tag, null)); IPAddress localif = IPAddress.Any; if (dest.AddressFamily == AddressFamily.InterNetworkV6) { localif = IPAddress.IPv6Any; } if (s == null) { ReceivedFirstResponse = false; if (ProxySetting != null) { s = new HTTPSession(new IPEndPoint(localif, 0), ProxySetting, CreateSink, CreateFailedSink, null); } else { s = new HTTPSession(new IPEndPoint(localif, 0), dest, CreateSink, CreateFailedSink, null); } } else { if (s.IsConnected && ReceivedFirstResponse) { try { if (ProxySetting == null) { s.Send(r); } else { HTTPMessage pr = (HTTPMessage)r.Clone(); pr.DirectiveObj = "http://" + dest + pr.DirectiveObj; pr.Version = "1.0"; s.Send(pr); } } catch (Exception ex) { EventLogger.Log(ex); } } } } }
/// <summary> /// Parses a Byte Array at a specific location, and builds a Packet. /// </summary> /// <param name="buffer">The Array of Bytes</param> /// <param name="indx">The Start Index</param> /// <param name="count">The number of Bytes to process</param> /// <returns></returns> static public HTTPMessage ParseByteArray(byte[] buffer, int indx, int count) { HTTPMessage TheMessage = new HTTPMessage(); UTF8Encoding UTF8 = new UTF8Encoding(); String TempData = UTF8.GetString(buffer, indx, count); DText parser = new DText(); String TempString; int idx = TempData.IndexOf("\r\n\r\n", StringComparison.Ordinal); if (idx < 0) { return(null); } TempData = TempData.Substring(0, idx); parser.ATTRMARK = "\r\n"; parser.MULTMARK = ":"; parser[0] = TempData; string CurrentLine = parser[1]; DText HdrParser = new DText(); HdrParser.ATTRMARK = " "; HdrParser.MULTMARK = "/"; HdrParser[0] = CurrentLine; if (CurrentLine.ToUpper().StartsWith("HTTP/")) { TheMessage.ResponseCode = int.Parse(HdrParser[2]); int s1 = CurrentLine.IndexOf(" ", StringComparison.Ordinal); s1 = CurrentLine.IndexOf(" ", s1 + 1, StringComparison.Ordinal); TheMessage.ResponseData = UnEscapeString(CurrentLine.Substring(s1)); try { TheMessage.Version = HdrParser[1, 2]; } catch (Exception ex) { EventLogger.Log(ex); TheMessage.Version = "0.9"; } } else { TheMessage.Directive = HdrParser[1]; TempString = CurrentLine.Substring(CurrentLine.LastIndexOf(" ", StringComparison.Ordinal) + 1); if (TempString.ToUpper().StartsWith("HTTP/") == false) { TheMessage.Version = "0.9"; TheMessage.DirectiveObj = UnEscapeString(TempString); } else { TheMessage.Version = TempString.Substring(TempString.IndexOf("/", StringComparison.Ordinal) + 1); int fs = CurrentLine.IndexOf(" ", StringComparison.Ordinal) + 1; TheMessage.DirectiveObj = UnEscapeString(CurrentLine.Substring( fs, CurrentLine.Length - fs - TempString.Length - 1)); } } String Tag = ""; for (int line = 2; line <= parser.DCOUNT(); ++line) { String TagData; if (Tag != "" && parser[line, 1].StartsWith(" ")) { TagData = parser[line, 1].Substring(1); } else { Tag = parser[line, 1]; TagData = ""; for (int i = 2; i <= parser.DCOUNT(line); ++i) { if (TagData == "") { TagData = parser[line, i]; } else { TagData = TagData + parser.MULTMARK + parser[line, i]; } } } TheMessage.AppendTag(Tag, TagData); } int cl; if (TheMessage.HasTag("Content-Length")) { try { cl = int.Parse(TheMessage.GetTag("Content-Length")); } catch (Exception ex) { EventLogger.Log(ex); cl = -1; } } else { cl = -1; } byte[] tbuffer; if (cl > 0) { tbuffer = new byte[cl]; if ((idx + 4 + cl) > count) { // NOP } else { Array.Copy(buffer, idx + 4, tbuffer, 0, cl); TheMessage.DataBuffer = tbuffer; } } if (cl == -1) { tbuffer = new Byte[count - (idx + 4)]; Array.Copy(buffer, idx + 4, tbuffer, 0, tbuffer.Length); TheMessage.DataBuffer = tbuffer; } if (cl == 0) { TheMessage.DataBuffer = new byte[0]; } return(TheMessage); }
/// <summary> /// Searches for a SearchTarget Asynchronously /// </summary> /// <param name="SearchTarget">The Target</param> public void FindDeviceAsync(String SearchTarget, IPEndPoint RemoteEP) { HTTPMessage request = new HTTPMessage(); request.Directive = "M-SEARCH"; request.DirectiveObj = "*"; request.AddTag("ST", SearchTarget); request.AddTag("MX", MX.ToString()); request.AddTag("MAN", "\"ssdp:discover\""); if (RemoteEP.AddressFamily == AddressFamily.InterNetwork) { request.AddTag("HOST", RemoteEP.ToString()); // "239.255.255.250:1900" } if (RemoteEP.AddressFamily == AddressFamily.InterNetworkV6) { request.AddTag("HOST", string.Format("[{0}]:{1}", RemoteEP.Address.ToString(), RemoteEP.Port)); // "[FF05::C]:1900" } byte[] buffer = UTF8Encoding.UTF8.GetBytes(request.StringPacket); IPAddress[] LocalAddresses = NetInfo.GetLocalAddresses(); foreach (IPAddress localaddr in LocalAddresses) { try { UdpClient session = (UdpClient)SSDPSessions[localaddr]; if (session == null) { session = new UdpClient(new IPEndPoint(localaddr, 0)); session.EnableBroadcast = true; session.BeginReceive(OnReceiveSink, session); SSDPSessions[localaddr] = session; } if (RemoteEP.AddressFamily != session.Client.AddressFamily) { continue; } if ((RemoteEP.AddressFamily == AddressFamily.InterNetworkV6) && ((IPEndPoint)session.Client.LocalEndPoint).Address.IsIPv6LinkLocal && RemoteEP != Utils.UpnpMulticastV6EndPoint2) { continue; } if ((RemoteEP.AddressFamily == AddressFamily.InterNetworkV6) && ((IPEndPoint)session.Client.LocalEndPoint).Address.IsIPv6LinkLocal == false && RemoteEP != Utils.UpnpMulticastV6EndPoint1) { continue; } IPEndPoint lep = (IPEndPoint)session.Client.LocalEndPoint; if (session.Client.AddressFamily == AddressFamily.InterNetwork) { session.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, localaddr.GetAddressBytes()); } else if (session.Client.AddressFamily == AddressFamily.InterNetworkV6) { session.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastInterface, BitConverter.GetBytes((int)localaddr.ScopeId)); } session.Send(buffer, buffer.Length, RemoteEP); session.Send(buffer, buffer.Length, RemoteEP); } catch (Exception ex) { EventLogger.Log(this, EventLogEntryType.Error, "CP Failure: " + localaddr.ToString()); EventLogger.Log(ex); } } }
private void HandleRequest(HTTPSession WebSession, HTTPMessage request) { OnReceiveEvent.Fire(request, WebSession); }
/// <summary> /// Pipelines a request packet /// </summary> /// <param name="dest">Destination IPEndPoint</param> /// <param name="MSG">HTTPMessage Packet</param> /// <param name="Tag">State Data</param> public void PipelineRequest(IPEndPoint dest, HTTPMessage MSG, object Tag) { ContinueRequest(dest, "", Tag, MSG); }
/// <summary> /// Triggered when a SSDP notification is received /// </summary> internal void SSDPNotifySink(IPEndPoint source, IPEndPoint local, Uri LocationURL, bool IsAlive, String USN, String SearchTarget, int MaxAge, HTTPMessage Packet) { UPnPDevice removedDevice = null; // Simple ignore everything that is not root if (SearchTarget != "upnp:rootdevice") { return; } if (IsAlive == false) { // The easy part first... we got a SSDP BYE message // Remove the device completely no matter what state it is in // right now. Also clear all clocks. lock (deviceTableLock) { removedDevice = UnprotectedRemoveMe(USN); } if (removedDevice != null) { removedDevice.Removed(); OnRemovedDeviceEvent.Fire(this, removedDevice); } } else { lock (deviceTableLock) { // Ok, This device is annoncing itself. if (deviceTable.ContainsKey(USN) == false) { // Never saw this device before DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.Device = null; deviceInfo.UDN = USN; deviceInfo.NotifyTime = DateTime.Now; deviceInfo.BaseURL = LocationURL; deviceInfo.MaxAge = MaxAge; deviceInfo.LocalEP = local; deviceTable[USN] = deviceInfo; deviceFactory.CreateDevice(deviceInfo.BaseURL, deviceInfo.MaxAge, local.Address, USN); // TODO2: Does URI construction work all this time?? } else { // We already know about this device, lets check it out DeviceInfo deviceInfo = (DeviceInfo)deviceTable[USN]; if (deviceInfo.Device != null) // If the device is in creation mode, do nothing { if (deviceInfo.BaseURL.Equals(LocationURL)) { // Cancel a possible source change deviceUpdateClock.Remove(deviceInfo); deviceInfo.PendingBaseURL = null; deviceInfo.PendingMaxAge = 0; deviceInfo.PendingLocalEP = null; deviceInfo.PendingSourceEP = null; // Then simply update the lifetime deviceInfo.NotifyTime = DateTime.Now; deviceTable[USN] = deviceInfo; deviceLifeTimeClock.Add(deviceInfo.UDN, MaxAge); } else { // Wow, same device, different source - Check timing if (deviceInfo.NotifyTime.AddSeconds(10).Ticks < DateTime.Now.Ticks) { // This is a possible source change. Wait for 3 seconds and make the switch. deviceInfo.PendingBaseURL = LocationURL; deviceInfo.PendingMaxAge = MaxAge; deviceInfo.PendingLocalEP = local; deviceInfo.PendingSourceEP = source; deviceTable[USN] = deviceInfo; deviceUpdateClock.Add(deviceInfo.UDN, 3); } } } } } } }
private void HandleNotify(IPEndPoint source, IPEndPoint local, Uri LocationURL, bool IsAlive, String USN, String ST, int MaxAge, HTTPMessage Packet) { if (IsAlive && LocationURL != null) { EventLogger.Log(this, EventLogEntryType.SuccessAudit, LocationURL.ToString()); } if (OnNotify != null) { OnNotify(source, local, LocationURL, IsAlive, USN, ST, MaxAge, Packet); } }