Main Page | Class Hierarchy | Data Structures | File List | Data Fields | Globals

bluetoothcommunicator.cpp

Go to the documentation of this file.
00001 /*
00002  * bluetoothcommunicator.cpp,v 1.38 2004/01/10 14:27:10 mattid Exp
00003  *
00004  * COBAIN - Communications API for EPOC Environments
00005  * Copyright (C) 2002-2003 Matti Dahlbom, Matti Kokkola
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  * Contact: Matti Dahlbom <matti@777-team.org>
00022  *          Matti Kokkola <matti.kokkola@iki.fi>
00023  */
00024 
00025 #include <es_sock.h>
00026 #include <bt_sock.h>
00027 #include <btmanclient.h>
00028 
00029 #include "bluetoothcommunicator.h"
00030 #include "cobainserver.h"
00031 #include "serversession.h"
00032 #include "btdiscoverer.h"
00033 #include "concreteconnection.h"
00034 #include "Log.h"
00035 
00036 CBTCommunicator::CBTCommunicator(CServerSession *aSession)
00037     : iIsListening(EFalse),
00038       iListeningConnection(NULL),
00039       iListeningSocketType(-1)
00040 {
00041     iServerSession = aSession;
00042 }
00043 
00044 CBTCommunicator::~CBTCommunicator()
00045 {
00046     delete iDiscoverer;
00047 
00048     if( iIsListening ) {
00049         StopListeningL();
00050 
00051         // close service discovery related resources
00052         iSdpDB.Close();
00053         iSdpSession.Close();
00054     }
00055 
00056     // disconnect from socket server
00057     Log::Print(_L("closing socket server.."));
00058     iSocketServ.Close();
00059 }
00060 
00061 void CBTCommunicator::ConstructL()
00062 {
00063     // connect to the socket server
00064     iSocketServ.Connect();
00065 }
00066 
00067 CBTCommunicator * CBTCommunicator::NewL(CServerSession *aSession)
00068 {
00069     CBTCommunicator *c = new CBTCommunicator(aSession);
00070     CleanupStack::PushL(c);
00071     c->ConstructL();
00072     CleanupStack::Pop(); // c
00073 
00074     return c;
00075 }
00076 
00077 void CBTCommunicator::DiscoverPeersL(const RMessage &aMessage,
00078                                      CServerSession &aSession)
00079 {
00080 #ifdef __WINS__
00081 
00082     // foobar test code for emulator
00084 
00085     //jolla's btdevaddr
00086     TUint8 btaddr[] = { 0x00, 0x04, 0x61, 0x80, 0x2f, 0xfd };
00087     TBuf8<6> addrbuf;
00088     addrbuf.Copy(btaddr, 6);
00089 
00090     TPeerDataList *peers = new (ELeave) TPeerDataList();
00091     TPeerData *data = new TPeerData;
00092     data->iDeviceName = _L("device1");
00093     data->iDeviceAddress = addrbuf;
00094     data->iServiceName = _L("dummy service 1");
00095     data->p.iBtProperties.iL2capPort = 1;
00096     peers->Append(data);
00097     data = new TPeerData;
00098     data->iDeviceName = _L("device2");
00099     data->iDeviceAddress = addrbuf;
00100     data->iServiceName = _L("dummy service 2");
00101     data->p.iBtProperties.iRfcommPort = 3;
00102     peers->Append(data);
00103     TInt size = 2;
00104 
00105     // set peerlist and complete call
00106     aSession.SetPeerList(peers);
00107     TBuf8<sizeof(TInt)> buf;
00108     buf.Copy((const TUint8 *)(&size), sizeof(TInt));
00109     aMessage.WriteL(aMessage.Ptr1(), buf);
00110     aMessage.Complete(KErrNone);
00111 #else
00112 
00113     // real discovery code for actual device
00115 
00116     if( iDiscoverer != NULL ) {
00117         delete iDiscoverer;
00118         iDiscoverer = NULL;
00119     }
00120 
00121     // start new discoverer
00122     iDiscoverer = CBTDiscoverer::NewL(aMessage, aSession);
00123     iDiscoverer->StartL(iSocketServ);
00124 
00125 #endif
00126 }
00127 
00128 // synchronously connects to the service
00129 RSocket* CBTCommunicator::ConnectL(TPeerData *aPeerData)
00130 {
00131     //Log::Print(_L("CBTCommunicator::ConnectL()"));
00132 
00133     RSocket *socket = new (ELeave) RSocket();
00134     CleanupStack::PushL(socket);
00135 
00136     // select between RFCOMM/L2CAP regarding to the peer data
00137     TBool use_rfcomm = ETrue;
00138     TInt port = aPeerData->p.iBtProperties.iRfcommPort;
00139 
00140     if( aPeerData->p.iBtProperties.iL2capPort > 0 ) {
00141         use_rfcomm = EFalse;
00142         port = aPeerData->p.iBtProperties.iL2capPort;
00143     }
00144 
00145     // check that there is a valid port value now
00146     __ASSERT_ALWAYS(port > 0, User::Leave(KErrArgument));
00147 
00148     if( use_rfcomm ) {
00149         // construct RFCOMM socket
00150         Log::Print(_L("Opening RFCOMM socket"));
00151         User::LeaveIfError(socket->Open(iSocketServ,
00152                                         KBTAddrFamily,
00153                                         KSockStream,
00154                                         KRFCOMM));
00155     } else {
00156         // construct L2CAP socket
00157         Log::Print(_L("Opening L2CAP socket"));
00158         User::LeaveIfError(socket->Open(iSocketServ,
00159                                         KBTAddrFamily,
00160                                         KSockSeqPacket, 
00161                                         KL2CAP));
00162     }
00163 
00164     // construct the address to connect to
00165     TBTDevAddr devaddr(aPeerData->iDeviceAddress);
00166     TBTSockAddr address;
00167     address.SetBTAddr(devaddr);
00168     address.SetPort(port);
00169 
00170     // connect the socket
00171     TRequestStatus status;
00172     socket->Connect(address, status);
00173     User::WaitForRequest(status);
00174 
00175     // validate that Connect() succeeded
00176     User::LeaveIfError(status.Int());    
00177 
00178     CleanupStack::Pop(); // socket
00179 
00180     Log::Print(_L("CBTCommunicator::ConnectL() exiting.."));
00181 
00182     return socket;
00183 }
00184 
00185 // closes listening socket and stops advertising the service
00186 void CBTCommunicator::StopListeningL()
00187 {
00188     if( !iIsListening ) {
00189         return;
00190     }
00191 
00192     // delete listening connection entity 
00193     delete iListeningConnection;
00194     iListeningConnection = NULL;
00195 
00196     // stop advertising - nevermind errors
00197     TRAPD(err, iSdpDB.DeleteRecordL(iRecord));
00198     if( err != KErrNone ) {
00199         Log::Print(_L("StopListeningL(): err %d"), err);
00200     }
00201 
00202     iRecord = 0;
00203 
00204     iIsListening = EFalse;
00205     iListeningSocketType = -1;
00206 }
00207 
00208 void CBTCommunicator::StartAdvertisingL(TInt aPort,
00209                                         const TInt aServiceClassID,
00210                                         const TInt aApplicationID,
00211                                         const TDesC8 &aServiceName,
00212                                         const TDesC8 &aServiceDesc) 
00213 {
00214     Log::Print(_L("StartAdvertisingL()"));
00215 
00216     // Connects to the SDP database
00217     User::LeaveIfError(iSdpSession.Connect());
00218     User::LeaveIfError(iSdpDB.Open(iSdpSession));
00219 
00220     // Defines the protocol that should be used to connect
00221     // with the advertised service
00222     CSdpAttrValueDES* protocol_descriptor = CSdpAttrValueDES::NewDESL(NULL);
00223     CleanupStack::PushL(protocol_descriptor);
00224 
00225     TBuf8<1> channel;
00226     channel.Append((TChar)aPort);
00227 
00228     if( iListeningSocketType == KRFCOMM ) {
00229         protocol_descriptor
00230         ->StartListL()   //  List of protocols required for this method
00231             ->BuildDESL()
00232             ->StartListL()
00233                 ->BuildUUIDL(aServiceClassID)
00234                 ->BuildUUIDL(KL2CAP)
00235                 ->BuildUUIDL(KRFCOMM)
00236                 ->BuildUintL(channel)
00237             ->EndListL()
00238         ->EndListL();
00239     } else {
00240         protocol_descriptor
00241         ->StartListL()   //  List of protocols required for this method
00242             ->BuildDESL()
00243             ->StartListL()
00244                 ->BuildUUIDL(aServiceClassID)
00245                 ->BuildUUIDL(KL2CAP)
00246                 ->BuildUintL(channel)
00247                 ->BuildUUIDL(KRFCOMM)
00248             ->EndListL()
00249         ->EndListL();
00250     }
00251 
00252     iSdpDB.CreateServiceRecordL(*protocol_descriptor, iRecord);
00253     iSdpDB.UpdateAttributeL(iRecord, 
00254                             KSdpAttrIdProtocolDescriptorList, 
00255                             *protocol_descriptor);
00256 
00257     CleanupStack::PopAndDestroy(); // protocol_descriptor
00258     
00259     // Defines the application ID
00260     iSdpDB.UpdateAttributeL(iRecord, 
00261                             KSdpAttrIdServiceID, 
00262                             aApplicationID);
00263 
00264     // Defines the service name
00265     CSdpAttrValueString *service_name =
00266         CSdpAttrValueString::NewStringL(aServiceName);
00267     CleanupStack::PushL(service_name);
00268     iSdpDB.UpdateAttributeL(iRecord, 
00269                 KSdpAttrIdBasePrimaryLanguage + 
00270                 KSdpAttrIdOffsetServiceName, 
00271                 *service_name);
00272     CleanupStack::PopAndDestroy(); // service_name
00273 
00274     // Add a description to the record
00275     CSdpAttrValueString *service_desc =
00276         CSdpAttrValueString::NewStringL(aServiceDesc);
00277     CleanupStack::PushL(service_desc);
00278     iSdpDB.UpdateAttributeL(iRecord, 
00279                 KSdpAttrIdBasePrimaryLanguage + 
00280                 KSdpAttrIdOffsetServiceDescription,
00281                 *service_desc);
00282     CleanupStack::PopAndDestroy(); // service_desc
00283 }
00284 
00285 void CBTCommunicator::SetAvailabilityL(TBool aIsAvailable)
00286 {
00287     TUint state = aIsAvailable ? 0xff : 0x00;
00288 
00289     // set the service availability attribute field
00290     iSdpDB.UpdateAttributeL(iRecord, KSdpAttrIdServiceAvailability, state);
00291 
00292     // increase the record version
00293     iSdpDB.UpdateAttributeL(iRecord, KSdpAttrIdServiceRecordState, iRecordVersion++);
00294 }
00295 
00296 
00297 // called by StartListeningL(). returns port to listen to
00298 TInt CBTCommunicator::OpenListeningSocketL()
00299 {
00300     Log::Print(_L("OpenListeningSocketL()"));
00301 
00302     // close existing listening socket if open
00303     iListeningSocket.Close();
00304 
00305     // delete old connection entity if any
00306     delete iListeningConnection;
00307     iListeningConnection = NULL;
00308 
00309     TInt port;
00310 
00311     if( iListeningSocketType == KRFCOMM ) {
00312         // open RFCOMM socket 
00313         Log::Print(_L("Opening RFCOMM socket"));
00314         User::LeaveIfError(iListeningSocket.Open(iSocketServ,
00315                                                  KBTAddrFamily,
00316                                                  KSockStream,
00317                                                  KRFCOMM));
00318 
00319         // acquire RFCOMM server channel to listen to
00320         User::LeaveIfError(
00321             iListeningSocket.GetOpt(KRFCOMMGetAvailableServerChannel, 
00322                     KSolBtRFCOMM, port)
00323         );
00324 
00325         iListeningSocket.SetLocalPort(port);
00326     } else {
00327         // open L2CAP socket
00328         Log::Print(_L("Opening L2CAP socket"));
00329         User::LeaveIfError(iListeningSocket.Open(iSocketServ,
00330                                                  KBTAddrFamily,
00331                                                  KSockSeqPacket,
00332                                                  KL2CAP));
00333 
00334         // find a L2CAP PSM port value (must be odd) by trying out values until
00335         // found one that is not in use, starting from 5
00336         TBool is_ok = EFalse;
00337         port = 5;
00338 
00339         while(  !is_ok ) {
00340             //Log::Print(_L("trying port %d"), port);
00341             TInt ret = iListeningSocket.SetLocalPort(port);
00342             if( ret == KErrNone ) {
00343                 // bound to the port - start to listen
00344                 break;
00345             } else if( ret == KErrInUse ) {
00346                 // try next port number
00347                 port += 2;
00348             } else {
00349                 // error - failed
00350                 //Log::Print(_L("SetLocalPort() error: %d"), ret);
00351                 User::Leave(ret);
00352             }
00353         }
00354     }
00355         
00356     Log::Print(_L("using port %d"), port);
00357 
00358     Log::Print(_L("calling Listen()"));
00359     User::LeaveIfError(iListeningSocket.Listen(KListeningQueueSize));
00360 
00361     Log::Print(_L("creating con entity"));
00362 
00363     // create new connection entity 
00364     iListeningConnection = CConcreteConnection::NewListeningL(&iListeningSocket,
00365                                                               &iSocketServ,
00366                                                               *iServerSession);
00367 
00368     return port;
00369 }
00370 
00371 void CBTCommunicator::SetChannelSecurityL(TInt aChannel)
00372 {
00373     RBTMan sec_manager;
00374     RBTSecuritySettings sec_session;
00375 
00376     // open security manager session
00377     User::LeaveIfError(sec_manager.Connect());
00378     CleanupClosePushL(sec_manager);
00379     User::LeaveIfError(sec_session.Open(sec_manager));
00380     CleanupClosePushL(sec_session);
00381 
00382     // define the security settings
00383     TBTServiceSecurity sec_settings(KCobainServerUid3, KSolBtRFCOMM, aChannel);
00384 
00385     if( iListeningSocketType == KL2CAP ) {
00386         sec_settings.SetProtocolID(KSolBtL2CAP);
00387     }
00388 
00389     sec_settings.SetAuthentication(EFalse);
00390     sec_settings.SetEncryption(EFalse);
00391     sec_settings.SetAuthorisation(EFalse);
00392 
00393     // register the service
00394     TRequestStatus status;
00395     sec_session.RegisterService(sec_settings, status);
00396     User::WaitForRequest(status);
00397     User::LeaveIfError(status.Int());
00398 
00399     // cleanup
00400     CleanupStack::PopAndDestroy(); // sec_session
00401     CleanupStack::PopAndDestroy(); // sec_manager
00402 }
00403 
00404 // called by CServerSession::ListenL()
00405 CConcreteConnection* CBTCommunicator::StartListeningL(const TInt aServiceClassID,
00406                                                       const TInt aApplicationID,
00407                                                       const TDesC8 &aServiceName,
00408                                                       const TDesC8 &aServiceDesc,
00409                                                       TInt aListeningSocketType) 
00410 {
00411     __ASSERT_ALWAYS(iListeningConnection == NULL, 
00412                     User::Panic(KBTCommPanic, KErrBTCommAlreadyListening));
00413 
00414     Log::Print(_L("StartListeningL()"));    
00415 
00416     // store type of listening socket
00417     iListeningSocketType = aListeningSocketType;
00418 
00419     // open new listening socket 
00420     TInt port = -1;
00421     
00422     TRAPD(err, (port = OpenListeningSocketL()));
00423     if( err != KErrNone ) {
00424         //Log::Print(_L("OpenListeningSocketL() error: %d"), err);
00425         User::Panic(KBTCommPanic, KerrBTCommFailedToCreateListeningSocket);
00426     }
00427 
00428     // set channel security
00429     SetChannelSecurityL(port);
00430 
00431     // start advertising the service
00432     StartAdvertisingL(port, 
00433                       aServiceClassID, 
00434                       aApplicationID, 
00435                       aServiceName,
00436                       aServiceDesc);
00437 
00438     // make the service available
00439     SetAvailabilityL(ETrue);
00440 
00441     iIsListening = ETrue;
00442 
00443     return iListeningConnection;
00444 }
00445 
00446 TInt CBTCommunicator::ResolveMTU(RSocket& aSocket) 
00447 {
00448     TInt mtu = 0;
00449     TInt rc = KErrNone;
00450 
00451     //##TODO## is this the same value with RFCOMM?
00452     rc = aSocket.GetOpt(KL2CAPGetOutboundMTU, 
00453              KSolBtL2CAP, mtu);    
00454     if (rc != KErrNone) {
00455     // Could not resolve MTU, use minimum value as
00456     // defined by API
00457     mtu = 48;
00458     }
00459     return mtu;
00460 }
00461 
00462 

Generated on Tue Jan 13 15:47:06 2004 for CobainAPIImplementation by doxygen 1.3.5