public bool ProcessP2PMessage(P2PBridge bridge, Contact source, Guid sourceGuid, P2PMessage p2pMessage) { // 1) SLP BUFFERING: Combine splitted SLP messages if (slpMessagePool.BufferMessage(ref p2pMessage)) { // * Buffering: Not completed yet, we must wait next packets -OR- // * Invalid packet received: Don't kill me, just ignore it... return(true); } Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, String.Format("Received P2PMessage from {0}\r\n{1}", bridge.ToString(), p2pMessage.ToDebugString()), GetType().Name); // 2) CHECK SLP: Check destination, source, endpoints SLPMessage slp = p2pMessage.IsSLPData ? p2pMessage.InnerMessage as SLPMessage : null; if (slp != null) { if (!slpHandler.CheckSLPMessage(bridge, source, sourceGuid, p2pMessage, slp)) { return(true); // HANDLED, This SLP is not for us. } } // 3) FIRST SLP MESSAGE: Create applications/sessions based on invitation if (slp != null && slp is SLPRequestMessage && (slp as SLPRequestMessage).Method == "INVITE" && slp.ContentType == "application/x-msnmsgr-sessionreqbody") { uint appId = slp.BodyValues.ContainsKey("AppID") ? uint.Parse(slp.BodyValues["AppID"].Value) : 0; Guid eufGuid = slp.BodyValues.ContainsKey("EUF-GUID") ? new Guid(slp.BodyValues["EUF-GUID"].Value) : Guid.Empty; P2PVersion ver = slp.P2PVersion; if (P2PApplication.IsRegistered(eufGuid, appId)) { P2PSession newSession = FindSessionByCallId(slp.CallId, ver); if (newSession == null) { newSession = new P2PSession(slp as SLPRequestMessage, p2pMessage, nsMessageHandler, bridge); newSession.Closed += P2PSessionClosed; if (newSession.Version == P2PVersion.P2PV2) { p2pV2Sessions.Add(newSession); } else { p2pV1Sessions.Add(newSession); } } else { // P2PSession exists, bridge changed... if (newSession.Bridge != bridge) { // BRIDGETODO } } return(true); } // Not registered application. Decline it without create a new session... slpHandler.SendSLPStatus(bridge, p2pMessage, source, sourceGuid, 603, "Decline"); return(true); } // 4) FIND SESSION: Search session by SessionId/ExpectedIdentifier P2PSession session = FindSession(p2pMessage, slp); if (session != null) { // ResetTimeoutTimer(); // Keep track of theremoteIdentifier // Keep track of the remote identifier session.remoteIdentifier = (p2pMessage.Version == P2PVersion.P2PV2) ? p2pMessage.Header.Identifier + p2pMessage.Header.MessageSize : p2pMessage.Header.Identifier; // Session SLP if (slp != null && slpHandler.HandleP2PSessionSignal(bridge, p2pMessage, slp, session)) { return(true); } // Session Data if (slp == null && session.ProcessP2PData(bridge, p2pMessage)) { return(true); } } return(false); }
internal bool HandleACK(P2PMessage p2pMessage) { bool isAckOrNak = false; if (p2pMessage.Header.IsAcknowledgement || p2pMessage.Header.IsNegativeAck) { P2PAckMessageEventArgs e = null; uint ackNakId = 0; isAckOrNak = true; if (p2pMessage.Version == P2PVersion.P2PV1) { lock (ackHandlersV1) { if (ackHandlersV1.ContainsKey(p2pMessage.Header.AckIdentifier)) { ackNakId = p2pMessage.Header.AckIdentifier; e = ackHandlersV1[ackNakId]; ackHandlersV1.Remove(ackNakId); } } } else if (p2pMessage.Version == P2PVersion.P2PV2) { lock (ackHandlersV2) { if (ackHandlersV2.ContainsKey(p2pMessage.Header.AckIdentifier)) { ackNakId = p2pMessage.Header.AckIdentifier; e = ackHandlersV2[ackNakId]; ackHandlersV2.Remove(ackNakId); } else if (ackHandlersV2.ContainsKey(p2pMessage.V2Header.NakIdentifier)) { ackNakId = p2pMessage.V2Header.NakIdentifier; e = ackHandlersV2[ackNakId]; ackHandlersV2.Remove(ackNakId); } } } if (ackNakId == 0) { Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("!!!!!! No AckHandler registered for ack/nak {0}:\r\n{1}", p2pMessage.Header.AckIdentifier, p2pMessage.ToDebugString()), GetType().Name); } else { if (e != null && e.AckHandler != null) { e.AckHandler(p2pMessage); } else { Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("!!!!!! No AckHandler pair for ack {0}\r\n{1}", ackNakId, p2pMessage.ToDebugString()), GetType().Name); } } } return isAckOrNak; }
/// <summary> /// Buffers incompleted P2PMessage SLP messages. Ignores data and control messages. /// </summary> /// <param name="p2pMessage"></param> /// <returns> /// true if the P2PMessage is buffering (not completed) or invalid packet received; /// false if the p2p message fully buffered or no need to buffer. /// </returns> public bool BufferMessage(ref P2PMessage p2pMessage) { // P2PV1 and P2PV2 check if (p2pMessage.Header.MessageSize == 0 || // Ack message or Unsplitted p2pMessage.Header.SessionId > 0) // Data message { return false; // No need to buffer } // P2PV2 pooling if (p2pMessage.Version == P2PVersion.P2PV2) { if ((p2pMessage.V2Header.TFCombination == TFCombination.First && p2pMessage.V2Header.DataRemaining == 0) || // Unsplitted SLP message or data preparation message (p2pMessage.V2Header.TFCombination > TFCombination.First)) // Data message { return false; // No need to buffer } // First splitted SLP message. if (p2pMessage.V2Header.TFCombination == TFCombination.First && p2pMessage.V2Header.DataRemaining > 0) { P2PMessage totalMessage = new P2PMessage(p2pMessage); // Copy it ulong totalSize = (ulong)(p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength) + p2pMessage.V2Header.DataRemaining; totalMessage.InnerBody = new byte[totalSize]; // Allocate buffer as needed Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)0, (long)p2pMessage.InnerBody.Length); lock (incompletedP2PV2Messages) incompletedP2PV2Messages[p2pMessage.V2Header.Identifier + p2pMessage.V2Header.MessageSize] = totalMessage; return true; // Buffering } // Other splitted SLP messages if (p2pMessage.V2Header.TFCombination == TFCombination.None) { lock (incompletedP2PV2Messages) { if (incompletedP2PV2Messages.ContainsKey(p2pMessage.V2Header.Identifier)) { if (incompletedP2PV2Messages[p2pMessage.V2Header.Identifier].V2Header.PackageNumber == p2pMessage.V2Header.PackageNumber) { P2PMessage totalMessage = incompletedP2PV2Messages[p2pMessage.V2Header.Identifier]; ulong dataSize = Math.Min(((ulong)(p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength)), totalMessage.V2Header.DataRemaining); ulong offSet = ((ulong)totalMessage.InnerBody.LongLength) - totalMessage.V2Header.DataRemaining; // Check range and buffer overflow... if (((p2pMessage.V2Header.DataRemaining + (ulong)dataSize) == totalMessage.V2Header.DataRemaining) && (ulong)(dataSize + offSet + p2pMessage.V2Header.DataRemaining) == (ulong)totalMessage.InnerBody.LongLength) { Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)offSet, (long)dataSize); uint originalIdentifier = p2pMessage.V2Header.Identifier; uint newIdentifier = p2pMessage.V2Header.Identifier + p2pMessage.V2Header.MessageSize; totalMessage.V2Header.DataRemaining = p2pMessage.V2Header.DataRemaining; totalMessage.V2Header.Identifier = newIdentifier; if (originalIdentifier != newIdentifier) { incompletedP2PV2Messages.Remove(originalIdentifier); } // Don't debug p2p inner packet (SLP) here. Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, " Buffering splitted SLP message! DataRemaining:" + totalMessage.V2Header.DataRemaining + " NewIdentifier: " + newIdentifier); if (p2pMessage.V2Header.DataRemaining > 0) { // Don't debug p2p packet here. Because it hasn't completed yet and SLPMessage.Parse() fails... incompletedP2PV2Messages[newIdentifier] = totalMessage; return true; // Buffering } else // Last part { totalMessage.InnerBody = totalMessage.InnerBody; // Refresh... DataRemaining=0 deletes data headers. totalMessage.V2Header.Identifier = newIdentifier - totalMessage.Header.MessageSize; Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "A splitted message was combined :\r\n" + totalMessage.ToDebugString()); p2pMessage = totalMessage; return false; // We have the whole message } } } // Invalid packet received!!! Ignore and delete it... incompletedP2PV2Messages.Remove(p2pMessage.V2Header.Identifier); Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "INVALID P2PV2 PACKET received!!! Ignored and deleted:\r\n" + p2pMessage.ToDebugString()); } } } } else // P2PV1 pooling { if ((p2pMessage.V1Header.MessageSize == p2pMessage.V1Header.TotalSize) || // Whole data ((p2pMessage.V1Header.Flags & P2PFlag.Data) == P2PFlag.Data)) // Data message { return false; // No need to buffer } lock (incompletedP2PV1Messages) { if (false == incompletedP2PV1Messages.ContainsKey(p2pMessage.Header.Identifier)) { byte[] totalPayload = new byte[p2pMessage.V1Header.TotalSize]; Array.Copy(p2pMessage.InnerBody, 0, totalPayload, (long)p2pMessage.V1Header.Offset, (long)p2pMessage.V1Header.MessageSize); P2PMessage copyMessage = new P2PMessage(p2pMessage); copyMessage.InnerBody = totalPayload; copyMessage.V1Header.Offset = p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize; incompletedP2PV1Messages[p2pMessage.Header.Identifier] = copyMessage; return true; // Buffering } P2PMessage totalMessage = incompletedP2PV1Messages[p2pMessage.Header.Identifier]; if (p2pMessage.V1Header.TotalSize == totalMessage.V1Header.TotalSize && (p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize) <= totalMessage.Header.TotalSize) { Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)p2pMessage.V1Header.Offset, (long)p2pMessage.V1Header.MessageSize); totalMessage.V1Header.Offset = p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize; // Last packet if (totalMessage.V1Header.Offset == p2pMessage.V1Header.TotalSize) { totalMessage.V1Header.Offset = 0; incompletedP2PV1Messages.Remove(p2pMessage.Header.Identifier); p2pMessage = totalMessage; return false; // We have the whole message } return true; // Buffering } // Invalid packet received!!! Ignore and delete it... incompletedP2PV1Messages.Remove(p2pMessage.Header.Identifier); Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "INVALID P2PV1 PACKET received!!! Ignored and deleted:\r\n" + p2pMessage.ToDebugString()); } } return true; // Invalid packet, don't kill me. }
public void ProcessP2PMessage(Contact source, Guid sourceGuid, P2PMessage p2pMessage) { // HANDLE RAK: RAKs are session independent and mustn't be quoted on bridges. bool requireAck = HandleRAK(source, sourceGuid, p2pMessage); // HANDLE ACK: ACK/NAK to our RAK message if (HandleACK(p2pMessage)) { return; } // PASS TO P2PHandler if (nsMessageHandler.P2PHandler.ProcessP2PMessage(this, source, sourceGuid, p2pMessage)) { return; } if (!requireAck) { // UNHANDLED P2P MESSAGE Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("*******Unhandled P2P message ****** \r\n{0}", p2pMessage.ToDebugString()), GetType().Name); // Keep RemoteID Synchronized, I think we must track remoteIdentifier here... // Send NAK?????? } }
/// <summary> /// Buffers incompleted P2PMessage SLP messages. Ignores data and control messages. /// </summary> /// <param name="p2pMessage"></param> /// <returns> /// true if the P2PMessage is buffering (not completed) or invalid packet received; /// false if the p2p message fully buffered or no need to buffer. /// </returns> public bool BufferMessage(ref P2PMessage p2pMessage) { // P2PV1 and P2PV2 check if (p2pMessage.Header.MessageSize == 0 || // Ack message or Unsplitted p2pMessage.Header.SessionId > 0) // Data message { return(false); // No need to buffer } // P2PV2 pooling if (p2pMessage.Version == P2PVersion.P2PV2) { if ((p2pMessage.V2Header.TFCombination == TFCombination.First && p2pMessage.V2Header.DataRemaining == 0) || // Unsplitted SLP message or data preparation message (p2pMessage.V2Header.TFCombination > TFCombination.First)) // Data message { return(false); // No need to buffer } // First splitted SLP message. if (p2pMessage.V2Header.TFCombination == TFCombination.First && p2pMessage.V2Header.DataRemaining > 0) { P2PMessage totalMessage = new P2PMessage(p2pMessage); // Copy it ulong totalSize = (ulong)(p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength) + p2pMessage.V2Header.DataRemaining; totalMessage.InnerBody = new byte[totalSize]; // Allocate buffer as needed Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)0, (long)p2pMessage.InnerBody.Length); lock (incompletedP2PV2Messages) incompletedP2PV2Messages[p2pMessage.V2Header.Identifier + p2pMessage.V2Header.MessageSize] = totalMessage; return(true); // Buffering } // Other splitted SLP messages if (p2pMessage.V2Header.TFCombination == TFCombination.None) { lock (incompletedP2PV2Messages) { if (incompletedP2PV2Messages.ContainsKey(p2pMessage.V2Header.Identifier)) { if (incompletedP2PV2Messages[p2pMessage.V2Header.Identifier].V2Header.PackageNumber == p2pMessage.V2Header.PackageNumber) { P2PMessage totalMessage = incompletedP2PV2Messages[p2pMessage.V2Header.Identifier]; ulong dataSize = Math.Min(((ulong)(p2pMessage.V2Header.MessageSize - p2pMessage.V2Header.DataPacketHeaderLength)), totalMessage.V2Header.DataRemaining); ulong offSet = ((ulong)totalMessage.InnerBody.LongLength) - totalMessage.V2Header.DataRemaining; // Check range and buffer overflow... if (((p2pMessage.V2Header.DataRemaining + (ulong)dataSize) == totalMessage.V2Header.DataRemaining) && (ulong)(dataSize + offSet + p2pMessage.V2Header.DataRemaining) == (ulong)totalMessage.InnerBody.LongLength) { Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)offSet, (long)dataSize); uint originalIdentifier = p2pMessage.V2Header.Identifier; uint newIdentifier = p2pMessage.V2Header.Identifier + p2pMessage.V2Header.MessageSize; totalMessage.V2Header.DataRemaining = p2pMessage.V2Header.DataRemaining; totalMessage.V2Header.Identifier = newIdentifier; if (originalIdentifier != newIdentifier) { incompletedP2PV2Messages.Remove(originalIdentifier); } // Don't debug p2p inner packet (SLP) here. Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, " Buffering splitted SLP message! DataRemaining:" + totalMessage.V2Header.DataRemaining + " NewIdentifier: " + newIdentifier); if (p2pMessage.V2Header.DataRemaining > 0) { // Don't debug p2p packet here. Because it hasn't completed yet and SLPMessage.Parse() fails... incompletedP2PV2Messages[newIdentifier] = totalMessage; return(true); // Buffering } else // Last part { totalMessage.InnerBody = totalMessage.InnerBody; // Refresh... DataRemaining=0 deletes data headers. totalMessage.V2Header.Identifier = newIdentifier - totalMessage.Header.MessageSize; Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, "A splitted message was combined :\r\n" + totalMessage.ToDebugString()); p2pMessage = totalMessage; return(false); // We have the whole message } } } // Invalid packet received!!! Ignore and delete it... incompletedP2PV2Messages.Remove(p2pMessage.V2Header.Identifier); Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "INVALID P2PV2 PACKET received!!! Ignored and deleted:\r\n" + p2pMessage.ToDebugString()); } } } } else // P2PV1 pooling { if ((p2pMessage.V1Header.MessageSize == p2pMessage.V1Header.TotalSize) || // Whole data ((p2pMessage.V1Header.Flags & P2PFlag.Data) == P2PFlag.Data)) // Data message { return(false); // No need to buffer } lock (incompletedP2PV1Messages) { if (false == incompletedP2PV1Messages.ContainsKey(p2pMessage.Header.Identifier)) { byte[] totalPayload = new byte[p2pMessage.V1Header.TotalSize]; Array.Copy(p2pMessage.InnerBody, 0, totalPayload, (long)p2pMessage.V1Header.Offset, (long)p2pMessage.V1Header.MessageSize); P2PMessage copyMessage = new P2PMessage(p2pMessage); copyMessage.InnerBody = totalPayload; copyMessage.V1Header.Offset = p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize; incompletedP2PV1Messages[p2pMessage.Header.Identifier] = copyMessage; return(true); // Buffering } P2PMessage totalMessage = incompletedP2PV1Messages[p2pMessage.Header.Identifier]; if (p2pMessage.V1Header.TotalSize == totalMessage.V1Header.TotalSize && (p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize) <= totalMessage.Header.TotalSize) { Array.Copy(p2pMessage.InnerBody, 0, totalMessage.InnerBody, (long)p2pMessage.V1Header.Offset, (long)p2pMessage.V1Header.MessageSize); totalMessage.V1Header.Offset = p2pMessage.V1Header.Offset + p2pMessage.V1Header.MessageSize; // Last packet if (totalMessage.V1Header.Offset == p2pMessage.V1Header.TotalSize) { totalMessage.V1Header.Offset = 0; incompletedP2PV1Messages.Remove(p2pMessage.Header.Identifier); p2pMessage = totalMessage; return(false); // We have the whole message } return(true); // Buffering } // Invalid packet received!!! Ignore and delete it... incompletedP2PV1Messages.Remove(p2pMessage.Header.Identifier); Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "INVALID P2PV1 PACKET received!!! Ignored and deleted:\r\n" + p2pMessage.ToDebugString()); } } return(true); // Invalid packet, don't kill me. }
public bool ProcessP2PMessage(P2PBridge bridge, Contact source, Guid sourceGuid, P2PMessage p2pMessage) { // 1) SLP BUFFERING: Combine splitted SLP messages if (slpMessagePool.BufferMessage(ref p2pMessage)) { // * Buffering: Not completed yet, we must wait next packets -OR- // * Invalid packet received: Don't kill me, just ignore it... return true; } Trace.WriteLineIf(Settings.TraceSwitch.TraceVerbose, String.Format("Received P2PMessage from {0}\r\n{1}", bridge.ToString(), p2pMessage.ToDebugString()), GetType().Name); // 2) CHECK SLP: Check destination, source, endpoints SLPMessage slp = p2pMessage.IsSLPData ? p2pMessage.InnerMessage as SLPMessage : null; if (slp != null) { if (!slpHandler.CheckSLPMessage(bridge, source, sourceGuid, p2pMessage, slp)) return true; // HANDLED, This SLP is not for us. } // 3) FIRST SLP MESSAGE: Create applications/sessions based on invitation if (slp != null && slp is SLPRequestMessage && (slp as SLPRequestMessage).Method == "INVITE" && slp.ContentType == "application/x-msnmsgr-sessionreqbody") { uint appId = slp.BodyValues.ContainsKey("AppID") ? uint.Parse(slp.BodyValues["AppID"].Value) : 0; Guid eufGuid = slp.BodyValues.ContainsKey("EUF-GUID") ? new Guid(slp.BodyValues["EUF-GUID"].Value) : Guid.Empty; P2PVersion ver = slp.P2PVersion; if (P2PApplication.IsRegistered(eufGuid, appId)) { P2PSession newSession = FindSessionByCallId(slp.CallId, ver); if (newSession == null) { newSession = new P2PSession(slp as SLPRequestMessage, p2pMessage, nsMessageHandler, bridge); newSession.Closed += P2PSessionClosed; if (newSession.Version == P2PVersion.P2PV2) p2pV2Sessions.Add(newSession); else p2pV1Sessions.Add(newSession); } else { // P2PSession exists, bridge changed... if (newSession.Bridge != bridge) { // BRIDGETODO } } return true; } // Not registered application. Decline it without create a new session... slpHandler.SendSLPStatus(bridge, p2pMessage, source, sourceGuid, 603, "Decline"); return true; } // 4) FIND SESSION: Search session by SessionId/ExpectedIdentifier P2PSession session = FindSession(p2pMessage, slp); if (session != null) { // ResetTimeoutTimer(); // Keep track of theremoteIdentifier // Keep track of the remote identifier session.remoteIdentifier = (p2pMessage.Version == P2PVersion.P2PV2) ? p2pMessage.Header.Identifier + p2pMessage.Header.MessageSize : p2pMessage.Header.Identifier; // Session SLP if (slp != null && slpHandler.HandleP2PSessionSignal(bridge, p2pMessage, slp, session)) return true; // Session Data if (slp == null && session.ProcessP2PData(bridge, p2pMessage)) return true; } return false; }
internal bool HandleACK(P2PMessage p2pMessage) { bool isAckOrNak = false; if (p2pMessage.Header.IsAcknowledgement || p2pMessage.Header.IsNegativeAck) { P2PAckMessageEventArgs e = null; uint ackNakId = 0; isAckOrNak = true; if (p2pMessage.Version == P2PVersion.P2PV1) { lock (ackHandlersV1) { if (ackHandlersV1.ContainsKey(p2pMessage.Header.AckIdentifier)) { ackNakId = p2pMessage.Header.AckIdentifier; e = ackHandlersV1[ackNakId]; ackHandlersV1.Remove(ackNakId); } } } else if (p2pMessage.Version == P2PVersion.P2PV2) { lock (ackHandlersV2) { if (ackHandlersV2.ContainsKey(p2pMessage.Header.AckIdentifier)) { ackNakId = p2pMessage.Header.AckIdentifier; e = ackHandlersV2[ackNakId]; ackHandlersV2.Remove(ackNakId); } else if (ackHandlersV2.ContainsKey(p2pMessage.V2Header.NakIdentifier)) { ackNakId = p2pMessage.V2Header.NakIdentifier; e = ackHandlersV2[ackNakId]; ackHandlersV2.Remove(ackNakId); } } } if (ackNakId == 0) { Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("!!!!!! No AckHandler registered for ack/nak {0}:\r\n{1}", p2pMessage.Header.AckIdentifier, p2pMessage.ToDebugString()), GetType().Name); } else { if (e != null && e.AckHandler != null) { e.AckHandler(p2pMessage); } else { Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("!!!!!! No AckHandler pair for ack {0}\r\n{1}", ackNakId, p2pMessage.ToDebugString()), GetType().Name); } } } return(isAckOrNak); }