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 22 import android.content.Context; 23 import android.net.Uri; 24 import android.net.ConnectivityManager; 25 import android.util.Log; 26 27 import java.io.IOException; 28 import java.net.InetAddress; 29 import java.net.UnknownHostException; 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 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 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 */ 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 */ 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 */ 100 public int getServiceId() { 101 return mServiceId; 102 } 103 104 public TransactionSettings getConnectionSettings() { 105 return mTransactionSettings; 106 } 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 */ 120 protected byte[] sendPdu(byte[] pdu) throws IOException { 121 return sendPdu(SendingProgressTokenManager.NO_TOKEN, pdu, 122 mTransactionSettings.getMmscUrl()); 123 } 124 125 /** 126 * A common method to send a PDU to MMSC. 127 * 128 * @param pdu A byte array which contains the data of the PDU. 129 * @param mmscUrl Url of the recipient MMSC. 130 * @return A byte array which contains the response data. 131 * If an HTTP error code is returned, an IOException will be thrown. 132 * @throws IOException if any error occurred on network interface or 133 * an HTTP error code(>=400) returned from the server. 134 */ 135 protected byte[] sendPdu(byte[] pdu, String mmscUrl) throws IOException { 136 return sendPdu(SendingProgressTokenManager.NO_TOKEN, pdu, mmscUrl); 137 } 138 139 /** 140 * A common method to send a PDU to MMSC. 141 * 142 * @param token The token to identify the sending progress. 143 * @param pdu A byte array which contains the data of the PDU. 144 * @return A byte array which contains the response data. 145 * If an HTTP error code is returned, an IOException will be thrown. 146 * @throws IOException if any error occurred on network interface or 147 * an HTTP error code(>=400) returned from the server. 148 */ 149 protected byte[] sendPdu(long token, byte[] pdu) throws IOException { 150 return sendPdu(token, pdu, mTransactionSettings.getMmscUrl()); 151 } 152 153 /** 154 * A common method to send a PDU to MMSC. 155 * 156 * @param token The token to identify the sending progress. 157 * @param pdu A byte array which contains the data of the PDU. 158 * @param mmscUrl Url of the recipient MMSC. 159 * @return A byte array which contains the response data. 160 * If an HTTP error code is returned, an IOException will be thrown. 161 * @throws IOException if any error occurred on network interface or 162 * an HTTP error code(>=400) returned from the server. 163 */ 164 protected byte[] sendPdu(long token, byte[] pdu, String mmscUrl) throws IOException { 165 ensureRouteToHost(mmscUrl, mTransactionSettings); 166 return HttpUtils.httpConnection( 167 mContext, token, 168 mmscUrl, 169 pdu, HttpUtils.HTTP_POST_METHOD, 170 mTransactionSettings.isProxySet(), 171 mTransactionSettings.getProxyAddress(), 172 mTransactionSettings.getProxyPort()); 173 } 174 175 /** 176 * A common method to retrieve a PDU from MMSC. 177 * 178 * @param url The URL of the message which we are going to retrieve. 179 * @return A byte array which contains the data of the PDU. 180 * If the status code is not correct, an IOException will be thrown. 181 * @throws IOException if any error occurred on network interface or 182 * an HTTP error code(>=400) returned from the server. 183 */ 184 protected byte[] getPdu(String url) throws IOException { 185 ensureRouteToHost(url, mTransactionSettings); 186 return HttpUtils.httpConnection( 187 mContext, SendingProgressTokenManager.NO_TOKEN, 188 url, null, HttpUtils.HTTP_GET_METHOD, 189 mTransactionSettings.isProxySet(), 190 mTransactionSettings.getProxyAddress(), 191 mTransactionSettings.getProxyPort()); 192 } 193 194 /** 195 * Make sure that a network route exists to allow us to reach the host in the 196 * supplied URL, and to the MMS proxy host as well, if a proxy is used. 197 * @param url The URL of the MMSC to which we need a route 198 * @param settings Specifies the address of the proxy host, if any 199 * @throws IOException if the host doesn't exist, or adding the route fails. 200 */ 201 private void ensureRouteToHost(String url, TransactionSettings settings) throws IOException { 202 ConnectivityManager connMgr = 203 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 204 205 int inetAddr; 206 if (settings.isProxySet()) { 207 String proxyAddr = settings.getProxyAddress(); 208 inetAddr = lookupHost(proxyAddr); 209 if (inetAddr == -1) { 210 throw new IOException("Cannot establish route for " + url + ": Unknown host"); 211 } else { 212 if (!connMgr.requestRouteToHost( 213 ConnectivityManager.TYPE_MOBILE_MMS, inetAddr)) { 214 throw new IOException("Cannot establish route to proxy " + inetAddr); 215 } 216 } 217 } else { 218 Uri uri = Uri.parse(url); 219 inetAddr = lookupHost(uri.getHost()); 220 if (inetAddr == -1) { 221 throw new IOException("Cannot establish route for " + url + ": Unknown host"); 222 } else { 223 if (!connMgr.requestRouteToHost( 224 ConnectivityManager.TYPE_MOBILE_MMS, inetAddr)) { 225 throw new IOException("Cannot establish route to " + inetAddr + " for " + url); 226 } 227 } 228 } 229 } 230 231 /** 232 * Look up a host name and return the result as an int. Works if the argument 233 * is an IP address in dot notation. Obviously, this can only be used for IPv4 234 * addresses. 235 * @param hostname the name of the host (or the IP address) 236 * @return the IP address as an {@code int} in network byte order 237 */ 238 // TODO: move this to android-common 239 public static int lookupHost(String hostname) { 240 InetAddress inetAddress; 241 try { 242 inetAddress = InetAddress.getByName(hostname); 243 } catch (UnknownHostException e) { 244 return -1; 245 } 246 byte[] addrBytes; 247 int addr; 248 addrBytes = inetAddress.getAddress(); 249 addr = ((addrBytes[3] & 0xff) << 24) 250 | ((addrBytes[2] & 0xff) << 16) 251 | ((addrBytes[1] & 0xff) << 8) 252 | (addrBytes[0] & 0xff); 253 return addr; 254 } 255 256 @Override 257 public String toString() { 258 return getClass().getName() + ": serviceId=" + mServiceId; 259 } 260 261 /** 262 * Get the type of the transaction. 263 * 264 * @return Transaction type in integer. 265 */ 266 abstract public int getType(); 267 } 268