MMS Fixes

1) Respect proxyIfPossible flag and make sure to try all mms APNs

2) Reorder mmsc connection process
This commit is contained in:
rymdhund 2014-07-30 00:31:20 +02:00 committed by Moxie Marlinspike
parent d3da409774
commit feabbb33d2
6 changed files with 72 additions and 55 deletions

View File

@ -86,7 +86,7 @@ public class MmsPreferencesActivity extends PassphraseRequiredSherlockPreference
} }
private void initializePreferences() { private void initializePreferences() {
if (!MmsDownloadHelper.isMmsConnectionParametersAvailable(this, null, false)) { if (!MmsDownloadHelper.isMmsConnectionParametersAvailable(this, null)) {
TextSecurePreferences.setUseLocalApnsEnabled(this, true); TextSecurePreferences.setUseLocalApnsEnabled(this, true);
addPreferencesFromResource(R.xml.mms_preferences); addPreferencesFromResource(R.xml.mms_preferences);
this.findPreference(TextSecurePreferences.ENABLE_MANUAL_MMS_PREF).setOnPreferenceChangeListener(new OverrideMmsChangeListener()); this.findPreference(TextSecurePreferences.ENABLE_MANUAL_MMS_PREF).setOnPreferenceChangeListener(new OverrideMmsChangeListener());

View File

@ -31,9 +31,8 @@ import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams; import org.apache.http.params.HttpProtocolParams;
import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.service.MmsDownloader;
import org.whispersystems.textsecure.util.Conversions;
import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.textsecure.util.Conversions;
import org.whispersystems.textsecure.util.Util; import org.whispersystems.textsecure.util.Util;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -81,8 +80,7 @@ public class MmsCommunication {
} }
} }
protected static MmsConnectionParameters getMmsConnectionParameters(Context context, String apn, protected static MmsConnectionParameters getMmsConnectionParameters(Context context, String apn)
boolean proxyIfPossible)
throws ApnUnavailableException throws ApnUnavailableException
{ {
Cursor cursor = null; Cursor cursor = null;
@ -95,46 +93,28 @@ public class MmsCommunication {
do { do {
String mmsc = cursor.getString(cursor.getColumnIndexOrThrow("mmsc")); String mmsc = cursor.getString(cursor.getColumnIndexOrThrow("mmsc"));
String proxy = null; String proxy = cursor.getString(cursor.getColumnIndexOrThrow("mmsproxy"));
String port = null; String port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport"));
if (proxyIfPossible) {
proxy = cursor.getString(cursor.getColumnIndexOrThrow("mmsproxy"));
port = cursor.getString(cursor.getColumnIndexOrThrow("mmsport"));
}
if (!Util.isEmpty(mmsc)) if (!Util.isEmpty(mmsc))
return new MmsConnectionParameters(mmsc, proxy, port); return new MmsConnectionParameters(mmsc, proxy, port);
} while (cursor.moveToNext()); } while (cursor.moveToNext());
return getLocalMmsConnectionParameters(context);
} catch (SQLiteException sqe) { } catch (SQLiteException sqe) {
Log.w("MmsCommunication", sqe); Log.w("MmsCommunication", sqe);
return getLocalMmsConnectionParameters(context);
} catch (SecurityException se) { } catch (SecurityException se) {
Log.i("MmsCommunication", "Couldn't write APN settings, expected. msg: " + se.getMessage()); Log.i("MmsCommunication", "Couldn't write APN settings, expected. msg: " + se.getMessage());
return getLocalMmsConnectionParameters(context);
} catch (IllegalArgumentException iae) { } catch (IllegalArgumentException iae) {
Log.w("MmsCommunication", iae); Log.w("MmsCommunication", iae);
return getLocalMmsConnectionParameters(context);
} finally { } finally {
if (cursor != null) if (cursor != null)
cursor.close(); cursor.close();
} }
return getLocalMmsConnectionParameters(context);
} }
protected static boolean checkRouteToHost(Context context, MmsConnectionParameters.Apn parameters, protected static boolean checkRouteToHost(Context context, String host, boolean usingMmsRadio)
String url, boolean usingMmsRadio)
throws IOException
{
if (parameters == null || !parameters.hasProxy())
return checkRouteToHost(context, Uri.parse(url).getHost(), usingMmsRadio);
else
return checkRouteToHost(context, parameters.getProxy(), usingMmsRadio);
}
private static boolean checkRouteToHost(Context context, String host, boolean usingMmsRadio)
throws IOException throws IOException
{ {
InetAddress inetAddress = InetAddress.getByName(host); InetAddress inetAddress = InetAddress.getByName(host);
@ -160,14 +140,14 @@ public class MmsCommunication {
return true; return true;
} }
protected static AndroidHttpClient constructHttpClient(Context context, MmsConnectionParameters.Apn mmsConfig) { protected static AndroidHttpClient constructHttpClient(Context context, String proxy, int port) {
AndroidHttpClient client = AndroidHttpClient.newInstance("Android-Mms/2.0", context); AndroidHttpClient client = AndroidHttpClient.newInstance("Android-Mms/2.0", context);
HttpParams params = client.getParams(); HttpParams params = client.getParams();
HttpProtocolParams.setContentCharset(params, "UTF-8"); HttpProtocolParams.setContentCharset(params, "UTF-8");
HttpConnectionParams.setSoTimeout(params, 20 * 1000); HttpConnectionParams.setSoTimeout(params, 20 * 1000);
if (mmsConfig.hasProxy()) { if (proxy != null) {
ConnRouteParams.setDefaultProxy(params, new HttpHost(mmsConfig.getProxy(), mmsConfig.getPort())); ConnRouteParams.setDefaultProxy(params, new HttpHost(proxy, port));
} }
return client; return client;

View File

@ -17,6 +17,7 @@
package org.thoughtcrime.securesms.mms; package org.thoughtcrime.securesms.mms;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.net.http.AndroidHttpClient; import android.net.http.AndroidHttpClient;
import android.util.Log; import android.util.Log;
@ -34,13 +35,13 @@ import ws.com.google.android.mms.pdu.RetrieveConf;
public class MmsDownloadHelper extends MmsCommunication { public class MmsDownloadHelper extends MmsCommunication {
private static byte[] makeRequest(Context context, MmsConnectionParameters.Apn connectionParameters, String url) private static byte[] makeRequest(Context context, String url, String proxy, int proxyPort)
throws IOException throws IOException
{ {
AndroidHttpClient client = null; AndroidHttpClient client = null;
try { try {
client = constructHttpClient(context, connectionParameters); client = constructHttpClient(context, proxy, proxyPort);
URI targetUrl = new URI(url.trim()); URI targetUrl = new URI(url.trim());
HttpHost target = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME); HttpHost target = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME);
HttpGet request = new HttpGet(url.trim()); HttpGet request = new HttpGet(url.trim());
@ -64,9 +65,9 @@ public class MmsDownloadHelper extends MmsCommunication {
} }
} }
public static boolean isMmsConnectionParametersAvailable(Context context, String apn, boolean proxyIfPossible) { public static boolean isMmsConnectionParametersAvailable(Context context, String apn) {
try { try {
getMmsConnectionParameters(context, apn, proxyIfPossible); getMmsConnectionParameters(context, apn);
return true; return true;
} catch (ApnUnavailableException e) { } catch (ApnUnavailableException e) {
return false; return false;
@ -77,12 +78,28 @@ public class MmsDownloadHelper extends MmsCommunication {
boolean usingMmsRadio, boolean proxyIfPossible) boolean usingMmsRadio, boolean proxyIfPossible)
throws IOException, ApnUnavailableException throws IOException, ApnUnavailableException
{ {
MmsConnectionParameters connectionParameters = getMmsConnectionParameters(context, apn, proxyIfPossible); MmsConnectionParameters connectionParameters = getMmsConnectionParameters(context, apn);
byte[] pdu = null; byte[] pdu = null;
for (MmsConnectionParameters.Apn param : connectionParameters.get()) { for (MmsConnectionParameters.Apn param : connectionParameters.get()) {
if (checkRouteToHost(context, param, param.getMmsc(), usingMmsRadio)) { String proxy = null;
pdu = makeRequest(context, param, url); int proxyPort = 80;
boolean hasRoute;
if (proxyIfPossible && param.hasProxy()) {
proxy = param.getProxy();
proxyPort = param.getPort();
hasRoute = checkRouteToHost(context, proxy, usingMmsRadio);
} else {
hasRoute = checkRouteToHost(context, Uri.parse(param.getMmsc()).getHost(), usingMmsRadio);
}
if (hasRoute) {
try {
pdu = makeRequest(context, url, proxy, proxyPort);
} catch(IOException e) {
Log.w("MmsDownloadHelper", "Request failed: "+e.getMessage());
}
if (pdu != null) break; if (pdu != null) break;
} }
} }

View File

@ -19,6 +19,7 @@ package org.thoughtcrime.securesms.mms;
import android.content.Context; import android.content.Context;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.Uri;
import android.net.http.AndroidHttpClient; import android.net.http.AndroidHttpClient;
import android.util.Log; import android.util.Log;
@ -39,21 +40,21 @@ import ws.com.google.android.mms.pdu.SendConf;
public class MmsSendHelper extends MmsCommunication { public class MmsSendHelper extends MmsCommunication {
private final static String TAG = MmsSendHelper.class.getSimpleName(); private final static String TAG = MmsSendHelper.class.getSimpleName();
private static byte[] makePost(Context context, MmsConnectionParameters.Apn parameters, byte[] mms) private static byte[] makePost(Context context, String url, String proxy, int proxyPort, byte[] mms)
throws IOException throws IOException
{ {
AndroidHttpClient client = null; AndroidHttpClient client = null;
try { try {
Log.w(TAG, "Sending MMS1 of length: " + (mms != null ? mms.length : "null")); Log.w(TAG, "Sending MMS1 of length: " + (mms != null ? mms.length : "null"));
client = constructHttpClient(context, parameters); client = constructHttpClient(context, proxy, proxyPort);
URI targetUrl = new URI(parameters.getMmsc()); URI targetUrl = new URI(url);
if (Util.isEmpty(targetUrl.getHost())) if (Util.isEmpty(targetUrl.getHost()))
throw new IOException("Invalid target host: " + targetUrl.getHost() + " , " + targetUrl); throw new IOException("Invalid target host: " + targetUrl.getHost() + " , " + targetUrl);
HttpHost target = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME); HttpHost target = new HttpHost(targetUrl.getHost(), targetUrl.getPort(), HttpHost.DEFAULT_SCHEME_NAME);
HttpPost request = new HttpPost(parameters.getMmsc()); HttpPost request = new HttpPost(url);
ByteArrayEntity entity = new ByteArrayEntity(mms); ByteArrayEntity entity = new ByteArrayEntity(mms);
entity.setContentType("application/vnd.wap.mms-message"); entity.setContentType("application/vnd.wap.mms-message");
@ -99,11 +100,27 @@ public class MmsSendHelper extends MmsCommunication {
{ {
Log.w(TAG, "Sending MMS of length: " + mms.length); Log.w(TAG, "Sending MMS of length: " + mms.length);
try { try {
MmsConnectionParameters parameters = getMmsConnectionParameters(context, apn, useProxyIfAvailable); MmsConnectionParameters parameters = getMmsConnectionParameters(context, apn);
for (MmsConnectionParameters.Apn param : parameters.get()) { for (MmsConnectionParameters.Apn param : parameters.get()) {
if (checkRouteToHost(context, param, param.getMmsc(), usingMmsRadio)) { String proxy = null;
byte[] response = makePost(context, param, mms); int proxyPort = 80;
boolean hasRoute;
if(useProxyIfAvailable && param.hasProxy()){
proxy = param.getProxy();
proxyPort = param.getPort();
hasRoute = checkRouteToHost(context, proxy, usingMmsRadio);
} else {
hasRoute = checkRouteToHost(context, Uri.parse(param.getMmsc()).getHost(), usingMmsRadio);
}
if (hasRoute) {
try {
byte[] response = makePost(context, param.getMmsc(), proxy, proxyPort, mms);
if (response != null) return response; if (response != null) return response;
} catch(IOException e) {
Log.w("MmsSendHelper", "Request failed: "+e.getMessage());
}
} }
} }
throw new IOException("Connection manager could not obtain route to host."); throw new IOException("Connection manager could not obtain route to host.");
@ -123,7 +140,7 @@ public class MmsSendHelper extends MmsCommunication {
} }
String apn = networkInfo.getExtraInfo(); String apn = networkInfo.getExtraInfo();
MmsCommunication.getMmsConnectionParameters(context, apn, true); MmsCommunication.getMmsConnectionParameters(context, apn);
return true; return true;
} catch (ApnUnavailableException e) { } catch (ApnUnavailableException e) {
Log.w("MmsSendHelper", e); Log.w("MmsSendHelper", e);

View File

@ -18,6 +18,7 @@ package org.thoughtcrime.securesms.service;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.telephony.TelephonyManager; import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -69,7 +70,7 @@ public class MmsDownloader {
} }
private void handleMmsPendingApnDownloads(MasterSecret masterSecret) { private void handleMmsPendingApnDownloads(MasterSecret masterSecret) {
if (!MmsDownloadHelper.isMmsConnectionParametersAvailable(context, null, false)) if (!MmsDownloadHelper.isMmsConnectionParametersAvailable(context, null))
return; return;
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context); MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
@ -100,6 +101,8 @@ public class MmsDownloader {
database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_CONNECTING); database.markDownloadState(messageId, MmsDatabase.Status.DOWNLOAD_CONNECTING);
Log.w("MmsDownloader", "Downloading mms at "+ Uri.parse(contentLocation).getHost());
try { try {
if (isCdmaNetwork()) { if (isCdmaNetwork()) {
Log.w("MmsDownloader", "Connecting directly..."); Log.w("MmsDownloader", "Connecting directly...");
@ -115,22 +118,22 @@ public class MmsDownloader {
Log.w("MmsDownloader", "Changing radio to MMS mode.."); Log.w("MmsDownloader", "Changing radio to MMS mode..");
radio.connect(); radio.connect();
Log.w("MmsDownloader", "Downloading in MMS mode without proxy..."); Log.w("MmsDownloader", "Downloading in MMS mode with proxy...");
try { try {
retrieveAndStore(masterSecret, messageId, threadId, contentLocation, retrieveAndStore(masterSecret, messageId, threadId, contentLocation,
transactionId, true, false); transactionId, true, true);
radio.disconnect(); radio.disconnect();
return; return;
} catch (IOException e) { } catch (IOException e) {
Log.w("MmsDownloader", e); Log.w("MmsDownloader", e);
} }
Log.w("MmsDownloader", "Downloading in MMS mode with proxy..."); Log.w("MmsDownloader", "Downloading in MMS mode without proxy...");
try { try {
retrieveAndStore(masterSecret, messageId, threadId, retrieveAndStore(masterSecret, messageId, threadId,
contentLocation, transactionId, true, true); contentLocation, transactionId, true, false);
radio.disconnect(); radio.disconnect();
return; return;
} catch (IOException e) { } catch (IOException e) {

View File

@ -80,21 +80,21 @@ public class MmsTransport {
} }
} }
Log.w("MmsTransport", "Sending MMS with radio change..."); Log.w("MmsTransport", "Sending MMS with radio change and proxy...");
radio.connect(); radio.connect();
try { try {
MmsSendResult result = sendMms(message, true, false); MmsSendResult result = sendMms(message, true, true);
radio.disconnect(); radio.disconnect();
return result; return result;
} catch (IOException e) { } catch (IOException e) {
Log.w("MmsTransport", e); Log.w("MmsTransport", e);
} }
Log.w("MmsTransport", "Sending MMS with radio change and proxy..."); Log.w("MmsTransport", "Sending MMS with radio change and without proxy...");
try { try {
MmsSendResult result = sendMms(message, true, true); MmsSendResult result = sendMms(message, true, false);
radio.disconnect(); radio.disconnect();
return result; return result;
} catch (IOException ioe) { } catch (IOException ioe) {