|Affix in a Nutshell: Affix - Open Source Bluetooth Protocol Stack for Linux|
|Prev||Chapter 3. Application Programming Interface||Next|
The SDP API is divided into two pars: service client API and service provider API.
The Service client API is dedicated for clients to find out what services are available on a remote device, what attributes they have and how to connect and properly use a service.
The Service provider API is dedicated for services to register information about itself with SDP server. it allows for a client to find it and connect to it.
Each service attribute describes a single characteristic of a service.
Universal attributes are defined in the SDP specification. Their definition and purpose are clearly stated and well understood, and are briefly described here.
ServiceRecordHandle is a unique service identifier (32 bits) valid only on the device that gave out the handle. The same service on two different devices would have different handles.
ServiceID is a universally unique service identifier (UUID) guaranteed to be the same on all devices where the service can be found.
ServiceClassIDSequence is a sequence of UUIDs representing the hierarchy (type) of service classes a service is known to conform to. Usually specified in the order "most specific" to "most generic".
AccessProtocols is one or more sequences of protocol descriptors. A protocol descriptor is a sequence of attributes - UUID of protocol, version number and port number, where a service can be accessed.
Bluetooth Profile Descriptor is a sequence of standard "Bluetooth Profile" descriptions that the service is known to conform to. Bluetooth profile description contains UUID of profile, its version number.
ServiceRecordState is a 32-bit integer provided to facilitate caching of service attributes. If this attribute is present in a service record, then it is guaranteed to change on any modification to the record.
ServiceInfoTimeToLive is a 32-bit integer that contains the number of seconds for which the service record is expected not to change, but not a guarantee. The time interval is measured from the time the attribute is received from the SDP server.
ServiceAvailability is an 8 bit unsigned integer that represents the measure of service's capability to handle more clients. 0x00 means completely unavailable and 0xff means maximum availability.
ServiceName, ServiceDescription and ServiceProviderName these are user visible strings conveying information about a service. These can be provided in one (universal) or more languages.
LanguageBasedAttributeIDList contains language specific attribute identifiers for user visible strings.
BrowseGroupList consists of a sequence of UUIDs representing the "browse group" the service belongs. Browse group is a hierarchy of service categories, facilitating service discovery without "a priori" information of any service.
ClientExecutableURL location of a client platform specific (Win, Unix, Palm) application that can use the service.
DocumentationURL location of additional service documentation.
IconURL location of an icon that can be used to represent the service.
ServiceDatabaseState is an attribute specific to the service discovery server itself. If this value changes, then the service repository was recently modified.
In addition to universal attributes, a service could have "service specific attributes". These attributes make sense only in the context of the said service. Dynamic attributes could be either basic attributes or constructed.
A UUID is a universally unique identifier that is guaranteed to be unique across all space and all time. UUIDs can be independently created in a distributed fashion. No central registry of assigned UUIDs is required. A UUID is a 128-bit value.
To reduce the burden of storing and transferring 128-bit UUID values, a range of UUID values has been pre-allocated for assignment to often-used, registered purposes. The first UUID in this pre-allocated range is known as the Bluetooth Base UUID and has the value 00000000-0000-1000-8000- 00805F9B34FB, from the Bluetooth Assigned Numbers document. UUID values in the pre-allocated range have aliases that are represented as 16-bit or 32-bit values. These aliases are often called 16-bit and 32-bit UUIDs, but it is important to note that each actually represents a 128-bit UUID value.
UUID object is used to store uuid, which can store 16, 32 or 128 bits uuid. To simplify interface to this object Affix provides set of functions to create UUID from a value and convert one type of UUID to another.
Table 3-9. UUID API
|void makeUUIDFrom16Bits(UUID *pUUID, UUID16Bit value16Bit);||Creates UUID object from 16 bit value.|
|void makeUUIDFrom32Bits(UUID *pUUID, UUID32Bit value32Bit);||Creates UUID object from 32 bit value.|
|void makeUUIDFrom128Bits(UUID *pUUID, UUID128Bit *value128Bit);||Creates UUID object from 128 bit value.|
|UUID *convertTo128Bits(UUID *pUUID);||Converts any type UUID to 128 bits UUID. It allocates memory to store new object.|
All of the information about a service that is maintained by an SDP server is contained within a single service record. The service record consists entirely of a list of service attributes.
ServiceRecord object is used to store information about service. It maintains a list of all service attributes.
The generic data structure SDPData is meant to hold any attribute, universal or dynamic. Each SDPData contains one attribute. The SDPData object contains the service attribute identifier, a data type identifier (int, char *, sequence etc), followed by the value.
Table 3-10. Attribute API
|SDPData *createSDPData(DataTypeDescriptor dtd, void *pValue);||Creates SDP attribute object of certain type.|
|int addToAttributeList(ServiceRecord *svcRec, ServiceAttributeIdentifier attrId, SDPData *pSDPData, int replaceFlag);||Adds attribute object to the attribute list of ServiceRecord object.|
|void freeSDPData(SDPData *pData);||Destroys entire attribute object.|
The client SDP API is used by a client to find services provided by a remote device and to find out what attributes they have. The overall function set is shown on the following table:
Table 3-11. Service client SDP API
|int SDPInit(0);||Initializes the SDP infrastructure.|
|SDPServerHandle SDPOpenServerConnection(struct sockaddr_affix *saddr);||Opens a connection to the SDP server.|
|void SDPCloseServerConnection(SDPServerHandle srvHandle);||Closes a connection to the SDP server.|
|int SDPServiceSearchRequest(SDPServerHandle srvHandle, slist_t *svcSearchList, uint16_t maxSvcRecordCount, slist_t **svcResponseList, uint16_t *handleCountInResponse);||Makes a service search request to the SDP server and returns service handle list of the services that match to search pattern. Search pattern - list of service class identifiers.|
|int SDPServiceAttributeRequest(SDPServerHandle srvHandle, ServiceRecordHandle svcHandle, AttributeRequestType attrReqType, slist_t *attrIDList, uint16_t maxAttrIDByteCount, ServiceRecord **_svcRec, uint16_t *maxAttrResponseByteCount);||Makes an attribute request of a service with a handle "svcHandle" and returns requested attribute list. "attrIDList" list defines attributes to return.|
|int SDPServiceSearchAttributeRequest(SDPServerHandle srvHandle, slist_t *svcSearchList, AttributeRequestType attrReqType, slist_t *attrIDList, uint16_t maxAttrByteCount, slist_t **svcResponseList, uint16_t *maxAttrResponseByteCount);||Makes a service search request which returns attributes of all found services. Combines previous two functions.|
|int __SDPServiceXXX(struct sockaddr_affix *saddr, ...);||These are variations of former three functions that take address to send request instead of ServerHandle. They open/close connection internally.|
|int getXXX(ServiceRecord *svcRec, ....)||Template of functions: extracts individual attributes (XXX) from service record, e.g.: service name, access port, profile id, ...|
The SDP infrastructure must be initialized before any activity using SDPInit(int mode).
Before any request to the SDP server can be made, a client has to make a connection to the SDP server using following function:
SDPServerHandle SDPOpenServerConnection(struct sockaddr_affix *saddr)
This function accepts one parameter - address of the server and returns SDP server handle. An Address is given using Affix sockaddr structure.
To close a connection, call [void SDPCloseServerConnection(SDPServerHandle srvHandle);].
The ServerHandle is provided as a first argument to SDPServiceXXX() functions.
Service search on the basis of given search pattern consisting of a set of service class identifiers. The maximum service class identifiers in the pattern can be 12. SDPServiceSearchRequest() is used for that.
The search pattern (svcSearchList) is a list of UUIDs (the UUID objects can either be 16, 32 or 128 bits). The UUID objects can be created using the helper functions defined in UUID support.
The client can limit the number of service record handles it expects from the server, and this is specified in maxSvcRecordCount. If there is no limit, set this to a large value.
The server response to this request is a list of matching service record handles (if any), and this is setup in svcResponseList (a slist_t) and returned to the caller. The number of handles found is also set in handleCountInResponse.
Search for a specified set of service attributes in a specific service. This request usually follows a previous service class identifier based search. Once a service has been identified, this request is used to find more about the service. Brief descriptions of the arguments follow:
ServiceRecordHandle of the service both need to be provided to uniquely identify the service.
The API supports requesting the entire range of attributes or a certain subset and this is specified in the request type, followed by the actual list of attributes in attrIdList (slist_t). Attribute identifiers are 16 bit unsigned integers specified in one of 2 ways. IndividualAttributes - 16bit individual identifiers actual attribute identifiers in ascending order. RangeOfAttributes - 32bit identifier range; the high-order 16bits is the start of range, the low-order 16bits are the end of range; 0x0000 to 0xFFFF gets all attributes.
maxAttrIDByteCount is the maximum byte count that the client expects to receive. The server will never return a response containing attribute byte count greater than this value.
maxAttrByteCount - this is a pointer to a 16-bit integer, which is set to indicate the number of bytes of attributes returned.
A successful execution of the command results in E_OK being returned else a negative value indicating the type of error (timeout, invalid args etc) is returned.
This request combines the service class identifier and the service attribute search request, thus minimizing the number of request/response pairs needed to find a service. The parameters contain a service search pattern and a list of attributes that need to be fetched, should a service record match the service search pattern.
First a service class match is done and for matching service, requested attributes are extracted.
The svcSearchList (slist_t) is a singly linked list containing elements of the search pattern. Each entry in the list is a UUID(DataTypeUUID_16) of the service to be searched.
AttributeSpecification attrSpec, specifies whether the request is for a subset of attributes or the entire range as described in Service attributes request from a specific service record.
The argument attrIDList (slist_t) is a singly linked list containing attribute identifiers desired. Every element is either a uint16_t(attrSpec = IndividualAttributes) or a uint32_t (attrSpec=RangeOfAttributes).
The argument maxAttrIDByteCount is the byte count of the number of attribute IDs specified in the request list.
The pointer svcResponseList (slist_t **) is set on successful return from the query, and will contain the service record handles of matching services.
The argument maxAttrResponseByteCount is a pointer to a 16-bit integer, which is set to indicate the number of bytes of attributes returned. This pointer is set on successful return.
The client API in the previous section were very basic, and do not provide mechanisms to extract attributes of individual ServiceRecord or their sub-components.
The getXXX(ServiceRecord *svcRec, XXX *xxx) functions provided in sdpclt.h, are intended for extracting attributes, where XXX is an attribute type. These are not listed here, but the API definition is self-explanatory. These are complements of the setXXX(XXX *x) utility functions for the server, but packaged in a different library.
Bluetooth service developers can use the following API to register services with the "local" SDP server. The "on-the-wire" formats of service registrations mimic the SDP. However a key difference is that service registrations PDUs are never sent on Bluetooth channels, but done using TCP sockets. The service registration requests and responses do use the "reserved range" of SDP PDU Identifiers. There is no problem since it is not sent on BT channels. The following are the APIs available for service implementers to register their service with the SDP server on the device. For details, please read the attached header files.
Table 3-12. Service provider SDP API
|int SDPInit(SDP_SVC_PROVIDER);||Initializes SDP infrastructure.|
|SDPServerHandle SDPOpenServerConnection(struct sockaddr_affix *saddr);||Opens a connection to local SDP server.|
|void SDPCloseServerConnection(SDPServerHandle srvHandle);||Closes a connection to SDP server.|
|ServiceRecord *createServiceRecord(void);||Creates a basic Service Record object w/o attributes.|
|void freeServiceRecord(ServiceRecord *svcRec);||Destroys Service Record object and free all used resources.|
|ServiceRecord *createRFCOMMServiceRecord(int port, int flags);||Creates a Service Record object and set common RFCOMM attributes.|
|int registerServiceRecord(SDPServerHandle srvHandle, ServiceRecord *svcRec);||Registers a Service Record object with the SDP server.|
|int updateServiceRecord(SDPServerHandle srvHandle, ServiceRecord *svcRec);||Updates a Service Record object on the SDP server.|
|int deleteServiceRecord(SDPServerHandle srvHandle, ServiceRecord *svcRec);||Deletes a Service Record object from SDP server.|
|int setXXX(ServiceRecord *svcRec, ....)||Template of functions: set individual attributes (XXX) to service record, e.g.: service name, access port, profile id, ...|
The SDP infrastructure must be initialized before any activity and this is done using SDPInit(SDP_SVC_PROVIDER).
Before any service registration can be made service provider must make a connection to local SDP server using following function.
The connection must be maintained the whole lifetime of the service. If connection is closed then SDP server removes all services that belongs to this connection. It prevents from the situation when service provider process terminates and forgets to delete registered services.
To close a connection, call SDPCloseServerConnection().
setXXX(ServiceRecord *svcRec, XXX *value) functions provided in sdpsrv.h, are intended for creating and modifying service attributes, where XXX is an attribute type. These are not listed here, but the API definition is self-explanatory. Only point to note is that any old XXX that exists will be deleted before the new value is set.
Note that the pointers passed to setXXX() functions must not be deleted for the life-time of the service as these are stored. Copies are not made of attributes pointed to by these pointers.
Deletes a service record pointed to by svcRec. This deletes the SDP server's image of the service record. Returns 0 if successful or -1 if there is a failure.
int deleteServiceRecord(ServiceRecord *svcRec);