|
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 } |