Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vpn/proxy issues when creating new mp game #6715

Closed
wants to merge 12 commits into from

Conversation

ofetios
Copy link
Contributor

@ofetios ofetios commented May 6, 2022

resolves #6709, resolves #6649 by opening a connection to dropbox when starting a new mp game

Tested on windows and linux (Zorin OS). Seems to be working now.
I removed the redundant ping and replaced it with opening a connection to dropbox

I've also fixed the unnecessary commits and will close the other PR

replaced redundant ping with opening a connection to dropbox to fix the proxy issue
@touhidurrr
Copy link
Contributor

firstly, I think I suggested that you use https://content.dropboxapi.com for connection checking instead of http://www.dropbox.com. The api and their main website is entirely two different thing altogether.
Also i suggested that you use com.unciv.UncivGame.Current.settings.multiplayerServer when available.

@touhidurrr
Copy link
Contributor

I suggest this changes!!!
https://github.com/alexban011/Unciv/pull/2/files

@ofetios
Copy link
Contributor Author

ofetios commented May 6, 2022

I suggested that you use https://content.dropboxapi.com

I'll change it now but

com.unciv.UncivGame.Current.settings.multiplayerServer

not sure how to check for that

@touhidurrr
Copy link
Contributor

not sure how to check for that

Did you check my pr in your fork?

check multiplayerServer url if the user is playing on it
@ofetios
Copy link
Contributor Author

ofetios commented May 6, 2022

Did you check my pr in your fork?

I did and merged it, thanks !

@Mape6
Copy link
Contributor

Mape6 commented May 6, 2022

Looks good from my I-don't-know-anything-about-Kotlin point of view.

@touhidurrr
Copy link
Contributor

touhidurrr commented May 6, 2022

Looks good from my I-don't-know-anything-about-Kotlin point of view.

Lol. I used https://play.kotlinlang.org & https://www.google.com to test some assumed lines of kotlin code and checked if those worked before doing these commits.

I know I used to say that. I will change 'anything' to 'much' from now on maybe. 🤣

I saw a YouTube video on Kotlin basics months ago. Maybe I should add that too.

@ofetios
Copy link
Contributor Author

ofetios commented May 6, 2022

Looks good from my I-don't-know-anything-about-Kotlin point of view.

Lol. I used https://play.kotlinlang.org & https://www.google.com to test some assumed lines of kotlin code and checked if those worked before doing these commits.

I know I used to say that. I will change 'anything' to 'much' from now on maybe. 🤣

I saw a YouTube video on Kotlin basics months ago. Maybe I should add that too.

yeah I never wrote Kotlin before committing to this repo, I just assumed its somewhat similar to java and so far it seems to be. (more like python variables combined with java but yeah) :))

@SomeTroglodyte
Copy link
Collaborator

somewhat similar

Kotlin is an Island and a language. Java is an Island and a language. Intentional. The Kotlin compiler emits Java VM bytecode - unless a different backend is used.

if connected to proxy but no internet access it will freeze for a couple seconds (until it finishes the for loop) but it works
@touhidurrr
Copy link
Contributor

touhidurrr commented May 6, 2022

This new code looks a lot of sus to me. How does it work?
Also if it freezes for a few seconds then why not use promise and loop through promise.all output?

@touhidurrr
Copy link
Contributor

Also if internet is not working shouldn’t the previous changes be enough to check it?
Do we really need to check internet connectivity further like this?
Feels like a waste of time to me.

Or is the previous version is not enough to detect proxy?

@ofetios
Copy link
Contributor Author

ofetios commented May 7, 2022

How does it work?

well its the code that runs on desktop, but I'm not sure why it freezes.
Removing the android SDK stuff also works the same way (execution probably doesnt even get there unless it has internet access), so the freezing seems to be coming from connect(), but changing the timeouts doesn't fix the 3 sec freeze. (Btw it only freezes when connected to proxy)

Or is the previous version is not enough to detect proxy?

No, the previous version was not working when connected to proxy

@ofetios
Copy link
Contributor Author

ofetios commented May 7, 2022

So I could remove the SDK code. That would make the function identical to the desktop one so It could be moved back to NewGameScreen to avoid duplicate code? Or leave it in PlatformSpecificHelpers?

