📄 serverinfo.java
字号:
/* The Bluetooth Library for client-server communication Copyright (C) 2006 Martin Vysny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 for more details. */package net.sf.btw.btlib;import java.io.ByteArrayInputStream;import java.io.DataInputStream;import java.io.IOException;import javax.bluetooth.DeviceClass;import javax.bluetooth.DiscoveryAgent;import javax.bluetooth.DiscoveryListener;import javax.bluetooth.L2CAPConnection;import javax.bluetooth.RemoteDevice;import javax.bluetooth.ServiceRecord;import javax.bluetooth.UUID;import javax.microedition.io.Connector;import net.sf.btw.tools.Logger;import net.sf.btw.tools.StreamUtils;/** * A simple bean holding server info. * * @author Martin Vysny */public final class ServerInfo implements DiscoveryListener { /** * Creates instance of the info. * * @param device * the device */ public ServerInfo(final RemoteDevice device) { super(); this.device = device; bluetoothAddress = device.getBluetoothAddress(); displayableName = Peer.getDeviceName(device, false); } /** * The remote device reference. */ public final RemoteDevice device; /** * Bluetooth unique address. */ public final String bluetoothAddress; /** * Displayable name of the server. */ public String displayableName; /* * (non-Javadoc) * * @see java.lang.Object#toString() */ public String toString() { return displayableName; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof ServerInfo)) return false; final ServerInfo other = (ServerInfo) obj; return bluetoothAddress.equals(other.bluetoothAddress); } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ public int hashCode() { return bluetoothAddress.hashCode(); } /** * Not intended to be called by clients. */ public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) { // not used } /** * Not intended to be called by clients. */ public void inquiryCompleted(int discType) { // not used } /** * Not intended to be called by clients. */ public void servicesDiscovered(int transID, ServiceRecord[] servRecord) { if ((servRecord == null) || servRecord.length == 0) { Logger.debug("ServerInfo.servicesDiscovered(): 0 services", null); //$NON-NLS-1$ return; } // try to obtain a connection clientId = tryToConnect(servRecord); if (connection != null) { // We got a connection. interrupt! discoveryAgent.cancelServiceSearch(serviceTransactionID); synchronized (lock) { lock.notify(); } } } private static final DiscoveryAgent discoveryAgent = Peer.getDevice() .getDiscoveryAgent(); /** * Not intended to be called by clients. * * @see javax.bluetooth.DiscoveryListener#serviceSearchCompleted(int, int) */ public void serviceSearchCompleted(int transID, int respCode) { final boolean forcefullyTerminated = (respCode == SERVICE_SEARCH_TERMINATED) && (connection != null); final boolean error = (respCode != SERVICE_SEARCH_COMPLETED) && (respCode != SERVICE_SEARCH_NO_RECORDS) && !forcefullyTerminated; Logger.log(error ? Logger.LEVEL_ERROR : Logger.LEVEL_INFO, "ServerInfo.serviceSearchCompleted(): " //$NON-NLS-1$ + ServerLookup.getServiceErrorCode(respCode), null); synchronized (lock) { lock.notify(); } } /** * Thread must lock onto this object prior inquiry/service search. */ static final Object DISCOVERY_LOCK = new Object(); /** * <p> * Tries to obtain a connection to this server. The function blocks until a * connection is made or an exception is thrown. This function synchronizes * to its class instance hence only one VM thread may enter this method on a * single instance of the object. * </p> * <p> * Warning: This function uses service discovery: it should not be called * while another discovery is in progress as some phones support no * concurrent service discovery/inquiry. If a {@link ServerLookup} is in * progress the function will block until the lookup is finished. You should * NOT call this function from {@link ILookupListener} methods - the * function will not deadlock but the search may fail. * </p> * * @param serverId * the ID of the server. * @return connection, never <code>null</code>. * @throws IOException * if we were unable to open a connection. */ public L2CAPConnection connectToServer(final UUID serverId) throws IOException { synchronized (DISCOVERY_LOCK) { connection = null; exception = null; for (int tries = 0; tries < 3; tries++) { serviceTransactionID = discoveryAgent.searchServices(null, new UUID[] { serverId }, device, this); synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { // do nothing } } if (connection != null) return connection; } if (exception == null) throw new IOException("No server services found"); //$NON-NLS-1$ throw exception; } } /** * {@link #connectToServer(UUID)} waits for this object until a service * search is completed. */ private final Object lock = new Object(); /** * Exception is set here by {@link #tryToConnect(ServiceRecord[])} on * unsuccesfull connect. */ private volatile IOException exception = null; /** * Current active service transaction ID. */ private int serviceTransactionID = -1; /** * Connection is set here by {@link #tryToConnect(ServiceRecord[])} on * succesfull connect. */ private volatile L2CAPConnection connection = null; /** * Client ID given by server to this client. Contains <code>-1</code> on * unsuccesfull connect. Valid after the {@link #connectToServer(UUID)} * returns with non-<code>null</code> connection. */ public volatile byte clientId = -1; /** * Tries to connect to one of the services provided by the server. * * @param serviceRecords * list of {@link ServiceRecord} to connect to. * @return client ID given by server to this client. Returns <code>-1</code> * on unsuccesfull connect. */ private byte tryToConnect(final ServiceRecord[] serviceRecords) { if (serviceRecords.length == 0) throw new IllegalArgumentException("Empty serviceRecords"); //$NON-NLS-1$ for (int i = 0; i < serviceRecords.length; i++) { final ServiceRecord service = serviceRecords[i]; final String url = service.getConnectionURL( ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false); Logger.debug("ServerInfo.tryToConnect(): Trying " + url, null); //$NON-NLS-1$ try { final L2CAPConnection connection = (L2CAPConnection) Connector .open(url); // test the connection by sending and receiving initialization // packet. connection.send(StreamUtils.stringToByteArray(Peer.getDeviceName())); final byte[] initBuf = new byte[48]; final int bufLen = connection.receive(initBuf); final DataInputStream in = new DataInputStream( new ByteArrayInputStream(initBuf, 0, bufLen)); final byte clientId = in.readByte(); // good! Logger.info("ServerInfo.tryToConnect(): Got connection to " //$NON-NLS-1$ + url, null); this.connection = connection; return clientId; } catch (IOException ex) { Logger.debug("ServerInfo.tryToConnect(): Failed to connect to " //$NON-NLS-1$ + url, ex); exception = ex; } } Logger.error("ServerInfo.tryToConnect(): Tried " //$NON-NLS-1$ + serviceRecords.length + " services and failed", null); //$NON-NLS-1$ return -1; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -