networkprotocols/tcpipv4v6prt/src/udp_sap.cpp
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2006-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 // udp_sap.cpp - UDP service access point
       
    15 // UDP service access point
       
    16 //
       
    17 
       
    18 
       
    19 
       
    20 /**
       
    21  @file udp_sap.cpp
       
    22 */
       
    23 
       
    24 #include "udp.h"
       
    25 #include "inet6log.h"
       
    26 #include <in6_opt.h>
       
    27 #include <nifman_internal.h>
       
    28 
       
    29 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    30 #include <in_sock_internal.h>
       
    31 #endif
       
    32 
       
    33 CProviderUDP6::CProviderUDP6(CProtocolInet6Base* aProtocol)
       
    34 	: CProviderInet6Transport(aProtocol)
       
    35 	{
       
    36 	__DECLARE_NAME(_S("CProviderUDP6"));
       
    37 	iProtocolId = KProtocolInetUdp;
       
    38 	}
       
    39 
       
    40 CProviderUDP6::~CProviderUDP6()
       
    41 	{
       
    42 	iProtocol->UnbindProvider(this);
       
    43 	iSockInQ.Free();
       
    44 	iSockOutBuf.Free();
       
    45 	}
       
    46 
       
    47 
       
    48 void CProviderUDP6::InitL()
       
    49 	{
       
    50 	CProviderInet6Transport::InitL();
       
    51 	iFlow.SetProtocol(KProtocolInetUdp);
       
    52 	iFlow.SetNotify(this);
       
    53 	iSockInQLen = 0;
       
    54 	iSockInBufSize = Protocol()->RecvBuf();
       
    55 	}
       
    56 
       
    57 void CProviderUDP6::Ioctl(TUint aLevel, TUint aName, TDes8* aOption)
       
    58 	{
       
    59 	// LOG provided by the base class
       
    60 	CProviderInet6Transport::Ioctl(aLevel, aName, aOption);
       
    61 	}
       
    62 
       
    63 
       
    64 void CProviderUDP6::CancelIoctl(TUint aLevel, TUint aName)
       
    65 	{
       
    66 	// LOG provided by the base class
       
    67 	CProviderInet6Transport::CancelIoctl(aLevel, aName);
       
    68 	}
       
    69 
       
    70 
       
    71 TInt CProviderUDP6::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption)
       
    72 	{
       
    73 	TInt ret = KErrNotSupported;
       
    74 	TInt intValue = 0;
       
    75 
       
    76 	switch (aLevel)
       
    77 		{
       
    78 	case KSolInetUdp:
       
    79 		switch (aName)
       
    80 			{
       
    81 		case KSoUdpReceiveICMPError:
       
    82 			ret = GetOptionInt(aOption, intValue);
       
    83 			if (ret == KErrNone)
       
    84 				iSockFlags.iReportIcmp = intValue ? TRUE : FALSE;
       
    85 #ifdef _LOG
       
    86 			Log::Printf(_L("SetOpt\tudp SAP[%u] KSoUdpReceiveICMPError=%d err=%d"),
       
    87 				(TInt)this, (TInt)iSockFlags.iReportIcmp, ret);
       
    88 #endif
       
    89 			break;
       
    90 
       
    91 		case KSoUdpSynchronousSend:
       
    92 			ret = GetOptionInt(aOption, intValue);
       
    93 			if (ret == KErrNone)
       
    94 				iSynchSend = intValue ? TRUE : FALSE;
       
    95 #ifdef _LOG
       
    96 			Log::Printf(_L("SetOpt\tudp SAP[%u] KSoUdpSynchronousSend = %d err=%d"),
       
    97 				(TInt)this, iSynchSend, ret);
       
    98 #endif
       
    99 			break;
       
   100 			
       
   101 		case KSoUdpRecvBuf:
       
   102 			ret = GetOptionInt(aOption, intValue);
       
   103 			if (ret == KErrNone)
       
   104 				iSockInBufSize = intValue;
       
   105 #ifdef _LOG
       
   106 			Log::Printf(_L("SetOpt\tudp SAP[%u] KSoUdpRecvBuf = %d err=%d"),
       
   107 				(TInt)this, iSockInBufSize, ret);
       
   108 #endif
       
   109 			break;
       
   110 
       
   111 		case KSoUdpAddressSet:
       
   112 			ret = GetOptionInt(aOption, intValue);
       
   113 			if (ret == KErrNone)
       
   114 				iSockFlags.iAddressSet = intValue ? TRUE : FALSE;
       
   115 #ifdef _LOG
       
   116 			Log::Printf(_L("SetOpt\tudp SAP[%u] KSoUdpAddressSet = %d err=%d"),
       
   117 				(TInt)this, (TInt)iSockFlags.iAddressSet, ret);
       
   118 #endif
       
   119 			break;
       
   120 
       
   121 		default:
       
   122 			break;
       
   123 			}
       
   124 		break;
       
   125 
       
   126 
       
   127 	case KSolInetIp: 
       
   128 		{ 
       
   129         if (aName == KSoReuseAddr) 
       
   130         	{ 
       
   131             ret = CheckPolicy(KPolicyNetworkControl, 0); 
       
   132             if (ret == KErrNone) 
       
   133       	      { 
       
   134               TInt intValue; 
       
   135               ret = GetOptionInt(aOption, intValue); 
       
   136               if (ret == KErrNone) 
       
   137       	        iSockFlags.iReuse = intValue ? TRUE : FALSE; 
       
   138               } 
       
   139 #ifdef _LOG 
       
   140             Log::Printf(_L("SetOpt\tudp SAP[%u] KSoReuseAddr = %d err=%d"), 
       
   141       		               (TInt)this, (TInt)iSockFlags.iReuse, ret); 
       
   142 #endif 
       
   143             return ret; // NOTE! We must not let CProviderInet6Transport handle this (security issue) 
       
   144             } 
       
   145         } 
       
   146         break; 
       
   147         
       
   148 	default:
       
   149 		break;
       
   150 		}
       
   151 
       
   152 	if (ret == KErrNotSupported)
       
   153 		ret = CProviderInet6Transport::SetOption(aLevel, aName, aOption);
       
   154 
       
   155 	return ret;
       
   156 	}
       
   157 
       
   158 
       
   159 TInt CProviderUDP6::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const
       
   160 	{
       
   161 	TInt ret = KErrNotSupported;
       
   162 
       
   163 	switch (aLevel)
       
   164 		{
       
   165 	case KSOLSocket:
       
   166 		if (aName == KSOReadBytesPending)
       
   167 			ret = SetOptionInt(aOption, iSockInQ.IsEmpty() ? 0 : iSockInQ.First().Length() - iSockInQ.First().First()->Length());
       
   168 		break;
       
   169 	case KSolInetUdp:
       
   170 		switch (aName)
       
   171 			{
       
   172 		case KSoUdpReceiveICMPError:
       
   173 			ret = SetOptionInt(aOption, iSockFlags.iReportIcmp);
       
   174 			break;
       
   175 
       
   176 		case KSoUdpSynchronousSend:
       
   177 			ret = SetOptionInt(aOption, iSynchSend);
       
   178 			break;
       
   179 
       
   180 		case KSoUdpRecvBuf:
       
   181 			ret = SetOptionInt(aOption, iSockInBufSize);
       
   182 			break;
       
   183 
       
   184 		default:
       
   185 			break;
       
   186 			}
       
   187 		break;
       
   188 
       
   189 	default:
       
   190 		break;
       
   191 		}
       
   192 
       
   193 	if (ret == KErrNotSupported)
       
   194 		ret = CProviderInet6Transport::GetOption(aLevel, aName, aOption);
       
   195 
       
   196 	return ret;
       
   197 	}
       
   198 
       
   199 TInt CProviderUDP6::SetRemName(TSockAddr &aAddr)
       
   200 	{
       
   201 	TInt err;
       
   202 	TInetAddr addr = aAddr;
       
   203 
       
   204 	if (err = CProviderInet6Transport::SetRemName(addr), err == KErrNone)
       
   205 		{
       
   206 		if (iFlow.FlowContext()->LocalPort() == KInetPortNone)
       
   207 			CProviderInet6Transport::AutoBind();
       
   208 		if (iFlow.FlowContext()->LocalPort() != KInetPortNone)
       
   209 			err = iFlow.Connect();
       
   210 		else
       
   211 			{
       
   212 			iSockFlags.iConnected = EFalse;
       
   213 			iSockFlags.iReportIcmp = ETrue;
       
   214 			err = KErrInUse;
       
   215 			}
       
   216 		}
       
   217 
       
   218 	return (err < KErrNone) ? err : KErrNone;
       
   219 	}
       
   220 
       
   221 
       
   222 void CProviderUDP6::Shutdown(TCloseType aOption)
       
   223 	{
       
   224 	LOG(Log::Printf(_L("Shutdown\tudp SAP[%u] TCloseType=%d"), (TInt)this, aOption));
       
   225 	switch(aOption)
       
   226 		{
       
   227 	case EStopInput:
       
   228 		iSockFlags.iRecvClose = ETrue;
       
   229 		iSockInQ.Free();
       
   230 		iSockInQLen = 0;
       
   231 		iSocket->Error(KErrNone,MSocketNotify::EErrorClose);
       
   232 		Nif::SetSocketState(ENifSocketConnected, this);
       
   233 		break;
       
   234 
       
   235 	case EStopOutput:
       
   236 		iSockFlags.iSendClose = ETrue;
       
   237 		iSocket->Error(KErrNone,MSocketNotify::EErrorClose);
       
   238 		Nif::SetSocketState(ENifSocketConnected, this);
       
   239 		break;
       
   240 
       
   241 	case ENormal:
       
   242 		iSocket->CanClose();
       
   243 		break;
       
   244 
       
   245 	case EImmediate:
       
   246 		break;
       
   247 
       
   248 	default:
       
   249 		Panic(EInet6Panic_NotSupported);
       
   250 		break;
       
   251 		}
       
   252 	}
       
   253 
       
   254 
       
   255 //
       
   256 // PRTv1.0 API
       
   257 //
       
   258 void CProviderUDP6::GetData(TDes8 &aDesc, TUint aOptions, TSockAddr *aAddr)
       
   259 	{
       
   260 	TDualBufPtr buf(aDesc);
       
   261 	Recv(buf, aDesc.Length(), aOptions, aAddr);
       
   262 	}
       
   263 
       
   264 //
       
   265 // PRTv1.5 API
       
   266 //
       
   267 TInt CProviderUDP6::GetData(RMBufChain& aData, TUint aLength, TUint aOptions, TSockAddr* aAddr)
       
   268 	{
       
   269 	TDualBufPtr buf(aData);
       
   270 	return Recv(buf, aLength, aOptions, aAddr);
       
   271 	}
       
   272 
       
   273 static void FillUdpHeader(TInet6Checksum<TInet6HeaderUDP> &aPkt, RMBufSendPacket &aPacket, RMBufSendInfo &aInfo, TUint aOffset)
       
   274 	{
       
   275 	//
       
   276 	// Build UDP header
       
   277 	aPkt.iHdr->SetSrcPort(aInfo.iSrcAddr.Port());
       
   278 	aPkt.iHdr->SetDstPort(aInfo.iDstAddr.Port());
       
   279 	aPkt.iHdr->SetLength(aInfo.iLength);
       
   280 	// Compute checksum
       
   281 	aPkt.ComputeChecksum(aPacket, &aInfo, aOffset);
       
   282 	if (aPkt.iHdr->Checksum() == 0)  // Zero indicates "no checksum" in IPv4
       
   283 		aPkt.iHdr->SetChecksum(0xffff);
       
   284 	}
       
   285 
       
   286 TInt CProviderUDP6::DoWrite(RMBufSendPacket &aPacket, RMBufSendInfo &aInfo, TUint /*aOptions*/, TUint aOffset)
       
   287 	{
       
   288 	// Whenever a new packet to send arrives, the buffered packet, if any, is dropped!
       
   289 	// [Because the new packet may make the flow selectors different from the buffered packet]
       
   290 	LOG(if (!iSockOutBuf.IsEmpty()) Log::Printf(_L("\tudp SAP[%u] No space. Unsent packet DROPPED"), (TInt)this));
       
   291 	iSockOutBuf.Free();
       
   292 
       
   293 	if (aOffset == 0)
       
   294 		{
       
   295 		// When offset is 0, the packet is not using the KIpHeaderIncluded.
       
   296 		// The UDP header needs to be allocated in front of the payload.
       
   297 		TInt err = aPacket.Prepend(TInet6HeaderUDP::MinHeaderLength());
       
   298 		if (err != KErrNone)
       
   299 			return KErrNoMBufs;
       
   300 		aInfo.iLength += TInet6HeaderUDP::MinHeaderLength();
       
   301 		}
       
   302 	TInet6Checksum<TInet6HeaderUDP> pkt(aPacket, aOffset);
       
   303 	if (pkt.iHdr == NULL)
       
   304 		{
       
   305 		// Can happen if user uses KIpHeaderIncluded without UDP header, but
       
   306 		// may catch other unexpected problems with the RMBuf handling. In
       
   307 		// any case, this packet cannot be sent (no retries allowed).
       
   308 		return KErrInet6ShortPacket;
       
   309 		}
       
   310 	if (aOffset > 0)
       
   311 		{
       
   312 		// The packet is sent using KIpHeaderIncluded option, extract the UDP
       
   313 		// ports from the included header.
       
   314 		aInfo.iSrcAddr.SetPort(pkt.iHdr->SrcPort());
       
   315 		if (aInfo.iDstAddr.Port() == 0)
       
   316 			{
       
   317 			// aToAddr was not specified, or it had ZERO port. copy the port
       
   318 			// from the UDP header.
       
   319 			aInfo.iDstAddr.SetPort(pkt.iHdr->DstPort());
       
   320 			}
       
   321 		// Change the flow to match the included header! The header gives
       
   322 		// both source and destination, and will OVERRIDE any previous
       
   323 		// Bind() or Connect() for the socket.
       
   324 		//
       
   325 		// [Alternate: if socket is explicitly bound or connected,
       
   326 		// do not accept HeaderIncluded, and return error?]
       
   327 		// Should the port ranges be checked here or not?
       
   328 		//
       
   329 		// The source address may still be unknown and will become
       
   330 		// known only after flow Open succeeds (watch out for
       
   331 		// iSockOutBuf buffering case--address becomes known in
       
   332 		// CanSend!)
       
   333 		iFlow.SetLocalAddr(aInfo.iSrcAddr);
       
   334 		iFlow.SetRemoteAddr(aInfo.iDstAddr);
       
   335 		}
       
   336 	else
       
   337 		{
       
   338 		// Packet is not using KIpHeaderIncluded.
       
   339 		if (aInfo.iDstAddr.Family())
       
   340 			{
       
   341 			// [Alternate: if socket is connected, do not accept explicit
       
   342 			// destination setting, and return error?]
       
   343 			// If aToAddr specified, then iDstAddr already includes a copy of it.
       
   344 			// Check port range
       
   345 			if (aInfo.iDstAddr.Port() < 1 || aInfo.iDstAddr.Port() > 65535)
       
   346 				{
       
   347 				return KErrGeneral;
       
   348 				}
       
   349 			iFlow.SetRemoteAddr(aInfo.iDstAddr);
       
   350 			}
       
   351 		}
       
   352 
       
   353 	const TInt status = aInfo.iFlow.Open(iFlow, &aInfo);
       
   354 	if (status == EFlow_READY)
       
   355 		{
       
   356 		// Flow is ready for send
       
   357 		//
       
   358 		// Build UDP header
       
   359 		FillUdpHeader(pkt, aPacket, aInfo, aOffset);
       
   360 		return KErrNone;
       
   361 		}
       
   362 	else if (status < 0)
       
   363 		return status;
       
   364 
       
   365 	// status > 0
       
   366 
       
   367 
       
   368 	// Block if the flow is blocked and application has requested synchronous send
       
   369 	// or if we're waiting for an interface to come up
       
   370 	//
       
   371 	if (iSynchSend || (status == EFlow_PENDING && Protocol()->WaitNif()))
       
   372 		{
       
   373 		if (aOffset == 0)
       
   374 			{
       
   375 			// Cancel the UDP header allocation.
       
   376 			aPacket.TrimStart(TInet6HeaderUDP::MinHeaderLength());
       
   377 			}
       
   378 		LOG(Log::Printf(_L("\tudp SAP[%u] Flow not ready (%d), BLOCKING the socket"), (TInt)this, status));
       
   379 		// The socket write will be blocked!
       
   380 		return status;
       
   381 		}
       
   382 
       
   383 	// Flow is not ready for sending, buffer the packet for a case where the flow
       
   384 	// becomes ready before the application sends another packet.
       
   385 	LOG(Log::Printf(_L("\tudp SAP[%u] Flow not ready (%d), BUFFER one packet"), (TInt) this, status));
       
   386 	aPacket.Pack();
       
   387 	iSockOutBuf.Assign(aPacket);
       
   388 	iSockOutOffset = aOffset;
       
   389 	return KErrNone;
       
   390 	}
       
   391 
       
   392 TInt CProviderUDP6::Recv(TDualBufPtr& aBuf, TUint aLength, TUint aOptions, TSockAddr* aAddr)
       
   393 	{
       
   394 //	LOG(Log::Printf(_L("CProviderUDP6::Recv(%d, %d)\r\n"), aLength, aOptions));
       
   395 	ASSERT(iSockFlags.iRecvClose == EFalse);
       
   396 
       
   397 	RMBufRecvPacket packet;
       
   398 	RMBufRecvInfo *info;
       
   399 	TInt off;
       
   400 
       
   401 
       
   402 	if (!iSockInQ.Remove(packet))
       
   403 		Panic(EInet6Panic_NoData);
       
   404 
       
   405 	info = packet.Unpack();
       
   406 	off = (/*iSockFlags.*/iRawMode || (aOptions & KIpHeaderIncluded)) ? 0 : info->iOffset;
       
   407 	aLength = Min(STATIC_CAST(TInt, aLength), info->iLength - off);
       
   408 
       
   409 	ASSERT(info->iLength == packet.Length());
       
   410 
       
   411 	// Get remote address
       
   412 	LOG(TBuf<70> tmp(_L("NULL")));
       
   413 	if (aAddr != NULL)
       
   414 		{
       
   415 		*aAddr = info->iSrcAddr;
       
   416 		LOG(TInetAddr::Cast(*aAddr).OutputWithScope(tmp));
       
   417 		if (iAppFamily == KAfInet)
       
   418 			TInetAddr::Cast(*aAddr).ConvertToV4();
       
   419 		}
       
   420 
       
   421 	if (aOptions & KSockReadPeek)
       
   422 		{
       
   423 		TInt err = aBuf.CopyIn(packet, off, aLength);
       
   424 		packet.Pack();
       
   425 		iSockInQ.Prepend(packet);
       
   426 		LOG(Log::Printf(_L("GetData\tudp SAP[%u] Peek len=%d err=%d from=%S, calling NewData(1)"), (TInt)this, aLength, err, &tmp));
       
   427 		iSocket->NewData(1);
       
   428 		if (err != KErrNone)
       
   429 			return KErrNoMBufs;
       
   430 		}
       
   431 	else
       
   432 		{
       
   433 		iSockInQLen -= info->iLength;
       
   434 		if (off > 0)
       
   435 			packet.TrimStart(off);
       
   436 		aBuf.Consume(packet, aLength, iBufAllocator);
       
   437 		packet.Free();
       
   438 		LOG(Log::Printf(_L("GetData\tudp SAP[%u] length=%d from=%S"), (TInt)this, aLength, &tmp));
       
   439 		}
       
   440 
       
   441 	return 1;
       
   442 	}
       
   443 
       
   444 
       
   445 void CProviderUDP6::Process(RMBufChain& aPacket, CProtocolBase* /*aSourceProtocol*/)
       
   446 	{
       
   447 	TUint length = 0;
       
   448 	RMBufRecvInfo *const info = RMBufRecvPacket::PeekInfoInChain(aPacket);
       
   449 	if (info)
       
   450 		{
       
   451 		length = info->iLength;
       
   452 
       
   453 		//
       
   454 		// ESock does not properly buffer multiple datagrams in the receive buffer,
       
   455 		// so we need to do it here. The worst part is that we don't know the size
       
   456 		// of the receive buffer requested by the application, because ESock does not
       
   457 		// pass the socket option to us. We use a TCPIP.INI parameter/Udp socket option instead.
       
   458 		//
       
   459 		if (iSockFlags.iRecvClose || !iSockFlags.iNotify ||
       
   460 			(!iSockInQ.IsEmpty() && iSockInQLen + length > iSockInBufSize))
       
   461 			{
       
   462 			LOG(Log::Printf(_L("\tudp SAP[%u] No space. Incoming packet DROPPED"), (TInt)this));
       
   463 			}
       
   464 		else
       
   465 			{
       
   466 			iSockInQLen += length;
       
   467 			iSockInQ.Append(aPacket);
       
   468 			LOG(Log::Printf(_L("\tudp SAP[%u] Packet queued, QLen=%d, calling NewData(1)"), (TInt)this, iSockInQLen));
       
   469 			iSocket->NewData(1);
       
   470 			return;
       
   471 			}
       
   472 		}
       
   473 	aPacket.Free();
       
   474 	}
       
   475 
       
   476 void CProviderUDP6::Error(TInt aError, TUint aOperationMask)
       
   477 	{
       
   478 	// Report errors by interrupting send and receive operations
       
   479 	aOperationMask &= MSocketNotify::EErrorSend|MSocketNotify::EErrorRecv;
       
   480 	CProviderInet6Transport::Error(aError, aOperationMask);
       
   481 
       
   482 	//
       
   483 	// Force the flow to reconnect on the next send, clearing the error state.
       
   484 	//
       
   485 	iFlow.FlowContext()->SetChanged();
       
   486 	}
       
   487 
       
   488 void CProviderUDP6::CanSend()
       
   489 	{
       
   490 
       
   491 	//
       
   492 	// Check flow status.
       
   493 	//
       
   494 	// Note: calling iFlow.Status() here also makes sure that a connect()
       
   495 	//       operation on the UDP socket will bring the flow up completely
       
   496 	//       without requiring the application to follow it up with a
       
   497 	//       send(). This is required by, e,g. the QoS framework.
       
   498 	//
       
   499 	TInt status;
       
   500 	if (iSockOutBuf.IsEmpty())
       
   501 		{
       
   502 		// No buffered packet.
       
   503 		status = iFlow.Status();
       
   504 		if (status == EFlow_READY)
       
   505 			{
       
   506 			LOG(Log::Printf(_L("\tudp SAP[%u] CanSend() Nothing buffered, flow ready, wakeup"), (TInt)this));
       
   507 			// Wake application
       
   508 			CProviderInet6Transport::CanSend();
       
   509 			return;
       
   510 			}
       
   511 		LOG(Log::Printf(_L("\tudp SAP[%u] CanSend() Nothing buffered, flow status %d"), (TInt)this, status));
       
   512 		}
       
   513 	else
       
   514 		{
       
   515 		// A packet is waiting for this!
       
   516 		RMBufSendInfo *info = iSockOutBuf.PeekInfo();
       
   517 		status = info->iFlow.Open(iFlow, info);
       
   518 		if (status == EFlow_READY)
       
   519 			{
       
   520 			RMBufSendPacket packet;
       
   521 			packet.Assign(iSockOutBuf);
       
   522 			packet.Unpack();
       
   523 			TInet6Checksum<TInet6HeaderUDP> pkt(packet, iSockOutOffset);
       
   524 			if (pkt.iHdr == NULL)
       
   525 				{
       
   526 				// Can happen if user uses KIpHeaderIncluded without UDP header, but
       
   527 				// may catch other unexpected problems with the RMBuf handling. In
       
   528 				// any case, this packet cannot be sent (no retries allowed).
       
   529 				LOG(Log::Printf(_L("CProviderUDP6::CanSend() Bad buffered UDP packet dropped")));
       
   530 				info->iFlow.Close();
       
   531 				packet.Free();
       
   532 				}
       
   533 			else
       
   534 				{
       
   535 				LOG(Log::Printf(_L("\tudp SAP[%u] CanSend() Sending buffered UDP packet"), (TInt)this));
       
   536 				FillUdpHeader(pkt, packet, *info, iSockOutOffset);
       
   537 				packet.Pack();
       
   538 				iProtocol->Send(packet);
       
   539 				}
       
   540 			// Note: When packet is buffered, then the SocketServer is not blocked
       
   541 			// on this socket. Thus, there is no need to call iSocket->Notify()!
       
   542 			return;
       
   543 			}
       
   544 		LOG(Log::Printf(_L("\tudp SAP[%u] CanSend() Buffered packet waiting, flow status %d"), (TInt)this, status));
       
   545 		}
       
   546 
       
   547 	if (status < 0)
       
   548 		{
       
   549 		Error(status, MSocketNotify::EErrorSend|MSocketNotify::EErrorRecv);
       
   550 		}
       
   551 	}