1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.os;
17
18import java.net.InetAddress;
19import java.net.Inet4Address;
20import java.net.Inet6Address;
21import java.net.InetSocketAddress;
22import static libcore.io.OsConstants.*;
23
24class CommonTimeUtils {
25    /**
26     * Successful operation.
27     */
28    public static final int SUCCESS = 0;
29    /**
30     * Unspecified error.
31     */
32    public static final int ERROR = -1;
33    /**
34     * Operation failed due to bad parameter value.
35     */
36    public static final int ERROR_BAD_VALUE = -4;
37    /**
38     * Operation failed due to dead remote object.
39     */
40    public static final int ERROR_DEAD_OBJECT = -7;
41
42    public CommonTimeUtils(IBinder remote, String interfaceDesc) {
43        mRemote = remote;
44        mInterfaceDesc = interfaceDesc;
45    }
46
47    public int transactGetInt(int method_code, int error_ret_val)
48    throws RemoteException {
49        android.os.Parcel data  = android.os.Parcel.obtain();
50        android.os.Parcel reply = android.os.Parcel.obtain();
51        int ret_val;
52
53        try {
54            int res;
55            data.writeInterfaceToken(mInterfaceDesc);
56            mRemote.transact(method_code, data, reply, 0);
57
58            res = reply.readInt();
59            ret_val = (0 == res) ? reply.readInt() : error_ret_val;
60        }
61        finally {
62            reply.recycle();
63            data.recycle();
64        }
65
66        return ret_val;
67    }
68
69    public int transactSetInt(int method_code, int val) {
70        android.os.Parcel data  = android.os.Parcel.obtain();
71        android.os.Parcel reply = android.os.Parcel.obtain();
72
73        try {
74            data.writeInterfaceToken(mInterfaceDesc);
75            data.writeInt(val);
76            mRemote.transact(method_code, data, reply, 0);
77
78            return reply.readInt();
79        }
80        catch (RemoteException e) {
81            return ERROR_DEAD_OBJECT;
82        }
83        finally {
84            reply.recycle();
85            data.recycle();
86        }
87    }
88
89    public long transactGetLong(int method_code, long error_ret_val)
90    throws RemoteException {
91        android.os.Parcel data  = android.os.Parcel.obtain();
92        android.os.Parcel reply = android.os.Parcel.obtain();
93        long ret_val;
94
95        try {
96            int res;
97            data.writeInterfaceToken(mInterfaceDesc);
98            mRemote.transact(method_code, data, reply, 0);
99
100            res = reply.readInt();
101            ret_val = (0 == res) ? reply.readLong() : error_ret_val;
102        }
103        finally {
104            reply.recycle();
105            data.recycle();
106        }
107
108        return ret_val;
109    }
110
111    public int transactSetLong(int method_code, long val) {
112        android.os.Parcel data  = android.os.Parcel.obtain();
113        android.os.Parcel reply = android.os.Parcel.obtain();
114
115        try {
116            data.writeInterfaceToken(mInterfaceDesc);
117            data.writeLong(val);
118            mRemote.transact(method_code, data, reply, 0);
119
120            return reply.readInt();
121        }
122        catch (RemoteException e) {
123            return ERROR_DEAD_OBJECT;
124        }
125        finally {
126            reply.recycle();
127            data.recycle();
128        }
129    }
130
131    public String transactGetString(int method_code, String error_ret_val)
132    throws RemoteException {
133        android.os.Parcel data  = android.os.Parcel.obtain();
134        android.os.Parcel reply = android.os.Parcel.obtain();
135        String ret_val;
136
137        try {
138            int res;
139            data.writeInterfaceToken(mInterfaceDesc);
140            mRemote.transact(method_code, data, reply, 0);
141
142            res = reply.readInt();
143            ret_val = (0 == res) ? reply.readString() : error_ret_val;
144        }
145        finally {
146            reply.recycle();
147            data.recycle();
148        }
149
150        return ret_val;
151    }
152
153    public int transactSetString(int method_code, String val) {
154        android.os.Parcel data  = android.os.Parcel.obtain();
155        android.os.Parcel reply = android.os.Parcel.obtain();
156
157        try {
158            data.writeInterfaceToken(mInterfaceDesc);
159            data.writeString(val);
160            mRemote.transact(method_code, data, reply, 0);
161
162            return reply.readInt();
163        }
164        catch (RemoteException e) {
165            return ERROR_DEAD_OBJECT;
166        }
167        finally {
168            reply.recycle();
169            data.recycle();
170        }
171    }
172
173    public InetSocketAddress transactGetSockaddr(int method_code)
174    throws RemoteException {
175        android.os.Parcel data  = android.os.Parcel.obtain();
176        android.os.Parcel reply = android.os.Parcel.obtain();
177        InetSocketAddress ret_val = null;
178
179        try {
180            int res;
181            data.writeInterfaceToken(mInterfaceDesc);
182            mRemote.transact(method_code, data, reply, 0);
183
184            res = reply.readInt();
185            if (0 == res) {
186                int type;
187                int port = 0;
188                String addrStr = null;
189
190                type = reply.readInt();
191
192                if (AF_INET == type) {
193                    int addr = reply.readInt();
194                    port = reply.readInt();
195                    addrStr = String.format("%d.%d.%d.%d", (addr >> 24) & 0xFF,
196                                                           (addr >> 16) & 0xFF,
197                                                           (addr >>  8) & 0xFF,
198                                                            addr        & 0xFF);
199                } else if (AF_INET6 == type) {
200                    int addr1 = reply.readInt();
201                    int addr2 = reply.readInt();
202                    int addr3 = reply.readInt();
203                    int addr4 = reply.readInt();
204
205                    port = reply.readInt();
206
207                    int flowinfo = reply.readInt();
208                    int scope_id = reply.readInt();
209
210                    addrStr = String.format("[%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X]",
211                                            (addr1 >> 16) & 0xFFFF, addr1 & 0xFFFF,
212                                            (addr2 >> 16) & 0xFFFF, addr2 & 0xFFFF,
213                                            (addr3 >> 16) & 0xFFFF, addr3 & 0xFFFF,
214                                            (addr4 >> 16) & 0xFFFF, addr4 & 0xFFFF);
215                }
216
217                if (null != addrStr) {
218                    ret_val = new InetSocketAddress(addrStr, port);
219                }
220            }
221        }
222        finally {
223            reply.recycle();
224            data.recycle();
225        }
226
227        return ret_val;
228    }
229
230    public int transactSetSockaddr(int method_code, InetSocketAddress addr) {
231        android.os.Parcel data  = android.os.Parcel.obtain();
232        android.os.Parcel reply = android.os.Parcel.obtain();
233        int ret_val = ERROR;
234
235        try {
236            data.writeInterfaceToken(mInterfaceDesc);
237
238            if (null == addr) {
239                data.writeInt(0);
240            } else {
241                data.writeInt(1);
242                final InetAddress a = addr.getAddress();
243                final byte[]      b = a.getAddress();
244                final int         p = addr.getPort();
245
246                if (a instanceof Inet4Address) {
247                    int v4addr = (((int)b[0] & 0xFF) << 24) |
248                                 (((int)b[1] & 0xFF) << 16) |
249                                 (((int)b[2] & 0xFF) << 8) |
250                                  ((int)b[3] & 0xFF);
251
252                    data.writeInt(AF_INET);
253                    data.writeInt(v4addr);
254                    data.writeInt(p);
255                } else
256                if (a instanceof Inet6Address) {
257                    int i;
258                    Inet6Address v6 = (Inet6Address)a;
259                    data.writeInt(AF_INET6);
260                    for (i = 0; i < 4; ++i) {
261                        int aword = (((int)b[(i*4) + 0] & 0xFF) << 24) |
262                                    (((int)b[(i*4) + 1] & 0xFF) << 16) |
263                                    (((int)b[(i*4) + 2] & 0xFF) << 8) |
264                                     ((int)b[(i*4) + 3] & 0xFF);
265                        data.writeInt(aword);
266                    }
267                    data.writeInt(p);
268                    data.writeInt(0);   // flow info
269                    data.writeInt(v6.getScopeId());
270                } else {
271                    return ERROR_BAD_VALUE;
272                }
273            }
274
275            mRemote.transact(method_code, data, reply, 0);
276            ret_val = reply.readInt();
277        }
278        catch (RemoteException e) {
279            ret_val = ERROR_DEAD_OBJECT;
280        }
281        finally {
282            reply.recycle();
283            data.recycle();
284        }
285
286        return ret_val;
287    }
288
289    private IBinder mRemote;
290    private String mInterfaceDesc;
291};
292