networkprotocols/iphook/inhook6/src/flow.cpp
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // flow.cpp - IPv6/IPv4 flow information
       
    15 //
       
    16 
       
    17 #include <es_mbuf.h>
       
    18 #include "flow.h"
       
    19 //
       
    20 //	COptionValue
       
    21 //	************
       
    22 //	(Only used internally in flow.cpp, DO NOT EXPORT! It has somewhat
       
    23 //	"delicate" constructor requiring the extra allocation been done,
       
    24 //	not checked... -- sma
       
    25 //
       
    26 class COptionValue : public CBase
       
    27 	{
       
    28 public:
       
    29 	COptionValue(TInt aLevel, TInt aName, const TDesC8 &aOption) : iLevel(aLevel), iName(aName), iLength(aOption.Length())
       
    30 		{
       
    31 		TPtr8((TUint8 *)this + sizeof(COptionValue), iLength).Copy(aOption);
       
    32 		}
       
    33 	inline TPtrC8 Value() { return TPtr8((TUint8 *)this + sizeof(COptionValue), iLength, iLength); }
       
    34 	COptionValue *iNext;		// Next value or NULL
       
    35 	const TUint iLevel;			// Option level
       
    36 	const TUint iName;			// Option name
       
    37 	const TInt iLength;			// Option value length
       
    38 	//
       
    39 	// This is followed by the actual octets of the
       
    40 	// option value. COptionValue class *CANNOT* be
       
    41 	// subclassed!!!!
       
    42 	};
       
    43 
       
    44 // ************
       
    45 // RFlowContext
       
    46 // ************
       
    47 
       
    48 
       
    49 EXPORT_C TInt RFlowContext::Open(MFlowManager *aManager, TUint aProtocol)
       
    50 	/**
       
    51 	* Creates a new empty and unconnected flow context and initialises the handle 
       
    52 	* to point this context.
       
    53 	*
       
    54 	* The handle, which is used to create the flow context
       
    55 	* through this method, will become the owner of the flow context.
       
    56 	*
       
    57 	* @param aManager
       
    58 	*		Flow manager
       
    59 	* @param aProtocol
       
    60 	*		The upper layer protocol associated with the flow.
       
    61 	*		This is also the value for the IP NextHeader/Protocol field, unless
       
    62 	*		a hook adds some extension headers. This can also be set later using
       
    63 	*		RFlowContext::SetProtocol method.
       
    64 	* @return
       
    65 	*		KErrNone, if the context was successfully created and attached to the handle.
       
    66 	*/
       
    67 	{
       
    68 	iFlow = 0;
       
    69 	TRAPD(err, iFlow = aManager->NewFlowL(this, aProtocol));
       
    70 	return err;
       
    71 	}
       
    72 
       
    73 EXPORT_C TInt RFlowContext::ReOpen()
       
    74 	/**
       
    75 	* Allocates a new flow context to the handle using the parameters from
       
    76 	* the existing flow context.
       
    77 	*
       
    78 	* If the handle is the only reference to the current context, the context is 
       
    79 	* deleted after the new context has been created.
       
    80 	*
       
    81 	* This function is not for general use.
       
    82 	*
       
    83 	* @return
       
    84 	*		KErrNone on success.
       
    85 	*/
       
    86 	{
       
    87 	CFlowContext *old = iFlow;
       
    88 	if (old)
       
    89 		{
       
    90 		iFlow = NULL;
       
    91 		TRAPD(err, iFlow = old->iMgr->NewFlowL(this, *old));
       
    92 		old->Close();
       
    93 		return err;
       
    94 		}
       
    95 	else
       
    96 		return KErrBadHandle;
       
    97 	}
       
    98 
       
    99 EXPORT_C TInt RFlowContext::Clone(const RFlowContext &aFlow)
       
   100 	/**
       
   101 	* Creates a new flow with the flow parameters copied from another flow.
       
   102 	*
       
   103 	* @param aFlow
       
   104 	*		a flow to be duplicated
       
   105 	*
       
   106 	* @return
       
   107 	*		System wide error codes
       
   108 	*/
       
   109 	{
       
   110 	//
       
   111 	// This sequence of actions below tries to do the cloning in
       
   112 	// such a way, that it is safe even if the this == aFlow (in which
       
   113 	// case this is same as plain "ReOpen()").
       
   114 	//
       
   115 	CFlowContext *old = iFlow;
       
   116 	iFlow = aFlow.iFlow;
       
   117 	iFlow->Open();
       
   118 	TInt ret = ReOpen();
       
   119 	if (old)
       
   120 		old->Close();
       
   121 	return ret;
       
   122 	}
       
   123 
       
   124 
       
   125 EXPORT_C TInt RFlowContext::Connect()
       
   126 	/**
       
   127 	* Forces a (re)connect on the flow.
       
   128 	*
       
   129 	* Connect activates the connection phase of the flow context.
       
   130 	* Any previous connection is disconnected from the flow.
       
   131 	*
       
   132 	* @return
       
   133 	*		the status of the flow. Any non-zero positive
       
   134 	*		value indicates "pending" state: a connection
       
   135 	*		is being setup but not yet ready (for example,
       
   136 	*		a netdial process may have been activated, but
       
   137 	*		it is still waiting for the user input).
       
   138 	*/
       
   139 	{
       
   140 	if (iFlow)
       
   141 		{
       
   142 		iFlow->Connect();
       
   143 		return iFlow->iStatus;
       
   144 		}
       
   145 	else
       
   146 		return KErrBadHandle;
       
   147 	}
       
   148 
       
   149 EXPORT_C TInt RFlowContext::Open(MFlowManager *aManager, const TSockAddr &aDst,	const TSockAddr &aSrc, TUint aProtocol, TUint aIcmpType, TUint aIcmpCode)
       
   150 	/**
       
   151 	* Just a convenience function, which combines Open, SetRemoteAddr, SetLocalAddr, SetIcmpInfo and Connect.
       
   152 	*
       
   153 	* @param aManager	Flow Manager
       
   154 	* @param aDst		Flow's destination address (and port)
       
   155 	* @param aSrc		Flow's source address (and port)
       
   156 	* @param aProtocol	The upper layer protocol associated with the flow
       
   157 	*					(and the value for the IP  NextHeader/Protocol field,
       
   158 	*					unless some hook adds extension headers)
       
   159 	* @param aIcmpType	ICMP type (only sensible when protocol is ICMP)
       
   160 	* @param aIcmpCode	ICMP code (only sensible when protocol is ICMP)
       
   161 	*
       
   162 	* @return
       
   163 	*		current value of CFlowContext::iStatus.
       
   164 	*/
       
   165 	{
       
   166 	TInt ret = Open(aManager, aProtocol);
       
   167 	if (ret != KErrNone)
       
   168 		return ret;
       
   169 	else if (iFlow)
       
   170 		{
       
   171 		SetRemoteAddr(aDst);
       
   172 		SetLocalAddr(aSrc);
       
   173 		SetIcmpType(aIcmpType, aIcmpCode);
       
   174 		iFlow->Connect();
       
   175 		return iFlow->iStatus;
       
   176 		}
       
   177 	else
       
   178 		return KErrBadHandle;
       
   179 	}
       
   180 
       
   181 EXPORT_C TInt RFlowContext::Open(RFlowContext &aFlow, RMBufPktInfo *aInfo)
       
   182 	/**
       
   183 	* Attaches the flow to a specified packet.
       
   184 	*
       
   185 	* This function is used only to attach a copy reference to the flow to an outgoing 
       
   186 	* packet (RMBufSendInfo::iFlow).
       
   187 
       
   188 	* This method is very specific and currently used only for attaching a copy reference
       
   189 	* of the flow to an outgoing packet (iFlow member of the RMBufPacketInfo).
       
   190 	*
       
   191 	* The function checks aContext and if there have been no changes to the flow
       
   192 	* parameters (as recorded by CFlowContext::iChanged) since the last connection,
       
   193 	* the flow is assumed to be validly connected. Note that this means that if
       
   194 	* the referenced flow is in an error state and if no flow parameters have been 
       
   195 	* changed, this attach/open also fails. No reconnect attempt is made in that 
       
   196 	* case.
       
   197 	*
       
   198 	* If the flow parameters have been changed since the last connect, the flow 
       
   199 	* is reconnected. If there are additional references to the flow context, an 
       
   200 	* implicit re-open (RFlowContext::ReOpen) is executed for the handle and the
       
   201 	* flow parameters are copied  from the old flow context.
       
   202 	* After this, the new flow is connected. Note that 
       
   203 	* if a new cloned context is created, and if the context had a provider notify 
       
   204 	* pointer (see RFlowContext::SetNotify()) set through this handle, the pointer
       
   205 	* is automatically transferred to the new flow context, and removed from the old context. 
       
   206 	*
       
   207 	* If, after above processing, the referenced flow is ready to receive outgoing packets,
       
   208 	* the flow context associated with the referenced handle is attached to the current handle.
       
   209 	*
       
   210 	* This design allows simple processing for the upper layers, as they don't need to worry
       
   211 	* if the old flow is used by some packet still on the way out. Additionally, delaying the
       
   212 	* "cloning" until actual attach/connect, may avoid unnecessary copying.
       
   213 	*
       
   214 	* The opened handle is not the owner of the flow context. This will only create an additional
       
   215 	* reference to an existing flow context owned by someone else (usually aFlow).
       
   216 	*
       
   217 	* @param aFlow
       
   218 	*		the "source flow" to be attached to the current handle
       
   219 	* @retval aInfo
       
   220 	*		An optional information block.
       
   221 	*		If specified, then on a successful attach, the info members iProtocol,
       
   222 	*		iSrcAddr and iDstAddr are initialized from the respective selector
       
   223 	*		fields of the flow.
       
   224 	* @return
       
   225 	*		The return value of the Open is in general same as what would be returned
       
   226 	*		by the Status call. However, when attach causes the actual connection of the flow,
       
   227 	*		there exists error return codes which do not happen with Status call.
       
   228 	*/
       
   229 	{
       
   230 	// FFS: It should be considered that this method is replaced with something like
       
   231 	// Attach(aFlow) function in the RMBufSendInfo itself. That would be much cleaner
       
   232 	// solution.
       
   233 	iFlow = NULL;
       
   234 	CFlowContext *flow = aFlow.iFlow;
       
   235 	if (!flow)
       
   236 		return KErrBadHandle;
       
   237 
       
   238 	if (flow->iChanged)
       
   239 		{
       
   240 		//
       
   241 		// The flow parameters have been changed
       
   242 		//
       
   243 		if (flow->iRefs > 0)
       
   244 			{
       
   245 			//
       
   246 			// Need to allocate a new flow
       
   247 
       
   248 			TInt err = aFlow.ReOpen();
       
   249 			if (err != KErrNone)
       
   250 				return err;
       
   251 			flow = aFlow.iFlow;
       
   252 			}
       
   253 		// Assume: ConnectFlow will clean out all previous connection state! -- msa
       
   254 		flow->Connect();
       
   255 		}
       
   256 	//
       
   257 	// ...should this Refresh be done here or not? -- msa
       
   258 	//
       
   259 	if (flow->iStatus > EFlow_READY)
       
   260 		flow->RefreshFlow();
       
   261 	if (flow->iStatus == EFlow_READY)
       
   262 		{
       
   263 		//
       
   264 		// Attach the flow to this handle
       
   265 		//
       
   266 		flow->Open();
       
   267 		iFlow = flow;
       
   268 		}
       
   269 	//
       
   270 	// Return current address information
       
   271 	// (even though it in some cases might be random)
       
   272 	//
       
   273 	if (aInfo)
       
   274 		{
       
   275 		aInfo->iDstAddr = flow->RemoteAddr();
       
   276 		aInfo->iSrcAddr = flow->LocalAddr();
       
   277 		aInfo->iProtocol = flow->Protocol();
       
   278 		}
       
   279 	return flow->iStatus;
       
   280 	}
       
   281 
       
   282 // Help function for address loading, returns
       
   283 //  = 0, if address did not change
       
   284 //  = 1, if address has changed
       
   285 //
       
   286 static TInt ChangedAddress(TInetAddr &aAddr, const TInetAddr &aNewAddr)
       
   287 	{
       
   288 	// "Normalize" new address
       
   289 	// - convert IPv4 addresess into IPv4 mapped
       
   290 	// - anything other then KAfInet6 will be set as None
       
   291 	TInetAddr tmp(aNewAddr);
       
   292 	if (tmp.Family() == KAfInet)
       
   293 		{
       
   294 		tmp.ConvertToV4Mapped();
       
   295 		tmp.SetScope(0);	// [is already part of "convert" in newer insocks]
       
   296 		}
       
   297 	else if (tmp.Family() != KAfInet6)
       
   298 		tmp.SetAddress(KInet6AddrNone);
       
   299 
       
   300 	if (tmp.CmpAddr(aAddr) &&				// address and port same?
       
   301 		tmp.FlowLabel() == aAddr.FlowLabel())
       
   302 		{
       
   303 		// If the scope id in new addres is zero, then the
       
   304 		// scope id is not part the address compare.
       
   305 		// (this will optimize unconnected sockets where application
       
   306 		// gives destination without scope -- eliminates unnecessary
       
   307 		// flow connect operations.
       
   308 		if (tmp.Scope() == aAddr.Scope() || tmp.Scope() == 0)
       
   309 			return 0;	// No Change to the previous value
       
   310 		}
       
   311 
       
   312 	// Address is being changed
       
   313 	aAddr = tmp;
       
   314 	return 1;
       
   315 	}
       
   316 
       
   317 
       
   318 /**
       
   319 * @defgroup	setselectors	Flow selector fields
       
   320 *
       
   321 * The selector information currently includes the following:
       
   322 * @li	local address and port
       
   323 * @li	remote addresses and port
       
   324 * @li	IP protocol number
       
   325 * @li	ICMP (or some other protocol) type and code.
       
   326 *
       
   327 * When a method is used to set any of the selector fields, the new and current value are
       
   328 * compared, and if there is a change, the CFlowContext::iChanged is set.
       
   329 *
       
   330 * Although the code does not verify it, changing any of the selector fields should
       
   331 * be done only by the owner of the flow context.
       
   332 *
       
   333 * If the handle is not attached to a flow, all methods will just silently return
       
   334 * without doing anything.
       
   335 *
       
   336 * @{
       
   337 */
       
   338 
       
   339 EXPORT_C void RFlowContext::SetRemoteAddr(const TSockAddr &aAddr)
       
   340 	/**
       
   341 	* Sets the flow's remote address and port.
       
   342 	*
       
   343 	* @param aAddr
       
   344 	*	An address and port of the selector.
       
   345 	*	If an address is given in IPv4 format (KAfInet), it will be automaticly
       
   346 	*	converted into IPv4 mapped format (KAfInet6) in the flow context.
       
   347 	*	Note that the flow  itself does not record whether an IPv4 address was specified. 
       
   348 	*/
       
   349 	{
       
   350 	if (iFlow && ChangedAddress(iFlow->iInfo.iRemote, TInetAddr::Cast(aAddr)))
       
   351 		{
       
   352 		if (!iFlow->IsLocalSet())
       
   353 			//
       
   354 			// If the local address is unspecified by the application,
       
   355 			// changing the remote address must also reset the local address
       
   356 			// back to the unspecified state, so that the system will reselect
       
   357 			// a new local address which will match the new remote address!
       
   358 			//
       
   359 			// Due to IPSEC, even changing port may cause destination
       
   360 			// change, if policy specifies tunneling for certain ports
       
   361 			// [this None setting may be unnecessary, need to check -- msa]
       
   362 			iFlow->iInfo.iLocal.SetAddress(KInet6AddrNone);
       
   363 		iFlow->iChanged = 1;
       
   364 		}
       
   365 	}
       
   366 
       
   367 EXPORT_C void RFlowContext::SetLocalAddr(const TSockAddr &aAddr)
       
   368 	/**
       
   369 	* Sets the flow's local address and port
       
   370 	*
       
   371 	* @param aAddr
       
   372 	*	An address and port of the selector.
       
   373 	*
       
   374 	*	If an address is given in IPv4 format (KAfInet), it will be converted
       
   375 	*	into IPv4 mapped format (KAfInet6) in the flow context. If address
       
   376 	*	is unspecified, the CFlowContext::iLocalSet is cleared, and set otherwise.
       
   377 	*	See also CFlowContext::IsLocalSet().
       
   378 	*
       
   379 	*	Note that the flow  itself does not record whether an IPv4 address
       
   380 	*	was originally specified in KAfInet or KAfInet6 format.
       
   381 	*/
       
   382 	{
       
   383 	if (iFlow && ChangedAddress(iFlow->iInfo.iLocal, TInetAddr::Cast(aAddr)))
       
   384 		{
       
   385 		iFlow->iInfo.iLocalSet = !(iFlow->iInfo.iLocal.IsUnspecified());
       
   386 		iFlow->iChanged = 1;
       
   387 		}
       
   388 	}
       
   389 
       
   390 EXPORT_C void RFlowContext::SetProtocol(TUint aProtocol)
       
   391 	/**
       
   392 	* Sets the flow's protocol.
       
   393 	* @param aProtocol
       
   394 	*	The upper layer protocol associated with the flow (and the value for the IP
       
   395 	*	NextHeader/Protocol field, unless some hook adds extension headers)
       
   396 	*/
       
   397 	{
       
   398 	if (iFlow && iFlow->iInfo.iProtocol != aProtocol)
       
   399 		{
       
   400 		iFlow->iInfo.iProtocol = (TUint8)aProtocol;
       
   401 		if (!iFlow->iInfo.iLocalSet)
       
   402 			//
       
   403 			// Need to reset source address to unselected also here...
       
   404 			//
       
   405 			// Due to IPSEC, even changing protocol, may cause destination
       
   406 			// change, if policy specifies tunneling for certain protocols
       
   407 			// [this None setting may be unnecessary, need to check -- msa]
       
   408 			iFlow->iInfo.iLocal.SetAddress(KInet6AddrNone);
       
   409 
       
   410 		iFlow->iChanged = 1;
       
   411 		}
       
   412 	}
       
   413 
       
   414 EXPORT_C void RFlowContext::SetIcmpType(TUint aType, TUint aCode)
       
   415 	/**
       
   416 	* Sets the flow's ICMP type and code. Omitted aCode will set ICMP code in the
       
   417 	* flow as zero.
       
   418 	*
       
   419 	* Note: Although this method is designed for ICMP, there are other protocols
       
   420 	* which do not use ports, but some kind to type/code instead. Despite
       
   421 	* it's name, this function can be used.
       
   422 	*
       
   423 	* @param aType		ICMP type
       
   424 	* @param aCode		ICMP code
       
   425 	*/
       
   426 	{
       
   427 	if (iFlow && (iFlow->iInfo.iIcmpType != aType || iFlow->iInfo.iIcmpCode != aCode))
       
   428 		{
       
   429 		iFlow->iInfo.iIcmpType = (TUint8)aType;
       
   430 		iFlow->iInfo.iIcmpCode = (TUint8)aCode;
       
   431 		if (!iFlow->iInfo.iLocalSet)
       
   432 			//
       
   433 			// Need to reset source address to unselected also here...
       
   434 			//
       
   435 			// Due to IPSEC, changing anything that affects selector,
       
   436 			// may cause destination change (due tunnel), and thus
       
   437 			// a new source address..
       
   438 			// [this None setting may be unnecessary, need to check -- msa]
       
   439 			iFlow->iInfo.iLocal.SetAddress(KInet6AddrNone);
       
   440 		iFlow->iChanged = 1;
       
   441 		}
       
   442 	}
       
   443 
       
   444 
       
   445 /** @} */	// End setselectors
       
   446 
       
   447 
       
   448 
       
   449 EXPORT_C MProviderNotify * RFlowContext::SetNotify(MProviderNotify *aProvider)
       
   450 	/**
       
   451 	* Requesting notifications of events on the flow.
       
   452 	*
       
   453 	* A provider may request notification callbacks from events affecting the flow
       
   454 	* by attaching a MProviderNotify instance to a flow context.
       
   455 	* A flow can only have one such notifier at any time.
       
   456 	*
       
   457 	* Only the owner of the flow context is allowed to set this.
       
   458 	*
       
   459 	* The receiver of the notifications must implement the MProviderNotify mixin class:
       
   460 	*
       
   461 	* MProviderNotify::CanSend() is called when the flow might be ready to change
       
   462 	* into the EFlow_READY status (this is only called when flow status is HOLD
       
   463 	* or PENDING).
       
   464 	*
       
   465 	* MProviderNotify::Error is called whenever the flow is set into error state.
       
   466 	* The aMask parameter follows the MSocketNotify (in <es_prot.h>) definitions.
       
   467 	*
       
   468 	* These two methods are a subset of the MSocketNotify,
       
   469 	* and the intention is that, by default the SAP implementation using the flow
       
   470 	* can just call the equivalent MSocketNotify method from these notifies.
       
   471 	*
       
   472 	* @param aProvider
       
   473 	*		an object to receive the CanSend() or Error() upcalls,
       
   474 	*		or NULL if cancel notifications
       
   475 	* @return
       
   476 	*		the pointer of the previous notifier, if any, is returned
       
   477 	*		(or, the context was not attached, the method returns the
       
   478 	*		aProvider).
       
   479 	*/
       
   480 	{
       
   481 	// FFS: The notifier call should be suppressed while
       
   482 	// iChanged is set, only the CanSend() notify?
       
   483 	if (iFlow && iFlow->iOwner == this)
       
   484 		{
       
   485 		MProviderNotify *n = iFlow->iProvider;
       
   486 		iFlow->iProvider = aProvider;
       
   487 		return n;
       
   488 		}
       
   489 	else
       
   490 		return aProvider;
       
   491 	}
       
   492 
       
   493 EXPORT_C void RFlowContext::Close()
       
   494 	/**
       
   495 	* Closes an open handle.
       
   496 	*
       
   497 	* This must be called when the handle is no longer required.
       
   498 	* Close detaches the actual flow context from this handle.
       
   499 	* If this handle was the last reference to the context, the context is
       
   500 	* destroyed.
       
   501  	*/
       
   502 	{
       
   503 	if (iFlow)
       
   504 		{
       
   505 		if (iFlow->iOwner == this)
       
   506 			iFlow->iProvider = NULL;
       
   507 		// Do a "safe" close, by removing the flow context
       
   508 		// reference from the handle before closing.
       
   509 		CFlowContext &flow = *iFlow;
       
   510 		iFlow = NULL;
       
   511 		flow.Close();
       
   512 		}
       
   513 	}
       
   514 
       
   515 EXPORT_C TInt RFlowContext::Status()
       
   516 	/**
       
   517 	* Gets the status of the flow.
       
   518 	*
       
   519 	* This function attempts to return the current "effective" status
       
   520 	* of the flow based on current settings. Thus, if the flows parameters
       
   521 	* have been changed since the last connect, the function does an implicit
       
   522 	* (re)connect first.
       
   523 	*
       
   524 	* For documentation on values, see CFlowContext::Status.
       
   525 	*
       
   526 	* @return
       
   527 	*		KErrBadHandle, if handle is not attached to a flow context. Other returns
       
   528 	*		are defined by CFlowContext::Status.
       
   529 	*/
       
   530 	{
       
   531 	if (!iFlow)
       
   532 		return KErrBadHandle;
       
   533 
       
   534 	// If the flow is in error state (< 0), the Status() alone will not
       
   535 	// clear it (changed bit is not effective!).
       
   536 	if (iFlow->iStatus >= 0 && iFlow->iChanged)
       
   537 		{
       
   538 		//
       
   539 		// The flow parameters have been changed
       
   540 		//
       
   541 		if (iFlow->iRefs > 0)
       
   542 			{
       
   543 			//
       
   544 			// Need to allocate a new flow
       
   545 
       
   546 			TInt err = ReOpen();
       
   547 			if (err != KErrNone)
       
   548 				return err;
       
   549 			}
       
   550 		// Assume: ConnectFlow will clean out all previous connection state! -- msa
       
   551 		iFlow->Connect();
       
   552 		}
       
   553 	return iFlow->Status();
       
   554 	}
       
   555 
       
   556 EXPORT_C CNifIfBase * RFlowContext::Interface() const
       
   557 	/**
       
   558 	* Gets a pointer to the network interface object at the end of the flow.
       
   559 	*
       
   560 	* @return	Network interface object (or NULL).
       
   561 	*/
       
   562 	{
       
   563 	return iFlow ? iFlow->Interface() : NULL;
       
   564 	}
       
   565 
       
   566 EXPORT_C void RFlowContext::Grab(RFlowContext &aContext)
       
   567 	/**
       
   568 	* Moves the flow context from one handle to another.
       
   569 	*
       
   570 	* This operation does not increase or decrease the references.
       
   571 	* The grabbed handle will become unattached.
       
   572 	*
       
   573 	* This function is not for general use.
       
   574 	* @param aContext
       
   575 	*		Handle from which to move the context
       
   576 	*/
       
   577 	{
       
   578 	iFlow = aContext.iFlow;
       
   579 	// FFS: Should check that the aContext is not the owner and disallow grab in such
       
   580 	// situation (or disable notifier callback, if set). If a aContext
       
   581 	// is the owner of the CFlowContext and notifier is set, then this pointer
       
   582 	// is left "dangling"! Currently only used to detach from the packet, which
       
   583 	// is never the owner? Suggested code (disable notifier):
       
   584 	if (iFlow && iFlow->iOwner == &aContext)
       
   585 		iFlow->iProvider = NULL;
       
   586 	aContext.iFlow = NULL;
       
   587 	}
       
   588 
       
   589 EXPORT_C void RFlowContext::Copy(RFlowContext &aContext)
       
   590 	/**
       
   591 	* Copies the specified flow context to the handle and updates the
       
   592 	* flow's reference count.
       
   593 	* The call never fails.
       
   594 	*
       
   595 	* @param	aContext
       
   596 	*	Handle to the flow context to copy
       
   597 	*/
       
   598 	{
       
   599 	iFlow = aContext.iFlow;
       
   600 	if (iFlow)
       
   601 		iFlow->Open();
       
   602 	}
       
   603 
       
   604 #ifdef SYMBIAN_TCPIPDHCP_UPDATE
       
   605 //RFC 4861 Section 7.2.2
       
   606 //Checks whether Neighbour Discovery is currently pending
       
   607 EXPORT_C TBool RFlowContext::IsNdResolutionPending()
       
   608 	{
       
   609 	TBool bFlag = EFalse;
       
   610 	if (iFlow)
       
   611 		{
       
   612 		bFlag = iFlow->IsNdPacketPendingResolution();  			
       
   613 		}
       
   614 	return bFlag;	
       
   615 	}
       
   616 #endif //SYMBIAN_TCPIPDHCP_UPDATE
       
   617 
       
   618 // ************
       
   619 // CFlowContext (methods)
       
   620 // ************
       
   621 //
       
   622 EXPORT_C CFlowContext::CFlowContext(const void *aOwner, MFlowManager *aManager) : iOwner(aOwner), iMgr(aManager), iStatus(KErrNotReady)
       
   623 	/**
       
   624 	* Constructor.
       
   625 	*
       
   626 	* The contructor (returned pointer) counts as a reference. The user does
       
   627 	* not need to issue a separate Open() to update the reference count. When
       
   628 	* the flow pointer is not needed, it must be released by a Close() call
       
   629 	* (and not by a delete operator).
       
   630 	* The Close() deletes the CFlowContext automaticly, when the last reference
       
   631 	* is removed. The delete must not be used.
       
   632 	*
       
   633 	* @note
       
   634 	*	The CFlowContext should be handled through the RFlowContext class, which
       
   635 	*	takes care of the Open() and Close() calls correctly.
       
   636 	*
       
   637 	* @param aOwner
       
   638 	*	Flow owner identifier. This is untyped, but can be used for 
       
   639 	*	comparisions against other owner identifier.
       
   640 	* @param aManager
       
   641 	*	The flow manager that created this object
       
   642 	*/
       
   643 	{
       
   644 	}
       
   645 
       
   646 EXPORT_C CFlowContext::CFlowContext(const void *aOwner, MFlowManager *aManager, CFlowContext &aFlow)
       
   647   : iOwner(aOwner), iMgr(aManager), iStatus(KErrNotReady)
       
   648 	/**
       
   649 	* Constructor, copying the parameters of an existing flow.
       
   650 	*
       
   651 	* The contructed flow must be connected before it can be used
       
   652 	* (regardless of the state of the copied flow).
       
   653 	* @param aOwner
       
   654 	*	Flow owner identifier. This is untyped, but can be used for 
       
   655 	*	comparisions against other owner identifier.
       
   656 	* @param aManager
       
   657 	*	The flow manager that created this object
       
   658 	* @param aFlow
       
   659 	*	The flow from which to copy parameters
       
   660 	*/
       
   661 	{
       
   662 	//
       
   663 	// Copy/transfer upper layer specific information
       
   664 	// into the new flow
       
   665 	//
       
   666 	iInfo = aFlow.iInfo;
       
   667 	//
       
   668 	// If the source flow has the same owner, then transfer the
       
   669 	// notifier and option storage into the new flow context
       
   670 	//
       
   671 	if (iOwner == aFlow.iOwner)
       
   672 		{
       
   673 		iProvider = aFlow.iProvider;
       
   674 		aFlow.iProvider = NULL;
       
   675 		iStorage = aFlow.iStorage;
       
   676 		aFlow.iStorage = NULL;
       
   677 		}
       
   678 	}
       
   679 
       
   680 
       
   681 // Destructor should not be exported, it should be private! -- msa
       
   682 EXPORT_C CFlowContext::~CFlowContext()
       
   683 	/** Destructor. */
       
   684 	{
       
   685 	while (iStorage)
       
   686 		{
       
   687 		COptionValue *o = iStorage;
       
   688 		iStorage = o->iNext;
       
   689 		delete o;
       
   690 		}
       
   691 	//
       
   692 	// Release associated RMBUF's, if left over by someone
       
   693 	//
       
   694 	iHead.iPacket.Free();
       
   695 	iHead.iIcmp.Free();
       
   696 	}
       
   697 
       
   698 
       
   699 
       
   700 EXPORT_C void CFlowContext::Close()
       
   701 	/**
       
   702 	* Decrements a reference count on the context.
       
   703 	*
       
   704 	* The function deletes the CFlowContext object when the last reference is removed.
       
   705 	*/
       
   706 	{
       
   707 	if (--iRefs < 0)
       
   708 		delete this;
       
   709 	}
       
   710 
       
   711 EXPORT_C TInt CFlowContext::Status()
       
   712 	/**
       
   713 	* Refresh and return current status.
       
   714 	*
       
   715 	* This function is for upper layer users (flow owner) only, because it includes
       
   716 	* conditional side effects through a call to the CFlowContext::RefreshFlow,
       
   717 	* if the status not ready.
       
   718 	*
       
   719 	* A hook must not use this method for flows that it doesn't own itself..
       
   720 	*
       
   721 	* @return
       
   722 	*		the general rules about the returned value are:
       
   723 	* @li	< 0, the flow is in unrecoverable error state. No further output can be done
       
   724 	*		over it and the only way to recover from this is to cause a reconnect.
       
   725 	* @li	= 0, the flow is ready for output, data can be sent over it. (#EFlow_READY)
       
   726 	* @li	> 0, the flow is temporarily blocked and waiting for event. When the event occurs,
       
   727 	*		the SAP is notified if it has setup for it (see SetNotify method).
       
   728 	* @li	A few specific values have been defined as follows:
       
   729 	* @par	Flow_PENDING
       
   730 	*		Not ready for data yet. This occurs normally at the connection
       
   731 	*		startup, when the connection to outside is being established (netdial),
       
   732 	*		but it can also occur at later stage (for example, when IPSEC needs to
       
   733 	*		negotiate a new key).
       
   734 	* @par EFlow_HOLD
       
   735 	*		This state is set when the interface reports congestion
       
   736 	*		(cannot receive more data for a while).
       
   737 	*/
       
   738 	{
       
   739 	//
       
   740 	// The rationale here goes something...
       
   741 	// in normal situation the iStatus == EFlow_READY and this non-virtual
       
   742 	// method is very light to execute. For the exceptional situation a
       
   743 	// heavier virtual RefreshFlow() is called to check if flow state can
       
   744 	// be changed (this may include initializing the source address).
       
   745 	// "Normal" exceptions are
       
   746 	//	EFlow_PENGING ( > EFlow_READY)
       
   747 	//		usually means that the interface is not yet fully and/or the source
       
   748 	//		address to be use cannot yet be decided. The refresh will verify this
       
   749 	//		and update the source if situation has changed.
       
   750 	//	EFlow_HOLD
       
   751 	//		the interface has reported that it is unable to receive more packet
       
   752 	//		packets
       
   753 	//
       
   754 	//	For this to work, it requires
       
   755 	//		1) when interface goes into HOLD, all affected flows must be marked with
       
   756 	//		HOLD state
       
   757 	//		2) if a SAP keeps opened flow handle, it MUST use Status() call before
       
   758 	//		sending of each packet.
       
   759 	//
       
   760 	//	Refresh is only called for PENDING states. Once the flow enters error
       
   761 	//	(< EFlow_READY), it cannot be used for sending data!
       
   762 	//
       
   763 	if (iStatus > EFlow_READY)
       
   764 		RefreshFlow();
       
   765 	return iStatus;
       
   766 	}
       
   767 
       
   768 EXPORT_C void CFlowContext::SetStatus(TInt aStatus)
       
   769 	/**
       
   770 	* Sets (suggests) the flow status value.
       
   771 	*
       
   772 	* The function allows a hook to suggest a value for the flow status.
       
   773 	* The flow does not necessarily accept this value.
       
   774 	*
       
   775 	* This function should never be used by the flow owner.
       
   776 	*
       
   777 	* The function uses the following rules (in the listed order) to
       
   778 	* determine the new status value:
       
   779 	* -# if the new status is an error ( < 0), it will become the flow status
       
   780 	* and all hooks are removed throuh a call to Disconnect().
       
   781 	* A hook must be careful here, as this will cause a call to
       
   782 	* the MFlowHook::Close. Also, the MProviderNotify::Error is called,
       
   783 	* if the notifier is attached to the flow.
       
   784 	* -# if the old status is an error ( < 0), it cannot be changed to any
       
   785 	* non-error status (SetStatus is ignored),
       
   786 	* -# if the new status is #EFlow_READY and the old flow status was
       
   787 	* not READY (was > 0), the flow status is NOT changed, but the attached upper
       
   788 	* layer is notified (MProviderNotify::CanSend). This will eventually cause a
       
   789 	* flow refresh where the correct value of the status will be determined.
       
   790 	* -# if the new status is pending/hold/blocked (> 0), it will become the
       
   791 	* flow status.
       
   792 	*
       
   793 	* The idea behind above definition is that the hook can suggest a status
       
   794 	* from its local view of the flow, and SetStatus makes the "global"
       
   795 	* decision, and activates necessary callbacks if any is required.
       
   796 	*
       
   797 	* @param aStatus
       
   798 	*	The suggested status of the flow: either a system wide error 
       
   799 	*	code or a #TFlowStatus value.
       
   800 	*/
       
   801 	{
       
   802 	if (aStatus < 0)
       
   803 		{
       
   804 		// New status is Error status, set it
       
   805 		// and notify SAP. The previous status does not
       
   806 		// matter.
       
   807 		iStatus = aStatus;
       
   808 		Disconnect();		// ...removes the hooks
       
   809 		if (iProvider)
       
   810 			iProvider->Error(aStatus);
       
   811 		}
       
   812 	else if (iStatus > 0)
       
   813 		{
       
   814 		// Old status is "pending/hold/blocked"
       
   815 		if (aStatus > 0)
       
   816 			iStatus = aStatus;		// Allow any overrides > 0 (!= EFlow_READY)
       
   817 		else if (iProvider)
       
   818 			iProvider->CanSend();
       
   819 		}
       
   820 	else if (iStatus == EFlow_READY)
       
   821 		// New status is either READY or PENDING
       
   822 		iStatus = aStatus;
       
   823 	// When none of the above conditions apply, old status
       
   824 	// is Error state and cannot be overridden by any
       
   825 	// non-Error status.
       
   826 	}
       
   827 
       
   828 EXPORT_C TInt CFlowContext::StoreOption(TUint aLevel, TUint aName, const TDesC8 &aOption)
       
   829 	/**
       
   830 	* Stores a flow context-specific option.
       
   831 	*
       
   832 	* The function allows outbound flow hook modules to store the options that they 
       
   833 	* support. Sockets clients can ultimately query these options through RSocket::GetOpt().
       
   834 	*
       
   835 	* If the specified (level, name) pair already exists in the storage, the new 
       
   836 	* value replaces the old value.
       
   837 	*
       
   838 	* @param aLevel the option level
       
   839 	* @param aName the option name
       
   840 	* @param aOption the option value
       
   841 	*
       
   842 	* @return
       
   843 	*		@li KErrNone on success,
       
   844 	*		@li KErrNoMemory, if option cannot stored due to memory shortage
       
   845 	*/
       
   846 	{
       
   847 	COptionValue **h, *o;
       
   848 	const TInt length = aOption.Length();
       
   849 	for (h = &iStorage; (o = *h) != NULL; h = &o->iNext)
       
   850 		{
       
   851 		if (o->iLevel == aLevel && o->iName == aName)
       
   852 			{
       
   853 			// Replacing a value of existing option. Just delete
       
   854 			// the previous allocation (and insert new as if this
       
   855 			// was not present).
       
   856 			*h = o->iNext;
       
   857 			delete o;
       
   858 			break;
       
   859 			}
       
   860 		}
       
   861 	//
       
   862 	// Attach the new option to the front of the list
       
   863 	//
       
   864 	o = new (length) COptionValue(aLevel, aName, aOption);
       
   865 	if (o)
       
   866 		{
       
   867 		o->iNext = iStorage;
       
   868 		iStorage = o;
       
   869 		return KErrNone;
       
   870 		}
       
   871 	else
       
   872 		return KErrNoMemory;
       
   873 	}
       
   874 
       
   875 EXPORT_C TInt CFlowContext::RetrieveOption(TUint aLevel, TUint aName, TDes8 &aOption) const
       
   876 	/**
       
   877 	* Gets a flow context-specific option.
       
   878 	*
       
   879 	* The option must have been previously stored with StoreOption().
       
   880 	* Retrieve value from flow
       
   881 	*
       
   882 	* @param aLevel The option level
       
   883 	* @param aName The option name
       
   884 	* @retval aOption The option value
       
   885 	*
       
   886 	* @return
       
   887 	*		@li KErrNone on success,
       
   888 	*		@li KErrNotFound, if the value is not stored
       
   889 	*/
       
   890 	{
       
   891 	for (COptionValue *o = iStorage; o != NULL; o = o->iNext)
       
   892 		{
       
   893 		if (o->iLevel == aLevel && o->iName == aName)
       
   894 			{
       
   895 			aOption = o->Value();
       
   896 			return KErrNone;
       
   897 			}
       
   898 		}
       
   899 	return KErrNotFound;
       
   900 	}