1 /* 2 * Copyright (C) 2007-2008 Esmertec AG. 3 * Copyright (C) 2007-2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.mms.transaction; 19 20 import java.io.IOException; 21 import java.net.InetAddress; 22 import java.net.UnknownHostException; 23 24 import android.content.Context; 25 import android.net.ConnectivityManager; 26 import android.net.Uri; 27 28 import com.android.mms.util.SendingProgressTokenManager; 29 import com.google.android.mms.MmsException; 30 31 /** 32 * Transaction is an abstract class for notification transaction, send transaction 33 * and other transactions described in MMS spec. 34 * It provides the interfaces of them and some common methods for them. 35 */ 36 public abstract class Transaction extends Observable { 37 private final int mServiceId; 38 39 protected Context mContext; 40 protected String mId; 41 protected TransactionState mTransactionState; 42 protected TransactionSettings mTransactionSettings; 43 44 /** 45 * Identifies push requests. 46 */ 47 public static final int NOTIFICATION_TRANSACTION = 0; 48 /** 49 * Identifies deferred retrieve requests. 50 */ 51 public static final int RETRIEVE_TRANSACTION = 1; 52 /** 53 * Identifies send multimedia message requests. 54 */ 55 public static final int SEND_TRANSACTION = 2; 56 /** 57 * Identifies send read report requests. 58 */ 59 public static final int READREC_TRANSACTION = 3; 60 Transaction(Context context, int serviceId, TransactionSettings settings)61 public Transaction(Context context, int serviceId, 62 TransactionSettings settings) { 63 mContext = context; 64 mTransactionState = new TransactionState(); 65 mServiceId = serviceId; 66 mTransactionSettings = settings; 67 } 68 69 /** 70 * Returns the transaction state of this transaction. 71 * 72 * @return Current state of the Transaction. 73 */ 74 @Override getState()75 public TransactionState getState() { 76 return mTransactionState; 77 } 78 79 /** 80 * An instance of Transaction encapsulates the actions required 81 * during a MMS Client transaction. 82 */ process()83 public abstract void process(); 84 85 /** 86 * Used to determine whether a transaction is equivalent to this instance. 87 * 88 * @param transaction the transaction which is compared to this instance. 89 * @return true if transaction is equivalent to this instance, false otherwise. 90 */ isEquivalent(Transaction transaction)91 public boolean isEquivalent(Transaction transaction) { 92 return getClass().equals(transaction.getClass()) 93 && mId.equals(transaction.mId); 94 } 95 96 /** 97 * Get the service-id of this transaction which was assigned by the framework. 98 * @return the service-id of the transaction 99 */ getServiceId()100 public int getServiceId() { 101 return mServiceId; 102 } 103 getConnectionSettings()104 public TransactionSettings getConnectionSettings() { 105 return mTransactionSettings; 106 } setConnectionSettings(TransactionSettings settings)107 public void setConnectionSettings(TransactionSettings settings) { 108 mTransactionSettings = settings; 109 } 110 111 /** 112 * A common method to send a PDU to MMSC. 113 * 114 * @param pdu A byte array which contains the data of the PDU. 115 * @return A byte array which contains the response data. 116 * If an HTTP error code is returned, an IOException will be thrown. 117 * @throws IOException if any error occurred on network interface or 118 * an HTTP error code(>=400) returned from the server. 119 * @throws MmsException if pdu is null. 120 */ sendPdu(byte[] pdu)121 protected byte[] sendPdu(byte[] pdu) throws IOException, MmsException { 122 return sendPdu(SendingProgressTokenManager.NO_TOKEN, pdu, 123 mTransactionSettings.getMmscUrl()); 124 } 125 126 /** 127 * A common method to send a PDU to MMSC. 128 * 129 * @param pdu A byte array which contains the data of the PDU. 130 * @param mmscUrl Url of the recipient MMSC. 131 * @return A byte array which contains the response data. 132 * If an HTTP error code is returned, an IOException will be thrown. 133 * @throws IOException if any error occurred on network interface or 134 * an HTTP error code(>=400) returned from the server. 135 * @throws MmsException if pdu is null. 136 */ sendPdu(byte[] pdu, String mmscUrl)137 protected byte[] sendPdu(byte[] pdu, String mmscUrl) throws IOException, MmsException { 138 return sendPdu(SendingProgressTokenManager.NO_TOKEN, pdu, mmscUrl); 139 } 140 141 /** 142 * A common method to send a PDU to MMSC. 143 * 144 * @param token The token to identify the sending progress. 145 * @param pdu A byte array which contains the data of the PDU. 146 * @return A byte array which contains the response data. 147 * If an HTTP error code is returned, an IOException will be thrown. 148 * @throws IOException if any error occurred on network interface or 149 * an HTTP error code(>=400) returned from the server. 150 * @throws MmsException if pdu is null. 151 */ sendPdu(long token, byte[] pdu)152 protected byte[] sendPdu(long token, byte[] pdu) throws IOException, MmsException { 153 return sendPdu(token, pdu, mTransactionSettings.getMmscUrl()); 154 } 155 156 /** 157 * A common method to send a PDU to MMSC. 158 * 159 * @param token The token to identify the sending progress. 160 * @param pdu A byte array which contains the data of the PDU. 161 * @param mmscUrl Url of the recipient MMSC. 162 * @return A byte array which contains the response data. 163 * If an HTTP error code is returned, an IOException will be thrown. 164 * @throws IOException if any error occurred on network interface or 165 * an HTTP error code(>=400) returned from the server. 166 * @throws MmsException if pdu is null. 167 */ sendPdu(long token, byte[] pdu, String mmscUrl)168 protected byte[] sendPdu(long token, byte[] pdu, 169 String mmscUrl) throws IOException, MmsException { 170 if (pdu == null) { 171 throw new MmsException(); 172 } 173 174 ensureRouteToHost(mmscUrl, mTransactionSettings); 175 return HttpUtils.httpConnection( 176 mContext, token, 177 mmscUrl, 178 pdu, HttpUtils.HTTP_POST_METHOD, 179 mTransactionSettings.isProxySet(), 180 mTransactionSettings.getProxyAddress(), 181 mTransactionSettings.getProxyPort()); 182 } 183 184 /** 185 * A common method to retrieve a PDU from MMSC. 186 * 187 * @param url The URL of the message which we are going to retrieve. 188 * @return A byte array which contains the data of the PDU. 189 * If the status code is not correct, an IOException will be thrown. 190 * @throws IOException if any error occurred on network interface or 191 * an HTTP error code(>=400) returned from the server. 192 */ getPdu(String url)193 protected byte[] getPdu(String url) throws IOException { 194 ensureRouteToHost(url, mTransactionSettings); 195 return HttpUtils.httpConnection( 196 mContext, SendingProgressTokenManager.NO_TOKEN, 197 url, null, HttpUtils.HTTP_GET_METHOD, 198 mTransactionSettings.isProxySet(), 199 mTransactionSettings.getProxyAddress(), 200 mTransactionSettings.getProxyPort()); 201 } 202 203 /** 204 * Make sure that a network route exists to allow us to reach the host in the 205 * supplied URL, and to the MMS proxy host as well, if a proxy is used. 206 * @param url The URL of the MMSC to which we need a route 207 * @param settings Specifies the address of the proxy host, if any 208 * @throws IOException if the host doesn't exist, or adding the route fails. 209 */ ensureRouteToHost(String url, TransactionSettings settings)210 private void ensureRouteToHost(String url, TransactionSettings settings) throws IOException { 211 ConnectivityManager connMgr = 212 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 213 214 int inetAddr; 215 if (settings.isProxySet()) { 216 String proxyAddr = settings.getProxyAddress(); 217 inetAddr = lookupHost(proxyAddr); 218 if (inetAddr == -1) { 219 throw new IOException("Cannot establish route for " + url + ": Unknown host"); 220 } else { 221 if (!connMgr.requestRouteToHost( 222 ConnectivityManager.TYPE_MOBILE_MMS, inetAddr)) { 223 throw new IOException("Cannot establish route to proxy " + inetAddr); 224 } 225 } 226 } else { 227 Uri uri = Uri.parse(url); 228 inetAddr = lookupHost(uri.getHost()); 229 if (inetAddr == -1) { 230 throw new IOException("Cannot establish route for " + url + ": Unknown host"); 231 } else { 232 if (!connMgr.requestRouteToHost( 233 ConnectivityManager.TYPE_MOBILE_MMS, inetAddr)) { 234 throw new IOException("Cannot establish route to " + inetAddr + " for " + url); 235 } 236 } 237 } 238 } 239 240 /** 241 * Look up a host name and return the result as an int. Works if the argument 242 * is an IP address in dot notation. Obviously, this can only be used for IPv4 243 * addresses. 244 * @param hostname the name of the host (or the IP address) 245 * @return the IP address as an {@code int} in network byte order 246 */ 247 // TODO: move this to android-common lookupHost(String hostname)248 public static int lookupHost(String hostname) { 249 InetAddress inetAddress; 250 try { 251 inetAddress = InetAddress.getByName(hostname); 252 } catch (UnknownHostException e) { 253 return -1; 254 } 255 byte[] addrBytes; 256 int addr; 257 addrBytes = inetAddress.getAddress(); 258 addr = ((addrBytes[3] & 0xff) << 24) 259 | ((addrBytes[2] & 0xff) << 16) 260 | ((addrBytes[1] & 0xff) << 8) 261 | (addrBytes[0] & 0xff); 262 return addr; 263 } 264 265 @Override toString()266 public String toString() { 267 return getClass().getName() + ": serviceId=" + mServiceId; 268 } 269 270 /** 271 * Get the type of the transaction. 272 * 273 * @return Transaction type in integer. 274 */ getType()275 abstract public int getType(); 276 } 277