|
1 // Copyright (c) 1997-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 @file |
|
18 @internalComponent |
|
19 */ |
|
20 |
|
21 #include <charconv.h> |
|
22 #include <utf.h> |
|
23 #include <obex.h> |
|
24 #include <obextransportinfo.h> |
|
25 #include <obex/transport/obextransportcontrollerbase.h> |
|
26 #include <obex/internal/obextransportconstants.h> |
|
27 #include <obex/internal/obexinternalheader.h> |
|
28 #include <obex/internal/obexpacket.h> |
|
29 #include "logger.h" |
|
30 #include "obexsetpathdata.h" |
|
31 #include "OBEXUTIL.H" |
|
32 #include "obexheaderutil.h" |
|
33 #include "authentication.h" |
|
34 #include "obexpacketsignaller.h" |
|
35 #include "obexpackettimer.h" |
|
36 #include "obexnotifyhandlerclient.h" |
|
37 #include "obexerrorengine.h" |
|
38 |
|
39 #ifdef __FLOG_ACTIVE |
|
40 _LIT8(KLogComponent, "OBEX"); |
|
41 #endif |
|
42 |
|
43 // Constant used to identify if the last received response code field |
|
44 // has been populated (i.e., if the first response has been received |
|
45 // from the OBEX server). The response code field is only 7 bits (+ the |
|
46 // 'final bit') so the use of this 16 bit number will ensure the value |
|
47 // for KUnpopulatedResponseCode never overlaps with an actual code. |
|
48 const static TUint16 KUnpopulatedResponseCode = 0xffff; |
|
49 |
|
50 // For debug builds check that when an underlying error is set |
|
51 // it has not already been set since the start of the client operation |
|
52 // and check that a last error has been set when the operation completes. |
|
53 #define SET_LAST_ERROR(_error) __ASSERT_DEBUG(!iIsLastErrorSet, IrOBEXUtil::Fault(ELastErrorSetTwice)); iErrorEngine->SetLastError(CObexErrorEngine::_error); iIsLastErrorSet = ETrue |
|
54 #define CHECK_LAST_ERROR_IS_SET __ASSERT_DEBUG(iIsLastErrorSet, IrOBEXUtil::Fault(ELastErrorNotSet)); iIsLastErrorSet = EFalse |
|
55 |
|
56 |
|
57 // Constructor - set initial values |
|
58 CObexClient::CObexClient() : CObex() |
|
59 { |
|
60 iCurrentOperation = EOpIdle; |
|
61 iConnectionID = KConnIDInvalid; |
|
62 iLastReceivedResponseOpcode = static_cast<TObexResponse>(KUnpopulatedResponseCode); |
|
63 } |
|
64 |
|
65 void CObexClient::ConstructL(TObexTransportInfo& aObexTransportInfo) |
|
66 { |
|
67 CObex::ConstructL(aObexTransportInfo); |
|
68 iNotifyHandler = new(ELeave)CObexNotifyHandlerClient(*this); |
|
69 iTransportController->SetOwner(*iNotifyHandler); |
|
70 |
|
71 // iHeaderSet is used to store headers received in Put Response |
|
72 iHeaderSet = CObexHeaderSet::NewL(); |
|
73 iHeader = CObexHeader::NewL(); |
|
74 iPacketProcessSignaller = CObexPacketSignaller::NewL(); |
|
75 iErrorEngine = CObexErrorEngine::NewL(); |
|
76 iPacketTimer = CObexPacketTimer::NewL(*this); |
|
77 } |
|
78 |
|
79 /** Destructor. |
|
80 |
|
81 @publishedAll |
|
82 @released |
|
83 */ |
|
84 EXPORT_C CObexClient::~CObexClient() |
|
85 { |
|
86 LOG_LINE |
|
87 LOG_FUNC |
|
88 |
|
89 Error(KErrCompletion); |
|
90 delete iHeader; |
|
91 delete iHeaderSet; |
|
92 delete iPacketProcessSignaller; |
|
93 delete iNotifyHandler; |
|
94 delete iErrorEngine; |
|
95 delete iPacketTimer; |
|
96 } |
|
97 |
|
98 /** A call back from the the service with the password required for use with generating |
|
99 the challenge response. |
|
100 |
|
101 @param aPassword Password |
|
102 |
|
103 @leave KErrNotReady if this function is not called from a MObexAuthChallengeHandler::GetUserPasswordL callback. |
|
104 |
|
105 @publishedAll |
|
106 @released |
|
107 */ |
|
108 EXPORT_C void CObexClient::UserPasswordL(const TDesC& aPassword) |
|
109 { |
|
110 LOG_LINE |
|
111 LOG_FUNC |
|
112 |
|
113 //now have a password, get a nonce, and get it hashed then reply |
|
114 FLOG(_L("CObexClient::UserPasswordL\n\r")); |
|
115 if (GetConnectState() == EWaitForUserInput) |
|
116 { |
|
117 PrepareChallResponseL( aPassword); |
|
118 |
|
119 TObexInternalHeader hdr; |
|
120 hdr.Set(TObexInternalHeader::EAuthResponse, CONST_CAST(TUint8*, iOutgoingChallResp.Ptr()), iOutgoingChallResp.Size()); |
|
121 FLOG(_L("CObexClient::UserPasswordL EAuth heaqder added\n\r")); |
|
122 if(iTransportController->SendPacket().InsertData(hdr)) |
|
123 { |
|
124 SetConnectState(EWaitForFinalResponse); |
|
125 iTransportController->SendPacket().SetFinal(); |
|
126 SendRequestPacket(); |
|
127 FLOG(_L("CObexClient::UserPasswordL packet sent\n\r")); |
|
128 |
|
129 } |
|
130 else |
|
131 { |
|
132 LEAVEIFERRORL(KErrGeneral); |
|
133 } |
|
134 } |
|
135 else |
|
136 { |
|
137 LEAVEIFERRORL(KErrNotReady); |
|
138 } |
|
139 } |
|
140 |
|
141 /** Allocates and constructs a new OBEX client object. |
|
142 |
|
143 The received protocol information object, aObexProtocolInfoPtr, specifies the transport protocol to use: |
|
144 For the standard transports the following are used, TObexIrProtocolInfo for IrDA, TObexBluetoothProtocolInfo |
|
145 for Bluetooth, TObexUsbProtocolInfo for USB. |
|
146 |
|
147 @param aObexProtocolInfoPtr Protocol information object describing the transport to use |
|
148 @return New OBEX client object |
|
149 |
|
150 @publishedAll |
|
151 @released |
|
152 */ |
|
153 EXPORT_C CObexClient* CObexClient::NewL(TObexProtocolInfo& aObexProtocolInfoPtr) |
|
154 { |
|
155 LOG_LINE |
|
156 LOG_STATIC_FUNC_ENTRY |
|
157 |
|
158 TObexProtocolPolicy defaultProtocolPolicy; // no packet sizing policy specified, so use default |
|
159 TObexTransportInfo* transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, defaultProtocolPolicy); |
|
160 CleanupStack::PushL(transportInfo); |
|
161 CObexClient* client = CObexClient::NewL(*transportInfo); |
|
162 CleanupStack::PopAndDestroy(transportInfo); |
|
163 return client; |
|
164 } |
|
165 |
|
166 /** Allocates and constructs a new OBEX client object with packet sizing information. |
|
167 |
|
168 The received protocol information object, aObexProtocolInfoPtr, specifies the transport protocol to use: |
|
169 For the standard transports the following are used, TObexIrProtocolInfo for IrDA, TObexBluetoothProtocolInfo |
|
170 for Bluetooth, TObexUsbProtocolInfo for USB. |
|
171 |
|
172 The aObexProtocolPolicy parameter specifies the packet sizing policy for this OBEX object. |
|
173 |
|
174 @param aObexProtocolInfoPtr Protocol information object describing the transport to use |
|
175 @param aObexProtocolPolicy Protocol policy object specifying the packet sizes to use |
|
176 @return New OBEX client object |
|
177 |
|
178 @publishedAll |
|
179 @released |
|
180 */ |
|
181 EXPORT_C CObexClient* CObexClient::NewL(TObexProtocolInfo& aObexProtocolInfoPtr, TObexProtocolPolicy& aObexProtocolPolicy) |
|
182 { |
|
183 LOG_LINE |
|
184 LOG_STATIC_FUNC_ENTRY |
|
185 |
|
186 TObexTransportInfo* transportInfo = IrOBEXUtil::CreateTransportInfoL(aObexProtocolInfoPtr, aObexProtocolPolicy); |
|
187 CleanupStack::PushL(transportInfo); |
|
188 CObexClient* client = CObexClient::NewL(*transportInfo); |
|
189 CleanupStack::PopAndDestroy(transportInfo); |
|
190 return client; |
|
191 } |
|
192 |
|
193 /** Allocates and constructs a new OBEX client object with packet sizing information. |
|
194 |
|
195 The received transport information object, aObexTransportInfo, specifies the transport protocol packet sizes to use: |
|
196 For the standard transports the following are used, TObexIrProtocolInfo for IrDA, TObexBluetoothProtocolInfo |
|
197 for Bluetooth, TObexUsbProtocolInfo for USB. |
|
198 |
|
199 @param aObexTransportInfo Transport information object describing the transport and packet sizes to use |
|
200 @return New OBEX client object |
|
201 |
|
202 @capability WriteDeviceData If the TObexIrV3TransportInfo is passed as the argument |
|
203 and the associated name is valid. |
|
204 |
|
205 @publishedAll |
|
206 @released |
|
207 */ |
|
208 EXPORT_C CObexClient* CObexClient::NewL(TObexTransportInfo& aObexTransportInfo) |
|
209 { |
|
210 LOG_LINE |
|
211 LOG_STATIC_FUNC_ENTRY |
|
212 |
|
213 CObexClient* self = new(ELeave) CObexClient(); |
|
214 CleanupStack::PushL(self); |
|
215 self->ConstructL(aObexTransportInfo); |
|
216 CleanupStack::Pop(self); |
|
217 return(self); |
|
218 } |
|
219 |
|
220 /** OBEX CONNECT operation to any available remote machine, specifying an object |
|
221 to pass. |
|
222 |
|
223 @param aObject OBEX object to pass to the remote machine |
|
224 @param aStatus Asynchronous status word. On completion, KErrNone if it was |
|
225 successful, or a system-wide error code |
|
226 |
|
227 @publishedAll |
|
228 @released |
|
229 */ |
|
230 EXPORT_C void CObexClient::Connect(CObexBaseObject& aObject, TRequestStatus& aStatus) |
|
231 { |
|
232 LOG_LINE |
|
233 LOG_FUNC |
|
234 |
|
235 if(!AlreadyActive(aStatus)) |
|
236 { |
|
237 FLOG(_L("CObexClient::Connect no password but some header data\r\n")); |
|
238 EmptyHeaderSet(); |
|
239 iChallenge = EFalse; |
|
240 OBEX_TRAP(Error, ClientCommandL(EOpConnect, static_cast<TAny*>(&aObject), aStatus)); |
|
241 } |
|
242 } |
|
243 |
|
244 /** OBEX CONNECT operation to any available remote machine, specifying an object |
|
245 to pass and a password. |
|
246 |
|
247 @param aObject OBEX object to pass to the remote machine |
|
248 @param aPassword Password to access remote machine |
|
249 @param aStatus Asynchronous status word. On completion, KErrNone if it was |
|
250 successful, or a system-wide error code |
|
251 |
|
252 @publishedAll |
|
253 @released |
|
254 */ |
|
255 EXPORT_C void CObexClient::ConnectL(CObexBaseObject& aObject, const TDesC& aPassword, |
|
256 TRequestStatus& aStatus) |
|
257 { |
|
258 LOG_LINE |
|
259 LOG_FUNC |
|
260 |
|
261 if(!AlreadyActive(aStatus)) |
|
262 { |
|
263 FLOG(_L("CObexClient::Connect with password and some header info\r\n")); |
|
264 EmptyHeaderSet(); |
|
265 delete iChallPassword; |
|
266 iChallPassword = NULL; |
|
267 iChallPassword = HBufC8::NewL(aPassword.Size()); |
|
268 TPtr8 ptr = iChallPassword->Des(); |
|
269 CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr, aPassword); |
|
270 iChallenge = ETrue; |
|
271 OBEX_TRAP(Error, ClientCommandL(EOpConnect, static_cast<TAny*>(&aObject), aStatus)); |
|
272 } |
|
273 } |
|
274 |
|
275 |
|
276 /** OBEX CONNECT operation to any available remote machine, specifying a password. |
|
277 |
|
278 @param aPassword Password to access remote machine |
|
279 @param aStatus On completion, KErrNone if it was successful, or a system-wide |
|
280 error code |
|
281 |
|
282 @publishedAll |
|
283 @released |
|
284 */ |
|
285 EXPORT_C void CObexClient::ConnectL(const TDesC& aPassword, TRequestStatus& aStatus) |
|
286 { |
|
287 LOG_LINE |
|
288 LOG_FUNC |
|
289 |
|
290 if(!AlreadyActive(aStatus)) |
|
291 { |
|
292 FLOG(_L("CObexClient::Connect with password but no header info\r\n")); |
|
293 EmptyHeaderSet(); |
|
294 delete iChallPassword; |
|
295 iChallPassword = NULL; |
|
296 iChallPassword = HBufC8::NewL(aPassword.Length()); |
|
297 TPtr8 ptr = iChallPassword->Des(); |
|
298 CnvUtfConverter::ConvertFromUnicodeToUtf8(ptr, aPassword); |
|
299 iChallenge = ETrue; |
|
300 OBEX_TRAP(Error, ClientCommandL(EOpConnect, NULL, aStatus)); |
|
301 } |
|
302 } |
|
303 |
|
304 /** OBEX CONNECT operation to any available remote machine. |
|
305 |
|
306 @param aStatus Asynchronous status word. On completion, KErrNone if it was |
|
307 successful, or a system-wide error code |
|
308 |
|
309 @publishedAll |
|
310 @released |
|
311 */ |
|
312 EXPORT_C void CObexClient::Connect(TRequestStatus& aStatus) |
|
313 { |
|
314 LOG_LINE |
|
315 LOG_FUNC |
|
316 |
|
317 if(!AlreadyActive(aStatus)) |
|
318 { |
|
319 FLOG(_L("\tno password no header")); |
|
320 EmptyHeaderSet(); |
|
321 iChallenge = EFalse; |
|
322 OBEX_TRAP(Error, ClientCommandL(EOpConnect, NULL, aStatus)); |
|
323 } |
|
324 } |
|
325 |
|
326 /** OBEX DISCONNECT operation. |
|
327 |
|
328 This terminates the OBEX connection, and closes the transport on receiving |
|
329 any response from the server. |
|
330 |
|
331 @param aStatus Asynchronous status word. On completion, KErrNone on normal |
|
332 disconnection, or KErrDisconnected if the server dropped the transport before |
|
333 sending an OBEX response (which is valid behaviour). |
|
334 |
|
335 @publishedAll |
|
336 @released |
|
337 */ |
|
338 EXPORT_C void CObexClient::Disconnect(TRequestStatus& aStatus) |
|
339 { |
|
340 LOG_LINE |
|
341 LOG_FUNC |
|
342 |
|
343 if(!AlreadyActive(aStatus)) |
|
344 { |
|
345 FLOG(_L("CObexClient::Disconnect\r\n")); |
|
346 EmptyHeaderSet(); |
|
347 OBEX_TRAP (Error, ClientCommandL(EOpDisconnect, NULL, aStatus)); |
|
348 } |
|
349 } |
|
350 |
|
351 /** OBEX PUT operation. |
|
352 |
|
353 Any valid header that is also present in aObject’s header mask will be sent |
|
354 to the server, along with the object body specified by the implementation |
|
355 of aObject. |
|
356 |
|
357 @param aObject OBEX object to put |
|
358 @param aStatus Asynchronous status word. On completion, KErrNone if the server |
|
359 accepted the object and received it fully, or the appropriate file error if |
|
360 the data file could not be opened |
|
361 |
|
362 @publishedAll |
|
363 @released |
|
364 */ |
|
365 EXPORT_C void CObexClient::Put(CObexBaseObject& aObject, TRequestStatus& aStatus) |
|
366 { |
|
367 LOG_LINE |
|
368 LOG_FUNC |
|
369 |
|
370 if(!AlreadyActive(aStatus)) |
|
371 { |
|
372 FLOG(_L("\tnot already active")); |
|
373 EmptyHeaderSet(); |
|
374 OBEX_TRAP(Error, ClientCommandL(EOpPut, static_cast<TAny*>(&aObject), aStatus)); |
|
375 } |
|
376 } |
|
377 |
|
378 /** OBEX GET operation. |
|
379 |
|
380 The caller specifies in aObject the headers to send to the server to specify |
|
381 the object to get: normally just a name is expected. If the server can serve |
|
382 the request, the object it returns will be loaded into aObject on completion. |
|
383 All headers returned by the server that are also allowed by the object’s |
|
384 header mask will be loaded into the relevant attributes of aObject. Any object |
|
385 body is stored according to the implementation type of the CObexBaseObject |
|
386 passed. |
|
387 |
|
388 @param aObject OBEX object to get; on completion, the retrieved object |
|
389 @param aStatus Asynchronous status word. On completion, KErrNone if the server |
|
390 passed back an OBEX object, or the appropriate file error if the data file |
|
391 could not be opened |
|
392 |
|
393 @publishedAll |
|
394 @released |
|
395 */ |
|
396 EXPORT_C void CObexClient::Get(CObexBaseObject& aObject, TRequestStatus& aStatus) |
|
397 { |
|
398 LOG_LINE |
|
399 LOG_FUNC |
|
400 |
|
401 if(!AlreadyActive(aStatus)) |
|
402 { |
|
403 FLOG(_L("CObexClient::Get\r\n")); |
|
404 EmptyHeaderSet(); |
|
405 OBEX_TRAP(Error, ClientCommandL(EOpGet, static_cast<TAny*>(&aObject), aStatus)); |
|
406 } |
|
407 } |
|
408 |
|
409 /** OBEX SETPATH operation. |
|
410 |
|
411 This changes the remote device's current path. |
|
412 |
|
413 @param aPathInfo Information to send in the SETPATH command. If you do not |
|
414 which to send a name, make sure CObex::TSetPathInfo::iNamePresent is set to |
|
415 false. |
|
416 @param aStatus Asynchronous status word. On completion, KErrNone if successful, |
|
417 or a system-wide error code |
|
418 |
|
419 @publishedAll |
|
420 @released |
|
421 */ |
|
422 EXPORT_C void CObexClient::SetPath(TSetPathInfo& aPathInfo, TRequestStatus& aStatus) |
|
423 { |
|
424 LOG_LINE |
|
425 LOG_FUNC |
|
426 |
|
427 if(!AlreadyActive(aStatus)) |
|
428 { |
|
429 FLOG(_L("CObexClient::SetPath\r\n")); |
|
430 EmptyHeaderSet(); |
|
431 OBEX_TRAP(Error, ClientCommandL(EOpSetPath, static_cast<TAny*>(&aPathInfo), aStatus)); |
|
432 } |
|
433 } |
|
434 |
|
435 /** OBEX ABORT operation. |
|
436 |
|
437 The function sends the OBEX abort command to the remote machine if a multi-packet |
|
438 operation (i.e. PUT or GET) is in progress. An operation in progress will |
|
439 complete with KErrAbort. |
|
440 |
|
441 @publishedAll |
|
442 @released |
|
443 */ |
|
444 EXPORT_C void CObexClient::Abort() |
|
445 { |
|
446 LOG_LINE |
|
447 LOG_FUNC |
|
448 |
|
449 if(iPendingRequest &&(iCurrentOperation == EOpPut |
|
450 || iCurrentOperation == EOpGet || iCurrentOperation == EOpGetResponse)) |
|
451 { |
|
452 // We have two phase abort, async. abort request, followed by async. response |
|
453 // To achive this without extra members we use extra operations in TOperation |
|
454 // EOpAbortNoFBit for the asynchronous request |
|
455 // EOpAbort for waiting for the response |
|
456 iCurrentOperation = EOpAbortNoFBit; |
|
457 } |
|
458 } |
|
459 |
|
460 /** |
|
461 This function can be called following the successful completion of a Put, |
|
462 and will return a reference to a CObexHeaderSet containing all the headers |
|
463 that were contained in the final Put response packet returned from the |
|
464 peer Obex server. |
|
465 |
|
466 The headers in the header set will be deleted by any subsequent call to |
|
467 CObexClient functions that trigger Obex commands (ie. Connect, Disconnect, |
|
468 Put, Get, SetPath). |
|
469 |
|
470 The reference should not be retained beyond the end of the lifetime of the |
|
471 CObexClient object. |
|
472 |
|
473 @publishedAll |
|
474 @released |
|
475 |
|
476 @return const reference to a Headerset containing headers returned in final |
|
477 Put response packet. |
|
478 */ |
|
479 EXPORT_C const CObexHeaderSet& CObexClient::GetPutFinalResponseHeaders() |
|
480 { |
|
481 LOG_LINE |
|
482 LOG_FUNC |
|
483 |
|
484 return *iHeaderSet; |
|
485 } |
|
486 |
|
487 /** Sets a final packet observer. |
|
488 |
|
489 This replaces any previous observer. The observer will receive a callback |
|
490 when a final packet for a put or get request begins to be sent and |
|
491 another when the send completes. Although the start and finish callbacks |
|
492 are guaranteed to be in order, no guarantees are made about the ordering |
|
493 with respect to the completion of the put or get request. |
|
494 |
|
495 This does not transfer ownership. |
|
496 |
|
497 @publishedAll |
|
498 @released |
|
499 @param aObserver The observer to receive packet process events. This may |
|
500 be NULL. |
|
501 */ |
|
502 EXPORT_C void CObexClient::SetFinalPacketObserver(MObexFinalPacketObserver* aObserver) |
|
503 { |
|
504 iPacketProcessSignaller->SetFinalPacketObserver(aObserver); |
|
505 } |
|
506 |
|
507 /** Get last server response code |
|
508 This method returns the last received OBEX response code. |
|
509 The method must not be called prior to a response notification being received by the |
|
510 client application. If the method is called a panic will be raised. |
|
511 |
|
512 @return The last received OBEX response code. |
|
513 @panic ENoResponseCodeToReturn Panics if the method is called prior to a response being received from the OBEX server. |
|
514 @publishedAll |
|
515 @released |
|
516 */ |
|
517 EXPORT_C TObexResponse CObexClient::LastServerResponseCode() const |
|
518 { |
|
519 LOG_LINE |
|
520 LOG_FUNC |
|
521 // If the last received response code has not been set (i.e., no response has been received) then panic |
|
522 // the client. |
|
523 __ASSERT_ALWAYS(iLastReceivedResponseOpcode != KUnpopulatedResponseCode, IrOBEXUtil::Panic(ENoResponseCodeToReturn)); |
|
524 return iLastReceivedResponseOpcode; |
|
525 } |
|
526 |
|
527 /** Sets the Command Idle Time-out. |
|
528 |
|
529 This function sets the timer period to be observed during the progress of |
|
530 all OBEX commands. If the OBEX server does not respond within the set period |
|
531 the current OBEX command will be completed with an error of KErrIrObexRespTimedOut |
|
532 and the transport will be disconnected. |
|
533 |
|
534 Setting a time-out value of 0, all OBEX commands will be allowed to continue |
|
535 indefinitely. |
|
536 |
|
537 @param aTimeOut The time-out period in Microseconds. |
|
538 @publishedAll |
|
539 @released |
|
540 */ |
|
541 EXPORT_C void CObexClient::SetCommandTimeOut(TTimeIntervalMicroSeconds32 aTimeOut) |
|
542 { |
|
543 LOG_LINE |
|
544 LOG_FUNC |
|
545 iCmdTimeOutDuration = aTimeOut; |
|
546 } |
|
547 |
|
548 TBool CObexClient::AlreadyActive(TRequestStatus& aStatus) |
|
549 //can't do more than one request at atime |
|
550 { |
|
551 if(iPendingRequest) |
|
552 { |
|
553 TRequestStatus* tempStatus = &aStatus; |
|
554 User::RequestComplete(tempStatus,KErrAccessDenied); |
|
555 return ETrue; |
|
556 } |
|
557 return EFalse; |
|
558 } |
|
559 |
|
560 void CObexClient::ResetConnectionID() |
|
561 { |
|
562 iConnectionID = KConnIDInvalid; |
|
563 iConnectionIdSet = EFalse; |
|
564 } |
|
565 |
|
566 void CObexClient::SetConnectionID(TUint32 aConnectionID) |
|
567 { |
|
568 iConnectionID = aConnectionID; |
|
569 iConnectionIdSet = ETrue; |
|
570 } |
|
571 |
|
572 void CObexClient::ClientCommandL(TOperation aOp, TAny* aParam, TRequestStatus& aStatus) |
|
573 { |
|
574 LOG_LINE |
|
575 LOG_FUNC |
|
576 |
|
577 // Note: Function Calls to this method must be enclosed with an if statement utilising |
|
578 // CObexClient::AlreadyActive |
|
579 |
|
580 SetRequest(aStatus, aOp); |
|
581 if(aOp != EOpConnect &&(GetConnectState() != EConnObex || iTransportController == NULL)) |
|
582 { |
|
583 SET_LAST_ERROR(EDisconnected); |
|
584 LEAVEIFERRORL(KErrDisconnected); |
|
585 } |
|
586 |
|
587 switch(aOp) |
|
588 { |
|
589 case EOpConnect: |
|
590 { |
|
591 switch(GetConnectState()) |
|
592 { |
|
593 case EConnIdle: |
|
594 { |
|
595 // Don t start the Packet timer, It will be done once the Transport is up(see :onTransportUp) |
|
596 ResetConnectionID(); //set connection ID to invalid and flag to EFalse |
|
597 iCurrentObject = static_cast<CObexBaseObject*>(aParam); |
|
598 TRAPD(err, iTransportController->ConnectL()); |
|
599 if (err != KErrNone) |
|
600 { |
|
601 SET_LAST_ERROR(ETransportUpFailed); |
|
602 LEAVEIFERRORL(err); |
|
603 } |
|
604 } |
|
605 break; |
|
606 case EConnTransport: |
|
607 iCurrentObject = static_cast<CObexBaseObject*>(aParam); |
|
608 //Transport is already connected just do the connection |
|
609 //Previously TransportUp was called. However the transport is already connected |
|
610 //thus the only required actions are the following. |
|
611 OnTransportUp(); |
|
612 iTransportController->Receive(); |
|
613 break; |
|
614 default: |
|
615 SET_LAST_ERROR(EAlreadyConnected); |
|
616 CompleteRequest(KErrAlreadyExists); |
|
617 } |
|
618 } |
|
619 break; |
|
620 case EOpDisconnect: |
|
621 { |
|
622 iTransportController->SendPacket().Init(TUint8(EOpDisconnect)); |
|
623 iTransportController->SendPacket().SetFinal(); |
|
624 |
|
625 // Insert the ConnectionID if necessary |
|
626 if (iConnectionIdSet) |
|
627 { |
|
628 |
|
629 TObexInternalHeader connectionID; |
|
630 connectionID.Set(TObexInternalHeader::EConnectionID, iConnectionID); |
|
631 |
|
632 if(!iTransportController->SendPacket().InsertData(connectionID)) |
|
633 { |
|
634 LEAVEIFERRORL(KErrOverflow); |
|
635 } |
|
636 } |
|
637 SendRequestPacket(); |
|
638 } |
|
639 break; |
|
640 case EOpPut: |
|
641 case EOpGet: |
|
642 // The Put and Get "request" state machines are identical |
|
643 // and live inside the object streamer. |
|
644 { |
|
645 // |
|
646 // For 'Get' the params are what to 'Get' and where to put it |
|
647 // For 'Put' the params are what to put |
|
648 // Either way we need to send a request based on the params |
|
649 iCurrentObject = static_cast<CObexBaseObject*>(aParam); |
|
650 |
|
651 // Initialise the object ready for sending |
|
652 TInt err = iCurrentObject->InitSend(TObexOpcode(aOp)); |
|
653 if (err != KErrNone) |
|
654 { |
|
655 SET_LAST_ERROR(ECannotInitialiseObject); |
|
656 LEAVEIFERRORL(err); |
|
657 } |
|
658 |
|
659 //if a ConnectionID was added then it's important to add the Connection ID |
|
660 //header here, allow it to be processed by PrepareNextSendPacket |
|
661 if ( iConnectionIdSet ) |
|
662 { |
|
663 FLOG(_L("\tiConnectionIdSet is true")); |
|
664 TRAPD(err, iCurrentObject->SetConnectionIdL(iConnectionID)); |
|
665 if (err != KErrNone) |
|
666 { |
|
667 SET_LAST_ERROR(ECannotSetConnectionId); |
|
668 LEAVEIFERRORL(err); |
|
669 } |
|
670 } |
|
671 |
|
672 // If we can... |
|
673 if(iCurrentObject->PrepareNextSendPacket(iTransportController->SendPacket()) != CObexBaseObject::EError) |
|
674 { |
|
675 iTransportController->SendPacket().AddPacketProcessEvents(EObexFinalPacketStarted | EObexFinalPacketFinished); |
|
676 |
|
677 // ...send the first request packet |
|
678 FLOG(_L("\tsending first request packet...")); |
|
679 SendRequestPacket(); |
|
680 } |
|
681 else |
|
682 { |
|
683 FLOG(_L("\tleaving...")); |
|
684 SET_LAST_ERROR(ECannotPreparePacket); |
|
685 LEAVEIFERRORL(KErrGeneral); |
|
686 } |
|
687 } |
|
688 break; |
|
689 |
|
690 case EOpSetPath: |
|
691 {// Build up a setinfo packet and send it. |
|
692 TSetPathInfo* info = static_cast<TSetPathInfo*>(aParam); |
|
693 |
|
694 iTransportController->SendPacket().Init(TUint8(aOp)); |
|
695 iTransportController->SendPacket().SetFinal(); |
|
696 |
|
697 TObexSetPathData data; |
|
698 data.iFlags = info->iFlags; |
|
699 data.iConstants = info->iConstants; |
|
700 if(!iTransportController->SendPacket().InsertData(data)) |
|
701 { |
|
702 LEAVEIFERRORL(KErrOverflow); |
|
703 } |
|
704 |
|
705 //insert the ConnectionID if necessary |
|
706 if ( iConnectionIdSet ) |
|
707 { |
|
708 |
|
709 TObexInternalHeader connectionID; |
|
710 connectionID.Set(TObexInternalHeader::EConnectionID, iConnectionID); |
|
711 |
|
712 if(!iTransportController->SendPacket().InsertData(connectionID)) |
|
713 { |
|
714 LEAVEIFERRORL(KErrOverflow); |
|
715 } |
|
716 } |
|
717 if(info->iNamePresent) |
|
718 { |
|
719 TObexInternalHeader name; |
|
720 name.Set(TObexInternalHeader::EName, info->iName); |
|
721 if(!iTransportController->SendPacket().InsertData(name)) |
|
722 { |
|
723 LEAVEIFERRORL(KErrOverflow); |
|
724 } |
|
725 } |
|
726 SendRequestPacket(); |
|
727 break; |
|
728 } |
|
729 default: |
|
730 IrOBEXUtil::Fault(EClientCommandOpUnrecognised); |
|
731 } |
|
732 |
|
733 } |
|
734 |
|
735 void CObexClient::OnPacketReceive(CObexPacket& aPacket) |
|
736 { |
|
737 LOG_LINE |
|
738 LOG_FUNC |
|
739 |
|
740 //Cancel the timer |
|
741 if (iPacketTimer->IsActive()) |
|
742 { |
|
743 iPacketTimer->Cancel(); |
|
744 } |
|
745 |
|
746 // Store the response code including the 'final bit'. |
|
747 iLastReceivedResponseOpcode = static_cast<TObexResponse>(aPacket.Opcode() | (aPacket.IsFinal() ? KObexPacketFinalBit : 0)); |
|
748 |
|
749 if(iTransportController->IsWriteActive()) |
|
750 { |
|
751 FLOG(_L("OnPacketReceive received request whilst writing... dropping connection\r\n")); |
|
752 SET_LAST_ERROR(EResponseWhileWriting); |
|
753 CompleteRequest(KErrNone); |
|
754 ControlledTransportDown(); |
|
755 return; |
|
756 } |
|
757 |
|
758 // Initialise the send packet to ensure that we do not |
|
759 // accidentally send the same packet as last time! |
|
760 iTransportController->SendPacket().Init(0); |
|
761 |
|
762 switch(iCurrentOperation) |
|
763 { |
|
764 case EOpConnect: |
|
765 { |
|
766 FLOG(_L("CObexClient::OnPacketReceive Connect OpCode\r\n")); |
|
767 if(ParseConnectPacket(aPacket) == KErrNone) |
|
768 { |
|
769 FLOG(_L("OnPacketReceive Connect Packet parsed \r\n")); |
|
770 |
|
771 //the request is only completed if now connected |
|
772 if(GetConnectState() == EConnObex) |
|
773 { |
|
774 SET_LAST_ERROR(ENoError); |
|
775 CompleteRequest(KErrNone); |
|
776 } |
|
777 else //otherwise still some outstanding issues |
|
778 { |
|
779 iTransportController->SendPacket().Init(EOpConnect); |
|
780 TInt err = PrepareConnectPacket(iTransportController->SendPacket()); |
|
781 if( err == KErrNone ) |
|
782 { |
|
783 FLOG(_L("OnPacketReceive PrepareConnectPacket SUCCESS\r\n")); |
|
784 |
|
785 iTransportController->SendPacket().SetFinal(); |
|
786 SendRequestPacket(); |
|
787 } |
|
788 else if ( GetConnectState() != EWaitForUserInput ) |
|
789 { |
|
790 FLOG(_L("OnPacketReceive PrepareConnectPacket FAILED\r\n")); |
|
791 // Last underlying error already set in PrepareConnectPacket(). |
|
792 Error(err); |
|
793 } |
|
794 } |
|
795 } |
|
796 else |
|
797 { |
|
798 FLOG(_L("OnPacketReceive Connect Packet Parse FAILED\r\n")); |
|
799 // Last underlying error already set in ParseConnectPacket(). |
|
800 Error(KErrAbort); |
|
801 } |
|
802 } |
|
803 break; |
|
804 case EOpDisconnect: |
|
805 { |
|
806 FLOG(_L("CObexClient::OnPacketReceive DisConnect OpCode\r\n")); |
|
807 switch (aPacket.Opcode()) |
|
808 { |
|
809 case ERespSuccess: |
|
810 { |
|
811 SET_LAST_ERROR(ENoError); |
|
812 CompleteRequest(KErrNone); |
|
813 } |
|
814 break; |
|
815 case ERespServiceUnavailable: |
|
816 { |
|
817 SET_LAST_ERROR(EBadConnectionId); |
|
818 CompleteRequest(KErrDisconnected); |
|
819 } |
|
820 break; |
|
821 default: |
|
822 { |
|
823 SET_LAST_ERROR(EErrorResponseFromServer); |
|
824 CompleteRequest(KErrDisconnected); |
|
825 } |
|
826 } |
|
827 |
|
828 ControlledTransportDown(); // Bring down the transport anyway, otherwise we could end up in a situation where we can't |
|
829 } |
|
830 break; |
|
831 case EOpPut: |
|
832 { |
|
833 FLOG(_L("CObexClient::OnPacketReceive Put OpCode\r\n")); |
|
834 if(!aPacket.IsFinal()) |
|
835 {// Multipacket responses not allowed. |
|
836 SET_LAST_ERROR(EMultipacketResponse); |
|
837 Error(KErrCommsOverrun); |
|
838 break; |
|
839 } |
|
840 if(aPacket.Opcode() != ERespContinue |
|
841 && aPacket.Opcode() != ERespSuccess |
|
842 && aPacket.Opcode() != ERespPartialContent) |
|
843 {// Server has returned an OBEX error response. Deal with it... |
|
844 TInt err = IrOBEXUtil::EpocError(aPacket.Opcode()); |
|
845 LOG1(_L8("Put error: %d"), err); |
|
846 SET_LAST_ERROR(EErrorResponseFromServer); |
|
847 CompleteRequest(err); |
|
848 break; |
|
849 } |
|
850 |
|
851 { |
|
852 CObexBaseObject::TProgress progress = |
|
853 iCurrentObject->PrepareNextSendPacket(iTransportController->SendPacket()); |
|
854 iTransportController->SendPacket().AddPacketProcessEvents(EObexFinalPacketStarted | EObexFinalPacketFinished); |
|
855 |
|
856 // Work around for a problem both with some DoCoMo phones and Windows 2000: |
|
857 // Their server sends "Success" when it should actually send "Continue", |
|
858 // so we accept either here. |
|
859 if (((progress == CObexBaseObject::EContinue || progress == CObexBaseObject::ELastPacket) |
|
860 && (aPacket.Opcode () == ERespContinue || aPacket.Opcode () == ERespSuccess))|| |
|
861 (progress == CObexBaseObject::EComplete |
|
862 && (aPacket.Opcode() == ERespContinue ))) |
|
863 {// More stuff to send. |
|
864 SendRequestPacket(); |
|
865 } |
|
866 else if(progress == CObexBaseObject::EComplete |
|
867 && (aPacket.Opcode() == ERespSuccess || aPacket.Opcode() == ERespPartialContent )) |
|
868 {// We've completed okay. |
|
869 // There may be headers to extract from this final put response |
|
870 TObexInternalHeader header; |
|
871 |
|
872 while(aPacket.ExtractData(header)) |
|
873 { |
|
874 FLOG(_L("OnPacketReceive Extracting header from final Put Response")); |
|
875 TInt err=IrOBEXHeaderUtil::ParseHeader(header, *iHeaderSet); |
|
876 if(err != KErrNone) |
|
877 { |
|
878 SET_LAST_ERROR(ECannotExtractFinalPutHeader); |
|
879 Error(err); |
|
880 } |
|
881 } |
|
882 TInt err = IrOBEXUtil::EpocError(aPacket.Opcode()); |
|
883 if (err == KErrNone) |
|
884 { |
|
885 SET_LAST_ERROR(ENoError); |
|
886 } |
|
887 else |
|
888 { |
|
889 SET_LAST_ERROR(EErrorResponseFromServer); |
|
890 } |
|
891 CompleteRequest(err); |
|
892 } |
|
893 else |
|
894 {// We're out of sync with server. Give up. |
|
895 SET_LAST_ERROR(EPutOutOfSync); |
|
896 Error(KErrGeneral); |
|
897 } |
|
898 } |
|
899 break; |
|
900 } |
|
901 case EOpGet: |
|
902 { |
|
903 FLOG(_L("CObexClient::OnPacketReceive Get OpCode\r\n")); |
|
904 if(!aPacket.IsFinal()) |
|
905 { |
|
906 SET_LAST_ERROR(EMultipacketResponse); |
|
907 Error(KErrCommsOverrun); //??? WTF? Comms overrun? |
|
908 break; |
|
909 } |
|
910 |
|
911 // There's only two valid responses to a 'Get' Request... |
|
912 TUint8 respCode = aPacket.Opcode(); |
|
913 if( respCode != ERespContinue && |
|
914 respCode != ERespSuccess ) |
|
915 // ... and if we didn't get one of them... |
|
916 { |
|
917 // ...there's not much else we can do |
|
918 SET_LAST_ERROR(EErrorResponseFromServer); |
|
919 CompleteRequest(IrOBEXUtil::EpocError(respCode)); |
|
920 break; |
|
921 } |
|
922 |
|
923 // Now we know the response was probably valid, see if we need |
|
924 // to send another request packet |
|
925 CObexBaseObject::TProgress progress; |
|
926 progress = iCurrentObject->PrepareNextSendPacket(iTransportController->SendPacket()); |
|
927 |
|
928 if( progress != CObexBaseObject::EComplete && |
|
929 progress != CObexBaseObject::ELastPacket) |
|
930 // We're not done sending the request yet. |
|
931 { |
|
932 // So we'd better not have got a 'Success' from the remote end |
|
933 if( progress == CObexBaseObject::EContinue && |
|
934 respCode == ERespContinue) |
|
935 { |
|
936 iTransportController->SendPacket().AddPacketProcessEvents(EObexFinalPacketStarted | EObexFinalPacketFinished); |
|
937 |
|
938 // Not finished sending the request yet, so send the next packet |
|
939 SendRequestPacket(); |
|
940 } |
|
941 else |
|
942 { |
|
943 // Something went wrong - can't continue. |
|
944 SET_LAST_ERROR(EGetPrematureSuccess); |
|
945 CompleteRequest(KErrGeneral); |
|
946 } |
|
947 |
|
948 // We're done with this packet |
|
949 break; |
|
950 } |
|
951 |
|
952 // Still here? We MUST have got an EComplete from the sending state |
|
953 // machine. That means that the response we're handling RIGHT NOW is |
|
954 // the first packet of the thing we are 'Get'ting. |
|
955 |
|
956 // Must initialise the object to receive the data from the server |
|
957 iCurrentObject->InitReceive(); |
|
958 // Change state so we handle the next response properly |
|
959 iCurrentOperation = EOpGetResponse; |
|
960 } |
|
961 // ** NB ** NO BREAK - DROP THROUGH TO HANDLE THE RESPONSE |
|
962 case EOpGetResponse: |
|
963 // Expecting a possibly multi-packet 'Get' response |
|
964 { |
|
965 FLOG(_L("CObexClient::OnPacketReceive GetResponse OpCode")); |
|
966 |
|
967 if(iCurrentObject->ParseNextReceivePacket(aPacket) == CObexBaseObject::EError) |
|
968 { |
|
969 SET_LAST_ERROR(EGetResponseParseError); |
|
970 Error(KErrGeneral); |
|
971 break; |
|
972 } |
|
973 if(aPacket.Opcode() == ERespContinue) |
|
974 { |
|
975 // Send a blank 'Get' request to solicit the next bit of the response |
|
976 SendRequestPacket(EOpGet); |
|
977 FTRACE(iTransportController->SendPacket().Dump()); |
|
978 } |
|
979 else |
|
980 { |
|
981 // Got all of the response, give it to the user |
|
982 if (aPacket.Opcode() == ERespSuccess) |
|
983 { |
|
984 SET_LAST_ERROR(ENoError); |
|
985 } |
|
986 else |
|
987 { |
|
988 SET_LAST_ERROR(EErrorResponseFromServer); |
|
989 } |
|
990 CompleteRequest(IrOBEXUtil::EpocError(aPacket.Opcode())); |
|
991 } |
|
992 } |
|
993 break; |
|
994 case EOpSetPath: |
|
995 FLOG(_L("CObexClient::OnPacketReceive Set Path OpCode\r\n")); |
|
996 if (aPacket.Opcode() == ERespSuccess) |
|
997 { |
|
998 SET_LAST_ERROR(ENoError); |
|
999 } |
|
1000 else |
|
1001 { |
|
1002 SET_LAST_ERROR(EErrorResponseFromServer); |
|
1003 } |
|
1004 CompleteRequest(IrOBEXUtil::EpocError(aPacket.Opcode())); |
|
1005 break; |
|
1006 case EOpAbortNoFBit: |
|
1007 FLOG(_L("CObexClient::OnPacketReceive Abort NoFBit OpCode\r\n")); |
|
1008 SendRequestPacket(EOpAbort); |
|
1009 iCurrentOperation = EOpAbort; |
|
1010 break; |
|
1011 case EOpAbort: |
|
1012 { |
|
1013 FLOG(_L("CObexClient::OnPacketReceive Abort OpCode\r\n")); |
|
1014 |
|
1015 SET_LAST_ERROR(EAborted); |
|
1016 if(aPacket.IsFinal() && aPacket.Opcode() == ERespSuccess) |
|
1017 {// Just complete the put/get with code aborted |
|
1018 CompleteRequest(KErrAbort); |
|
1019 } |
|
1020 else |
|
1021 {// Report an error while aborting -> causes a disconnect |
|
1022 Error(KErrAbort); |
|
1023 } |
|
1024 } |
|
1025 break; |
|
1026 default: |
|
1027 // FPrint(_L("CObexClient::OnPacketReceive unknown opcode 0x%X!"), |
|
1028 // iCurrentOperation); |
|
1029 break; |
|
1030 } |
|
1031 |
|
1032 // Client has finished with the read packet so queue the next read (if necessary) |
|
1033 if(iConnectState >= EConnTransport) |
|
1034 { |
|
1035 iTransportController->Receive(); |
|
1036 } |
|
1037 |
|
1038 } |
|
1039 |
|
1040 TInt CObexClient::ParseConnectPacket(CObexPacket& aPacket) |
|
1041 { |
|
1042 TInt retValue = KErrNone; |
|
1043 TConnectState nextState = EDropLink; |
|
1044 |
|
1045 if(!iTransportController || !iTransportController->ExtractRemoteConnectInfo(aPacket, iRemoteInfo.iVersion, iRemoteInfo.iFlags)) |
|
1046 { |
|
1047 FLOG(_L("CObexClient::ParseConnectPacket Extract Remote Info FAILED\r\n")); |
|
1048 SET_LAST_ERROR(ECannotExtractConnectInfo); |
|
1049 return KErrGeneral; |
|
1050 } |
|
1051 FLOG(_L("CObexClient::ParseConnectPacket Extract Remote Info Success\r\n")); |
|
1052 |
|
1053 TObexInternalHeader hdr; |
|
1054 |
|
1055 if ( aPacket.Opcode() == ERespSuccess ) |
|
1056 { |
|
1057 FLOG(_L("ParseConnectPacket ERespSuccess Opcode\r\n")); |
|
1058 |
|
1059 //if a simple connect was originally requested |
|
1060 //then a simple ERespSuccess without any headers is enough |
|
1061 if ( GetConnectState() == ESimpleConnRequest ) |
|
1062 nextState = EConnObex; |
|
1063 //if responding to a chall from the server |
|
1064 if (( GetConnectState() == EWaitForFinalResponse)&&(!iChallenge)) |
|
1065 nextState = EConnObex; |
|
1066 while(aPacket.ExtractData(hdr)) |
|
1067 { |
|
1068 switch(hdr.HI()) |
|
1069 { |
|
1070 case TObexInternalHeader::EWho: |
|
1071 { |
|
1072 FLOG(_L("ParseConnectPacket Extracting EWHO header\r\n")); |
|
1073 iRemoteInfo.iWho.Copy(hdr.HVByteSeq(), hdr.HVSize() > iRemoteInfo.iWho.MaxSize() ? iRemoteInfo.iWho.MaxSize() : hdr.HVSize()); |
|
1074 } |
|
1075 break; |
|
1076 case TObexInternalHeader::EConnectionID: |
|
1077 { |
|
1078 FLOG(_L("ParseConnectPacket Extracting EConnectionID header\r\n")); |
|
1079 |
|
1080 TUint32 newConnectionID = ((hdr.HVByteSeq()[0] << 24) + (hdr.HVByteSeq()[1] << 16) + (hdr.HVByteSeq()[2] << 8) + (hdr.HVByteSeq()[3])); |
|
1081 SetConnectionID(newConnectionID); |
|
1082 |
|
1083 if ( GetConnectState() == ESimpleConnRequest ) |
|
1084 { |
|
1085 nextState = EConnObex; |
|
1086 } |
|
1087 } |
|
1088 break; |
|
1089 case TObexInternalHeader::EAuthResponse: |
|
1090 { |
|
1091 if (iChallenge) |
|
1092 { |
|
1093 FLOG(_L("ParseConnectPacket Extracting EAuthResponse header\r\n")); |
|
1094 //extract the response into it's constituent parts |
|
1095 TRAPD(err, ProcessChallResponseL(hdr)); |
|
1096 if ( err == KErrNone ) |
|
1097 { |
|
1098 FLOG(_L("ParseConnectPacket ProcessChallResponse Success\r\n")); |
|
1099 |
|
1100 if ((GetConnectState() == EChallConnRequested) || ( GetConnectState() == EWaitForFinalResponse)) |
|
1101 { |
|
1102 nextState = EConnObex; |
|
1103 } |
|
1104 else |
|
1105 { |
|
1106 SET_LAST_ERROR(EUnexpectedChallengeResponse); |
|
1107 nextState = EDropLink; |
|
1108 retValue = KErrGeneral; |
|
1109 } |
|
1110 } |
|
1111 else |
|
1112 { |
|
1113 FLOG(_L("ParseConnectPacket ProcessChallResponse FAILED\r\n")); |
|
1114 SET_LAST_ERROR(ECannotProcessChallenge); |
|
1115 nextState = EDropLink; |
|
1116 retValue = KErrGeneral; |
|
1117 } |
|
1118 } |
|
1119 else |
|
1120 { |
|
1121 // if no challenge was issued, then receiving a challenge response means the peer is badly |
|
1122 // behaved. For this case we simply ignore the header, anything else would be too drastic. |
|
1123 FLOG(_L("ParseConnectPacket Chall Response received when no Chall issued\r\n")); |
|
1124 } |
|
1125 } |
|
1126 break; |
|
1127 default: |
|
1128 break; |
|
1129 }//end switch |
|
1130 }//end while |
|
1131 } |
|
1132 else if (aPacket.Opcode() == ERespUnauthorized ) |
|
1133 { |
|
1134 FLOG(_L("ParseConnectPacket ERespUnauthorized Opcode\r\n")); |
|
1135 // Only valid header here is AuthChallenge, if it's absent then authentication failed. |
|
1136 TBool challengeAbsent = ETrue; |
|
1137 while(aPacket.ExtractData(hdr)) |
|
1138 { |
|
1139 switch(hdr.HI()) |
|
1140 { |
|
1141 case TObexInternalHeader::EAuthChallenge: |
|
1142 { |
|
1143 FLOG(_L("ParseConnectPacket Extracting EAuthChallenge header\r\n")); |
|
1144 challengeAbsent = EFalse; |
|
1145 TRAPD(err, ProcessChallengeL(hdr)); |
|
1146 if ( !err ) |
|
1147 { |
|
1148 nextState = EConnChallRxed; |
|
1149 retValue = KErrNone; |
|
1150 } |
|
1151 else |
|
1152 { |
|
1153 SET_LAST_ERROR(ECannotProcessChallenge); |
|
1154 retValue = KErrGeneral; |
|
1155 } |
|
1156 #ifdef TEST_CLIENT_CHANGES_ITS_MIND_ABOUT_CHALLENGE |
|
1157 //this will force the client to challenge the server |
|
1158 //even if it didn't challenge initially |
|
1159 //this is not standard behaviour for our client |
|
1160 //but the server must be capable of handling this situation |
|
1161 iChallenge = ETrue; |
|
1162 #endif |
|
1163 } |
|
1164 break; |
|
1165 default: |
|
1166 break; |
|
1167 }//end switch |
|
1168 }//end while |
|
1169 |
|
1170 if (challengeAbsent) |
|
1171 { |
|
1172 SET_LAST_ERROR(EChallengeAbsent); |
|
1173 retValue = KErrGeneral; |
|
1174 } |
|
1175 } |
|
1176 else |
|
1177 { |
|
1178 FLOG(_L("ParseConnectPacket Unknown Opcode Opcode\r\n")); |
|
1179 SET_LAST_ERROR(EBadOpcodeInConnectPacket); |
|
1180 retValue = KErrGeneral; |
|
1181 } |
|
1182 |
|
1183 |
|
1184 SetConnectState(nextState); |
|
1185 return(retValue); |
|
1186 } |
|
1187 |
|
1188 void CObexClient::OnError(TInt aError) |
|
1189 { |
|
1190 LOG1(_L8("CObexClient::OnError(%d)"), aError); |
|
1191 CompleteRequest(aError); |
|
1192 |
|
1193 // Don't reset the Obex link for a normal disconnection, as |
|
1194 // technically there is no real error requiring such drastic |
|
1195 // action. In the case of USB, stalling the IN endpoint will |
|
1196 // cause another round of alternate interface changes which |
|
1197 // appears to confuse either Obex or the USB connector. |
|
1198 |
|
1199 // In other words the error KErrDisconnected occurs as a |
|
1200 // result of the transport coming down, so there's no need to |
|
1201 // signal a transport error in this case. |
|
1202 |
|
1203 // If this is called during construction, iTransportController could be NULL |
|
1204 if(aError!=KErrDisconnected && iTransportController) |
|
1205 { |
|
1206 iTransportController->SignalTransportError(); |
|
1207 } |
|
1208 } |
|
1209 |
|
1210 |
|
1211 |
|
1212 TInt CObexClient::PrepareConnectPacket(CObexPacket& aPacket) |
|
1213 { |
|
1214 TInt retValue = KErrNone; |
|
1215 TConnectState nextState = EDropLink; |
|
1216 |
|
1217 if (!iTransportController->InsertLocalConnectInfo(aPacket, iLocalInfo.iVersion, iLocalInfo.iFlags)) |
|
1218 { |
|
1219 FLOG(_L("CObexClient::PrepareConnectPacket local data insertion FAILED\r\n")); |
|
1220 SET_LAST_ERROR(ECannotInsertConnectInfo); |
|
1221 return(KErrGeneral); |
|
1222 } |
|
1223 FLOG(_L("CObexClient::PrepareConnectPacket local data inserted Succesfully\r\n")); |
|
1224 |
|
1225 //iCurrentObject could be NULL if Connect with no headers was requested |
|
1226 if ( iCurrentObject ) |
|
1227 iCurrentObject->PrepareConnectionHeader(iTransportController->SendPacket()); |
|
1228 |
|
1229 |
|
1230 if (( iChallenge )&&(!retValue)) //if a challenge is to be sent |
|
1231 { |
|
1232 FLOG(_L("PrepareConnectPacket Generating challenge\r\n")); |
|
1233 |
|
1234 retValue = GenerateChallenge(aPacket); |
|
1235 if ( retValue == KErrNone) |
|
1236 { |
|
1237 nextState = EChallConnRequested; |
|
1238 } |
|
1239 else |
|
1240 { |
|
1241 nextState = EDropLink; |
|
1242 } |
|
1243 } |
|
1244 |
|
1245 |
|
1246 //check the state of the connect instruction |
|
1247 if ( GetConnectState() == EConnTransport ) //first time round the loop |
|
1248 { |
|
1249 //it's going to be a simple challenge unless |
|
1250 //it's already been decides it's a EChallConnRequested |
|
1251 if ( nextState == EDropLink ) |
|
1252 nextState = ESimpleConnRequest; |
|
1253 } |
|
1254 else if (GetConnectState() == EConnChallRxed) |
|
1255 { |
|
1256 if (iCallBack ) |
|
1257 { |
|
1258 FLOG(_L("PrepareConnectPacket requesting password from user\r\n")); |
|
1259 |
|
1260 //ask the user for a password |
|
1261 //the callback does happens in the method OnPacketReceive() |
|
1262 nextState = EWaitForUserInput; |
|
1263 retValue = KErrGeneral; //mustn't send yet wait for reply from user |
|
1264 } |
|
1265 else |
|
1266 { |
|
1267 FLOG(_L("PrepareConnectPacket chall rxed but can't ask for password dropping link\r\n")); |
|
1268 SET_LAST_ERROR(EChallengeRejected); |
|
1269 retValue = KErrIrObexConnectChallRejected; |
|
1270 nextState = EDropLink; |
|
1271 } |
|
1272 } //or drop the link |
|
1273 else |
|
1274 { |
|
1275 FLOG(_L("PrepareConnectPacket unknown connect state\r\n")); |
|
1276 SET_LAST_ERROR(EPrepareConnectPacketIncorrectState); |
|
1277 retValue = KErrGeneral; |
|
1278 nextState = EDropLink; |
|
1279 } |
|
1280 SetConnectState(nextState); |
|
1281 |
|
1282 return(retValue); |
|
1283 } |
|
1284 |
|
1285 void CObexClient::OnTransportUp() |
|
1286 { |
|
1287 FLOG(_L("CObexClient::OnTransportUp\r\n")); |
|
1288 ResetConnectionID(); |
|
1289 |
|
1290 iTransportController->SendPacket().Init(EOpConnect); |
|
1291 if (PrepareConnectPacket(iTransportController->SendPacket()) == KErrNone) |
|
1292 { |
|
1293 FLOG(_L("OnTransportUp PrepareConnectPacket Succesfull\r\n")); |
|
1294 |
|
1295 iTransportController->SendPacket().SetFinal(); |
|
1296 FTRACE(iTransportController->SendPacket().Dump()); |
|
1297 SendRequestPacket(); |
|
1298 } |
|
1299 } |
|
1300 |
|
1301 void CObexClient::OnTransportDown() |
|
1302 { |
|
1303 LOG_LINE |
|
1304 LOG_FUNC |
|
1305 |
|
1306 // Cancel the timer |
|
1307 if (iPacketTimer->IsActive()) |
|
1308 { |
|
1309 iPacketTimer->Cancel(); |
|
1310 } |
|
1311 // If there's an outstanding request, an error has occured |
|
1312 // But don't do anything if an error has already been set (due to e.g. packet timer timeout) |
|
1313 if(iPendingRequest && !iIsLastErrorSet) |
|
1314 { |
|
1315 SET_LAST_ERROR(EOpOutstandingOnTransportDown); |
|
1316 Error(KErrIrObexClientPutPeerAborted); //extended error for IrObex,("Other IR device aborted the transfer") |
|
1317 } |
|
1318 } |
|
1319 |
|
1320 /** Signals an event has ocurred. |
|
1321 |
|
1322 @released |
|
1323 @internalComponent |
|
1324 @param aEvent The event that has ocurred (TObexPacketProcessEvent) |
|
1325 */ |
|
1326 void CObexClient::SignalPacketProcessEvent(TInt aEvent) |
|
1327 { |
|
1328 if(aEvent & KObexPacketSignallerInterestingClientEvents) |
|
1329 { |
|
1330 // Currently all notifications are related to writes, so only need to |
|
1331 // clear events from the SendPacket. |
|
1332 iTransportController->SendPacket().RemovePacketProcessEvents(aEvent); |
|
1333 |
|
1334 iPacketProcessSignaller->Signal(static_cast<TObexPacketProcessEvent>(aEvent)); |
|
1335 } |
|
1336 } |
|
1337 |
|
1338 void CObexClient::SetRequest(TRequestStatus& aStatus, TOperation aOperation) |
|
1339 { |
|
1340 aStatus = KRequestPending; |
|
1341 iPendingRequest = &aStatus; |
|
1342 iCurrentOperation = aOperation; |
|
1343 } |
|
1344 |
|
1345 void CObexClient::CompleteRequest(const TInt aCompletion) |
|
1346 { |
|
1347 LOG_LINE |
|
1348 LOG_FUNC |
|
1349 |
|
1350 if(iPendingRequest) |
|
1351 { |
|
1352 // Some errors, particularly IR, only come up through OnError(). |
|
1353 // Thus the setting of underlying error happens here. |
|
1354 switch (aCompletion) |
|
1355 { |
|
1356 case KErrIrObexRespTimedOut: |
|
1357 { |
|
1358 SET_LAST_ERROR(EResponseTimeout); |
|
1359 } |
|
1360 break; |
|
1361 case KErrDisconnected: |
|
1362 { |
|
1363 // There are at least two ways of getting here. |
|
1364 // The first is disruption to the transport (e.g. IrDA beam blocked) |
|
1365 // and the second is attempting an operation other than connect when |
|
1366 // there is no connection (see CObexClient::ClientCommandL()). |
|
1367 // We don't want to set the last error twice in the second case, |
|
1368 // so check that the last error is not set before setting it here. |
|
1369 if (!iIsLastErrorSet) |
|
1370 { |
|
1371 SET_LAST_ERROR(EOpOutstandingOnTransportDown); |
|
1372 } |
|
1373 } |
|
1374 break; |
|
1375 case KErrCompletion: |
|
1376 { |
|
1377 // This is an error from the destructor. |
|
1378 // Operation is complete, successfully or otherwise. |
|
1379 // Since the operation is still outstanding and the interruption |
|
1380 // was initiated locally, the operation is effectively aborted. |
|
1381 SET_LAST_ERROR(EAborted); |
|
1382 } |
|
1383 break; |
|
1384 case KErrNotReady: |
|
1385 { |
|
1386 // This error occurs when the BT link times out. |
|
1387 SET_LAST_ERROR(EOpOutstandingOnTransportDown); |
|
1388 } |
|
1389 break; |
|
1390 case KErrCouldNotConnect: |
|
1391 { |
|
1392 // BT could not connect. |
|
1393 SET_LAST_ERROR(EOpOutstandingOnTransportDown); |
|
1394 } |
|
1395 break; |
|
1396 case KErrGeneral: |
|
1397 { |
|
1398 // Since Obex also uses this error elsewhere, only set a last error |
|
1399 // if none has been set previously. |
|
1400 if (!iIsLastErrorSet) |
|
1401 { |
|
1402 SET_LAST_ERROR(EOpOutstandingOnTransportDown); |
|
1403 } |
|
1404 } |
|
1405 break; |
|
1406 default: |
|
1407 { |
|
1408 // If an error has not yet been set, then set the last error as appropriate. |
|
1409 if (!iIsLastErrorSet) |
|
1410 { |
|
1411 // For all other errors. |
|
1412 SET_LAST_ERROR(EOpOutstandingOnTransportDown); |
|
1413 } |
|
1414 } |
|
1415 } |
|
1416 CHECK_LAST_ERROR_IS_SET; |
|
1417 User::RequestComplete(iPendingRequest, aCompletion);// Sets iPendingRequest = NULL |
|
1418 } |
|
1419 iPendingRequest=NULL; |
|
1420 iCurrentOperation = EOpIdle; |
|
1421 |
|
1422 if (iPacketTimer) |
|
1423 { |
|
1424 iPacketTimer->Cancel(); |
|
1425 } |
|
1426 } |
|
1427 |
|
1428 void CObexClient::EmptyHeaderSet() |
|
1429 { |
|
1430 LOG_LINE |
|
1431 LOG_FUNC |
|
1432 |
|
1433 iHeaderSet->First(); |
|
1434 while(iHeaderSet->This(iHeader) == KErrNone) |
|
1435 { |
|
1436 iHeaderSet->DeleteCurrentHeader(); |
|
1437 } |
|
1438 } |
|
1439 |
|
1440 void CObexClient::TimeOutCompletion() |
|
1441 { |
|
1442 LOG_LINE |
|
1443 LOG_FUNC |
|
1444 |
|
1445 CompleteRequest(KErrIrObexRespTimedOut); |
|
1446 // Disconnect transport to prevent the client entering an invalid state |
|
1447 ForcedTransportDown(); |
|
1448 } |
|
1449 |
|
1450 void CObexClient::SendRequestPacket() |
|
1451 { |
|
1452 //Send the request. |
|
1453 iTransportController->Send(); |
|
1454 |
|
1455 //Set the Timer. |
|
1456 iPacketTimer->SetTimer(iCmdTimeOutDuration); |
|
1457 } |
|
1458 |
|
1459 void CObexClient::SendRequestPacket(TObexOpcode aObexOpcode) |
|
1460 { |
|
1461 //Send the request. |
|
1462 iTransportController->Send(aObexOpcode); |
|
1463 |
|
1464 //Set the Timer. |
|
1465 iPacketTimer->SetTimer(iCmdTimeOutDuration); |
|
1466 } |
|
1467 |
|
1468 /** |
|
1469 Provides additional interfaces for CObexClient. |
|
1470 |
|
1471 @param aUid The UID of the interface that is required. |
|
1472 @return A pointer to an instance implementing the interface represented by aUid. |
|
1473 */ |
|
1474 EXPORT_C TAny* CObexClient::ExtensionInterface(TUid aUid) |
|
1475 { |
|
1476 TAny* ret = NULL; |
|
1477 |
|
1478 if (aUid == KObexClientErrorResolverInterface) |
|
1479 { |
|
1480 ret = static_cast<MObexClientErrorResolver*>(iErrorEngine); |
|
1481 } |
|
1482 |
|
1483 return ret; |
|
1484 } |
|
1485 |
|
1486 |