@@ -86,6 +86,7 @@ pub struct UdpServer {
86
86
keepalive_rx : mpsc:: Receiver < NatKey > ,
87
87
time_to_live : Duration ,
88
88
accept_opts : AcceptOpts ,
89
+ worker_count : usize ,
89
90
}
90
91
91
92
impl UdpServer {
@@ -127,9 +128,15 @@ impl UdpServer {
127
128
keepalive_rx,
128
129
time_to_live,
129
130
accept_opts,
131
+ worker_count : 1 ,
130
132
}
131
133
}
132
134
135
+ #[ inline]
136
+ pub fn set_worker_count ( & mut self , worker_count : usize ) {
137
+ self . worker_count = worker_count;
138
+ }
139
+
133
140
pub async fn run ( mut self , svr_cfg : & ServerConfig ) -> io:: Result < ( ) > {
134
141
let socket = ProxySocket :: bind_with_opts ( self . context . context ( ) , svr_cfg, self . accept_opts . clone ( ) ) . await ?;
135
142
@@ -145,63 +152,35 @@ impl UdpServer {
145
152
146
153
let mut orx_opt = None ;
147
154
148
- let cpus = num_cpus :: get ( ) ;
149
- let mut other_cores = Vec :: new ( ) ;
155
+ let cpus = self . worker_count ;
156
+ let mut other_receivers = Vec :: new ( ) ;
150
157
if cpus > 1 {
151
- let ( otx, orx) = mpsc:: channel ( 64 ) ;
158
+ let ( otx, orx) = mpsc:: channel ( ( cpus - 1 ) * 16 ) ;
152
159
orx_opt = Some ( orx) ;
153
160
154
- other_cores . reserve ( cpus - 1 ) ;
161
+ other_receivers . reserve ( cpus - 1 ) ;
155
162
trace ! ( "udp server starting extra {} recv workers" , cpus - 1 ) ;
156
163
157
164
for _ in 1 ..cpus {
158
165
let otx = otx. clone ( ) ;
159
166
let listener = listener. clone ( ) ;
160
167
let context = self . context . clone ( ) ;
161
168
162
- other_cores . push ( tokio:: spawn ( async move {
169
+ other_receivers . push ( tokio:: spawn ( async move {
163
170
let mut buffer = [ 0u8 ; MAXIMUM_UDP_PAYLOAD_SIZE ] ;
164
171
165
172
loop {
166
- let ( n, peer_addr, target_addr, control) = match listener. recv_from_with_ctrl ( & mut buffer) . await
167
- {
168
- Ok ( s) => s,
169
- Err ( err) => {
170
- error ! ( "udp server recv_from failed with error: {}" , err) ;
171
- continue ;
172
- }
173
- } ;
174
-
175
- if n == 0 {
176
- // For windows, it will generate a ICMP Port Unreachable Message
177
- // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom
178
- // Which will result in recv_from return 0.
179
- //
180
- // It cannot be solved here, because `WSAGetLastError` is already set.
181
- //
182
- // See `relay::udprelay::utils::create_socket` for more detail.
183
- continue ;
184
- }
185
-
186
- if context. check_client_blocked ( & peer_addr) {
187
- warn ! (
188
- "udp client {} outbound {} access denied by ACL rules" ,
189
- peer_addr, target_addr
190
- ) ;
191
- continue ;
192
- }
173
+ let ( n, peer_addr, target_addr, control) =
174
+ match UdpServer :: recv_one_packet ( & context, & listener, & mut buffer) . await {
175
+ Some ( s) => s,
176
+ None => continue ,
177
+ } ;
193
178
194
- if context. check_outbound_blocked ( & target_addr) . await {
195
- warn ! ( "udp client {} outbound {} blocked by ACL rules" , peer_addr, target_addr) ;
196
- continue ;
197
- }
198
-
199
- let r = otx
179
+ if let Err ( ..) = otx
200
180
. send ( ( peer_addr, target_addr, control, Bytes :: copy_from_slice ( & buffer[ ..n] ) ) )
201
- . await ;
202
-
203
- // If Result is error, the channel receiver is closed. We should exit the task.
204
- if r. is_err ( ) {
181
+ . await
182
+ {
183
+ // If Result is error, the channel receiver is closed. We should exit the task.
205
184
break ;
206
185
}
207
186
}
@@ -222,7 +201,7 @@ impl UdpServer {
222
201
}
223
202
224
203
let _guard = MulticoreTaskGuard {
225
- tasks : & mut other_cores ,
204
+ tasks : & mut other_receivers ,
226
205
} ;
227
206
228
207
#[ inline]
@@ -251,39 +230,12 @@ impl UdpServer {
251
230
self . assoc_map. keep_alive( & peer_addr) ;
252
231
}
253
232
254
- recv_result = listener . recv_from_with_ctrl ( & mut buffer) => {
233
+ recv_result = UdpServer :: recv_one_packet ( & self . context , & listener , & mut buffer) => {
255
234
let ( n, peer_addr, target_addr, control) = match recv_result {
256
- Ok ( s) => s,
257
- Err ( err) => {
258
- error!( "udp server recv_from failed with error: {}" , err) ;
259
- continue ;
260
- }
235
+ Some ( s) => s,
236
+ None => continue ,
261
237
} ;
262
238
263
- if n == 0 {
264
- // For windows, it will generate a ICMP Port Unreachable Message
265
- // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom
266
- // Which will result in recv_from return 0.
267
- //
268
- // It cannot be solved here, because `WSAGetLastError` is already set.
269
- //
270
- // See `relay::udprelay::utils::create_socket` for more detail.
271
- continue ;
272
- }
273
-
274
- if self . context. check_client_blocked( & peer_addr) {
275
- warn!(
276
- "udp client {} outbound {} access denied by ACL rules" ,
277
- peer_addr, target_addr
278
- ) ;
279
- continue ;
280
- }
281
-
282
- if self . context. check_outbound_blocked( & target_addr) . await {
283
- warn!( "udp client {} outbound {} blocked by ACL rules" , peer_addr, target_addr) ;
284
- continue ;
285
- }
286
-
287
239
let data = & buffer[ ..n] ;
288
240
if let Err ( err) = self . send_packet( & listener, peer_addr, target_addr, control, Bytes :: copy_from_slice( data) ) . await {
289
241
debug!(
@@ -295,7 +247,7 @@ impl UdpServer {
295
247
}
296
248
}
297
249
298
- recv_result = multicore_recv( & mut orx_opt) => {
250
+ recv_result = multicore_recv( & mut orx_opt) , if orx_opt . is_some ( ) => {
299
251
let ( peer_addr, target_addr, control, data) = recv_result;
300
252
let data_len = data. len( ) ;
301
253
if let Err ( err) = self . send_packet( & listener, peer_addr, target_addr, control, data) . await {
@@ -311,6 +263,46 @@ impl UdpServer {
311
263
}
312
264
}
313
265
266
+ async fn recv_one_packet (
267
+ context : & ServiceContext ,
268
+ l : & MonProxySocket ,
269
+ buffer : & mut [ u8 ] ,
270
+ ) -> Option < ( usize , SocketAddr , Address , Option < UdpSocketControlData > ) > {
271
+ let ( n, peer_addr, target_addr, control) = match l. recv_from_with_ctrl ( buffer) . await {
272
+ Ok ( s) => s,
273
+ Err ( err) => {
274
+ error ! ( "udp server recv_from failed with error: {}" , err) ;
275
+ return None ;
276
+ }
277
+ } ;
278
+
279
+ if n == 0 {
280
+ // For windows, it will generate a ICMP Port Unreachable Message
281
+ // https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recvfrom
282
+ // Which will result in recv_from return 0.
283
+ //
284
+ // It cannot be solved here, because `WSAGetLastError` is already set.
285
+ //
286
+ // See `relay::udprelay::utils::create_socket` for more detail.
287
+ return None ;
288
+ }
289
+
290
+ if context. check_client_blocked ( & peer_addr) {
291
+ warn ! (
292
+ "udp client {} outbound {} access denied by ACL rules" ,
293
+ peer_addr, target_addr
294
+ ) ;
295
+ return None ;
296
+ }
297
+
298
+ if context. check_outbound_blocked ( & target_addr) . await {
299
+ warn ! ( "udp client {} outbound {} blocked by ACL rules" , peer_addr, target_addr) ;
300
+ return None ;
301
+ }
302
+
303
+ Some ( ( n, peer_addr, target_addr, control) )
304
+ }
305
+
314
306
async fn send_packet (
315
307
& mut self ,
316
308
listener : & Arc < MonProxySocket > ,
0 commit comments