|
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 // in_trans.cpp - transport layer protocol base |
|
15 // |
|
16 |
|
17 #include "in_trans.h" |
|
18 #include "inet6log.h" |
|
19 |
|
20 #include <e32math.h> |
|
21 #include <comms-infras/nifif_internal.h> |
|
22 |
|
23 // speed optimisations |
|
24 #ifdef __ARMCC__ |
|
25 #pragma push |
|
26 #pragma arm |
|
27 #endif |
|
28 |
|
29 #define SYMBIAN_NETWORKING_UPS |
|
30 |
|
31 CProtocolInet6Transport::CProtocolInet6Transport() |
|
32 { |
|
33 // Initialize random seed value |
|
34 TTime currentTime; |
|
35 currentTime.HomeTime(); |
|
36 iSeed = currentTime.Int64() + User::TickCount(); |
|
37 } |
|
38 |
|
39 |
|
40 void CProtocolInet6Transport::InitL(TDesC& aTag) |
|
41 { |
|
42 CProtocolInet6Base::InitL(aTag); |
|
43 } |
|
44 |
|
45 |
|
46 void CProtocolInet6Transport::StartL() |
|
47 { |
|
48 CProtocolInet6Base::StartL(); |
|
49 } |
|
50 |
|
51 |
|
52 CProtocolInet6Transport::~CProtocolInet6Transport() |
|
53 { |
|
54 } |
|
55 |
|
56 |
|
57 TInt CProtocolInet6Transport::Send(RMBufChain& /*aPacket*/,CProtocolBase* /*aSourceProtocol=NULL*/) |
|
58 { |
|
59 Panic(EInet6Panic_NotSupported); |
|
60 return 0; |
|
61 } |
|
62 |
|
63 |
|
64 // |
|
65 // Bind request from a protocol above us |
|
66 // |
|
67 void CProtocolInet6Transport::BindL(CProtocolBase* /*aProtocol*/, TUint /*aId*/) |
|
68 { |
|
69 Panic(EInet6Panic_NotSupported); |
|
70 } |
|
71 |
|
72 |
|
73 // |
|
74 // Find SAP based on end-point addresses. |
|
75 // |
|
76 // This routine is rather involved, because it is used for a number of different |
|
77 // purposes. The routine returns a "best match" socket provider based on source |
|
78 // and destination socket addresses (IP address & port), or NULL if no mathing |
|
79 // provider is found (see below for an explanation on how matches are ranked). |
|
80 // |
|
81 // The method supports the following forms: |
|
82 // |
|
83 // o LocateProvider(minimum rank, local socket address); or |
|
84 // LocateProvider(minimum rank, local socket address, unspecified socket address); |
|
85 // |
|
86 // This form is used when binding a socket in order to check that the port is |
|
87 // not already in use. At least local port must be specified. Local address |
|
88 // may be unspecified. The first provider that matches the local port (and |
|
89 // local address, if given) is returned. |
|
90 // |
|
91 // o LocateProvider(minimum rank, local socket address, remote socket address); |
|
92 // |
|
93 // This form is used in order to locate the correct socket provider, when |
|
94 // a transport PDU has been received. For this use, the complete local |
|
95 // and remote addresses must be specified. |
|
96 // |
|
97 // Another use of this form is to verify the uniqueness of the source/destination |
|
98 // socket address pair when creating a new connection. This is only an issue if |
|
99 // the source port has been explicitly bound and local address reuse has been enabled. |
|
100 // In this case, the destination socket address MUST be unique among all connections |
|
101 // terminating in the same local socket address. |
|
102 // |
|
103 // Note: for the latter use, local IP address may be left unspecified. In this case, |
|
104 // it matches all addresses. Local port is mandatory. |
|
105 // |
|
106 // The minimum rank parameter specifies the minimum acceptable accuracy of the match. |
|
107 // The the match with the highest rank found is returned, or NULL if no match of |
|
108 // at least the requested rank is found. |
|
109 // |
|
110 // Matches are ranked as follows (highest rank first): |
|
111 // |
|
112 // EMatchExact or EMatchConnection: |
|
113 // |
|
114 // Both local and remote socket addresses match. Local IP address may be |
|
115 // unspecified, if the connection is waiting for a flow to become ready. |
|
116 // |
|
117 // This rank is only relevant if caller specified a remote address. |
|
118 // The returned socket provider handles a connected socket. |
|
119 // |
|
120 // EMatchServerSpecAddr: |
|
121 // |
|
122 // Local socket address matches and remote socket address is unspecified. |
|
123 // |
|
124 // This means that the returned socket provider handles a server socket |
|
125 // that has been bound to a specific local address. |
|
126 // |
|
127 // EMatchServerUnspecAddr: |
|
128 // |
|
129 // Local port matches. Local IP address is unspecified. Remote socket address |
|
130 // is unspecified. |
|
131 // |
|
132 // This means that the returned socket provider handles a server socket |
|
133 // that has been bound to an unspecified address. |
|
134 // |
|
135 // EMatchLocalPort: |
|
136 // |
|
137 // Local port must match. Local IP address or remote socket address are not tested. |
|
138 // |
|
139 // This means that the returned socket provider will conflict with an attempted |
|
140 // bind() if the KSoReuseAddr socket option is not used. |
|
141 // |
|
142 #ifndef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
143 CProviderInet6Transport* CProtocolInet6Transport::LocateSap(TProviderMatchEnum aRank, TUint aFamily, |
|
144 const TInetAddr& aLocalAddr, const TInetAddr& aRemoteAddr, CProviderInet6Base *aSap) |
|
145 #else |
|
146 CProviderInet6Transport* CProtocolInet6Transport::LocateSap(TProviderMatchEnum aRank, TUint aFamily, |
|
147 const TInetAddr& aLocalAddr, const TInetAddr& aRemoteAddr, CProviderInet6Base *aSap, |
|
148 TUint32 aSourceIfIndex) |
|
149 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
150 { |
|
151 ASSERT(aLocalAddr.Port() != KInetPortNone); |
|
152 |
|
153 CProviderInet6Transport *sapFound = NULL, *sap; |
|
154 TUint port = aLocalAddr.Port(); |
|
155 TProviderMatchEnum rank = (TProviderMatchEnum)(aRank-1); |
|
156 |
|
157 // CProtocolInet6Base::LocateProvider() puts us into the right hashed queue. |
|
158 for (sap = (CProviderInet6Transport *)(aSap != NULL ? aSap : CProtocolInet6Base::LocateProvider(port)); |
|
159 sap != NULL; sap = (CProviderInet6Transport *)sap->iNextSAP) |
|
160 { |
|
161 // If aSap non-NULL, return first match |
|
162 if (aSap != NULL && rank >= aRank) |
|
163 break; |
|
164 |
|
165 const TInetAddr& local = sap->iFlow.FlowContext()->LocalAddr(); |
|
166 if (port != local.Port()) |
|
167 continue; |
|
168 #ifdef SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
169 // In case of loopback no need to lock interface |
|
170 if(!aLocalAddr.IsLoopback()) |
|
171 { |
|
172 // Port matches this SAP, so if this SAP has an interface that it is |
|
173 // locked to, confirm the inbound packet is on that interface. That is, |
|
174 // if the SAP is locked to an interface, this code ensures that the |
|
175 // packet is only accepted if it is coming over the same interface |
|
176 // that the SAP is locked to. |
|
177 TScopeType scoping = sap->iFlow.FlowContext()->LockType(); |
|
178 TUint32 interfaceNum = sap->iFlow.FlowContext()->LockId(); |
|
179 |
|
180 // Check that the source interface index was supplied. Also check for lock id > 0. |
|
181 // If lock id > 0 this implies that the interface is locked down for this SAP. Also |
|
182 // ignore the magic value lock id of KNetworkIdFromAddress. |
|
183 if ((aSourceIfIndex > 0) && (interfaceNum > 0) && (interfaceNum != KNetworkIdFromAddress)) |
|
184 { |
|
185 // The sap currently being checked is locked to an interface. Check to |
|
186 // see what type of lock (scoping) it is. |
|
187 if (scoping == EScopeType_IF) |
|
188 { |
|
189 // This sap is locked to EScopeType_IF |
|
190 if (interfaceNum != aSourceIfIndex) |
|
191 { |
|
192 // Not the right interface, go to next SAP |
|
193 continue; |
|
194 } |
|
195 } |
|
196 else |
|
197 { |
|
198 // Not locked to EScopeType_IF, so now need the network ID and IAP number from the |
|
199 // interface, to check against one of those. Fetch this from the source interface |
|
200 // based on the interface index. |
|
201 const MInterface* iface = sap->iFlow.FlowContext()->Interfacer()->Interface(aSourceIfIndex); |
|
202 if (iface) |
|
203 { |
|
204 if (scoping == EScopeType_IAP) |
|
205 { |
|
206 // This sap is locked to EScopeType_IAP. Check if the source interface |
|
207 // is over the same IAP. |
|
208 TUint id = iface->Scope(EScopeType_IAP); |
|
209 if (id != interfaceNum) |
|
210 { |
|
211 // IAP does not match that required |
|
212 continue; |
|
213 } |
|
214 } |
|
215 else if (scoping == EScopeType_NET ) |
|
216 { |
|
217 // This sap is locked to EScopeType_NET. Check if the source interface |
|
218 // is over the same network ID. |
|
219 TUint id = iface->Scope(EScopeType_NET); |
|
220 if (id != interfaceNum) |
|
221 { |
|
222 // Network ID does not match that required |
|
223 continue; |
|
224 } |
|
225 } |
|
226 } |
|
227 } |
|
228 } |
|
229 } |
|
230 #endif //SYMBIAN_STRICT_EXPLICIT_SOCKET_BINDING |
|
231 |
|
232 const CFlowContext *const flow = sap->iFlow.FlowContext(); |
|
233 |
|
234 TBool localMatch = aLocalAddr.CmpAddr(local) && |
|
235 (aLocalAddr.Scope() == 0 || aLocalAddr.Scope() == local.Scope()); |
|
236 if (!sap->iSockFlags.iAddressSet || localMatch) |
|
237 { |
|
238 if (sap->iSockFlags.iConnected) |
|
239 { |
|
240 if (localMatch && aRemoteAddr.CmpAddr(flow->RemoteAddr()) |
|
241 && (aRemoteAddr.Scope() == 0 || aRemoteAddr.Scope() == flow->RemoteAddr().Scope())) |
|
242 { |
|
243 rank = EMatchExact; |
|
244 sapFound = sap; |
|
245 break; |
|
246 } |
|
247 } |
|
248 else |
|
249 { |
|
250 if (rank >= EMatchServerSpecAddr) |
|
251 continue; |
|
252 |
|
253 if (localMatch) |
|
254 { |
|
255 rank = EMatchServerSpecAddr; |
|
256 sapFound = sap; |
|
257 continue; |
|
258 } |
|
259 |
|
260 if (rank >= EMatchServerUnspecAddr) |
|
261 continue; |
|
262 |
|
263 if (sap->iSockFamily == aFamily || sap->iSockFamily == KAFUnspec || aFamily == KAFUnspec) |
|
264 { |
|
265 rank = EMatchServerUnspecAddr; |
|
266 sapFound = sap; |
|
267 continue; |
|
268 } |
|
269 } |
|
270 } |
|
271 |
|
272 if (rank >= EMatchLocalPort) |
|
273 continue; |
|
274 |
|
275 rank = EMatchLocalPort; |
|
276 sapFound = sap; |
|
277 } |
|
278 |
|
279 #ifdef _LOG |
|
280 TBuf<50> src, dst; |
|
281 //TBuf<50> src2, dst2; |
|
282 aLocalAddr.OutputWithScope(src); |
|
283 aRemoteAddr.OutputWithScope(dst); |
|
284 Log::Printf(_L("\t%S LocateProvider({%S,%d} <--> {%S,%d})"), |
|
285 &ProtocolName(), &src, port, &dst, aRemoteAddr.Port()); |
|
286 if (sapFound) |
|
287 { |
|
288 TBuf<50> src2, dst2; |
|
289 sapFound->iFlow.FlowContext()->LocalAddr().OutputWithScope(src2); |
|
290 sapFound->iFlow.FlowContext()->RemoteAddr().OutputWithScope(dst2); |
|
291 Log::Printf(_L("\t%S SAP[%u] found {%S,%d} <--> {%S,%d}, rank=%d, family=%x"), |
|
292 &ProtocolName(), (TInt)sapFound, |
|
293 &src2, port, &dst2, sapFound->iFlow.FlowContext()->RemotePort(), |
|
294 rank, aFamily); |
|
295 } |
|
296 else |
|
297 { |
|
298 Log::Printf(_L("\t%S SAP not found, best rank=%d, family=%x"), &ProtocolName(), rank, aFamily); |
|
299 } |
|
300 #endif |
|
301 |
|
302 return (CProviderInet6Transport *)sapFound; |
|
303 } |
|
304 |
|
305 #ifdef _LOG |
|
306 #include "tcp.h" |
|
307 void CProtocolInet6Transport::LogProviders(TUint aPort) |
|
308 { |
|
309 CProviderInet6Base *sap; |
|
310 TBool title = EFalse; |
|
311 |
|
312 for (sap = CProtocolInet6Base::LocateProvider(aPort); sap != NULL; sap = sap->iNextSAP) |
|
313 { |
|
314 if (aPort != sap->iFlow.FlowContext()->LocalPort()) |
|
315 continue; |
|
316 |
|
317 if (!title) |
|
318 { |
|
319 title = ETrue; |
|
320 Log::Printf(_L("Active TCBs on %S port %d:"), &ProtocolName(), aPort); |
|
321 } |
|
322 |
|
323 TBuf<50> src, dst; |
|
324 sap->iFlow.FlowContext()->LocalAddr().OutputWithScope(src); |
|
325 sap->iFlow.FlowContext()->RemoteAddr().OutputWithScope(dst); |
|
326 Log::Printf(_L("\t%S SAP[%u] {%S,%d} <--> {%S,%d} [reuse=%d] %s"), |
|
327 &ProtocolName(), (TInt)sap, |
|
328 &src, sap->iFlow.FlowContext()->LocalPort(), |
|
329 &dst, sap->iFlow.FlowContext()->RemotePort(), |
|
330 ((CProviderInet6Transport*)sap)->iSockFlags.iReuse, |
|
331 (sap->iFlow.FlowContext()->Protocol() == KProtocolInetTcp) ? |
|
332 ((CProviderTCP6*)sap)->TcpState() : _S("UDP")); |
|
333 } |
|
334 } |
|
335 #endif |
|
336 |
|
337 |
|
338 // |
|
339 // Pick a free port by random from the range [32768,61000]. |
|
340 // Random ephemeral port selection will help counter certain |
|
341 // types of attacks. |
|
342 // |
|
343 TUint CProtocolInet6Transport::AssignAutoPort() |
|
344 { |
|
345 TUint i, port = KInetMinAutoPort + Random(KInetMaxAutoPort - KInetMinAutoPort + 1); |
|
346 |
|
347 for (i = KInetMinAutoPort; i <= KInetMaxAutoPort; i++) |
|
348 { |
|
349 if (CProtocolInet6Base::LocateProvider(port) == NULL) |
|
350 return port; |
|
351 if (++port > KInetMaxAutoPort) |
|
352 port = KInetMinAutoPort; |
|
353 } |
|
354 return KInetPortNone; |
|
355 } |
|
356 |
|
357 |
|
358 TInt CProtocolInet6Transport::GetIniValue( const TDesC &aSection, |
|
359 const TDesC &aName, |
|
360 TInt aDefault, |
|
361 TInt aMin, |
|
362 TInt aMax, |
|
363 TBool aBoundMode) const |
|
364 /** |
|
365 Reads integer value for ini parameters from tcpip.ini file. |
|
366 |
|
367 @param aSection Section under which ini parameter belongs ([xxx] tag). |
|
368 @param aName Name of the ini parameter. |
|
369 @param aDefault Default value for the parameter, if not given in ini file. |
|
370 @param aMin Minimum limit for the parameter value. |
|
371 @param aMax Maximum limit for the parameter value. |
|
372 @param aBoundMode If ETrue, values that exceed min or max are truncated back to the min/max |
|
373 boundary. If EFalse, exceeding values are considered invalid, and default |
|
374 is used for those parameters. |
|
375 |
|
376 @return Integer value for the parameter. |
|
377 */ |
|
378 { |
|
379 LOG(_LIT(KFormat, "\t[%S] %S = %d")); |
|
380 LOG(_LIT(KFormatInv, "\t[%S] %S = %d is invalid")); |
|
381 |
|
382 TInt value; |
|
383 if (!Interfacer()->FindVar(aSection, aName, value)) |
|
384 { |
|
385 value = aDefault; |
|
386 } |
|
387 else |
|
388 { |
|
389 if (value < aMin) |
|
390 { |
|
391 LOG(Log::Printf(KFormatInv, &aSection, &aName, value)); |
|
392 value = aBoundMode ? aMin : aDefault; |
|
393 } |
|
394 else if (value > aMax) |
|
395 { |
|
396 LOG(Log::Printf(KFormatInv, &aSection, &aName, value)); |
|
397 value = aBoundMode ? aMax : aDefault; |
|
398 } |
|
399 } |
|
400 LOG(Log::Printf(KFormat, &aSection, &aName, value)); |
|
401 return value; |
|
402 } |
|
403 |
|
404 |
|
405 // |
|
406 // Transport Layer Socket Providers |
|
407 // |
|
408 |
|
409 CProviderInet6Transport::CProviderInet6Transport(CProtocolInet6Base *aProtocol) |
|
410 : CProviderInet6Base(aProtocol) |
|
411 { |
|
412 iSockFlags.iRecvClose = EFalse; |
|
413 iSockFlags.iSendClose = EFalse; |
|
414 iSockFlags.iConnected = EFalse; |
|
415 iSockFlags.iFlowStopped = EFalse; |
|
416 iSockFlags.iNotify = ETrue; |
|
417 iSockFlags.iReuse = EFalse; |
|
418 iSockFlags.iAttached = ETrue; |
|
419 // iSockFlags.iRawMode = EFalse; |
|
420 // iSockFlags.iHeaderIncluded = EFalse; |
|
421 iSockFamily = KAFUnspec; |
|
422 iAppFamily = KAFUnspec; |
|
423 } |
|
424 |
|
425 CProviderInet6Transport::~CProviderInet6Transport() |
|
426 { |
|
427 } |
|
428 |
|
429 |
|
430 void CProviderInet6Transport::LocalName(TSockAddr &aAddr) const |
|
431 { |
|
432 aAddr = iFlow.FlowContext()->LocalAddr(); |
|
433 if (iAppFamily == KAfInet) |
|
434 TInetAddr::Cast(aAddr).ConvertToV4(); |
|
435 } |
|
436 |
|
437 |
|
438 TInt CProviderInet6Transport::SetLocalName(TSockAddr &aAddr) |
|
439 { |
|
440 #ifdef _LOG |
|
441 TBuf<50> a; TInetAddr::Cast(aAddr).OutputWithScope(a); |
|
442 LOG(Log::Printf(_L("\t%S SAP[%u] SetLocalName({%S,%d}) [reuse=%d]"), |
|
443 &ProtocolName(), (TInt)this, |
|
444 &a, aAddr.Port(), iSockFlags.iReuse)); |
|
445 #endif |
|
446 |
|
447 LOG(((CProtocolInet6Transport*)iProtocol)->LogProviders(aAddr.Port())); |
|
448 |
|
449 TInetAddr addr = aAddr; |
|
450 |
|
451 // Bound already? |
|
452 if (iFlow.FlowContext()->LocalPort() != KInetPortNone) |
|
453 return KErrAlreadyExists; |
|
454 |
|
455 // Convert an IPv4 address to a V4 Mapped IPv6 address |
|
456 if (addr.Family() == KAfInet) |
|
457 addr.ConvertToV4Mapped(); |
|
458 |
|
459 // Check source address |
|
460 if (addr.Family() != KAFUnspec) |
|
461 { |
|
462 iSockFamily = addr.IsV4Mapped() ? KAfInet : KAfInet6; |
|
463 if (!addr.IsUnspecified()) |
|
464 { |
|
465 if (addr.Scope() == 0) |
|
466 { |
|
467 // Check address and pick a default scope id |
|
468 addr.SetScope(iProtocol->Interfacer()->LocalScope(addr.Ip6Address(), |
|
469 iFlow.FlowContext()->LockId(), iFlow.FlowContext()->LockType())); |
|
470 if (addr.Scope() == 0) |
|
471 return KErrNotFound; |
|
472 } |
|
473 else |
|
474 { |
|
475 // Check scoped address |
|
476 if (addr.Scope() != iProtocol->Interfacer()->LocalScope(addr.Ip6Address(), |
|
477 addr.Scope(), (TScopeType)(addr.Ip6Address().Scope() - 1))) |
|
478 return KErrNotFound; |
|
479 } |
|
480 } |
|
481 } |
|
482 |
|
483 // Autobind requested? |
|
484 if (addr.Port() == KInetPortNone) |
|
485 { |
|
486 addr.SetPort(((CProtocolInet6Transport*)iProtocol)->AssignAutoPort()); |
|
487 if (addr.Port() == KInetPortNone) |
|
488 return KErrInUse; |
|
489 } |
|
490 else |
|
491 { |
|
492 if (addr.Port() > 65535) |
|
493 return KErrTooBig; |
|
494 |
|
495 if (!iSockFlags.iReuse && Protocol()->LocateSap(EMatchLocalPort, aAddr.Family(), addr)) |
|
496 return KErrInUse; |
|
497 } |
|
498 |
|
499 iAppFamily = aAddr.Family(); // aAddr here to get the original family |
|
500 CProviderInet6Base::SetLocalName(addr); |
|
501 iSockFlags.iAddressSet = iFlow.FlowContext()->IsLocalSet(); |
|
502 iProtocol->BindProvider(this); |
|
503 return KErrNone; |
|
504 } |
|
505 |
|
506 void CProviderInet6Transport::RemName(TSockAddr &aAddr) const |
|
507 { |
|
508 aAddr = iFlow.FlowContext()->RemoteAddr(); |
|
509 if (iAppFamily == KAfInet) |
|
510 TInetAddr::Cast(aAddr).ConvertToV4(); |
|
511 } |
|
512 |
|
513 |
|
514 TInt CProviderInet6Transport::SetRemName(TSockAddr &aAddr) |
|
515 { |
|
516 //__ASSERT_DEBUG(!iSockFlags.iConnected && iFlow.FlowContext()->RemoteAddr().IsUnspecified() && iFlow.FlowContext()->RemotePort() == KInetPortNone, |
|
517 // Panic(EInet6Panic_NotSupported)); |
|
518 TInetAddr addr = aAddr; |
|
519 |
|
520 #ifdef _LOG |
|
521 TBuf<50> a; addr.OutputWithScope(a); |
|
522 LOG(Log::Printf(_L("\t%S SAP[%u] SetRemName({%S,%d})"), &ProtocolName(), (TInt)this, &a, addr.Port());) |
|
523 #endif |
|
524 TUint port = addr.Port(); |
|
525 if (port < 1) |
|
526 return KErrGeneral; |
|
527 else if (port > 65535) |
|
528 return KErrTooBig; |
|
529 |
|
530 if (addr.IsUnspecified()) |
|
531 return KErrBadName; |
|
532 |
|
533 if (addr.Family() == KAfInet) |
|
534 addr.ConvertToV4Mapped(); |
|
535 |
|
536 TInt family = addr.IsV4Mapped() ? KAfInet : KAfInet6; |
|
537 |
|
538 if(iSockFamily == KAFUnspec) |
|
539 iSockFamily = family; |
|
540 else if (iSockFamily != family) |
|
541 return KErrBadName; |
|
542 |
|
543 iFlow.SetRemoteAddr(addr); |
|
544 iAppFamily = aAddr.Family(); |
|
545 |
|
546 iSockFlags.iConnected = ETrue; |
|
547 return KErrNone; |
|
548 } |
|
549 |
|
550 |
|
551 void CProviderInet6Transport::AutoBind() |
|
552 { |
|
553 //__ASSERT_DEBUG(iFlow.FlowContext()->LocalPort()==KInetPortNone, Panic(EInet6Panic_BadBind)); |
|
554 TInetAddr localAddr; |
|
555 |
|
556 // Socket is already bound? |
|
557 if (iFlow.FlowContext()->LocalPort()!=KInetPortNone) |
|
558 return; |
|
559 |
|
560 localAddr.SetPort(((CProtocolInet6Transport *)iProtocol)->AssignAutoPort()); |
|
561 if (localAddr.Port()==KInetPortNone) |
|
562 { |
|
563 Error(KErrInUse); |
|
564 return; |
|
565 } |
|
566 |
|
567 iFlow.SetLocalAddr(localAddr); |
|
568 |
|
569 #ifdef _LOG |
|
570 TBuf<50> addr; iFlow.FlowContext()->LocalAddr().OutputWithScope(addr); |
|
571 Log::Printf(_L("\t%S SAP[%u] AutoBind() --> {%S,%d}"), &ProtocolName(), (TInt)this, &addr, iFlow.FlowContext()->LocalPort()); |
|
572 #endif |
|
573 |
|
574 iProtocol->BindProvider(this); |
|
575 } |
|
576 |
|
577 TInt CProviderInet6Transport::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption) |
|
578 { |
|
579 TInt ret = KErrNotSupported; |
|
580 |
|
581 if (aLevel == KSolInetIp && aName == KSoReuseAddr) |
|
582 { |
|
583 TInt intValue; |
|
584 ret = GetOptionInt(aOption, intValue); |
|
585 if (ret == KErrNone) |
|
586 iSockFlags.iReuse = intValue ? TRUE : FALSE; |
|
587 #ifdef _LOG |
|
588 Log::Printf(_L("SetOpt\t%S SAP[%u] KSoReuseAddr = %d err=%d"), |
|
589 &ProtocolName(), (TInt)this, (TInt)iSockFlags.iReuse, ret); |
|
590 #endif |
|
591 } |
|
592 |
|
593 if (ret == KErrNotSupported) |
|
594 ret = CProviderInet6Base::SetOption(aLevel, aName, aOption); |
|
595 |
|
596 #ifdef SYMBIAN_NETWORKING_UPS |
|
597 if (ret == KErrNone && aLevel == KSOLProvider && aName == (TUint) KSoConnectionInfo) |
|
598 { |
|
599 iConnectionInfoReceived = 1; |
|
600 } |
|
601 #endif |
|
602 |
|
603 return ret; |
|
604 } |
|
605 |
|
606 |
|
607 TInt CProviderInet6Transport::GetOption(TUint aLevel, TUint aName, TDes8& aOption) const |
|
608 { |
|
609 TInt ret = KErrNotSupported; |
|
610 |
|
611 if (aLevel == KSolInetIp && aName == KSoReuseAddr) |
|
612 ret = SetOptionInt(aOption, iSockFlags.iReuse); |
|
613 |
|
614 if (ret == KErrNotSupported) |
|
615 ret = CProviderInet6Base::GetOption(aLevel, aName, aOption); |
|
616 |
|
617 return ret; |
|
618 } |
|
619 |
|
620 void CProviderInet6Transport::CanSend() |
|
621 { |
|
622 LOG(Log::Printf(_L("\t%S SAP[%u] CanSend()"), &ProtocolName(), (TInt)this)); |
|
623 // Do not enable data flow if the protocol doesn't want it. |
|
624 if(!iSockFlags.iFlowStopped && iSockFlags.iNotify) |
|
625 CProviderInet6Base::CanSend(); |
|
626 } |
|
627 |
|
628 void CProviderInet6Transport::Error(TInt aError, TUint aOperationMask) |
|
629 { |
|
630 if (iSockFlags.iNotify) |
|
631 CProviderInet6Base::Error(aError, aOperationMask); |
|
632 if (FatalState()) |
|
633 iSockFlags.iNotify = EFalse; |
|
634 } |
|
635 |
|
636 void CProviderInet6Transport::IcmpError(TInt aError, TUint aOperationMask, TInt aType, TInt aCode, |
|
637 const TInetAddr& aSrcAddr, const TInetAddr& aDstAddr, const TInetAddr& aErrAddr) |
|
638 { |
|
639 CProviderInet6Base::SaveIcmpError(aType, aCode, aSrcAddr, aDstAddr, aErrAddr); |
|
640 if (iAppFamily == KAfInet) |
|
641 { |
|
642 iLastError.iSrcAddr.ConvertToV4(); |
|
643 iLastError.iDstAddr.ConvertToV4(); |
|
644 iLastError.iErrAddr.ConvertToV4(); |
|
645 } |
|
646 |
|
647 if (iSockFlags.iReportIcmp && aError != KErrNone) |
|
648 Error(aError, aOperationMask); |
|
649 } |
|
650 |
|
651 #ifdef SYMBIAN_NETWORKING_UPS |
|
652 TBool CProviderInet6Transport::ConnectionInfoSet() |
|
653 { |
|
654 return static_cast<TBool>(iConnectionInfoReceived); |
|
655 } |
|
656 |
|
657 |
|
658 TBool CProviderInet6Transport::HasSocket() |
|
659 { |
|
660 if (iSocket == NULL) |
|
661 { |
|
662 return EFalse; |
|
663 } |
|
664 else |
|
665 { |
|
666 return ETrue; |
|
667 } |
|
668 } |
|
669 |
|
670 void *CProviderInet6Transport::GetApiL(const TDesC8& aApiName, TUint* aVersion) |
|
671 { |
|
672 if (aApiName == _L8("MProviderBindings")) |
|
673 { |
|
674 return EXPORT_API_L(MProviderBindings, static_cast<MProviderBindings*>(this), aVersion); |
|
675 } |
|
676 |
|
677 return NULL; |
|
678 } |
|
679 #endif |
|
680 |
|
681 void RMBufSockQ::AppendL(const TDesC8& aData, TInt aLen) |
|
682 { |
|
683 if (aLen <= 0) |
|
684 return; |
|
685 |
|
686 RMBufChain seg; |
|
687 seg.AllocL(aLen); |
|
688 seg.CopyIn(aData); |
|
689 RMBufChain::Append(seg); |
|
690 } |
|
691 |
|
692 TInt RMBufSockQ::AppendDes(const TDesC8& aData, TInt aLen) |
|
693 { |
|
694 if (aLen <= 0) |
|
695 return KErrNone; |
|
696 |
|
697 RMBufChain seg; |
|
698 TInt err = seg.Alloc(aLen); |
|
699 if(err == KErrNone) |
|
700 { |
|
701 seg.CopyIn(aData); |
|
702 RMBufChain::Append(seg); |
|
703 } |
|
704 return err; |
|
705 } |
|
706 |
|
707 |
|
708 // |
|
709 // Append at least aLength bytes from aChain. |
|
710 // Leave the remainder in aChain. Return number |
|
711 // of bytes removed from aChain. |
|
712 // |
|
713 TInt RMBufSockQ::AppendAtLeast(RMBufChain& aChain, TInt aLength) |
|
714 { |
|
715 TInt o, n; |
|
716 RMBuf* m, *p; |
|
717 |
|
718 if (!aChain.Goto(aLength, m, o, n, p)) |
|
719 { |
|
720 aLength = aChain.Length(); |
|
721 RMBufChain::Append(aChain); |
|
722 return aLength; |
|
723 } |
|
724 |
|
725 if (o != m->Offset()) |
|
726 { |
|
727 p = m; |
|
728 m = m->Next(); |
|
729 aLength += n; |
|
730 } |
|
731 |
|
732 p->Unlink(); |
|
733 RMBufChain::Append(aChain); |
|
734 aChain = m; |
|
735 |
|
736 return aLength; |
|
737 } |
|
738 |
|
739 // |
|
740 // Remove at most aLength bytes from the queue. |
|
741 // Place the result in aChain. Return number |
|
742 // of bytes removed from the queue. |
|
743 // |
|
744 TInt RMBufSockQ::RemoveAtMost(RMBufChain& aChain, TInt aLength) |
|
745 { |
|
746 TInt o, n; |
|
747 RMBuf* m, *p; |
|
748 |
|
749 if (aLength <= 0 || iNext == NULL) |
|
750 return 0; |
|
751 |
|
752 if (!Goto(aLength, m, o, n, p)) |
|
753 { |
|
754 aChain = iNext; |
|
755 iNext = NULL; |
|
756 return aChain.Length(); |
|
757 } |
|
758 |
|
759 p->Unlink(); |
|
760 aChain = iNext; |
|
761 iNext = m; |
|
762 |
|
763 return aLength + m->Offset() - o; |
|
764 } |
|
765 |
|
766 // |
|
767 // Copy aLength bytes from aQueue at aOffset |
|
768 // |
|
769 void TDualBufPtr::CopyInL(const RMBufChain& aQueue, TInt aOffset, TInt aLength) |
|
770 { |
|
771 switch(iType) |
|
772 { |
|
773 case ERMBufChain: |
|
774 if (aLength > 0) |
|
775 aQueue.CopyL(*iChain, aOffset, aLength); |
|
776 break; |
|
777 |
|
778 case EDes8: |
|
779 iDesc->SetLength(aLength); |
|
780 if (aLength > 0) |
|
781 aQueue.CopyOut(*iDesc, aOffset); |
|
782 break; |
|
783 |
|
784 default: |
|
785 Panic(EInet6Panic_NotSupported); |
|
786 } |
|
787 } |
|
788 |
|
789 // |
|
790 // Copy aLength bytes from aQueue at aOffset |
|
791 // |
|
792 TInt TDualBufPtr::CopyIn(const RMBufChain& aQueue, TInt aOffset, TInt aLength) |
|
793 { |
|
794 switch(iType) |
|
795 { |
|
796 case ERMBufChain: |
|
797 if (aLength > 0) |
|
798 return aQueue.Copy(*iChain, aOffset, aLength); |
|
799 break; |
|
800 |
|
801 case EDes8: |
|
802 iDesc->SetLength(aLength); |
|
803 if (aLength > 0) |
|
804 aQueue.CopyOut(*iDesc, aOffset); |
|
805 break; |
|
806 |
|
807 default: |
|
808 Panic(EInet6Panic_NotSupported); |
|
809 } |
|
810 return KErrNone; |
|
811 } |
|
812 |
|
813 // |
|
814 // Copy into aChain at aOffset |
|
815 // |
|
816 void TDualBufPtr::CopyOut(RMBufChain& aChain, TInt aOffset) const |
|
817 { |
|
818 switch(iType) |
|
819 { |
|
820 case EDes8: |
|
821 case EDesC8: |
|
822 aChain.CopyIn(*iDesc, aOffset); |
|
823 break; |
|
824 |
|
825 default: |
|
826 Panic(EInet6Panic_NotSupported); |
|
827 } |
|
828 } |
|
829 |
|
830 // |
|
831 // Remove aLength bytes from the beginning of aQueue. |
|
832 // |
|
833 TInt TDualBufPtr::Consume(RMBufChain& aQueue, TInt aLength, RMBufAllocator& aAllocator) |
|
834 { |
|
835 RMBufChain tail; |
|
836 TInt err; |
|
837 |
|
838 switch(iType) |
|
839 { |
|
840 case ERMBufChain: |
|
841 if (aLength > 0) |
|
842 { |
|
843 err = aQueue.Split(aLength, tail, aAllocator); |
|
844 if (err == KErrNone) |
|
845 { |
|
846 iChain->Assign(aQueue); |
|
847 aQueue.Assign(tail); |
|
848 } |
|
849 else |
|
850 { |
|
851 aLength = RMBufSockQ::Cast(aQueue).RemoveAtMost(*iChain, aLength); |
|
852 LOG(Log::Printf(_L("TDualBufPtr::Consume(): Alloc problem. Returning less"))); |
|
853 } |
|
854 } |
|
855 break; |
|
856 |
|
857 case EDes8: |
|
858 iDesc->SetLength(aLength); |
|
859 if (aLength > 0) |
|
860 { |
|
861 aQueue.CopyOut(*iDesc); |
|
862 aQueue.TrimStart(aLength); |
|
863 } |
|
864 break; |
|
865 |
|
866 default: |
|
867 Panic(EInet6Panic_NoData); |
|
868 } |
|
869 return aLength; |
|
870 } |
|
871 |
|
872 // |
|
873 // Append at least aLength bytes to aQueue |
|
874 // |
|
875 TInt TDualBufPtr::AppendL(RMBufChain& aQueue, TInt aLength) |
|
876 { |
|
877 switch(iType) |
|
878 { |
|
879 case ERMBufChain: |
|
880 aLength = RMBufSockQ::Cast(aQueue).AppendAtLeast(*iChain, aLength); |
|
881 break; |
|
882 |
|
883 case EDes8: |
|
884 case EDesC8: |
|
885 RMBufSockQ::Cast(aQueue).AppendL(*iDesc, aLength); |
|
886 break; |
|
887 |
|
888 default: |
|
889 Panic(EInet6Panic_NoData); |
|
890 } |
|
891 |
|
892 return aLength; |
|
893 } |
|
894 |
|
895 // |
|
896 // Append at least aLength bytes to aQueue. Panics if used with des-tyoe |
|
897 // |
|
898 TInt TDualBufPtr::Append(RMBufChain& aQueue, TInt aLength) |
|
899 { |
|
900 switch(iType) |
|
901 { |
|
902 case ERMBufChain: |
|
903 aLength = RMBufSockQ::Cast(aQueue).AppendAtLeast(*iChain, aLength); |
|
904 break; |
|
905 |
|
906 default: |
|
907 Panic(EInet6Panic_NoData); |
|
908 } |
|
909 |
|
910 return aLength; |
|
911 } |
|
912 |
|
913 // |
|
914 // Free buffer |
|
915 // |
|
916 void TDualBufPtr::Free() |
|
917 { |
|
918 switch(iType) |
|
919 { |
|
920 case ERMBufChain: |
|
921 iChain->Free(); |
|
922 break; |
|
923 |
|
924 case EDes8: |
|
925 iDesc->SetLength(0); |
|
926 break; |
|
927 |
|
928 default: |
|
929 Panic(EInet6Panic_NoData); |
|
930 } |
|
931 } |
|
932 |
|
933 #ifdef __ARMCC__ |
|
934 #pragma pop |
|
935 #endif |