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