I kept it there in case that fails, so that it continues to the SDK code, but I probably should have added another try-catch inside that one. Might be redundant though, so what do you think? Keep the android SDK code or get rid of it? And if the latter should I move isInternetConnected() out of the platform specific stuff and move it in NewGameScreen where its being used?

@touhidurrr
Copy link
Contributor

Keep the android SDK code or get rid of it

Probably something that runs on both is better. Android Specific codes are a problem.

Also if the previous changes then Unciv shouldn’t work on proxy in the first place. URL comes directly from Java so i don't get why it wouldn’t work.

@touhidurrr
Copy link
Contributor

Maybe check Dropbox codes and use the network utilities used there? They should work regardless of platform a they are already working properly currently right?

@@ -34,13 +36,23 @@ Sources for Info about current orientation in case need:
}

override fun isInternetConnected(): Boolean {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're changing this to not only check internet connectivity, there are actually 2 fail states and so A. the function name should be changed (checkConnectionToMultiplayerServer or something) and B. we should tell the user if it's a problem with his internet or the server itself, so either return a fail string or an enum or something.

This also means we can keep the already-translated line of "No internet connection!" and just add another translation line of "The server is unreachable" or something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I'm gonna split the 2 in 2 separate functions

Comment on lines 45 to 53
val connectivityManager = activity.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
for (network in connectivityManager.allNetworks) {
val networkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: continue
val isInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
val info = connectivityManager.getNetworkInfo(network) ?: continue
if (isInternet && info.isConnected) return true
}

true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And obviously this should be first.
First check if we even have internet, if no - failure A.
Then check if we can reach server - if no, failure B.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried with that first but the code fails (the freeze is back)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And obviously this should be first.
First check if we even have internet, if no - failure A.
Then check if we can reach server - if no, failure B.

I think alex said that even after doing a connection check to the server, if the client is connected to the a proxy / vpn URL.connect doesn't work (?)

So, if B always fails ob Proxy, doing it before A is pointless.

@ofetios
Copy link
Contributor Author

ofetios commented May 7, 2022

ignore my last commit :)

@SomeTroglodyte
Copy link
Collaborator

Sorry, in its current state I'd call this a no-go, wrong design.

  • Java URL.openConnection is not exactly platform-dependent. Not as cross-platform as Gdx APIs maybe, but still. So - doesn't really belong in platform-specific code if there are no other compelling reasons.
  • Querying the Connectivity manager do decide whether or not to attempt an actual internet connection is good practice. It's meant to determine stuff like whether config allows, and interfaces are up, and should typically do its job without any packet on the line (and if it sends stuff that's the OS guy's decision and none of our business). So before, not after, and it is the correct thing to do. The equivalent on Linux would be to query the Network manager, maybe even by calling nmcli and parsing the result; on Windows one could query whether a default route exits and its associated interface it up; or the API offers something equivalent (which probably would do similar things under the hood.)
  • If you're sure the usecase justifies putting a packet on the line without prior test whether it even has a chance to reach its destination, go ahead, you don't need the whole PlatformSpecificHelpers stuff. Unless existing Java or Gdx apis are lacking a feature.
  • Uh, and a tiny thing: ?: "Dropbox"; if (multiplayerServer != "Dropbox") is silly. val url = URL(UncivGame.Current.settings.multiplayerServer ?: "https://content.dropboxapi.com") would do. And the static dripbox address there could be clearer as a static const val somewhere appropriate.

Ah, parallel comments & commits, OK pick what's still relevant.

removed frunctions from PlatformSpecificHelpers__
@ofetios
Copy link
Contributor Author

ofetios commented May 8, 2022

In platform-specific code: NO - UI doesn't belong there

so I guess its good where it is now (next to the invalid ID code)

Copy link
Contributor

@touhidurrr touhidurrr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplify and redo it!!

