private void OnReceiveSink2(byte[] buffer, IPEndPoint remote, IPEndPoint local) { HTTPMessage msg; try { msg = HTTPMessage.ParseByteArray(buffer, 0, buffer.Length); } catch (Exception ex) { OpenSource.Utilities.EventLogger.Log(ex); msg = new HTTPMessage(); msg.Directive = "---"; msg.DirectiveObj = "---"; msg.BodyBuffer = buffer; } msg.LocalEndPoint = local; msg.RemoteEndPoint = remote; HandleSniffer(remote, local, msg); 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("::")); } OpenSource.Utilities.EventLogger.Log(this, System.Diagnostics.EventLogEntryType.SuccessAudit, msg.RemoteEndPoint.ToString()); if (OnSearch != null) { OnSearch(msg.RemoteEndPoint, msg.LocalEndPoint, new Uri(Location), USN, ST, MaxAge); } }
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) { this.IdleTimeout = true; KeepAliveTimer.Add(this.GetHashCode(), 10); } } }
private bool ValidateSearchPacket(HTTPMessage msg) { int MX = 0; 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) < (double)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); }
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(":") + 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) { OpenSource.Utilities.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 OnReceiveSink2(byte[] buffer, IPEndPoint remote, IPEndPoint local) { HTTPMessage msg; try { msg = HTTPMessage.ParseByteArray(buffer, 0, buffer.Length); } catch (Exception ex) { OpenSource.Utilities.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("::")); OpenSource.Utilities.EventLogger.Log(this, System.Diagnostics.EventLogEntryType.SuccessAudit, msg.RemoteEndPoint.ToString()); if (OnSearch != null) OnSearch(msg.RemoteEndPoint, msg.LocalEndPoint, new Uri(Location), USN, ST, MaxAge); }
private void HandleSubscribeResponse(HTTPRequest sender, HTTPMessage response, object Tag) { UPnPEventSubscribeHandler CB = (UPnPEventSubscribeHandler)Tag; SubscribeRequestTable.Remove(sender); sender.Dispose(); if (response != null) { if (response.StatusCode != 200) { if (CB != null) { CB(this, false); } else { if (OnSubscribe != null) OnSubscribe(this, false); } } else { CurrentSID = response.GetTag("SID"); if (CB != null) { CB(this, true); } else { if (OnSubscribe != null) OnSubscribe(this, true); } if (CurrentTimeout != 0) { EventLogger.Log(this, System.Diagnostics.EventLogEntryType.SuccessAudit, "SUBSCRIBE [" + this.CurrentSID + "] Duration: " + CurrentTimeout.ToString() + " <" + DateTime.Now.ToLongTimeString() + ">"); SubscribeCycle.Add(this.GetHashCode(), CurrentTimeout / 2); } } } else { if (CB != null) { CB(this, false); } else { if (OnSubscribe != null) OnSubscribe(this, false); } } }
/// <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"); 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/") == true) { TheMessage.ResponseCode = int.Parse(HdrParser[2]); int s1 = CurrentLine.IndexOf(" "); s1 = CurrentLine.IndexOf(" ", s1 + 1); TheMessage.ResponseData = HTTPMessage.UnEscapeString(CurrentLine.Substring(s1)); try { TheMessage.Version = HdrParser[1, 2]; } catch (Exception ex) { OpenSource.Utilities.EventLogger.Log(ex); TheMessage.Version = "0.9"; } } else { TheMessage.Directive = HdrParser[1]; TempString = CurrentLine.Substring(CurrentLine.LastIndexOf(" ") + 1); if (TempString.ToUpper().StartsWith("HTTP/") == false) { TheMessage.Version = "0.9"; TheMessage.DirectiveObj = HTTPMessage.UnEscapeString(TempString); } else { TheMessage.Version = TempString.Substring(TempString.IndexOf("/") + 1); int fs = CurrentLine.IndexOf(" ") + 1; TheMessage.DirectiveObj = HTTPMessage.UnEscapeString(CurrentLine.Substring( fs, CurrentLine.Length - fs - TempString.Length - 1)); } } String Tag = ""; String TagData = ""; for (int line = 2; line <= parser.DCOUNT(); ++line) { 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 = 0; if (TheMessage.HasTag("Content-Length")) { try { cl = int.Parse(TheMessage.GetTag("Content-Length")); } catch (Exception ex) { OpenSource.Utilities.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> /// Examines an <see cref="HTTPMessage"/> object and /// attempts to find the content length of the message body. /// </summary> /// <param name="msg"></param> /// <returns></returns> private long ExtractContentLength(HTTPMessage msg) { long expectedLength = 0; string contentLengthString = msg.GetTag("CONTENT-LENGTH"); try { expectedLength = long.Parse(contentLengthString); } catch{} return expectedLength; }
private void EventProcesser(UPnPDevice sender, HTTPMessage msg, HTTPSession WebSession, string VirtualDir) { if (ControlPointOnly == true) { String Method = msg.Directive; HTTPMessage Response = new HTTPMessage(); if (Method != "NOTIFY") { Response.StatusCode = 405; Response.StatusData = Method + " not supported"; WebSession.Send(Response); return; // Other methods are unknown to us } else if (Method == "NOTIFY") { for (int id = 0; id < Services.Length; ++id) { // SSDP.ParseURL(Services[id].__eventurl,out WebIP, out WebPort, out WebData); // if (WebData==MethodData) // { if (Services[id].IsYourEvent(msg.GetTag("SID")) == true) { Response.StatusCode = 200; Response.StatusData = "OK"; WebSession.Send(Response); Services[id]._TriggerEvent(msg.GetTag("SID"), long.Parse(msg.GetTag("SEQ")), msg.StringBuffer, 0); break; } // } } } } }
private bool ValidateSearchPacket(HTTPMessage msg) { int MX = 0; 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) < (double)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; }
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(":") + 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) { } } 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 HandleReceive(AsyncSocket sender, Byte[] buffer, int BeginPointer, int BufferSize, int BytesRead, IPEndPoint source, IPEndPoint remote) { if (BytesRead!=0) { OnSniffEvent.Fire(buffer,BufferSize-BytesRead, BytesRead); } if (this.FinishedHeader==false) { if (BufferSize<4) { sender.BufferReadLength = 1; sender.BufferBeginPointer = 0; return; } /* This is New */ for(int i=4;i<BufferSize-4;++i) { if ((buffer[i-4]==13)&&(buffer[i-3]==10)&& (buffer[i-2]==13)&&(buffer[i-1]==10)) { BufferSize = i; break; } } if ((buffer[BufferSize-4]==13)&&(buffer[BufferSize-3]==10)&& (buffer[BufferSize-2]==13)&&(buffer[BufferSize-1]==10)) { // End Of Headers Headers = HTTPMessage.ParseByteArray(buffer,0,BufferSize); if (Headers.StatusCode!=-1) { if (Headers.StatusCode>=100 && Headers.StatusCode<=199) { //Informational if (OpenSource.Utilities.EventLogger.Enabled) { OpenSource.Utilities.EventLogger.Log(this,System.Diagnostics.EventLogEntryType.Information,"<<IGNORING>>\r\n" + Headers.StringPacket); } // OnHeaderEvent.Fire(this,Headers, UserStream); OnSniffPacketEvent.Fire(this,Headers); // OnReceiveEvent.Fire(this, Headers); // DONE_ReadingPacket(); BeginHeader(BufferSize); return; } if (Headers.StatusCode==204 || Headers.StatusCode==304) { //No Body or No Change if (OpenSource.Utilities.EventLogger.Enabled) { OpenSource.Utilities.EventLogger.Log(this,System.Diagnostics.EventLogEntryType.Information,Headers.StringPacket); } OnHeaderEvent.Fire(this,Headers, UserStream); OnSniffPacketEvent.Fire(this,Headers); OnReceiveEvent.Fire(this, Headers); DONE_ReadingPacket(); BeginHeader(BufferSize); return; } } else { SET_START_OF_REQUEST(); } FinishedHeader = true; if (Headers.GetTag("Content-Length")=="") { if (Headers.GetTag("Transfer-Encoding").ToUpper()=="CHUNKED") { IsChunked = true; } else { if (Headers.StatusCode!=-1) { this.NeedToWaitToClose = true; } } } else { if (Headers.GetTag("Transfer-Encoding").ToUpper()=="CHUNKED") { IsChunked = true; } else { BodySize = int.Parse(Headers.GetTag("Content-Length")); } } if (Headers.GetTag("Connection").ToUpper()=="CLOSE") { this.ConnectionCloseSpecified=true; } if (!IsChunked && NeedToWaitToClose && !ConnectionCloseSpecified &&!IsLegacy && Headers.Version!="1.0") { NeedToWaitToClose = false; BodySize = 0; } OnHeaderEvent.Fire(this,Headers, UserStream); if (this.NeedToWaitToClose==true) { sender.BufferBeginPointer = BufferSize; sender.BufferReadLength = 4096; } else { if (IsChunked==true) { // Chunked BeginChunk(BufferSize); } else { // Normal if (BodySize==0) { // Already have the packet if (OpenSource.Utilities.EventLogger.Enabled) { OpenSource.Utilities.EventLogger.Log(this,System.Diagnostics.EventLogEntryType.Information,Headers.StringPacket); } OnSniffPacketEvent.Fire(this,Headers); OnReceiveEvent.Fire(this, Headers); if (UserStream!=null) { UserStream.Flush(); OnStreamDoneEvent.Fire(this,UserStream); } DONE_ReadingPacket(); BeginHeader(BufferSize); } else { if (BodySize<=4096) { sender.BufferBeginPointer = BufferSize; sender.BufferReadLength = BodySize; } else { sender.BufferBeginPointer = BufferSize; sender.BufferReadLength = 4096; } } } // End Normal Else Clause } // End Non HTTP/1.0 Else Clause return; } // End of Processing Header else { // Need to read more of the header sender.BufferBeginPointer = 0; sender.BufferReadLength = 1; } return; } // End of If FinishedHeader // Have some body data if (IsChunked == false) { /* This is New */ if (this.NeedToWaitToClose==false) { if (BufferSize>BodySize) BufferSize = BodySize; } // Normal Data if (UserStream!=null) { UserStream.Write(buffer,0,BufferSize); } else { // OpenSource.Utilities.EventLogger.Log(this,System.Diagnostics.EventLogEntryType.SuccessAudit,"NONChunk Data: " + BufferSize.ToString() + " bytes"); // OpenSource.Utilities.EventLogger.Log(this,System.Diagnostics.EventLogEntryType.SuccessAudit,"Writing["+SocketStream.GetHashCode().ToString()+"]: " + U.GetString(buffer,0,BufferSize)); SocketStream.Write(buffer,0,BufferSize); } if (this.NeedToWaitToClose==false) { BodySize -= BufferSize; if (BodySize>0) { // More To Read sender.BufferBeginPointer = BufferSize; if (BodySize < 4096) { sender.BufferReadLength = BodySize; } else { sender.BufferReadLength = 4096; } } else { // Finished Reading if (UserStream==null) { SocketStream.Flush(); Headers.BodyBuffer = SocketStream.ToArray(); if (OpenSource.Utilities.EventLogger.Enabled) { OpenSource.Utilities.EventLogger.Log(this,System.Diagnostics.EventLogEntryType.Information,Headers.StringPacket); } OnSniffPacketEvent.Fire(this,Headers); OnReceiveEvent.Fire(this, Headers); } else { UserStream.Flush(); OnStreamDoneEvent.Fire(this,UserStream); } DONE_ReadingPacket(); BeginHeader(BufferSize); } } else { // HTTP/1.0 Socket sender.BufferReadLength = 4096; sender.BufferBeginPointer = BufferSize; } } else { // Chunked Data ProcessChunk(buffer, BufferSize); } }
public override void Start(UPnPDevice device) { if(!Enabled) return; UPnPDevice dv = device; while(dv.ParentDevice!=null) { dv = dv.ParentDevice; } state = UPnPTestStates.Running; UPnPService[] _S = device.GetServices("urn:"); foreach(UPnPService s in _S) { bool ok = false; foreach(UPnPStateVariable v in s.GetStateVariables()) { if(v.SendEvent) { ok = true; break; } } if(ok) { UPnPDebugObject d = new UPnPDebugObject(s); Uri EventUri = new Uri((string)d.GetField("__eventurl")); IPEndPoint dest = new IPEndPoint(IPAddress.Parse(EventUri.Host),EventUri.Port); HTTPMessage R = new HTTPMessage(); R.Directive = "SUBSCRIBE"; R.DirectiveObj = HTTPMessage.UnEscapeString(EventUri.PathAndQuery); R.AddTag("Host",dest.ToString()); R.AddTag("Callback","<http://" + dv.InterfaceToHost.ToString()+ ":" + NetworkInfo.GetFreePort(10000,50000,dv.InterfaceToHost).ToString() + ">"); //R.AddTag("Callback","<http://127.0.0.1:55555>"); R.AddTag("NT","upnp:event"); R.AddTag("Timeout","Second-15"); System.Console.WriteLine(R.GetTag("Callback")); MRE.Reset(); SID = ""; StartCountDown(30); HTTPRequest rq = new HTTPRequest(); rq.OnResponse += new HTTPRequest.RequestHandler(SubscribeSink); AddHTTPMessage(R); rq.PipelineRequest(dest,R,s); MRE.WaitOne(30000,false); AbortCountDown(); if (SID=="") { AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE: " + s.ServiceURN + " << FAILED >>"); AddEvent(LogImportance.Remark,"Subscribe","Aborting tests"); result = "Subscription test failed."; // TODO state = UPnPTestStates.Failed; return; } else { AddEvent(LogImportance.Remark,"Subscribe","SUBSCRIBE: " + s.ServiceURN + " << OK >>"); // Renew Test R = new HTTPMessage(); R.Directive = "SUBSCRIBE"; R.DirectiveObj = HTTPMessage.UnEscapeString(EventUri.PathAndQuery); R.AddTag("Host",dest.ToString()); R.AddTag("SID",SID); R.AddTag("Timeout","Second-15"); StartCountDown(30); SID = ""; MRE.Reset(); AddHTTPMessage(R); rq = new HTTPRequest(); rq.OnResponse += new HTTPRequest.RequestHandler(SubscribeSink); rq.PipelineRequest(dest,R,s); MRE.WaitOne(30000,false); AbortCountDown(); if (SID=="") { AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE (Renew): " + s.ServiceURN + " << FAILED >>"); AddEvent(LogImportance.Remark,"Subscribe","Aborting tests"); result = "Subscription test failed."; // TODO state = UPnPTestStates.Failed; return; } else { AddEvent(LogImportance.Remark,"Subscribe","SUBSCRIBE (Renew): " + s.ServiceURN + " << OK >>"); // Cancel R = new HTTPMessage(); R.Directive = "UNSUBSCRIBE"; R.DirectiveObj = HTTPMessage.UnEscapeString(EventUri.PathAndQuery); R.AddTag("Host",dest.ToString()); R.AddTag("SID",SID); StartCountDown(30); SID = ""; MRE.Reset(); rq = new HTTPRequest(); rq.OnResponse += new HTTPRequest.RequestHandler(CancelSink); AddHTTPMessage(R); rq.PipelineRequest(dest,R,s); MRE.WaitOne(30000,false); AbortCountDown(); if (SID=="") { AddEvent(LogImportance.Critical,"Subscribe","UNSUBSCRIBE: " + s.ServiceURN + " << FAILED >>"); AddEvent(LogImportance.Remark,"Subscribe","Aborting tests"); result = "Subscription test failed."; state = UPnPTestStates.Failed; return; } else { AddEvent(LogImportance.Remark,"Subscribe","UNSUBSCRIBE: " + s.ServiceURN + " << OK >>"); } /* Test for duplicate SID * as well as initial events */ EventTable.Clear(); NumEvents = 0; foreach(UPnPStateVariable V in s.GetStateVariables()) { if(V.SendEvent) { ++ NumEvents; EventTable[V.Name] = false; V.OnModified -= new UPnPStateVariable.ModifiedHandler(StateVarModifiedSink); V.OnModified += new UPnPStateVariable.ModifiedHandler(StateVarModifiedSink); } } if(EventTable.Count>0) { MRE.Reset(); s.OnSubscribe -= new UPnPService.UPnPEventSubscribeHandler(OnSubscribeSink); s.OnSubscribe += new UPnPService.UPnPEventSubscribeHandler(OnSubscribeSink); s.UnSubscribe(null); foreach(UPnPStateVariable V in s.GetStateVariables()) { V.Clear(); } s.Subscribe(120,null); MRE.WaitOne(30000,false); if(SID=="") { // Subscribe Failed AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE(2): " + s.ServiceURN + " << FAILED >>"); AddEvent(LogImportance.Remark,"Subscribe","Aborting tests"); result = "Subscription test failed."; state = UPnPTestStates.Failed; return; } else { if(SID==null) { // Duplicate SID // Subscribe Failed AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE(2): " + s.ServiceURN + " << FAILED, duplicate SID >>"); AddEvent(LogImportance.Remark,"Subscribe","Aborting tests"); result = "Subscription test failed."; state = UPnPTestStates.Failed; return; } else { // Check Hashtable IDictionaryEnumerator de = EventTable.GetEnumerator(); bool OK = true; while(de.MoveNext()) { if((bool)de.Value==false) { // No Event Received OK = false; AddEvent(LogImportance.Critical,"Subscribe"," StateVariable: " + (string)de.Key + " >> Event NOT received"); } else { // OK AddEvent(LogImportance.Remark,"Subscribe"," StateVariable: " + (string)de.Key + " >> Event OK"); } } if(OK==false) { AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE(2): " + s.ServiceURN + " << FAILED, Did not receive all events >>"); AddEvent(LogImportance.Remark,"Subscribe","Aborting tests"); result = "Subscription test failed."; state = UPnPTestStates.Failed; return; } } } } } } } } result = "Subscribe Tests OK"; state = UPnPTestStates.Pass; }
private void SubscribeSink(HTTPRequest sender, HTTPMessage MSG, object Tag) { if (MSG!=null) { AddPacket(MSG); if (MSG.StatusCode==200) { SID = MSG.GetTag("SID"); } } MRE.Set(); }
/// <summary> /// This method is called by <see cref="MediaServerDevice.WebServer_OnPacketReceiveSink"/> /// and handles the HTTP-GET or HTTP-GET message requests and provides /// the appropriate response. In either case, the handler is intended /// to handle requests for resource URIs that have been mapped to local /// files using the <see cref="MediaResource.AUTOMAPFILE"/> convention. /// <para> /// If a resource cannot be mapped to a local file, /// then the method will ask upper-layer application logic /// for a stream object to send in response to the request. /// This is used primarily in scenarios where the application intentionally /// specified a contentUri value for a resource that uses the /// <see cref="MediaResource.AUTOMAPFILE"/> convention but doesn't /// actually map to a local file. This gives the upper application layer /// to provide transcoded stream objects or some specialized file stream /// that is not stored on the local file system. /// </para> /// <para> /// Upper application layers can always opt to leave the stream object /// blank, effectively indicating that the HTTP-GET or head request /// cannot be handled because such a file does not exist. /// </para> /// </summary> /// <param name="msg"></param> /// <param name="session"></param> private void HandleGetOrHeadRequest(HTTPMessage msg, HTTPSession session) { // Format of DirectiveObj will be // "/[res.m_ResourceID]/[item.ID]/[item.Title].[ext]" // We want the bool is404 = true; Exception problem = null; string resourceID = null; string objectID = null; try { DText DirectiveParser = new DText(); DirectiveParser.ATTRMARK = "/"; DirectiveParser[0] = msg.DirectiveObj; resourceID = DirectiveParser[2]; objectID = DirectiveParser[3]; IDvResource res = this.GetResource(objectID, resourceID); if (res == null) { throw new Error_GetRequestError(msg.DirectiveObj, null); } else { // attempt to figure otu the local file path and the mime type string f = MediaResource.AUTOMAPFILE; string fileName = res.ContentUri.Substring(f.Length); string type = res.ProtocolInfo.MimeType; if ((type == null) || (type == "") || (type == "*")) { //content-type not known, programmer //that built content-hierarchy didn't provide one throw new Error_GetRequestError(msg.DirectiveObj, res); } else { // must be a get or head request // check if the file actually exists if (Directory.Exists(fileName)) { throw new Error_GetRequestError(msg.DirectiveObj, res); } FileNotMapped mapping = new FileNotMapped(); mapping.RequestedResource = res; mapping.LocalInterface = session.Source.ToString(); mapping.RedirectedStream = null; if (File.Exists(fileName)) { // the file exists, so go ahead and send it mapping.RedirectedStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); } else { try { // the file doesn't exist but the owner of this // server specified some kind of locally mapped file // so perhaps they may want to route a stream object themselves if (this.OnFileNotMapped != null) { this.OnFileNotMapped (this, mapping); } } catch (Exception ofnm) { mapping.RedirectedStream = null; } } // if the RedirectedStream is blank, then it means // no stream can be sent in response to the request if (mapping.RedirectedStream != null) { lock (session) { // get the intended length, if known long expectedLength = -1; if (mapping.OverrideRedirectedStreamLength) { expectedLength = mapping.ExpectedStreamLength; } else { expectedLength = mapping.RedirectedStream.Length; } if (String.Compare(msg.Directive, "HEAD", true) == 0) { // must be a head request - reply with 200/OK, content type, content length HTTPMessage head = new HTTPMessage(); head.StatusCode = 200; head.StatusData = "OK"; head.ContentType = type; if (expectedLength >= 0) { // if we can calculate the length, // then we provide a content-length and // also indicate that range requests can be // handled. head.OverrideContentLength = true; string rangeStr = msg.GetTag("RANGE"); if ((rangeStr == null) || (rangeStr == "")) { head.AddTag("CONTENT-LENGTH", expectedLength.ToString()); head.AddTag("ACCEPT-RANGES", "bytes"); } else { ArrayList rangeSets = new ArrayList(); head.StatusCode = 206; AddRangeSets(rangeSets, rangeStr.Trim().ToLower(), expectedLength); if (rangeSets.Count == 1) { head.AddTag("Content-Range", "bytes " + ((HTTPSession.Range)(rangeSets[0])).Position.ToString() + "-" + ((int)(((HTTPSession.Range)(rangeSets[0])).Position+((HTTPSession.Range)(rangeSets[0])).Length-1)).ToString() + "/" + expectedLength.ToString()); head.AddTag("Content-Length", ((HTTPSession.Range)(rangeSets[0])).Length.ToString()); } } } else { // can't calculate length => can't do range head.AddTag("ACCEPT-RANGES", "none"); } session.Send(head); is404 = false; } else { ArrayList rangeSets = new ArrayList(); string rangeStr = msg.GetTag("RANGE"); // Only allow range requests for content where we have the // entire length and also only for requests that have // also provided an allowed range. if ((rangeStr == null) || (rangeStr != "")) { if (expectedLength >= 0) { // validate the requested ranges; if invalid range // found, send the entire document... AddRangeSets(rangeSets, rangeStr.Trim().ToLower(), expectedLength); } } // must be a get request // create an outgoing transfer that is not visible to UPNP // GetTransferProgress method, and add the transfer HttpTransfer transferInfo = new HttpTransfer(false, false, session, res, mapping.RedirectedStream, expectedLength); this.AddTransfer(session, transferInfo); if (rangeSets.Count > 0) { session.SendStreamObject(mapping.RedirectedStream, (HTTPSession.Range[])rangeSets.ToArray(typeof(HTTPSession.Range)), type); } else { //start from the beginning mapping.RedirectedStream.Seek(0, SeekOrigin.Begin); if (expectedLength >= 0) { session.SendStreamObject(mapping.RedirectedStream, expectedLength, type); } else { session.SendStreamObject(mapping.RedirectedStream, type); } } is404 = false; } } } } } } catch (Exception error) { problem = error; } if (is404) { StringBuilder sb = new StringBuilder(); sb.Append("File not found."); sb.AppendFormat("\r\n\tRequested: \"{0}\"", msg.DirectiveObj); if (objectID != null) { sb.AppendFormat("\r\n\tObjectID=\"{0}\"", objectID); } if (resourceID != null) { sb.AppendFormat("\r\n\tResourceID=\"{0}\"", resourceID); } Error_GetRequestError getHeadError = problem as Error_GetRequestError; if (getHeadError != null) { sb.Append("\r\n"); IUPnPMedia mobj = this._GetEntry(objectID); if (mobj == null) { sb.AppendFormat("\r\n\tCould not find object with ID=\"{0}\"", objectID); } else { sb.AppendFormat("\r\n\tFound object with ID=\"{0}\"", objectID); sb.Append("\r\n---Metadata---\r\n"); sb.Append(mobj.ToDidl()); } sb.Append("\r\n"); if (getHeadError.Resource == null) { sb.Append("\r\n\tResource is null."); } else { sb.Append("\r\n\tResource is not null."); string uri = getHeadError.Resource.ContentUri; if (uri== null) { sb.Append("\r\n\t\tContentUri of resource is null."); } else if (uri == "") { sb.Append("\r\n\t\tContentUri of resource is empty."); } else { sb.AppendFormat("\r\n\t\tContentUri of resource is \"{0}\"", uri); } } } if (problem != null) { sb.Append("\r\n"); Exception e = problem; sb.Append("\r\n!!! Exception information !!!"); while (e != null) { sb.AppendFormat("\r\nMessage=\"{0}\".\r\nStackTrace=\"{1}\"", e.Message, e.StackTrace); e = e.InnerException; if (e != null) { sb.Append("\r\n---InnerException---"); } } } // file has not been found so return a valid HTTP 404 error message HTTPMessage error = new HTTPMessage(); error.StatusCode = 404; error.StatusData = "File not found"; error.StringBuffer = sb.ToString(); session.Send(error); } }
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) { this.IdleTimeout = true; KeepAliveTimer.Add(this.GetHashCode(), 10); } } }
/// <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> public static 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"); 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/")==true) { TheMessage.ResponseCode = int.Parse(HdrParser[2]); int s1 = CurrentLine.IndexOf(" "); s1 = CurrentLine.IndexOf(" ",s1+1); TheMessage.ResponseData = HTTPMessage.UnEscapeString(CurrentLine.Substring(s1)); try { TheMessage.Version = HdrParser[1,2]; } catch(Exception) { TheMessage.Version = "0.9"; } } else { TheMessage.Directive = HdrParser[1]; TempString = CurrentLine.Substring(CurrentLine.LastIndexOf(" ") + 1); if (TempString.ToUpper().StartsWith("HTTP/")==false) { TheMessage.Version = "0.9"; TheMessage.DirectiveObj = HTTPMessage.UnEscapeString(TempString); } else { TheMessage.Version = TempString.Substring(TempString.IndexOf("/")+1); int fs = CurrentLine.IndexOf(" ") + 1; TheMessage.DirectiveObj = HTTPMessage.UnEscapeString(CurrentLine.Substring( fs, CurrentLine.Length-fs-TempString.Length-1)); } } String Tag=""; String TagData=""; for(int line=2;line<=parser.DCOUNT();++line) { 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=0; if (TheMessage.HasTag("Content-Length")) { try { cl = int.Parse(TheMessage.GetTag("Content-Length")); } catch(Exception) { 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); }
private void HandleWebRequest(HTTPMessage msg, HTTPSession WebSession) { DText parser = new DText(); HTTPMessage Response = new HTTPMessage(); HTTPMessage Response2 = null; String Method = msg.Directive; String MethodData = msg.DirectiveObj; if (WebSession.InternalStateObject != null) { HTTPMessage _msg = (HTTPMessage)msg.Clone(); object[] state = (object[])WebSession.InternalStateObject; _msg.DirectiveObj = (string)state[1]; VirtualDirectoryHandler t = (VirtualDirectoryHandler)state[2]; WebSession.InternalStateObject = null; t(this, _msg, WebSession, (string)state[0]); return; } if ((Method != "GET") && (Method != "HEAD") && (Method != "POST") && (Method != "SUBSCRIBE") && (Method != "UNSUBSCRIBE") && (Method != "NOTIFY")) { Response.StatusCode = 405; Response.StatusData = Method + " not supported"; WebSession.Send(Response); return; // Other methods are unknown to us } // Process Headers if (Method == "GET" || Method == "HEAD") { try { Response = Get(MethodData, WebSession.Source); } catch (UPnPCustomException ce) { OpenSource.Utilities.EventLogger.Log(ce); Response.StatusCode = ce.ErrorCode; Response.StatusData = ce.ErrorDescription; WebSession.Send(Response); return; } catch (Exception e) { OpenSource.Utilities.EventLogger.Log(e); Response.StatusCode = 500; Response.StatusData = "Internal"; Response.StringBuffer = e.ToString(); } if (Method == "HEAD") { Response.BodyBuffer = null; } WebSession.Send(Response); } if (Method == "POST") { //InvokerInfo[Thread.CurrentThread.GetHashCode()] = WebSession; try { Response = Post(MethodData, msg.StringBuffer, msg.GetTag("SOAPACTION"), WebSession); } catch (DelayedResponseException ex) { OpenSource.Utilities.EventLogger.Log(ex); InvokerInfo.Remove(Thread.CurrentThread.GetHashCode()); WebSession.StopReading(); return; } catch (UPnPCustomException ce) { OpenSource.Utilities.EventLogger.Log(this, System.Diagnostics.EventLogEntryType.Error, "UPnP Error [" + ce.ErrorCode.ToString() + "] " + ce.ErrorDescription); Response.StatusCode = 500; Response.StatusData = "Internal"; Response.StringBuffer = BuildErrorBody(ce); WebSession.Send(Response); InvokerInfo.Remove(Thread.CurrentThread.GetHashCode()); return; } catch (UPnPInvokeException ie) { Response.StatusCode = 500; Response.StatusData = "Internal"; if (ie.UPNP != null) { OpenSource.Utilities.EventLogger.Log(this, System.Diagnostics.EventLogEntryType.Error, "UPnP Error [" + ie.UPNP.ErrorCode.ToString() + "] " + ie.UPNP.ErrorDescription); Response.StringBuffer = BuildErrorBody(ie.UPNP); } else { OpenSource.Utilities.EventLogger.Log(this, System.Diagnostics.EventLogEntryType.Error, "UPnP Invocation Error [" + ie.MethodName + "] " + ie.Message); Response.StringBuffer = BuildErrorBody(new UPnPCustomException(500, ie.Message)); } WebSession.Send(Response); InvokerInfo.Remove(Thread.CurrentThread.GetHashCode()); return; } catch (UPnPTypeMismatchException tme) { OpenSource.Utilities.EventLogger.Log(tme); Response.StatusCode = 500; Response.StatusData = "Internal"; Response.StringBuffer = BuildErrorBody(new UPnPCustomException(402, tme.Message)); WebSession.Send(Response); InvokerInfo.Remove(Thread.CurrentThread.GetHashCode()); return; } catch (UPnPStateVariable.OutOfRangeException oor) { OpenSource.Utilities.EventLogger.Log(oor); Response.StatusCode = 500; Response.StatusData = "Internal"; Response.StringBuffer = BuildErrorBody(new UPnPCustomException(402, oor.Message)); WebSession.Send(Response); InvokerInfo.Remove(Thread.CurrentThread.GetHashCode()); return; } catch (System.Reflection.TargetInvocationException tie) { Exception inner = tie.InnerException; OpenSource.Utilities.EventLogger.Log(tie); while (inner.InnerException != null && (typeof(UPnPCustomException).IsInstanceOfType(inner) == false)) { inner = inner.InnerException; } if (typeof(UPnPCustomException).IsInstanceOfType(inner)) { UPnPCustomException ce = (UPnPCustomException)inner; OpenSource.Utilities.EventLogger.Log(this, System.Diagnostics.EventLogEntryType.Error, "UPnP Error [" + ce.ErrorCode.ToString() + "] " + ce.ErrorDescription); Response.StatusCode = 500; Response.StatusData = "Internal"; Response.StringBuffer = BuildErrorBody(ce); WebSession.Send(Response); InvokerInfo.Remove(Thread.CurrentThread.GetHashCode()); return; } else { Response.StatusCode = 500; Response.StatusData = "Internal"; Response.StringBuffer = BuildErrorBody(new UPnPCustomException(500, inner.ToString())); WebSession.Send(Response); OpenSource.Utilities.EventLogger.Log(inner); return; } } catch (Exception e) { Response.StatusCode = 500; Response.StatusData = "Internal"; Response.StringBuffer = BuildErrorBody(new UPnPCustomException(500, e.ToString())); WebSession.Send(Response); OpenSource.Utilities.EventLogger.Log(e); return; } WebSession.Send(Response); InvokerInfo.Remove(Thread.CurrentThread.GetHashCode()); return; } if (Method == "SUBSCRIBE") { String SID = msg.GetTag("SID"); String NT = msg.GetTag("NT"); String Timeout = msg.GetTag("Timeout"); String CallbackURL = msg.GetTag("Callback"); if (Timeout == "") { Timeout = "7200"; // Default = 2 Hours } else { Timeout = Timeout.Substring(Timeout.IndexOf("-") + 1).Trim().ToUpper(); if (Timeout == "INFINITE") { Timeout = "0"; } } if (SID != "") { // Renew RenewEvents(MethodData.Substring(1), SID, Timeout); } else { // Subscribe try { Response2 = SubscribeEvents(ref SID, MethodData.Substring(1), CallbackURL, Timeout); } catch (Exception s_exception) { OpenSource.Utilities.EventLogger.Log(s_exception); HTTPMessage err = new HTTPMessage(); err.StatusCode = 500; err.StatusData = s_exception.Message; WebSession.Send(err); return; } } if (Timeout == "0") { Timeout = "Second-infinite"; } else { Timeout = "Second-" + Timeout; } Response.StatusCode = 200; Response.StatusData = "OK"; Response.AddTag("Server", "Windows NT/5.0, UPnP/1.0"); Response.AddTag("SID", SID); Response.AddTag("Timeout", Timeout); WebSession.Send(Response); if (Response2 != null) { Uri[] cbURL = ParseEventURL(CallbackURL); for (int x = 0; x < cbURL.Length; ++x) { Response2.DirectiveObj = HTTPMessage.UnEscapeString(cbURL[x].PathAndQuery); Response2.AddTag("Host", cbURL[x].Host + ":" + cbURL[x].Port.ToString()); IPEndPoint d = new IPEndPoint(IPAddress.Parse(cbURL[x].Host), cbURL[x].Port); HTTPRequest R = new HTTPRequest(); R.OnResponse += new HTTPRequest.RequestHandler(HandleInitialEvent); this.InitialEventTable[R] = R; R.PipelineRequest(d, Response2, null); } } } if (Method == "UNSUBSCRIBE") { CancelEvent(MethodData.Substring(1), msg.GetTag("SID")); Response.StatusCode = 200; Response.StatusData = "OK"; WebSession.Send(Response); } }