1 /*
2  * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <cstdint>
16 #include <sys/select.h>
17 #include <sys/time.h>
18 #include "system_func_mock.h"
19 #include "address_utils.h"
20 #include "dhcp_define.h"
21 #include "dhcp_server_ipv4.h"
22 #include "dhcp_logger.h"
23 #include "dhcp_message.h"
24 #include "dhcp_message_sim.h"
25 #include "dhcp_option.h"
26 #include "securec.h"
27 
28 DEFINE_DHCPLOG_DHCP_LABEL("DhcpServerSystemFuncMock");
29 
30 using namespace OHOS::DHCP;
31 
32 #define MAGIC_COOKIE_LENGTH 4
33 #define OPT_HEADER_LENGTH 2
34 #define TIME_SEC_TO_USEC (1000 * 1000)
35 
36 static bool g_mockTag = false;
37 static int TIME_MSEC_TO_USEC = 1000;
GetInstance()38 SystemFuncMock &SystemFuncMock::GetInstance()
39 {
40     static SystemFuncMock gSystemFuncMock;
41     return gSystemFuncMock;
42 };
43 
SystemFuncMock()44 SystemFuncMock::SystemFuncMock() {}
45 
~SystemFuncMock()46 SystemFuncMock::~SystemFuncMock() {}
47 
SetMockFlag(bool flag)48 void SystemFuncMock::SetMockFlag(bool flag)
49 {
50     g_mockTag = flag;
51 }
52 
GetMockFlag(void)53 bool SystemFuncMock::GetMockFlag(void)
54 {
55     return g_mockTag;
56 }
57 
58 extern "C" {
59 struct in_addr {
60     uint32_t s_addr;
61 };
62 
63 struct sockaddr_in {
64     short int sin_family;
65     unsigned short int sin_port;
66     struct in_addr sin_addr;
67     unsigned char sin_zero[8];
68 };
69 
70 int __real_open(const char *__file, int __oflag);
__wrap_open(const char * __file,int __oflag)71 int __wrap_open(const char *__file, int __oflag)
72 {
73     if (g_mockTag) {
74         return SystemFuncMock::GetInstance().open(__file, __oflag);
75     } else {
76         return __real_open(__file, __oflag);
77     }
78 }
79 
80 ssize_t __real_write(int fd, const void *buf, size_t count);
__wrap_write(int fd,const void * buf,size_t count)81 ssize_t __wrap_write(int fd, const void *buf, size_t count)
82 {
83     if (g_mockTag) {
84         return SystemFuncMock::GetInstance().write(fd, buf, count);
85     } else {
86         return __real_write(fd, buf, count);
87     }
88 }
89 
90 ssize_t __real_read(int fd, void *buf, size_t count);
__wrap_read(int fd,void * buf,size_t count)91 ssize_t __wrap_read(int fd, void *buf, size_t count)
92 {
93     if (g_mockTag) {
94         return SystemFuncMock::GetInstance().read(fd, buf, count);
95     } else {
96         return __real_read(fd, buf, count);
97     }
98 }
99 
100 int __real_socket(int __domain, int __type, int __protocol);
__wrap_socket(int __domain,int __type,int __protocol)101 int __wrap_socket(int __domain, int __type, int __protocol)
102 {
103     DHCP_LOGD("==>socket.");
104     if (g_mockTag) {
105         DHCP_LOGD(" ==>mock enable.");
106         return SystemFuncMock::GetInstance().socket(__domain, __type, __protocol);
107     } else {
108         DHCP_LOGD(" ==>mock disable.");
109     }
110     return __real_socket(__domain, __type, __protocol);
111 }
112 
113 int __real_setsockopt(int __fd, int __level, int __optname, const void *__optval, socklen_t __optlen);
__wrap_setsockopt(int __fd,int __level,int __optname,const void * __optval,socklen_t __optlen)114 int __wrap_setsockopt(int __fd, int __level, int __optname, const void *__optval, socklen_t __optlen)
115 {
116     DHCP_LOGD("==>setsockopt.");
117     if (g_mockTag) {
118         DHCP_LOGD(" ==>mock enable.");
119         return SystemFuncMock::GetInstance().setsockopt(__fd, __level, __optname, __optval, __optlen);
120     } else {
121         DHCP_LOGD(" ==>mock disable.");
122     }
123     return __real_setsockopt(__fd, __level, __optname, __optval, __optlen);
124 }
125 
126 int __real_select(int __nfds, fd_set *__readfds, fd_set *__writefds, fd_set *__exceptfds, struct timeval *__timeout);
__wrap_select(int __nfds,fd_set * __readfds,fd_set * __writefds,fd_set * __exceptfds,struct timeval * __timeout)127 int __wrap_select(int __nfds, fd_set *__readfds, fd_set *__writefds, fd_set *__exceptfds, struct timeval *__timeout)
128 {
129     const unsigned int SLEEP_TIEM = 300000;
130     DHCP_LOGD("==>select.");
131     if (g_mockTag) {
132         DHCP_LOGD(" ==>mock enable.");
133         DHCP_LOGD("message queue total: %d.", DhcpMsgManager::GetInstance().SendTotal());
134         if (DhcpMsgManager::GetInstance().SendTotal() > 0) {
135             FD_CLR(__nfds, __readfds);
136             usleep(SLEEP_TIEM);
137             return 1;
138         }
139         int retval = SystemFuncMock::GetInstance().select(__nfds, __readfds, __writefds, __exceptfds, __timeout);
140         if (retval == 0) {
141             if (__timeout != nullptr) {
142                 usleep(DHCP_SEL_WAIT_TIMEOUTS * TIME_MSEC_TO_USEC);
143                 DHCP_LOGD("select time out.");
144             }
145         }
146         return retval;
147     } else {
148         DHCP_LOGD(" ==>mock disable.");
149     }
150     return __real_select(__nfds, __readfds, __writefds, __exceptfds, __timeout);
151 }
152 
153 int __real_ioctl(int __fd, unsigned long __request, struct sockaddr *__ifreq);
__wrap_ioctl(int __fd,unsigned long __request,struct sockaddr * __ifreq)154 int __wrap_ioctl(int __fd, unsigned long __request, struct sockaddr *__ifreq)
155 {
156     if (g_mockTag) {
157         return SystemFuncMock::GetInstance().ioctl(__fd, __request, __ifreq);
158     } else {
159         return __real_ioctl(__fd, __request, __ifreq);
160     }
161 }
162 
163 int __real_listen(int __fd, int __n);
__wrap_listen(int __fd,int __n)164 int __wrap_listen(int __fd, int __n)
165 {
166     if (g_mockTag) {
167         return SystemFuncMock::GetInstance().listen(__fd, __n);
168     } else {
169         return __real_listen(__fd, __n);
170     }
171 }
172 
173 int __real_connect(int __fd, const struct sockaddr *__addr, socklen_t __len);
__wrap_connect(int __fd,const struct sockaddr * __addr,socklen_t __len)174 int __wrap_connect(int __fd, const struct sockaddr *__addr, socklen_t __len)
175 {
176     if (g_mockTag) {
177         return SystemFuncMock::GetInstance().connect(__fd, __addr, __len);
178     } else {
179         return __real_connect(__fd, __addr, __len);
180     }
181 }
182 
183 pid_t __real_vfork();
__wrap_vfork()184 pid_t __wrap_vfork()
185 {
186     if (g_mockTag) {
187         return SystemFuncMock::GetInstance().vfork();
188     } else {
189         return __real_vfork();
190     }
191 }
192 
193 int __real_execv(const char *__path, char *const *__argv);
__wrap_execv(const char * __path,char * const * __argv)194 int __wrap_execv(const char *__path, char *const *__argv)
195 {
196     if (g_mockTag) {
197         return SystemFuncMock::GetInstance().execv(__path, __argv);
198     } else {
199         return __real_execv(__path, __argv);
200     }
201 }
202 
203 void __real__exit(int status);
__wrap__exit(int status)204 void __wrap__exit(int status)
205 {
206     if (g_mockTag) {
207         SystemFuncMock::GetInstance()._exit(status);
208     } else {
209         __real__exit(status);
210     }
211     return;
212 }
213 
214 pid_t __real_waitpid(pid_t pid, int *status, int options);
__wrap_waitpid(pid_t pid,int * status,int options)215 pid_t __wrap_waitpid(pid_t pid, int *status, int options)
216 {
217     if (g_mockTag) {
218         return SystemFuncMock::GetInstance().waitpid(pid, status, options);
219     } else {
220         return __real_waitpid(pid, status, options);
221     }
222 }
223 
224 int __real_kill(pid_t pid, int sig);
__wrap_kill(pid_t pid,int sig)225 int __wrap_kill(pid_t pid, int sig)
226 {
227     if (g_mockTag) {
228         return SystemFuncMock::GetInstance().kill(pid, sig);
229     } else {
230         return __real_kill(pid, sig);
231     }
232 }
233 
234 int __real_bind(int __fd, struct sockaddr *__addr, socklen_t __len);
__wrap_bind(int __fd,struct sockaddr * __addr,socklen_t __len)235 int __wrap_bind(int __fd, struct sockaddr *__addr, socklen_t __len)
236 {
237     DHCP_LOGD("==>bind.");
238     if (g_mockTag) {
239         DHCP_LOGD(" ==>mock enable.");
240         return SystemFuncMock::GetInstance().bind(__fd, __addr, __len);
241     } else {
242         DHCP_LOGD(" ==>mock disable.");
243     }
244     return __real_bind(__fd, __addr, __len);
245 }
246 
247 int __real_close(int _fileno);
__wrap_close(int _fileno)248 int __wrap_close(int _fileno)
249 {
250     DHCP_LOGD("==>close.");
251     if (g_mockTag) {
252         DHCP_LOGD(" ==>mock enable.");
253         return SystemFuncMock::GetInstance().close(_fileno);
254     } else {
255         DHCP_LOGD(" ==>mock disable.");
256     }
257     return __real_close(_fileno);
258 }
259 
recvfrom(int __fd,void * __buf,size_t __n,int __flags,struct sockaddr * __addr,socklen_t * __addr_len)260 ssize_t recvfrom(int __fd, void *__buf, size_t __n, int __flags, struct sockaddr *__addr, socklen_t *__addr_len)
261 {
262     DHCP_LOGD("==>recvfrom.");
263     if (!g_mockTag) {
264         DHCP_LOGD(" ==>mock disable.");
265         return SystemFuncMock::GetInstance().recvfrom(__fd, __buf, __n, __flags, __addr, __addr_len);
266     }
267     DHCP_LOGD(" ==>mock enable.");
268     if (DhcpMsgManager::GetInstance().SendTotal() > 0 && __buf) {
269         DHCP_LOGD("== new message received.");
270         DhcpMessage msg = { 0 };
271         if (DhcpMsgManager::GetInstance().FrontSendMsg(&msg)) {
272             (void)memcpy_s(__buf, __n, &msg, sizeof(DhcpMessage));
273             DhcpMsgManager::GetInstance().PopSendMsg();
274             uint32_t srcIp = DhcpMsgManager::GetInstance().GetClientIp();
275             if (__addr != nullptr && srcIp != 0) {
276                 struct sockaddr_in *sAddr = reinterpret_cast<sockaddr_in *>(__addr);
277                 sAddr->sin_addr.s_addr = HostToNetwork(srcIp);
278                 DhcpMsgManager::GetInstance().SetClientIp(0);
279             }
280             return sizeof(DhcpMessage);
281         }
282     }
283     return SystemFuncMock::GetInstance().recvfrom(__fd, __buf, __n, __flags, __addr, __addr_len);
284 }
285 
ParseMockOptions(DhcpMessage * packet)286 int ParseMockOptions(DhcpMessage *packet)
287 {
288     if (packet == nullptr) {
289         DHCP_LOGD("dhcp message pointer is null.");
290         return RET_FAILED;
291     }
292     DhcpMsgInfo reply;
293     if (memset_s(&reply, sizeof(DhcpMsgInfo), 0, sizeof(DhcpMsgInfo)) != EOK) {
294         DHCP_LOGD("failed to reset dhcp message info.");
295         return RET_FAILED;
296     }
297     int retval = RET_FAILED;
298     if (memcpy_s(&reply.packet, sizeof(reply.packet), packet, sizeof(DhcpMessage)) != EOK) {
299         DHCP_LOGD("failed to fill dhcp message.");
300         return RET_FAILED;
301     }
302     reply.length = sizeof(DhcpMessage);
303     if (InitOptionList(&reply.options) != RET_SUCCESS) {
304         DHCP_LOGD("failed to init dhcp option list.");
305         return retval;
306     }
307     FreeOptionList(&reply.options);
308     return retval;
309 }
310 
sendto(int __fd,const void * __buf,size_t __n,int __flags,struct sockaddr * __addr,socklen_t __addr_len)311 ssize_t sendto(int __fd, const void *__buf, size_t __n, int __flags, struct sockaddr *__addr, socklen_t __addr_len)
312 {
313     DHCP_LOGD("==>sendto.");
314     if (g_mockTag) {
315         DHCP_LOGD(" ==>mock enable.");
316         if (__buf == nullptr) {
317             return SystemFuncMock::GetInstance().sendto(__fd, __buf, __n, __flags, __addr, __addr_len);
318         }
319     } else {
320         DHCP_LOGD(" ==>mock disable.");
321     }
322     return SystemFuncMock::GetInstance().sendto(__fd, __buf, __n, __flags, __addr, __addr_len);
323 }
324 }
325