Line data Source code
1 : // Copyright (c) 2020-2024 The Dash Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include <util/edge.h>
6 :
7 : #include <logging.h>
8 : #include <util/sock.h>
9 :
10 : #ifdef USE_EPOLL
11 : #include <sys/epoll.h>
12 : #endif
13 :
14 : #ifdef USE_KQUEUE
15 : #include <sys/event.h>
16 : #endif
17 :
18 5642 : EdgeTriggeredEvents::EdgeTriggeredEvents(SocketEventsMode events_mode)
19 : : m_mode(events_mode)
20 2821 : {
21 : if (m_mode == SocketEventsMode::EPoll) {
22 : #ifdef USE_EPOLL
23 : m_fd = epoll_create1(0);
24 : if (m_fd == -1) {
25 : LogPrintf("Unable to initialize EdgeTriggeredEvents, epoll_create1 returned -1 with error %s\n",
26 : NetworkErrorString(WSAGetLastError()));
27 : return;
28 : }
29 : #else
30 : LogPrintf("Attempting to initialize EdgeTriggeredEvents for epoll without support compiled in!\n");
31 : return;
32 : #endif /* USE_EPOLL */
33 : } else if (m_mode == SocketEventsMode::KQueue) {
34 : #ifdef USE_KQUEUE
35 : m_fd = kqueue();
36 : if (m_fd == -1) {
37 : LogPrintf("Unable to initialize EdgeTriggeredEvents, kqueue returned -1 with error %s\n",
38 : NetworkErrorString(WSAGetLastError()));
39 : return;
40 : }
41 : #else
42 : LogPrintf("Attempting to initialize EdgeTriggeredEvents for kqueue without support compiled in!\n");
43 : return;
44 : #endif /* USE_KQUEUE */
45 : } else {
46 : assert(false);
47 : }
48 : m_valid = true;
49 2821 : }
50 :
51 5642 : EdgeTriggeredEvents::~EdgeTriggeredEvents()
52 2821 : {
53 2821 : if (m_valid) {
54 : #if defined(USE_KQUEUE) || defined(USE_EPOLL)
55 2821 : if (close(m_fd) != 0) {
56 0 : LogPrintf("Destroying EdgeTriggeredEvents instance, close() failed for m_fd = %d with error %s\n", m_fd,
57 : NetworkErrorString(WSAGetLastError()));
58 0 : }
59 : #else
60 : assert(false);
61 : #endif /* defined(USE_KQUEUE) || defined(USE_EPOLL) */
62 2821 : }
63 5642 : }
64 :
65 5857 : bool EdgeTriggeredEvents::RegisterEntity(int entity, const std::string& entity_name) const
66 : {
67 5857 : assert(m_valid);
68 :
69 5857 : if (m_mode == SocketEventsMode::EPoll) {
70 : #ifdef USE_EPOLL
71 : epoll_event event;
72 : event.data.fd = entity;
73 : event.events = EPOLLIN;
74 : if (epoll_ctl(m_fd, EPOLL_CTL_ADD, entity, &event) != 0) {
75 : LogPrintf("Failed to add %s to epoll fd (epoll_ctl returned error %s)\n", entity_name,
76 : NetworkErrorString(WSAGetLastError()));
77 : return false;
78 : }
79 : #else
80 0 : assert(false);
81 : #endif /* USE_EPOLL */
82 5857 : } else if (m_mode == SocketEventsMode::KQueue) {
83 : #ifdef USE_KQUEUE
84 : struct kevent event;
85 5857 : EV_SET(&event, entity, EVFILT_READ, EV_ADD, 0, 0, nullptr);
86 5857 : if (kevent(m_fd, &event, 1, nullptr, 0, nullptr) != 0) {
87 0 : LogPrintf("Failed to add %s to kqueue fd (kevent returned error %s)\n", entity_name,
88 : NetworkErrorString(WSAGetLastError()));
89 0 : return false;
90 : }
91 : #else
92 : assert(false);
93 : #endif /* USE_KQUEUE */
94 5857 : } else {
95 0 : assert(false);
96 : }
97 5857 : return true;
98 5857 : }
99 :
100 5857 : bool EdgeTriggeredEvents::UnregisterEntity(int entity, const std::string& entity_name) const
101 : {
102 5857 : assert(m_valid);
103 :
104 5857 : if (m_mode == SocketEventsMode::EPoll) {
105 : #ifdef USE_EPOLL
106 : if (epoll_ctl(m_fd, EPOLL_CTL_DEL, entity, nullptr) != 0) {
107 : LogPrintf("Failed to remove %s from epoll fd (epoll_ctl returned error %s)\n", entity_name,
108 : NetworkErrorString(WSAGetLastError()));
109 : return false;
110 : }
111 : #else
112 0 : assert(false);
113 : #endif /* USE_EPOLL */
114 5857 : } else if (m_mode == SocketEventsMode::KQueue) {
115 : #ifdef USE_KQUEUE
116 : struct kevent event;
117 5857 : EV_SET(&event, entity, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
118 5857 : if (kevent(m_fd, &event, 1, nullptr, 0, nullptr) != 0) {
119 0 : LogPrintf("Failed to remove %s from kqueue fd (kevent returned error %s)\n", entity_name,
120 : NetworkErrorString(WSAGetLastError()));
121 0 : return false;
122 : }
123 : #else
124 : assert(false);
125 : #endif /* USE_KQUEUE */
126 5857 : } else {
127 0 : assert(false);
128 : }
129 5857 : return true;
130 5857 : }
131 :
132 3036 : bool EdgeTriggeredEvents::AddSocket(SOCKET socket) const
133 : {
134 3036 : return RegisterEntity(socket, "socket");
135 0 : }
136 :
137 3036 : bool EdgeTriggeredEvents::RemoveSocket(SOCKET socket) const
138 : {
139 3036 : return UnregisterEntity(socket, "socket");
140 0 : }
141 :
142 2821 : bool EdgeTriggeredEvents::RegisterPipe(int wakeup_pipe)
143 : {
144 2821 : if (m_pipe_registered) {
145 0 : LogPrintf("Pipe already registered, ignoring new registration request\n");
146 0 : return false;
147 : }
148 2821 : bool ret = RegisterEntity(wakeup_pipe, "wakeup pipe");
149 2821 : if (ret) m_pipe_registered = true;
150 2821 : return ret;
151 2821 : }
152 :
153 2821 : bool EdgeTriggeredEvents::UnregisterPipe(int wakeup_pipe)
154 : {
155 2821 : if (!m_pipe_registered) {
156 0 : LogPrintf("No pipe currently registered to unregister, ignoring request\n");
157 0 : return false;
158 : }
159 2821 : bool ret = UnregisterEntity(wakeup_pipe, "wakeup pipe");
160 2821 : if (ret) m_pipe_registered = false;
161 2821 : return ret;
162 2821 : }
163 :
164 9947 : bool EdgeTriggeredEvents::RegisterEvents(SOCKET socket) const
165 : {
166 9947 : assert(m_valid && socket != INVALID_SOCKET);
167 :
168 9947 : if (m_mode == SocketEventsMode::EPoll) {
169 : #ifdef USE_EPOLL
170 : epoll_event e;
171 : // We're using edge-triggered mode, so it's important that we drain sockets even if no signals come in
172 : e.events = EPOLLIN | EPOLLOUT | EPOLLET | EPOLLERR | EPOLLHUP;
173 : e.data.fd = socket;
174 :
175 : if (epoll_ctl(m_fd, EPOLL_CTL_ADD, socket, &e) != 0) {
176 : LogPrintf("Failed to register events for socket -- epoll_ctl(%d, %d, %d, ...) returned error: %s\n",
177 : m_fd, EPOLL_CTL_ADD, socket, NetworkErrorString(WSAGetLastError()));
178 : return false;
179 : }
180 : #else
181 0 : assert(false);
182 : #endif /* USE_EPOLL */
183 9947 : } else if (m_mode == SocketEventsMode::KQueue) {
184 : #ifdef USE_KQUEUE
185 : struct kevent events[2];
186 9947 : EV_SET(&events[0], socket, EVFILT_READ, EV_ADD, 0, 0, nullptr);
187 9947 : EV_SET(&events[1], socket, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, nullptr);
188 :
189 9947 : if (kevent(m_fd, events, 2, nullptr, 0, nullptr) != 0) {
190 0 : LogPrintf("Failed to register events for socket -- kevent(%d, %d, %d, ...) returned error: %s\n",
191 : m_fd, EV_ADD, socket, NetworkErrorString(WSAGetLastError()));
192 0 : return false;
193 : }
194 : #else
195 : assert(false);
196 : #endif /* USE_KQUEUE */
197 9947 : } else {
198 0 : assert(false);
199 : }
200 9947 : return true;
201 9947 : }
202 :
203 9947 : bool EdgeTriggeredEvents::UnregisterEvents(SOCKET socket) const
204 : {
205 9947 : assert(m_valid);
206 :
207 9947 : if (socket == INVALID_SOCKET) {
208 0 : LogPrintf("Cannot unregister events for invalid socket\n");
209 0 : return false;
210 : }
211 :
212 9947 : if (m_mode == SocketEventsMode::EPoll) {
213 : #ifdef USE_EPOLL
214 : if (epoll_ctl(m_fd, EPOLL_CTL_DEL, socket, nullptr) != 0) {
215 : LogPrintf("Failed to unregister events for socket -- epoll_ctl(%d, %d, %d, ...) returned error: %s\n",
216 : m_fd, EPOLL_CTL_DEL, socket, NetworkErrorString(WSAGetLastError()));
217 : return false;
218 : }
219 : #else
220 0 : assert(false);
221 : #endif /* USE_EPOLL */
222 9947 : } else if (m_mode == SocketEventsMode::KQueue) {
223 : #ifdef USE_KQUEUE
224 : struct kevent events[2];
225 9947 : EV_SET(&events[0], socket, EVFILT_READ, EV_DELETE, 0, 0, nullptr);
226 9947 : EV_SET(&events[1], socket, EVFILT_WRITE, EV_DELETE, 0, 0, nullptr);
227 9947 : if (kevent(m_fd, events, 2, nullptr, 0, nullptr) != 0) {
228 0 : LogPrintf("Failed to unregister events for socket -- kevent(%d, %d, %d, ...) returned error: %s\n",
229 : m_fd, EV_DELETE, socket, NetworkErrorString(WSAGetLastError()));
230 0 : return false;
231 : }
232 : #else
233 : assert(false);
234 : #endif /* USE_KQUEUE */
235 9947 : } else {
236 0 : assert(false);
237 : }
238 9947 : return true;
239 9947 : }
|