|
1 // Copyright (c) 2008-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 // upnpflow.cpp |
|
15 // @internalComponent |
|
16 // |
|
17 // |
|
18 |
|
19 //System Includes |
|
20 #include <comms-infras/ss_nodeinterfaces.h> |
|
21 |
|
22 |
|
23 #include <http/thttptable.h> |
|
24 #include <http/framework/cheadercodecplugin.h> |
|
25 #include <httpstringconstants.h> |
|
26 #include <inetprottextutils.h> |
|
27 #include <upnp/tupnptable.h> |
|
28 |
|
29 //Local Includes |
|
30 #include "httpudpflow.h" |
|
31 #include "upnppint.h" |
|
32 #include "upnp_cf_msgs.h" |
|
33 #include "upnpctrlscprstates.h" |
|
34 #include "upnpserverconstants.h" |
|
35 #include "upnplog.h" |
|
36 #include "upnpmemoryutils.h" |
|
37 |
|
38 const TUint KDeftMaxAgeVal = 1800; |
|
39 const TUint KDeftSendCount = 9; |
|
40 const TUint KDeftTimeOutVal = 200000; //200ms,Requirements [7.2.4.2] & [7.2.4.7] of DLNA |
|
41 |
|
42 __FLOG_STMT(_LIT8(KComponent,"Flow");) |
|
43 |
|
44 CHttpUdpFlow* CHttpUdpFlow::NewL ( CSubConnectionFlowFactoryBase& aFactory, |
|
45 CUPnPProtocolIntfBase* aProtocolIntf, |
|
46 const TNodeId& aSubConnId ) |
|
47 { |
|
48 CHttpUdpFlow* self = new ( ELeave )CHttpUdpFlow ( aFactory, aProtocolIntf, aSubConnId ); |
|
49 CleanupStack::PushL ( self ); |
|
50 self->ConstructL (); |
|
51 CleanupStack::Pop (); // self |
|
52 return self; |
|
53 } |
|
54 |
|
55 CHttpUdpFlow::CHttpUdpFlow ( CSubConnectionFlowFactoryBase& aFactory, |
|
56 CUPnPProtocolIntfBase* aProtocolIntf, |
|
57 const TNodeId& aSubConnId ) |
|
58 : CUPnPFlowBase ( aFactory, aProtocolIntf, EHttpUdpFlow, aSubConnId ), |
|
59 iSocketHandler ( *this ), iSocketCreated ( EFalse ),iSendCount ( 0 ), |
|
60 iIsLeaving ( EFalse ),iSendFlag ( EFalse ),iIsComposeCompleted ( EFalse ) |
|
61 { |
|
62 LOG_NODE_CREATE(KESockFlowTag, CHttpUdpFlow); |
|
63 } |
|
64 |
|
65 CHttpUdpFlow::~CHttpUdpFlow () |
|
66 { |
|
67 delete iRequestComposer; |
|
68 delete iResponseParser; |
|
69 delete iResponseComposer; |
|
70 delete iSendTimer; |
|
71 |
|
72 delete iSocketOpener; |
|
73 iSocketHandler.CancelAll (); |
|
74 |
|
75 iSocket.Close (); |
|
76 iSearchTargetArray.Close (); |
|
77 delete iUPnPResponse; |
|
78 //delete iCodec; |
|
79 iSendElements.Close (); |
|
80 iStringPool.Close(); |
|
81 iSubConnectionProvider.Close (); |
|
82 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("Destroyed CHttpUdpFlow"))); |
|
83 LOG_NODE_DESTROY(KESockFlowTag, CHttpUdpFlow); |
|
84 } |
|
85 |
|
86 |
|
87 void CHttpUdpFlow::ConstructL () |
|
88 { |
|
89 iStringPool.OpenL ( TUPnPTable::Table() ); |
|
90 iStringPool.OpenL(THTTPTable::Table()); |
|
91 iCodec = CHeaderCodecPlugin::NewL ( KUPnPCodecName, iStringPool ); |
|
92 iResponseParser = CUpnpResponseParser::NewL ( *this ); |
|
93 iRequestComposer = CUpnpRequestComposer::NewL ( *this ); |
|
94 iResponseComposer = CUpnpResponseComposer::NewL ( *this ); |
|
95 iUPnPResponse = CResponse::NewL ( *iCodec, iStringPool ); |
|
96 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("Created CHttpUdpFlow"))); |
|
97 } |
|
98 |
|
99 void CHttpUdpFlow::ReceivedL ( const TRuntimeCtxId& aSender, const TNodeId& /*aRecipient*/, TSignatureBase& aMessage ) |
|
100 { |
|
101 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL"))); |
|
102 |
|
103 if ( aMessage.IsMessage<TEChild::TDestroy> () ) |
|
104 { |
|
105 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TCFMessage::TDestroy"))); |
|
106 if ( RemoveControlClient ( FindControlClient ( address_cast<TNodeId> ( aSender ) ) ) == 0 ) |
|
107 { |
|
108 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TCFMessage::TDestroy - Deleting current flow"))); |
|
109 DeleteThisFlow (); |
|
110 } |
|
111 } |
|
112 else if ( aMessage.IsMessage<TCFDataClient::TStart> () ) |
|
113 { |
|
114 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TCFMessage::TDataClientStart"))); |
|
115 RClientInterface::OpenPostMessageClose ( NodeId (), address_cast<TNodeCtxId> ( aSender ), TCFDataClient::TStarted ().CRef () ); |
|
116 } |
|
117 else if ( aMessage.IsMessage<TCFDataClient::TStop> () ) |
|
118 { |
|
119 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TUpnpMessage::TUPnPStopSearch"))); |
|
120 |
|
121 SetClientLeaving ( address_cast<TNodeId> ( aSender ) ); // set the control client leaving |
|
122 |
|
123 if ( CheckIfAllClientsLeaving ( ) && iSendElements.Count () != 0 ) |
|
124 { |
|
125 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TUpnpMessage::TUPnPStopSearch -- Marked for Deletion"))); |
|
126 |
|
127 MarkMeForDeletion (); |
|
128 iIsLeaving = ETrue; |
|
129 iLastLeavingClient = address_cast<TNodeCtxId> ( aSender ); |
|
130 } |
|
131 else |
|
132 { |
|
133 PostDataClientStopped ( address_cast<TNodeCtxId> ( aSender ) ); |
|
134 } |
|
135 } |
|
136 else if ( TUpnpMessage::ERealmId == aMessage.MessageId( ).Realm( ) ) |
|
137 { |
|
138 switch ( aMessage.MessageId( ).MessageId( ) ) |
|
139 { |
|
140 case TUpnpMessage::TUPnPSearchRequest::EId: |
|
141 { |
|
142 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TUpnpMessage::TUPnPSearchRequest"))); |
|
143 HandleSearchRequestL ( address_cast<TNodeCtxId> ( aSender ), static_cast < TUpnpMessage::TUPnPSearchRequest& > ( aMessage ) ); |
|
144 CreateSendTimerL(); |
|
145 SendIfOneElement (); |
|
146 } |
|
147 break; |
|
148 |
|
149 case TUpnpMessage::TCancelRequest::EId: |
|
150 { |
|
151 HandleStopSearch ( address_cast<TNodeCtxId> ( aSender ) ); |
|
152 } |
|
153 break; |
|
154 |
|
155 case TUpnpMessage::TUPnPSearchResponse::EId: |
|
156 { |
|
157 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TUpnpMessage::TUPnPSearchResponse"))); |
|
158 HandleSearchResponseL ( static_cast < TUpnpMessage::TUPnPSearchResponse& > ( aMessage ) ); |
|
159 SendIfOneElement (); |
|
160 } |
|
161 break; |
|
162 |
|
163 case TUpnpMessage::TUPnPPublishAliveRequest::EId: |
|
164 { |
|
165 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TUpnpMessage::TUPnPPublishAliveRequest"))); |
|
166 HandlePublishAliveRequestL ( static_cast < TUpnpMessage::TUPnPPublishAliveRequest& > ( aMessage ) ); |
|
167 CreateSendTimerL(); |
|
168 SendIfOneElement (); |
|
169 } |
|
170 break; |
|
171 |
|
172 case TUpnpMessage::TUPnPPublishByeRequest::EId: |
|
173 { |
|
174 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReceivedL - TUpnpMessage::TUPnPPublishByeRequest"))); |
|
175 HandlePublishByeRequestL ( static_cast < TUpnpMessage::TUPnPPublishByeRequest& > ( aMessage ) ); |
|
176 SendIfOneElement (); |
|
177 } |
|
178 break; |
|
179 } |
|
180 } |
|
181 } |
|
182 |
|
183 // From MSocketHandlerObserver |
|
184 void CHttpUdpFlow::OpenComplete ( RInternalSocket& aSocket ) |
|
185 { |
|
186 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::OpenComplete"))); |
|
187 iSocket = aSocket; |
|
188 TInt err = KErrNone; |
|
189 TUint port = KUpnpUdpPort; |
|
190 do |
|
191 { |
|
192 // [REF] DLNA Requirement-7.2.3.4 |
|
193 if ( port == KUpnpMCPort ) |
|
194 ++port; |
|
195 |
|
196 TInetAddr addr ( port++ ); |
|
197 addr.SetAddress ( KInetAddrAny ); |
|
198 |
|
199 err = aSocket.Bind( addr ); |
|
200 |
|
201 }while ( err == KErrInUse && port != KMaxTUint ); |
|
202 |
|
203 if ( err == KErrInUse || port == KMaxTUint ) |
|
204 { |
|
205 return; // bind error is ignored, needs to be handled |
|
206 } |
|
207 |
|
208 iSocketHandler.Attach ( aSocket ); |
|
209 iSocketCreated = ETrue; |
|
210 HandleSendElement (); // This call will happen only once. |
|
211 StartRecv(); //keep Socket in receive mode |
|
212 } |
|
213 |
|
214 void CHttpUdpFlow::SendToComplete ( TInt /*aLength*/ ) |
|
215 { |
|
216 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::SendToComplete"))); |
|
217 |
|
218 if ( !iSendFlag && iSendElements[0]->iType != CSendElement::EMSearchResponse ) |
|
219 { |
|
220 IncrementSendCount(); |
|
221 iSendFlag = ETrue; |
|
222 iSocketHandler.SendTo ( iBackupData, iSendElements[0]->iSockAddr ); |
|
223 } |
|
224 else |
|
225 { |
|
226 iBackupData.Init (); |
|
227 iSendFlag = EFalse; |
|
228 |
|
229 iIsComposeCompleted = ETrue; |
|
230 CSendElement::TSendType currentSendType = RemoveFirstSendElement (); |
|
231 if ( CSendElement::EMSearchResponse == currentSendType ) |
|
232 { |
|
233 //M-Serach Response |
|
234 iResponseComposer->ResponseDataSent (); |
|
235 iResponseComposer->ResetComposer (); |
|
236 } |
|
237 else |
|
238 { |
|
239 //Publish |
|
240 iRequestComposer->RequestDataSent(); |
|
241 iRequestComposer->ResetComposer (); |
|
242 } |
|
243 |
|
244 HandleSendElement (); |
|
245 } |
|
246 } |
|
247 |
|
248 void CHttpUdpFlow::RecvFromComplete ( RMBufChain& aData, const TSockAddr& /*aAddr*/ ) |
|
249 { |
|
250 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::RecvFromComplete"))); |
|
251 |
|
252 RMemoryAllocator allocator(static_cast<CUPnPProtocolIntfBase *>( ProtocolIntf () )->GetMemoryChunkManager()); |
|
253 RMemChunk memChunk; |
|
254 TUPnPMemoryUtils::CreateMemChunk(memChunk, aData, allocator); |
|
255 |
|
256 iResponseParser->ParseResponse ( memChunk, iUPnPResponse ); |
|
257 |
|
258 aData.Free(); |
|
259 } |
|
260 |
|
261 // From MComposerObserver |
|
262 void CHttpUdpFlow::MessageDataReadyL ( RBuf8& aData ) |
|
263 { |
|
264 ASSERT ( iSendElements.Count() > 0 ); |
|
265 |
|
266 if ( !iSendFlag && iSendElements[0]->iType != CSendElement::EMSearchResponse) |
|
267 { |
|
268 iBackupData.CreateL(aData); |
|
269 } |
|
270 RMBufChain sendData; |
|
271 sendData.CreateL(aData); |
|
272 iSocketHandler.SendTo ( sendData, iSendElements[0]->iSockAddr ); |
|
273 } |
|
274 |
|
275 void CHttpUdpFlow::ComposingConcluded () |
|
276 { |
|
277 if ( iIsLeaving && iSendElements.Count () == 0 ) |
|
278 { |
|
279 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ComposingConcluded - Deleting current flow"))); |
|
280 |
|
281 PostDataClientStopped ( iLastLeavingClient ); |
|
282 } |
|
283 } |
|
284 |
|
285 void CHttpUdpFlow::ComposerError ( TInt /*aError*/ ) |
|
286 { |
|
287 RemoveFirstSendElement (); |
|
288 HandleSendElement (); |
|
289 } |
|
290 |
|
291 // From MParserObserver |
|
292 void CHttpUdpFlow::GotHeaders () |
|
293 { |
|
294 if ( ValidateSearchResponse () != KErrNone ) |
|
295 { |
|
296 // Corrupt message. Reset the parser and restart the receive |
|
297 StartRecv (); |
|
298 } |
|
299 // Else we will notify the SCPR from ::ParsingComplete |
|
300 } |
|
301 |
|
302 void CHttpUdpFlow::ParsingComplete ( RMemChunk& /*aExcessData*/ ) |
|
303 { |
|
304 TRAP_IGNORE ( NotifyClientsL () ); |
|
305 StartRecv (); |
|
306 iUPnPResponse->Reset(); |
|
307 } |
|
308 |
|
309 void CHttpUdpFlow::ParserError ( TInt /*aError*/ ) |
|
310 { |
|
311 StartRecv (); |
|
312 } |
|
313 |
|
314 TInt CHttpUdpFlow::GetHeaderValue ( const CResponse& aResponse, TInt aFieldIndex, THTTPHdrVal& aFieldVal, const TStringTable& aTable ) |
|
315 { |
|
316 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::GetHeaderValue"))); |
|
317 CResponse& response = const_cast < CResponse& > ( aResponse ); |
|
318 RResponse res = response.Handle (); |
|
319 RHTTPHeaders headers = res.GetHeaderCollection (); |
|
320 RStringF fieldStr = aResponse.StringPool ().StringF ( aFieldIndex, aTable ); |
|
321 return headers.GetField ( fieldStr, 0, aFieldVal ); |
|
322 } |
|
323 |
|
324 TInt CHttpUdpFlow::GetParamValue ( const CResponse& aResponse, TInt aFieldIndex, TInt aParamIndex, THTTPHdrVal& aParamVal, const TStringTable& aTable ) |
|
325 { |
|
326 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::GetParamValue"))); |
|
327 CResponse& response = const_cast < CResponse& > ( aResponse ); |
|
328 RResponse res = response.Handle (); |
|
329 RHTTPHeaders headers = res.GetHeaderCollection (); |
|
330 RStringF fieldStr = aResponse.StringPool ().StringF ( aFieldIndex, aTable ); |
|
331 RStringF paramStr = aResponse.StringPool ().StringF ( aParamIndex, aTable ); |
|
332 TInt err = KErrNotFound; |
|
333 TInt fieldCount = 0; |
|
334 TRAP ( err, fieldCount = headers.FieldPartsL(fieldStr) ); |
|
335 while (fieldCount>0) |
|
336 { |
|
337 err = headers.GetParam ( fieldStr, paramStr, aParamVal, fieldCount-1 ); |
|
338 if(err == KErrNone ) |
|
339 break; |
|
340 fieldCount--; |
|
341 } |
|
342 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::GetParamValue - Returned with error code %d"), err)); |
|
343 return err; |
|
344 } |
|
345 |
|
346 TInt CHttpUdpFlow::IsHeaderPresent ( const CResponse& aResponse, TInt aFieldIndex, const TStringTable& aTable ) |
|
347 { |
|
348 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::IsHeaderPresent"))); |
|
349 THTTPHdrVal value; |
|
350 return GetHeaderValue ( aResponse, aFieldIndex, value, aTable ); |
|
351 } |
|
352 |
|
353 TInt CHttpUdpFlow::IsValidCacheControlHeader ( const CResponse& aResponse ) |
|
354 { |
|
355 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::IsValidCacheControlHeader"))); |
|
356 THTTPHdrVal value; |
|
357 return GetParamValue ( aResponse, HTTP::ECacheControl, HTTP::EMaxAge, value, THTTPTable::Table() ); |
|
358 } |
|
359 |
|
360 |
|
361 void CHttpUdpFlow::SetHeaderValueL ( RHTTPHeaders& aHdr, TInt aFieldIndex, const TDesC8& aFieldVal, const TStringTable& aTable ) |
|
362 { |
|
363 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::SetHeaderValueL"))); |
|
364 RStringF hdrValStr = iStringPool.OpenFStringL ( aFieldVal ); |
|
365 THTTPHdrVal hdrVal ( hdrValStr ); |
|
366 aHdr.SetFieldL ( iStringPool.StringF ( aFieldIndex, aTable ), hdrVal ); |
|
367 hdrValStr.Close(); |
|
368 } |
|
369 |
|
370 TInt CHttpUdpFlow::ValidateSearchResponse () |
|
371 { |
|
372 // 1. MUST be a HTTP/1.1 version |
|
373 // 2. MUST contain cache-control header with max-age directive |
|
374 // 3. EXT header MUST be present |
|
375 // 4. Location header MUST be present |
|
376 // 5. ST header MUST be present |
|
377 // 6. USN header MUST be present |
|
378 // 7. No body |
|
379 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ValidateSearchResponse"))); |
|
380 |
|
381 if ( !iUPnPResponse->IsHTTP10() && IsValidCacheControlHeader ( *iUPnPResponse ) == KErrNone && |
|
382 IsHeaderPresent ( *iUPnPResponse, UPnP::EExt, TUPnPTable::Table() ) == KErrNone && |
|
383 IsHeaderPresent ( *iUPnPResponse, HTTP::ELocation, THTTPTable::Table() ) == KErrNone && |
|
384 IsHeaderPresent ( *iUPnPResponse, UPnP::EST, TUPnPTable::Table() ) == KErrNone && |
|
385 IsHeaderPresent ( *iUPnPResponse, UPnP::EUSN, TUPnPTable::Table() ) == KErrNone && |
|
386 IsContentLengthZero ( *iUPnPResponse ) ) |
|
387 { |
|
388 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ValidateSearchResponse - Returned with KErrNone"))); |
|
389 return KErrNone; |
|
390 } |
|
391 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ValidateSearchResponse - Returned with KErrCorrupt"))); |
|
392 return KErrCorrupt; |
|
393 } |
|
394 |
|
395 void CHttpUdpFlow::ReadResponseValues ( TInt& aMaxAge, RStringF& aLocation, RStringF& aUsn, RStringF& aST ) |
|
396 { |
|
397 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::ReadResponseValues"))); |
|
398 // We already checked the presence of these headers. We can just read those here |
|
399 // Read maxAge, Location & USN values from the response |
|
400 THTTPHdrVal value(KDeftMaxAgeVal); |
|
401 GetParamValue ( *iUPnPResponse, HTTP::ECacheControl, HTTP::EMaxAge, value, THTTPTable::Table() ); |
|
402 aMaxAge = value.Int (); |
|
403 |
|
404 GetHeaderValue ( *iUPnPResponse, HTTP::ELocation, value, THTTPTable::Table() ); |
|
405 aLocation = value.StrF (); |
|
406 |
|
407 GetHeaderValue ( *iUPnPResponse, UPnP::EUSN, value, TUPnPTable::Table() ); |
|
408 aUsn = value.StrF (); |
|
409 |
|
410 GetHeaderValue ( *iUPnPResponse, UPnP::EST, value, TUPnPTable::Table() ); |
|
411 aST = value.StrF (); |
|
412 } |
|
413 |
|
414 void CHttpUdpFlow::NotifyClientsL () |
|
415 { |
|
416 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::NotifyClients"))); |
|
417 TInt maxAge; |
|
418 RStringF location; |
|
419 RStringF usn; |
|
420 RStringF st; |
|
421 ReadResponseValues ( maxAge, location, usn, st ); |
|
422 for ( TInt i = 0; i < iSearchTargetArray.Count (); ++i ) |
|
423 { |
|
424 const CSearchTarget& target = *(iSearchTargetArray[i]); |
|
425 if ( target.Match ( st.DesC() ) != KErrNotFound |
|
426 && !IsClientLeaving ( target.Originator () ) ) |
|
427 { |
|
428 // We have a match. Post the information to our control client |
|
429 RMemoryAllocator allocator(static_cast<CUPnPProtocolIntfBase *>( ProtocolIntf () )->GetMemoryChunkManager()); |
|
430 |
|
431 RMemChunk locBuf; |
|
432 RMemChunk usnBuf; |
|
433 RMemChunk stBuf; |
|
434 locBuf.CreateL ( location.DesC (), allocator ); |
|
435 TCleanupItem item1 ( &UPnPStateMachine::CUPnPUtils::CleanupMBufChain, &locBuf ); |
|
436 CleanupStack::PushL ( item1 ); |
|
437 usnBuf.CreateL ( usn.DesC (), allocator ); |
|
438 TCleanupItem item2 ( &UPnPStateMachine::CUPnPUtils::CleanupMBufChain, &usnBuf ); |
|
439 CleanupStack::PushL ( item2 ); |
|
440 stBuf.CreateL ( st.DesC (), allocator ); |
|
441 TCleanupItem item3 ( &UPnPStateMachine::CUPnPUtils::CleanupMBufChain, &stBuf ); |
|
442 CleanupStack::PushL ( item3 ); |
|
443 |
|
444 TSsdpInfo info ( maxAge, locBuf, usnBuf, stBuf ); |
|
445 |
|
446 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::NotifyClients - Posting message TUpnpMessage::TUPnPSearchResponse"))); |
|
447 TUpnpMessage::TUPnPSearchResponse msg ( info ); |
|
448 RClientInterface::OpenPostMessageClose ( NodeId (), target.Originator (), msg ); |
|
449 |
|
450 CleanupStack::Pop (); // item1 |
|
451 CleanupStack::Pop (); // item2 |
|
452 CleanupStack::Pop (); // item3 |
|
453 } |
|
454 } |
|
455 } |
|
456 |
|
457 void CHttpUdpFlow::StartRecv () |
|
458 { |
|
459 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::StartRecv"))); |
|
460 // Reset the parser and recv |
|
461 iResponseParser->ResetParser (); |
|
462 iSocketHandler.RecvFrom (); |
|
463 } |
|
464 |
|
465 // ----------------------- |
|
466 // The below functions to be genralised |
|
467 void CHttpUdpFlow::HandleSearchRequestL ( TNodeCtxId aChannelId, TUpnpMessage::TUPnPSearchRequest& aMessage ) |
|
468 { |
|
469 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::HandleSearchRequestL"))); |
|
470 _LIT8 ( KMultiCastAddr, "239.255.255.250:1900" ); |
|
471 _LIT8 ( KManHeaderValue, "ssdp:discover" ); |
|
472 _LIT8 ( KSearchUri, "*" ); |
|
473 CRequest* searchRequest = CRequest::NewL ( *iCodec, iStringPool ); |
|
474 CleanupStack::PushL ( searchRequest ); |
|
475 |
|
476 RStringF method = iStringPool.StringF ( UPnP::EMSearch, TUPnPTable::Table() ); |
|
477 // Set the method and URI |
|
478 RRequest req = searchRequest->Handle (); |
|
479 req.SetMethod ( method ); |
|
480 TUriParser8 parser; |
|
481 parser.Parse ( KSearchUri () ); |
|
482 req.SetURIL ( parser ); |
|
483 |
|
484 RHTTPHeaders hdr = searchRequest->Handle ().GetHeaderCollection (); |
|
485 |
|
486 // Set host header |
|
487 SetHeaderValueL ( hdr, HTTP::EHost, KMultiCastAddr(), THTTPTable::Table() ); |
|
488 |
|
489 // Set MAN header |
|
490 SetHeaderValueL ( hdr, UPnP::EMAN, KManHeaderValue(), TUPnPTable::Table() ); |
|
491 |
|
492 |
|
493 // Set MX header |
|
494 THTTPHdrVal mxVal ( aMessage.iSsdpInfo.iMx ); |
|
495 hdr.SetFieldL ( iStringPool.StringF ( UPnP::EMX, TUPnPTable::Table() ), mxVal ); |
|
496 |
|
497 // Set ST header |
|
498 TPtrC8 stPtr ( aMessage.iSsdpInfo.iSearchTarget.First ()->Ptr (), aMessage.iSsdpInfo.iSearchTarget.First ()->Length () ); |
|
499 SetHeaderValueL ( hdr, UPnP::EST, stPtr, TUPnPTable::Table() ); |
|
500 |
|
501 CSearchTarget* searchTarget = new ( ELeave ) CSearchTarget ( aChannelId ); |
|
502 CleanupStack::PushL ( searchTarget ); |
|
503 searchTarget->AddTargetL ( aMessage.iSsdpInfo.iSearchTarget ); |
|
504 iSearchTargetArray.AppendL ( searchTarget ); |
|
505 CleanupStack::Pop (); // searchTarget |
|
506 TAppProtAddr addr ( KSsdpMulticastAddr, KUpnpMCPort ); |
|
507 |
|
508 CSendElement* sendElement = new ( ELeave ) CSendElement ( CSendElement::EMSearchRequest, *searchRequest, addr ); |
|
509 CleanupStack::PushL ( sendElement ); |
|
510 iSendElements.AppendL ( sendElement ); |
|
511 CleanupStack::Pop (); // sendElement |
|
512 |
|
513 CleanupStack::Pop (); // searchRequest |
|
514 } |
|
515 |
|
516 void CHttpUdpFlow::HandleStopSearch ( TNodeCtxId aChannelId ) |
|
517 { |
|
518 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::HandleStopSearch"))); |
|
519 |
|
520 TInt pos = FindSearchTarget ( aChannelId ); |
|
521 |
|
522 if ( pos != KErrNotFound ) |
|
523 { |
|
524 CSearchTarget *target = iSearchTargetArray[pos]; |
|
525 iSearchTargetArray.Remove ( pos ); |
|
526 delete target; |
|
527 |
|
528 RClientInterface::OpenPostMessageClose ( NodeId (), aChannelId, TUpnpMessage::TCancelled ().CRef () ); |
|
529 } |
|
530 } |
|
531 |
|
532 void CHttpUdpFlow::HandleSearchResponseL ( TUpnpMessage::TUPnPSearchResponse& aMessage ) |
|
533 { |
|
534 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::HandleSearchResponseL"))); |
|
535 CResponse* searchResponse = CResponse::NewL ( *iCodec, iStringPool ); |
|
536 |
|
537 RResponse response = searchResponse->Handle (); |
|
538 RHTTPHeaders hdr = response.GetHeaderCollection (); |
|
539 |
|
540 const TInt KStatusCode = 200; |
|
541 _LIT8 ( KStatusText, "OK" ); |
|
542 // Set status code & text |
|
543 response.SetStatusCode ( KStatusCode ); |
|
544 |
|
545 RStringF statusTextStr = iStringPool.OpenFStringL ( KStatusText() ); |
|
546 CleanupClosePushL ( statusTextStr ); |
|
547 response.SetStatusText ( statusTextStr ); |
|
548 CleanupStack::PopAndDestroy (); // statusTextStr |
|
549 |
|
550 // Set CACHE-CONTROL: max-age="" |
|
551 SetMaxAgeHeaderValueL ( aMessage.iSsdpInfo.iMx, hdr ); |
|
552 |
|
553 // Set Date header |
|
554 TTime time; |
|
555 time.UniversalTime(); |
|
556 THTTPHdrVal timeHdrVal ( time.DateTime() ); |
|
557 hdr.SetFieldL ( iStringPool.StringF(HTTP::EDate, THTTPTable::Table() ), timeHdrVal ); |
|
558 |
|
559 // set EXT header |
|
560 SetHeaderValueL ( hdr, UPnP::EExt, KNullDesC8 (), TUPnPTable::Table() ); |
|
561 |
|
562 // Set location str |
|
563 TPtrC8 locationPtr ( aMessage.iSsdpInfo.iLocation.First ()->Ptr (), aMessage.iSsdpInfo.iLocation.First ()->Length () ); |
|
564 SetHeaderValueL ( hdr, HTTP::ELocation, locationPtr, THTTPTable::Table() ); |
|
565 |
|
566 // Set ST str |
|
567 TPtrC8 stPtr ( aMessage.iSsdpInfo.iSearchTarget.First ()->Ptr (), aMessage.iSsdpInfo.iSearchTarget.First ()->Length () ); |
|
568 SetHeaderValueL ( hdr, UPnP::EST, stPtr, TUPnPTable::Table() ); |
|
569 |
|
570 // Set USN str |
|
571 TPtrC8 usnPtr ( aMessage.iSsdpInfo.iUsn.First ()->Ptr (), aMessage.iSsdpInfo.iUsn.First ()->Length () ); |
|
572 SetHeaderValueL ( hdr, UPnP::EUSN, usnPtr, TUPnPTable::Table() ); |
|
573 |
|
574 //Set Content Length |
|
575 hdr.SetFieldL ( iStringPool.StringF ( HTTP::EContentLength, THTTPTable::Table() ), THTTPHdrVal ( 0 ) ); |
|
576 |
|
577 CSendElement* sendElement = new ( ELeave ) CSendElement ( CSendElement::EMSearchResponse, *searchResponse, aMessage.iSsdpInfo.iAddr ); |
|
578 iSendElements.AppendL ( sendElement ); |
|
579 } |
|
580 |
|
581 |
|
582 |
|
583 void CHttpUdpFlow::HandlePublishAliveRequestL ( TUpnpMessage::TUPnPPublishAliveRequest& aMessage ) |
|
584 { |
|
585 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::HandlePublishAliveRequestL"))); |
|
586 CRequest& request = CreatePublishRequestLC (); |
|
587 |
|
588 RHTTPHeaders hdr = request.Handle ().GetHeaderCollection (); |
|
589 // Set CACHE-CONTROL: max-age="" |
|
590 SetMaxAgeHeaderValueL ( aMessage.iSsdpInfo.iMx, hdr ); |
|
591 |
|
592 // Set location str |
|
593 TPtrC8 locationPtr ( aMessage.iSsdpInfo.iLocation.First ()->Ptr (), aMessage.iSsdpInfo.iLocation.First ()->Length () ); |
|
594 SetHeaderValueL ( hdr, HTTP::ELocation, locationPtr, THTTPTable::Table() ); |
|
595 |
|
596 // Set NT str |
|
597 TPtrC8 ntPtr ( aMessage.iSsdpInfo.iSearchTarget.First ()->Ptr (), aMessage.iSsdpInfo.iSearchTarget.First ()->Length () ); |
|
598 SetHeaderValueL ( hdr, UPnP::ENT, ntPtr, TUPnPTable::Table() ); |
|
599 |
|
600 SetHeaderValueL ( hdr, UPnP::ENTS, KSsdpAlive(), TUPnPTable::Table() ); |
|
601 TPtrC8 usnPtr ( aMessage.iSsdpInfo.iUsn.First ()->Ptr (), aMessage.iSsdpInfo.iUsn.First ()->Length () ); |
|
602 SetHeaderValueL ( hdr, UPnP::EUSN, usnPtr, TUPnPTable::Table() ); |
|
603 |
|
604 //Set Server |
|
605 _LIT8 ( KServerName, "Symbian UPnP/1.0 server" ); |
|
606 RStringF serverStr = iStringPool.OpenFStringL ( KServerName () ); |
|
607 THTTPHdrVal serverHdrVal ( serverStr ); |
|
608 hdr.SetFieldL ( iStringPool.StringF ( HTTP::EServer, THTTPTable::Table () ), serverHdrVal ); |
|
609 serverStr.Close (); |
|
610 |
|
611 //Set Content Length |
|
612 hdr.SetFieldL ( iStringPool.StringF ( HTTP::EContentLength, THTTPTable::Table() ), THTTPHdrVal ( 0 ) ); |
|
613 |
|
614 TAppProtAddr addr ( KSsdpMulticastAddr, KUpnpMCPort ); |
|
615 CSendElement* sendElement = new ( ELeave ) CSendElement ( CSendElement::ENotifyAliveRequest, request, addr ); |
|
616 iSendElements.AppendL ( sendElement ); |
|
617 |
|
618 CleanupStack::Pop (); //request |
|
619 } |
|
620 |
|
621 void CHttpUdpFlow::SetMaxAgeHeaderValueL ( TInt aMaxAgeVal, RHTTPHeaders aHeaders ) |
|
622 { |
|
623 _LIT8 ( KMaxAge, "max-age=" ); |
|
624 |
|
625 RStringF cacheControl = iStringPool.StringF( HTTP::ECacheControl, THTTPTable::Table() ); |
|
626 HBufC8* buf; |
|
627 InetProtTextUtils::ConvertIntToDescriptorL ( aMaxAgeVal, buf ); |
|
628 CleanupStack::PushL ( buf ); |
|
629 RBuf8 rBuf; |
|
630 rBuf.CreateMaxL ( KMaxAge ().Length () + buf->Length () ); |
|
631 rBuf.Copy ( KMaxAge ); |
|
632 rBuf.Append ( buf->Des () ); |
|
633 |
|
634 RStringF cacheControlValStrF = iStringPool.OpenFStringL( rBuf ); |
|
635 CleanupClosePushL ( cacheControlValStrF ); |
|
636 THTTPHdrVal cacheControlVal; |
|
637 cacheControlVal.SetStrF ( cacheControlValStrF ); |
|
638 |
|
639 aHeaders.SetFieldL ( cacheControl, cacheControlVal ); |
|
640 |
|
641 CleanupStack::PopAndDestroy ( &cacheControlValStrF ); |
|
642 CleanupStack::PopAndDestroy ( ); |
|
643 } |
|
644 |
|
645 void CHttpUdpFlow::HandlePublishByeRequestL ( TUpnpMessage::TUPnPPublishByeRequest& aMessage ) |
|
646 { |
|
647 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::HandlePublishByeRequestL"))); |
|
648 CRequest& request = CreatePublishRequestLC (); |
|
649 |
|
650 RHTTPHeaders hdr = request.Handle ().GetHeaderCollection (); |
|
651 |
|
652 // Set NT str |
|
653 TPtrC8 ntPtr ( aMessage.iSsdpInfo.iSearchTarget.First ()->Ptr (), aMessage.iSsdpInfo.iSearchTarget.First ()->Length () ); |
|
654 SetHeaderValueL ( hdr, UPnP::ENT, ntPtr, TUPnPTable::Table() ); |
|
655 |
|
656 SetHeaderValueL ( hdr, UPnP::ENTS, KSsdpBye(), TUPnPTable::Table() ); |
|
657 TPtrC8 usnPtr ( aMessage.iSsdpInfo.iUsn.First ()->Ptr (), aMessage.iSsdpInfo.iUsn.First ()->Length () ); |
|
658 SetHeaderValueL ( hdr, UPnP::EUSN, usnPtr, TUPnPTable::Table() ); |
|
659 |
|
660 //Set Content Length |
|
661 hdr.SetFieldL ( iStringPool.StringF ( HTTP::EContentLength, THTTPTable::Table() ), THTTPHdrVal ( 0 ) ); |
|
662 |
|
663 TAppProtAddr addr ( KSsdpMulticastAddr, KUpnpMCPort ); |
|
664 CSendElement* sendElement = new ( ELeave ) CSendElement ( CSendElement::ENotifyByeRequest, request, addr ); |
|
665 iSendElements.AppendL ( sendElement ); |
|
666 |
|
667 CleanupStack::Pop (); //request |
|
668 } |
|
669 |
|
670 CRequest& CHttpUdpFlow::CreatePublishRequestLC () |
|
671 { |
|
672 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::CreatePublishRequestLC"))); |
|
673 CRequest* publishRequest = CRequest::NewL ( *iCodec, iStringPool ); |
|
674 CleanupStack::PushL ( publishRequest ); |
|
675 |
|
676 RStringF method = iStringPool.StringF ( UPnP::ENotify, TUPnPTable::Table() ); |
|
677 // Set the method and URI |
|
678 RRequest req = publishRequest->Handle (); |
|
679 req.SetMethod ( method ); |
|
680 TUriParser8 parser; |
|
681 parser.Parse ( KSearchUri () ); |
|
682 req.SetURIL ( parser ); |
|
683 |
|
684 RHTTPHeaders hdr = publishRequest->Handle ().GetHeaderCollection (); |
|
685 |
|
686 // Set host header |
|
687 SetHeaderValueL ( hdr, HTTP::EHost, KMultiCastAddr(), THTTPTable::Table() ); |
|
688 |
|
689 return *publishRequest; |
|
690 } |
|
691 |
|
692 // -------------------------------------------- |
|
693 |
|
694 void CHttpUdpFlow::SendIfOneElement () |
|
695 { |
|
696 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::SendIfOneElement"))); |
|
697 if ( iSendElements.Count () == 1 ) |
|
698 { |
|
699 HandleSendElement (); |
|
700 } |
|
701 } |
|
702 |
|
703 void CHttpUdpFlow::HandleSendElement () |
|
704 { |
|
705 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::HandleSendElement"))); |
|
706 |
|
707 if ( !IsSocketCreated () ) |
|
708 { |
|
709 TRAP_IGNORE ( CreateSocketL () ); |
|
710 return; |
|
711 } |
|
712 // Sent the first element |
|
713 if ( iSendElements.Count() > 0 ) |
|
714 { |
|
715 CSendElement* element = iSendElements[0]; |
|
716 |
|
717 if(iSendCount > KDeftSendCount) |
|
718 { |
|
719 if(iSendTimer && iSendTimer->IsActive()) |
|
720 return; |
|
721 } |
|
722 iIsComposeCompleted = EFalse; |
|
723 if ( element->Type() == CSendElement::EMSearchResponse ) |
|
724 { |
|
725 iSendCount = 0; |
|
726 iResponseComposer->ComposeResponse ( static_cast < CResponse* > ( element->Message () ) ); |
|
727 } |
|
728 else |
|
729 { |
|
730 StartSendTimer(); |
|
731 IncrementSendCount(); |
|
732 iRequestComposer->ComposeRequest ( static_cast <CRequest*> ( (element->Message ()) ) ); |
|
733 } |
|
734 } |
|
735 } |
|
736 |
|
737 void CHttpUdpFlow::CreateSocketL () |
|
738 { |
|
739 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::CreateSocketL"))); |
|
740 if ( !iSocketOpener ) |
|
741 { |
|
742 iSocketOpener = CSocketOpener::NewL ( *this ); |
|
743 iSocketOpener->MakeSocket ( KAfInet, KSockDatagram, KProtocolInetUdp ); |
|
744 } |
|
745 } |
|
746 |
|
747 CSendElement::TSendType CHttpUdpFlow::RemoveFirstSendElement () |
|
748 { |
|
749 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::RemoveFirstSendElement"))); |
|
750 ASSERT ( iSendElements.Count () > 0 ); |
|
751 CSendElement* element = iSendElements[0]; |
|
752 iSendElements.Remove (0); |
|
753 CSendElement::TSendType sendType = element->Type (); |
|
754 delete element; |
|
755 return sendType; |
|
756 } |
|
757 |
|
758 TInt CHttpUdpFlow::FindSearchTarget ( TNodeCtxId& aChannelId ) |
|
759 { |
|
760 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::FindSearchTarget"))); |
|
761 for ( TInt i = 0; i < iSearchTargetArray.Count (); ++i ) |
|
762 { |
|
763 if ( iSearchTargetArray[i]->Originator () == aChannelId ) |
|
764 { |
|
765 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::FindSearchTarget - Search target found"))); |
|
766 return i; |
|
767 } |
|
768 } |
|
769 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::FindSearchTarget - Search target not found"))); |
|
770 return KErrNotFound; |
|
771 } |
|
772 |
|
773 |
|
774 TBool CHttpUdpFlow::IsContentLengthZero ( const CResponse& aResponse ) |
|
775 { |
|
776 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::IsContentLengthZero"))); |
|
777 THTTPHdrVal contentLenVal; |
|
778 if ( GetHeaderValue ( aResponse, HTTP::EContentLength, contentLenVal, THTTPTable::Table() ) == KErrNone ) |
|
779 { |
|
780 if ( contentLenVal.Int( ) == 0 ) |
|
781 { |
|
782 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::IsContentLengthZero - Returned ETrue"))); |
|
783 return ETrue; |
|
784 } |
|
785 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::IsContentLengthZero - Returned EFalse"))); |
|
786 return EFalse; |
|
787 } |
|
788 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::IsContentLengthZero - Content-Length header was not found"))); |
|
789 return EFalse; |
|
790 } |
|
791 |
|
792 void CHttpUdpFlow::CreateSendTimerL() |
|
793 { |
|
794 if(!iSendTimer) |
|
795 { |
|
796 iSendTimer = CUPnPTimer::NewL(*this); |
|
797 } |
|
798 } |
|
799 |
|
800 void CHttpUdpFlow::TimeOut() |
|
801 { |
|
802 iSendCount = 0; |
|
803 if(iIsComposeCompleted) |
|
804 { |
|
805 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::TimeOut[HandleSendElement]"))); |
|
806 HandleSendElement(); |
|
807 } |
|
808 return; |
|
809 } |
|
810 |
|
811 void CHttpUdpFlow::IncrementSendCount() |
|
812 { |
|
813 if(IsMSearchOrAliveRequest()) |
|
814 { |
|
815 ++iSendCount; |
|
816 } |
|
817 else |
|
818 { |
|
819 iSendCount = 0; |
|
820 } |
|
821 } |
|
822 |
|
823 void CHttpUdpFlow::StartSendTimer() |
|
824 { |
|
825 if( IsMSearchOrAliveRequest() ) |
|
826 { |
|
827 LOG(ESockLogExternal::Printf(KSubsysHttpUDPFlow, KComponent, _L8("CHttpUdpFlow::StartSendTimer[Timer Started]"))); |
|
828 iSendTimer->StartTimer(KDeftTimeOutVal); |
|
829 } |
|
830 } |
|
831 |
|
832 |
|
833 |
|
834 |
|
835 |
|
836 |
|
837 |