public ReconnectScenarioResult Execute()
        {
            try
            {
                bool pairingSucceeded = Pair();
                if (!pairingSucceeded)
                {
                    return(new ReconnectScenarioResult(false));
                }

                Disconnect();

                bool discoverySucceeded = Discover();
                if (!discoverySucceeded)
                {
                    return(new ReconnectScenarioResult(false));
                }

                Reconnect();

                WiFiDirectTestUtilities.RunDataPathValidation(localWFDController, remoteWFDController);
            }
            catch (Exception e)
            {
                WiFiDirectTestLogger.Error("Caught exception while executing reconnect scenario: {0}", e);
                return(new ReconnectScenarioResult(false));
            }

            return(new ReconnectScenarioResult(true));
        }
Exemplo n.º 2
0
 public static void TestClassSetup(TestContext context)
 {
     try
     {
         localWFDController  = new WiFiDirectTestController(context);
         remoteWFDController = WiFiDirectTestUtilities.GetRemoteTestControllerFromTestContext(context);
     }
     catch (Exception)
     {
         CleanupTestControllers();
         throw;
     }
 }
        public static WiFiDirectTestController GetRemoteTestControllerFromTestContext(TestContext context)
        {
            ushort remoteServerPort = WiFiDirectTestUtilities.ParsePortParameter(context, "RemoteServerPort", WiFiDirectRemoteServer.DefaultListenPort);

            string remoteServer = context.Properties["RemoteServer"] as string;

            if (remoteServer == null)
            {
                Verify.Fail("RemoteServer parameter must be provided.");
            }

            return(WiFiDirectTestController.CreateFromRemoteCommandClient(remoteServer, remoteServerPort));
        }