@@ -73,7 +73,7 @@ class NewGameScreen(
if (gameSetupInfo.gameParameters.isOnlineMultiplayer) {
if (UncivGame.Current.platformSpecificHelper?.isInternetConnected() != true) {
val noInternetConnectionPopup = Popup(this)
noInternetConnectionPopup.addGoodSizedLabel("No internet connection!".tr()).row()
noInternetConnectionPopup.addGoodSizedLabel("No connection to internet or dropbox!".tr()).row()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Just Couldn't connect to the Server would do?

Suggested change
noInternetConnectionPopup.addGoodSizedLabel("No connection to internet or dropbox!".tr()).row()
noInternetConnectionPopup.addGoodSizedLabel("Couldn't connect to the Server!".tr()).row()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SomeTroglodyte what do you think?

Comment on lines 45 to 53
val connectivityManager = activity.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
for (network in connectivityManager.allNetworks) {
val networkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: continue
val isInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
val info = connectivityManager.getNetworkInfo(network) ?: continue
if (isInternet && info.isConnected) return true
}

true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And obviously this should be first.
First check if we even have internet, if no - failure A.
Then check if we can reach server - if no, failure B.

I think alex said that even after doing a connection check to the server, if the client is connected to the a proxy / vpn URL.connect doesn't work (?)

So, if B always fails ob Proxy, doing it before A is pointless.

return try {
val u = URL(UncivGame.Current.settings.multiplayerServer)
val conn = u.openConnection()
conn.connect()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to java docs, openConnection() and connect() is used like this:

  1. The connection object is created by invoking the openConnection method on a URL.
  2. The setup parameters and general request properties are manipulated.
  3. The actual connection to the remote object is made, using the connect method.
  4. The remote object becomes available. The header fields and the contents of the remote object can be accessed.

So basically openConnection() makes a connection object and connect() connects to the server and makes the remote resouces available for further requests?

So basically java allows you to make a URLConnection object, modify it and then do actual network operations with connect(). There also seems to a property called connected that stores boolean values of a connection.

So, I guess proper way to do this would be something like

URL().openConnection().setTimeout(5000).connect()

Also it's unnecessary to ping any specific url since we are only checking the connection. But isalive would be better I guess since it sends less data.

@touhidurrr
Copy link
Contributor

touhidurrr commented May 10, 2022

but it doesn't really matter if it can't check for dropbox)

@alexban011 I think I have found the correct way to do this. See this:

if (settings.multiplayerServer != Constants.dropboxMultiplayerServer) settings.multiplayerServer

So, I think something like this would do:

import java.net.URL
import com.unciv.Constants
import com.unciv.UncivGame

private fun isConnectionToServerPossible(): Boolean {
    return try {
        val multiplayerServer = UncivGame.Current.settings.multiplayerServer
        val isDropbox = multiplayerServer == Constants.dropboxMultiplayerServer
        val u =  URL(if (isDropbox) "https://content.dropboxapi.com" else multiplayerServer)
        val con = u.openConnection()
        con.setConnectTimeout(5000)
        con.connect()

        true
    } catch(ex: Throwable) {
        val noInternetConnectionPopup = Popup(this)
        val label = if (isDropbox) "Couldn't connect to Dropbox!" else "Couldn't connect to Multiplayer Server!"
        noInternetConnectionPopup.addGoodSizedLabel(label.tr()).row()
        noInternetConnectionPopup.addCloseButton()
        noInternetConnectionPopup.open()
        return@onClick

        false
    }
}

@ofetios
Copy link
Contributor Author

ofetios commented May 10, 2022

Just tried it on android and it seems to work
I did had to make a slight modification: I moved the popup in the main function in an if(!isConnectionToServerPossible()) cause it was putting an error at @OnClick

did you tested it on the Pi?

@touhidurrr
Copy link
Contributor

touhidurrr commented May 10, 2022

did you tested it on the Pi?

I can't compile the source for reasons. Give me a jar to test.

@ofetios
Copy link
Contributor Author

ofetios commented May 10, 2022

I can't compile the source for reasons. Give me a jar to test.

I'm trying. I'm getting this:
Kotlin could not find the required JDK tools in the Java installation. Make sure Kotlin compilation is running on a JDK, not JRE.

I'll try reinstalling the JDK as people on forums said this should solve this

Sending it now

@ofetios
Copy link
Contributor Author

ofetios commented May 10, 2022

Sorry for mediafire link, I have no clue how else to send it:
Download link

@touhidurrr

@SomeTroglodyte
Copy link
Collaborator

putting an error at @OnClick

You're lucky (or maybe unlucky) there seems to be no actual user with that name around, or you would have spammed them. And the jar location is in the wiki not far under the gradlew syntax.

@SomeTroglodyte
Copy link
Collaborator

mediafire

otnolatrnup.com, doubleclick.net and aaxads.com are all quite malicious. do not visit without a good blocker.

@ofetios
Copy link
Contributor Author

ofetios commented May 10, 2022

You're lucky (or maybe unlucky) there seems to be no actual user with that name around, or you would have spammed them.

I made sure I'm not pinging anyone when I sent that :))

@ofetios
Copy link
Contributor Author

ofetios commented May 11, 2022

So now it works on Windows and Android even with proxy (both Mobile Hotspot and 1.1.1.1 vpn).

Now the "Couldn't connect to Dropbox!" makes more sense than the old "No internet connection!", but should I change it back to the old one to keep the translation or keep the new one as its more informative of what the issue is?

@ofetios
Copy link
Contributor Author

ofetios commented May 11, 2022

Last commit is just cleanup and I replaced the setConnectionTimeout because it was giving a warning.

Also I set the timeout to 3000 instead of 5000 since if the server doesn't respond in 3 seconds I really doubt it will in 5.
The freeze still happens on my phone but only if it was connected to the vpn before losing connection, so I don't think we should worry about it. Weirdly enough it seems to only freeze once and then the next time I press "start game" it displays the message instantly.

@touhidurrr
Copy link
Contributor

touhidurrr commented May 11, 2022

Never pull updates in a branch!!! But only in master / main.


override fun isInternetConnected(): Boolean {
return try {
InetAddress.getByName("8.8.8.8").isReachable(500) // Parameter timeout in milliseconds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sigh could it be that this is the reason why my checks always failed on Pi?
Proxy increases latency by a good margin and 500 is really not enough.
It is not enough even without proxy. And will fail 5-10% of times.
Who even sets timeout to only 0.5 seconds, I am astonished that nobody pointed this out.

@ofetios
Copy link
Contributor Author

ofetios commented May 11, 2022

Never pull updates in a branch!!! But only in master / main.

Noted.

@touhidurrr
Copy link
Contributor

Sorry for mediafire link, I have no clue how else to send it:
Download link

Sorry or not I can't even download it.

@touhidurrr
Copy link
Contributor

@alexban011 use this https://www.file.io/

@ofetios
Copy link
Contributor Author

ofetios commented May 11, 2022

@touhidurrr
Copy link
Contributor

touhidurrr commented May 11, 2022

@alexban011 I tested your jar and it works fine on raspberry pi

This pr got too big, maybe open a new one with clear & concise changes?

@ofetios
Copy link
Contributor Author

ofetios commented May 11, 2022

maybe open a new one with clear & concise changes?

yeah I was thinking about that. I'll do it now

@SomeTroglodyte
Copy link
Collaborator

SomeTroglodyte commented May 11, 2022

Never pull updates in a branch

Disagree. There are some very valid reasons to do so. Own work in two+ studio installations, or testing someone's branch and they pushed, or mixing features to see if they work together....... .. or maybe you meant "from yairm210/master"? That I don't do but even that could work if you know what you're doing - it'll start a merge.

@touhidurrr
Copy link
Contributor

touhidurrr commented May 11, 2022

Merge branch 'yairm210:master' into master-proxyIssues

I said that cause I don't like this kind of commits.

even that could work if you know what you're doing - it'll start a merge.

Yeah that also. For starters you would like them to start clean. After a while they would understand these things anyways.
At first i deleted and forked repos again after each of my prs were accepted and closed prs if I saw any such commits in the history. Lol.
Now I just use the pen button on a file to automatically create a new branch for me & then commit at that branch.
Since I use mobile data cloning things locally feels troublesome.

@SomeTroglodyte
Copy link
Collaborator

I said that cause I don't like

Then a wording like "Never" gives a misleading impression, the sentence was an imperative. With three Char(0x21) to boot. Simply "I never..." would have hit the mark, right? Online, culture barriers and so on, be careful..

@ofetios ofetios deleted the master-proxyIssues branch May 25, 2022 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants