From 423db817c6a80919cb3edf02638a7a9383e5bcfc Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 4 Feb 2022 17:52:43 +0100 Subject: [PATCH] MCS: fallback to port 443 if 5228 is blocked According to Google Firebase's doc, other ports than 5228 can be used: If your organization has a firewall to restrict traffic to or from the Internet, you need to configure it to allow mobile devices to connect with FCM in order for devices on your network to receive messages. FCM typically uses port 5228, but it sometimes uses 443, 5229, and 5230. Src: https://firebase.google.com/docs/cloud-messaging/concept-options#messaging-ports-and-your-firewall As suggested by @mar-v-in, it is enough to first try 5228 and then only try with 443 as fall back port. Indeed, it would be surprising to find any firewall blocking port 5228 but not 5229. If none of these ports, a new attempt will be done later as before. Closes: https://github.com/microg/GmsCore/issues/408 Signed-off-by: Matthieu Baerts --- .../java/org/microg/gms/gcm/McsService.java | 75 ++++++++++++------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java b/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java index 5a9eb53411..1795d9c6ff 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/McsService.java @@ -120,7 +120,10 @@ public class McsService extends Service implements Handler.Callback { public static final String FROM_FIELD = "gcm@android.com"; public static final String SERVICE_HOST = "mtalk.google.com"; - public static final int SERVICE_PORT = 5228; + // A few ports are available: 443, 5228-5230 but also 5222-5223 + // See https://github.com/microg/GmsCore/issues/408 + // Likely if the main port 5228 is blocked by a firewall, the other 52xx are blocked as well + public static final int[] SERVICE_PORTS = {5228, 443}; private static final int WAKELOCK_TIMEOUT = 5000; // On bad mobile network a ping can take >60s, so we wait for an ACK for 90s @@ -440,38 +443,52 @@ private void handleSendMessage(Intent intent) { } } + private void connect(int port) throws Exception { + this.wasTornDown = false; + + logd(this, "Starting MCS connection to port " + port + "..."); + Socket socket = new Socket(SERVICE_HOST, port); + logd(this, "Connected to " + SERVICE_HOST + ":" + port); + sslSocket = SSLContext.getDefault().getSocketFactory().createSocket(socket, SERVICE_HOST, port, true); + logd(this, "Activated SSL with " + SERVICE_HOST + ":" + port); + inputStream = new McsInputStream(sslSocket.getInputStream(), rootHandler); + outputStream = new McsOutputStream(sslSocket.getOutputStream(), rootHandler); + inputStream.start(); + outputStream.start(); + + startTimestamp = System.currentTimeMillis(); + lastHeartbeatPingElapsedRealtime = SystemClock.elapsedRealtime(); + lastHeartbeatAckElapsedRealtime = SystemClock.elapsedRealtime(); + lastIncomingNetworkRealtime = SystemClock.elapsedRealtime(); + scheduleHeartbeat(this); + } + private synchronized void connect() { - try { - closeAll(); - ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo(); - activeNetworkPref = GcmPrefs.get(this).getNetworkPrefForInfo(activeNetworkInfo); - if (!GcmPrefs.get(this).isEnabledFor(activeNetworkInfo)) { - logd(this, "Don't connect, because disabled for " + activeNetworkInfo.getTypeName()); - scheduleReconnect(this); + closeAll(); + + ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo(); + activeNetworkPref = GcmPrefs.get(this).getNetworkPrefForInfo(activeNetworkInfo); + if (!GcmPrefs.get(this).isEnabledFor(activeNetworkInfo)) { + logd(this, "Don't connect, because disabled for " + activeNetworkInfo.getTypeName()); + scheduleReconnect(this); + return; + } + + Exception exception = null; + for (int port : SERVICE_PORTS) { + try { + connect(port); return; + } catch (Exception e) { + exception = e; + Log.w(TAG, "Exception while connecting to " + SERVICE_HOST + ":" + port, e); + closeAll(); } - wasTornDown = false; - - logd(this, "Starting MCS connection..."); - Socket socket = new Socket(SERVICE_HOST, SERVICE_PORT); - logd(this, "Connected to " + SERVICE_HOST + ":" + SERVICE_PORT); - sslSocket = SSLContext.getDefault().getSocketFactory().createSocket(socket, SERVICE_HOST, SERVICE_PORT, true); - logd(this, "Activated SSL with " + SERVICE_HOST + ":" + SERVICE_PORT); - inputStream = new McsInputStream(sslSocket.getInputStream(), rootHandler); - outputStream = new McsOutputStream(sslSocket.getOutputStream(), rootHandler); - inputStream.start(); - outputStream.start(); - - startTimestamp = System.currentTimeMillis(); - lastHeartbeatPingElapsedRealtime = SystemClock.elapsedRealtime(); - lastHeartbeatAckElapsedRealtime = SystemClock.elapsedRealtime(); - lastIncomingNetworkRealtime = SystemClock.elapsedRealtime(); - scheduleHeartbeat(this); - } catch (Exception e) { - Log.w(TAG, "Exception while connecting!", e); - rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, e)); } + + logd(this, "Unable to connect to all different ports, retrying later"); + rootHandler.sendMessage(rootHandler.obtainMessage(MSG_TEARDOWN, exception)); } private void handleClose(Close close) {