|
1 // Copyright (c) 2005-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 // |
|
15 |
|
16 |
|
17 #include <obex.h> |
|
18 #include <obex/internal/obexinternalheader.h> |
|
19 #include "obexserverstatemachine.h" |
|
20 |
|
21 #if ( defined __FLOG_ACTIVE && defined __LOG_FUNCTIONS__ ) |
|
22 _LIT8(KLogComponent, "OBEX"); |
|
23 #endif |
|
24 |
|
25 /** |
|
26 @file |
|
27 @internalComponent |
|
28 */ |
|
29 |
|
30 /** |
|
31 Constructs the state machine and the state classes |
|
32 |
|
33 @param aOwner Server object that owns the state machine |
|
34 @param aTransport Transport Controller associated with the Server |
|
35 |
|
36 @return Contructed CObexServerStateMachine object |
|
37 */ |
|
38 CObexServerStateMachine* CObexServerStateMachine::NewL(CObexServer& aOwner, CObexTransportControllerBase& aTransport) |
|
39 { |
|
40 CObexServerStateMachine* self = new(ELeave) CObexServerStateMachine(aOwner, aTransport); |
|
41 CleanupStack::PushL(self); |
|
42 self->ConstructL(); |
|
43 CleanupStack::Pop(self); |
|
44 return self; |
|
45 } |
|
46 |
|
47 /** |
|
48 First phase constructor |
|
49 |
|
50 @param aOwner Server object that owns the state machine |
|
51 @param aTransport Transport Controller associated with the Server |
|
52 */ |
|
53 CObexServerStateMachine::CObexServerStateMachine(CObexServer& aOwner, CObexTransportControllerBase& aTransport) |
|
54 : iCurrentState(&iStates[EDisconnected]), iTransport(aTransport), iOwner(aOwner), iServerStarted(EFalse) |
|
55 { |
|
56 // Use placement new here to create the state objects and put them into a pre-defined array |
|
57 // This is done as the number of states is known at compile time and this avoids heap fragmentation |
|
58 new(&iStates[EDisconnected]) TObexServerStateDisconnected(); |
|
59 new(&iStates[ETransportConnected]) TObexServerStateTransportConnected(); |
|
60 new(&iStates[EObexConnecting]) TObexServerStateObexConnecting(); |
|
61 new(&iStates[EWaitForUserPassword]) TObexServerStateWaitForUserPassword(); |
|
62 new(&iStates[EReady]) TObexServerStateReady(); |
|
63 new(&iStates[EPutOpWaitForUser]) TObexServerStatePutOpWaitForUser(); |
|
64 new(&iStates[EPutOpReceiveObject]) TObexServerStatePutOpReceiveObject(); |
|
65 new(&iStates[EGetOpReceiveSpecification]) TObexServerStateGetOpReceiveSpecification(); |
|
66 new(&iStates[EGetOpWaitForUser]) TObexServerStateGetOpWaitForUser(); |
|
67 new(&iStates[EGetOpSendObject]) TObexServerStateGetOpSendObject(); |
|
68 new(&iStates[ESetPathOp]) TObexServerStateSetPathOp(); |
|
69 new(&iStates[EPutOpFinal]) TObexServerStatePutOpFinal(); |
|
70 new(&iStates[EGetOpFinal]) TObexServerStateGetOpFinal(); |
|
71 new(&iStates[EDisconnecting]) TObexServerStateDisconnecting(); |
|
72 } |
|
73 |
|
74 /** |
|
75 Second phase constructor |
|
76 */ |
|
77 void CObexServerStateMachine::ConstructL() |
|
78 { |
|
79 iSpecObject = CObexNullObject::NewL(); |
|
80 iHeader = CObexHeader::NewL(); |
|
81 iCallBack = new(ELeave) CAsyncCallBack(CActive::EPriorityStandard); |
|
82 } |
|
83 |
|
84 /** |
|
85 Destructor |
|
86 */ |
|
87 CObexServerStateMachine::~CObexServerStateMachine() |
|
88 { |
|
89 // No need to delete state array |
|
90 delete iHeader; |
|
91 delete iSpecObject; |
|
92 delete iPutFinalResponseHeaderSet; |
|
93 delete iCallBack; |
|
94 } |
|
95 |
|
96 /** |
|
97 Move machine to a new state |
|
98 Note that this function is synchronous, so any code after calling this function |
|
99 will be executed with the machine in a different state. |
|
100 Usually the action after changing state should be to return from the current function. |
|
101 |
|
102 @param aState Index of new state |
|
103 @return Result of state change |
|
104 */ |
|
105 void CObexServerStateMachine::ChangeState(TObexServerOperationStateEnum aState) |
|
106 { |
|
107 STATE_LOG_2(_L8("Changing from state %S to %S"), &iCurrentState->iName, &iStates[aState].iName); |
|
108 iCurrentState = &(iStates[aState]); |
|
109 iCurrentStateEnum = aState; |
|
110 iCurrentState->Entry(*this); |
|
111 } |
|
112 |
|
113 void CObexServerStateMachine::ControlledTransportDown() |
|
114 { |
|
115 LOG_FUNC |
|
116 |
|
117 iOwner.ControlledTransportDown(); |
|
118 } |
|
119 |
|
120 /** |
|
121 Process a received packet according to the packet's op-code and the current state |
|
122 |
|
123 @param aPacket Packet to process |
|
124 @return Result of any state changes |
|
125 */ |
|
126 void CObexServerStateMachine::OnPacketReceive(CObexPacket& aPacket) |
|
127 { |
|
128 if (!iServerStarted) |
|
129 { |
|
130 __ASSERT_DEBUG(iServerStarted, IrOBEXUtil::Fault(EPacketReceivedWhenServerNotStarted)); |
|
131 return; |
|
132 } |
|
133 |
|
134 iLastReceivedPacket = &aPacket; |
|
135 |
|
136 if(Transport().IsWriteActive()) |
|
137 { |
|
138 FLOG(_L("OnPacketReceive received request whilst writing... dropping connection\r\n")); |
|
139 Notification().ObexDisconnectIndication(KNullDesC8); |
|
140 // change state before issuing the transport down, as it may cause notifications |
|
141 ChangeState(ETransportConnected); |
|
142 ControlledTransportDown(); |
|
143 return; |
|
144 } |
|
145 |
|
146 // Initialise the send packet to ensure that we do not |
|
147 // accidentally send the same packet as last time! |
|
148 iTransport.SendPacket().Init(0); |
|
149 |
|
150 switch (aPacket.Opcode()) |
|
151 { |
|
152 case CObex::EOpConnect: |
|
153 STATE_LOG(_L8("Calling connect")); |
|
154 iCurrentState->Connect(*this, aPacket); |
|
155 break; |
|
156 case CObex::EOpDisconnect: |
|
157 STATE_LOG(_L8("Calling disconnect")); |
|
158 iCurrentState->Disconnect(*this, aPacket); |
|
159 break; |
|
160 case CObex::EOpPut: |
|
161 STATE_LOG(_L8("Calling put")); |
|
162 iCurrentState->Put(*this, aPacket); |
|
163 break; |
|
164 case CObex::EOpGet: |
|
165 STATE_LOG(_L8("Calling get")); |
|
166 iCurrentState->Get(*this, aPacket); |
|
167 break; |
|
168 case CObex::EOpSetPath: |
|
169 STATE_LOG(_L8("Calling SetPath")); |
|
170 iCurrentState->SetPath(*this, aPacket); |
|
171 break; |
|
172 case CObex::EOpAbortNoFBit: |
|
173 // Abort does not check target headers (hence no need to send the packet to the event) |
|
174 STATE_LOG(_L8("Calling abort")); |
|
175 iCurrentState->Abort(*this); |
|
176 break; |
|
177 |
|
178 default: |
|
179 // Unknown packet type |
|
180 STATE_LOG(_L8("Unknown packet type")); |
|
181 iTransport.Send(ERespNotImplemented); |
|
182 break; |
|
183 } |
|
184 } |
|
185 |
|
186 /** |
|
187 Indicates a transport-level connection has been made to the Server |
|
188 */ |
|
189 void CObexServerStateMachine::TransportUp() |
|
190 { |
|
191 // This event could happen while the Server is stopped (as the transport state |
|
192 // can be independent of whether the Server has requested a read) |
|
193 iCurrentState->TransportUp(*this); |
|
194 } |
|
195 |
|
196 /** |
|
197 Indicates the transport-level connection to the Server has disappeared |
|
198 */ |
|
199 void CObexServerStateMachine::TransportDown() |
|
200 { |
|
201 // This event could happen while the Server is stopped (as the transport state |
|
202 // can be independent of whether the Server has requested a read) |
|
203 iCurrentState->Reset(*this); |
|
204 } |
|
205 |
|
206 /** |
|
207 Indicates a Protocol Error has occurred |
|
208 */ |
|
209 void CObexServerStateMachine::Error() |
|
210 { |
|
211 // This event could happen while the Server is stopped (as the transport state |
|
212 // can be independent of whether the Server has requested a read) |
|
213 iCurrentState->Reset(*this); |
|
214 } |
|
215 |
|
216 /** |
|
217 Process an OBEX object received as part of an asynchronous Put/Get indication |
|
218 This object pointer can be NULL to indicate an error condition |
|
219 @see MObexServerNotifyAsync::PutRequestInidication |
|
220 @see MObexServerNotifyAsync::GetRequestInidication |
|
221 @see CObexServer::RequestIndicationCallback |
|
222 |
|
223 @param aObject OBEX object to use (NULL to indication an error condition) |
|
224 @return Result of any state changes |
|
225 */ |
|
226 TInt CObexServerStateMachine::RequestNotificationCompleted(CObexBaseObject* aObject) |
|
227 { |
|
228 __ASSERT_ALWAYS(iCurrentStateEnum == EPutOpWaitForUser || |
|
229 iCurrentStateEnum == EGetOpWaitForUser, IrOBEXUtil::Panic(EInvalidResponseCallback)); |
|
230 if (!iServerStarted) |
|
231 { |
|
232 return KErrIrObexServerStopped; |
|
233 } |
|
234 |
|
235 iCurrentState->RequestNotificationCompleted(*this, aObject); |
|
236 return KErrNone; |
|
237 } |
|
238 |
|
239 /** |
|
240 Process the response received as part of an asynchronous PutComplete/GetComplete/SetPath indication |
|
241 |
|
242 @param aAppResponse Application's response to the indication |
|
243 @return result of state changes |
|
244 */ |
|
245 TInt CObexServerStateMachine::RequestNotificationCompleted(TObexResponse aAppResponse) |
|
246 { |
|
247 __ASSERT_ALWAYS(iCurrentStateEnum == EPutOpWaitForUser || |
|
248 iCurrentStateEnum == EGetOpWaitForUser, IrOBEXUtil::Panic(EInvalidResponseCallback)); |
|
249 __ASSERT_ALWAYS(iCurrentState->ValidResponse(aAppResponse), IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp)); |
|
250 if (!iServerStarted) |
|
251 { |
|
252 return KErrIrObexServerStopped; |
|
253 } |
|
254 |
|
255 iCurrentState->RequestNotificationCompleted(*this, aAppResponse); |
|
256 return KErrNone; |
|
257 } |
|
258 |
|
259 /** |
|
260 Process the response received as part of an asynchronous PutComplete/GetComplete/SetPath indication |
|
261 |
|
262 @param aAppResponse Application's response to the indication |
|
263 @return result of state changes |
|
264 */ |
|
265 TInt CObexServerStateMachine::RequestCompleteNotificationCompleted(TObexResponse aAppResponse) |
|
266 { |
|
267 __ASSERT_ALWAYS(iCurrentStateEnum == ESetPathOp || iCurrentStateEnum == EGetOpFinal || |
|
268 iCurrentStateEnum == EPutOpFinal, IrOBEXUtil::Panic(EInvalidResponseCallback)); |
|
269 __ASSERT_ALWAYS(iCurrentState->ValidResponse(aAppResponse), IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp)); |
|
270 if (!iServerStarted) |
|
271 { |
|
272 return KErrIrObexServerStopped; |
|
273 } |
|
274 |
|
275 iCurrentState->RequestCompleteNotificationCompleted(*this, aAppResponse); |
|
276 return KErrNone; |
|
277 } |
|
278 |
|
279 /** |
|
280 Indicates an OBEX level connection has been established |
|
281 |
|
282 @return Result of any state changes |
|
283 */ |
|
284 void CObexServerStateMachine::ConnectionComplete() |
|
285 { |
|
286 __ASSERT_ALWAYS(iServerStarted, IrOBEXUtil::Fault(EConnectionCompleteWhenServerStopped)); |
|
287 |
|
288 iCurrentState->ConnectionComplete(*this); |
|
289 } |
|
290 |
|
291 /** |
|
292 Indicates Server has been started |
|
293 |
|
294 @param aNotify Notification interface to use |
|
295 */ |
|
296 void CObexServerStateMachine::Start(MObexServerNotifyAsync& aNotify) |
|
297 { |
|
298 iServerStarted = ETrue; |
|
299 iNotification = &aNotify; // state will panic if trying to change interface at an inappropriate point |
|
300 iCurrentState->Start(*this); |
|
301 } |
|
302 |
|
303 /** |
|
304 Indicates Server has been stopped |
|
305 */ |
|
306 void CObexServerStateMachine::Stop() |
|
307 { |
|
308 iCurrentState->Reset(*this); |
|
309 iServerStarted = EFalse; |
|
310 } |
|
311 |
|
312 /** |
|
313 Indication that the Obex server application has chosen to override the |
|
314 handling of the request packet that has been received. |
|
315 |
|
316 @param aResponse The response the server application has indicated that should |
|
317 be sent to the Obex client. The actual sending of the response |
|
318 is delegated to the individual states to handle as appropriate. |
|
319 @return Result of any state changes |
|
320 */ |
|
321 void CObexServerStateMachine::OverrideRequestHandling(TObexResponse aResponse) |
|
322 { |
|
323 iCurrentState->OverrideRequestHandling(*this, aResponse); |
|
324 } |
|
325 |
|
326 /** |
|
327 Indicates that a write of a packet has been completed successfully at the |
|
328 transport level. |
|
329 */ |
|
330 void CObexServerStateMachine::WriteComplete() |
|
331 { |
|
332 LOG_FUNC |
|
333 |
|
334 iCurrentState->WriteComplete(*this); |
|
335 } |
|
336 |
|
337 /** |
|
338 Indicates that a new obex packet is being read. |
|
339 */ |
|
340 void CObexServerStateMachine::ReadActivityDetected() |
|
341 { |
|
342 LOG_FUNC |
|
343 |
|
344 iCurrentState->ReadActivityDetected(*this); |
|
345 } |
|
346 |
|
347 /** |
|
348 @return Last packet processed by the state machine |
|
349 */ |
|
350 CObexPacket& CObexServerStateMachine::LastReceivedPacket() const |
|
351 { |
|
352 __ASSERT_DEBUG(iLastReceivedPacket, IrOBEXUtil::Fault(ENoReceivePacketAvailable)); |
|
353 return *iLastReceivedPacket; |
|
354 } |
|
355 |
|
356 /** |
|
357 This sets pointer of the object received from the application |
|
358 and so can be NULL to indicate an error |
|
359 |
|
360 @see CObexServerStateMachine::NotificationComplete |
|
361 @return Specification Object - used to describe the OBEX object to Get |
|
362 */ |
|
363 CObexBaseObject* CObexServerStateMachine::SpecObject() const |
|
364 { |
|
365 return iSpecObject; |
|
366 } |
|
367 |
|
368 /** |
|
369 This returns pointer to the object received from the application |
|
370 and so can be NULL to indicate an error |
|
371 |
|
372 @see CObexServerStateMachine::NotificationComplete |
|
373 @return Transfer object to exchange with the Client |
|
374 */ |
|
375 CObexBaseObject* CObexServerStateMachine::TransObject() const |
|
376 { |
|
377 return iTransObject; |
|
378 } |
|
379 |
|
380 /** |
|
381 @param aTransObject New transfer object to exchange with the Client |
|
382 */ |
|
383 void CObexServerStateMachine::SetTransObject(CObexBaseObject* aTransObject) |
|
384 { |
|
385 iTransObject = aTransObject; |
|
386 } |
|
387 |
|
388 /** |
|
389 @return Transport Controller associated with the Server |
|
390 */ |
|
391 CObexTransportControllerBase& CObexServerStateMachine::Transport() const |
|
392 { |
|
393 return iTransport; |
|
394 } |
|
395 |
|
396 /** |
|
397 @return Server object associated with the State Machine |
|
398 */ |
|
399 CObexServer& CObexServerStateMachine::Owner() const |
|
400 { |
|
401 return iOwner; |
|
402 } |
|
403 |
|
404 /** |
|
405 @return Notification interface associated with the Server |
|
406 */ |
|
407 MObexServerNotifyAsync& CObexServerStateMachine::Notification() const |
|
408 { |
|
409 __ASSERT_DEBUG(iNotification, IrOBEXUtil::Fault(ENoNotifierAvailable)); |
|
410 return *iNotification; |
|
411 } |
|
412 |
|
413 /** |
|
414 @return Final Header set to send at the end of a Put operation |
|
415 */ |
|
416 CObexHeaderSet* CObexServerStateMachine::PutFinalResponseHeaderSet() |
|
417 { |
|
418 return iPutFinalResponseHeaderSet; |
|
419 } |
|
420 |
|
421 /** |
|
422 @param aHeaderSet Final Header set to send at the end of a Put operation |
|
423 */ |
|
424 void CObexServerStateMachine::SetPutFinalResponseHeaderSet(CObexHeaderSet* aHeaderSet) |
|
425 { |
|
426 delete iPutFinalResponseHeaderSet; |
|
427 iPutFinalResponseHeaderSet = aHeaderSet; |
|
428 } |
|
429 |
|
430 /** |
|
431 @return Internal header object (used for sizing the final response header set) |
|
432 */ |
|
433 CObexHeader* CObexServerStateMachine::GetHeader() |
|
434 { |
|
435 return iHeader; |
|
436 } |
|
437 |
|
438 /** |
|
439 Activate one-shot call-back to run from the Active Scheduler |
|
440 @param aFunction Pointer to the function to call |
|
441 */ |
|
442 void CObexServerStateMachine::CallBack(TInt (*aFunction)(TAny* aPtr)) |
|
443 { |
|
444 iCallBack->Set(TCallBack(aFunction, this)); |
|
445 iCallBack->CallBack(); |
|
446 } |
|
447 |
|
448 /** |
|
449 Cancel one-shot call-back |
|
450 */ |
|
451 void CObexServerStateMachine::CancelCallBack() |
|
452 { |
|
453 iCallBack->Cancel(); |
|
454 } |
|
455 |
|
456 /** |
|
457 @return If one-shot call-back is active |
|
458 */ |
|
459 TBool CObexServerStateMachine::IsCallBackActive() const |
|
460 { |
|
461 return iCallBack->IsActive(); |
|
462 } |
|
463 |
|
464 TObexResponse CObexServerStateMachine::AppResponse() const |
|
465 { |
|
466 return iAppResponse; |
|
467 } |
|
468 |
|
469 void CObexServerStateMachine::SetAppResponse(TObexResponse aAppResponse) |
|
470 { |
|
471 __ASSERT_DEBUG(aAppResponse>0 && aAppResponse<=255, IrOBEXUtil::Panic(EInvalidResponseCodeFromServerApp )); |
|
472 |
|
473 //remove the final bit, sorry about the horrible double casting. |
|
474 aAppResponse = static_cast<TObexResponse>(static_cast<TInt> (aAppResponse) & 0x7F); |
|
475 iAppResponse = aAppResponse; |
|
476 } |
|
477 |