Symbian OS Communications (779884), страница 31
Текст из файла (страница 31)
As a result, thereis a short race window between loading the stack and instructing it toignore discovery sequences. Note that use of this option requires theNetworkControl capability, which makes it unsuitable for generalpurpose use. This window is unlikely to be encountered in real situations,but future versions of Symbian OS will offer a Publish and Subscribe keywhich may be used as well.5.3.5 Service DiscoveryOnce a device has been found, IAS can be used to discover whatservices are running and how to connect to them. On Symbian OS, thisfunctionality is provided by the RNetDatabase class. As with all ofthe other ESOCK interface classes, this generic API is extended with therequired IrDA specific concepts by the IrDA stack, and so parameters arepassed as a generic descriptor package.Compared to device discovery, which only has a single specializedclass to deal with, service discovery has three.
Two are used for discoveringservices on other devices – TIASQuery and TIASReponse, and one forregistering services with the local IAS database – TIASDatabaseEntry.We’ll explore discovering services on remote devices first, then look athow to register entries in the local IAS database.When submitting queries, two classes are used:NONSHARABLE_CLASS(TIASQuery) : public TBuf8<KMaxQueryStringLength>{public:IMPORT_C TIASQuery(const TDesC8& aClass, const TDesC8& aAttribute,TUint aRemoteDevAddr);IMPORT_C TIASQuery();IMPORT_C void Set(const TDesC8& aClass, const TDesC8& aAttribute,TUint aRemoteDevAddr);IMPORT_C void Get(TDes8& aClass, TDes8& aAttribute,TUint& aRemoteDevAddr);};TIASQuery is used when formulating the query to send to a device.When using this class, the class name and attribute value should bespecified either at construction time, or by calling Set() just prior toexecuting the query.
A remote device address is also taken – note thatthis is a simple integer rather than a full TIrdaSockAddr class. Thedevice address can be extracted from a TIrdaSockAddr by callingGetRemoteDevAddr() on it.It is also worth emphasizing the limits on the length of the class andattribute names – these cannot be codified in the API, but the class name134INFRAREDmay not be greater than KIASClassNameMax bytes in length, and theattribute name may not be greater than KIASAttributeNameMax bytes.TBuf8 descriptors may therefore always be used, as the maximum sizeis always known.Now let’s look at the response we will receive:NONSHARABLE_CLASS(TIASResponse) : public TBuf8<KMaxQueryStringLength>{public:// But not exportedvoid SetToInteger(TUint anInteger);void SetToCharString(const TDesC8& aCharString);void SetToOctetSeq(const TDesC8& aData);void SetToCharString(const TDesC16& aWideString);public:IMPORT_C TIASResponse();IMPORT_CIMPORT_CIMPORT_CIMPORT_CIMPORT_CIMPORT_CIMPORT_CIMPORT_CIMPORT_C};TBool IsList() const;TInt NumItems() const;TIASDataType Type() const;TInt GetInteger(TInt& aResult, TInt anIndex=0) const;TInt GetOctetSeq(TDes8& aResult, TInt anIndex=0) const;TInt GetCharString(TDes8& aResult, TInt anIndex=0) const;const TPtrC8 GetCharString8(TInt anIndex=0) const;TInt GetCharString(TDes16& aResult, TInt anIndex=0) const;const TPtrC16 GetCharString16(TInt anIndex=0) const;A TIASResponse should be passed as the aResult parameter ofRNetDatabase::Query(), which upon completion will contain theresult of the query.
As the class returns the results of the query, the‘setter’ functions, while public, are internal to the stack and are notexported. Of far greater interest are the ‘getter’ functions. The functionsIsList() and NumItems() relate to IAS’s list functionality. Someoperations may return more than one result, which will be encoded asa list. Unfortunately, although Symbian OS provides the ability to detectwhether a list has been returned, it does not provide a way to obtain anyresult but the first in the resulting list. Some of the accessors will returnKErrUnsupported if called with a non-zero list index, some will returna null value, and others will just return the first item in the list anyway.Equally, because this functionality is unused, it is not safe to assume thatthe IsList() and NumItems() functions work as expected.
It is bestto ignore list values, and only ever ask for the first entry. As all of theindex parameters default to zero, they can simply be ignored.Type() returns the type of result obtained from IAS. IAS can transportintegers, byte sequences or user strings. It can also signal that an entrywas not found in the IAS database, with a result of ‘missing’. TheTIASDataType enumeration contains the strings used to tag each ofthese types.
If an unknown type of response is received, Symbian OS willreturn the type as EIASDataMissing.IRDA IN SYMBIAN OS135Once the type is known the data may be extracted. There are accessorsfor each type of data – in the case of integers and octet sequences, theseaccessors are simple. Pass in a variable, and the result will be copiedinto it, or the function will return an error. In the case of octet sequences,the specification imposes a maximum size of 1024 bytes, but SymbianOS will not support sequences of over 125 bytes. User strings are morecomplicated, due to the character set.
Four accessors are provided,returning either 8- or 16-bit descriptors, either as parameters passedby reference or as TPtrC return values. Unfortunately, defects in theimplementation mean that only one of the four accessors is reliable – theone taking a TDes8& parameter. The 16-bit accessors will never returna descriptor, they always return KErrNotSupported, KErrCorrupt,or a null string. The 8-bit TPtrC accessor will work in many situations,but will return a null string if it thinks the returned string is in Unicode(UCS-2) encoding.
Unfortunately, even this check is incorrect, as insteadof checking the character set byte, it checks the second byte of the string.It is unlikely that this byte will be 0xff (the Unicode character set), but ifit is, or if the user string is actually in Unicode format, the result will notbe as expected.It is possible that all of these defects will be corrected in futurereleases. For the moment, and to maximize compatibility in future, theTable 5.2 Return values and corresponding character setReturn valueCharacter setencodingCharConv conversation value0x00ASCIIKCharacterSetIdentifierAscii0x01ISO-8859-1KCharacterSetIdentifier885910x02ISO-8859-2KCharacterSetIdentifier885920x03ISO-8859-3KCharacterSetIdentifier885930x04ISO-8859-4KCharacterSetIdentifier885940x05ISO-8859-5KCharacterSetIdentifier885950x06ISO-8859-6KCharacterSetIdentifer885960x07ISO-8859-7KCharacterSetIdentifier885970x08ISO-8859-8KCharacterSetIdentifier885980x09ISO-8859-9KCharacterSetIdentifier885990xFFUCS2KCharacterSetIdentiferUcs2136INFRAREDonly recommended accessor function is the one which takes a TDes8¶meter and copies the data returned into it.
The return value of thisvariant is either the character set, in the case of a successful extraction; oran error code, in the case where the response is not a user string. Thereare 11 possible return values, which are listed in Table 5.2 along with thecharacter set they represent.The data copied into the supplied descriptor are the exact bytesequence retrieved from the remote device, so use of CCnvCharacterSetConverter from the CharConv framework is necessary to translatebetween the received character set and a 16-bit descriptor.// assume IAS query has already been performed_LIT(KIrResponseCharSetConversionPanic, "IRCharConv");enum TIrCharConvPanics{ECouldNotUseAsciiAsFallbackCharacterSet = 1};TBuf8<KMaxQueryStringLength> responseBuf;TBuf<KMaxQueryStringLength> outputBuf;// the two buffers above are consuming 384 bytes of stack - consider// using heap-based buffers (HBufC or RBuf) insteadTInt charSetOrErr;TUint charSet;charSetOrErr = iasResponse.GetCharString(responseBuf);if(charSetOrErr < 0){User::Leave(charSetOrErr);}else{switch (charSetOrErr) // we know it’s a char set now{case 0x00:charset = KCharacterSetIdentifierAscii;break;case 0x01:charset = KCharacterSetIdentifer88591;break;...
// and statements for the rest of the character setdefault:charset = KCharacterSetIdentiferAscii;// if unknown, assume ASCIIbreak;}}CCnvCharacterSetCoverter* converter = CCnvCharacterSetConverter::NewLC();RFs fs;User::LeaveIfError(fs.Connect());// alternately, if in a UI thread, use CCoeEnv::Static()->FsSession() toIRDA IN SYMBIAN OS137// retrieve shared RFs handleCleanupClosePushL(fs);CCnvCharacterSetConvertor::TAvailability isAvailable;isAvailable = converter.PrepareToConvertToOrFromL(charset, fs);if (isAvailable == ENotAvailable){// then we have a problem – again just treat as ASCIIisAvailable = converter.PrepareToConvertToOrFromL(KCharacterSetIdentiferAscii, fs);if (isAvailable == ENotAvailable) // ASCII should always be available!{User::Panic(KIrResponseCharSetConversionPanic,ECouldNotUseAsciiAsFallbackCharacterSet);}}TInt err;// at this point the required conversion routine is available, or we’re// using ASCII as a fallbackerr = converter.ConvertToUnicode(outputBuf, responseBuf, KStateDefault);User::LeaveIfError(err);// ignore any unconverted characters// outputBuf is now ready for useExample 5.1TDes16converting between user strings retrived from IAS andAt the end of all that we should now have a string suitable for userdisplay!As with octet sequences, the maximum length of a user string inSymbian OS is 125 bytes (so 62 Unicode characters), although the IASspecification allows a length of 255 bytes.Now let’s look at some example code for performing service discovery.In the first case, we’re going to search for the LSAP SEL for the defaultOBEX service.class CIrServiceDiscoverer : public CActive{public:...void DiscoverServicesL();virtual void RunL();// DoCancel would also need implementing for real applications...private:RSocketServ iSs;RNetDatabase iServices;TIASQuery iQuery;138INFRAREDTIASResponse iResponse;TInt iRemoteLSAP;TIrdaSockAddr iDiscoveredDevice; // assume already discovered and// address stored in here};_LIT8(KClassDefaultObexSevice, "OBEX");_LIT8(KAttributeLsapSel, "IrDA:TinyTP:LsapSel");void CIrServiceDiscoverer::DiscoverServicesL(){// Open a connection to socket serverUser::LeaveIfError(iSs.Open());// Open an IrDA service resolverUser::LeaveIfError(iServices.Open(iSs, KIrdaAddrFamily, KIrTinyTP));// Run a service inquiry sequencequery.Set(KClassDefaultObexSevice, KAttributeLsapSel,iDiscoveredDevice.GetRemoteDevAddr);services.Query(query, response, iStatus);SetActive();}void CIrServiceDiscoverer::RunL(){if (iStatus.Int() == KErrNone){switch (response.Type()){case EIASDataMissing:User::Leave(KErrNotFound);break;case EIASDataInteger:// Save the remote LSAP returnedUser::LeaveIfError(result.GetInteger(iRemoteLSAP));break;case EIASDataOctetSequence:case EIASDataUserString:default:// We asked for an LSAP, and received something other than an// integer.