/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.jsr082.bluetooth;
import java.io.IOException;
import com.sun.jsr082.obex.ObexPacketStream;
import com.sun.jsr082.obex.ObexTransport;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.BluetoothConnectionException;
import javax.microedition.io.Connection;
import javax.microedition.io.Connector;
/*
* Base class for all bluetooth connections.
*/
abstract public class BluetoothConnection {
/* Keeps requested connection details. */
protected BluetoothUrl url;
/* Keeps open mode. */
protected int mode;
/* true if this connection was authorized, false otherwise. */
private boolean authorized;
/* true if this connection has requested encryption and is encrypted. */
private boolean encrypted;
/* Remote device for this connection. */
private RemoteDevice remoteDevice;
/*
* Retrieves <code>BluetoothConnection</code> from given one.
* Connection given is supposed to be either Bluetooth connection
* or a connection that uses Bluetooth as transport. All involved
* connections supposed to be open.
*
* @param conn the connection to extract Bluetooth connection from
* @return proper <code>BluetoothConnection</code> instance
* @throws IllegalArgumentException if connection is neither an instance
* of BluetoothConnection, nor uses one as transport.
* @throws IOException if connection given or transport is closed or
* transport is invalid.
*/
public static BluetoothConnection getConnection(Connection conn)
throws IOException {
if (conn == null) {
throw new NullPointerException("Null connection specified.");
}
if (conn instanceof ObexPacketStream) {
conn = ((ObexPacketStream)conn).getTransport();
}
if (!(conn instanceof BluetoothConnection)) {
throw new IllegalArgumentException("The specified connection " +
"is not a Bluetooth connection.");
}
BluetoothConnection btConn = (BluetoothConnection)conn;
btConn.checkOpen();
return btConn;
}
/*
* Creates a new instance of this class.
*
* @param url connection url
* @param mode I/O access mode server side otherwise it's false
*/
protected BluetoothConnection(BluetoothUrl url, int mode) {
// IMPL_NOTE: find proper place; the intent here is to start EmulationPolling
// and SDPServer prior to create a user's notifier
SDDB.getInstance();
this.url = url;
this.mode = mode;
}
/*
* Returns remote device for this connection.
*
* @return <code>RemoteDevice</code> object for this connection
* @throws IOException if this connection is closed
*/
public RemoteDevice getRemoteDevice() throws IOException {
checkOpen();
return remoteDevice;
}
/*
* Returns Bluetooth address of the remote device for this connection.
*
* @return Bluetooth address of the remote device
*/
public abstract String getRemoteDeviceAddress();
/*
* Retrieves reference to the remote device for this connection.
*/
protected void setRemoteDevice() {
remoteDevice = DiscoveryAgentImpl.getInstance().
getRemoteDevice(getRemoteDeviceAddress());
BCC.getInstance().addConnection(getRemoteDeviceAddress());
}
/*
* Removes reference to the remote device.
*/
protected void resetRemoteDevice() {
if (encrypted) {
encrypt(false);
}
remoteDevice = null;
BCC.getInstance().removeConnection(getRemoteDeviceAddress());
}
/*
* Determines if this connection is closed.
*
* @return true if this connection is closed, false otherwise
*/
public boolean isClosed() {
return remoteDevice == null;
}
/*
* Determines whether this connection represents the server side,
* i.e. this connection was created by a notifier in acceptAndOpen().
*
* @return true if this connection is a server-side connection,
* false otherwise
*/
public boolean isServerSide() {
return url.isServer;
}
/*
* Returns the authorization state of this connection.
*
* @return true if this connection has been authorized, false otherwise
*/
public boolean isAuthorized() {
return authorized;
}
/*
* Authorizes this connection. It is assumed that the remote device has
* previously been authenticated. This connection must represent the server
* side, i.e. isServer() should return true.
*
* @return true if the operation succeeded, false otherwise
*/
public boolean authorize() {
authorized = BCC.getInstance().authorize(
remoteDevice.getBluetoothAddress(), getServiceRecordHandle());
return authorized;
}
/*
* Changes encryption for this connection.
*
* @param enable specifies whether encription should be turned on or off
* @return true if encryption has been set as required, false otherwise
*/
public boolean encrypt(boolean enable) {
if (enable == encrypted) {
return true;
}
BCC.getInstance().encrypt(remoteDevice.getBluetoothAddress(), enable);
if (remoteDevice.isEncrypted()) {
if (enable) {
encrypted = true;
return true;
}
encrypted = false;
return false;
} else {
if (enable) {
return false;
}
encrypted = false;
return true;
}
}
/*
* Returns handle for the service record of the service this connection
* is attached to. Valid for server-side (incoming) connections only.
*
* @return service record handle, or 0 if the handle is not available
*/
protected int getServiceRecordHandle() {
return 0;
}
/*
* Checks if this connection is open.
*
* @throws IOException if this connection is closed
*/
protected void checkOpen() throws IOException {
if (isClosed()) {
throw new IOException("Connection is closed.");
}
}
/*
* Performs security checks, such as authentication, authorization, and
* encryption setup.
*
* @throws BluetoothConnectionException when failed
*/
protected void checkSecurity()
throws BluetoothConnectionException, IOException {
if (url.authenticate) {
if (!remoteDevice.authenticate()) {
throw new BluetoothConnectionException(
BluetoothConnectionException.SECURITY_BLOCK,
"Authentication failed.");
}
}
if (url.authorize) {
if (!remoteDevice.authorize((Connection)this)) {
throw new BluetoothConnectionException(
BluetoothConnectionException.SECURITY_BLOCK,
"Authorization failed.");
}
}
if (url.encrypt) {
if (!remoteDevice.encrypt((Connection)this, true)) {
throw new BluetoothConnectionException(
BluetoothConnectionException.SECURITY_BLOCK,
"Encryption failed.");
}
}
}
/*
* Checks read access.
*
* @throws IOException if open mode does not permit read access
*/
protected void checkReadMode() throws IOException {
if ((mode & Connector.READ) == 0) {
throw new IOException("Invalid mode: " + mode);
}
}
/*
* Checks write access.
*
* @throws IOException if open mode does not permit write access
*/
protected void checkWriteMode() throws IOException {
if ((mode & Connector.WRITE) == 0) {
throw new IOException("Invalid mode: " + mode);
}
}
}