Exemplo n.º 4
0
        private void ExecuteInternal()
        {
            try
            {
                WiFiDirectTestLogger.Log(
                    "Sending data ({6} char string) from socket with handle {0} on device {1} ({2}), expect received on socket with handle {3} on device {4} ({5})",
                    dataParameters.SenderSocketHandle,
                    senderWFDController.DeviceAddress,
                    senderWFDController.MachineName,
                    dataParameters.ReceiverSocketHandle,
                    receiverWFDController.DeviceAddress,
                    receiverWFDController.MachineName,
                    dataParameters.DataSize
                    );

                // Generate message of "DataSize" characters
                StringBuilder builder = new StringBuilder();
                for (int i = 0; i < dataParameters.DataSize; i++)
                {
                    builder.Append(s_chars[rng.Next(s_chars.Length)]);
                }
                string msg = builder.ToString();

                senderWFDController.SendServiceSocketMessage(
                    dataParameters.SenderSessionHandle,
                    dataParameters.SenderSocketHandle,
                    msg
                    );

                string rcv = receiverWFDController.ReceiveServiceSocketMessage(
                    dataParameters.ReceiverSessionHandle,
                    dataParameters.ReceiverSocketHandle
                    );

                // Validate
                if (msg != rcv)
                {
                    WiFiDirectTestLogger.Error("Sent: '{0}', Received: '{1}'",
                                               WiFiDirectTestUtilities.GetTruncatedString(msg, 32),
                                               WiFiDirectTestUtilities.GetTruncatedString(rcv, 32)
                                               );
                    throw new Exception("Received Message was not the same as expected!");
                }

                succeeded = true;
            }
            catch (Exception e)
            {
                WiFiDirectTestLogger.Error("Caught exception while executing service send data scenario: {0}", e);
            }
        }
        public void ConnectASPOverExistingP2PGroup()
        {
            using (RemoteControllerLogGroup lg = new RemoteControllerLogGroup(remoteWFDController))
            {
                // Start by doing WFD pairing
                // NOTE: use invitation (not used for services) and config method push button (not used for services)
                ExecutePairingScenario(PairingScenarioType.Invitation, DOT11_WPS_CONFIG_METHOD.DOT11_WPS_CONFIG_METHOD_PUSHBUTTON);

                // Make sure we close this session on cleanup
                needToCloseSession = true;

                // Connect, auto accept
                string serviceName = remoteWFDController.GenerateUniqueServiceName();
                ServicesPublishDiscoverConnectParameters connectParams = new ServicesPublishDiscoverConnectParameters(
                    serviceName,
                    new ServicesConnectOptions(validateData: true)
                    );

                var pairResults = ExecutePublishDiscoverConnectScenario(connectParams);

                Verify.AreEqual(1, pairResults.ConnectResults.Count);

                // Disconnect
                ExecuteDisconnectScenario(
                    new ServicesDisconnectParameters(
                        pairResults.ConnectResults[0].AdvertiserSessionHandle,
                        pairResults.ConnectResults[0].SeekerSessionHandle
                        ),
                    false
                    );

                // WFD connection should stay up
                WiFiDirectTestLogger.Log("Closed ASP Session, waiting to make sure WFD session stays active...");
                Task.Delay(8000).Wait();

                WfdGlobalSessionState globalSessionStateLocal = localWFDController.QueryGlobalSessionState();

                if (globalSessionStateLocal.Sessions.Length != 1)
                {
                    WiFiDirectTestLogger.Error("Expected a single active session.  Current session count = {0}", globalSessionStateLocal.Sessions.Length);
                    throw new Exception("Local machine session is closed");
                }

                WiFiDirectTestUtilities.RunDataPathValidation(localWFDController, remoteWFDController, "6001");

                // Close WFD connection
                localWFDController.CloseSession();
                needToCloseSession = false;
            }
        }
        /// <summary>
        /// Start advertising a service
        /// </summary>
        /// <param name="serviceName"></param>
        /// <param name="autoAccept"></param>
        /// <param name="preferGO"></param>
        /// <param name="configMethods"></param>
        /// <param name="status"></param>
        /// <param name="customStatus"></param>
        /// <param name="serviceInfo"></param>
        /// <param name="deferredServiceInfo"></param>
        /// <returns></returns>
        public WFDSvcWrapperHandle PublishService(
            string serviceName,
            bool autoAccept = true,
            bool preferGO   = true,
            List <WiFiDirectServiceConfigurationMethod> configMethods = null,
            WiFiDirectServiceStatus status = WiFiDirectServiceStatus.Available,
            uint customStatus          = 0,
            string serviceInfo         = "",
            string deferredServiceInfo = "",
            List <String> prefixList   = null
            )
        {
            ThrowIfDisposed();

            WiFiDirectTestLogger.Log("Creating Service: \"{0}\"", serviceName);

            WiFiDirectServiceAdvertiser advertiser = new WiFiDirectServiceAdvertiser(serviceName);

            advertiser.AutoAcceptSession       = autoAccept;
            advertiser.PreferGroupOwnerMode    = preferGO;
            advertiser.ServiceStatus           = status;
            advertiser.CustomServiceStatusCode = customStatus;

            if (serviceInfo != null && serviceInfo.Length > 0)
            {
                using (var serviceInfoDataWriter = new Windows.Storage.Streams.DataWriter(new Windows.Storage.Streams.InMemoryRandomAccessStream()))
                {
                    serviceInfoDataWriter.WriteString(serviceInfo);
                    advertiser.ServiceInfo = serviceInfoDataWriter.DetachBuffer();
                }
                WiFiDirectTestLogger.Log("Included Service Info: \"{0}\"", WiFiDirectTestUtilities.GetTruncatedString(serviceInfo));
            }
            else
            {
                advertiser.ServiceInfo = null;
            }

            if (deferredServiceInfo != null && deferredServiceInfo.Length > 0)
            {
                using (var deferredSessionInfoDataWriter = new Windows.Storage.Streams.DataWriter(new Windows.Storage.Streams.InMemoryRandomAccessStream()))
                {
                    deferredSessionInfoDataWriter.WriteString(deferredServiceInfo);
                    advertiser.DeferredSessionInfo = deferredSessionInfoDataWriter.DetachBuffer();
                }
                WiFiDirectTestLogger.Log("Included Session Info: \"{0}\"", WiFiDirectTestUtilities.GetTruncatedString(deferredServiceInfo));
            }
            else
            {
                advertiser.DeferredSessionInfo = null;
            }

            if (configMethods != null)
            {
                advertiser.PreferredConfigurationMethods.Clear();
                foreach (var configMethod in configMethods)
                {
                    advertiser.PreferredConfigurationMethods.Add(configMethod);
                    WiFiDirectTestLogger.Log("Added config method {0}", configMethod.ToString());
                }
            }

            if (prefixList != null && prefixList.Count > 0)
            {
                advertiser.ServiceNamePrefixes.Clear();
                foreach (var prefix in prefixList)
                {
                    advertiser.ServiceNamePrefixes.Add(prefix);
                    WiFiDirectTestLogger.Log("Added prefix {0}", prefix);
                }
            }

            ServiceAdvertiser advertiserWrapper = new ServiceAdvertiser(advertiser, this, this, this);

            advertiserCollection.Add(advertiserWrapper.Handle, advertiserWrapper);

            WiFiDirectTestLogger.Log("Starting Service: \"{1}\" (Advertiser={0})", advertiserWrapper.Handle, serviceName);
            advertiser.Start();

            return(advertiserWrapper.Handle);
        }
        private void ExecuteInternal()
        {
            try
            {
                // For non-pushbutton pairing, generate a new passkey and make sure both test controllers have it.
                if (configMethod != DOT11_WPS_CONFIG_METHOD.DOT11_WPS_CONFIG_METHOD_PUSHBUTTON)
                {
                    remoteWFDController.PassKey = localWFDController.GenerateAndStoreNewPassKey();
                }

                // Prepare the remote device to receive the connection request.
                remoteWFDController.AcceptNextGroupRequest(
                    localWFDController.DeviceAddress,
                    (pairingScenarioType == PairingScenarioType.GoNegotiationDutBecomesGo) ? ((byte)0) : ((byte)14),
                    GetAcceptConfigMethod()
                    );

                // Begin by performing a targeted discovery for the remote device.
                bool discoverySucceeded = PerformTargetedDiscovery();
                if (!discoverySucceeded)
                {
                    return;
                }

                WFD_PAIR_WITH_DEVICE_PREFERENCE pairWithDevicePreference;

                switch (this.pairingScenarioType)
                {
                case PairingScenarioType.JoinExistingGo:
                    pairWithDevicePreference = WFD_PAIR_WITH_DEVICE_PREFERENCE.WFD_PAIRING_PREFER_NONE;
                    break;

                case PairingScenarioType.Invitation:
                    pairWithDevicePreference = WFD_PAIR_WITH_DEVICE_PREFERENCE.WFD_PAIRING_PREFER_INVITATION;
                    break;

                case PairingScenarioType.GoNegotiationDutBecomesGo:
                case PairingScenarioType.GoNegotiationDutBecomesClient:
                    pairWithDevicePreference = WFD_PAIR_WITH_DEVICE_PREFERENCE.WFD_PAIRING_PREFER_GO_NEGOTIATION;
                    break;

                default:
                    throw new Exception("Cannot map pairing scenario to pairing preference.");
                }

                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();

                // Pair with the target device.
                WiFiDirectTestLogger.Log("Starting pairing with device {0} ({1})", remoteWFDController.DeviceAddress, remoteWFDController.MachineName);
                localWFDController.PairWithDevice(
                    remoteWFDController.DeviceAddress,
                    pairWithDevicePreference,
                    (pairingScenarioType == PairingScenarioType.GoNegotiationDutBecomesClient) ? ((byte)0) : ((byte)14),
                    configMethod,
                    isPersistent
                    );
                WiFiDirectTestLogger.Log("Pairing successful", remoteWFDController.DeviceAddress, remoteWFDController.MachineName);

                stopwatch.Stop();
                WiFiDirectTestLogger.Log("Pairing completed in {0} ms.", stopwatch.ElapsedMilliseconds);

                bool sessionStateValid = VerifySessionState();
                if (!sessionStateValid)
                {
                    return;
                }

                if (this.runDataPathValidation)
                {
                    WiFiDirectTestUtilities.RunDataPathValidation(localWFDController, remoteWFDController);
                }

                succeeded = true;
            }
            catch (Exception e)
            {
                WiFiDirectTestLogger.Error("Caught exception while executing pairing scenario: {0}", e);
            }
        }
        private void ExecuteInternal()
        {
            try
            {
                WiFiDirectTestLogger.Log(
                    "Beginning Connect Scenario from Discovery Handle {0} to Advertiser {1}. GetProvisioning={2}, ValidateData={3}",
                    connectParameters.DiscoveryHandle,
                    connectParameters.AdvertiserHandle,
                    connectParameters.Options.CallGetProvisioningInfo,
                    connectParameters.Options.ValidateData
                    );

                string pin = "";

                // Get the current session counts
                int advertiserCountBefore = advertiserWFDController.GetServiceSessionCount();
                int seekerCountBefore     = seekerWFDController.GetServiceSessionCount();

                // Set any options (like prefer GO)
                // This also calls OpenSession()

                if (connectParameters.Options.DeclineConnect)
                {
                    if (!connectParameters.Options.CallGetProvisioningInfo ||
                        connectParameters.Options.ExpectConnectSuccess)
                    {
                        throw new Exception(String.Format(
                                                CultureInfo.InvariantCulture,
                                                "Bad test case, decline connection should call get provisioning info and expect failure"
                                                ));
                    }

                    advertiserWFDController.DeclineNextServiceConnectionRequest(connectParameters.AdvertiserHandle);
                }

                if (!connectParameters.Options.ExpectAdvertiserConnectSuccess)
                {
                    advertiserWFDController.ExpectNextServiceConnectionRequestFailure(connectParameters.AdvertiserHandle);
                }

                Stopwatch openSessionStopwatch = new Stopwatch();
                openSessionStopwatch.Start();
                seekerWFDController.SetServiceOptions(
                    connectParameters.DiscoveryHandle,
                    connectParameters.Options.PreferGO,
                    connectParameters.Options.SessionInfo
                    );
                openSessionStopwatch.Stop();

                WiFiDirectTestLogger.Log("OpenSession completed in {0} ms.", openSessionStopwatch.ElapsedMilliseconds);

                // Optionally GetProvisioningInfo before doing a PIN connection

                if (connectParameters.Options.CallGetProvisioningInfo)
                {
                    ProvisioningInfoWrapper provisioningInfo = null;
                    Stopwatch provDiscStopwatch = new Stopwatch();
                    // Handle expected failures in GetProvisioningInfo
                    try
                    {
                        provDiscStopwatch.Start();
                        provisioningInfo = seekerWFDController.GetServiceProvisioningInfo(
                            connectParameters.DiscoveryHandle,
                            connectParameters.Options.PreferredConfigMethod
                            );
                    }
                    catch (Exception e)
                    {
                        if (connectParameters.Options.ExpectGetProvisioningSuccess)
                        {
                            throw;
                        }
                        else
                        {
                            WiFiDirectTestLogger.Log("Caught expected exception in GetProvisioningInfo: {0}", e.Message);

                            if (connectParameters.Options.DeclineConnect)
                            {
                                advertiserWFDController.CheckAdvertiserLastSessionDeclined(connectParameters.AdvertiserHandle);
                            }

                            succeeded = true;
                            return;
                        }
                    }
                    finally
                    {
                        provDiscStopwatch.Stop();
                        WiFiDirectTestLogger.Log("GetServiceProvisioningInfo completed in {0} ms.", provDiscStopwatch.ElapsedMilliseconds);

                        if (succeeded && connectParameters.Options.DeclineConnect)
                        {
                            // 30 seconds is much more time than actually needed
                            if (provDiscStopwatch.ElapsedMilliseconds > 30000)
                            {
                                throw new Exception(String.Format(
                                                        CultureInfo.InvariantCulture,
                                                        "Expected decline to fail connect before 2 minute timeout, took too long, decline did not succeed properly"
                                                        ));
                            }
                        }
                    }

                    if (!connectParameters.Options.ExpectGetProvisioningSuccess)
                    {
                        throw new Exception(String.Format(
                                                CultureInfo.InvariantCulture,
                                                "Expected GetProvisioningInfo to fail"
                                                ));
                    }

                    if (provisioningInfo.IsGroupFormationNeeded != connectParameters.Options.ExpectGroupFormationNeeded)
                    {
                        throw new Exception(String.Format(
                                                CultureInfo.InvariantCulture,
                                                "Expected Group Formation {0}, Actual Group Formation {1}",
                                                (connectParameters.Options.ExpectGroupFormationNeeded) ? "Needed" : "Not Needed",
                                                (provisioningInfo.IsGroupFormationNeeded) ? "Needed" : "Not Needed"
                                                ));
                    }

                    if (provisioningInfo.IsGroupFormationNeeded &&
                        provisioningInfo.SelectedConfigMethod != WiFiDirectServiceConfigurationMethod.Default)
                    {
                        if (provisioningInfo.SelectedConfigMethod == WiFiDirectServiceConfigurationMethod.PinDisplay)
                        {
                            // Seeker should have generated a PIN, now advertiser can enter the PIN
                            pin = seekerWFDController.GetServiceDisplayedPin();
                            advertiserWFDController.EnterServicesPin(pin);
                        }
                        else
                        {
                            // Advertiser will generate/display PIN, enter on seeker side before connecting
                            pin = advertiserWFDController.GetServiceDisplayedPin();
                            seekerWFDController.EnterServicesPin(pin);
                        }
                    }
                    WiFiDirectTestLogger.Log("Get Provisioning Info complete, using PIN: {0}", pin);
                }

                // Some tests will validate that this works even if there is a time delay from provisioning info available on seeker to calling connect
                // Add a sleep here if that is the case
                if (connectParameters.Options.DelaySeekerConnectCall)
                {
                    // 5 seconds should be long enough for advertiser to attempt the connect before seeker is ready
                    Task.Delay(5000).Wait();
                }

                // Now do the real connect
                Stopwatch connectStopwatch = new Stopwatch();

                // Handle expected failures in ConnectService
                try
                {
                    connectStopwatch.Start();
                    seekerSessionHandle = seekerWFDController.ConnectService(
                        connectParameters.DiscoveryHandle
                        );
                }
                catch (Exception e)
                {
                    if (connectParameters.Options.ExpectConnectSuccess)
                    {
                        throw;
                    }
                    else
                    {
                        WiFiDirectTestLogger.Log("Caught expected exception in ConnectService: {0}", e.Message);
                        succeeded = true;
                        return;
                    }
                }
                finally
                {
                    connectStopwatch.Stop();
                    WiFiDirectTestLogger.Log("Connect completed in {0} ms.", connectStopwatch.ElapsedMilliseconds);

                    if (!connectParameters.Options.ExpectAdvertiserConnectSuccess)
                    {
                        advertiserWFDController.CheckAdvertiserLastSessionFailed(connectParameters.AdvertiserHandle);
                    }

                    if (succeeded && connectParameters.Options.DeclineConnect)
                    {
                        // 30 seconds is much more time than actually needed
                        if (connectStopwatch.ElapsedMilliseconds > 30000)
                        {
                            throw new Exception(String.Format(
                                                    CultureInfo.InvariantCulture,
                                                    "Expected decline to fail connect before 2 minute timeout, took too long, decline did not succeed properly"
                                                    ));
                        }
                    }
                }

                if (!connectParameters.Options.ExpectConnectSuccess)
                {
                    throw new Exception(String.Format(
                                            CultureInfo.InvariantCulture,
                                            "Expected Connect to fail"
                                            ));
                }

                // Advertiser should have gotten the connection
                advertiserSessionHandle = advertiserWFDController.GetAdvertiserLastSession(
                    connectParameters.AdvertiserHandle,
                    pin.Length == 0 // autoAccept
                    );

                ServiceSessionInfo advertiserSession = advertiserWFDController.GetServiceSessionInfo(advertiserSessionHandle);

                if (advertiserSession.Status != WiFiDirectServiceSessionStatus.Open)
                {
                    throw new Exception(String.Format(
                                            CultureInfo.InvariantCulture,
                                            "Advertiser session is not open (Status={0}, ErrorStatus={1})",
                                            advertiserSession.Status,
                                            advertiserSession.ErrorStatus
                                            ));
                }

                if (connectParameters.Options.SessionInfo.Length > 0 &&
                    connectParameters.Options.SessionInfo != advertiserSession.DeferredSessionInfo)
                {
                    throw new Exception(String.Format(
                                            CultureInfo.InvariantCulture,
                                            "Advertiser and Seeker session info mismatch! (Seeker={0}) (Advertiser={1})",
                                            WiFiDirectTestUtilities.GetTruncatedString(connectParameters.Options.SessionInfo),
                                            WiFiDirectTestUtilities.GetTruncatedString(advertiserSession.DeferredSessionInfo)
                                            ));
                }

                ServiceSessionInfo seekerSession = seekerWFDController.GetServiceSessionInfo(seekerSessionHandle);

                // Compare sessions for correct data
                if (advertiserSession.ServiceName != seekerSession.ServiceName ||
                    advertiserSession.AdvertisementId != seekerSession.AdvertisementId ||
                    advertiserSession.ServiceAddress != seekerSession.ServiceAddress ||
                    advertiserSession.SessionAddress != seekerSession.SessionAddress ||
                    advertiserSession.SessionId != seekerSession.SessionId)
                {
                    throw new Exception(String.Format(
                                            CultureInfo.InvariantCulture,
                                            "Advertiser and Seeker session mismatch! (Seeker={0}) (Advertiser={1})",
                                            seekerSession.ToString(),
                                            advertiserSession.ToString()
                                            ));
                }

                if (connectParameters.Options.ExpectDeferred)
                {
                    seekerWFDController.CheckServiceSessionDeferred(seekerSessionHandle, true);
                    var advertiserInfo = advertiserWFDController.GetAdvertiserInfo(connectParameters.AdvertiserHandle);

                    if (advertiserInfo.DeferredSessionInfo.Length > 0 &&
                        seekerSession.DeferredSessionInfo != advertiserInfo.DeferredSessionInfo)
                    {
                        throw new Exception(String.Format(
                                                CultureInfo.InvariantCulture,
                                                "Advertiser and Seeker deferred session info mismatch! (Seeker={0}) (Advertiser={1})",
                                                WiFiDirectTestUtilities.GetTruncatedString(seekerSession.DeferredSessionInfo),
                                                WiFiDirectTestUtilities.GetTruncatedString(advertiserInfo.DeferredSessionInfo)
                                                ));
                    }
                }
                else
                {
                    seekerWFDController.CheckServiceSessionDeferred(seekerSessionHandle, false);

                    if (seekerSession.DeferredSessionInfo != "")
                    {
                        throw new Exception(String.Format(
                                                CultureInfo.InvariantCulture,
                                                "Seeker Received Deferred Session info, was not deferred session! (Session Info={0})",
                                                WiFiDirectTestUtilities.GetTruncatedString(seekerSession.DeferredSessionInfo)
                                                ));
                    }
                }

                // Check that we added 1 session to each side
                int advertiserCountAfter = advertiserWFDController.GetServiceSessionCount();
                int seekerCountAfter     = seekerWFDController.GetServiceSessionCount();

                if (advertiserCountBefore + 1 != advertiserCountAfter ||
                    seekerCountBefore + 1 != seekerCountAfter)
                {
                    throw new Exception(String.Format(
                                            CultureInfo.InvariantCulture,
                                            "Expected 1 new session on each side! (Seeker {0} -> {1}, Advertiser {2} -> {3})",
                                            seekerCountBefore,
                                            seekerCountAfter,
                                            advertiserCountBefore,
                                            advertiserCountAfter
                                            ));
                }

                if (connectParameters.Options.ValidateData)
                {
                    var dataScenario = new ServicesOpenSocketSendDataScenario(
                        seekerWFDController,
                        advertiserWFDController,
                        new ServicesOpenSocketSendDataParameters(
                            seekerSessionHandle,
                            advertiserSessionHandle,
                            WiFiDirectServiceIPProtocol.Tcp,
                            validationPort++,
                            65536
                            )
                        );

                    validateDataResults = dataScenario.Execute();

                    if (!validateDataResults.ScenarioSucceeded)
                    {
                        throw new Exception("Failed data validation!");
                    }
                }

                succeeded = true;
            }
            catch (Exception e)
            {
                WiFiDirectTestLogger.Error("Caught exception while executing service connect scenario: {0}", e);
            }
        }
