/// <summary> /// Creates a new session initiated locally and prepares the invitation message. /// The next step must be Invite(). /// </summary> public P2PSession(P2PApplication app) { p2pApplication = app; version = app.P2PVersion; localContact = app.Local; remoteContact = app.Remote; localContactEndPointID = NSMessageHandler.MachineGuid; remoteContactEndPointID = app.Remote.SelectBestEndPointId(); nsMessageHandler = app.Local.NSMessageHandler; sessionId = (uint)random.Next(50000, int.MaxValue); // These 2 fields are set when optimal bridge found. localBaseIdentifier = 0; localIdentifier = 0; invitation = new SLPRequestMessage(RemoteContactEPIDString, MSNSLPRequestMethod.INVITE); invitation.Target = RemoteContactEPIDString; invitation.Source = LocalContactEPIDString; invitation.ContentType = "application/x-msnmsgr-sessionreqbody"; invitation.BodyValues["SessionID"] = SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); app.SetupInviteMessage(invitation); app.P2PSession = this; // Register events remoteContact.DirectBridgeEstablished += RemoteDirectBridgeEstablished; Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, String.Format("{0} created (Initiated locally)", SessionId), GetType().Name); status = P2PSessionStatus.WaitingForRemote; // Next step must be: Invite() }
internal bool SendDirectInvite() { // Skip if we're currently using a TCPBridge. if (Remote.DirectBridge != null && Remote.DirectBridge.IsOpen) { return(false); } int netId; string connectionType = ConnectionType(nsMessageHandler, out netId); P2PMessage p2pMessage = new P2PMessage(Version); Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, String.Format("Connection type set to {0} for session {1}", connectionType, SessionId.ToString())); // Create the message SLPRequestMessage slpMessage = new SLPRequestMessage(RemoteContactEPIDString, MSNSLPRequestMethod.INVITE); slpMessage.Source = LocalContactEPIDString; slpMessage.CSeq = 0; slpMessage.CallId = Invitation.CallId; slpMessage.MaxForwards = 0; slpMessage.ContentType = "application/x-msnmsgr-transreqbody"; slpMessage.BodyValues["Bridges"] = "TCPv1 SBBridge"; slpMessage.BodyValues["Capabilities-Flags"] = "1"; slpMessage.BodyValues["NetID"] = netId.ToString(CultureInfo.InvariantCulture); slpMessage.BodyValues["Conn-Type"] = connectionType; slpMessage.BodyValues["TCP-Conn-Type"] = connectionType; slpMessage.BodyValues["UPnPNat"] = "false"; // UPNP Enabled slpMessage.BodyValues["ICF"] = (connectionType == "Firewall").ToString(); // Firewall enabled slpMessage.BodyValues["Nat-Trav-Msg-Type"] = "WLX-Nat-Trav-Msg-Direct-Connect-Req"; // We support Hashed-Nonce ( 2 way handshake ) Remote.GenerateNewDCKeys(); slpMessage.BodyValues["Hashed-Nonce"] = Remote.dcLocalHashedNonce.ToString("B").ToUpper(CultureInfo.InvariantCulture); p2pMessage.InnerMessage = slpMessage; if (p2pMessage.Version == P2PVersion.P2PV2) { p2pMessage.V2Header.TFCombination = TFCombination.First; } else if (p2pMessage.Version == P2PVersion.P2PV1) { p2pMessage.V1Header.Flags = P2PFlag.MSNSLPInfo; } // These 3 step is very important... // 1- Stop sending for this session on sdgbridge until we receive a response to the direct invite or the timeout expires nsMessageHandler.SDGBridge.StopSending(this); // 2- Setup a dc timer. SetupDCTimer(); // 3- Don't pass p2psession to the sdg bridge. Because, sdgbridge stopped this session. nsMessageHandler.SDGBridge.Send(null /*must be null to bypass queueing*/, Remote, RemoteContactEndPointID, p2pMessage); return(true); }
/// <summary> /// Closes the session. /// </summary> public void Close() { if (status == P2PSessionStatus.Closing) { Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("P2PSession {0} was already closing, forcing unclean closure", SessionId), GetType().Name); OnClosed(new ContactEventArgs(Local)); } else { OnClosing(new ContactEventArgs(Local)); SLPRequestMessage slpMessage = new SLPRequestMessage(RemoteContactEPIDString, "BYE"); slpMessage.Target = RemoteContactEPIDString; slpMessage.Source = LocalContactEPIDString; slpMessage.Branch = invitation.Branch; slpMessage.CallId = invitation.CallId; slpMessage.MaxForwards = 0; slpMessage.ContentType = "application/x-msnmsgr-sessionclosebody"; slpMessage.BodyValues["SessionID"] = SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); P2PMessage p2pMessage = new P2PMessage(Version); if (version == P2PVersion.P2PV1) { p2pMessage.V1Header.Flags = P2PFlag.MSNSLPInfo; } else if (version == P2PVersion.P2PV2) { p2pMessage.V2Header.OperationCode = (byte)OperationCode.RAK; p2pMessage.V2Header.TFCombination = TFCombination.First; p2pMessage.V2Header.PackageNumber = ++p2pBridge.PackageNo; } p2pMessage.InnerMessage = slpMessage; Send(p2pMessage, delegate(P2PMessage ack) { OnClosed(new ContactEventArgs(Local)); }); } }
private static void ProcessDCRespInvite(SLPMessage message, NSMessageHandler ns, P2PSession startupSession) { MimeDictionary bodyValues = message.BodyValues; // Check the protocol if (bodyValues.ContainsKey("Bridge") && bodyValues["Bridge"].ToString() == "TCPv1" && bodyValues.ContainsKey("Listening") && bodyValues["Listening"].ToString().ToLowerInvariant().IndexOf("true") >= 0) { Contact remote = ns.ContactList.GetContactWithCreate(message.FromEmailAccount, IMAddressInfoType.WindowsLive); Guid remoteGuid = message.FromEndPoint; DCNonceType dcNonceType; Guid remoteNonce = ParseDCNonce(message.BodyValues, out dcNonceType); bool hashed = (dcNonceType == DCNonceType.Sha1); Guid replyGuid = hashed ? remote.dcPlainKey : remoteNonce; IPEndPoint[] selectedPoint = SelectIPEndPoint(bodyValues, ns); if (selectedPoint != null && selectedPoint.Length > 0) { P2PVersion ver = message.P2PVersion; // We must connect to the remote client ConnectivitySettings settings = new ConnectivitySettings(); settings.EndPoints = selectedPoint; remote.DirectBridge = CreateDirectConnection(remote, remoteGuid, ver, settings, replyGuid, remoteNonce, hashed, ns, startupSession); bool needConnectingEndpointInfo; if (bodyValues.ContainsKey("NeedConnectingEndpointInfo") && bool.TryParse(bodyValues["NeedConnectingEndpointInfo"], out needConnectingEndpointInfo) && needConnectingEndpointInfo == true) { IPEndPoint ipep = ((TCPv1Bridge)remote.DirectBridge).LocalEndPoint; string desc = "stroPdnAsrddAlanretnI4vPI"; char[] rev = ipep.ToString().ToCharArray(); Array.Reverse(rev); string ipandport = new string(rev); SLPRequestMessage slpResponseMessage = new SLPRequestMessage(message.Source, MSNSLPRequestMethod.ACK); slpResponseMessage.Source = message.Target; slpResponseMessage.Via = message.Via; slpResponseMessage.CSeq = 0; slpResponseMessage.CallId = Guid.Empty; slpResponseMessage.MaxForwards = 0; slpResponseMessage.ContentType = @"application/x-msnmsgr-transdestaddrupdate"; slpResponseMessage.BodyValues[desc] = ipandport; slpResponseMessage.BodyValues["Nat-Trav-Msg-Type"] = "WLX-Nat-Trav-Msg-Updated-Connecting-Port"; P2PMessage msg = new P2PMessage(ver); msg.InnerMessage = slpResponseMessage; ns.SDGBridge.Send(null, remote, remoteGuid, msg); } return; } } if (startupSession != null) startupSession.DirectNegotiationFailed(); }
internal bool SendDirectInvite() { // Skip if we're currently using a TCPBridge. if (Remote.DirectBridge != null && Remote.DirectBridge.IsOpen) return false; int netId; string connectionType = ConnectionType(nsMessageHandler, out netId); P2PMessage p2pMessage = new P2PMessage(Version); Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, String.Format("Connection type set to {0} for session {1}", connectionType, SessionId.ToString())); // Create the message SLPRequestMessage slpMessage = new SLPRequestMessage(RemoteContactEPIDString, MSNSLPRequestMethod.INVITE); slpMessage.Source = LocalContactEPIDString; slpMessage.CSeq = 0; slpMessage.CallId = Invitation.CallId; slpMessage.MaxForwards = 0; slpMessage.ContentType = "application/x-msnmsgr-transreqbody"; slpMessage.BodyValues["Bridges"] = "TCPv1 SBBridge"; slpMessage.BodyValues["Capabilities-Flags"] = "1"; slpMessage.BodyValues["NetID"] = netId.ToString(CultureInfo.InvariantCulture); slpMessage.BodyValues["Conn-Type"] = connectionType; slpMessage.BodyValues["TCP-Conn-Type"] = connectionType; slpMessage.BodyValues["UPnPNat"] = "false"; // UPNP Enabled slpMessage.BodyValues["ICF"] = (connectionType == "Firewall").ToString(); // Firewall enabled slpMessage.BodyValues["Nat-Trav-Msg-Type"] = "WLX-Nat-Trav-Msg-Direct-Connect-Req"; // We support Hashed-Nonce ( 2 way handshake ) Remote.GenerateNewDCKeys(); slpMessage.BodyValues["Hashed-Nonce"] = Remote.dcLocalHashedNonce.ToString("B").ToUpper(CultureInfo.InvariantCulture); p2pMessage.InnerMessage = slpMessage; if (p2pMessage.Version == P2PVersion.P2PV2) { p2pMessage.V2Header.TFCombination = TFCombination.First; } else if (p2pMessage.Version == P2PVersion.P2PV1) { p2pMessage.V1Header.Flags = P2PFlag.MSNSLPInfo; } // These 3 step is very important... // 1- Stop sending for this session on sdgbridge until we receive a response to the direct invite or the timeout expires nsMessageHandler.SDGBridge.StopSending(this); // 2- Setup a dc timer. SetupDCTimer(); // 3- Don't pass p2psession to the sdg bridge. Because, sdgbridge stopped this session. nsMessageHandler.SDGBridge.Send(null /*must be null to bypass queueing*/, Remote, RemoteContactEndPointID, p2pMessage); return true; }
internal bool HandleP2PSessionSignal(P2PBridge bridge, P2PMessage p2pMessage, SLPMessage slp, P2PSession session) { if (slp is SLPRequestMessage) { SLPRequestMessage slpRequest = slp as SLPRequestMessage; if (slpRequest.ContentType == "application/x-msnmsgr-sessionclosebody" && slpRequest.Method == "BYE") { if (p2pMessage.Version == P2PVersion.P2PV1) { P2PMessage byeAck = p2pMessage.CreateAcknowledgement(); byeAck.V1Header.Flags = P2PFlag.CloseSession; session.Send(byeAck); } else if (p2pMessage.Version == P2PVersion.P2PV2) { SLPRequestMessage slpMessage = new SLPRequestMessage(session.RemoteContactEPIDString, "BYE"); slpMessage.Target = session.RemoteContactEPIDString; slpMessage.Source = session.LocalContactEPIDString; slpMessage.Branch = session.Invitation.Branch; slpMessage.CallId = session.Invitation.CallId; slpMessage.ContentType = "application/x-msnmsgr-sessionclosebody"; slpMessage.BodyValues["SessionID"] = session.SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); session.Send(session.WrapSLPMessage(slpMessage)); } session.OnClosed(new ContactEventArgs(session.Remote)); return true; } else { if (slpRequest.ContentType == "application/x-msnmsgr-transreqbody" || slpRequest.ContentType == "application/x-msnmsgr-transrespbody" || slpRequest.ContentType == "application/x-msnmsgr-transdestaddrupdate") { P2PSession.ProcessDirectInvite(slpRequest, nsMessageHandler, session); // Direct connection invite return true; } } } else if (slp is SLPStatusMessage) { SLPStatusMessage slpStatus = slp as SLPStatusMessage; if (slpStatus.Code == 200) // OK { if (slpStatus.ContentType == "application/x-msnmsgr-transrespbody") { P2PSession.ProcessDirectInvite(slpStatus, nsMessageHandler, session); return true; } else { if (session.Application != null) { session.OnActive(EventArgs.Empty); session.Application.Start(); return true; } } } else if (slpStatus.Code == 603) // Decline { session.OnClosed(new ContactEventArgs(session.Remote)); return true; } else if (slpStatus.Code == 500) // Internal Error { return true; } } Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("Unhandled SLP Message in session:---->>\r\n{0}", p2pMessage.ToString()), GetType().Name); session.OnError(EventArgs.Empty); return true; }
/// <summary> /// Creates a new session initiated remotely. If the application cannot be handled, decline message will be sent. /// The application will handle all messages automatically and no user interaction is required if AutoAccept is true. /// If AutoAccept is false, <see cref="P2PHandler.InvitationReceived"/> event will be fired. /// </summary> public P2PSession(SLPRequestMessage slp, P2PMessage msg, NSMessageHandler ns, P2PBridge bridge) { nsMessageHandler = ns; invitation = slp; version = slp.P2PVersion; if (version == P2PVersion.P2PV1) { localContact = (slp.ToEmailAccount == ns.Owner.Account) ? ns.Owner : ns.ContactList.GetContactWithCreate(slp.ToEmailAccount, IMAddressInfoType.WindowsLive); remoteContact = ns.ContactList.GetContactWithCreate(slp.FromEmailAccount, IMAddressInfoType.WindowsLive); } else { localContact = (slp.ToEmailAccount == ns.Owner.Account) ? ns.Owner : ns.ContactList.GetContactWithCreate(slp.ToEmailAccount, IMAddressInfoType.WindowsLive); localContactEndPointID = slp.ToEndPoint; remoteContact = ns.ContactList.GetContactWithCreate(slp.FromEmailAccount, IMAddressInfoType.WindowsLive); remoteContactEndPointID = slp.FromEndPoint; } if (!uint.TryParse(slp.BodyValues["SessionID"].Value, out sessionId)) { Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Can't parse SessionID: " + SessionId, GetType().Name); } p2pBridge = bridge; localBaseIdentifier = bridge.SequenceId; localIdentifier = localBaseIdentifier; status = P2PSessionStatus.WaitingForLocal; Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, String.Format("{0} created (Initiated remotely)", SessionId), GetType().Name); remoteContact.DirectBridgeEstablished += RemoteDirectBridgeEstablished; if (msg != null) { // Set remote baseID remoteBaseIdentifier = msg.Header.Identifier; remoteIdentifier = remoteBaseIdentifier; if (version == P2PVersion.P2PV2) { remoteIdentifier += msg.V2Header.MessageSize; } } // Create application based on invitation 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; p2pApplication = P2PApplication.CreateInstance(eufGuid, appId, this); if (p2pApplication != null && p2pApplication.ValidateInvitation(invitation)) { if (p2pApplication.AutoAccept) { Accept(); } else { ns.P2PHandler.OnInvitationReceived(new P2PSessionEventArgs(this)); } } else { Decline(); } }
/// <summary> /// Creates a new session initiated remotely. If the application cannot be handled, decline message will be sent. /// The application will handle all messages automatically and no user interaction is required if AutoAccept is true. /// If AutoAccept is false, <see cref="P2PHandler.InvitationReceived"/> event will be fired. /// </summary> public P2PSession(SLPRequestMessage slp, P2PMessage msg, NSMessageHandler ns, P2PBridge bridge) { nsMessageHandler = ns; invitation = slp; version = slp.P2PVersion; if (version == P2PVersion.P2PV1) { localContact = (slp.ToEmailAccount == ns.Owner.Account) ? ns.Owner : ns.ContactList.GetContactWithCreate(slp.ToEmailAccount, IMAddressInfoType.WindowsLive); remoteContact = ns.ContactList.GetContactWithCreate(slp.FromEmailAccount, IMAddressInfoType.WindowsLive); } else { localContact = (slp.ToEmailAccount == ns.Owner.Account) ? ns.Owner : ns.ContactList.GetContactWithCreate(slp.ToEmailAccount, IMAddressInfoType.WindowsLive); localContactEndPointID = slp.ToEndPoint; remoteContact = ns.ContactList.GetContactWithCreate(slp.FromEmailAccount, IMAddressInfoType.WindowsLive); remoteContactEndPointID = slp.FromEndPoint; } if (!uint.TryParse(slp.BodyValues["SessionID"].Value, out sessionId)) { Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, "Can't parse SessionID: " + SessionId, GetType().Name); } p2pBridge = bridge; localBaseIdentifier = bridge.SequenceId; localIdentifier = localBaseIdentifier; status = P2PSessionStatus.WaitingForLocal; Trace.WriteLineIf(Settings.TraceSwitch.TraceInfo, String.Format("{0} created (Initiated remotely)", SessionId), GetType().Name); remoteContact.DirectBridgeEstablished += RemoteDirectBridgeEstablished; if (msg != null) { // Set remote baseID remoteBaseIdentifier = msg.Header.Identifier; remoteIdentifier = remoteBaseIdentifier; if (version == P2PVersion.P2PV2) remoteIdentifier += msg.V2Header.MessageSize; } // Create application based on invitation 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; p2pApplication = P2PApplication.CreateInstance(eufGuid, appId, this); if (p2pApplication != null && p2pApplication.ValidateInvitation(invitation)) { if (p2pApplication.AutoAccept) { Accept(); } else { ns.P2PHandler.OnInvitationReceived(new P2PSessionEventArgs(this)); } } else { Decline(); } }
internal bool HandleP2PSessionSignal(P2PBridge bridge, P2PMessage p2pMessage, SLPMessage slp, P2PSession session) { if (slp is SLPRequestMessage) { SLPRequestMessage slpRequest = slp as SLPRequestMessage; if (slpRequest.ContentType == "application/x-msnmsgr-sessionclosebody" && slpRequest.Method == "BYE") { if (p2pMessage.Version == P2PVersion.P2PV1) { P2PMessage byeAck = p2pMessage.CreateAcknowledgement(); byeAck.V1Header.Flags = P2PFlag.CloseSession; session.Send(byeAck); } else if (p2pMessage.Version == P2PVersion.P2PV2) { SLPRequestMessage slpMessage = new SLPRequestMessage(session.RemoteContactEPIDString, "BYE"); slpMessage.Target = session.RemoteContactEPIDString; slpMessage.Source = session.LocalContactEPIDString; slpMessage.Branch = session.Invitation.Branch; slpMessage.CallId = session.Invitation.CallId; slpMessage.ContentType = "application/x-msnmsgr-sessionclosebody"; slpMessage.BodyValues["SessionID"] = session.SessionId.ToString(System.Globalization.CultureInfo.InvariantCulture); session.Send(session.WrapSLPMessage(slpMessage)); } session.OnClosed(new ContactEventArgs(session.Remote)); return(true); } else { if (slpRequest.ContentType == "application/x-msnmsgr-transreqbody" || slpRequest.ContentType == "application/x-msnmsgr-transrespbody" || slpRequest.ContentType == "application/x-msnmsgr-transdestaddrupdate") { P2PSession.ProcessDirectInvite(slpRequest, nsMessageHandler, session); // Direct connection invite return(true); } } } else if (slp is SLPStatusMessage) { SLPStatusMessage slpStatus = slp as SLPStatusMessage; if (slpStatus.Code == 200) // OK { if (slpStatus.ContentType == "application/x-msnmsgr-transrespbody") { P2PSession.ProcessDirectInvite(slpStatus, nsMessageHandler, session); return(true); } else { if (session.Application != null) { session.OnActive(EventArgs.Empty); session.Application.Start(); return(true); } } } else if (slpStatus.Code == 603) // Decline { session.OnClosed(new ContactEventArgs(session.Remote)); return(true); } else if (slpStatus.Code == 500) // Internal Error { return(true); } } Trace.WriteLineIf(Settings.TraceSwitch.TraceWarning, String.Format("Unhandled SLP Message in session:---->>\r\n{0}", p2pMessage.ToString()), GetType().Name); session.OnError(EventArgs.Empty); return(true); }
private static void ProcessDCRespInvite(SLPMessage message, NSMessageHandler ns, P2PSession startupSession) { MimeDictionary bodyValues = message.BodyValues; // Check the protocol if (bodyValues.ContainsKey("Bridge") && bodyValues["Bridge"].ToString() == "TCPv1" && bodyValues.ContainsKey("Listening") && bodyValues["Listening"].ToString().ToLowerInvariant().IndexOf("true") >= 0) { Contact remote = ns.ContactList.GetContactWithCreate(message.FromEmailAccount, IMAddressInfoType.WindowsLive); Guid remoteGuid = message.FromEndPoint; DCNonceType dcNonceType; Guid remoteNonce = ParseDCNonce(message.BodyValues, out dcNonceType); bool hashed = (dcNonceType == DCNonceType.Sha1); Guid replyGuid = hashed ? remote.dcPlainKey : remoteNonce; IPEndPoint[] selectedPoint = SelectIPEndPoint(bodyValues, ns); if (selectedPoint != null && selectedPoint.Length > 0) { P2PVersion ver = message.P2PVersion; // We must connect to the remote client ConnectivitySettings settings = new ConnectivitySettings(); settings.EndPoints = selectedPoint; remote.DirectBridge = CreateDirectConnection(remote, remoteGuid, ver, settings, replyGuid, remoteNonce, hashed, ns, startupSession); bool needConnectingEndpointInfo; if (bodyValues.ContainsKey("NeedConnectingEndpointInfo") && bool.TryParse(bodyValues["NeedConnectingEndpointInfo"], out needConnectingEndpointInfo) && needConnectingEndpointInfo == true) { IPEndPoint ipep = ((TCPv1Bridge)remote.DirectBridge).LocalEndPoint; string desc = "stroPdnAsrddAlanretnI4vPI"; char[] rev = ipep.ToString().ToCharArray(); Array.Reverse(rev); string ipandport = new string(rev); SLPRequestMessage slpResponseMessage = new SLPRequestMessage(message.Source, MSNSLPRequestMethod.ACK); slpResponseMessage.Source = message.Target; slpResponseMessage.Via = message.Via; slpResponseMessage.CSeq = 0; slpResponseMessage.CallId = Guid.Empty; slpResponseMessage.MaxForwards = 0; slpResponseMessage.ContentType = @"application/x-msnmsgr-transdestaddrupdate"; slpResponseMessage.BodyValues[desc] = ipandport; slpResponseMessage.BodyValues["Nat-Trav-Msg-Type"] = "WLX-Nat-Trav-Msg-Updated-Connecting-Port"; P2PMessage msg = new P2PMessage(ver); msg.InnerMessage = slpResponseMessage; ns.SDGBridge.Send(null, remote, remoteGuid, msg); } return; } } if (startupSession != null) { startupSession.DirectNegotiationFailed(); } }