1 /*
2  * Copyright (C) 2021 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 
16 #include "securec.h"
17 #include "nstackx_epoll.h"
18 #include "nstackx_log.h"
19 #include "nstackx_error.h"
20 #include "nstackx_list.h"
21 #include "nstackx_socket.h"
22 #include "nstackx_timer.h"
23 
24 #define TAG "nStackXEpoll"
25 
26 #ifndef LWIP_LITEOS_A_COMPAT
27 #define IS_INVALID_SOCKET_DESC(fd) \
28     (((fd) < LWIP_SOCKET_OFFSET) || ((fd) >= (LWIP_CONFIG_NUM_SOCKETS + LWIP_SOCKET_OFFSET)))
29 #define EVENT_PTR_IDX(fd) ((fd) - (LWIP_SOCKET_OFFSET))
30 #else
31 #define IS_INVALID_SOCKET_DESC(fd) ((fd) < 0)
32 #endif /* LWIP_LITEOS_A_COMPAT */
33 
34 typedef struct {
35     fd_set *readfds;
36     fd_set *writefds;
37     fd_set *exceptfds;
38 } EpollSetPtr;
39 
40 typedef struct {
41     struct EpollDescStr epollfd;
42     int32_t maxfd;
43     fd_set readfds;
44     fd_set writefds;
45     fd_set exceptfds;
46     pthread_mutex_t mutex;
47 } EpollSet;
48 
49 #ifdef LWIP_LITEOS_A_COMPAT
50 struct EpollTaskList {
51     List list;
52     EpollTask *taskPtr;
53 };
54 
55 struct EpollEventPtr {
56     List list;
57     List taskList;
58     EpollSet *epollSetPtr;
59 };
60 #else
61 struct EpollEventPtr {
62     EpollSet *epollSetPtr;
63     EpollTask *taskPtr;
64 };
65 #endif
66 
67 typedef void (*EpollTraverseFunc)(EpollSet *epollSetPtr, void *param, int32_t fd);
68 typedef void (*EpollEventCtrlFunc)(EpollSet *epollSetPtr, uint32_t events, EpollTask *task);
69 
70 static uint8_t g_epollInited = NSTACKX_FALSE;
71 static pthread_mutex_t g_epollEventPtrMutex;
72 
73 #ifdef LWIP_LITEOS_A_COMPAT
74 static List g_epollEventPtrList;
75 #else
76 static struct EpollEventPtr *g_epollEventPtrArray = NULL;
77 #endif
78 
79 static void EpollFdEventAdd(EpollSet *epollSetPtr, uint32_t events, EpollTask *task);
80 static void EpollFdEventDel(EpollSet *epollSetPtr, uint32_t events, EpollTask *task);
81 static void EpollFdEventMod(EpollSet *epollSetPtr, uint32_t events, EpollTask *task);
82 
CtlEpollDesc(EpollTask * task,int op,uint32_t events)83 static int32_t CtlEpollDesc(EpollTask *task, int op, uint32_t events)
84 {
85     struct EpollEvent event;
86 #ifdef NSTACKX_DEBUG
87     static uint32_t evtCnt = 0;
88 #endif
89 
90     if ((task == NULL) || ((op != EPOLL_CTL_RUN) && IS_INVALID_SOCKET_DESC(task->taskfd)) ||
91         (!IsEpollDescValid(task->epollfd))) {
92         LOGE(TAG, "invalid params");
93         return NSTACKX_EINVAL;
94     }
95 
96     event.op = op;
97     event.events = events;
98     event.ptr = (void *)task;
99 #ifdef NSTACKX_DEBUG
100     event.evtSeq = evtCnt++;
101     LOGD(TAG, "%d op %d event seq: %u", task->epollfd->recvFd, op, event.evtSeq);
102 #endif
103     if (sendto(task->epollfd->sendFd, (const void *)&event, sizeof(event), 0, NULL, 0) < 0) {
104         LOGE(TAG, "ctrl epollfd failed: %d", errno);
105         return NSTACKX_EFAILED;
106     }
107 
108     return NSTACKX_EOK;
109 }
110 
CtlEpollDescSync(EpollTask * task,EpollEventCtrlFunc func,uint32_t events)111 static int32_t CtlEpollDescSync(EpollTask *task, EpollEventCtrlFunc func, uint32_t events)
112 {
113     EpollSet *epollSetPtr = NULL;
114     if ((task == NULL) || IS_INVALID_SOCKET_DESC(task->taskfd) || (!IsEpollDescValid(task->epollfd))) {
115         LOGE(TAG, "invalid params");
116         return NSTACKX_EINVAL;
117     }
118 
119     epollSetPtr = container_of(task->epollfd, EpollSet, epollfd);
120     if (pthread_mutex_lock(&(epollSetPtr->mutex)) != 0) {
121         LOGE(TAG, "pthread mutex lock error");
122         return NSTACKX_EFAILED;
123     }
124     func(epollSetPtr, events, task);
125     if (pthread_mutex_unlock(&(epollSetPtr->mutex)) != 0) {
126         LOGE(TAG, "pthread mutex unlock error");
127     }
128 
129     return NSTACKX_EOK;
130 }
131 
RunEpollTask(void * task,uint32_t events)132 int32_t RunEpollTask(void *task, uint32_t events)
133 {
134     return CtlEpollDesc((EpollTask *)task, EPOLL_CTL_RUN, events);
135 }
136 
RefreshEpollTask(EpollTask * task,uint32_t events)137 int32_t RefreshEpollTask(EpollTask *task, uint32_t events)
138 {
139     return CtlEpollDescSync(task, EpollFdEventMod, events);
140 }
141 
RegisterEpollTask(EpollTask * task,uint32_t events)142 int32_t RegisterEpollTask(EpollTask *task, uint32_t events)
143 {
144     return CtlEpollDescSync(task, EpollFdEventAdd, events);
145 }
146 
DeRegisterEpollTask(EpollTask * task)147 int32_t DeRegisterEpollTask(EpollTask *task)
148 {
149     return CtlEpollDescSync(task, EpollFdEventDel, 0);
150 }
151 
152 #ifdef LWIP_LITEOS_A_COMPAT
EpollSetFindByFd(int32_t fd)153 static EpollSet *EpollSetFindByFd(int32_t fd)
154 {
155     List *curr = NULL;
156     struct EpollEventPtr *ptr = NULL;
157     LIST_FOR_EACH(curr, &g_epollEventPtrList) {
158         ptr = container_of(curr, struct EpollEventPtr, list);
159         if (FD_ISSET(fd, &(ptr->epollSetPtr->exceptfds))) {
160             return ptr->epollSetPtr;
161         }
162     }
163     return NULL;
164 }
165 
EpollEventListFind(const EpollSet * epollSetPtr)166 static struct EpollEventPtr *EpollEventListFind(const EpollSet *epollSetPtr)
167 {
168     List *curr = NULL;
169     struct EpollEventPtr *ptr = NULL;
170     LIST_FOR_EACH(curr, &g_epollEventPtrList) {
171         ptr = container_of(curr, struct EpollEventPtr, list);
172         if (ptr->epollSetPtr == epollSetPtr) {
173             return ptr;
174         }
175     }
176     return NULL;
177 }
178 
EpollTaskListFind(const struct EpollEventPtr * ptr,const EpollTask * task)179 static struct EpollTaskList *EpollTaskListFind(const struct EpollEventPtr *ptr, const EpollTask *task)
180 {
181     List *curr = NULL;
182     struct EpollTaskList *taskListPtr = NULL;
183     LIST_FOR_EACH(curr, &(ptr->taskList)) {
184         taskListPtr = container_of(curr, struct EpollTaskList, list);
185         if (taskListPtr->taskPtr == task) {
186             return taskListPtr;
187         }
188     }
189     return NULL;
190 }
191 
EpollTaskListNew(EpollTask * task)192 static struct EpollTaskList *EpollTaskListNew(EpollTask *task)
193 {
194     struct EpollTaskList *taskListPtr = (struct EpollTaskList *)malloc(sizeof(struct EpollTaskList));
195     if (taskListPtr == NULL) {
196         LOGE(TAG, "alloc EpollTaskList failed");
197         return NULL;
198     }
199     (void)memset_s(taskListPtr, sizeof(*taskListPtr), 0, sizeof(*taskListPtr));
200     taskListPtr->taskPtr = task;
201     ListInitHead(&(taskListPtr->list));
202     return taskListPtr;
203 }
204 
EpollEventTaskListAdd(const EpollSet * epollSetPtr,EpollTask * task)205 static int32_t EpollEventTaskListAdd(const EpollSet *epollSetPtr, EpollTask *task)
206 {
207     struct EpollEventPtr *ptr = EpollEventListFind(epollSetPtr);
208     struct EpollTaskList *taskListPtr = NULL;
209     if (ptr == NULL) {
210         LOGE(TAG, "EpollSet not in list");
211         return NSTACKX_NOEXIST;
212     }
213     taskListPtr = EpollTaskListNew(task);
214     if (taskListPtr == NULL) {
215         return NSTACKX_ENOMEM;
216     }
217     ListInsertTail(&(ptr->taskList), &(taskListPtr->list));
218     return NSTACKX_EOK;
219 }
220 
EpollEventTaskListDel(const EpollSet * epollSetPtr,const EpollTask * task)221 static void EpollEventTaskListDel(const EpollSet *epollSetPtr, const EpollTask *task)
222 {
223     struct EpollEventPtr *ptr = EpollEventListFind(epollSetPtr);
224     struct EpollTaskList *taskListPtr = NULL;
225     if (ptr == NULL) {
226         LOGE(TAG, "EpollSet not in list");
227         return;
228     }
229     taskListPtr = EpollTaskListFind(ptr, task);
230     if (taskListPtr == NULL) {
231         return;
232     }
233     ListRemoveNode(&(taskListPtr->list));
234     free(taskListPtr);
235     return;
236 }
237 
EpollTaskFindByFd(const struct EpollEventPtr * ptr,int32_t fd)238 static EpollTask *EpollTaskFindByFd(const struct EpollEventPtr *ptr, int32_t fd)
239 {
240     List *curr = NULL;
241     struct EpollTaskList *taskListPtr = NULL;
242     LIST_FOR_EACH(curr, &(ptr->taskList)) {
243         taskListPtr = container_of(curr, struct EpollTaskList, list);
244         if (taskListPtr->taskPtr->taskfd == fd) {
245             return taskListPtr->taskPtr;
246         }
247     }
248     return NULL;
249 }
250 
EpollSetFindTaskByFd(const EpollSet * epollSetPtr,int32_t fd)251 static EpollTask *EpollSetFindTaskByFd(const EpollSet *epollSetPtr, int32_t fd)
252 {
253     struct EpollEventPtr *ptr = EpollEventListFind(epollSetPtr);
254     if (ptr == NULL) {
255         LOGE(TAG, "EpollSet not in list");
256         return NULL;
257     }
258     return EpollTaskFindByFd(ptr, fd);
259 }
260 #endif /* LWIP_LITEOS_A_COMPAT */
261 
ConnectPeerFd(int32_t localFd,int32_t peerFd)262 static int32_t ConnectPeerFd(int32_t localFd, int32_t peerFd)
263 {
264     struct sockaddr_in addr = {0};
265     socklen_t addr_len = sizeof(addr);
266 
267     if (getsockname(peerFd, (struct sockaddr *)&addr, &addr_len) != 0) {
268         LOGE(TAG, "getsockname failed: %d", errno);
269         return NSTACKX_EFAILED;
270     }
271     if (connect(localFd, (struct sockaddr *)&addr, addr_len) != 0) {
272         LOGE(TAG, "connect failed: %d", errno);
273         return NSTACKX_EFAILED;
274     }
275 
276     return NSTACKX_EOK;
277 }
278 
GetLoopbackFd(int32_t peerFd)279 static int32_t GetLoopbackFd(int32_t peerFd)
280 {
281     int32_t fd;
282     struct sockaddr_in addr = {0};
283     struct sockaddr *sockaddr = NULL;
284     socklen_t addr_len;
285 
286     addr.sin_family = AF_INET;
287     addr.sin_port = 0;
288     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
289     sockaddr = (struct sockaddr *)&addr;
290     addr_len = sizeof(addr);
291 
292     fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
293     if (fd < 0) {
294         LOGE(TAG, "socket failed: %d", errno);
295         return -1;
296     }
297 
298     if (SetSocketNonBlock(fd) != NSTACKX_EOK) {
299         LOGE(TAG, "set socket nonblock failed");
300         close(fd);
301         return -1;
302     }
303 
304     if (bind(fd, sockaddr, addr_len) != 0) {
305         LOGE(TAG, "bind failed: %d", errno);
306         close(fd);
307         return -1;
308     }
309 
310     if (peerFd < 0) {
311         /* if peerFd is invalid, there is no need to connect to it, just return */
312         return fd;
313     }
314 
315     if ((ConnectPeerFd(fd, peerFd) == NSTACKX_EFAILED) || (ConnectPeerFd(peerFd, fd) == NSTACKX_EFAILED)) {
316         close(fd);
317         return -1;
318     }
319 
320     return fd;
321 }
322 
CreateEpollFdPair(struct EpollDescStr * epollfd)323 int32_t CreateEpollFdPair(struct EpollDescStr *epollfd)
324 {
325     if (epollfd == NULL) {
326         LOGE(TAG, "invalid param");
327         return NSTACKX_EINVAL;
328     }
329 
330     epollfd->recvFd = GetLoopbackFd(-1);
331     if (epollfd->recvFd < 0) {
332         epollfd->recvFd = -1;
333         epollfd->sendFd = -1;
334         return NSTACKX_EFAILED;
335     }
336 
337     epollfd->sendFd = GetLoopbackFd(epollfd->recvFd);
338     if (epollfd->sendFd < 0) {
339         close(epollfd->recvFd);
340         epollfd->recvFd = -1;
341         epollfd->sendFd = -1;
342         return NSTACKX_EFAILED;
343     }
344 
345     return NSTACKX_EOK;
346 }
347 
EpollEventPtrInit(void)348 void EpollEventPtrInit(void)
349 {
350     if (g_epollInited == NSTACKX_TRUE) {
351         return;
352     }
353     /* this function is called when init lwip thread */
354     if (pthread_mutex_init(&g_epollEventPtrMutex, NULL) != 0) {
355         LOGE(TAG, "pthread_mutex_init error");
356         return;
357     }
358 #ifdef LWIP_LITEOS_A_COMPAT
359     ListInitHead(&g_epollEventPtrList);
360 #else
361     /* as ported to LwIP, once the memory is allocated, it will not be freed ever */
362     g_epollEventPtrArray = (struct EpollEventPtr *)malloc(LWIP_CONFIG_NUM_SOCKETS * sizeof(struct EpollEventPtr));
363     if (g_epollEventPtrArray == NULL) {
364         LOGE(TAG, "malloc epoll ptr array failed");
365         return;
366     }
367     (void)memset_s(g_epollEventPtrArray, LWIP_CONFIG_NUM_SOCKETS * sizeof(struct EpollEventPtr), 0x0,
368         LWIP_CONFIG_NUM_SOCKETS * sizeof(struct EpollEventPtr));
369 #endif
370     g_epollInited = NSTACKX_TRUE;
371     LOGD(TAG, "epoll event init success");
372     return;
373 }
374 
EpollEventRecordAdd(EpollSet * epollSetPtr)375 static int32_t EpollEventRecordAdd(EpollSet *epollSetPtr)
376 {
377     if (pthread_mutex_lock(&g_epollEventPtrMutex) != 0) {
378         LOGE(TAG, "pthread mutex lock error");
379         return NSTACKX_EFAILED;
380     }
381 #ifdef LWIP_LITEOS_A_COMPAT
382     struct EpollEventPtr *ptr = (struct EpollEventPtr *)malloc(sizeof(struct EpollEventPtr));
383     if (ptr == NULL) {
384         if (pthread_mutex_unlock(&g_epollEventPtrMutex) != 0) {
385             LOGE(TAG, "pthread mutex unlock error");
386         }
387         LOGE(TAG, "EpollEventPtr alloc failed");
388         return NSTACKX_ENOMEM;
389     }
390     (void)memset_s(ptr, sizeof(struct EpollEventPtr), 0, sizeof(struct EpollEventPtr));
391     ListInitHead(&(ptr->list));
392     ListInitHead(&(ptr->taskList));
393     ptr->epollSetPtr = epollSetPtr;
394     ListInsertTail(&g_epollEventPtrList, &(ptr->list));
395 #else
396     g_epollEventPtrArray[EVENT_PTR_IDX(epollSetPtr->epollfd.recvFd)].epollSetPtr = epollSetPtr;
397     g_epollEventPtrArray[EVENT_PTR_IDX(epollSetPtr->epollfd.sendFd)].epollSetPtr = epollSetPtr;
398 #endif
399     if (pthread_mutex_unlock(&g_epollEventPtrMutex) != 0) {
400         /* just give log, no error returned */
401         LOGE(TAG, "pthread mutex unlock error");
402     }
403     return NSTACKX_EOK;
404 }
405 
CreateEpollDesc(void)406 EpollDesc CreateEpollDesc(void)
407 {
408     EpollSet *epollSetPtr = NULL;
409 
410     if (g_epollInited != NSTACKX_TRUE) {
411         LOGE(TAG, "Epoll Event Ptr Not Init");
412         return NULL;
413     }
414 
415     epollSetPtr = (EpollSet *)malloc(sizeof(EpollSet));
416     if (epollSetPtr == NULL) {
417         LOGE(TAG, "malloc EpollSet failed");
418         return NULL;
419     }
420     (void)memset_s(epollSetPtr, sizeof(EpollSet), 0, sizeof(EpollSet));
421 
422     if (pthread_mutex_init(&(epollSetPtr->mutex), NULL) != 0) {
423         LOGE(TAG, "pthread_mutex_init error");
424         goto FAIL_FREE;
425     }
426 
427     if (CreateEpollFdPair(&(epollSetPtr->epollfd)) != NSTACKX_EOK) {
428         LOGE(TAG, "Create Epoll failed");
429         goto FAIL_MUTEX;
430     }
431 
432     FD_SET(epollSetPtr->epollfd.recvFd, &epollSetPtr->readfds);
433     FD_SET(epollSetPtr->epollfd.recvFd, &epollSetPtr->exceptfds);
434     epollSetPtr->maxfd = epollSetPtr->epollfd.recvFd;
435 
436     if (EpollEventRecordAdd(epollSetPtr) != NSTACKX_EOK) {
437         goto FAIL_CLOSE;
438     }
439 
440     return &(epollSetPtr->epollfd);
441 FAIL_CLOSE:
442     close(epollSetPtr->epollfd.recvFd);
443     close(epollSetPtr->epollfd.sendFd);
444 FAIL_MUTEX:
445     if (pthread_mutex_destroy(&(epollSetPtr->mutex)) != 0) {
446         LOGE(TAG, "pthread mutex destroy error: %d", errno);
447     }
448 FAIL_FREE:
449     free(epollSetPtr);
450     return NULL;
451 }
452 
RearZeroBitNum(unsigned long x)453 static int32_t RearZeroBitNum(unsigned long x)
454 {
455     int32_t n = 1;
456     int bitMov = TYPE_BITS_NUM(x) >> 1;
457     int bitNum = bitMov;
458 
459     /* through binarySearch */
460     while (bitNum > 1) {
461         if ((x << bitMov) == 0) {
462             n = n + bitNum;
463             x = x >> bitNum;
464         }
465         bitNum = bitNum >> 1;
466         bitMov += bitNum;
467     }
468 
469     n = n - (x & 1);
470     return n;
471 }
472 
PreZeroBitNum(unsigned long x)473 static int32_t PreZeroBitNum(unsigned long x)
474 {
475     int n = 1;
476     int bitMov = TYPE_BITS_NUM(x) >> 1;
477     int bitNum = bitMov;
478 
479     /* through binarySearch */
480     while (bitNum > 1) {
481         if ((x >> bitMov) == 0) {
482             n = n + bitNum;
483             x = x << bitNum;
484         }
485         bitNum = bitNum >> 1;
486         bitMov += bitNum;
487     }
488 
489     n = n - (x >> (TYPE_BITS_NUM(x) - 1));
490     return n;
491 }
492 
EpollTaskEventHandle(uint32_t events,EpollTask * task)493 static void EpollTaskEventHandle(uint32_t events, EpollTask *task)
494 {
495     if ((events & EPOLLERR) == EPOLLERR) {
496         if (task->errorHandle != NULL) {
497             task->errorHandle(task);
498         }
499         return;
500     }
501 
502     if (((events & EPOLLIN) == EPOLLIN) && (task->readHandle != NULL)) {
503         task->readHandle(task);
504     }
505 
506     /* Caution: It is possible for xxxHandle to free the Timer struct part of which the `task` is pointing to.
507      * See ClientSettingTimeoutHandle() and ServerSettingTimeoutHandle() functions for an example. Coders must
508      * logically assert that the `task` pointer will never be dereferenced if its content is previously freed.
509      */
510     if (((events & EPOLLOUT) == EPOLLOUT) && (task->writeHandle != NULL)) {
511         task->writeHandle(task);
512     }
513 }
514 
EpollFdEventTaskAdd(EpollSet * epollSetPtr,EpollTask * task)515 static int32_t EpollFdEventTaskAdd(EpollSet *epollSetPtr, EpollTask *task)
516 {
517     int32_t ret = NSTACKX_EOK;
518     if (pthread_mutex_lock(&g_epollEventPtrMutex) != 0) {
519         LOGE(TAG, "pthread mutex lock error");
520         return NSTACKX_EFAILED;
521     }
522 #ifdef LWIP_LITEOS_A_COMPAT
523     if (EpollEventTaskListAdd(epollSetPtr, task) != NSTACKX_EOK) {
524         ret = NSTACKX_EFAILED;
525     }
526 #else
527     g_epollEventPtrArray[EVENT_PTR_IDX(task->taskfd)].epollSetPtr = epollSetPtr;
528     g_epollEventPtrArray[EVENT_PTR_IDX(task->taskfd)].taskPtr = task;
529 #endif
530     if (pthread_mutex_unlock(&g_epollEventPtrMutex) != 0) {
531         LOGE(TAG, "pthread mutex unlock error");
532     }
533     return ret;
534 }
535 
EpollFdEventAdd(EpollSet * epollSetPtr,uint32_t events,EpollTask * task)536 static void EpollFdEventAdd(EpollSet *epollSetPtr, uint32_t events, EpollTask *task)
537 {
538 #ifndef LWIP_LITEOS_A_COMPAT
539     EpollSet *setPtr = g_epollEventPtrArray[EVENT_PTR_IDX(task->taskfd)].epollSetPtr;
540     if ((setPtr != NULL) && (setPtr != epollSetPtr)) {
541         LOGE(TAG, "ADD: fd %d ptr has been used", task->taskfd);
542         return;
543     }
544 #endif
545     if (FD_ISSET(task->taskfd, &epollSetPtr->exceptfds)) {
546         LOGD(TAG, "ADD: fd %d has in epoll ctl", task->taskfd);
547         return;
548     }
549     if ((events & (EPOLLIN | EPOLLOUT)) == 0) {
550         LOGI(TAG, "invalid events");
551         return;
552     }
553     if ((events & EPOLLIN) == EPOLLIN) {
554         FD_SET(task->taskfd, &epollSetPtr->readfds);
555     }
556     if ((events & EPOLLOUT) == EPOLLOUT) {
557         FD_SET(task->taskfd, &epollSetPtr->writefds);
558     }
559     FD_SET(task->taskfd, &epollSetPtr->exceptfds);
560 
561     if (EpollFdEventTaskAdd(epollSetPtr, task) != NSTACKX_EOK) {
562         FD_CLR(task->taskfd, &epollSetPtr->readfds);
563         FD_CLR(task->taskfd, &epollSetPtr->writefds);
564         FD_CLR(task->taskfd, &epollSetPtr->exceptfds);
565         return;
566     }
567     if (task->taskfd > epollSetPtr->maxfd) {
568         epollSetPtr->maxfd = task->taskfd;
569     }
570 }
571 
EpollSetMaxFdUpdate(EpollSet * epollSetPtr)572 static void EpollSetMaxFdUpdate(EpollSet *epollSetPtr)
573 {
574     int32_t i, fd;
575 
576 #ifdef __LITEOS__
577 #ifdef FDSETSAFESET
578     for (i = (epollSetPtr->maxfd - LWIP_SOCKET_OFFSET) / BYTE_BITS_NUM; i >= 0; i--) {
579         uint8_t bits = epollSetPtr->exceptfds.fd_bits[i];
580 #else
581     for (i = epollSetPtr->maxfd / NFDBITS; i >= LWIP_SOCKET_OFFSET / NFDBITS; i--) {
582         unsigned long bits = epollSetPtr->exceptfds.fds_bits[i];
583 #endif
584 #else
585     for (i = epollSetPtr->maxfd / __NFDBITS; i >= LWIP_SOCKET_OFFSET / __NFDBITS; i--) {
586         unsigned long bits = (unsigned long)(__FDS_BITS(&(epollSetPtr->exceptfds))[i]);
587 #endif
588         if (bits == 0) {
589             continue;
590         }
591         int32_t bitIdx = PreZeroBitNum(bits);
592 #ifdef __LITEOS__
593 #ifdef FDSETSAFESET
594         fd = i * BYTE_BITS_NUM + (TYPE_BITS_NUM(unsigned long) - 1 - bitIdx) + LWIP_SOCKET_OFFSET;
595 #else
596         fd = i * NFDBITS + (TYPE_BITS_NUM(unsigned long) - 1 - bitIdx);
597 #endif
598 #else
599         fd = i * __NFDBITS + (TYPE_BITS_NUM(unsigned long) - 1 - bitIdx);
600 #endif
601         epollSetPtr->maxfd = fd;
602         break;
603     }
604 
605     return;
606 }
607 
608 static void EpollFdEventTaskDel(const EpollSet *epollSetPtr, const EpollTask *task)
609 {
610     if (pthread_mutex_lock(&g_epollEventPtrMutex) != 0) {
611         LOGE(TAG, "pthread mutex lock error");
612         return;
613     }
614 #ifdef LWIP_LITEOS_A_COMPAT
615     EpollEventTaskListDel(epollSetPtr, task);
616 #else
617     g_epollEventPtrArray[EVENT_PTR_IDX(task->taskfd)].epollSetPtr = NULL;
618     g_epollEventPtrArray[EVENT_PTR_IDX(task->taskfd)].taskPtr = NULL;
619 #endif
620     if (pthread_mutex_unlock(&g_epollEventPtrMutex) != 0) {
621         LOGE(TAG, "pthread mutex unlock error");
622     }
623 }
624 
625 static void EpollFdEventDel(EpollSet *epollSetPtr, uint32_t events, EpollTask *task)
626 {
627 #ifndef LWIP_LITEOS_A_COMPAT
628     EpollSet *setPtr = g_epollEventPtrArray[EVENT_PTR_IDX(task->taskfd)].epollSetPtr;
629     if ((setPtr != NULL) && (setPtr != epollSetPtr)) {
630         LOGE(TAG, "DEL: fd %d ptr has been used", task->taskfd);
631         return;
632     }
633 #endif
634     (void)events;
635     if (!FD_ISSET(task->taskfd, &epollSetPtr->exceptfds)) {
636         LOGD(TAG, "DEL: fd %d not in epoll ctl", task->taskfd);
637         return;
638     }
639     FD_CLR(task->taskfd, &epollSetPtr->readfds);
640     FD_CLR(task->taskfd, &epollSetPtr->writefds);
641     FD_CLR(task->taskfd, &epollSetPtr->exceptfds);
642 
643     EpollFdEventTaskDel(epollSetPtr, task);
644 
645     if (task->taskfd == epollSetPtr->maxfd) {
646         EpollSetMaxFdUpdate(epollSetPtr);
647     }
648 
649     return;
650 }
651 
652 static void EpollFdEventMod(EpollSet *epollSetPtr, uint32_t events, EpollTask *task)
653 {
654 #ifndef LWIP_LITEOS_A_COMPAT
655     EpollSet *setPtr = g_epollEventPtrArray[EVENT_PTR_IDX(task->taskfd)].epollSetPtr;
656     if ((setPtr != NULL) && (setPtr != epollSetPtr)) {
657         LOGE(TAG, "MOD: fd %d ptr has been used", task->taskfd);
658         return;
659     }
660 #endif
661     if (!FD_ISSET(task->taskfd, &epollSetPtr->exceptfds)) {
662         LOGD(TAG, "MOD: fd %d not in epoll ctl", task->taskfd);
663         return;
664     }
665     if ((events & (EPOLLIN | EPOLLOUT)) == 0) {
666         LOGI(TAG, "invalid events");
667         return;
668     }
669     FD_CLR(task->taskfd, &epollSetPtr->readfds);
670     FD_CLR(task->taskfd, &epollSetPtr->writefds);
671     if ((events & EPOLLIN) == EPOLLIN) {
672         FD_SET(task->taskfd, &epollSetPtr->readfds);
673     }
674     if ((events & EPOLLOUT) == EPOLLOUT) {
675         FD_SET(task->taskfd, &epollSetPtr->writefds);
676     }
677 
678     return;
679 }
680 
681 static void EpollFdEventRun(EpollSet *epollSetPtr, uint32_t events, EpollTask *task)
682 {
683     (void)epollSetPtr;
684     EpollTaskEventHandle(events, task);
685 }
686 
687 static void EpollFdEventOpHandle(EpollSet *epollSetPtr, int op, uint32_t events, EpollTask *task)
688 {
689     switch (op) {
690         case EPOLL_CTL_ADD:
691         case EPOLL_CTL_DEL:
692         case EPOLL_CTL_MOD:
693             break;
694         case EPOLL_CTL_RUN:
695             EpollFdEventRun(epollSetPtr, events, task);
696             break;
697         default:
698             LOGI(TAG, "unsupported op %u", op);
699             break;
700     }
701 }
702 
703 static void EpollFdEventHandle(EpollSet *epollSetPtr, fd_set *readfds)
704 {
705     int32_t ret;
706     EpollTask *task = NULL;
707     struct EpollEvent event;
708     if (!FD_ISSET(epollSetPtr->epollfd.recvFd, readfds)) {
709         return;
710     }
711 
712     while (NSTACKX_TRUE) {
713         ret = recvfrom(epollSetPtr->epollfd.recvFd, (void *)&event, sizeof(event), 0, NULL, NULL);
714         if (ret < (int32_t)(sizeof(event))) {
715             break;
716         }
717 #ifdef NSTACKX_DEBUG
718         LOGD(TAG, "Handle task %d event seq: %u", epollSetPtr->epollfd.recvFd, event.evtSeq);
719 #endif
720         task = (EpollTask *)event.ptr;
721         if (task == NULL) {
722             continue;
723         }
724         EpollFdEventOpHandle(epollSetPtr, event.op, event.events, task);
725     }
726 }
727 
728 static void EpollEventHandle(EpollSet *epollSetPtr, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, int32_t fd)
729 {
730     uint32_t events = 0;
731     EpollTask *task = NULL;
732 
733 #ifdef LWIP_LITEOS_A_COMPAT
734     task = EpollSetFindTaskByFd(epollSetPtr, fd);
735 #else
736     EpollSet *setPtr = g_epollEventPtrArray[EVENT_PTR_IDX(fd)].epollSetPtr;
737     if (setPtr != epollSetPtr) {
738         return;
739     }
740     task = g_epollEventPtrArray[EVENT_PTR_IDX(fd)].taskPtr;
741 #endif
742     if (task == NULL) {
743         return;
744     }
745 
746     if (FD_ISSET(fd, readfds)) {
747         events |= EPOLLIN;
748     }
749     if (FD_ISSET(fd, writefds)) {
750         events |= EPOLLOUT;
751     }
752     if (FD_ISSET(fd, exceptfds)) {
753         events |= EPOLLERR;
754     }
755     if (events == 0) {
756         return;
757     }
758 
759     EpollTaskEventHandle(events, task);
760 }
761 
762 static void EpollSetFdHandle(EpollSet *epollSetPtr, void *param, int32_t fd)
763 {
764     EpollSetPtr *setPtr = (EpollSetPtr *)param;
765     fd_set *readfds = setPtr->readfds;
766     fd_set *writefds = setPtr->writefds;
767     fd_set *exceptfds = setPtr->exceptfds;
768     if (fd == epollSetPtr->epollfd.recvFd) {
769         EpollFdEventHandle(epollSetPtr, readfds);
770 #ifdef LWIP_LITEOS_A_COMPAT
771     } else {
772 #else
773     } else if (g_epollEventPtrArray[EVENT_PTR_IDX(fd)].epollSetPtr == epollSetPtr) {
774 #endif
775         EpollEventHandle(epollSetPtr, readfds, writefds, exceptfds, fd);
776     }
777 }
778 
779 static void EpollSetTraverse(EpollSet *epollSetPtr, EpollTraverseFunc func, void *param)
780 {
781 #ifdef __LITEOS__
782 #ifdef FDSETSAFESET
783     for (int32_t i = 0; i <= (epollSetPtr->maxfd - LWIP_SOCKET_OFFSET) / BYTE_BITS_NUM; i++) {
784         uint8_t bits = epollSetPtr->exceptfds.fd_bits[i];
785 #else
786     for (int32_t i = LWIP_SOCKET_OFFSET / NFDBITS; i <= epollSetPtr->maxfd / NFDBITS; i++) {
787         unsigned long bits = epollSetPtr->exceptfds.fds_bits[i];
788 #endif
789 #else
790     for (int32_t i = LWIP_SOCKET_OFFSET / __NFDBITS; i <= epollSetPtr->maxfd / __NFDBITS; i++) {
791         unsigned long bits = (unsigned long)(__FDS_BITS(&(epollSetPtr->exceptfds))[i]);
792 #endif
793         while (bits != 0) {
794             int32_t fd;
795             int32_t bitIdx = RearZeroBitNum(bits);
796 #ifdef __LITEOS__
797 #ifdef FDSETSAFESET
798             fd = i * BYTE_BITS_NUM + bitIdx + LWIP_SOCKET_OFFSET;
799 #else
800             fd = i * NFDBITS + bitIdx;
801 #endif
802 #else
803             fd = i * __NFDBITS + bitIdx;
804 #endif
805             func(epollSetPtr, param, fd);
806             bits &= (bits - 1);
807         }
808     }
809 }
810 
811 int32_t EpollLoop(EpollDesc epollfd, int32_t timeout)
812 {
813     EpollSet *epollSetPtr = NULL;
814     fd_set readfds, writefds, exceptfds;
815     EpollSetPtr param = {&readfds, &writefds, &exceptfds};
816     int32_t ret;
817     struct timeval tv;
818     struct timeval *tvp = NULL;
819 
820     if (!IsEpollDescValid(epollfd)) {
821         return NSTACKX_EFAILED;
822     }
823 
824     if (timeout != -1) {
825         tv.tv_sec = timeout / NSTACKX_MILLI_TICKS;
826         tv.tv_usec = (timeout % NSTACKX_MILLI_TICKS) * NSTACKX_MICRO_SEC_PER_MILLI_SEC;
827         tvp = &tv;
828     }
829 
830     epollSetPtr = container_of(epollfd, EpollSet, epollfd);
831     if (memcpy_s(&readfds, sizeof(fd_set), &epollSetPtr->readfds, sizeof(fd_set)) != EOK ||
832         memcpy_s(&writefds, sizeof(fd_set), &epollSetPtr->writefds, sizeof(fd_set)) != EOK ||
833         memcpy_s(&exceptfds, sizeof(fd_set), &epollSetPtr->exceptfds, sizeof(fd_set)) != EOK) {
834         return NSTACKX_EFAILED;
835     }
836 
837     ret = select(epollSetPtr->maxfd + 1, &readfds, &writefds, &exceptfds, tvp);
838     if (ret < 0) {
839         if (errno == EINTR) {
840             return NSTACKX_EINTR;
841         }
842         LOGE(TAG, "epoll %d select error", epollfd->recvFd);
843         return NSTACKX_EFAILED;
844     } else if (ret == 0) {
845         return NSTACKX_ETIMEOUT;
846     }
847 
848     EpollSetTraverse(epollSetPtr, EpollSetFdHandle, &param);
849 
850     return ret;
851 }
852 
853 #ifndef LWIP_LITEOS_A_COMPAT
854 static void EpollSetClearHandle(EpollSet *epollSetPtr, void *param, int32_t fd)
855 {
856     EpollSet *setPtr = g_epollEventPtrArray[EVENT_PTR_IDX(fd)].epollSetPtr;
857     (void)param;
858     if ((setPtr != NULL) && (setPtr != epollSetPtr)) {
859         LOGE(TAG, "Clear: fd %d ptr has been used", fd);
860         return;
861     }
862     if (pthread_mutex_lock(&g_epollEventPtrMutex) != 0) {
863         LOGE(TAG, "pthread mutex lock error");
864         return;
865     }
866     g_epollEventPtrArray[EVENT_PTR_IDX(fd)].epollSetPtr = NULL;
867     g_epollEventPtrArray[EVENT_PTR_IDX(fd)].taskPtr = NULL;
868     if (pthread_mutex_unlock(&g_epollEventPtrMutex) != 0) {
869         LOGE(TAG, "pthread mutex unlock error");
870         return;
871     }
872 }
873 
874 static void EpollEventCleanup(const EpollSet *epollSetPtr)
875 {
876     g_epollEventPtrArray[EVENT_PTR_IDX(epollSetPtr->epollfd.recvFd)].epollSetPtr = NULL;
877     g_epollEventPtrArray[EVENT_PTR_IDX(epollSetPtr->epollfd.recvFd)].taskPtr = NULL;
878     g_epollEventPtrArray[EVENT_PTR_IDX(epollSetPtr->epollfd.sendFd)].epollSetPtr = NULL;
879     g_epollEventPtrArray[EVENT_PTR_IDX(epollSetPtr->epollfd.sendFd)].taskPtr = NULL;
880 }
881 #else
882 static void EpollEventCleanup(const EpollSet *epollSetPtr)
883 {
884     List *pos = NULL;
885     List *tmp = NULL;
886     struct EpollTaskList *taskListPtr = NULL;
887     struct EpollEventPtr *ptr = EpollEventListFind(epollSetPtr);
888     if (ptr == NULL) {
889         return;
890     }
891     ListRemoveNode(&(ptr->list));
892     LIST_FOR_EACH_SAFE(pos, tmp, &(ptr->taskList)) {
893         taskListPtr = container_of(pos, struct EpollTaskList, list);
894         ListRemoveNode(&taskListPtr->list);
895         free(taskListPtr);
896     }
897     free(ptr);
898 }
899 #endif /* LWIP_LITEOS_A_COMPAT */
900 
901 void CloseEpollDescInner(EpollDesc epollfd)
902 {
903     EpollSet *epollSetPtr = NULL;
904     if (!(IsEpollDescValid(epollfd))) {
905         return;
906     }
907     epollSetPtr = container_of(epollfd, EpollSet, epollfd);
908 #ifndef LWIP_LITEOS_A_COMPAT
909     EpollSetTraverse(epollSetPtr, EpollSetClearHandle, NULL);
910 #endif /* LWIP_LITEOS_A_COMPAT */
911     if (pthread_mutex_lock(&g_epollEventPtrMutex) != 0) {
912         LOGE(TAG, "pthread mutex lock error");
913         goto FAIL_CLOSE;
914     }
915     EpollEventCleanup(epollSetPtr);
916     if (pthread_mutex_unlock(&g_epollEventPtrMutex) != 0) {
917         LOGE(TAG, "pthread mutex unlock error");
918     }
919 FAIL_CLOSE:
920     close(epollfd->recvFd);
921     close(epollfd->sendFd);
922     if (pthread_mutex_destroy(&(epollSetPtr->mutex)) != 0) {
923         LOGE(TAG, "pthread mutex destroy error: %d", errno);
924     }
925     free(epollSetPtr);
926 
927     return;
928 }
929 
930 #ifdef LWIP_LITEOS_A_COMPAT
931 static EpollSet *CloseDescEpollHandle(int32_t desc)
932 {
933     return EpollSetFindByFd(desc);
934 }
935 #else
936 static EpollSet *CloseDescEpollHandle(int32_t desc)
937 {
938     EpollSet *epollSetPtr = g_epollEventPtrArray[EVENT_PTR_IDX(desc)].epollSetPtr;
939     g_epollEventPtrArray[EVENT_PTR_IDX(desc)].epollSetPtr = NULL;
940     g_epollEventPtrArray[EVENT_PTR_IDX(desc)].taskPtr = NULL;
941     return epollSetPtr;
942 }
943 #endif
944 
945 void CloseDescClearEpollPtr(int32_t desc)
946 {
947     EpollSet *epollSetPtr = NULL;
948     if (IS_INVALID_SOCKET_DESC(desc)) {
949         LOGE(TAG, "invalid socket : %d", desc);
950         return;
951     }
952     if (g_epollInited != NSTACKX_TRUE) {
953         LOGE(TAG, "Epoll Event Ptr Not Init");
954         return;
955     }
956 
957     if (pthread_mutex_lock(&g_epollEventPtrMutex) != 0) {
958         LOGE(TAG, "pthread mutex lock error");
959         return;
960     }
961     epollSetPtr = CloseDescEpollHandle(desc);
962     if (pthread_mutex_unlock(&g_epollEventPtrMutex) != 0) {
963         LOGE(TAG, "pthread mutex unlock error");
964         return;
965     }
966 
967     if (epollSetPtr == NULL) {
968         return;
969     }
970 
971     if (pthread_mutex_lock(&(epollSetPtr->mutex)) != 0) {
972         LOGE(TAG, "pthread mutex lock error");
973         return;
974     }
975     FD_CLR(desc, &epollSetPtr->readfds);
976     FD_CLR(desc, &epollSetPtr->writefds);
977     FD_CLR(desc, &epollSetPtr->exceptfds);
978     if (desc == epollSetPtr->maxfd) {
979         EpollSetMaxFdUpdate(epollSetPtr);
980     }
981     if (pthread_mutex_unlock(&(epollSetPtr->mutex)) != 0) {
982         LOGE(TAG, "pthread mutex unlock error");
983         return;
984     }
985 }
986