|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // panincoming.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @note PAN agent incoming connection listener implementation |
|
21 */ |
|
22 |
|
23 #include <bluetooth/logger.h> |
|
24 #include <bt_sock.h> |
|
25 #include <comms-infras/eintsock.h> |
|
26 #include <networking/panuiinterfaces.h> |
|
27 #include "panagtincoming.h" |
|
28 #include "panagtpolicy.h" |
|
29 #include "panagtutils.h" |
|
30 |
|
31 #ifdef __FLOG_ACTIVE |
|
32 _LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT); |
|
33 #endif |
|
34 |
|
35 using namespace PanAgent; |
|
36 |
|
37 CPanIncomingConnectionListener* CPanIncomingConnectionListener::NewL(MIncomingConnectionAcceptor& aAcceptor) |
|
38 /** |
|
39 Create a new instance of the class |
|
40 @param aAcceptor The class to notify when a new connection is received |
|
41 @return A pointer to the new CPanIncomingConnectionListener, or NULL if it could not be created |
|
42 */ |
|
43 { |
|
44 CPanIncomingConnectionListener* self = new(ELeave) CPanIncomingConnectionListener(aAcceptor); |
|
45 CleanupStack::PushL(self); |
|
46 self->ConstructL(); |
|
47 CleanupStack::Pop(self); |
|
48 return(self); |
|
49 } |
|
50 |
|
51 CPanIncomingConnectionListener::CPanIncomingConnectionListener(MIncomingConnectionAcceptor& aAcceptor) : |
|
52 CActive(KPriorityIncomingListenerAo), iAcceptor(aAcceptor) |
|
53 /** |
|
54 Not much to do here |
|
55 */ |
|
56 { } |
|
57 |
|
58 CPanIncomingConnectionListener::~CPanIncomingConnectionListener() |
|
59 /** |
|
60 Close all the sockets |
|
61 */ |
|
62 { |
|
63 Cancel(); |
|
64 |
|
65 iAcceptingSocket.Close(); |
|
66 iListeningSocket.Close(); |
|
67 iListeningSocketIsOpen = EFalse; |
|
68 |
|
69 delete iDelayedOpenHelper; |
|
70 } |
|
71 |
|
72 void CPanIncomingConnectionListener::ConstructL() |
|
73 /** |
|
74 |
|
75 */ |
|
76 { |
|
77 CActiveScheduler::Add(this); |
|
78 |
|
79 iDelayedOpenHelper = CPanIncomingSocketDelayedOpenHelper::NewL(*this); |
|
80 |
|
81 OpenListeningSocketL(); |
|
82 User::LeaveIfError(iAcceptingSocket.Open()); |
|
83 iListeningSocket.Accept(iAcceptingSocket, iStatus); |
|
84 |
|
85 LOG(_L("IncomingConnectionListener: Incoming socket started and ready to accept connections")); |
|
86 |
|
87 SetActive(); |
|
88 } |
|
89 |
|
90 TBool CPanIncomingConnectionListener::IsAcceptingSocketOpen() const |
|
91 /** |
|
92 Is there an accepting socket open? |
|
93 */ |
|
94 { |
|
95 return(IsActive()); // if we're active, then we must have an outstanding Accept() |
|
96 } |
|
97 |
|
98 |
|
99 #ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY |
|
100 /** |
|
101 Notify the main class of the incoming connection |
|
102 */ |
|
103 void CPanIncomingConnectionListener::RunL() |
|
104 { |
|
105 if(iStatus == KErrNone) |
|
106 { |
|
107 LOG(_L("IncomingConnectionListener: ...connection completed successfully, handing connected device off to agent core.")); |
|
108 |
|
109 TRAPD(err, iAcceptor.CreateNewConnectionFromIncomingL(iAcceptingSocket)); // if successful, the socket is transferred away from us here, so a "null" socket is all we have left... |
|
110 if (err != KErrNone) |
|
111 { |
|
112 // Something has failed before the message could be sent |
|
113 // so we execute the remainder of the RunL logic synchronously |
|
114 RestartIncomingConnectionListener(err); |
|
115 } |
|
116 // else { |
|
117 // The rest of the RunL logic is executed asynchonously in |
|
118 // RestartIncomingConnectionListener() once BNEP has responded |
|
119 // to the TCreateChannelController message |
|
120 // } |
|
121 } |
|
122 else // check what went wrong |
|
123 { |
|
124 LOG1(_L("IncomingConnectionListener: ...connection completed with error %d"), iStatus.Int()); |
|
125 iDelayedOpenHelper->SocketOpenFailed(); |
|
126 } |
|
127 } |
|
128 |
|
129 void CPanIncomingConnectionListener::RestartIncomingConnectionListener(TInt aError) |
|
130 { |
|
131 // ...otherwise we still have a "live" socket |
|
132 if(aError) // for some reason the connection could not be completed, so we'll just have to close the socket |
|
133 { // it's possible that the device is already connected |
|
134 LOG(_L("IncomingConnectionListener: ...error - could not hand off socket to agent core, closing socket instead.")); |
|
135 iAcceptingSocket.Close(); |
|
136 } |
|
137 |
|
138 // create a new accepting socket... |
|
139 TInt err = iAcceptingSocket.Open(); |
|
140 if(err) // esp. likely if we've just got KErrNoMemory as the last error |
|
141 { |
|
142 LOG(_L("IncomingConnectionListener: ...could not open new accepting socket. Will try again later.")); |
|
143 iDelayedOpenHelper->SocketOpenFailed(); |
|
144 } |
|
145 else |
|
146 { |
|
147 LOG(_L("IncomingConnectionListener: ...requeing listening socket...")); |
|
148 |
|
149 // ...and repeat the cycle |
|
150 iListeningSocket.Accept(iAcceptingSocket, iStatus); |
|
151 SetActive(); |
|
152 } |
|
153 } |
|
154 |
|
155 #else |
|
156 // !SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY |
|
157 |
|
158 void CPanIncomingConnectionListener::RunL() |
|
159 /** |
|
160 Notify the main class of the incoming connection |
|
161 */ |
|
162 { |
|
163 if(iStatus==KErrNone) |
|
164 { |
|
165 LOG(_L("IncomingConnectionListener: ...connection completed successfully, handing connected device off to agent core.")); |
|
166 |
|
167 TRAPD(err, iAcceptor.CreateNewConnectionFromIncomingL(iAcceptingSocket)); // if successful, the socket is transferred away from us here, so a "null" socket is all we have left... |
|
168 |
|
169 // ...otherwise we still have a "live" socket |
|
170 if(err) // for some reason the connection could not be completed, so we'll just have to close the socket |
|
171 { // it's possible that the device is already connected |
|
172 LOG(_L("IncomingConnectionListener: ...error - could not hand off socket to agent core, closing socket instead.")); |
|
173 iAcceptingSocket.Close(); |
|
174 } |
|
175 |
|
176 // create a new accepting socket... |
|
177 err = iAcceptingSocket.Open(); |
|
178 if(err) // esp. likely if we've just got KErrNoMemory as the last error |
|
179 { |
|
180 LOG(_L("IncomingConnectionListener: ...could not open new accepting socket. Will try again later.")); |
|
181 iDelayedOpenHelper->SocketOpenFailed(); |
|
182 } |
|
183 else |
|
184 { |
|
185 LOG(_L("IncomingConnectionListener: ...requeing listening socket...")); |
|
186 |
|
187 // ...and repeat the cycle |
|
188 iListeningSocket.Accept(iAcceptingSocket, iStatus); |
|
189 SetActive(); |
|
190 } |
|
191 } |
|
192 else // check what went wrong |
|
193 { |
|
194 LOG1(_L("IncomingConnectionListener: ...connection completed with error %d"), iStatus.Int()); |
|
195 iDelayedOpenHelper->SocketOpenFailed(); |
|
196 } |
|
197 } |
|
198 #endif |
|
199 // SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY |
|
200 |
|
201 void CPanIncomingConnectionListener::DoCancel() |
|
202 /** |
|
203 Cancel the outstanding accept |
|
204 */ |
|
205 { |
|
206 iListeningSocket.CancelAccept(); |
|
207 } |
|
208 |
|
209 void CPanIncomingConnectionListener::OpenListeningSocketL() |
|
210 /** |
|
211 Create and initialise the listening socket |
|
212 */ |
|
213 { |
|
214 #if defined(_DEBUG) && defined(SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY) |
|
215 TInt err = iListeningSocket.Open(KBTAddrFamily, KSockSeqPacket, KL2CAP); |
|
216 __ASSERT_DEBUG(err != KErrBadName, PanAgentPanic(EPanAgtMissingBinding)); |
|
217 User::LeaveIfError(err); |
|
218 #else |
|
219 User::LeaveIfError(iListeningSocket.Open(KBTAddrFamily, KSockSeqPacket, KL2CAP)); |
|
220 #endif |
|
221 |
|
222 // listen on the assigned l2cap port for BNEP |
|
223 TBTSockAddr incomingConnectionSettings; |
|
224 incomingConnectionSettings.SetPort(KBnepPsm); |
|
225 |
|
226 // read the required security settings from commdb, and use them to set up the listening socket |
|
227 TBTServiceSecurity incomingSecuritySettings; |
|
228 incomingSecuritySettings.SetAuthentication(KPanIncomingAuthenticationRequired); |
|
229 incomingSecuritySettings.SetAuthorisation(KPanIncomingAuthorisationRequired); |
|
230 incomingSecuritySettings.SetEncryption(KPanIncomingEncryptionRequired); |
|
231 incomingSecuritySettings.SetUid(KBTPanAuthorisationUid); |
|
232 incomingConnectionSettings.SetSecurity(incomingSecuritySettings); |
|
233 |
|
234 User::LeaveIfError(iListeningSocket.Bind(incomingConnectionSettings)); |
|
235 |
|
236 // Set the MTU to the required minimum for BNEP |
|
237 TUint16 bnepMtu = KBnepMtu; |
|
238 TPckg<TUint16> mtuBuf(bnepMtu); |
|
239 User::LeaveIfError(iListeningSocket.SetOpt(KL2CAPInboundMTU, KSolBtL2CAP, mtuBuf)); |
|
240 User::LeaveIfError(iListeningSocket.SetOpt(KL2CAPNegotiatedOutboundMTU, KSolBtL2CAP, mtuBuf)); |
|
241 // Register the CoD service - Networking bit (especially relevant for WinXP) |
|
242 User::LeaveIfError(iListeningSocket.SetOpt(KBTRegisterCodService, KSolBtSAPBase, EMajorServiceNetworking)); |
|
243 |
|
244 User::LeaveIfError(iListeningSocket.Listen(KIncomingSockQueueSize)); |
|
245 iListeningSocketIsOpen = ETrue; |
|
246 } |
|
247 |
|
248 CPanIncomingSocketDelayedOpenHelper* CPanIncomingSocketDelayedOpenHelper::NewL(CPanIncomingConnectionListener& aIncomingConnectionListener) |
|
249 /** |
|
250 |
|
251 */ |
|
252 { |
|
253 CPanIncomingSocketDelayedOpenHelper* self = new(ELeave) CPanIncomingSocketDelayedOpenHelper(aIncomingConnectionListener); |
|
254 CleanupStack::PushL(self); |
|
255 self->ConstructL(); |
|
256 CleanupStack::Pop(self); |
|
257 return self; |
|
258 } |
|
259 |
|
260 CPanIncomingSocketDelayedOpenHelper::CPanIncomingSocketDelayedOpenHelper(CPanIncomingConnectionListener& aIncomingConnectionListener) : |
|
261 CTimer(KPriorityIncomingListenerAo), iCurrentTimerPeriod(KMinSocketReopenAttemptInterval), iIncomingConnectionListener(aIncomingConnectionListener) |
|
262 /** |
|
263 |
|
264 */ |
|
265 { |
|
266 CActiveScheduler::Add(this); |
|
267 } |
|
268 |
|
269 void CPanIncomingSocketDelayedOpenHelper::ConstructL() |
|
270 /** |
|
271 |
|
272 */ |
|
273 { |
|
274 CTimer::ConstructL(); |
|
275 } |
|
276 |
|
277 CPanIncomingSocketDelayedOpenHelper::~CPanIncomingSocketDelayedOpenHelper() |
|
278 /** |
|
279 Nothing to do |
|
280 */ |
|
281 { |
|
282 |
|
283 } |
|
284 |
|
285 void CPanIncomingSocketDelayedOpenHelper::SocketOpenFailed() |
|
286 /** |
|
287 A socket open has failed, so it's now up to us to keep retrying |
|
288 */ |
|
289 { |
|
290 After(iCurrentTimerPeriod); |
|
291 } |
|
292 |
|
293 void CPanIncomingSocketDelayedOpenHelper::RunL() |
|
294 /** |
|
295 Attempt to open the listening socket (if necessary) and the accepting socket |
|
296 */ |
|
297 { |
|
298 // check that the accepting (and therefore by inference the listening) sockets aren't open already |
|
299 __ASSERT_DEBUG(!(iIncomingConnectionListener.IsAcceptingSocketOpen()), PanAgentPanic(EDelayedOpenHelperActiveWhenBothListeningAndAcceptingSocketsAreOpen)); |
|
300 |
|
301 TInt err; |
|
302 if(!(iIncomingConnectionListener.IsListeningSocketOpen())) |
|
303 { |
|
304 TRAP(err, iIncomingConnectionListener.OpenListeningSocketL()); |
|
305 if(err) // failed to open listening socket, back off and try again later |
|
306 { |
|
307 SetNewTimerPeriod(); |
|
308 After(iCurrentTimerPeriod); // will set us active |
|
309 return; |
|
310 } |
|
311 } |
|
312 |
|
313 if(!(iIncomingConnectionListener.IsAcceptingSocketOpen())) |
|
314 { |
|
315 err = iIncomingConnectionListener.iAcceptingSocket.Open(); |
|
316 if(err) // failed to open accepting socket, back off and try again later |
|
317 { |
|
318 SetNewTimerPeriod(); |
|
319 After(iCurrentTimerPeriod); // will set us active |
|
320 return; |
|
321 } |
|
322 else |
|
323 { |
|
324 iIncomingConnectionListener.iListeningSocket.Accept(iIncomingConnectionListener.iAcceptingSocket, iIncomingConnectionListener.iStatus); |
|
325 iIncomingConnectionListener.SetActive(); |
|
326 return; |
|
327 } |
|
328 } |
|
329 } |
|
330 |
|
331 void CPanIncomingSocketDelayedOpenHelper::SetNewTimerPeriod() |
|
332 /** |
|
333 Set the timer period to a new value - doubles each time up to the limit |
|
334 */ |
|
335 { |
|
336 iCurrentTimerPeriod = iCurrentTimerPeriod.Int() * 2; |
|
337 |
|
338 if(iCurrentTimerPeriod > TTimeIntervalMicroSeconds32(KMaxSocketReopenAttemptInterval)) // this happens rarely enough (once per many secs to minutes) to take the hit of constructing a new object each time |
|
339 { |
|
340 iCurrentTimerPeriod = KMaxSocketReopenAttemptInterval; |
|
341 } |
|
342 } |