Exemplo n.º 9
0
 public static void TestClassSetup(TestContext context)
 {
     testContext = context;
     listenPort  = WiFiDirectTestUtilities.ParsePortParameter(context, "ListenPort", DefaultListenPort);
 }
        private void DoFindAllDiscovery()
        {
            Stopwatch discoveryStopwatch = new Stopwatch();

            discoveryStopwatch.Start();

            discoveryHandles = discoveryTestController.DiscoverServices(
                discoveryParameters.Query,
                discoveryParameters.ExpectedMatchCount > 0,
                discoveryParameters.ServiceInfoRequest
                );

            discoveryStopwatch.Stop();
            WiFiDirectTestLogger.Log("Services Discovery (FindAllAsync) completed in {0} ms.", discoveryStopwatch.ElapsedMilliseconds);

            if (discoveryHandles.Count != discoveryParameters.ExpectedMatchCount)
            {
                WiFiDirectTestLogger.Error(
                    "Expected {0} devices but discovered {1} devices",
                    discoveryParameters.ExpectedMatchCount,
                    discoveryHandles.Count
                    );
                return;
            }

            if (discoveryHandles.Count > 0 &&
                discoveryParameters.AdvertisersToMatch != null &&
                discoveryParameters.AdvertisersToMatch.Count > 0)
            {
                WiFiDirectTestLogger.Log("Checking discovery results for expected services");
                bool foundAll = true;

                IList <DiscoveredServiceInfo> discoveredDevices = new List <DiscoveredServiceInfo>();
                foreach (var handle in discoveryHandles)
                {
                    DiscoveredServiceInfo discovery = discoveryTestController.GetDiscoveredServiceInfo(handle);
                    discoveredDevices.Add(discovery);

                    WiFiDirectTestLogger.Log(
                        "Discovered service: {0} with address: {1}",
                        discovery.ServiceName,
                        discovery.ServiceAddress.ToString()
                        );
                }

                int adIdx = 0;
                foreach (var handle in discoveryParameters.AdvertisersToMatch)
                {
                    ServiceAdvertiserInfo advertiser = advertiserTestController.GetAdvertiserInfo(handle);
                    bool found = false;

                    // Check discovered list for match, remove
                    for (int i = 0; i < discoveredDevices.Count; i++)
                    {
                        if (advertiser.ServiceName == discoveredDevices[i].ServiceName &&
                            advertiser.ServiceAddress == discoveredDevices[i].ServiceAddress)
                        {
                            WiFiDirectTestLogger.Log(
                                "Found Expected Service: {0} with address: {1}",
                                discoveredDevices[i].ServiceName,
                                discoveredDevices[i].ServiceAddress.ToString()
                                );

                            if (discoveryParameters.AdvertiserServiceInfoMatch != null &&
                                discoveryParameters.AdvertiserServiceInfoMatch.Count >= adIdx)
                            {
                                if (discoveryParameters.AdvertiserServiceInfoMatch[adIdx])
                                {
                                    WiFiDirectTestLogger.Log(
                                        "Expecting Service Info:\n\t{0}\nReceived:\n\t{1}",
                                        WiFiDirectTestUtilities.GetTruncatedString(advertiser.ServiceInfo, 32),
                                        WiFiDirectTestUtilities.GetTruncatedString(discoveredDevices[i].ServiceInfo, 32)
                                        );
                                    if (advertiser.ServiceInfo != discoveredDevices[i].ServiceInfo)
                                    {
                                        // Allow multiple services with same name/different service info
                                        // Skip if service info match fails, will fail if no service info found
                                        continue;
                                    }
                                }
                                else
                                {
                                    WiFiDirectTestLogger.Log(
                                        "Expecting No Service Info, Received:\n\t{0}",
                                        WiFiDirectTestUtilities.GetTruncatedString(discoveredDevices[i].ServiceInfo, 32)
                                        );
                                    if ("" != discoveredDevices[i].ServiceInfo)
                                    {
                                        // Allow multiple services with same name/different service info
                                        // Skip if service info match fails, will fail if no service info found
                                        continue;
                                    }
                                }
                            }

                            discoveredDevices.RemoveAt(i);

                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        WiFiDirectTestLogger.Error(
                            "Did NOT Find Expected Service: {0} with address: {1}",
                            advertiser.ServiceName,
                            advertiser.ServiceAddress.ToString()
                            );
                        foundAll = false;
                        // Continue checking complete list
                    }

                    adIdx++;
                }

                if (discoveredDevices.Count > 0)
                {
                    WiFiDirectTestLogger.Error("Found unexpected services!");
                    foundAll = false;
                }

                if (!foundAll)
                {
                    return;
                }
            }

            succeeded = true;
        }