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.io.j2me.btl2cap;
027:
028: import javax.bluetooth.L2CAPConnection;
029: import javax.bluetooth.BluetoothConnectionException;
030: import com.sun.kvem.jsr082.bluetooth.BluetoothConnection;
031: import java.io.IOException;
032: import java.io.InterruptedIOException;
033: import java.util.Vector;
034: import com.sun.midp.io.BluetoothUrl;
035: import com.sun.midp.jsr082.BluetoothUtils;
036:
037: /**
038: * Provides the <code>javax.bluetooth.L2CAPConnection</code>
039: * connection implemetation.
040: */
041: public class L2CAPConnectionImpl extends BluetoothConnection implements
042: L2CAPConnection {
043: /** Static initializer. */
044: static {
045: initialize();
046: }
047:
048: /**
049: * Native static class initializer.
050: */
051: private native static void initialize();
052:
053: /**
054: * Native finalizer.
055: * Releases all native resources used by this connection.
056: */
057: private native void finalize();
058:
059: /**
060: * Stores the address of the remote device connected by this connection.
061: * The value is set by the constructor.
062: */
063: byte[] remoteDeviceAddress;
064:
065: /** Lock object for reading from the socket */
066: private final Object readerLock = new Object();
067:
068: /** Lock object for writing to the socket */
069: private final Object writerLock = new Object();
070:
071: /**
072: * Negotiated ReceiveMTU and TransmitMTU.
073: * 16 high bits is ReceiveMTU, 16 low bits is TransmitMTU.
074: *
075: * This packeted value is returned by L2CAPConnectionImpl.connect0 and
076: * L2CAPNotifierImpl.accept0 methods and decoded by doReceiveMTU
077: * and doTransmitMTU methods.
078: */
079: int mtus = (((-1) << 16) & 0xFFFF0000) & ((-1) & 0xFFFF);
080:
081: /**
082: * Identifies this connection at native layer,
083: * <code>-1<code> if connection is not open.
084: *
085: * Note: in real mode this field is accessed only from native code.
086: */
087: private int handle = -1;
088:
089: /** The receive MTU for the connection. */
090: private int receiveMTU = -1;
091:
092: /** The transmit MTU for the connection. */
093: private int transmitMTU = -1;
094:
095: /**
096: * Constructs an instance and opens connection.
097: *
098: * @param url keeps connection details
099: * @param mode I/O access mode
100: * @exception IOException if connection fails
101: */
102: protected L2CAPConnectionImpl(BluetoothUrl url, int mode)
103: throws IOException {
104: this (url, mode, null);
105: }
106:
107: /**
108: * Constructs an instance and
109: * sets up corresponding native connection handle to it.
110: *
111: * @param url keeps connection details
112: * @param mode I/O access mode
113: * @param notif corresponding <code>L2CAPNotifierImpl</code> instance
114: * temporary storing native peer handle
115: * @exception IOException if connection fails
116: */
117: protected L2CAPConnectionImpl(BluetoothUrl url, int mode,
118: L2CAPNotifierImpl notif) throws IOException {
119: super (url, mode);
120:
121: if (notif == null) {
122: remoteDeviceAddress = BluetoothUtils
123: .getAddressBytes(url.address);
124: doOpen();
125: } else {
126: remoteDeviceAddress = new byte[6];
127: System.arraycopy(notif.peerAddress, 0, remoteDeviceAddress,
128: 0, 6);
129:
130: setThisConnHandle0(notif);
131: // copy negotiated MTUs returned by L2CAPNotifierImpl.accept0
132: mtus = notif.mtus;
133: }
134:
135: receiveMTU = (mtus >> 16) & 0xFFFF;
136: transmitMTU = mtus & 0xFFFF;
137:
138: // Check whether transmit MTU was increased during connection
139: // establishment phase. If it was, set original MTU value.
140: // IMPL_NOTE: pass updated transmit MTU to underlaying Bluetooth stack.
141: if (url.transmitMTU != -1 && transmitMTU > url.transmitMTU) {
142: transmitMTU = url.transmitMTU;
143: }
144:
145: setRemoteDevice();
146: }
147:
148: /**
149: * Retrieves native connection handle from temporary storage
150: * inside <code>L2CAPNotifierImpl</code> instance
151: * and sets it to this <code>L2CAPConnectionImpl</code> instance.
152: *
153: * Note: the method sets native connection handle directly to
154: * <code>handle<code> field of <code>L2CAPConnectionImpl</code> object.
155: *
156: * @param notif reference to corresponding <code>L2CAPNotifierImpl</code>
157: * instance storing native peer handle
158: */
159: private native void setThisConnHandle0(L2CAPNotifierImpl notif);
160:
161: /**
162: * Retrieves address of remote device on the other side of this connection.
163: *
164: * @return remote device address
165: */
166: public String getRemoteDeviceAddress() {
167: return BluetoothUtils.getAddressString(remoteDeviceAddress);
168: }
169:
170: /**
171: * Returns ReceiveMTU.
172: *
173: * @return receive MTU
174: *
175: * @throws IOException if the connection is closed.
176: */
177: public final int getReceiveMTU() throws IOException {
178: if (isClosed()) {
179: throw new IOException("Connection is closed");
180: }
181:
182: return receiveMTU;
183: }
184:
185: /**
186: * Returns TransmitMTU.
187: *
188: * @return transmit MTU
189: *
190: * @throws IOException if the connection is closed.
191: */
192: public final int getTransmitMTU() throws IOException {
193: if (isClosed()) {
194: throw new IOException("Connection is closed");
195: }
196:
197: return transmitMTU;
198: }
199:
200: /**
201: * Sends given bytes to this connection.
202: *
203: * Note: the method is non-blocking.
204: *
205: * @param data bytes to send.
206: *
207: * @throws IOException if either connection is closed or I/O error occured
208: */
209: public void send(byte[] data) throws IOException {
210: checkOpen();
211: checkWriteMode();
212: if (data == null) {
213: throw new NullPointerException("The data is null");
214: }
215:
216: int len = (data.length < transmitMTU) ? data.length
217: : transmitMTU;
218: int sentBytes;
219:
220: /*
221: * Multiple threads blocked on write operation may return results
222: * interleaved arbitrarily. From an application perspective, the
223: * results would be indeterministic. So "writer locks" are
224: * introduced for "write" operation to the same socket.
225: */
226: synchronized (writerLock) {
227: sentBytes = send0(data, 0, len);
228: }
229:
230: if (sentBytes != len) {
231: throw new IOException("Data sending failed");
232: }
233: }
234:
235: /**
236: * Receives data from this connection.
237: *
238: * Note: The method is blocking.
239: *
240: * @param buf byte array to place data received to
241: * @return amount of bytes received
242: * @throws IOException if either connection is closed or I/O error occured
243: */
244: public int receive(byte[] buf) throws IOException {
245: checkOpen();
246: checkReadMode();
247: if (buf == null) {
248: throw new NullPointerException("The buffer is null");
249: }
250: if (buf.length == 0) {
251: return 0;
252: }
253: int len = (buf.length > receiveMTU) ? receiveMTU : buf.length;
254:
255: /*
256: * Multiple threads blocked on read operation may
257: * return results interleaved arbitrarily. From an
258: * application perspective, the results would be
259: * indeterministic. So "reader locks" are introduced
260: * for "read" operation from the same handle.
261: */
262: synchronized (readerLock) {
263: return receive0(buf, 0, len);
264: }
265: }
266:
267: /**
268: * Checks if there is data to receive without blocking.
269: * @return true if any data can be retrieved via
270: * <code>receive()</code> method without blocking.
271: * @throws IOException if the connection is closed.
272: */
273: public boolean ready() throws IOException {
274: checkOpen();
275: return ready0();
276: }
277:
278: /**
279: * Closes this connection.
280: * @throws IOException if I/O error.
281: */
282: public void close() throws IOException {
283: synchronized (this ) {
284: if (isClosed()) {
285: return;
286: }
287: resetRemoteDevice();
288: }
289: close0();
290: }
291:
292: /**
293: * Receives data from this connection.
294: *
295: * Note: the method gets native connection handle directly from
296: * <code>handle<code> field of <code>L2CAPConnectionImpl</code> object.
297: *
298: * @param buf the buffer to read to
299: * @param off start offset in <code>buf</code> array
300: * at which the data to be written
301: * @param size the maximum number of bytes to read,
302: * the rest of the packet is discarded.
303: * @return total number of bytes read into the buffer or
304: * <code>0</code> if a zero length packet is received
305: * @throws IOException if an I/O error occurs
306: */
307: private native int receive0(byte[] buf, int off, int size)
308: throws IOException;
309:
310: /**
311: * Sends the specified data to this connection.
312: *
313: * Note: the method gets native connection handle directly from
314: * <code>handle<code> field of <code>L2CAPConnectionImpl</code> object.
315: *
316: * @param buf the data to send
317: * @param off the offset into the data buffer
318: * @param len the length of the data in the buffer
319: * @return total number of send bytes,
320: * or <code>-1</code> if nothing is send
321: * @throws IOException if an I/O error occurs
322: */
323: private native int send0(byte[] buf, int off, int len)
324: throws IOException;
325:
326: /**
327: * Checks if there is data to receive without blocking.
328: *
329: * Note: the method gets native connection handle directly from
330: * <code>handle<code> field of <code>L2CAPConnectionImpl</code> object.
331: *
332: * @return <code>true</code> if a packet is present,
333: * <code>false</code> otherwise
334: * @throws IOException if any I/O error occurs
335: */
336: private native boolean ready0() throws IOException;
337:
338: /**
339: * Closes client connection.
340: *
341: * Note: the method gets native connection handle directly from
342: * <code>handle<code> field of <code>L2CAPConnectionImpl</code> object.
343: *
344: * @throws IOException if any I/O error occurs
345: */
346: private native void close0() throws IOException;
347:
348: /** Opens client connection */
349: private void doOpen() throws IOException {
350: // create native connection object
351: // Note: the method sets resulting native connection handle
352: // directly to field <code>handle<code>.
353: create0(url.receiveMTU, url.transmitMTU, url.authenticate,
354: url.encrypt, url.master);
355:
356: byte[] address = BluetoothUtils.getAddressBytes(url.address);
357:
358: try {
359: // establish connection
360: mtus = connect0(address, url.port);
361: } catch (IOException e) {
362: throw new BluetoothConnectionException(
363: BluetoothConnectionException.FAILED_NOINFO, e
364: .getMessage());
365: }
366: }
367:
368: /**
369: * Creates a client connection object.
370: *
371: * Note: the method gets native connection handle directly from
372: * <code>handle<code> field of <code>L2CAPConnectionImpl</code> object.
373: *
374: * @param imtu receive MTU or <code>-1</code> if not specified
375: * @param omtu transmit MTU or <code>-1</code> if not specified
376: * @param auth <code>true</code> if authication is required
377: * @param enc <code>true</code> indicates
378: * what connection must be encrypted
379: * @param master <code>true</code> if client requires to be
380: * a connection's master
381: * @throws IOException if any I/O error occurs
382: */
383: private native void create0(int imtu, int omtu, boolean auth,
384: boolean enc, boolean master) throws IOException;
385:
386: /**
387: * Starts client connection establishment.
388: *
389: * Note: the method gets native connection handle directly from
390: * <code>handle<code> field of <code>L2CAPConnectionImpl</code> object.
391: *
392: * @param addr bluetooth address of device to connect to
393: * @param psm Protocol Service Multiplexor (PSM) value
394: * @return Negotiated ReceiveMTU and TransmitMTU.
395: * 16 high bits is ReceiveMTU, 16 low bits is TransmitMTU.
396: * @throws IOException if any I/O error occurs
397: */
398: private native int connect0(byte[] addr, int psm)
399: throws IOException;
400:
401: }
|