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 
16 #include "socket_listener.h"
17 #include <sys/epoll.h>
18 #include <sys/eventfd.h>
19 #include <unistd.h>
20 #include "log.h"
21 
22 namespace OHOS {
23 namespace bluetooth {
GetInstance()24 SocketThread &SocketThread::GetInstance()
25 {
26     static SocketThread instance;
27     return instance;
28 }
29 
Initialize()30 bool SocketThread::Initialize()
31 {
32     LOG_INFO("[SocketListener]: %{public}s", __func__);
33     epollFd_ = epoll_create1(EPOLL_CLOEXEC);
34     stopFd_ = eventfd(0, 0);
35     if (epollFd_ == -1 || stopFd_ == -1) {
36         LOG_ERROR("[SocketListener]: Create epoll failed!!");
37         return false;
38     }
39 
40     int ret;
41     struct epoll_event event = {};
42     event.data.ptr = nullptr;
43     event.events = EPOLLIN;
44 
45     CHECK_EXCEPT_INTR(ret = epoll_ctl(epollFd_, EPOLL_CTL_ADD, stopFd_, &event));
46     if (ret == -1) {
47         LOG_ERROR("[SocketListener]: Epoll add stop-event failed!!");
48         return false;
49     }
50 
51     thread_ = std::make_unique<std::thread>(&SocketThread::OnListenEvents, this);
52     count_ = 0;
53 
54     return true;
55 }
56 
Uninitialize()57 bool SocketThread::Uninitialize()
58 {
59     LOG_INFO("[SocketListener]: %{public}s", __func__);
60     eventfd_write(stopFd_, 1);
61     if (thread_ && thread_->joinable()) {
62         thread_->join();
63         thread_ = nullptr;
64     }
65 
66     std::lock_guard<std::mutex> lock(epollFdMutex_);
67     if (epollFd_ != -1) {
68         close(epollFd_);
69         epollFd_ = -1;
70     }
71     if (stopFd_ != -1) {
72         close(stopFd_);
73         stopFd_ = -1;
74     }
75     return true;
76 }
77 
AddSocket(int fd,int flag,Socket & sock)78 bool SocketThread::AddSocket(int fd, int flag, Socket &sock)
79 {
80     LOG_INFO("[SocketListener]: %{public}s", __func__);
81 
82     if (count_ >= MAX_EPOLL) {
83         LOG_ERROR("[SocketListener]: Too many sockets..");
84         return false;
85     }
86 
87     {
88         std::lock_guard<std::mutex> lock(mutex_);
89         fdMap_[&sock] = fd;
90     }
91 
92     int ret;
93     struct epoll_event event = {};
94     event.data.ptr = &sock;
95     if (flag == 1) {
96         event.events = EPOLLRDHUP | EPOLLERR | EPOLLIN | EPOLLOUT | EPOLLONESHOT;
97         ret = epoll_ctl(epollFd_, EPOLL_CTL_MOD, fd, &event);
98     } else {
99         count_++;
100         event.events = EPOLLRDHUP | EPOLLERR | EPOLLIN;
101         ret = epoll_ctl(epollFd_, EPOLL_CTL_ADD, fd, &event);
102     }
103 
104     LOG_INFO("[SocketListener]: epollFd: %{public}d, fd:%{public}d, errno:%{public}d", epollFd_, fd, errno);
105     if (ret == -1) {
106         LOG_ERROR("[SocketListener]: add Socket-Event failed");
107         return false;
108     }
109 
110     return true;
111 }
112 
OnListenEvents(void)113 void SocketThread::OnListenEvents(void)
114 {
115     struct epoll_event events[MAX_EPOLL];
116 
117     while (true) {
118         int nfds;
119         CHECK_EXCEPT_INTR(nfds = epoll_wait(epollFd_, events, MAX_EPOLL, -1));
120         if (nfds == -1) {
121             return;
122         }
123 
124         for (int i = 0; i < nfds; ++i) {
125             if (events[i].data.ptr == nullptr) {
126                 eventfd_t val;
127                 eventfd_read(this->stopFd_, &val);
128                 return;
129             }
130 
131             Socket &sock = *(Socket *)events[i].data.ptr;
132             if (events[i].events & EPOLLIN) {
133                 readCallback_(sock);
134             }
135             std::lock_guard<std::mutex> lock(epollFdMutex_);
136             int fd = FindFd(sock);
137             if (events[i].events & EPOLLOUT) {
138                 writeCallback_(sock);
139 
140                 struct epoll_event event = {};
141                 event.data.ptr = &sock;
142                 event.events = EPOLLRDHUP | EPOLLERR | EPOLLIN;
143                 epoll_ctl(epollFd_, EPOLL_CTL_MOD, fd, &event);
144                 LOG_DEBUG("[SocketListener]: epollFd: %{public}d, fd:%{public}d, errno:%{public}d",
145                     epollFd_, fd, errno);
146             }
147             if (events[i].events & (EPOLLRDHUP | EPOLLERR)) {
148                 LOG_INFO("[SocketListener]: remove fd:%{public}d", fd);
149                 epoll_ctl(epollFd_, EPOLL_CTL_DEL, fd, nullptr);
150                 DeleteFd(sock);
151                 count_--;
152                 LOG_INFO("[SocketListener]: exceptCallback");
153                 exceptCallback_(sock);
154             }
155         }
156     }
157 }
158 
FindFd(Socket & sock)159 int SocketThread::FindFd(Socket &sock)
160 {
161     std::lock_guard<std::mutex> lock(mutex_);
162     int fd = -1;
163     if (fdMap_.find(&sock) != fdMap_.end()) {
164         fd = fdMap_.at(&sock);
165     } else {
166         LOG_ERROR("[SocketListener]: fd does not exist");
167     }
168     return fd;
169 }
170 
DeleteFd(Socket & sock)171 void SocketThread::DeleteFd(Socket &sock)
172 {
173     std::lock_guard<std::mutex> lock(mutex_);
174     fdMap_.erase(&sock);
175 }
176 
DeleteSocket(Socket & sock)177 bool SocketThread::DeleteSocket(Socket &sock)
178 {
179     int fd = FindFd(sock);
180     LOG_DEBUG("SocketThread: DeleteSocket fd:%{public}d", fd);
181     std::lock_guard<std::mutex> lock(epollFdMutex_);
182     if ((fd == -1) || (epollFd_ == -1)) {
183         return false;
184     }
185     if (epoll_ctl(epollFd_, EPOLL_CTL_DEL, fd, nullptr) != -1) {
186         DeleteFd(sock);
187         count_--;
188         return true;
189     }
190     LOG_DEBUG("SocketThread: DeleteSocket errno:%{public}d", errno);
191     return false;
192 }
193 }  // namespace bluetooth
194 }  // namespace OHOS