From 770f1a1ca08bf9497c0c08fa5519e4b7314df6bf Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 1 Aug 2020 22:19:40 -0700 Subject: [PATCH] Add network connection test --- app/src/main/java/com/limelight/Game.java | 2 +- app/src/main/java/com/limelight/PcView.java | 8 +++- .../com/limelight/nvstream/NvConnection.java | 8 ++-- .../nvstream/NvConnectionListener.java | 2 +- .../limelight/nvstream/jni/MoonBridge.java | 29 +++++++++++++- .../com/limelight/utils/ServerHelper.java | 38 +++++++++++++++++++ app/src/main/jni/moonlight-core/simplejni.c | 28 ++++++++++++++ app/src/main/res/values/strings.xml | 9 +++++ 8 files changed, 116 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/limelight/Game.java b/app/src/main/java/com/limelight/Game.java index 813b8ce3..b7ebe571 100644 --- a/app/src/main/java/com/limelight/Game.java +++ b/app/src/main/java/com/limelight/Game.java @@ -1502,7 +1502,7 @@ public class Game extends Activity implements SurfaceHolder.Callback, } @Override - public void stageFailed(final String stage, final int errorCode) { + public void stageFailed(final String stage, final int portFlags, final int errorCode) { runOnUiThread(new Runnable() { @Override public void run() { diff --git a/app/src/main/java/com/limelight/PcView.java b/app/src/main/java/com/limelight/PcView.java index 61d86247..56846581 100644 --- a/app/src/main/java/com/limelight/PcView.java +++ b/app/src/main/java/com/limelight/PcView.java @@ -118,6 +118,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { private final static int QUIT_ID = 7; private final static int VIEW_DETAILS_ID = 8; private final static int FULL_APP_LIST_ID = 9; + private final static int TEST_NETWORK_ID = 10; private void initializeViews() { setContentView(R.layout.activity_pc_view); @@ -321,7 +322,8 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { if (computer.details.state == ComputerDetails.State.OFFLINE || computer.details.state == ComputerDetails.State.UNKNOWN) { menu.add(Menu.NONE, WOL_ID, 1, getResources().getString(R.string.pcview_menu_send_wol)); - menu.add(Menu.NONE, DELETE_ID, 2, getResources().getString(R.string.pcview_menu_delete_pc)); + menu.add(Menu.NONE, TEST_NETWORK_ID, 2, getResources().getString(R.string.pcview_menu_test_network)); + menu.add(Menu.NONE, DELETE_ID, 3, getResources().getString(R.string.pcview_menu_delete_pc)); } else if (computer.details.pairState != PairState.PAIRED) { menu.add(Menu.NONE, PAIR_ID, 1, getResources().getString(R.string.pcview_menu_pair_pc)); @@ -629,6 +631,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks { Dialog.displayDialog(PcView.this, getResources().getString(R.string.title_details), computer.details.toString(), false); return true; + case TEST_NETWORK_ID: + ServerHelper.doNetworkTest(PcView.this); + return true; + default: return super.onContextItemSelected(item); } diff --git a/app/src/main/java/com/limelight/nvstream/NvConnection.java b/app/src/main/java/com/limelight/nvstream/NvConnection.java index d52ee271..ac03a777 100644 --- a/app/src/main/java/com/limelight/nvstream/NvConnection.java +++ b/app/src/main/java/com/limelight/nvstream/NvConnection.java @@ -231,19 +231,19 @@ public class NvConnection { try { if (!startApp()) { - context.connListener.stageFailed(appName, 0); + context.connListener.stageFailed(appName, 0, 0); return; } context.connListener.stageComplete(appName); } catch (GfeHttpResponseException e) { e.printStackTrace(); context.connListener.displayMessage(e.getMessage()); - context.connListener.stageFailed(appName, e.getErrorCode()); + context.connListener.stageFailed(appName, 0, e.getErrorCode()); return; } catch (XmlPullParserException | IOException e) { e.printStackTrace(); context.connListener.displayMessage(e.getMessage()); - context.connListener.stageFailed(appName, 0); + context.connListener.stageFailed(appName, MoonBridge.ML_PORT_FLAG_TCP_47984 | MoonBridge.ML_PORT_FLAG_TCP_47989, 0); return; } @@ -256,7 +256,7 @@ public class NvConnection { connectionAllowed.acquire(); } catch (InterruptedException e) { context.connListener.displayMessage(e.getMessage()); - context.connListener.stageFailed(appName, 0); + context.connListener.stageFailed(appName, 0, 0); return; } diff --git a/app/src/main/java/com/limelight/nvstream/NvConnectionListener.java b/app/src/main/java/com/limelight/nvstream/NvConnectionListener.java index cc49c45c..4879f2d3 100644 --- a/app/src/main/java/com/limelight/nvstream/NvConnectionListener.java +++ b/app/src/main/java/com/limelight/nvstream/NvConnectionListener.java @@ -3,7 +3,7 @@ package com.limelight.nvstream; public interface NvConnectionListener { void stageStarting(String stage); void stageComplete(String stage); - void stageFailed(String stage, int errorCode); + void stageFailed(String stage, int portFlags, int errorCode); void connectionStarted(); void connectionTerminated(int errorCode); diff --git a/app/src/main/java/com/limelight/nvstream/jni/MoonBridge.java b/app/src/main/java/com/limelight/nvstream/jni/MoonBridge.java index 71c6807e..1ef97133 100644 --- a/app/src/main/java/com/limelight/nvstream/jni/MoonBridge.java +++ b/app/src/main/java/com/limelight/nvstream/jni/MoonBridge.java @@ -36,6 +36,25 @@ public class MoonBridge { public static final int ML_ERROR_GRACEFUL_TERMINATION = 0; public static final int ML_ERROR_NO_VIDEO_TRAFFIC = -100; + public static final int ML_PORT_INDEX_TCP_47984 = 0; + public static final int ML_PORT_INDEX_TCP_47989 = 1; + public static final int ML_PORT_INDEX_TCP_48010 = 2; + public static final int ML_PORT_INDEX_UDP_47998 = 8; + public static final int ML_PORT_INDEX_UDP_47999 = 9; + public static final int ML_PORT_INDEX_UDP_48000 = 10; + public static final int ML_PORT_INDEX_UDP_48010 = 11; + + public static final int ML_PORT_FLAG_ALL = 0xFFFFFFFF; + public static final int ML_PORT_FLAG_TCP_47984 = 0x0001; + public static final int ML_PORT_FLAG_TCP_47989 = 0x0002; + public static final int ML_PORT_FLAG_TCP_48010 = 0x0004; + public static final int ML_PORT_FLAG_UDP_47998 = 0x0100; + public static final int ML_PORT_FLAG_UDP_47999 = 0x0200; + public static final int ML_PORT_FLAG_UDP_48000 = 0x0400; + public static final int ML_PORT_FLAG_UDP_48010 = 0x0800; + + public static final int ML_TEST_RESULT_INCONCLUSIVE = 0xFFFFFFFF; + private static AudioRenderer audioRenderer; private static VideoDecoderRenderer videoRenderer; private static NvConnectionListener connectionListener; @@ -186,7 +205,7 @@ public class MoonBridge { public static void bridgeClStageFailed(int stage, int errorCode) { if (connectionListener != null) { - connectionListener.stageFailed(getStageName(stage), errorCode); + connectionListener.stageFailed(getStageName(stage), getPortFlagsFromStage(stage), errorCode); } } @@ -271,5 +290,13 @@ public class MoonBridge { public static native int getPendingVideoFrames(); + public static native int testClientConnectivity(String testServerHostName, int referencePort, int testFlags); + + public static native int getPortFromPortFlagIndex(int portFlagIndex); + + public static native String getProtocolFromPortFlagIndex(int portFlagIndex); + + public static native int getPortFlagsFromStage(int stage); + public static native void init(); } diff --git a/app/src/main/java/com/limelight/utils/ServerHelper.java b/app/src/main/java/com/limelight/utils/ServerHelper.java index 7a75fb9f..94479cbe 100644 --- a/app/src/main/java/com/limelight/utils/ServerHelper.java +++ b/app/src/main/java/com/limelight/utils/ServerHelper.java @@ -6,6 +6,7 @@ import android.widget.Toast; import com.limelight.AppView; import com.limelight.Game; +import com.limelight.PcView; import com.limelight.R; import com.limelight.ShortcutTrampoline; import com.limelight.binding.PlatformBinding; @@ -14,6 +15,7 @@ import com.limelight.nvstream.http.ComputerDetails; import com.limelight.nvstream.http.GfeHttpResponseException; import com.limelight.nvstream.http.NvApp; import com.limelight.nvstream.http.NvHTTP; +import com.limelight.nvstream.jni.MoonBridge; import org.xmlpull.v1.XmlPullParserException; @@ -76,6 +78,42 @@ public class ServerHelper { parent.startActivity(createStartIntent(parent, app, computer, managerBinder)); } + public static void doNetworkTest(final Activity parent) { + new Thread(new Runnable() { + @Override + public void run() { + SpinnerDialog spinnerDialog = SpinnerDialog.displayDialog(parent, + parent.getResources().getString(R.string.nettest_title_waiting), + parent.getResources().getString(R.string.nettest_text_waiting), + false); + + int ret = MoonBridge.testClientConnectivity("conntest-android.moonlight-stream.org", 443, MoonBridge.ML_PORT_FLAG_ALL); + spinnerDialog.dismiss(); + + String dialogSummary; + if (ret == MoonBridge.ML_TEST_RESULT_INCONCLUSIVE) { + dialogSummary = parent.getResources().getString(R.string.nettest_text_inconclusive); + } + else if (ret == 0) { + dialogSummary = parent.getResources().getString(R.string.nettest_text_success); + } + else { + dialogSummary = parent.getResources().getString(R.string.nettest_text_failure); + for (int i = 0; i < 32; i++) { + if ((ret & (1 << i)) != 0) { + dialogSummary += MoonBridge.getProtocolFromPortFlagIndex(i) + " " + MoonBridge.getPortFromPortFlagIndex(i) + "\n"; + } + } + } + + Dialog.displayDialog(parent, + parent.getResources().getString(R.string.nettest_title_done), + dialogSummary, + false); + } + }).start(); + } + public static void doQuit(final Activity parent, final ComputerDetails computer, final NvApp app, diff --git a/app/src/main/jni/moonlight-core/simplejni.c b/app/src/main/jni/moonlight-core/simplejni.c index 574b72f4..e141c273 100644 --- a/app/src/main/jni/moonlight-core/simplejni.c +++ b/app/src/main/jni/moonlight-core/simplejni.c @@ -101,4 +101,32 @@ Java_com_limelight_nvstream_jni_MoonBridge_getPendingAudioDuration(JNIEnv *env, JNIEXPORT jint JNICALL Java_com_limelight_nvstream_jni_MoonBridge_getPendingVideoFrames(JNIEnv *env, jclass clazz) { return LiGetPendingVideoFrames(); +} + +JNIEXPORT jint JNICALL +Java_com_limelight_nvstream_jni_MoonBridge_testClientConnectivity(JNIEnv *env, jclass clazz, jstring testServerHostName, jint referencePort, jint testFlags) { + int ret; + const char* testServerHostNameStr = (*env)->GetStringUTFChars(env, testServerHostName, NULL); + + ret = LiTestClientConnectivity(testServerHostNameStr, (unsigned short)referencePort, testFlags); + + (*env)->ReleaseStringUTFChars(env, testServerHostName, testServerHostNameStr); + + return ret; +} + +JNIEXPORT jint JNICALL +Java_com_limelight_nvstream_jni_MoonBridge_getPortFromPortFlagIndex(JNIEnv *env, jclass clazz, jint portFlagIndex) { + return LiGetPortFromPortFlagIndex(portFlagIndex); +} + +JNIEXPORT jstring JNICALL +Java_com_limelight_nvstream_jni_MoonBridge_getProtocolFromPortFlagIndex(JNIEnv *env, jclass clazz, jint portFlagIndex) { + int protocol = LiGetProtocolFromPortFlagIndex(portFlagIndex); + return (*env)->NewStringUTF(env, protocol == IPPROTO_TCP ? "TCP" : "UDP"); +} + +JNIEXPORT jint JNICALL +Java_com_limelight_nvstream_jni_MoonBridge_getPortFlagsFromStage(JNIEnv *env, jclass clazz, jint stage) { + return LiGetPortFlagsFromStage(stage); } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c57df24e..3a90330f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,8 +21,17 @@ Unpair Send Wake-On-LAN request Delete PC + Test Network Connection View Details + + Testing Network Connection + Moonlight is testing your network connection to determine if NVIDIA GameStream is blocked.\n\nThis may take a few seconds… + Network Test Complete + Your network does not appear to be blocking Moonlight. If you still have trouble connecting, check your PC\'s firewall settings.\n\nIf you are trying to stream over the Internet, install the Moonlight Internet Hosting Tool on your PC and run the included Internet Streaming Tester to check your PC\'s Internet connection. + The network test could not be performed. Please try again later. + Your device\'s current network connection seems to be blocking Moonlight. Streaming over the Internet may not work properly while connected to this network.\n\nThe following network ports were blocked:\n + Pairing… Computer is offline