29
|
1 |
/*
|
|
2 |
* Copyright (c) 2006-2008 Nokia Corporation and/or its subsidiary(-ies).
|
|
3 |
* All rights reserved.
|
|
4 |
* This component and the accompanying materials are made available
|
|
5 |
* under the terms of "Eclipse Public License v1.0"
|
|
6 |
* which accompanies this distribution, and is available
|
|
7 |
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
8 |
*
|
|
9 |
* Initial Contributors:
|
|
10 |
* Nokia Corporation - initial contribution.
|
|
11 |
*
|
|
12 |
* Contributors:
|
|
13 |
*
|
|
14 |
* Description: DUN Bluetooth plugin's listener
|
|
15 |
*
|
|
16 |
*/
|
|
17 |
|
|
18 |
|
|
19 |
#include <btsdp.h>
|
|
20 |
#include <e32std.h>
|
|
21 |
#include <bt_sock.h>
|
|
22 |
#include <btengdiscovery.h>
|
|
23 |
#include "DunPlugin.h"
|
|
24 |
#include "DunBtListen.h"
|
|
25 |
#include "DunBtPlugin.h"
|
|
26 |
#include "DunDebug.h"
|
|
27 |
|
|
28 |
const TInt KListenQueSize = 1;
|
|
29 |
const TInt KDunFixedChannel = 22; // Hack/kludge for Apple Bug ID 6527598
|
|
30 |
|
|
31 |
//Service Class Bits supported by DUN
|
|
32 |
static const TUint16 KCoDDunServiceClass = EMajorServiceTelephony | EMajorServiceNetworking;
|
|
33 |
|
|
34 |
// ======== MEMBER FUNCTIONS ========
|
|
35 |
|
|
36 |
// ---------------------------------------------------------------------------
|
|
37 |
// Two-phased constructor.
|
|
38 |
// ---------------------------------------------------------------------------
|
|
39 |
//
|
|
40 |
CDunBtListen* CDunBtListen::NewL( MDunServerCallback* aServer,
|
|
41 |
MDunListenCallback* aParent,
|
|
42 |
CDunTransporter* aTransporter,
|
|
43 |
TBtPortEntity& aEntity )
|
|
44 |
{
|
|
45 |
CDunBtListen* self = new (ELeave) CDunBtListen( aServer,
|
|
46 |
aParent,
|
|
47 |
aTransporter,
|
|
48 |
aEntity );
|
|
49 |
CleanupStack::PushL( self );
|
|
50 |
self->ConstructL();
|
|
51 |
CleanupStack::Pop( self );
|
|
52 |
return self;
|
|
53 |
}
|
|
54 |
|
|
55 |
// ---------------------------------------------------------------------------
|
|
56 |
// Destructor.
|
|
57 |
// ---------------------------------------------------------------------------
|
|
58 |
//
|
|
59 |
CDunBtListen::~CDunBtListen()
|
|
60 |
{
|
|
61 |
FTRACE(FPrint( _L("CDunBtListen::~CDunBtListen()") ));
|
|
62 |
ResetData();
|
|
63 |
FTRACE(FPrint( _L("CDunBtListen::~CDunBtListen() complete") ));
|
|
64 |
}
|
|
65 |
|
|
66 |
// ---------------------------------------------------------------------------
|
|
67 |
// Resets data to initial values
|
|
68 |
// ---------------------------------------------------------------------------
|
|
69 |
//
|
|
70 |
void CDunBtListen::ResetData()
|
|
71 |
{
|
|
72 |
// APIs affecting this:
|
|
73 |
// IssueRequestL()
|
|
74 |
Stop();
|
|
75 |
StopServiceAdvertisement();
|
|
76 |
// NewL()
|
|
77 |
iTransporter->FreeAdvertisementMonitor( KDunBtPluginUid, this );
|
|
78 |
delete iDiscovery;
|
|
79 |
iDiscovery = NULL;
|
|
80 |
if ( iSockServer.Handle() != KNullHandle )
|
|
81 |
{
|
|
82 |
iSockServer.Close();
|
|
83 |
}
|
|
84 |
// Internal
|
|
85 |
Initialize();
|
|
86 |
}
|
|
87 |
|
|
88 |
// ---------------------------------------------------------------------------
|
|
89 |
// Registers itself to SDP and BT manager, opens a socket
|
|
90 |
// and starts to listen it.
|
|
91 |
// ---------------------------------------------------------------------------
|
|
92 |
//
|
|
93 |
void CDunBtListen::IssueRequestL()
|
|
94 |
{
|
|
95 |
FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL()" ) ));
|
|
96 |
|
|
97 |
if ( iListenState == EBtListenStateListening )
|
|
98 |
{
|
|
99 |
FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() (already active) complete" ) ));
|
|
100 |
User::Leave( KErrNotReady );
|
|
101 |
}
|
|
102 |
|
|
103 |
TBool advertise = iTransporter->AdvertisementStatus();
|
|
104 |
if ( !advertise )
|
|
105 |
{
|
|
106 |
// Return silently here as CDunTransporter will notify later
|
|
107 |
return;
|
|
108 |
}
|
|
109 |
|
|
110 |
TBool inUse = EFalse;
|
|
111 |
TInt numOfChans = 0;
|
|
112 |
TInt retTemp = StartServiceAdvertisement( inUse );
|
|
113 |
if ( retTemp != KErrNone )
|
|
114 |
{
|
|
115 |
if ( inUse )
|
|
116 |
{
|
|
117 |
numOfChans = iTransporter->GetNumberOfAllocatedChannelsByUid(
|
|
118 |
KDunBtPluginUid );
|
|
119 |
if ( numOfChans == 0)
|
|
120 |
{
|
|
121 |
// No channels so parent can't reissue requests of this object
|
|
122 |
// This is fatal case -> leave.
|
|
123 |
// NOTE: To add full support for this case a poller (timer) is
|
|
124 |
// needed that polls for free RFCOMM channel by given interval.
|
|
125 |
User::Leave( retTemp );
|
|
126 |
}
|
|
127 |
// If in use and parent has channels then just fail silently.
|
|
128 |
// Let this object to wait until parent finds new resources.
|
|
129 |
FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() complete" ) ));
|
|
130 |
return;
|
|
131 |
}
|
|
132 |
FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() (failed!) complete" ) ));
|
|
133 |
User::Leave( retTemp );
|
|
134 |
}
|
|
135 |
|
|
136 |
// Not already active here so start listening
|
|
137 |
// First open blank data socket
|
|
138 |
retTemp = iEntity.iBTPort.Open( iSockServer );
|
|
139 |
if ( retTemp != KErrNone )
|
|
140 |
{
|
|
141 |
FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() (ERROR) complete (%d)" ), retTemp));
|
|
142 |
User::Leave( retTemp );
|
|
143 |
}
|
|
144 |
iStatus = KRequestPending;
|
52
|
145 |
iListenState = EBtListenStateListening;
|
29
|
146 |
iListenSocket.Accept( iEntity.iBTPort, iStatus );
|
|
147 |
SetActive();
|
|
148 |
|
|
149 |
FTRACE(FPrint( _L( "CDunBtListen::IssueRequestL() complete") ));
|
|
150 |
}
|
|
151 |
|
|
152 |
// ---------------------------------------------------------------------------
|
|
153 |
// Stops listening
|
|
154 |
// ---------------------------------------------------------------------------
|
|
155 |
//
|
|
156 |
TInt CDunBtListen::Stop()
|
|
157 |
{
|
|
158 |
FTRACE(FPrint( _L( "CDunBtListen::Stop()") ));
|
|
159 |
if ( iListenState != EBtListenStateListening )
|
|
160 |
{
|
|
161 |
FTRACE(FPrint( _L("CDunBtListen::Stop() (not ready) complete" )));
|
|
162 |
return KErrNotReady;
|
|
163 |
}
|
|
164 |
iListenSocket.CancelAccept();
|
|
165 |
Cancel();
|
|
166 |
iListenState = EBtListenStateIdle;
|
|
167 |
FTRACE(FPrint( _L( "CDunBtListen::Stop() complete") ));
|
|
168 |
return KErrNone;
|
|
169 |
}
|
|
170 |
|
|
171 |
// ---------------------------------------------------------------------------
|
|
172 |
// CDunBtListen::CDunBtListen
|
|
173 |
// ---------------------------------------------------------------------------
|
|
174 |
//
|
|
175 |
CDunBtListen::CDunBtListen( MDunServerCallback* aServer,
|
|
176 |
MDunListenCallback* aParent,
|
|
177 |
CDunTransporter* aTransporter,
|
|
178 |
TBtPortEntity& aEntity ) :
|
|
179 |
CActive( EPriorityStandard ),
|
|
180 |
iServer( aServer ),
|
|
181 |
iParent( aParent ),
|
|
182 |
iTransporter( aTransporter ),
|
|
183 |
iEntity( aEntity )
|
|
184 |
{
|
|
185 |
Initialize();
|
|
186 |
}
|
|
187 |
|
|
188 |
// ---------------------------------------------------------------------------
|
|
189 |
// CDunBtListen::ConstructL
|
|
190 |
// ---------------------------------------------------------------------------
|
|
191 |
//
|
|
192 |
void CDunBtListen::ConstructL()
|
|
193 |
{
|
|
194 |
FTRACE(FPrint(_L("CDunBtListen::ConstructL()")));
|
|
195 |
if ( !iServer || !iParent || !iTransporter )
|
|
196 |
{
|
|
197 |
User::Leave( KErrGeneral );
|
|
198 |
}
|
|
199 |
|
|
200 |
CBTEngDiscovery* discovery = CBTEngDiscovery::NewLC();
|
|
201 |
FTRACE(FPrint(_L("CDunBtListen::ConstructL: iSockServer.Connect")));
|
|
202 |
User::LeaveIfError( iSockServer.Connect() );
|
|
203 |
|
|
204 |
// Set advertisement monitor
|
|
205 |
iTransporter->SetAdvertisementMonitorL( KDunBtPluginUid, this );
|
|
206 |
|
|
207 |
// Then we are ready to start listening and accepting incoming connection
|
|
208 |
// requests.
|
|
209 |
CleanupStack::Pop( discovery );
|
|
210 |
iDiscovery = discovery;
|
|
211 |
CActiveScheduler::Add( this );
|
|
212 |
FTRACE(FPrint(_L("CDunBtListen::ConstructL() complete")));
|
|
213 |
}
|
|
214 |
|
|
215 |
// ---------------------------------------------------------------------------
|
|
216 |
// Initializes this class
|
|
217 |
// ---------------------------------------------------------------------------
|
|
218 |
//
|
|
219 |
void CDunBtListen::Initialize()
|
|
220 |
{
|
|
221 |
// Don't initialize iServer here (it is set through NewL)
|
|
222 |
// Don't initialize iParent here (it is set through NewL)
|
|
223 |
// Don't initialize iTransporter here (it is set through NewL)
|
|
224 |
// Don't initialize iEntity here (it is set through NewL)
|
|
225 |
iListenState = EBtListenStateIdle;
|
|
226 |
iDiscovery = NULL;
|
|
227 |
iChannelNum = 0;
|
|
228 |
iSDPHandleDun = 0;
|
|
229 |
}
|
|
230 |
|
|
231 |
// ---------------------------------------------------------------------------
|
|
232 |
// Starts dialup service advertisement
|
|
233 |
// ---------------------------------------------------------------------------
|
|
234 |
//
|
|
235 |
TInt CDunBtListen::StartServiceAdvertisement( TBool& aInUse )
|
|
236 |
{
|
|
237 |
FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement()" ) ));
|
|
238 |
|
|
239 |
TInt retTemp = ReserveLocalChannel( iSockServer,
|
|
240 |
iListenSocket,
|
|
241 |
iChannelNum,
|
|
242 |
aInUse );
|
|
243 |
if ( retTemp != KErrNone )
|
|
244 |
{
|
|
245 |
FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement() (ERROR) complete" ) ));
|
|
246 |
return retTemp;
|
|
247 |
}
|
|
248 |
|
|
249 |
// Now RFCOMM channel number of the next data socket must be the same as
|
|
250 |
// the current listener's RFCOMM channel number. Set that now.
|
|
251 |
iEntity.iChannelNum = iChannelNum;
|
|
252 |
|
|
253 |
// Register SDP record
|
|
254 |
iSDPHandleDun = 0;
|
|
255 |
retTemp = iDiscovery->RegisterSdpRecord( KDialUpNetworkingUUID,
|
|
256 |
iChannelNum,
|
|
257 |
iSDPHandleDun );
|
|
258 |
if ( retTemp != KErrNone )
|
|
259 |
{
|
|
260 |
FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement() (failed!) complete (%d)" ), retTemp));
|
|
261 |
return retTemp;
|
|
262 |
}
|
|
263 |
FTRACE(FPrint( _L( "CDunBtListen::StartServiceAdvertisement() complete" ) ));
|
|
264 |
return KErrNone;
|
|
265 |
}
|
|
266 |
|
|
267 |
// ---------------------------------------------------------------------------
|
|
268 |
// Stops dialup service advertisement
|
|
269 |
// ---------------------------------------------------------------------------
|
|
270 |
//
|
|
271 |
TInt CDunBtListen::StopServiceAdvertisement()
|
|
272 |
{
|
|
273 |
FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement()" ) ));
|
|
274 |
if ( !iDiscovery )
|
|
275 |
{
|
|
276 |
FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement() (iDiscovery) not initialized!" ) ));
|
|
277 |
return KErrGeneral;
|
|
278 |
}
|
|
279 |
if ( iSDPHandleDun != 0 )
|
|
280 |
{
|
|
281 |
TInt retTemp = iDiscovery->DeleteSdpRecord( iSDPHandleDun );
|
|
282 |
FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement() record closed (%d)" ), retTemp ));
|
|
283 |
iSDPHandleDun = 0;
|
|
284 |
}
|
|
285 |
if ( iListenSocket.SubSessionHandle() )
|
|
286 |
{
|
|
287 |
iListenSocket.Close();
|
|
288 |
}
|
|
289 |
FTRACE(FPrint( _L( "CDunBtListen::StopServiceAdvertisement() complete" ) ));
|
|
290 |
return KErrNone;
|
|
291 |
}
|
|
292 |
|
|
293 |
// ---------------------------------------------------------------------------
|
|
294 |
// Method which reserves local RFCOMM channel (from possible channels 1-30)
|
|
295 |
// and returns it to client.
|
|
296 |
// ---------------------------------------------------------------------------
|
|
297 |
//
|
|
298 |
TInt CDunBtListen::ReserveLocalChannel( RSocketServ& aSocketServ,
|
|
299 |
RSocket& aListenSocket,
|
|
300 |
TUint& aChannelNum,
|
|
301 |
TBool& aInUse )
|
|
302 |
{
|
|
303 |
FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel()")));
|
|
304 |
aInUse = EFalse;
|
|
305 |
if ( aListenSocket.SubSessionHandle() )
|
|
306 |
{
|
|
307 |
FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() (open socket!) complete")));
|
|
308 |
return KErrArgument;
|
|
309 |
}
|
|
310 |
TInt retTemp;
|
|
311 |
TProtocolDesc pInfo;
|
|
312 |
retTemp = aSocketServ.FindProtocol( TProtocolName(KRFCOMMDesC), pInfo );
|
|
313 |
if ( retTemp != KErrNone )
|
|
314 |
{
|
|
315 |
FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() (FindProtocol failed) complete (%d)"), retTemp));
|
|
316 |
return retTemp;
|
|
317 |
}
|
|
318 |
retTemp = aListenSocket.Open( aSocketServ,
|
|
319 |
pInfo.iAddrFamily,
|
|
320 |
pInfo.iSockType,
|
|
321 |
pInfo.iProtocol );
|
|
322 |
if ( retTemp != KErrNone )
|
|
323 |
{
|
|
324 |
FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() (Open failed) complete (%d)"), retTemp));
|
|
325 |
return retTemp;
|
|
326 |
}
|
|
327 |
TRfcommSockAddr addr;
|
|
328 |
TBTServiceSecurity sec;
|
|
329 |
sec.SetAuthentication( ETrue );
|
|
330 |
sec.SetAuthorisation( ETrue );
|
|
331 |
sec.SetEncryption( ETrue );
|
|
332 |
sec.SetPasskeyMinLength( 0 );
|
|
333 |
addr.SetSecurity( sec );
|
|
334 |
addr.SetPort( KRfcommPassiveAutoBind );
|
|
335 |
// When fix from Apple, replace the following with
|
|
336 |
// "retTemp = aListenSocket.Bind( addr );"
|
|
337 |
retTemp = DoExtendedBind( aListenSocket, addr );
|
|
338 |
if ( retTemp != KErrNone )
|
|
339 |
{
|
|
340 |
aListenSocket.Close();
|
|
341 |
aInUse = ETrue;
|
|
342 |
FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() Bind() complete (%d)"), retTemp));
|
|
343 |
return KErrInUse;
|
|
344 |
}
|
|
345 |
aChannelNum = aListenSocket.LocalPort();
|
|
346 |
|
|
347 |
// We try to set the Telephony and Networking bits in our service class. If this fails we
|
|
348 |
// ignore it, as it's better to carry on without it than to fail to start listening.
|
|
349 |
aListenSocket.SetOpt(KBTRegisterCodService, KSolBtRFCOMM, KCoDDunServiceClass);
|
|
350 |
|
|
351 |
retTemp = aListenSocket.Listen( KListenQueSize );
|
|
352 |
if ( retTemp != KErrNone )
|
|
353 |
{
|
|
354 |
aListenSocket.Close();
|
|
355 |
FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() Listen() complete (%d)"), retTemp));
|
|
356 |
return retTemp;
|
|
357 |
}
|
|
358 |
FTRACE(FPrint(_L("CDunBtListen::ReserveLocalChannel() complete (%d)"), aChannelNum));
|
|
359 |
return KErrNone;
|
|
360 |
}
|
|
361 |
|
|
362 |
// ---------------------------------------------------------------------------
|
|
363 |
// Tries to bind to a fixed port and if that fails with KRfcommPassiveAutoBind.
|
|
364 |
// This is for spec breaking solutions like the OSX Leopard.
|
|
365 |
// ---------------------------------------------------------------------------
|
|
366 |
//
|
|
367 |
TInt CDunBtListen::DoExtendedBind( RSocket& aListenSocket,
|
|
368 |
TRfcommSockAddr& aSockAddr )
|
|
369 |
{
|
|
370 |
FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind()")));
|
|
371 |
if ( !aListenSocket.SubSessionHandle() )
|
|
372 |
{
|
|
373 |
FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind() (closed socket!) complete")));
|
|
374 |
return KErrGeneral;
|
|
375 |
}
|
|
376 |
TRfcommSockAddr fixedAddr = aSockAddr;
|
|
377 |
fixedAddr.SetPort( KDunFixedChannel );
|
|
378 |
TInt retTemp = aListenSocket.Bind( fixedAddr );
|
|
379 |
if ( retTemp == KErrNone )
|
|
380 |
{
|
|
381 |
FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind() complete")));
|
|
382 |
return KErrNone;
|
|
383 |
}
|
|
384 |
TInt retVal = aListenSocket.Bind( aSockAddr );
|
|
385 |
FTRACE(FPrint(_L("CDunBtListen::DoExtendedBind() complete")));
|
|
386 |
return retVal;
|
|
387 |
}
|
|
388 |
|
|
389 |
// ---------------------------------------------------------------------------
|
|
390 |
// From class CActive.
|
|
391 |
// Called when a service is requested via BT.
|
|
392 |
// ---------------------------------------------------------------------------
|
|
393 |
//
|
|
394 |
void CDunBtListen::RunL()
|
|
395 |
{
|
|
396 |
FTRACE(FPrint( _L( "CDunBtListen::RunL()" ) ));
|
|
397 |
iListenState = EBtListenStateIdle;
|
|
398 |
|
|
399 |
StopServiceAdvertisement();
|
|
400 |
|
|
401 |
TInt retTemp = iStatus.Int();
|
|
402 |
if ( retTemp != KErrNone )
|
|
403 |
{
|
|
404 |
FTRACE(FPrint( _L( "CDunBtListen::RunL() (ERROR) complete (%d)" ), retTemp));
|
|
405 |
iServer->NotifyPluginCloseRequest( KDunBtPluginUid, ETrue );
|
|
406 |
return;
|
|
407 |
}
|
|
408 |
// Notify new connection
|
|
409 |
TBool noFreeChans = EFalse;
|
|
410 |
retTemp = iParent->NotifyChannelAllocate( noFreeChans );
|
|
411 |
if ( retTemp != KErrNone )
|
|
412 |
{
|
|
413 |
FTRACE(FPrint( _L( "CDunBtListen::RunL() channel allocation failed! (%d)" ), retTemp));
|
|
414 |
// Other error than no free channels, close plugin now
|
|
415 |
if ( !noFreeChans )
|
|
416 |
{
|
|
417 |
iServer->NotifyPluginCloseRequest( KDunBtPluginUid, ETrue );
|
|
418 |
}
|
|
419 |
return;
|
|
420 |
}
|
|
421 |
|
|
422 |
// Don't restart listening here. Request is issued via
|
|
423 |
// NotifyAdvertisementStart()
|
|
424 |
|
|
425 |
FTRACE(FPrint( _L( "CDunBtListen::RunL() complete" ) ));
|
|
426 |
}
|
|
427 |
|
|
428 |
// ---------------------------------------------------------------------------
|
|
429 |
// From class CActive.
|
|
430 |
// Cancel current activity.
|
|
431 |
// ---------------------------------------------------------------------------
|
|
432 |
//
|
|
433 |
void CDunBtListen::DoCancel()
|
|
434 |
{
|
|
435 |
}
|
|
436 |
|
|
437 |
// ---------------------------------------------------------------------------
|
|
438 |
// From class MDunServAdvMon.
|
|
439 |
// Gets called when advertisement status changes to start.
|
|
440 |
// ---------------------------------------------------------------------------
|
|
441 |
//
|
|
442 |
void CDunBtListen::NotifyAdvertisementStart( TBool aCreation )
|
|
443 |
{
|
|
444 |
FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementStart()" ) ));
|
|
445 |
// Remove the "if" below when fix comes from Apple
|
|
446 |
if ( !aCreation )
|
|
447 |
{
|
|
448 |
TRAP_IGNORE( IssueRequestL() );
|
|
449 |
}
|
|
450 |
FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementStart() complete" ) ));
|
|
451 |
}
|
|
452 |
|
|
453 |
// ---------------------------------------------------------------------------
|
|
454 |
// From class MDunServAdvMon.
|
|
455 |
// Gets called when advertisement status changes to end.
|
|
456 |
// ---------------------------------------------------------------------------
|
|
457 |
//
|
|
458 |
void CDunBtListen::NotifyAdvertisementEnd()
|
|
459 |
{
|
|
460 |
FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementEnd()" ) ));
|
|
461 |
Stop();
|
|
462 |
StopServiceAdvertisement();
|
|
463 |
FTRACE(FPrint( _L( "CDunBtListen::NotifyAdvertisementEnd() complete" ) ));
|
|
464 |
}
|