001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.midp.jsr82emul;
027:
028: import java.io.UnsupportedEncodingException;
029: import com.sun.midp.io.BluetoothUrl;
030: import javax.bluetooth.BluetoothConnectionException;
031: import com.sun.midp.jsr082.BluetoothUtils;
032:
033: /**
034: * Utility class that keeps service connection information, packs it
035: * into byte array and restores form it. Has methods to check if a
036: * service represented by an instance can accept a connection represented
037: * by another one.
038: */
039: class ServiceConnectionData extends BytePack {
040: /**
041: * Error type, like in <code>BluetoothConnectionException</code>,
042: * ff error occured while looking for connection, <code>-1</code>
043: * if there is no error. Only makes sense in case of CONNECTION_DATA.
044: */
045: int error = -1;
046:
047: /** TCP socket port emulated service listens on. */
048: int socketPort;
049: /**
050: * IP address or host name of service in case of CONNECTION_DATA,
051: * Bluetooth address of client in case of CLIENT_DATA
052: */
053: byte[] address;
054: /** Channel ID or PSM. */
055: int port;
056: /** ReceiveMTU in server side terms. */
057: int receiveMTU;
058: /** TransmitMTU in server side terms. */
059: int transmitMTU;
060: /** Protocol ID as in <code>BluetoothUrl</code>. */
061: int protocol;
062: /** Shows wither server is master. */
063: boolean master;
064: /** Shows wither encrypted connection required. */
065: boolean encrypt;
066: /** Shows wither authorization required by server. */
067: boolean authorize;
068: /** Shows wither authentication required by server. */
069: boolean authenticate;
070:
071: /**
072: * Identifies if a service defined by this instance accepting currently.
073: * This flag is used to overcome TCK inconsistency where client may
074: * start connecting to Bluetooth TCK Agent while the latter is still not
075: * ready after previous connection.
076: */
077: private boolean accepting = true;
078: /**
079: * Delay duration for the case when acception is requested while it is
080: * not known if corresponding service is accepting.
081: */
082: private static final int ACCEPT_DELAY = 1000;
083: /**
084: * Max amount of acception trials when it is not known if service
085: * is accepting
086: */
087: private static final int MAX_ACCEPT_TRIALS = 24;
088:
089: /**
090: * Packed data type that implies that the following fields are included:
091: * socketPort, port, receiveMTU, transmitMTU, receiveMTU, protocol,
092: * master, encrypt, authorize, authenticate.
093: */
094: static final int SERVER_DATA = 0;
095: /**
096: * Packed data type that implies that the following fields are included:
097: * socketPort, IP address, receiveMTU, transmitMTU.
098: */
099: static final int CONNECTION_DATA = 1;
100: /**
101: * Packed data type that implies that the following fields are included:
102: * transmitMTU, receiveMTU, Bluetooth address.
103: */
104: static final int CLIENT_DATA = 2;
105: /**
106: * Packed data type that implies that the following fields are included:
107: * Bluetooth address, protocol, port, transmitMTU, receiveMTU, encrypt,
108: * authenticate, master.
109: * It is used CONNECT_TO_SERVICE request to the emulation server
110: */
111: static final int CONN_REQUEST_DATA = 3;
112:
113: /** Size of Bluetooth address in bytes representation. */
114: private static final int BTADDR_SIZE = 6;
115:
116: /** Byte array size when packed with CLIENT_DATA type. */
117: static final int CLIENT_DATA_SIZE = 4 * 2 + BTADDR_SIZE;
118: /** Byte array size when packed with SERVER_DATA type. */
119: static final int SERVER_DATA_SIZE = 4 * 4 + 1;
120:
121: /** Bit mask to highlight protcol type. */
122: private final static int PROTOCOL_MASK = 3;
123: /** Bit mask to highlight master flag. */
124: private final static int MASTER_MASK = 4;
125: /** Bit mask to highlight encrypt flas. */
126: private final static int ENCRYPT_MASK = 8;
127: /** Bit mask to highlight authorize flag. */
128: private final static int AUTHORIZE_MASK = 32;
129: /** Bit mask to highlight authenticate flag. */
130: private final static int AUTHENTICATE_MASK = 16;
131:
132: /**
133: * Constructs an instance which indicates that unknown error occured
134: * while looking for connection.
135: */
136: ServiceConnectionData() {
137: this (BluetoothConnectionException.FAILED_NOINFO);
138: }
139:
140: /**
141: * Constructs an instance which indicates that a connection error occured.
142: * @param error error code as in <code>BluetoothConnectionException</code>
143: */
144: ServiceConnectionData(int error) {
145: this .error = error;
146: }
147:
148: /**
149: * Constructs an instance by given byte representation.
150: * @param data byte representation
151: * @param type type of packed data, must be one of <code>
152: * SERVER_DATA, CONNECTION_DATA, CLIENT_DATA, CONN_REQUEST_DATA
153: * </code>
154: */
155: ServiceConnectionData(byte[] data, int type) {
156: super (data);
157:
158: switch (type) {
159: case CONN_REQUEST_DATA:
160: address = extractBytes(BTADDR_SIZE);
161:
162: // the rest of CONN_REQUEST_DATA case is poceeded here as well
163: case SERVER_DATA:
164: if (type == SERVER_DATA) {
165: socketPort = extractInt();
166: }
167:
168: port = extractInt();
169: receiveMTU = extractInt();
170: transmitMTU = extractInt();
171:
172: int misc = extract();
173: protocol = misc & PROTOCOL_MASK;
174: master = (misc & MASTER_MASK) != 0;
175: encrypt = (misc & ENCRYPT_MASK) != 0;
176: authorize = (misc & AUTHORIZE_MASK) != 0;
177: authenticate = (misc & AUTHORIZE_MASK) != 0;
178: break;
179:
180: case CONNECTION_DATA:
181: error = extractInt();
182: if (error == -1) {
183: socketPort = extractInt();
184: receiveMTU = extractInt();
185: transmitMTU = extractInt();
186: address = extractBytes(Const.IP_SIZE);
187: }
188: break;
189:
190: case CLIENT_DATA:
191: receiveMTU = extractInt();
192: transmitMTU = extractInt();
193: address = extractBytes(BTADDR_SIZE);
194: break;
195:
196: default:
197: throw new IllegalArgumentException();
198: }
199:
200: release();
201: }
202:
203: /**
204: * Retrieves bytes representation.
205: * @param type type of packed data, that defines which fields
206: * are to be packed, must be one of <code>
207: * SERVER_DATA, CONNECTION_DATA, CLIENT_DATA, CONN_REQUEST_DATA
208: * </code>
209: * @return byte array that keeps packed properties
210: */
211: byte[] toByteArray(int type) {
212: switch (type) {
213: case CONN_REQUEST_DATA:
214: reset(new byte[BTADDR_SIZE + SERVER_DATA_SIZE - 1]);
215: appendBytes(address);
216:
217: // the rest of CONN_REQUEST_DATA is proceeded here as well
218: case SERVER_DATA:
219: if (type == SERVER_DATA) {
220: reset(new byte[SERVER_DATA_SIZE]);
221: appendInt(socketPort);
222: }
223:
224: appendInt(port);
225: appendInt(receiveMTU);
226: appendInt(transmitMTU);
227:
228: int misc = protocol;
229: misc |= master ? MASTER_MASK : 0;
230: misc |= encrypt ? ENCRYPT_MASK : 0;
231: misc |= authorize ? AUTHORIZE_MASK : 0;
232: misc |= authenticate ? AUTHORIZE_MASK : 0;
233: append((byte) misc);
234: break;
235:
236: case CONNECTION_DATA:
237: if (error == -1) {
238: reset(new byte[4 * 4 + Const.IP_SIZE]);
239: appendInt(error);
240: appendInt(socketPort);
241: appendInt(receiveMTU);
242: appendInt(transmitMTU);
243: appendBytes(address);
244:
245: } else {
246: reset(new byte[4]);
247: appendInt(error);
248: }
249: break;
250:
251: case CLIENT_DATA:
252: reset(new byte[CLIENT_DATA_SIZE]);
253: appendInt(receiveMTU);
254: appendInt(transmitMTU);
255: appendBytes(address);
256: break;
257:
258: default:
259: throw new IllegalArgumentException();
260: }
261:
262: return release();
263: }
264:
265: /**
266: * Checks if client connection with given parameters can be accepted,
267: * if it can not, sets error code. If acception is possible but
268: * requires fields alignment, makes it modifying connection data
269: * passed as a parameter.
270: *
271: * @param client parameters of client connection request derived from
272: * client url, the parameters can be modified by this method
273: * if connection can be accepted.
274: * @return error code as in <code>BluetoothConnectionException</code>, if
275: * connection can not be accepted, <code>-1</code> if it can
276: */
277: void accept(ServiceConnectionData client) {
278: client.address = address;
279: client.socketPort = socketPort;
280: client.error = -1;
281:
282: if (client.master && master) {
283: client.error = BluetoothConnectionException.UNACCEPTABLE_PARAMS;
284:
285: } else if (client.protocol == BluetoothUrl.L2CAP) {
286: // If connection accepted successfully,
287: // (receiveMTU, transmitMTU) set here for the parameter
288: // become actual (receiveMTU, transmitMTU) for server and
289: // actual (transmitMTU, receiveMTU) for client.
290:
291: if (client.transmitMTU > receiveMTU
292: || transmitMTU > client.receiveMTU) {
293: client.error = BluetoothConnectionException.UNACCEPTABLE_PARAMS;
294: } else {
295: if (client.transmitMTU == -1) {
296: client.transmitMTU = receiveMTU;
297: }
298: if (transmitMTU != -1) {
299: client.receiveMTU = transmitMTU;
300: }
301: }
302: }
303:
304: if (client.error == -1) {
305: synchronized (this ) {
306: int trial = 0;
307: for (; trial < MAX_ACCEPT_TRIALS && !accepting; trial++) {
308: try {
309: Thread.sleep(ACCEPT_DELAY);
310: } catch (Throwable t) {
311: }
312: }
313:
314: if (trial == MAX_ACCEPT_TRIALS) {
315: client.error = BluetoothConnectionException.TIMEOUT;
316: } else {
317: // accepted successfully, now service is occupied by current client
318: accepting = false;
319: }
320: }
321: }
322: }
323:
324: /**
325: * Sets acception flag to true to identify that represented service
326: * is currebtly accepting. A part of the way that overcomes TCK
327: * inconsistency.
328: */
329: void setAccepting() {
330: accepting = true;
331: }
332: }
|