/// <summary> /// Pair with the hostname in the textbox /// </summary> public async Task Pair(CoreDispatcher uiDispatcher, Computer c) { Debug.WriteLine("Pairing..."); // Get the pair state. bool?pairState = await QueryPairState(); if (pairState == true) { DialogUtils.DisplayDialog(uiDispatcher, "This device is already paired to the host PC", "Already Paired"); return; } // pairstate = null. We've encountered an error else if (!pairState.HasValue) { DialogUtils.DisplayDialog(uiDispatcher, "Failed to query pair state", "Pairing failed"); return; } bool challenge = await PairingCryptoHelpers.PerformPairingHandshake(uiDispatcher, new WindowsCryptoProvider(), nv, nv.GetUniqueId()); if (!challenge) { Debug.WriteLine("Challenges failed"); return; } // Otherwise, everything was successful MainPage.SaveComputer(c); // FIXME: We can't have two dialogs open at once. // DialogUtils.DisplayDialog(uiDispatcher, "Pairing successful", "Success"); }
private static async Task<X509Certificate> ExtractPlainCert(XmlQuery q, String tag) { String certHexString = await q.ReadXmlElement(tag); byte[] certBytes = PairingCryptoHelpers.HexToBytes(certHexString); String certText = Encoding.UTF8.GetString(certBytes, 0, certBytes.Length); PemReader certReader = new PemReader(new StringReader(certText)); return (X509Certificate)certReader.ReadObject(); }
/// Get the local device's name /// </summary> /// <returns>Unique ID for the device</returns> public String GetUniqueId() { var settings = ApplicationData.Current.RoamingSettings; byte[] bytes; if (settings.Values.ContainsKey("uniqueid")) { bytes = (byte[])settings.Values["uniqueid"]; } else { bytes = PairingCryptoHelpers.GenerateRandomBytes(8); settings.Values["uniqueid"] = bytes; } return(PairingCryptoHelpers.BytesToHex(bytes)); }
/// <summary> /// Executed when the user presses "Start Streaming Steam!" /// </summary> private async Task StreamButton_Click_Common() { Debug.WriteLine("Start Streaming button pressed"); selected = (Computer)computerPicker.SelectedItem; // User hasn't selected a machine or selected a placeholder if (selected == null || String.IsNullOrWhiteSpace(selected.IpAddress)) { DialogUtils.DisplayDialog(this.Dispatcher, "No machine selected", "Streaming Failed"); } else { // Stop enumerating machines while we're trying to check pair state mDnsTimer.Stop(); byte[] aesKey = PairingCryptoHelpers.GenerateRandomBytes(16); // GameStream only uses 4 bytes of a 16 byte IV. Go figure. byte[] aesRiIndex = PairingCryptoHelpers.GenerateRandomBytes(4); byte[] aesIv = new byte[16]; Array.ConstrainedCopy(aesRiIndex, 0, aesIv, 0, aesRiIndex.Length); SettingsPage s = new SettingsPage(); MoonlightStreamConfiguration config = new MoonlightStreamConfiguration( s.GetStreamWidth(), s.GetStreamHeight(), s.GetStreamFps(), 10000, // FIXME: Scale by resolution 1024, aesKey, aesIv); StreamContext context = await ConnectionManager.StartStreaming(this.Dispatcher, selected, config); if (context != null) { this.Frame.Navigate(typeof(StreamFrame), context); } } }
/// <summary> /// Create start HTTP request /// </summary> private async Task <bool> StartOrResumeApp(NvHttp nv, MoonlightStreamConfiguration streamConfig) { XmlQuery serverInfo = new XmlQuery(nv.BaseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId()); string currentGameString = await serverInfo.ReadXmlElement("currentgame"); if (currentGameString == null) { return(false); } string versionString = await serverInfo.ReadXmlElement("appversion"); if (versionString == null) { return(false); } serverMajorVersion = Convert.ToInt32(versionString.Substring(0, 1)); byte[] aesIv = streamConfig.GetRiAesIv(); int riKeyId = (int)(((aesIv[0] << 24) & 0xFF000000U) | ((aesIv[1] << 16) & 0xFF0000U) | ((aesIv[2] << 8) & 0xFF00U) | (aesIv[3] & 0xFFU)); string riConfigString = "&rikey=" + PairingCryptoHelpers.BytesToHex(streamConfig.GetRiAesKey()) + "&rikeyid=" + riKeyId; // Launch a new game if nothing is running if (currentGameString == null || currentGameString.Equals("0")) { XmlQuery x = new XmlQuery(nv.BaseUrl + "/launch?uniqueid=" + nv.GetUniqueId() + "&appid=" + context.appId + "&mode=" + streamConfig.GetWidth() + "x" + streamConfig.GetHeight() + "x" + streamConfig.GetFps() + "&additionalStates=1&sops=1" + // FIXME: make sops configurable riConfigString); string sessionStr = await x.ReadXmlElement("gamesession"); if (sessionStr == null || sessionStr.Equals("0")) { return(false); } return(true); } else { // A game was already running, so resume it // FIXME: Quit and relaunch if it's not the game we came to start XmlQuery x = new XmlQuery(nv.BaseUrl + "/resume?uniqueid=" + nv.GetUniqueId() + riConfigString); string resumeStr = await x.ReadXmlElement("resume"); if (resumeStr == null || resumeStr.Equals("0")) { return(false); } return(true); } }