FileDocCategorySizeDatePackage
SDPServer.javaAPI DocphoneME MR2 API (J2ME)20116Wed May 02 18:00:32 BST 2007com.sun.kvem.jsr082.bluetooth

SDPServer

public class SDPServer extends Object
Represents Servive Discovery Protocol Server.

Fields Summary
private static final boolean
DEBUG
Set to false in RR version - then the javac skip the code.
private javax.bluetooth.L2CAPConnectionNotifier
conNotifier
notifier - a connection used by the server to wait for a client connection
private Vector
connections
Collects connections to the server.
private Acceptor
acceptor
Requests acceptor, it is Runnable and works in its own thread.
private boolean
acceptorStarted
Shows if acceptor thread is running.
private static final int
SDP_UUID
SDP UUID.
private static final int
SDP_ERROR_RESPONSE
SDP_ErrorResponse PDU ID.
private static final int
SDP_SERVICE_SEARCH_REQUEST
SDP_ServiceSearchRequest PDU ID.
private static final int
SDP_SERVICE_SEARCH_RESPONSE
SDP_ServiceSearchResponse PDU ID.
private static final int
SDP_SERVICE_ATTRIBUTE_REQUEST
SDP_ServiceAttributeRequest PDU ID.
private static final int
SDP_SERVICE_ATTRIBUTE_RESPONSE
SDP_ServiceAttributeResponse PDU ID.
private static final int
SDP_SERVICE_SEARCH_ATTRIBUTE_REQUEST
SDP_ServiceSearchAttributeResponse PDU ID.
private static final int
SDP_SERVICE_SEARCH_ATTRIBUTE_RESPONSE
SDP_ServiceSearchAttributeResponse PDU ID.
private static final int
SDP_INVALID_VERSION
Error code for SDP_ErrorResponse: Invalid/unsupported SDP version.
private static final int
SDP_INVALID_SR_HANDLE
Error code for SDP_ErrorResponse: Invalid Service Record Handle.
private static final int
SDP_INVALID_SYNTAX
Error 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 booleancontainsUUID(javax.bluetooth.DataElement attr, javax.bluetooth.UUID uuid)
Checks if specified 'attr' contains (or equals) to specified 'uuid.

param
attr data element to check if it equals to desired UUID or contains it.
param
uuid the UUID to compare with.
return
true if data element given represents either specified UUID or a sequence that contains it, false otherwise.

        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 booleanfindUUIDs(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).

param
sr service record to check.
param
uuids list of UUIDs to check record for.
return
true if the record given contains all the UUIDs, false otherwise.

        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 voidprocessRequest(DataL2CAPReaderWriter rw)
Retrieves next PDU from a connection and processes it.

param
rw DataL2CAPReaderWriter instance that represents desired connection and provides RW utilities.
throws
IOException if a processing error occured.

        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 voidprocessServiceAttribute(DataL2CAPReaderWriter rw, short transactionID)
Retrieves SDP_ServiceAttribute parameters from given connection, processes the requests and sends a respond.

param
rw DataL2CAPReaderWriter instance that represents desired connection and provides RW utilities.
param
transactionID ID of transaction the request is recieved in.
throws
IOException if a processing error occured.

        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 voidprocessServiceSearch(DataL2CAPReaderWriter rw, short transactionID)
Retrieves SDP_ServiceSearchRequest parameters from given connection, processes the requests and sends a respond.

param
rw DataL2CAPReaderWriter instance that represents desired connection and provides RW utilities.
param
transactionID ID of transaction the request is recieved in.
throws
IOException if a processing error occured.

        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 voidprocessServiceSearchAttribute(DataL2CAPReaderWriter rw, short transactionID)
Retrieves SDP_ServiceSearchAttribute parameters from given connection, processes the requests and sends a respond.

param
rw DataL2CAPReaderWriter instance that represents desired connection and provides RW utilities.
param
transactionID ID of transaction the request is recieved in.
throws
IOException if a processing error occured.

        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 voidrequestPSM()
Notifies native emulation code that next PSM requested is for SDP server.

public synchronized voidstart()
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 voidstop()
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 voidwriteErrorResponce(DataL2CAPReaderWriter rw, short transactionID, int errorCode, java.lang.String info)
Sends SDP_ErrorResponse PDU.

param
rw DataL2CAPReaderWriter instance that represents connection to send to and provides RW utilities.
param
transactionID ID of transaction to send response within.
param
errorCode error code.
param
info error details.
throws
IOException if a processing error occured.

        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();