3 * Copyright (c) 2020-2021 Project CHIP Authors
4 * Copyright (c) 2018 Google LLC.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * This header file implements the <tt>Inet::IPEndPointBasis</tt>
22 * class, an intermediate, non-instantiable basis class
23 * supporting other IP-based end points.
27 // define to ensure we have the IPV6_PKTINFO
28 #define __APPLE_USE_RFC_3542
30 #include "IPEndPointBasis.h"
35 #include <inet/EndPointBasis.h>
36 #include <inet/InetInterface.h>
37 #include <inet/InetLayer.h>
39 #include <support/CodeUtils.h>
40 #include <support/SafeInt.h>
42 #if CHIP_SYSTEM_CONFIG_USE_LWIP
43 #if INET_CONFIG_ENABLE_IPV4
44 #include <lwip/igmp.h>
45 #endif // INET_CONFIG_ENABLE_IPV4
46 #include <lwip/init.h>
48 #include <lwip/mld6.h>
49 #include <lwip/netif.h>
52 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
54 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
57 #include <netinet/in.h>
58 #include <sys/ioctl.h>
59 #include <sys/socket.h>
62 #include <sys/socket.h>
63 #endif // HAVE_SYS_SOCKET_H
66 * Some systems define both IPV6_{ADD,DROP}_MEMBERSHIP and
67 * IPV6_{JOIN,LEAVE}_GROUP while others only define
68 * IPV6_{JOIN,LEAVE}_GROUP. Prefer the "_MEMBERSHIP" flavor for
69 * parallelism with IPv4 and create the alias to the availabile
72 #if defined(IPV6_ADD_MEMBERSHIP)
73 #define INET_IPV6_ADD_MEMBERSHIP IPV6_ADD_MEMBERSHIP
74 #elif defined(IPV6_JOIN_GROUP)
75 #define INET_IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
78 "Neither IPV6_ADD_MEMBERSHIP nor IPV6_JOIN_GROUP are defined which are required for generalized IPv6 multicast group support."
79 #endif // IPV6_ADD_MEMBERSHIP
81 #if defined(IPV6_DROP_MEMBERSHIP)
82 #define INET_IPV6_DROP_MEMBERSHIP IPV6_DROP_MEMBERSHIP
83 #elif defined(IPV6_LEAVE_GROUP)
84 #define INET_IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
87 "Neither IPV6_DROP_MEMBERSHIP nor IPV6_LEAVE_GROUP are defined which are required for generalized IPv6 multicast group support."
88 #endif // IPV6_DROP_MEMBERSHIP
89 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
91 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
92 #define INET_PORTSTRLEN 6
93 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
95 #if CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
96 #include "ZephyrSocket.h"
97 #endif // CHIP_SYSTEM_CONFIG_USE_ZEPHYR_SOCKET_EXTENSIONS
102 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
109 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
111 #if CHIP_SYSTEM_CONFIG_USE_LWIP
112 #if INET_CONFIG_ENABLE_IPV4
113 #define LWIP_IPV4_ADDR_T ip4_addr_t
114 #define IPV4_TO_LWIPADDR(aAddress) (aAddress).ToIPv4()
115 #endif // INET_CONFIG_ENABLE_IPV4
116 #define LWIP_IPV6_ADDR_T ip6_addr_t
117 #define IPV6_TO_LWIPADDR(aAddress) (aAddress).ToIPv6()
119 #if !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || \
120 !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags)
121 #define HAVE_LWIP_MULTICAST_LOOP 0
123 #define HAVE_LWIP_MULTICAST_LOOP 1
124 #endif // !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) ||
125 // !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags)
126 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
128 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
129 static INET_ERROR CheckMulticastGroupArgs(InterfaceId aInterfaceId, const IPAddress & aAddress)
131 INET_ERROR lRetval = INET_NO_ERROR;
132 bool lIsPresent, lIsMulticast;
134 lIsPresent = IsInterfaceIdPresent(aInterfaceId);
135 VerifyOrExit(lIsPresent, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
137 lIsMulticast = aAddress.IsMulticast();
138 VerifyOrExit(lIsMulticast, lRetval = INET_ERROR_WRONG_ADDRESS_TYPE);
143 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
145 #if CHIP_SYSTEM_CONFIG_USE_LWIP
146 #if INET_CONFIG_ENABLE_IPV4
147 #if LWIP_IPV4 && LWIP_IGMP
148 static INET_ERROR LwIPIPv4JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress,
149 err_t (*aMethod)(struct netif *, const LWIP_IPV4_ADDR_T *))
151 INET_ERROR lRetval = INET_NO_ERROR;
153 struct netif * lNetif;
154 LWIP_IPV4_ADDR_T lIPv4Address;
156 lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId);
157 VerifyOrExit(lNetif != NULL, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
159 lIPv4Address = IPV4_TO_LWIPADDR(aAddress);
161 lStatus = aMethod(lNetif, &lIPv4Address);
167 lRetval = INET_ERROR_NO_MEMORY;
171 lRetval = chip::System::MapErrorLwIP(lStatus);
178 #endif // LWIP_IPV4 && LWIP_IGMP
179 #endif // INET_CONFIG_ENABLE_IPV4
181 // unusual define check for LWIP_IPV6_ND is because espressif fork
182 // of LWIP does not define the _ND constant.
183 #if LWIP_IPV6_MLD && (!defined(LWIP_IPV6_ND) || LWIP_IPV6_ND) && LWIP_IPV6
184 #define HAVE_IPV6_MULTICAST
186 // Within Project CHIP multicast support is highly desirable: used for mDNS
187 // as well as group communication.
188 #undef HAVE_IPV6_MULTICAST
191 #ifdef HAVE_IPV6_MULTICAST
192 static INET_ERROR LwIPIPv6JoinLeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress,
193 err_t (*aMethod)(struct netif *, const LWIP_IPV6_ADDR_T *))
195 INET_ERROR lRetval = INET_NO_ERROR;
197 struct netif * lNetif;
198 LWIP_IPV6_ADDR_T lIPv6Address;
200 lNetif = IPEndPointBasis::FindNetifFromInterfaceId(aInterfaceId);
201 VerifyOrExit(lNetif != NULL, lRetval = INET_ERROR_UNKNOWN_INTERFACE);
203 lIPv6Address = IPV6_TO_LWIPADDR(aAddress);
205 lStatus = aMethod(lNetif, &lIPv6Address);
211 lRetval = INET_ERROR_NO_MEMORY;
215 lRetval = chip::System::MapErrorLwIP(lStatus);
222 #endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
223 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
225 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
226 #if IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP
227 static INET_ERROR SocketsSetMulticastLoopback(int aSocket, bool aLoopback, int aProtocol, int aOption)
229 INET_ERROR lRetval = INET_NO_ERROR;
231 unsigned int lValue = aLoopback;
233 lStatus = setsockopt(aSocket, aProtocol, aOption, &lValue, sizeof(lValue));
234 VerifyOrExit(lStatus == 0, lRetval = chip::System::MapErrorPOSIX(errno));
239 #endif // IP_MULTICAST_LOOP || IPV6_MULTICAST_LOOP
241 static INET_ERROR SocketsSetMulticastLoopback(int aSocket, IPVersion aIPVersion, bool aLoopback)
243 #ifdef IPV6_MULTICAST_LOOP
250 lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IPV6, IPV6_MULTICAST_LOOP);
253 #if INET_CONFIG_ENABLE_IPV4
255 lRetval = SocketsSetMulticastLoopback(aSocket, aLoopback, IPPROTO_IP, IP_MULTICAST_LOOP);
257 #endif // INET_CONFIG_ENABLE_IPV4
260 lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
265 #else // IPV6_MULTICAST_LOOP
266 return INET_ERROR_NOT_SUPPORTED;
267 #endif // IPV6_MULTICAST_LOOP
270 #if INET_CONFIG_ENABLE_IPV4
271 static INET_ERROR SocketsIPv4JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress,
274 INET_ERROR lRetval = INET_NO_ERROR;
275 IPAddress lInterfaceAddress;
276 bool lInterfaceAddressFound = false;
277 struct ip_mreq lMulticastRequest;
279 for (InterfaceAddressIterator lAddressIterator; lAddressIterator.HasCurrent(); lAddressIterator.Next())
281 const IPAddress lCurrentAddress = lAddressIterator.GetAddress();
283 if (lAddressIterator.GetInterface() == aInterfaceId)
285 if (lCurrentAddress.IsIPv4())
287 lInterfaceAddressFound = true;
288 lInterfaceAddress = lCurrentAddress;
294 VerifyOrExit(lInterfaceAddressFound, lRetval = INET_ERROR_ADDRESS_NOT_FOUND);
296 memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
297 lMulticastRequest.imr_interface = lInterfaceAddress.ToIPv4();
298 lMulticastRequest.imr_multiaddr = aAddress.ToIPv4();
300 lRetval = setsockopt(aSocket, IPPROTO_IP, aCommand, &lMulticastRequest, sizeof(lMulticastRequest));
301 VerifyOrExit(lRetval == 0, lRetval = chip::System::MapErrorPOSIX(errno));
306 #endif // INET_CONFIG_ENABLE_IPV4
308 #if INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP
309 static INET_ERROR SocketsIPv6JoinLeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress,
312 INET_ERROR lRetval = INET_NO_ERROR;
313 const unsigned int lIfIndex = static_cast<unsigned int>(aInterfaceId);
314 struct ipv6_mreq lMulticastRequest;
316 // Check whether that cast we did was actually safe. We can't VerifyOrExit
317 // before declaring variables, and can't reassign lIfIndex without making it
318 // non-const, so have to do things in this order.
319 VerifyOrExit(CanCastTo<unsigned int>(aInterfaceId), lRetval = INET_ERROR_UNEXPECTED_EVENT);
321 memset(&lMulticastRequest, 0, sizeof(lMulticastRequest));
322 VerifyOrExit(CanCastTo<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex), lRetval = INET_ERROR_UNEXPECTED_EVENT);
324 lMulticastRequest.ipv6mr_interface = static_cast<decltype(lMulticastRequest.ipv6mr_interface)>(lIfIndex);
325 lMulticastRequest.ipv6mr_multiaddr = aAddress.ToIPv6();
327 lRetval = setsockopt(aSocket, IPPROTO_IPV6, aCommand, &lMulticastRequest, sizeof(lMulticastRequest));
328 VerifyOrExit(lRetval == 0, lRetval = chip::System::MapErrorPOSIX(errno));
333 #endif // INET_IPV6_ADD_MEMBERSHIP || INET_IPV6_DROP_MEMBERSHIP
335 static INET_ERROR SocketsIPv6JoinMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress)
337 #if INET_IPV6_ADD_MEMBERSHIP
338 return SocketsIPv6JoinLeaveMulticastGroup(aSocket, aInterfaceId, aAddress, INET_IPV6_ADD_MEMBERSHIP);
340 return INET_ERROR_NOT_SUPPORTED;
344 static INET_ERROR SocketsIPv6LeaveMulticastGroup(int aSocket, InterfaceId aInterfaceId, const IPAddress & aAddress)
346 #if INET_IPV6_DROP_MEMBERSHIP
347 return SocketsIPv6JoinLeaveMulticastGroup(aSocket, aInterfaceId, aAddress, INET_IPV6_DROP_MEMBERSHIP);
349 return INET_ERROR_NOT_SUPPORTED;
353 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
356 * @brief Set whether IP multicast traffic should be looped back.
358 * @param[in] aIPVersion
360 * @param[in] aLoopback
362 * @retval INET_NO_ERROR
363 * success: multicast loopback behavior set
365 * another system or platform error
368 * Set whether or not IP multicast traffic should be looped back
372 INET_ERROR IPEndPointBasis::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback)
374 INET_ERROR lRetval = INET_ERROR_NOT_IMPLEMENTED;
376 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
377 #if CHIP_SYSTEM_CONFIG_USE_LWIP
378 #if !HAVE_LWIP_MULTICAST_LOOP
379 lRetval = INET_ERROR_NOT_SUPPORTED;
383 switch (mLwIPEndPointType)
386 #if INET_CONFIG_ENABLE_RAW_ENDPOINT
387 case kLwIPEndPointType_Raw:
388 raw_set_flags(mRaw, RAW_FLAGS_MULTICAST_LOOP);
390 #endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
392 #if INET_CONFIG_ENABLE_UDP_ENDPOINT
393 case kLwIPEndPointType_UDP:
394 udp_set_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP);
396 #endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
399 lRetval = INET_ERROR_NOT_SUPPORTED;
405 switch (mLwIPEndPointType)
408 #if INET_CONFIG_ENABLE_RAW_ENDPOINT
409 case kLwIPEndPointType_Raw:
410 raw_clear_flags(mRaw, RAW_FLAGS_MULTICAST_LOOP);
412 #endif // INET_CONFIG_ENABLE_RAW_ENDPOINT
414 #if INET_CONFIG_ENABLE_UDP_ENDPOINT
415 case kLwIPEndPointType_UDP:
416 udp_clear_flags(mUDP, UDP_FLAGS_MULTICAST_LOOP);
418 #endif // INET_CONFIG_ENABLE_UDP_ENDPOINT
421 lRetval = INET_ERROR_NOT_SUPPORTED;
426 lRetval = INET_NO_ERROR;
427 #endif // !HAVE_LWIP_MULTICAST_LOOP
428 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
430 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
431 lRetval = SocketsSetMulticastLoopback(mSocket, aIPVersion, aLoopback);
432 SuccessOrExit(lRetval);
435 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
436 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
441 * @brief Join an IP multicast group.
443 * @param[in] aInterfaceId the indicator of the network interface to
444 * add to the multicast group
446 * @param[in] aAddress the multicast group to add the
449 * @retval INET_NO_ERROR
450 * success: multicast group removed
452 * @retval INET_ERROR_UNKNOWN_INTERFACE
453 * unknown network interface, \c aInterfaceId
455 * @retval INET_ERROR_WRONG_ADDRESS_TYPE
456 * \c aAddress is not \c kIPAddressType_IPv4 or
457 * \c kIPAddressType_IPv6 or is not multicast
460 * another system or platform error
463 * Join the endpoint to the supplied multicast group on the
464 * specified interface.
467 INET_ERROR IPEndPointBasis::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress)
469 INET_ERROR lRetval = INET_ERROR_NOT_IMPLEMENTED;
471 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
472 const IPAddressType lAddrType = aAddress.Type();
473 lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress);
474 SuccessOrExit(lRetval);
479 #if INET_CONFIG_ENABLE_IPV4
480 case kIPAddressType_IPv4: {
481 #if CHIP_SYSTEM_CONFIG_USE_LWIP
482 #if LWIP_IPV4 && LWIP_IGMP
483 lRetval = LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, igmp_joingroup_netif);
484 #else // LWIP_IPV4 && LWIP_IGMP
485 lRetval = INET_ERROR_NOT_SUPPORTED;
486 #endif // LWIP_IPV4 && LWIP_IGMP
487 SuccessOrExit(lRetval);
488 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
490 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
491 lRetval = SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, IP_ADD_MEMBERSHIP);
492 SuccessOrExit(lRetval);
493 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
496 #endif // INET_CONFIG_ENABLE_IPV4
498 case kIPAddressType_IPv6: {
499 #if CHIP_SYSTEM_CONFIG_USE_LWIP
500 #ifdef HAVE_IPV6_MULTICAST
501 lRetval = LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, mld6_joingroup_netif);
502 #else // HAVE_IPV6_MULTICAST
503 lRetval = INET_ERROR_NOT_SUPPORTED;
504 #endif // HAVE_IPV6_MULTICAST
505 SuccessOrExit(lRetval);
506 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
508 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
509 lRetval = SocketsIPv6JoinMulticastGroup(mSocket, aInterfaceId, aAddress);
510 SuccessOrExit(lRetval);
511 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
516 lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
521 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
526 * @brief Leave an IP multicast group.
528 * @param[in] aInterfaceId the indicator of the network interface to
529 * remove from the multicast group
531 * @param[in] aAddress the multicast group to remove the
534 * @retval INET_NO_ERROR
535 * success: multicast group removed
537 * @retval INET_ERROR_UNKNOWN_INTERFACE
538 * unknown network interface, \c aInterfaceId
540 * @retval INET_ERROR_WRONG_ADDRESS_TYPE
541 * \c aAddress is not \c kIPAddressType_IPv4 or
542 * \c kIPAddressType_IPv6 or is not multicast
545 * another system or platform error
548 * Remove the endpoint from the supplied multicast group on the
549 * specified interface.
552 INET_ERROR IPEndPointBasis::LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress)
554 INET_ERROR lRetval = INET_ERROR_NOT_IMPLEMENTED;
556 #if CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
557 const IPAddressType lAddrType = aAddress.Type();
558 lRetval = CheckMulticastGroupArgs(aInterfaceId, aAddress);
559 SuccessOrExit(lRetval);
564 #if INET_CONFIG_ENABLE_IPV4
565 case kIPAddressType_IPv4: {
566 #if CHIP_SYSTEM_CONFIG_USE_LWIP
567 #if LWIP_IPV4 && LWIP_IGMP
568 lRetval = LwIPIPv4JoinLeaveMulticastGroup(aInterfaceId, aAddress, igmp_leavegroup_netif);
569 #else // LWIP_IPV4 && LWIP_IGMP
570 lRetval = INET_ERROR_NOT_SUPPORTED;
571 #endif // LWIP_IPV4 && LWIP_IGMP
572 SuccessOrExit(lRetval);
573 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
575 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
576 lRetval = SocketsIPv4JoinLeaveMulticastGroup(mSocket, aInterfaceId, aAddress, IP_DROP_MEMBERSHIP);
577 SuccessOrExit(lRetval);
578 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
581 #endif // INET_CONFIG_ENABLE_IPV4
583 case kIPAddressType_IPv6: {
584 #if CHIP_SYSTEM_CONFIG_USE_LWIP
585 #if LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
586 lRetval = LwIPIPv6JoinLeaveMulticastGroup(aInterfaceId, aAddress, mld6_leavegroup_netif);
587 #else // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
588 lRetval = INET_ERROR_NOT_SUPPORTED;
589 #endif // LWIP_IPV6_MLD && LWIP_IPV6_ND && LWIP_IPV6
590 SuccessOrExit(lRetval);
591 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
593 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
594 lRetval = SocketsIPv6LeaveMulticastGroup(mSocket, aInterfaceId, aAddress);
595 SuccessOrExit(lRetval);
596 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
601 lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
606 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP || CHIP_SYSTEM_CONFIG_USE_SOCKETS
610 void IPEndPointBasis::Init(InetLayer * aInetLayer)
612 InitEndPointBasis(*aInetLayer);
614 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
615 mBoundIntfId = INET_NULL_INTERFACEID;
616 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
619 #if CHIP_SYSTEM_CONFIG_USE_LWIP
620 void IPEndPointBasis::HandleDataReceived(System::PacketBufferHandle aBuffer)
622 if ((mState == kState_Listening) && (OnMessageReceived != NULL))
624 const IPPacketInfo * pktInfo = GetPacketInfo(aBuffer);
628 const IPPacketInfo pktInfoCopy = *pktInfo; // copy the address info so that the app can free the
629 // PacketBuffer without affecting access to address info.
630 OnMessageReceived(this, std::move(aBuffer), &pktInfoCopy);
634 if (OnReceiveError != NULL)
635 OnReceiveError(this, INET_ERROR_INBOUND_MESSAGE_TOO_BIG, NULL);
641 * @brief Get LwIP IP layer source and destination addressing information.
643 * @param[in] aBuffer the packet buffer containing the IP message
645 * @returns a pointer to the address information on success; otherwise,
646 * NULL if there is insufficient space in the packet for
647 * the address information.
650 * When using LwIP information about the packet is 'hidden' in the
651 * reserved space before the start of the data in the packet
652 * buffer. This is necessary because the system layer events only
653 * have two arguments, which in this case are used to convey the
654 * pointer to the end point and the pointer to the buffer.
656 * In most cases this trick of storing information before the data
657 * works because the first buffer in an LwIP IP message contains
658 * the space that was used for the Ethernet/IP/UDP headers. However,
659 * given the current size of the IPPacketInfo structure (40 bytes),
660 * it is possible for there to not be enough room to store the
661 * structure along with the payload in a single packet buffer. In
662 * practice, this should only happen for extremely large IPv4
663 * packets that arrive without an Ethernet header.
666 IPPacketInfo * IPEndPointBasis::GetPacketInfo(const System::PacketBufferHandle & aBuffer)
669 uintptr_t lPacketInfoStart;
670 IPPacketInfo * lPacketInfo = NULL;
672 if (!aBuffer->EnsureReservedSize(sizeof(IPPacketInfo) + 3))
675 lStart = (uintptr_t) aBuffer->Start();
676 lPacketInfoStart = lStart - sizeof(IPPacketInfo);
678 // Align to a 4-byte boundary
680 lPacketInfo = reinterpret_cast<IPPacketInfo *>(lPacketInfoStart & ~(sizeof(uint32_t) - 1));
683 return (lPacketInfo);
686 System::Error IPEndPointBasis::PostPacketBufferEvent(chip::System::Layer & aLayer, System::Object & aTarget,
687 System::EventType aEventType, System::PacketBufferHandle aBuffer)
689 System::Error error =
690 aLayer.PostEvent(aTarget, aEventType, (uintptr_t) System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(aBuffer));
691 if (error == INET_NO_ERROR)
693 // If PostEvent() succeeded, it has ownership of the buffer, so we need to release it (without freeing it).
694 static_cast<void>(std::move(aBuffer).UnsafeRelease());
699 #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
701 #if CHIP_SYSTEM_CONFIG_USE_SOCKETS
702 INET_ERROR IPEndPointBasis::Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort, InterfaceId aInterfaceId)
704 INET_ERROR lRetval = INET_NO_ERROR;
706 if (aAddressType == kIPAddressType_IPv6)
708 struct sockaddr_in6 sa;
710 memset(&sa, 0, sizeof(sa));
712 sa.sin6_family = AF_INET6;
713 sa.sin6_port = htons(aPort);
714 sa.sin6_addr = aAddress.ToIPv6();
715 if (!CanCastTo<decltype(sa.sin6_scope_id)>(aInterfaceId))
717 return INET_ERROR_INCORRECT_STATE;
719 sa.sin6_scope_id = static_cast<decltype(sa.sin6_scope_id)>(aInterfaceId);
721 if (bind(mSocket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
722 lRetval = chip::System::MapErrorPOSIX(errno);
724 // Instruct the kernel that any messages to multicast destinations should be
725 // sent down the interface specified by the caller.
726 #ifdef IPV6_MULTICAST_IF
727 if (lRetval == INET_NO_ERROR)
728 setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &aInterfaceId, sizeof(aInterfaceId));
729 #endif // defined(IPV6_MULTICAST_IF)
731 // Instruct the kernel that any messages to multicast destinations should be
732 // set with the configured hop limit value.
733 #ifdef IPV6_MULTICAST_HOPS
734 int hops = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
735 setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
736 #endif // defined(IPV6_MULTICAST_HOPS)
738 #if INET_CONFIG_ENABLE_IPV4
739 else if (aAddressType == kIPAddressType_IPv4)
741 struct sockaddr_in sa;
744 memset(&sa, 0, sizeof(sa));
746 sa.sin_family = AF_INET;
747 sa.sin_port = htons(aPort);
748 sa.sin_addr = aAddress.ToIPv4();
750 if (bind(mSocket, reinterpret_cast<const sockaddr *>(&sa), static_cast<unsigned>(sizeof(sa))) != 0)
751 lRetval = chip::System::MapErrorPOSIX(errno);
753 // Instruct the kernel that any messages to multicast destinations should be
754 // sent down the interface to which the specified IPv4 address is bound.
755 #ifdef IP_MULTICAST_IF
756 if (lRetval == INET_NO_ERROR)
757 setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_IF, &sa, sizeof(sa));
758 #endif // defined(IP_MULTICAST_IF)
760 // Instruct the kernel that any messages to multicast destinations should be
761 // set with the configured hop limit value.
762 #ifdef IP_MULTICAST_TTL
763 int ttl = INET_CONFIG_IP_MULTICAST_HOP_LIMIT;
764 setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
765 #endif // defined(IP_MULTICAST_TTL)
767 // Allow socket transmitting broadcast packets.
768 if (lRetval == INET_NO_ERROR)
769 setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable));
771 #endif // INET_CONFIG_ENABLE_IPV4
773 lRetval = INET_ERROR_WRONG_ADDRESS_TYPE;
778 INET_ERROR IPEndPointBasis::BindInterface(IPAddressType aAddressType, InterfaceId aInterfaceId)
780 INET_ERROR lRetval = INET_NO_ERROR;
782 #if HAVE_SO_BINDTODEVICE
783 if (aInterfaceId == INET_NULL_INTERFACEID)
785 // Stop interface-based filtering.
786 if (setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, "", 0) == -1)
788 lRetval = chip::System::MapErrorPOSIX(errno);
793 // Start filtering on the passed interface.
794 char lInterfaceName[IF_NAMESIZE];
796 if (if_indextoname(aInterfaceId, lInterfaceName) == NULL)
798 lRetval = chip::System::MapErrorPOSIX(errno);
801 if (lRetval == INET_NO_ERROR &&
802 setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, lInterfaceName, socklen_t(strlen(lInterfaceName))) == -1)
804 lRetval = chip::System::MapErrorPOSIX(errno);
808 if (lRetval == INET_NO_ERROR)
809 mBoundIntfId = aInterfaceId;
811 #else // !HAVE_SO_BINDTODEVICE
812 lRetval = INET_ERROR_NOT_IMPLEMENTED;
813 #endif // HAVE_SO_BINDTODEVICE
818 INET_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle aBuffer, uint16_t aSendFlags)
820 INET_ERROR res = INET_NO_ERROR;
821 PeerSockAddr peerSockAddr;
823 uint8_t controlData[256];
824 struct msghdr msgHeader;
825 InterfaceId intfId = aPktInfo->Interface;
827 // Ensure the destination address type is compatible with the endpoint address type.
828 VerifyOrExit(mAddrType == aPktInfo->DestAddress.Type(), res = INET_ERROR_BAD_ARGS);
830 // For now the entire message must fit within a single buffer.
831 VerifyOrExit(!aBuffer->HasChainedBuffer(), res = INET_ERROR_MESSAGE_TOO_LONG);
833 memset(&msgHeader, 0, sizeof(msgHeader));
835 msgIOV.iov_base = aBuffer->Start();
836 msgIOV.iov_len = aBuffer->DataLength();
837 msgHeader.msg_iov = &msgIOV;
838 msgHeader.msg_iovlen = 1;
840 // Construct a sockaddr_in/sockaddr_in6 structure containing the destination information.
841 memset(&peerSockAddr, 0, sizeof(peerSockAddr));
842 msgHeader.msg_name = &peerSockAddr;
843 if (mAddrType == kIPAddressType_IPv6)
845 peerSockAddr.in6.sin6_family = AF_INET6;
846 peerSockAddr.in6.sin6_port = htons(aPktInfo->DestPort);
847 peerSockAddr.in6.sin6_addr = aPktInfo->DestAddress.ToIPv6();
848 VerifyOrExit(CanCastTo<decltype(peerSockAddr.in6.sin6_scope_id)>(aPktInfo->Interface), res = INET_ERROR_INCORRECT_STATE);
849 peerSockAddr.in6.sin6_scope_id = static_cast<decltype(peerSockAddr.in6.sin6_scope_id)>(aPktInfo->Interface);
850 msgHeader.msg_namelen = sizeof(sockaddr_in6);
852 #if INET_CONFIG_ENABLE_IPV4
855 peerSockAddr.in.sin_family = AF_INET;
856 peerSockAddr.in.sin_port = htons(aPktInfo->DestPort);
857 peerSockAddr.in.sin_addr = aPktInfo->DestAddress.ToIPv4();
858 msgHeader.msg_namelen = sizeof(sockaddr_in);
860 #endif // INET_CONFIG_ENABLE_IPV4
862 // If the endpoint has been bound to a particular interface,
863 // and the caller didn't supply a specific interface to send
864 // on, use the bound interface. This appears to be necessary
865 // for messages to multicast addresses, which under Linux
866 // don't seem to get sent out the correct interface, despite
867 // the socket being bound.
868 if (intfId == INET_NULL_INTERFACEID)
869 intfId = mBoundIntfId;
871 // If the packet should be sent over a specific interface, or with a specific source
872 // address, construct an IP_PKTINFO/IPV6_PKTINFO "control message" to that effect
873 // add add it to the message header. If the local OS doesn't support IP_PKTINFO/IPV6_PKTINFO
874 // fail with an error.
875 if (intfId != INET_NULL_INTERFACEID || aPktInfo->SrcAddress.Type() != kIPAddressType_Any)
877 #if defined(IP_PKTINFO) || defined(IPV6_PKTINFO)
878 memset(controlData, 0, sizeof(controlData));
879 msgHeader.msg_control = controlData;
880 msgHeader.msg_controllen = sizeof(controlData);
882 struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader);
884 #if INET_CONFIG_ENABLE_IPV4
886 if (mAddrType == kIPAddressType_IPv4)
888 #if defined(IP_PKTINFO)
889 controlHdr->cmsg_level = IPPROTO_IP;
890 controlHdr->cmsg_type = IP_PKTINFO;
891 controlHdr->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
893 struct in_pktinfo * pktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
894 if (!CanCastTo<decltype(pktInfo->ipi_ifindex)>(intfId))
896 ExitNow(res = INET_ERROR_NOT_SUPPORTED);
899 pktInfo->ipi_ifindex = static_cast<decltype(pktInfo->ipi_ifindex)>(intfId);
900 pktInfo->ipi_spec_dst = aPktInfo->SrcAddress.ToIPv4();
902 msgHeader.msg_controllen = CMSG_SPACE(sizeof(in_pktinfo));
903 #else // !defined(IP_PKTINFO)
904 ExitNow(res = INET_ERROR_NOT_SUPPORTED);
905 #endif // !defined(IP_PKTINFO)
908 #endif // INET_CONFIG_ENABLE_IPV4
910 if (mAddrType == kIPAddressType_IPv6)
912 #if defined(IPV6_PKTINFO)
913 controlHdr->cmsg_level = IPPROTO_IPV6;
914 controlHdr->cmsg_type = IPV6_PKTINFO;
915 controlHdr->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
917 struct in6_pktinfo * pktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
918 if (!CanCastTo<decltype(pktInfo->ipi6_ifindex)>(intfId))
920 ExitNow(res = INET_ERROR_UNEXPECTED_EVENT);
922 pktInfo->ipi6_ifindex = static_cast<decltype(pktInfo->ipi6_ifindex)>(intfId);
923 pktInfo->ipi6_addr = aPktInfo->SrcAddress.ToIPv6();
925 msgHeader.msg_controllen = CMSG_SPACE(sizeof(in6_pktinfo));
926 #else // !defined(IPV6_PKTINFO)
927 ExitNow(res = INET_ERROR_NOT_SUPPORTED);
928 #endif // !defined(IPV6_PKTINFO)
931 #else // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
932 IgnoreUnusedVariable(controlData);
933 ExitNow(res = INET_ERROR_NOT_SUPPORTED);
934 #endif // !(defined(IP_PKTINFO) && defined(IPV6_PKTINFO))
939 const ssize_t lenSent = sendmsg(mSocket, &msgHeader, 0);
941 res = chip::System::MapErrorPOSIX(errno);
942 else if (lenSent != aBuffer->DataLength())
943 res = INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED;
950 INET_ERROR IPEndPointBasis::GetSocket(IPAddressType aAddressType, int aType, int aProtocol)
952 INET_ERROR res = INET_NO_ERROR;
954 if (mSocket == INET_INVALID_SOCKET_FD)
959 switch (aAddressType)
961 case kIPAddressType_IPv6:
965 #if INET_CONFIG_ENABLE_IPV4
966 case kIPAddressType_IPv4:
969 #endif // INET_CONFIG_ENABLE_IPV4
972 return INET_ERROR_WRONG_ADDRESS_TYPE;
975 mSocket = ::socket(family, aType, aProtocol);
977 return chip::System::MapErrorPOSIX(errno);
979 mAddrType = aAddressType;
981 // NOTE WELL: the errors returned by setsockopt() here are not
982 // returned as Inet layer chip::System::MapErrorPOSIX(errno)
983 // codes because they are normally expected to fail on some
984 // platforms where the socket option code is defined in the
985 // header files but not [yet] implemented. Certainly, there is
986 // room to improve this by connecting the build configuration
987 // logic up to check for implementations of these options and
988 // to provide appropriate HAVE_xxxxx definitions accordingly.
990 res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
991 static_cast<void>(res);
994 res = setsockopt(mSocket, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
997 ChipLogError(Inet, "SO_REUSEPORT failed: %d", errno);
999 #endif // defined(SO_REUSEPORT)
1001 // If creating an IPv6 socket, tell the kernel that it will be
1002 // IPv6 only. This makes it posible to bind two sockets to
1003 // the same port, one for IPv4 and one for IPv6.
1006 if (aAddressType == kIPAddressType_IPv6)
1008 res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
1011 ChipLogError(Inet, "IPV6_V6ONLY failed: %d", errno);
1014 #endif // defined(IPV6_V6ONLY)
1016 #if INET_CONFIG_ENABLE_IPV4
1018 if (aAddressType == kIPAddressType_IPv4)
1020 res = setsockopt(mSocket, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one));
1023 ChipLogError(Inet, "IP_PKTINFO failed: %d", errno);
1026 #endif // defined(IP_PKTINFO)
1027 #endif // INET_CONFIG_ENABLE_IPV4
1029 #ifdef IPV6_RECVPKTINFO
1030 if (aAddressType == kIPAddressType_IPv6)
1032 res = setsockopt(mSocket, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
1035 ChipLogError(Inet, "IPV6_PKTINFO failed: %d", errno);
1038 #endif // defined(IPV6_RECVPKTINFO)
1040 // On systems that support it, disable the delivery of SIGPIPE
1041 // signals when writing to a closed socket. This is mostly
1042 // needed on iOS which has the peculiar habit of sending
1043 // SIGPIPEs on unconnected UDP sockets.
1046 res = setsockopt(mSocket, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
1049 ChipLogError(Inet, "SO_NOSIGPIPE failed: %d", errno);
1052 #endif // defined(SO_NOSIGPIPE)
1054 else if (mAddrType != aAddressType)
1056 return INET_ERROR_INCORRECT_STATE;
1059 return INET_NO_ERROR;
1062 SocketEvents IPEndPointBasis::PrepareIO()
1066 if (mState == kState_Listening && OnMessageReceived != nullptr)
1072 void IPEndPointBasis::HandlePendingIO(uint16_t aPort)
1074 INET_ERROR lStatus = INET_NO_ERROR;
1075 IPPacketInfo lPacketInfo;
1076 System::PacketBufferHandle lBuffer;
1078 lPacketInfo.Clear();
1079 lPacketInfo.DestPort = aPort;
1081 lBuffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSizeWithoutReserve, 0);
1083 if (!lBuffer.IsNull())
1085 struct iovec msgIOV;
1086 PeerSockAddr lPeerSockAddr;
1087 uint8_t controlData[256];
1088 struct msghdr msgHeader;
1090 msgIOV.iov_base = lBuffer->Start();
1091 msgIOV.iov_len = lBuffer->AvailableDataLength();
1093 memset(&lPeerSockAddr, 0, sizeof(lPeerSockAddr));
1095 memset(&msgHeader, 0, sizeof(msgHeader));
1097 msgHeader.msg_name = &lPeerSockAddr;
1098 msgHeader.msg_namelen = sizeof(lPeerSockAddr);
1099 msgHeader.msg_iov = &msgIOV;
1100 msgHeader.msg_iovlen = 1;
1101 msgHeader.msg_control = controlData;
1102 msgHeader.msg_controllen = sizeof(controlData);
1104 ssize_t rcvLen = recvmsg(mSocket, &msgHeader, MSG_DONTWAIT);
1108 lStatus = chip::System::MapErrorPOSIX(errno);
1110 else if (rcvLen > lBuffer->AvailableDataLength())
1112 lStatus = INET_ERROR_INBOUND_MESSAGE_TOO_BIG;
1116 lBuffer->SetDataLength(static_cast<uint16_t>(rcvLen));
1118 if (lPeerSockAddr.any.sa_family == AF_INET6)
1120 lPacketInfo.SrcAddress = IPAddress::FromIPv6(lPeerSockAddr.in6.sin6_addr);
1121 lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in6.sin6_port);
1123 #if INET_CONFIG_ENABLE_IPV4
1124 else if (lPeerSockAddr.any.sa_family == AF_INET)
1126 lPacketInfo.SrcAddress = IPAddress::FromIPv4(lPeerSockAddr.in.sin_addr);
1127 lPacketInfo.SrcPort = ntohs(lPeerSockAddr.in.sin_port);
1129 #endif // INET_CONFIG_ENABLE_IPV4
1132 lStatus = INET_ERROR_INCORRECT_STATE;
1136 if (lStatus == INET_NO_ERROR)
1138 for (struct cmsghdr * controlHdr = CMSG_FIRSTHDR(&msgHeader); controlHdr != nullptr;
1139 controlHdr = CMSG_NXTHDR(&msgHeader, controlHdr))
1141 #if INET_CONFIG_ENABLE_IPV4
1143 if (controlHdr->cmsg_level == IPPROTO_IP && controlHdr->cmsg_type == IP_PKTINFO)
1145 struct in_pktinfo * inPktInfo = reinterpret_cast<struct in_pktinfo *> CMSG_DATA(controlHdr);
1146 if (!CanCastTo<InterfaceId>(inPktInfo->ipi_ifindex))
1148 lStatus = INET_ERROR_INCORRECT_STATE;
1151 lPacketInfo.Interface = static_cast<InterfaceId>(inPktInfo->ipi_ifindex);
1152 lPacketInfo.DestAddress = IPAddress::FromIPv4(inPktInfo->ipi_addr);
1155 #endif // defined(IP_PKTINFO)
1156 #endif // INET_CONFIG_ENABLE_IPV4
1159 if (controlHdr->cmsg_level == IPPROTO_IPV6 && controlHdr->cmsg_type == IPV6_PKTINFO)
1161 struct in6_pktinfo * in6PktInfo = reinterpret_cast<struct in6_pktinfo *> CMSG_DATA(controlHdr);
1162 if (!CanCastTo<InterfaceId>(in6PktInfo->ipi6_ifindex))
1164 lStatus = INET_ERROR_INCORRECT_STATE;
1167 lPacketInfo.Interface = static_cast<InterfaceId>(in6PktInfo->ipi6_ifindex);
1168 lPacketInfo.DestAddress = IPAddress::FromIPv6(in6PktInfo->ipi6_addr);
1171 #endif // defined(IPV6_PKTINFO)
1177 lStatus = INET_ERROR_NO_MEMORY;
1180 if (lStatus == INET_NO_ERROR)
1182 lBuffer.RightSize();
1183 OnMessageReceived(this, std::move(lBuffer), &lPacketInfo);
1187 if (OnReceiveError != nullptr && lStatus != chip::System::MapErrorPOSIX(EAGAIN))
1188 OnReceiveError(this, lStatus, nullptr);
1191 #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS
1193 #if CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
1194 INET_ERROR IPEndPointBasis::ConfigureProtocol(IPAddressType aAddressType, const nw_parameters_t & aParameters)
1196 INET_ERROR res = INET_NO_ERROR;
1198 nw_protocol_stack_t protocolStack = nw_parameters_copy_default_protocol_stack(aParameters);
1199 nw_protocol_options_t ipOptions = nw_protocol_stack_copy_internet_protocol(protocolStack);
1201 switch (aAddressType)
1204 case kIPAddressType_IPv6:
1205 nw_ip_options_set_version(ipOptions, nw_ip_version_6);
1208 #if INET_CONFIG_ENABLE_IPV4
1209 case kIPAddressType_IPv4:
1210 nw_ip_options_set_version(ipOptions, nw_ip_version_4);
1212 #endif // INET_CONFIG_ENABLE_IPV4
1215 res = INET_ERROR_WRONG_ADDRESS_TYPE;
1218 nw_release(ipOptions);
1219 nw_release(protocolStack);
1224 INET_ERROR IPEndPointBasis::Bind(IPAddressType aAddressType, const IPAddress & aAddress, uint16_t aPort,
1225 const nw_parameters_t & aParameters)
1227 INET_ERROR res = INET_NO_ERROR;
1228 nw_endpoint_t endpoint = nullptr;
1230 VerifyOrExit(aParameters != NULL, res = INET_ERROR_BAD_ARGS);
1232 res = ConfigureProtocol(aAddressType, aParameters);
1235 res = GetEndPoint(endpoint, aAddressType, aAddress, aPort);
1236 nw_parameters_set_local_endpoint(aParameters, endpoint);
1237 nw_release(endpoint);
1240 mDispatchQueue = dispatch_queue_create("inet_dispatch_global", DISPATCH_QUEUE_CONCURRENT);
1241 VerifyOrExit(mDispatchQueue != NULL, res = INET_ERROR_NO_MEMORY);
1242 dispatch_retain(mDispatchQueue);
1244 mConnectionSemaphore = dispatch_semaphore_create(0);
1245 VerifyOrExit(mConnectionSemaphore != NULL, res = INET_ERROR_NO_MEMORY);
1246 dispatch_retain(mConnectionSemaphore);
1248 mSendSemaphore = dispatch_semaphore_create(0);
1249 VerifyOrExit(mSendSemaphore != NULL, res = INET_ERROR_NO_MEMORY);
1250 dispatch_retain(mSendSemaphore);
1252 mAddrType = aAddressType;
1259 INET_ERROR IPEndPointBasis::SendMsg(const IPPacketInfo * aPktInfo, chip::System::PacketBufferHandle aBuffer, uint16_t aSendFlags)
1261 __block INET_ERROR res = INET_NO_ERROR;
1262 dispatch_data_t content;
1264 // Ensure the destination address type is compatible with the endpoint address type.
1265 VerifyOrExit(mAddrType == aPktInfo->DestAddress.Type(), res = INET_ERROR_BAD_ARGS);
1267 // For now the entire message must fit within a single buffer.
1268 VerifyOrExit(aBuffer->Next() == NULL, res = INET_ERROR_MESSAGE_TOO_LONG);
1270 res = GetConnection(aPktInfo);
1273 // Send a message, and wait for it to be dispatched.
1274 content = dispatch_data_create(aBuffer->Start(), aBuffer->DataLength(), mDispatchQueue, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
1276 // If there is a current message pending and the state of the network connection change (e.g switch to a
1277 // different network) the connection will enter a nw_connection_state_failed state and the completion handler
1278 // will never be called. In such cases a signal is sent from the connection state change handler to release
1279 // the semaphore. In this case the INET_ERROR will not update with the result of the completion handler.
1280 // To make sure caller knows that sending a message has failed the following code consider there is an error
1281 // _unless_ the completion handler says otherwise.
1282 res = INET_ERROR_UNEXPECTED_EVENT;
1283 nw_connection_send(mConnection, content, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t error) {
1286 res = chip::System::MapErrorPOSIX(nw_error_get_error_code(error));
1290 res = INET_NO_ERROR;
1292 dispatch_semaphore_signal(mSendSemaphore);
1294 dispatch_release(content);
1296 dispatch_semaphore_wait(mSendSemaphore, DISPATCH_TIME_FOREVER);
1302 void IPEndPointBasis::HandleDataReceived(const nw_connection_t & aConnection)
1305 nw_connection_receive_completion_t handler =
1306 ^(dispatch_data_t content, nw_content_context_t context, bool is_complete, nw_error_t receive_error) {
1307 dispatch_block_t schedule_next_receive = ^{
1308 if (receive_error == NULL)
1310 HandleDataReceived(aConnection);
1312 else if (OnReceiveError != NULL)
1314 nw_error_domain_t error_domain = nw_error_get_error_domain(receive_error);
1315 errno = nw_error_get_error_code(receive_error);
1316 if (!(error_domain == nw_error_domain_posix && errno == ECANCELED))
1318 INET_ERROR error = chip::System::MapErrorPOSIX(errno);
1319 IPPacketInfo packetInfo;
1320 GetPacketInfo(aConnection, packetInfo);
1321 dispatch_async(mDispatchQueue, ^{
1322 OnReceiveError((IPEndPointBasis *) this, error, &packetInfo);
1328 if (content != NULL && OnMessageReceived != NULL)
1330 size_t count = dispatch_data_get_size(content);
1331 System::PacketBufferHandle * packetBuffer = System::PacketBufferHandle::New(count);
1332 dispatch_data_apply(content, ^(dispatch_data_t data, size_t offset, const void * buffer, size_t size) {
1333 memmove(packetBuffer->Start() + offset, buffer, size);
1336 packetBuffer->SetDataLength(count);
1338 IPPacketInfo packetInfo;
1339 GetPacketInfo(aConnection, packetInfo);
1340 dispatch_async(mDispatchQueue, ^{
1341 OnMessageReceived((IPEndPointBasis *) this, packetBuffer, &packetInfo);
1345 schedule_next_receive();
1348 nw_connection_receive_message(aConnection, handler);
1351 void IPEndPointBasis::GetPacketInfo(const nw_connection_t & aConnection, IPPacketInfo & aPacketInfo)
1353 nw_path_t path = nw_connection_copy_current_path(aConnection);
1354 nw_endpoint_t dest_endpoint = nw_path_copy_effective_local_endpoint(path);
1355 nw_endpoint_t src_endpoint = nw_path_copy_effective_remote_endpoint(path);
1357 aPacketInfo.Clear();
1358 aPacketInfo.SrcAddress = IPAddress::FromSockAddr(*nw_endpoint_get_address(src_endpoint));
1359 aPacketInfo.DestAddress = IPAddress::FromSockAddr(*nw_endpoint_get_address(dest_endpoint));
1360 aPacketInfo.SrcPort = nw_endpoint_get_port(src_endpoint);
1361 aPacketInfo.DestPort = nw_endpoint_get_port(dest_endpoint);
1364 INET_ERROR IPEndPointBasis::GetEndPoint(nw_endpoint_t & aEndPoint, const IPAddressType aAddressType, const IPAddress & aAddress,
1367 INET_ERROR res = INET_NO_ERROR;
1368 char addrStr[INET6_ADDRSTRLEN];
1369 char portStr[INET_PORTSTRLEN];
1371 // Note: aAddress.ToString will return the IPv6 Any address if the address type is Any, but that's not what
1372 // we want if the locale endpoint is IPv4.
1373 if (aAddressType == kIPAddressType_IPv4 && aAddress.Type() == kIPAddressType_Any)
1375 const IPAddress anyAddr = IPAddress::FromIPv4(aAddress.ToIPv4());
1376 anyAddr.ToString(addrStr, sizeof(addrStr));
1380 aAddress.ToString(addrStr, sizeof(addrStr));
1383 snprintf(portStr, sizeof(portStr), "%u", aPort);
1385 aEndPoint = nw_endpoint_create_host(addrStr, portStr);
1386 VerifyOrExit(aEndPoint != NULL, res = INET_ERROR_BAD_ARGS);
1392 INET_ERROR IPEndPointBasis::GetConnection(const IPPacketInfo * aPktInfo)
1394 INET_ERROR res = INET_NO_ERROR;
1395 nw_endpoint_t endpoint = NULL;
1396 nw_connection_t connection = NULL;
1398 VerifyOrExit(mParameters != NULL, res = INET_ERROR_INCORRECT_STATE);
1402 nw_path_t path = nw_connection_copy_current_path(mConnection);
1403 nw_endpoint_t remote_endpoint = nw_path_copy_effective_remote_endpoint(path);
1404 const IPAddress remote_address = IPAddress::FromSockAddr(*nw_endpoint_get_address(remote_endpoint));
1405 const uint16_t remote_port = nw_endpoint_get_port(remote_endpoint);
1406 const bool isDifferentEndPoint = aPktInfo->DestPort != remote_port || aPktInfo->DestAddress != remote_address;
1407 VerifyOrExit(isDifferentEndPoint, res = INET_NO_ERROR);
1409 res = ReleaseConnection();
1413 res = GetEndPoint(endpoint, mAddrType, aPktInfo->DestAddress, aPktInfo->DestPort);
1416 connection = nw_connection_create(endpoint, mParameters);
1417 nw_release(endpoint);
1419 VerifyOrExit(connection != NULL, res = INET_ERROR_INCORRECT_STATE);
1421 res = StartConnection(connection);
1427 INET_ERROR IPEndPointBasis::StartListener()
1429 __block INET_ERROR res = INET_NO_ERROR;
1430 nw_listener_t listener;
1432 VerifyOrExit(mListener == NULL, res = INET_ERROR_INCORRECT_STATE);
1433 VerifyOrExit(mListenerSemaphore == NULL, res = INET_ERROR_INCORRECT_STATE);
1434 VerifyOrExit(mListenerQueue == NULL, res = INET_ERROR_INCORRECT_STATE);
1436 listener = nw_listener_create(mParameters);
1437 VerifyOrExit(listener != NULL, res = INET_ERROR_INCORRECT_STATE);
1439 mListenerSemaphore = dispatch_semaphore_create(0);
1440 VerifyOrExit(mListenerSemaphore != NULL, res = INET_ERROR_NO_MEMORY);
1441 dispatch_retain(mListenerSemaphore);
1443 mListenerQueue = dispatch_queue_create("inet_dispatch_listener", DISPATCH_QUEUE_CONCURRENT);
1444 VerifyOrExit(mListenerQueue != NULL, res = INET_ERROR_NO_MEMORY);
1445 dispatch_retain(mListenerQueue);
1447 nw_listener_set_queue(listener, mListenerQueue);
1449 nw_listener_set_new_connection_handler(listener, ^(nw_connection_t connection) {
1450 ReleaseConnection();
1451 StartConnection(connection);
1454 nw_listener_set_state_changed_handler(listener, ^(nw_listener_state_t state, nw_error_t error) {
1458 case nw_listener_state_invalid:
1459 ChipLogDetail(Inet, "Listener: Invalid");
1460 res = INET_ERROR_INCORRECT_STATE;
1461 nw_listener_cancel(listener);
1464 case nw_listener_state_waiting:
1465 ChipLogDetail(Inet, "Listener: Waiting");
1468 case nw_listener_state_failed:
1469 ChipLogDetail(Inet, "Listener: Failed");
1470 res = chip::System::MapErrorPOSIX(nw_error_get_error_code(error));
1473 case nw_listener_state_ready:
1474 ChipLogDetail(Inet, "Listener: Ready");
1475 res = INET_NO_ERROR;
1476 dispatch_semaphore_signal(mListenerSemaphore);
1479 case nw_listener_state_cancelled:
1480 ChipLogDetail(Inet, "Listener: Cancelled");
1481 if (res == INET_NO_ERROR)
1482 res = INET_ERROR_CONNECTION_ABORTED;
1484 dispatch_semaphore_signal(mListenerSemaphore);
1489 nw_listener_start(listener);
1490 dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER);
1493 mListener = listener;
1494 nw_retain(mListener);
1499 INET_ERROR IPEndPointBasis::StartConnection(nw_connection_t & aConnection)
1501 __block INET_ERROR res = INET_NO_ERROR;
1503 nw_connection_set_queue(aConnection, mDispatchQueue);
1505 nw_connection_set_state_changed_handler(aConnection, ^(nw_connection_state_t state, nw_error_t error) {
1509 case nw_connection_state_invalid:
1510 ChipLogDetail(Inet, "Connection: Invalid");
1511 res = INET_ERROR_INCORRECT_STATE;
1512 nw_connection_cancel(aConnection);
1515 case nw_connection_state_preparing:
1516 ChipLogDetail(Inet, "Connection: Preparing");
1517 res = INET_ERROR_INCORRECT_STATE;
1520 case nw_connection_state_waiting:
1521 ChipLogDetail(Inet, "Connection: Waiting");
1522 nw_connection_cancel(aConnection);
1525 case nw_connection_state_failed:
1526 ChipLogDetail(Inet, "Connection: Failed");
1527 res = chip::System::MapErrorPOSIX(nw_error_get_error_code(error));
1530 case nw_connection_state_ready:
1531 ChipLogDetail(Inet, "Connection: Ready");
1532 res = INET_NO_ERROR;
1533 dispatch_semaphore_signal(mConnectionSemaphore);
1536 case nw_connection_state_cancelled:
1537 ChipLogDetail(Inet, "Connection: Cancelled");
1538 if (res == INET_NO_ERROR)
1539 res = INET_ERROR_CONNECTION_ABORTED;
1541 dispatch_semaphore_signal(mConnectionSemaphore);
1546 nw_connection_start(aConnection);
1547 dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER);
1550 mConnection = aConnection;
1551 nw_retain(mConnection);
1552 HandleDataReceived(mConnection);
1558 void IPEndPointBasis::ReleaseAll()
1561 OnMessageReceived = NULL;
1562 OnReceiveError = NULL;
1564 ReleaseConnection();
1569 nw_release(mParameters);
1575 dispatch_suspend(mDispatchQueue);
1576 dispatch_release(mDispatchQueue);
1577 mDispatchQueue = NULL;
1580 if (mConnectionSemaphore)
1582 dispatch_release(mConnectionSemaphore);
1583 mConnectionSemaphore = NULL;
1588 dispatch_suspend(mListenerQueue);
1589 dispatch_release(mListenerQueue);
1590 mListenerQueue = NULL;
1593 if (mListenerSemaphore)
1595 dispatch_release(mListenerSemaphore);
1596 mListenerSemaphore = NULL;
1601 dispatch_release(mSendSemaphore);
1602 mSendSemaphore = NULL;
1606 INET_ERROR IPEndPointBasis::ReleaseListener()
1608 INET_ERROR res = INET_NO_ERROR;
1610 VerifyOrExit(mListener, res = INET_ERROR_INCORRECT_STATE);
1611 VerifyOrExit(mDispatchQueue, res = INET_ERROR_INCORRECT_STATE);
1612 VerifyOrExit(mConnectionSemaphore, res = INET_ERROR_INCORRECT_STATE);
1614 nw_listener_cancel(mListener);
1615 dispatch_semaphore_wait(mListenerSemaphore, DISPATCH_TIME_FOREVER);
1616 nw_release(mListener);
1623 INET_ERROR IPEndPointBasis::ReleaseConnection()
1625 INET_ERROR res = INET_NO_ERROR;
1626 VerifyOrExit(mConnection, res = INET_ERROR_INCORRECT_STATE);
1627 VerifyOrExit(mDispatchQueue, res = INET_ERROR_INCORRECT_STATE);
1628 VerifyOrExit(mConnectionSemaphore, res = INET_ERROR_INCORRECT_STATE);
1630 nw_connection_cancel(mConnection);
1631 dispatch_semaphore_wait(mConnectionSemaphore, DISPATCH_TIME_FOREVER);
1632 nw_release(mConnection);
1639 #endif // CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK