SDPServerpublic class SDPServer extends Object Represents Servive Discovery Protocol Server. |
Fields Summary |
---|
private static final boolean | DEBUGSet to false in RR version - then the javac skip the code. | private javax.bluetooth.L2CAPConnectionNotifier | conNotifiernotifier - a connection used by the server
to wait for a client connection | private Vector | connectionsCollects connections to the server. | private Acceptor | acceptorRequests acceptor, it is Runnable and works in its own thread. | private boolean | acceptorStartedShows if acceptor thread is running. | private static final int | SDP_UUIDSDP UUID. | private static final int | SDP_ERROR_RESPONSESDP_ErrorResponse PDU ID. | private static final int | SDP_SERVICE_SEARCH_REQUESTSDP_ServiceSearchRequest PDU ID. | private static final int | SDP_SERVICE_SEARCH_RESPONSESDP_ServiceSearchResponse PDU ID. | private static final int | SDP_SERVICE_ATTRIBUTE_REQUESTSDP_ServiceAttributeRequest PDU ID. | private static final int | SDP_SERVICE_ATTRIBUTE_RESPONSESDP_ServiceAttributeResponse PDU ID. | private static final int | SDP_SERVICE_SEARCH_ATTRIBUTE_REQUESTSDP_ServiceSearchAttributeResponse PDU ID. | private static final int | SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSESDP_ServiceSearchAttributeResponse PDU ID. | private static final int | SDP_INVALID_VERSIONError code for SDP_ErrorResponse: Invalid/unsupported SDP version. | private static final int | SDP_INVALID_SR_HANDLEError code for SDP_ErrorResponse: Invalid Service Record Handle. | private static final int | SDP_INVALID_SYNTAXError code for SDP_ErrorResponse: Invalid request syntax. |
Constructors Summary |
---|
public SDPServer()Constructs SDPServer instance.
/*
* Note: The following constants aren't used by emulator
* but can be used in real device
* private static final int SDP_INVALID_PDU_SIZE = 0x04;
* private static final int SDP_INVALID_CONTINUATION_STATE = 0x05;
* private static final int SDP_INSUFFICIENT_RESOURCES = 0x06;
*/
connections = new Vector();
acceptor = new Acceptor();
|
Methods Summary |
---|
private boolean | containsUUID(javax.bluetooth.DataElement attr, javax.bluetooth.UUID uuid)Checks if specified 'attr' contains (or equals) to specified 'uuid.
if (attr.getDataType() == DataElement.UUID) {
return uuid.equals((UUID) attr.getValue());
}
if (attr.getDataType() != DataElement.DATSEQ) {
return false;
}
Enumeration e = (Enumeration) attr.getValue();
while (e.hasMoreElements()) {
DataElement de = (DataElement) e.nextElement();
if (containsUUID(de, uuid)) {
return true;
}
}
return false;
| private boolean | findUUIDs(ServiceRecordImpl sr, javax.bluetooth.DataElement uuids)Checks if the specified service record contains all of the
UUID with values from specified 'uuids' list.
Note, that according to spec clarification from spec lead
such a search is done over all of the service attribues
(not just ServiceClassIDList and ProtocolDescriptorList).
int[] attrs = sr.getAttributeIDs();
Enumeration e = (Enumeration) uuids.getValue();
NEXT_UUID:
while (e.hasMoreElements()) {
UUID uuid = (UUID) ((DataElement) e.nextElement()).getValue();
for (int i = 0; i < attrs.length; i++) {
DataElement attr = sr.getAttributeValue(attrs[i]);
if (containsUUID(attr, uuid)) {
continue NEXT_UUID;
}
}
return false;
}
return true;
| private void | processRequest(DataL2CAPReaderWriter rw)Retrieves next PDU from a connection and processes it.
byte requestType = rw.readByte();
short transactionID = rw.readShort();
short length = rw.readShort();
if (requestType == SDP_SERVICE_SEARCH_REQUEST) {
processServiceSearch(rw, transactionID);
} else if (requestType == SDP_SERVICE_ATTRIBUTE_REQUEST) {
processServiceAttribute(rw, transactionID);
} else if (requestType == SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST) {
processServiceSearchAttribute(rw, transactionID);
} else {
writeErrorResponce(rw, transactionID, SDP_INVALID_SYNTAX,
"Invalid Type of Request");
System.err.println("WARNING: Unsupported SDP request");
}
| private void | processServiceAttribute(DataL2CAPReaderWriter rw, short transactionID)Retrieves SDP_ServiceAttribute parameters from given connection,
processes the requests and sends a respond.
int handle = rw.readInteger();
// IMPL_NOTE: Add checking for real device
short maximimSize = rw.readShort();
DataElement attrSet = rw.readDataElement();
// IMPL_NOTE: ContinuationState isn't used, but should on real device
int continuationState = rw.readByte();
if (continuationState != 0) {
writeErrorResponce(rw, transactionID, SDP_INVALID_VERSION,
"Current implementation don't support continuation state");
return;
}
ServiceRecord sr = SDDB.getInstance().getServiceRecord(handle);
// if service record not found process it
if (sr == null) {
writeErrorResponce(rw, transactionID, SDP_INVALID_SR_HANDLE,
"Servicce Record with specified ID not found");
return;
}
DataElement attrIDValues = new DataElement(DataElement.DATSEQ);
Enumeration e = (Enumeration) attrSet.getValue();
while (e.hasMoreElements()) {
DataElement attrID = (DataElement) e.nextElement();
int attr = (int) attrID.getLong();
DataElement attrValue = sr.getAttributeValue(attr);
if (attrValue != null) {
attrIDValues.addElement(attrID);
attrIDValues.addElement(attrValue);
}
}
int length = (int) rw.getDataSize(attrIDValues);
rw.writeByte((byte) SDP_SERVICE_ATTRIBUTE_RESPONSE);
rw.writeShort(transactionID);
rw.writeShort((short) (length + 3));
rw.writeShort((short) length);
rw.writeDataElement(attrIDValues);
// IMPL_NOTE: ContinuationState isn't used, but should on real device
rw.writeByte((byte) 0x00);
rw.flush();
| private void | processServiceSearch(DataL2CAPReaderWriter rw, short transactionID)Retrieves SDP_ServiceSearchRequest parameters from given connection,
processes the requests and sends a respond.
DataElement uuidSet = rw.readDataElement();
short maximimSRCount = rw.readShort();
// IMPL_NOTE: ContinuationState isn't used, but should on real device
int continuationState = rw.readByte();
if (continuationState != 0) {
writeErrorResponce(rw, transactionID, SDP_INVALID_VERSION,
"Current implementation don't support continuation state");
return;
}
Vector currentHandles = new Vector();
int[] handles = SDDB.getInstance().getHandles();
for (int i = 0; i < handles.length; i++) {
ServiceRecord sr = SDDB.getInstance().getServiceRecord(handles[i]);
if (findUUIDs((ServiceRecordImpl) sr, uuidSet)) {
currentHandles.addElement(new Integer(handles[i]));
}
}
rw.writeByte((byte) SDP_SERVICE_SEARCH_RESPONSE);
rw.writeShort(transactionID);
rw.writeShort((short) (currentHandles.size() + 5));
// Total and current counts are the same for all the results are
// sent in one response PDU
rw.writeShort((short) currentHandles.size());
rw.writeShort((short) currentHandles.size());
for (int i = 0; i < currentHandles.size(); i++) {
if (i > maximimSRCount) {
break;
}
int h = ((Integer) currentHandles.elementAt(i)).intValue();
rw.writeInteger(h);
}
// IMPL_NOTE: ContinuationState isn't used, but should on real device
rw.writeByte((byte) 0x00);
rw.flush();
| private void | processServiceSearchAttribute(DataL2CAPReaderWriter rw, short transactionID)Retrieves SDP_ServiceSearchAttribute parameters from given connection,
processes the requests and sends a respond.
DataElement uuidSet = rw.readDataElement();
// IMPL_NOTE: Add checking for real device
short maximimSize = rw.readShort();
DataElement attrSet = rw.readDataElement();
// IMPL_NOTE: ContinuationState isn't used, but should on real device
int continuationState = rw.readByte();
if (continuationState != 0) {
writeErrorResponce(rw, transactionID, SDP_INVALID_VERSION,
"Current implementation don't support continuation state");
return;
}
int[] handles = SDDB.getInstance().getHandles();
int handle = -1;
for (int i = 0; i < handles.length; i++) {
ServiceRecord sr = SDDB.getInstance().getServiceRecord(handles[i]);
if (findUUIDs((ServiceRecordImpl) sr, uuidSet)) {
handle = handles[i];
}
}
ServiceRecord sr = SDDB.getInstance().getServiceRecord(handle);
// if service record not found process it
if (sr == null) {
writeErrorResponce(rw, transactionID, SDP_INVALID_SR_HANDLE,
"Servicce Record with specified ID not found");
return;
}
DataElement attributeLists = new DataElement(DataElement.DATSEQ);
DataElement attrIDValues = new DataElement(DataElement.DATSEQ);
Enumeration e = (Enumeration) attrSet.getValue();
while (e.hasMoreElements()) {
DataElement attrID = (DataElement) e.nextElement();
int attr = (int) attrID.getLong();
DataElement attrValue = sr.getAttributeValue(attr);
if (attrValue != null) {
attrIDValues.addElement(attrID);
attrIDValues.addElement(attrValue);
}
}
attributeLists.addElement(attrIDValues);
int length = (int) rw.getDataSize(attributeLists);
rw.writeByte((byte) SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE);
rw.writeShort(transactionID);
rw.writeShort((short) (length + 3));
rw.writeShort((short) length);
rw.writeDataElement(attributeLists);
// IMPL_NOTE: ContinuationState isn't used, but should on real device
rw.writeByte((byte) 0x00);
rw.flush();
| private native void | requestPSM()Notifies native emulation code that next PSM requested
is for SDP server.
| public synchronized void | start()Starts this SDP server if not started.
if (acceptorStarted) {
return;
}
requestPSM();
UUID sdpUUID = new UUID(SDP_UUID);
try {
conNotifier = (L2CAPConnectionNotifier)
SDP.getL2CAPConnection("//localhost:"
+ SDP.UUID + ";name=SDPServer");
} catch (IOException ioe) {
// ignore
}
if (conNotifier != null) {
acceptorStarted = true;
(new Thread(acceptor)).start();
}
| synchronized void | stop()Stops this server closing all the connections to it.
try {
conNotifier.close();
} catch (IOException ioe) {
// ignore
}
for (int i = connections.size(); i >= 0; i--) {
L2CAPConnection con = (L2CAPConnection) connections.elementAt(i);
try {
synchronized (con) {
con.close();
}
} catch (IOException ioe) {
// ignore
}
}
connections.removeAllElements();
| private void | writeErrorResponce(DataL2CAPReaderWriter rw, short transactionID, int errorCode, java.lang.String info)Sends SDP_ErrorResponse PDU.
byte[] infoBytes = info.getBytes();
int length = infoBytes.length + 2;
rw.writeByte((byte) SDP_ERROR_RESPONSE);
rw.writeShort(transactionID);
rw.writeShort((short) length);
rw.writeShort((short) errorCode);
rw.writeBytes(infoBytes);
rw.flush();
|
|