Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020-2025 Project CHIP Authors
4 : * Copyright (c) 2018 Google LLC.
5 : * Copyright (c) 2013-2018 Nest Labs, Inc.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * @file
22 : * This file implements the <tt>Inet::UDPEndPoint</tt>
23 : * class, where the CHIP Inet Layer encapsulates methods for
24 : * interacting with UDP transport endpoints (SOCK_DGRAM sockets
25 : * on Linux and BSD-derived systems) or LwIP UDP protocol
26 : * control blocks, as the system is configured accordingly.
27 : *
28 : */
29 :
30 : #include <inet/UDPEndPoint.h>
31 :
32 : #include <inet/IPPacketInfo.h>
33 : #include <inet/InetFaultInjection.h>
34 : #include <inet/arpa-inet-compatibility.h>
35 : #include <lib/support/CodeUtils.h>
36 : #include <lib/support/SafeInt.h>
37 : #include <lib/support/logging/CHIPLogging.h>
38 : #include <system/SystemFaultInjection.h>
39 :
40 : #include <cstring>
41 : #include <utility>
42 :
43 : namespace chip {
44 : namespace Inet {
45 :
46 85 : CHIP_ERROR UDPEndPoint::Bind(IPAddressType addrType, const IPAddress & addr, uint16_t port, InterfaceId intfId)
47 : {
48 85 : if (mState != State::kReady && mState != State::kBound)
49 : {
50 1 : return CHIP_ERROR_INCORRECT_STATE;
51 : }
52 :
53 84 : if ((addr != IPAddress::Any) && (addr.Type() != IPAddressType::kAny) && (addr.Type() != addrType))
54 : {
55 2 : return INET_ERROR_WRONG_ADDRESS_TYPE;
56 : }
57 :
58 82 : ReturnErrorOnFailure(BindImpl(addrType, addr, port, intfId));
59 :
60 80 : mState = State::kBound;
61 :
62 80 : return CHIP_NO_ERROR;
63 : }
64 :
65 2 : CHIP_ERROR UDPEndPoint::BindInterface(IPAddressType addrType, InterfaceId intfId)
66 : {
67 2 : if (mState != State::kReady && mState != State::kBound)
68 : {
69 1 : return CHIP_ERROR_INCORRECT_STATE;
70 : }
71 :
72 1 : ReturnErrorOnFailure(BindInterfaceImpl(addrType, intfId));
73 :
74 1 : mState = State::kBound;
75 :
76 1 : return CHIP_NO_ERROR;
77 : }
78 :
79 82 : CHIP_ERROR UDPEndPoint::Listen(OnMessageReceivedFunct onMessageReceived, OnReceiveErrorFunct onReceiveError, void * appState)
80 : {
81 82 : if (mState == State::kListening)
82 : {
83 1 : return CHIP_NO_ERROR;
84 : }
85 :
86 81 : if (mState != State::kBound)
87 : {
88 1 : return CHIP_ERROR_INCORRECT_STATE;
89 : }
90 :
91 80 : OnMessageReceived = onMessageReceived;
92 80 : OnReceiveError = onReceiveError;
93 80 : mAppState = appState;
94 :
95 80 : ReturnErrorOnFailure(ListenImpl());
96 :
97 80 : mState = State::kListening;
98 :
99 80 : return CHIP_NO_ERROR;
100 : }
101 :
102 49 : CHIP_ERROR UDPEndPoint::SendTo(const IPAddress & addr, uint16_t port, chip::System::PacketBufferHandle && msg, InterfaceId intfId)
103 : {
104 49 : IPPacketInfo pktInfo;
105 49 : pktInfo.Clear();
106 49 : pktInfo.DestAddress = addr;
107 49 : pktInfo.DestPort = port;
108 49 : pktInfo.Interface = intfId;
109 49 : return SendMsg(&pktInfo, std::move(msg));
110 : }
111 :
112 52 : CHIP_ERROR UDPEndPoint::SendMsg(const IPPacketInfo * pktInfo, System::PacketBufferHandle && msg)
113 : {
114 52 : INET_FAULT_INJECT(FaultInjection::kFault_Send, return INET_ERROR_UNKNOWN_INTERFACE;);
115 52 : INET_FAULT_INJECT(FaultInjection::kFault_SendNonCritical, return CHIP_ERROR_NO_MEMORY;);
116 :
117 52 : ReturnErrorOnFailure(SendMsgImpl(pktInfo, std::move(msg)));
118 :
119 52 : CHIP_SYSTEM_FAULT_INJECT_ASYNC_EVENT();
120 :
121 52 : return CHIP_NO_ERROR;
122 : }
123 :
124 81 : void UDPEndPoint::Free()
125 : {
126 81 : Close();
127 :
128 : // CloseImpl() may have called Ref() to keep endpoint alive for pending operations
129 : // (when mDelayReleaseCount != 0). Only delete if ref count is still 0.
130 : // If ref count > 0, the deferred Unref() scheduled by CloseImpl() will eventually
131 : // call Free() again when all pending operations complete.
132 81 : if (GetReferenceCount() == 0)
133 : {
134 81 : Delete();
135 : }
136 81 : }
137 :
138 81 : void UDPEndPoint::Close()
139 : {
140 81 : if (mState != State::kClosed)
141 : {
142 81 : mState = State::kClosed;
143 81 : CloseImpl();
144 : }
145 81 : }
146 :
147 36 : CHIP_ERROR UDPEndPoint::JoinMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress)
148 : {
149 36 : VerifyOrReturnError(aAddress.IsMulticast(), INET_ERROR_WRONG_ADDRESS_TYPE);
150 :
151 36 : switch (aAddress.Type())
152 : {
153 :
154 : #if INET_CONFIG_ENABLE_IPV4
155 18 : case IPAddressType::kIPv4:
156 18 : return IPv4JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, true);
157 : #endif // INET_CONFIG_ENABLE_IPV4
158 :
159 18 : case IPAddressType::kIPv6:
160 18 : return IPv6JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, true);
161 :
162 0 : default:
163 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
164 : }
165 : }
166 :
167 0 : CHIP_ERROR UDPEndPoint::LeaveMulticastGroup(InterfaceId aInterfaceId, const IPAddress & aAddress)
168 : {
169 0 : VerifyOrReturnError(aAddress.IsMulticast(), INET_ERROR_WRONG_ADDRESS_TYPE);
170 :
171 0 : switch (aAddress.Type())
172 : {
173 :
174 : #if INET_CONFIG_ENABLE_IPV4
175 0 : case IPAddressType::kIPv4:
176 0 : return IPv4JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, false);
177 : #endif // INET_CONFIG_ENABLE_IPV4
178 :
179 0 : case IPAddressType::kIPv6:
180 0 : return IPv6JoinLeaveMulticastGroupImpl(aInterfaceId, aAddress, false);
181 :
182 0 : default:
183 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
184 : }
185 : }
186 :
187 : } // namespace Inet
188 : } // namespace chip
|