1 /*
2  * Copyright (C) 2021-2024 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 "hril_event.h"
17 
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <sys/select.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include "securec.h"
25 
26 #include "telephony_log_wrapper.h"
27 
28 namespace OHOS {
29 namespace Telephony {
GetNowTime(struct timeval & tv)30 void HRilEvent::GetNowTime(struct timeval &tv)
31 {
32     struct timespec ts;
33     clock_gettime(CLOCK_MONOTONIC, &ts);
34     tv.tv_sec = ts.tv_sec;
35     tv.tv_usec = ts.tv_nsec / TIME_UNIT;
36 }
37 
GetNextTimeOut(struct timeval & tv)38 bool HRilEvent::GetNextTimeOut(struct timeval &tv)
39 {
40     std::lock_guard<std::mutex> mutexLock(listLock_);
41     std::list<HRilEventMessage>::iterator eventIt = timerList_.begin();
42     if (eventIt == timerList_.end() || timerList_.empty()) {
43         return false;
44     }
45 
46     struct timeval now;
47     GetNowTime(now);
48     TELEPHONY_LOGD("now = %{public}ds + %{public}dus", (int32_t)now.tv_sec, (int32_t)now.tv_usec);
49     TELEPHONY_LOGD(
50         "next = %{public}ds + %{public}dus", (int32_t)eventIt->timeout.tv_sec, (int32_t)eventIt->timeout.tv_usec);
51     if (timercmp(&eventIt->timeout, &now, >)) {
52         timersub(&eventIt->timeout, &now, &tv);
53     } else {
54         // timer already expired.
55         tv.tv_sec = tv.tv_usec = 0;
56     }
57     return true;
58 }
59 
ProcessTimerList()60 void HRilEvent::ProcessTimerList()
61 {
62     struct timeval now;
63     std::lock_guard<std::mutex> mutexLock(listLock_);
64     std::list<HRilEventMessage>::iterator eventIt = timerList_.begin();
65     GetNowTime(now);
66 
67     TELEPHONY_LOGD("finding for timers <= %{public}ds + %{public}dus", (int32_t)now.tv_sec, (int32_t)now.tv_usec);
68     while ((eventIt != timerList_.end()) && (timercmp(&now, &eventIt->timeout, >))) {
69         HRilEventMessage evMsg = {};
70         evMsg.fd = eventIt->fd;
71         evMsg.func = eventIt->func;
72         evMsg.index = eventIt->index;
73         evMsg.param = eventIt->param;
74         evMsg.timeout = eventIt->timeout;
75         pendingList_.push_back(evMsg);
76         eventIt = timerList_.erase(eventIt);
77     }
78 }
79 
HasEventMessageFromPendingList(HRilEventMessage * eventMsg)80 bool HRilEvent::HasEventMessageFromPendingList(HRilEventMessage *eventMsg)
81 {
82     std::lock_guard<std::mutex> mutexLock(listLock_);
83     std::list<HRilEventMessage>::iterator eventIt = pendingList_.begin();
84     if (eventIt == pendingList_.end()) {
85         return false;
86     }
87     eventMsg->fd = eventIt->fd;
88     eventMsg->func = eventIt->func;
89     eventMsg->index = eventIt->index;
90     eventMsg->param = eventIt->param;
91     eventMsg->timeout = eventIt->timeout;
92     pendingList_.erase(eventIt);
93     return true;
94 }
95 
ProcessPendingList()96 void HRilEvent::ProcessPendingList()
97 {
98     HRilEventMessage evMsg = {};
99     while (HasEventMessageFromPendingList(&evMsg)) {
100         if (evMsg.func != nullptr) {
101             evMsg.func(evMsg.fd, 0, evMsg.param);
102         }
103     }
104 }
105 
EraseListenEvent(HRilEventMessage & eventMsg,int32_t index)106 void HRilEvent::EraseListenEvent(HRilEventMessage &eventMsg, int32_t index)
107 {
108     listenEventTable_[index] = nullptr;
109     eventMsg.index = DEFAULT_INDEX;
110 
111     FD_CLR(eventMsg.fd, &readFds_);
112 
113     if (eventMsg.fd + 1 == nfds_) {
114         int32_t n = 0;
115         for (auto msg : listenEventTable_) {
116             if ((msg != nullptr) && (msg->fd > n)) {
117                 n = msg->fd;
118             }
119         }
120         nfds_ = n + 1;
121         TELEPHONY_LOGD("Updated nfds = %{public}d", nfds_);
122     }
123 }
124 
ProcessEvents(fd_set * rfds,int32_t number)125 void HRilEvent::ProcessEvents(fd_set *rfds, int32_t number)
126 {
127     if (rfds == nullptr) {
128         return;
129     }
130     std::lock_guard<std::mutex> mutexLock(listLock_);
131     auto it = listenEventTable_.begin();
132     for (; (it != listenEventTable_.end()) && (number > 0); ++it) {
133         if (*it != nullptr && FD_ISSET((*it)->fd, rfds)) {
134             pendingList_.push_back(*(*it));
135             if ((*it)->isHolding == false) {
136                 EraseListenEvent(*(*it), (*it)->index);
137             }
138             number--;
139         }
140     }
141 }
142 
TimerEventInit()143 void HRilEvent::TimerEventInit()
144 {
145     std::lock_guard<std::mutex> mutexLock(listLock_);
146     FD_ZERO(&readFds_);
147     timerList_.clear();
148     pendingList_.clear();
149     listenEventTable_.clear();
150     for (int32_t i = 0; i < LISTEN_FD_EVENTS_MAX; i++) {
151         listenEventTable_.push_back(nullptr);
152     }
153 }
154 
AddTimerEvent(HRilEventMessage & eventMsg,const struct timeval & tv)155 void HRilEvent::AddTimerEvent(HRilEventMessage &eventMsg, const struct timeval &tv)
156 {
157     std::lock_guard<std::mutex> mutexLock(listLock_);
158     struct timeval now;
159     eventMsg.fd = IVNALID_FD; // make sure fd is invalid
160 
161     GetNowTime(now);
162     timeradd(&now, &tv, &eventMsg.timeout);
163 
164     std::list<HRilEventMessage>::iterator it = timerList_.begin();
165     for (; it != timerList_.end(); ++it) {
166         if (timercmp(&it->timeout, &eventMsg.timeout, >)) {
167             timerList_.insert(it, eventMsg);
168             return;
169         }
170     }
171     if (it == timerList_.end()) {
172         timerList_.push_back(eventMsg);
173     }
174 }
175 
SetTimerEvent(HRilEventMessage & eventMsg,int32_t fd,bool isHolding,HRilEventCallback func,std::shared_ptr<void> param)176 void HRilEvent::SetTimerEvent(
177     HRilEventMessage &eventMsg, int32_t fd, bool isHolding, HRilEventCallback func, std::shared_ptr<void> param)
178 {
179     (void)memset_s(&eventMsg, sizeof(HRilEventMessage), 0, sizeof(HRilEventMessage));
180     eventMsg.fd = fd;
181     eventMsg.index = DEFAULT_INDEX;
182     eventMsg.func = func;
183     eventMsg.param = param;
184     eventMsg.isHolding = isHolding;
185     fcntl(fd, F_SETFL, O_NONBLOCK);
186 }
187 
AddEventMessage(const HRilEventMessage & eventMsg)188 void HRilEvent::AddEventMessage(const HRilEventMessage &eventMsg)
189 {
190     std::lock_guard<std::mutex> mutexLock(listLock_);
191     for (int32_t i = 0; i < LISTEN_FD_EVENTS_MAX; i++) {
192         if (listenEventTable_[i] == nullptr) {
193             listenEventTable_[i] = const_cast<HRilEventMessage *>(&eventMsg);
194             listenEventTable_[i]->index = i;
195             FD_SET(eventMsg.fd, &readFds_);
196             if (eventMsg.fd >= nfds_) {
197                 nfds_ = eventMsg.fd + 1;
198             }
199             break;
200         }
201     }
202 }
203 
RemoveEventMessage(HRilEventMessage & eventMsg)204 void HRilEvent::RemoveEventMessage(HRilEventMessage &eventMsg)
205 {
206     std::lock_guard<std::mutex> mutexLock(listLock_);
207     if (eventMsg.index < 0 || eventMsg.index >= LISTEN_FD_EVENTS_MAX) {
208         TELEPHONY_LOGE("Invalid event message! index:%{pubulic}d", eventMsg.index);
209         return;
210     }
211     EraseListenEvent(eventMsg, eventMsg.index);
212 }
213 
CopyReadFds(fd_set * rfds)214 void HRilEvent::CopyReadFds(fd_set *rfds)
215 {
216     std::lock_guard<std::mutex> mutexLock(listLock_);
217     (void)memcpy_s(rfds, sizeof(fd_set), &readFds_, sizeof(fd_set));
218 }
219 
EventMessageLoop()220 void HRilEvent::EventMessageLoop()
221 {
222     int32_t ret;
223     fd_set rfds;
224     struct timeval timeout;
225     struct timeval *pTimeOut;
226 
227     TELEPHONY_LOGD("****** EventMessageLoop start ******");
228     while (1) {
229         CopyReadFds(&rfds);
230         if (!GetNextTimeOut(timeout)) {
231             // Enter blocking wait without setting a timer.
232             TELEPHONY_LOGD("Enter blocking wait without setting a timer.");
233             pTimeOut = nullptr;
234         } else {
235             TELEPHONY_LOGD(
236                 "Setting timeout for %{public}ds + %{public}dus", (int32_t)timeout.tv_sec, (int32_t)timeout.tv_usec);
237             pTimeOut = &timeout;
238         }
239         ret = select(nfds_, &rfds, nullptr, nullptr, pTimeOut);
240         TELEPHONY_LOGD("There are %{public}d events fired, isNormalDestory: %{public}d.", ret, isNormalDestory);
241         if (isNormalDestory) {
242             return;
243         }
244         if (ret < 0) {
245             if (errno == EINTR) {
246                 continue;
247             }
248             TELEPHONY_LOGE("select error (%{public}d)", errno);
249             return;
250         }
251         ProcessTimerList();
252         ProcessEvents(&rfds, ret);
253         ProcessPendingList();
254     }
255 }
256 
SetNormalDestory(bool isDestory)257 void HRilEvent::SetNormalDestory(bool isDestory)
258 {
259     isNormalDestory = isDestory;
260 }
IsNormalDestory()261 bool HRilEvent::IsNormalDestory()
262 {
263     return isNormalDestory;
264 }
265 
266 } // namespace Telephony
267 } // namespace OHOS
268