1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package com.intel.bluetooth.obex;
26
27 import java.io.ByteArrayOutputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStream;
31 import java.util.Enumeration;
32 import java.util.Vector;
33
34 import javax.bluetooth.RemoteDevice;
35 import javax.bluetooth.ServiceRecord;
36 import javax.microedition.io.Connection;
37 import javax.microedition.io.StreamConnection;
38 import javax.obex.Authenticator;
39 import javax.obex.HeaderSet;
40 import javax.obex.ServerRequestHandler;
41
42 import com.intel.bluetooth.BluetoothConnectionAccess;
43 import com.intel.bluetooth.BluetoothStack;
44 import com.intel.bluetooth.DebugLog;
45 import com.intel.bluetooth.obex.OBEXAuthentication.Challenge;
46
47
48
49
50
51
52
53 abstract class OBEXSessionBase implements Connection, BluetoothConnectionAccess {
54
55 protected boolean isConnected;
56
57 private StreamConnection conn;
58
59 private InputStream is;
60
61 private OutputStream os;
62
63 protected long connectionID;
64
65 protected int mtu = OBEXOperationCodes.OBEX_DEFAULT_MTU;
66
67 protected Authenticator authenticator;
68
69 protected OBEXConnectionParams obexConnectionParams;
70
71 protected int packetsCountWrite;
72
73 protected int packetsCountRead;
74
75 private Vector authChallengesSent;
76
77
78
79
80 protected boolean requestSent;
81
82 public OBEXSessionBase(StreamConnection conn, OBEXConnectionParams obexConnectionParams) throws IOException {
83 if (obexConnectionParams == null) {
84 throw new NullPointerException("obexConnectionParams is null");
85 }
86 this.isConnected = false;
87 this.conn = conn;
88 this.obexConnectionParams = obexConnectionParams;
89 this.mtu = obexConnectionParams.mtu;
90 this.connectionID = -1;
91 this.packetsCountWrite = 0;
92 this.packetsCountRead = 0;
93 boolean initOK = false;
94 try {
95 this.os = conn.openOutputStream();
96 this.is = conn.openInputStream();
97 initOK = true;
98 } finally {
99 if (!initOK) {
100 try {
101 this.close();
102 } catch (IOException e) {
103 DebugLog.error("close error", e);
104 }
105 }
106 }
107 }
108
109 public void close() throws IOException {
110 StreamConnection c = this.conn;
111 this.conn = null;
112 try {
113 if (this.is != null) {
114 this.is.close();
115 this.is = null;
116 }
117 if (this.os != null) {
118 this.os.close();
119 this.os = null;
120 }
121 } finally {
122 if (c != null) {
123 c.close();
124 }
125 }
126
127 }
128
129 static OBEXHeaderSetImpl createOBEXHeaderSetImpl() {
130 return new OBEXHeaderSetImpl();
131 }
132
133 public static HeaderSet createOBEXHeaderSet() {
134 return createOBEXHeaderSetImpl();
135 }
136
137 static void validateCreatedHeaderSet(HeaderSet headers) {
138 OBEXHeaderSetImpl.validateCreatedHeaderSet(headers);
139 }
140
141 protected void writePacket(int commId, OBEXHeaderSetImpl headers) throws IOException {
142 writePacketWithFlags(commId, null, headers);
143 }
144
145 protected synchronized void writePacketWithFlags(int commId, byte[] headerFlagsData, OBEXHeaderSetImpl headers)
146 throws IOException {
147 if (this.requestSent) {
148 throw new IOException("Write packet out of order");
149 }
150 this.requestSent = true;
151 int len = 3;
152 if (this.connectionID != -1) {
153 len += 5;
154 }
155 if (headerFlagsData != null) {
156 len += headerFlagsData.length;
157 }
158 byte[] data = null;
159 if (headers != null) {
160 data = OBEXHeaderSetImpl.toByteArray(headers);
161 len += data.length;
162 }
163 if (len > mtu) {
164 throw new IOException("Can't sent more data than in MTU, len=" + len + ", mtu=" + mtu);
165 }
166 this.packetsCountWrite++;
167 ByteArrayOutputStream buf = new ByteArrayOutputStream();
168 OBEXHeaderSetImpl.writeObexLen(buf, commId, len);
169 if (headerFlagsData != null) {
170 buf.write(headerFlagsData);
171 }
172 if (this.connectionID != -1) {
173 OBEXHeaderSetImpl.writeObexInt(buf, OBEXHeaderSetImpl.OBEX_HDR_CONNECTION, this.connectionID);
174 }
175 if (data != null) {
176 buf.write(data);
177 }
178 DebugLog.debug0x("obex send (" + this.packetsCountWrite + ")", OBEXUtils.toStringObexResponseCodes(commId),
179 commId);
180 os.write(buf.toByteArray());
181 os.flush();
182 DebugLog.debug("obex sent (" + this.packetsCountWrite + ") len", len);
183
184 if ((headers != null) && (headers.hasAuthenticationChallenge())) {
185 if (authChallengesSent == null) {
186 authChallengesSent = new Vector();
187 }
188 for (Enumeration iter = headers.getAuthenticationChallenges(); iter.hasMoreElements();) {
189 byte[] authChallenge = (byte[]) iter.nextElement();
190 Challenge challenge = new Challenge(authChallenge);
191 authChallengesSent.addElement(challenge);
192 }
193 }
194 }
195
196 protected synchronized byte[] readPacket() throws IOException {
197 if (!this.requestSent) {
198 throw new IOException("Read packet out of order");
199 }
200 this.requestSent = false;
201 byte[] header = new byte[3];
202 OBEXUtils.readFully(is, obexConnectionParams, header);
203 this.packetsCountRead++;
204 DebugLog.debug0x("obex received (" + this.packetsCountRead + ")", OBEXUtils
205 .toStringObexResponseCodes(header[0]), header[0] & 0xFF);
206 int lenght = OBEXUtils.bytesToShort(header[1], header[2]);
207 if (lenght == 3) {
208 return header;
209 }
210 if ((lenght < 3) || (lenght > OBEXOperationCodes.OBEX_MAX_PACKET_LEN)) {
211 throw new IOException("Invalid packet length " + lenght);
212 }
213 byte[] data = new byte[lenght];
214 System.arraycopy(header, 0, data, 0, header.length);
215 OBEXUtils.readFully(is, obexConnectionParams, data, header.length, lenght - header.length);
216 if (is.available() > 0) {
217 DebugLog.debug("has more data after read", is.available());
218 }
219 return data;
220 }
221
222 private void validateBluetoothConnection() {
223 if ((conn != null) && !(conn instanceof BluetoothConnectionAccess)) {
224 throw new IllegalArgumentException("Not a Bluetooth connection " + conn.getClass().getName());
225 }
226 }
227
228 void validateAuthenticationResponse(OBEXHeaderSetImpl requestHeaders, OBEXHeaderSetImpl incomingHeaders)
229 throws IOException {
230 if ((requestHeaders != null) && requestHeaders.hasAuthenticationChallenge()
231 && (!incomingHeaders.hasAuthenticationResponses())) {
232
233 throw new IOException("Authentication response is missing");
234 }
235 handleAuthenticationResponse(incomingHeaders, null);
236 }
237
238 boolean handleAuthenticationResponse(OBEXHeaderSetImpl incomingHeaders, ServerRequestHandler serverHandler)
239 throws IOException {
240 if (incomingHeaders.hasAuthenticationResponses()) {
241 if (authenticator == null) {
242 throw new IOException("Authenticator required for authentication");
243 }
244 if ((authChallengesSent == null) && (authChallengesSent.size() == 0)) {
245 throw new IOException("Authentication challenges had not been sent");
246 }
247 boolean authenticated = false;
248 try {
249 authenticated = OBEXAuthentication.handleAuthenticationResponse(incomingHeaders, authenticator,
250 serverHandler, authChallengesSent);
251 } finally {
252 if ((authenticated) && (authChallengesSent != null)) {
253 authChallengesSent.removeAllElements();
254 }
255 }
256 return authenticated;
257 } else {
258 if ((authChallengesSent != null) && (authChallengesSent.size() > 0)) {
259 throw new IOException("Authentication response is missing");
260 }
261 return true;
262 }
263 }
264
265 void handleAuthenticationChallenge(OBEXHeaderSetImpl incomingHeaders, OBEXHeaderSetImpl replyHeaders)
266 throws IOException {
267 if (incomingHeaders.hasAuthenticationChallenge()) {
268 if (authenticator == null) {
269 throw new IOException("Authenticator required for authentication");
270 }
271 OBEXAuthentication.handleAuthenticationChallenge(incomingHeaders, replyHeaders, authenticator);
272 }
273 }
274
275
276
277
278
279
280 public long getRemoteAddress() throws IOException {
281 validateBluetoothConnection();
282 if (conn == null) {
283 throw new IOException("Connection closed");
284 }
285 return ((BluetoothConnectionAccess) conn).getRemoteAddress();
286 }
287
288
289
290
291
292
293 public RemoteDevice getRemoteDevice() {
294 validateBluetoothConnection();
295 if (conn == null) {
296 return null;
297 }
298 return ((BluetoothConnectionAccess) conn).getRemoteDevice();
299 }
300
301
302
303
304
305
306 public boolean isClosed() {
307 if (conn == null) {
308 return true;
309 }
310 if (this.conn instanceof BluetoothConnectionAccess) {
311 return ((BluetoothConnectionAccess) conn).isClosed();
312 } else {
313 return false;
314 }
315 }
316
317
318
319
320
321
322 public void shutdown() throws IOException {
323 if (this.conn instanceof BluetoothConnectionAccess) {
324 ((BluetoothConnectionAccess) conn).shutdown();
325 }
326 }
327
328
329
330
331
332
333 public void markAuthenticated() {
334 validateBluetoothConnection();
335 if (conn != null) {
336 ((BluetoothConnectionAccess) conn).markAuthenticated();
337 }
338 }
339
340
341
342
343
344
345 public int getSecurityOpt() {
346 validateBluetoothConnection();
347 if (conn == null) {
348 return ServiceRecord.NOAUTHENTICATE_NOENCRYPT;
349 } else {
350 return ((BluetoothConnectionAccess) conn).getSecurityOpt();
351 }
352 }
353
354
355
356
357
358
359 public boolean encrypt(long address, boolean on) throws IOException {
360 validateBluetoothConnection();
361 if (conn == null) {
362 throw new IOException("Connection closed");
363 }
364 return ((BluetoothConnectionAccess) conn).encrypt(address, on);
365 }
366
367
368
369
370
371
372 public void setRemoteDevice(RemoteDevice remoteDevice) {
373 validateBluetoothConnection();
374 if (conn != null) {
375 ((BluetoothConnectionAccess) conn).setRemoteDevice(remoteDevice);
376 }
377 }
378
379
380
381
382
383
384 public BluetoothStack getBluetoothStack() {
385 validateBluetoothConnection();
386 if (conn == null) {
387 return null;
388 }
389 return ((BluetoothConnectionAccess) conn).getBluetoothStack();
390 }
391
392
393
394
395
396
397 int getPacketsCountWrite() {
398 return this.packetsCountWrite;
399 }
400
401
402
403
404
405
406 int getPacketsCountRead() {
407 return this.packetsCountRead;
408 }
409
410
411
412
413
414
415 int getPacketSize() {
416 return this.mtu;
417 }
418
419
420
421
422
423
424
425 void setPacketSize(int mtu) throws IOException {
426 if (isConnected) {
427 throw new IOException("Session already connected");
428 }
429 obexConnectionParams.mtu = mtu;
430 }
431 }