rustdesk лет назад: 3
Родитель
Сommit
03ca2a9517

+ 1 - 0
.env

@@ -0,0 +1 @@
1
+DATABASE_URL=sqlite://./db_v2.sqlite3

+ 1 - 0
.gitignore

@@ -1,2 +1,3 @@
1
 target
1
 target
2
 id*
2
 id*
3
+db*

+ 6 - 0
Cargo.toml

@@ -43,3 +43,9 @@ regex = "1.4"
43
 tower-http = { version = "0.2", features = ["fs", "trace", "cors"] }
43
 tower-http = { version = "0.2", features = ["fs", "trace", "cors"] }
44
 http = "0.2"
44
 http = "0.2"
45
 flexi_logger = { version = "0.22", features = ["async", "use_chrono_for_offset"] }
45
 flexi_logger = { version = "0.22", features = ["async", "use_chrono_for_offset"] }
46
+
47
+[build-dependencies]
48
+hbb_common = { path = "libs/hbb_common" }
49
+
50
+[workspace]
51
+members = ["libs/hbb_common"]

+ 4 - 0
libs/hbb_common/.gitignore

@@ -0,0 +1,4 @@
1
+/target
2
+**/*.rs.bk
3
+Cargo.lock
4
+src/protos/

+ 48 - 0
libs/hbb_common/Cargo.toml

@@ -0,0 +1,48 @@
1
+[package]
2
+name = "hbb_common"
3
+version = "0.1.0"
4
+authors = ["open-trade <info@opentradesolutions.com>"]
5
+edition = "2018"
6
+
7
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8
+
9
+[dependencies]
10
+protobuf = "3.0.0-alpha.2"
11
+tokio = { version = "1.15", features = ["full"] }
12
+tokio-util = { version = "0.6", features = ["full"] }
13
+futures = "0.3"
14
+bytes = "1.1"
15
+log = "0.4"
16
+env_logger = "0.9"
17
+socket2 = { version = "0.3", features = ["reuseport"] }
18
+zstd = "0.9"
19
+quinn = {version = "0.8", optional = true }
20
+anyhow = "1.0"
21
+futures-util = "0.3"
22
+directories-next = "2.0"
23
+rand = "0.8"
24
+serde_derive = "1.0"
25
+serde = "1.0"
26
+lazy_static = "1.4"
27
+confy = { git = "https://github.com/open-trade/confy" }
28
+dirs-next = "2.0"
29
+filetime = "0.2"
30
+sodiumoxide = "0.2"
31
+regex = "1.4"
32
+tokio-socks = { git = "https://github.com/open-trade/tokio-socks" }
33
+
34
+[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
35
+mac_address = "1.1"
36
+
37
+[features]
38
+quic = []
39
+
40
+[build-dependencies]
41
+protobuf-codegen-pure = "3.0.0-alpha.2"
42
+
43
+[target.'cfg(target_os = "windows")'.dependencies]
44
+winapi = { version = "0.3", features = ["winuser"] }
45
+
46
+[dev-dependencies]
47
+toml = "0.5"
48
+serde_json = "1.0"

+ 9 - 0
libs/hbb_common/build.rs

@@ -0,0 +1,9 @@
1
+fn main() {
2
+    std::fs::create_dir_all("src/protos").unwrap();
3
+    protobuf_codegen_pure::Codegen::new()
4
+        .out_dir("src/protos")
5
+        .inputs(&["protos/rendezvous.proto", "protos/message.proto"])
6
+        .include("protos")
7
+        .run()
8
+        .expect("Codegen failed.");
9
+}

+ 481 - 0
libs/hbb_common/protos/message.proto

@@ -0,0 +1,481 @@
1
+syntax = "proto3";
2
+package hbb;
3
+
4
+message VP9 {
5
+  bytes data = 1;
6
+  bool key = 2;
7
+  int64 pts = 3;
8
+}
9
+
10
+message VP9s { repeated VP9 frames = 1; }
11
+
12
+message RGB { bool compress = 1; }
13
+
14
+// planes data send directly in binary for better use arraybuffer on web
15
+message YUV {
16
+  bool compress = 1;
17
+  int32 stride = 2;
18
+}
19
+
20
+message VideoFrame {
21
+  oneof union {
22
+    VP9s vp9s = 6;
23
+    RGB rgb = 7;
24
+    YUV yuv = 8;
25
+  }
26
+}
27
+
28
+message IdPk {
29
+  string id = 1;
30
+  bytes pk = 2;
31
+}
32
+
33
+message DisplayInfo {
34
+  sint32 x = 1;
35
+  sint32 y = 2;
36
+  int32 width = 3;
37
+  int32 height = 4;
38
+  string name = 5;
39
+  bool online = 6;
40
+}
41
+
42
+message PortForward {
43
+  string host = 1;
44
+  int32 port = 2;
45
+}
46
+
47
+message FileTransfer {
48
+  string dir = 1;
49
+  bool show_hidden = 2;
50
+}
51
+
52
+message LoginRequest {
53
+  string username = 1;
54
+  bytes password = 2;
55
+  string my_id = 4;
56
+  string my_name = 5;
57
+  OptionMessage option = 6;
58
+  oneof union {
59
+    FileTransfer file_transfer = 7;
60
+    PortForward port_forward = 8;
61
+  }
62
+  bool video_ack_required = 9;
63
+}
64
+
65
+message ChatMessage { string text = 1; }
66
+
67
+message PeerInfo {
68
+  string username = 1;
69
+  string hostname = 2;
70
+  string platform = 3;
71
+  repeated DisplayInfo displays = 4;
72
+  int32 current_display = 5;
73
+  bool sas_enabled = 6;
74
+  string version = 7;
75
+  int32 conn_id = 8;
76
+}
77
+
78
+message LoginResponse {
79
+  oneof union {
80
+    string error = 1;
81
+    PeerInfo peer_info = 2;
82
+  }
83
+}
84
+
85
+message MouseEvent {
86
+  int32 mask = 1;
87
+  sint32 x = 2;
88
+  sint32 y = 3;
89
+  repeated ControlKey modifiers = 4;
90
+}
91
+
92
+enum ControlKey {
93
+  Unknown = 0;
94
+  Alt = 1;
95
+  Backspace = 2;
96
+  CapsLock = 3;
97
+  Control = 4;
98
+  Delete = 5;
99
+  DownArrow = 6;
100
+  End = 7;
101
+  Escape = 8;
102
+  F1 = 9;
103
+  F10 = 10;
104
+  F11 = 11;
105
+  F12 = 12;
106
+  F2 = 13;
107
+  F3 = 14;
108
+  F4 = 15;
109
+  F5 = 16;
110
+  F6 = 17;
111
+  F7 = 18;
112
+  F8 = 19;
113
+  F9 = 20;
114
+  Home = 21;
115
+  LeftArrow = 22;
116
+  /// meta key (also known as "windows"; "super"; and "command")
117
+  Meta = 23;
118
+  /// option key on macOS (alt key on Linux and Windows)
119
+  Option = 24; // deprecated, use Alt instead
120
+  PageDown = 25;
121
+  PageUp = 26;
122
+  Return = 27;
123
+  RightArrow = 28;
124
+  Shift = 29;
125
+  Space = 30;
126
+  Tab = 31;
127
+  UpArrow = 32;
128
+  Numpad0 = 33;
129
+  Numpad1 = 34;
130
+  Numpad2 = 35;
131
+  Numpad3 = 36;
132
+  Numpad4 = 37;
133
+  Numpad5 = 38;
134
+  Numpad6 = 39;
135
+  Numpad7 = 40;
136
+  Numpad8 = 41;
137
+  Numpad9 = 42;
138
+  Cancel = 43;
139
+  Clear = 44;
140
+  Menu = 45; // deprecated, use Alt instead
141
+  Pause = 46;
142
+  Kana = 47;
143
+  Hangul = 48;
144
+  Junja = 49;
145
+  Final = 50;
146
+  Hanja = 51;
147
+  Kanji = 52;
148
+  Convert = 53;
149
+  Select = 54;
150
+  Print = 55;
151
+  Execute = 56;
152
+  Snapshot = 57;
153
+  Insert = 58;
154
+  Help = 59;
155
+  Sleep = 60;
156
+  Separator = 61;
157
+  Scroll = 62;
158
+  NumLock = 63;
159
+  RWin = 64;
160
+  Apps = 65;
161
+  Multiply = 66;
162
+  Add = 67;
163
+  Subtract = 68;
164
+  Decimal = 69;
165
+  Divide = 70;
166
+  Equals = 71;
167
+  NumpadEnter = 72;
168
+  RShift = 73;
169
+  RControl = 74;
170
+  RAlt = 75;
171
+  CtrlAltDel = 100;
172
+  LockScreen = 101;
173
+}
174
+
175
+message KeyEvent {
176
+  bool down = 1;
177
+  bool press = 2;
178
+  oneof union {
179
+    ControlKey control_key = 3;
180
+    uint32 chr = 4;
181
+    uint32 unicode = 5;
182
+    string seq = 6;
183
+  }
184
+  repeated ControlKey modifiers = 8;
185
+}
186
+
187
+message CursorData {
188
+  uint64 id = 1;
189
+  sint32 hotx = 2;
190
+  sint32 hoty = 3;
191
+  int32 width = 4;
192
+  int32 height = 5;
193
+  bytes colors = 6;
194
+}
195
+
196
+message CursorPosition {
197
+  sint32 x = 1;
198
+  sint32 y = 2;
199
+}
200
+
201
+message Hash {
202
+  string salt = 1;
203
+  string challenge = 2;
204
+}
205
+
206
+message Clipboard {
207
+  bool compress = 1;
208
+  bytes content = 2;
209
+}
210
+
211
+enum FileType {
212
+  Dir = 0;
213
+  DirLink = 2;
214
+  DirDrive = 3;
215
+  File = 4;
216
+  FileLink = 5;
217
+}
218
+
219
+message FileEntry {
220
+  FileType entry_type = 1;
221
+  string name = 2;
222
+  bool is_hidden = 3;
223
+  uint64 size = 4;
224
+  uint64 modified_time = 5;
225
+}
226
+
227
+message FileDirectory {
228
+  int32 id = 1;
229
+  string path = 2;
230
+  repeated FileEntry entries = 3;
231
+}
232
+
233
+message ReadDir {
234
+  string path = 1;
235
+  bool include_hidden = 2;
236
+}
237
+
238
+message ReadAllFiles {
239
+  int32 id = 1;
240
+  string path = 2;
241
+  bool include_hidden = 3;
242
+}
243
+
244
+message FileAction {
245
+  oneof union {
246
+    ReadDir read_dir = 1;
247
+    FileTransferSendRequest send = 2;
248
+    FileTransferReceiveRequest receive = 3;
249
+    FileDirCreate create = 4;
250
+    FileRemoveDir remove_dir = 5;
251
+    FileRemoveFile remove_file = 6;
252
+    ReadAllFiles all_files = 7;
253
+    FileTransferCancel cancel = 8;
254
+  }
255
+}
256
+
257
+message FileTransferCancel { int32 id = 1; }
258
+
259
+message FileResponse {
260
+  oneof union {
261
+    FileDirectory dir = 1;
262
+    FileTransferBlock block = 2;
263
+    FileTransferError error = 3;
264
+    FileTransferDone done = 4;
265
+  }
266
+}
267
+
268
+message FileTransferBlock {
269
+  int32 id = 1;
270
+  sint32 file_num = 2;
271
+  bytes data = 3;
272
+  bool compressed = 4;
273
+}
274
+
275
+message FileTransferError {
276
+  int32 id = 1;
277
+  string error = 2;
278
+  sint32 file_num = 3;
279
+}
280
+
281
+message FileTransferSendRequest {
282
+  int32 id = 1;
283
+  string path = 2;
284
+  bool include_hidden = 3;
285
+}
286
+
287
+message FileTransferDone {
288
+  int32 id = 1;
289
+  sint32 file_num = 2;
290
+}
291
+
292
+message FileTransferReceiveRequest {
293
+  int32 id = 1;
294
+  string path = 2; // path written to
295
+  repeated FileEntry files = 3;
296
+}
297
+
298
+message FileRemoveDir {
299
+  int32 id = 1;
300
+  string path = 2;
301
+  bool recursive = 3;
302
+}
303
+
304
+message FileRemoveFile {
305
+  int32 id = 1;
306
+  string path = 2;
307
+  sint32 file_num = 3;
308
+}
309
+
310
+message FileDirCreate {
311
+  int32 id = 1;
312
+  string path = 2;
313
+}
314
+
315
+// main logic from freeRDP
316
+message CliprdrMonitorReady {
317
+  int32 conn_id = 1;
318
+}
319
+
320
+message CliprdrFormat {
321
+  int32 conn_id = 1;
322
+  int32 id = 2;
323
+  string format = 3;
324
+}
325
+
326
+message CliprdrServerFormatList {
327
+  int32 conn_id = 1;
328
+  repeated CliprdrFormat formats = 2;
329
+}
330
+
331
+message CliprdrServerFormatListResponse {
332
+  int32 conn_id = 1;
333
+  int32 msg_flags = 2;
334
+}
335
+
336
+message CliprdrServerFormatDataRequest {
337
+  int32 conn_id = 1;
338
+  int32 requested_format_id = 2;
339
+}
340
+
341
+message CliprdrServerFormatDataResponse {
342
+  int32 conn_id = 1;
343
+  int32 msg_flags = 2;
344
+  bytes format_data = 3;
345
+}
346
+
347
+message CliprdrFileContentsRequest {
348
+  int32 conn_id = 1;
349
+  int32 stream_id = 2;
350
+  int32 list_index = 3;
351
+  int32 dw_flags = 4;
352
+  int32 n_position_low = 5;
353
+  int32 n_position_high = 6;
354
+  int32 cb_requested = 7;
355
+  bool have_clip_data_id = 8;
356
+  int32 clip_data_id = 9;
357
+}
358
+
359
+message CliprdrFileContentsResponse {
360
+  int32 conn_id = 1;
361
+  int32 msg_flags = 3;
362
+  int32 stream_id = 4;
363
+  bytes requested_data = 5;
364
+}
365
+
366
+message Cliprdr {
367
+  oneof union {
368
+    CliprdrMonitorReady ready = 1;
369
+    CliprdrServerFormatList format_list = 2;
370
+    CliprdrServerFormatListResponse format_list_response = 3;
371
+    CliprdrServerFormatDataRequest format_data_request = 4;
372
+    CliprdrServerFormatDataResponse format_data_response = 5;
373
+    CliprdrFileContentsRequest file_contents_request = 6;
374
+    CliprdrFileContentsResponse file_contents_response = 7;
375
+  }
376
+}
377
+
378
+message SwitchDisplay {
379
+  int32 display = 1;
380
+  sint32 x = 2;
381
+  sint32 y = 3;
382
+  int32 width = 4;
383
+  int32 height = 5;
384
+}
385
+
386
+message PermissionInfo {
387
+  enum Permission {
388
+    Keyboard = 0;
389
+    Clipboard = 2;
390
+    Audio = 3;
391
+    File = 4;
392
+  }
393
+
394
+  Permission permission = 1;
395
+  bool enabled = 2;
396
+}
397
+
398
+enum ImageQuality {
399
+  NotSet = 0;
400
+  Low = 2;
401
+  Balanced = 3;
402
+  Best = 4;
403
+}
404
+
405
+message OptionMessage {
406
+  enum BoolOption {
407
+    NotSet = 0;
408
+    No = 1;
409
+    Yes = 2;
410
+  }
411
+  ImageQuality image_quality = 1;
412
+  BoolOption lock_after_session_end = 2;
413
+  BoolOption show_remote_cursor = 3;
414
+  BoolOption privacy_mode = 4;
415
+  BoolOption block_input = 5;
416
+  int32 custom_image_quality = 6;
417
+  BoolOption disable_audio = 7;
418
+  BoolOption disable_clipboard = 8;
419
+  BoolOption enable_file_transfer = 9;
420
+}
421
+
422
+message OptionResponse {
423
+  OptionMessage opt = 1;
424
+  string error = 2;
425
+}
426
+
427
+message TestDelay {
428
+  int64 time = 1;
429
+  bool from_client = 2;
430
+}
431
+
432
+message PublicKey {
433
+  bytes asymmetric_value = 1;
434
+  bytes symmetric_value = 2;
435
+}
436
+
437
+message SignedId { bytes id = 1; }
438
+
439
+message AudioFormat {
440
+  uint32 sample_rate = 1;
441
+  uint32 channels = 2;
442
+}
443
+
444
+message AudioFrame { bytes data = 1; }
445
+
446
+message Misc {
447
+  oneof union {
448
+    ChatMessage chat_message = 4;
449
+    SwitchDisplay switch_display = 5;
450
+    PermissionInfo permission_info = 6;
451
+    OptionMessage option = 7;
452
+    AudioFormat audio_format = 8;
453
+    string close_reason = 9;
454
+    bool refresh_video = 10;
455
+    OptionResponse option_response = 11;
456
+    bool video_received = 12;
457
+  }
458
+}
459
+
460
+message Message {
461
+  oneof union {
462
+    SignedId signed_id = 3;
463
+    PublicKey public_key = 4;
464
+    TestDelay test_delay = 5;
465
+    VideoFrame video_frame = 6;
466
+    LoginRequest login_request = 7;
467
+    LoginResponse login_response = 8;
468
+    Hash hash = 9;
469
+    MouseEvent mouse_event = 10;
470
+    AudioFrame audio_frame = 11;
471
+    CursorData cursor_data = 12;
472
+    CursorPosition cursor_position = 13;
473
+    uint64 cursor_id = 14;
474
+    KeyEvent key_event = 15;
475
+    Clipboard clipboard = 16;
476
+    FileAction file_action = 17;
477
+    FileResponse file_response = 18;
478
+    Misc misc = 19;
479
+    Cliprdr cliprdr = 20;
480
+  }
481
+}

+ 171 - 0
libs/hbb_common/protos/rendezvous.proto

@@ -0,0 +1,171 @@
1
+syntax = "proto3";
2
+package hbb;
3
+
4
+message RegisterPeer {
5
+  string id = 1;
6
+  int32 serial = 2;
7
+}
8
+
9
+enum ConnType {
10
+  DEFAULT_CONN = 0;
11
+  FILE_TRANSFER = 1;
12
+  PORT_FORWARD = 2;
13
+  RDP = 3;
14
+}
15
+
16
+message RegisterPeerResponse { bool request_pk = 2; }
17
+
18
+message PunchHoleRequest { 
19
+  string id = 1; 
20
+  NatType nat_type = 2;
21
+  string licence_key = 3;
22
+  ConnType conn_type = 4;
23
+  string token = 5;
24
+}
25
+
26
+message PunchHole { 
27
+  bytes socket_addr = 1;
28
+  string relay_server = 2;
29
+  NatType nat_type = 3;
30
+}
31
+
32
+message TestNatRequest {
33
+  int32 serial = 1;
34
+}
35
+
36
+// per my test, uint/int has no difference in encoding, int not good for negative, use sint for negative
37
+message TestNatResponse {
38
+  int32 port = 1; 
39
+  ConfigUpdate cu = 2; // for mobile
40
+}
41
+
42
+enum NatType {
43
+  UNKNOWN_NAT = 0;
44
+  ASYMMETRIC = 1;
45
+  SYMMETRIC = 2;
46
+}
47
+
48
+message PunchHoleSent {
49
+  bytes socket_addr = 1;
50
+  string id = 2;
51
+  string relay_server = 3;
52
+  NatType nat_type = 4;
53
+  string version = 5;
54
+}
55
+
56
+message RegisterPk {
57
+  string id = 1;
58
+  bytes uuid = 2;
59
+  bytes pk = 3;
60
+  string old_id = 4;
61
+}
62
+
63
+message RegisterPkResponse {
64
+  enum Result {
65
+    OK = 0;
66
+    UUID_MISMATCH = 2;
67
+    ID_EXISTS = 3;
68
+    TOO_FREQUENT = 4;
69
+    INVALID_ID_FORMAT = 5;
70
+    NOT_SUPPORT = 6;
71
+    SERVER_ERROR = 7;
72
+  }
73
+  Result result = 1;
74
+}
75
+
76
+message PunchHoleResponse {
77
+  bytes socket_addr = 1;
78
+  bytes pk = 2;
79
+  enum Failure {
80
+    ID_NOT_EXIST = 0;
81
+    OFFLINE = 2;
82
+    LICENSE_MISMATCH = 3;
83
+    LICENSE_OVERUSE = 4;
84
+  }
85
+  Failure failure = 3;
86
+  string relay_server = 4;
87
+  oneof union {
88
+    NatType nat_type = 5;
89
+    bool is_local = 6;
90
+  }
91
+  string other_failure = 7;
92
+}
93
+
94
+message ConfigUpdate {
95
+  int32 serial = 1;
96
+  repeated string rendezvous_servers = 2;
97
+}
98
+
99
+message RequestRelay {
100
+  string id = 1;
101
+  string uuid = 2;
102
+  bytes socket_addr = 3;
103
+  string relay_server = 4;
104
+  bool secure = 5;
105
+  string licence_key = 6;
106
+  ConnType conn_type = 7;
107
+  string token = 8;
108
+}
109
+
110
+message RelayResponse {
111
+  bytes socket_addr = 1;
112
+  string uuid = 2;
113
+  string relay_server = 3;
114
+  oneof union {
115
+    string id = 4;
116
+    bytes pk = 5;
117
+  }
118
+  string refuse_reason = 6;
119
+  string version = 7;
120
+}
121
+
122
+message SoftwareUpdate { string url = 1; }
123
+
124
+// if in same intranet, punch hole won't work both for udp and tcp,
125
+// even some router has below connection error if we connect itself,
126
+//  { kind: Other, error: "could not resolve to any address" },
127
+// so we request local address to connect.
128
+message FetchLocalAddr { 
129
+  bytes socket_addr = 1; 
130
+  string relay_server = 2;
131
+}
132
+
133
+message LocalAddr {
134
+  bytes socket_addr = 1;
135
+  bytes local_addr = 2;
136
+  string relay_server = 3;
137
+  string id = 4;
138
+  string version = 5;
139
+}
140
+
141
+message PeerDiscovery {
142
+  string cmd = 1;
143
+  string mac = 2;
144
+  string id = 3;
145
+  string username = 4;
146
+  string hostname = 5;
147
+  string platform = 6;
148
+  string misc = 7;
149
+}
150
+
151
+message RendezvousMessage {
152
+  oneof union {
153
+    RegisterPeer register_peer = 6;
154
+    RegisterPeerResponse register_peer_response = 7;
155
+    PunchHoleRequest punch_hole_request = 8;
156
+    PunchHole punch_hole = 9;
157
+    PunchHoleSent punch_hole_sent = 10;
158
+    PunchHoleResponse punch_hole_response = 11;
159
+    FetchLocalAddr fetch_local_addr = 12;
160
+    LocalAddr local_addr = 13;
161
+    ConfigUpdate configure_update = 14;
162
+    RegisterPk register_pk = 15;
163
+    RegisterPkResponse register_pk_response = 16;
164
+    SoftwareUpdate software_update = 17;
165
+    RequestRelay request_relay = 18;
166
+    RelayResponse relay_response = 19;
167
+    TestNatRequest test_nat_request = 20;
168
+    TestNatResponse test_nat_response = 21;
169
+    PeerDiscovery peer_discovery = 22;
170
+  }
171
+}

+ 274 - 0
libs/hbb_common/src/bytes_codec.rs

@@ -0,0 +1,274 @@
1
+use bytes::{Buf, BufMut, Bytes, BytesMut};
2
+use std::io;
3
+use tokio_util::codec::{Decoder, Encoder};
4
+
5
+#[derive(Debug, Clone, Copy)]
6
+pub struct BytesCodec {
7
+    state: DecodeState,
8
+    raw: bool,
9
+    max_packet_length: usize,
10
+}
11
+
12
+#[derive(Debug, Clone, Copy)]
13
+enum DecodeState {
14
+    Head,
15
+    Data(usize),
16
+}
17
+
18
+impl BytesCodec {
19
+    pub fn new() -> Self {
20
+        Self {
21
+            state: DecodeState::Head,
22
+            raw: false,
23
+            max_packet_length: usize::MAX,
24
+        }
25
+    }
26
+
27
+    pub fn set_raw(&mut self) {
28
+        self.raw = true;
29
+    }
30
+
31
+    pub fn set_max_packet_length(&mut self, n: usize) {
32
+        self.max_packet_length = n;
33
+    }
34
+
35
+    fn decode_head(&mut self, src: &mut BytesMut) -> io::Result<Option<usize>> {
36
+        if src.is_empty() {
37
+            return Ok(None);
38
+        }
39
+        let head_len = ((src[0] & 0x3) + 1) as usize;
40
+        if src.len() < head_len {
41
+            return Ok(None);
42
+        }
43
+        let mut n = src[0] as usize;
44
+        if head_len > 1 {
45
+            n |= (src[1] as usize) << 8;
46
+        }
47
+        if head_len > 2 {
48
+            n |= (src[2] as usize) << 16;
49
+        }
50
+        if head_len > 3 {
51
+            n |= (src[3] as usize) << 24;
52
+        }
53
+        n >>= 2;
54
+        if n > self.max_packet_length {
55
+            return Err(io::Error::new(io::ErrorKind::InvalidData, "Too big packet"));
56
+        }
57
+        src.advance(head_len);
58
+        src.reserve(n);
59
+        return Ok(Some(n));
60
+    }
61
+
62
+    fn decode_data(&self, n: usize, src: &mut BytesMut) -> io::Result<Option<BytesMut>> {
63
+        if src.len() < n {
64
+            return Ok(None);
65
+        }
66
+        Ok(Some(src.split_to(n)))
67
+    }
68
+}
69
+
70
+impl Decoder for BytesCodec {
71
+    type Item = BytesMut;
72
+    type Error = io::Error;
73
+
74
+    fn decode(&mut self, src: &mut BytesMut) -> Result<Option<BytesMut>, io::Error> {
75
+        if self.raw {
76
+            if !src.is_empty() {
77
+                let len = src.len();
78
+                return Ok(Some(src.split_to(len)));
79
+            } else {
80
+                return Ok(None);
81
+            }
82
+        }
83
+        let n = match self.state {
84
+            DecodeState::Head => match self.decode_head(src)? {
85
+                Some(n) => {
86
+                    self.state = DecodeState::Data(n);
87
+                    n
88
+                }
89
+                None => return Ok(None),
90
+            },
91
+            DecodeState::Data(n) => n,
92
+        };
93
+
94
+        match self.decode_data(n, src)? {
95
+            Some(data) => {
96
+                self.state = DecodeState::Head;
97
+                Ok(Some(data))
98
+            }
99
+            None => Ok(None),
100
+        }
101
+    }
102
+}
103
+
104
+impl Encoder<Bytes> for BytesCodec {
105
+    type Error = io::Error;
106
+
107
+    fn encode(&mut self, data: Bytes, buf: &mut BytesMut) -> Result<(), io::Error> {
108
+        if self.raw {
109
+            buf.reserve(data.len());
110
+            buf.put(data);
111
+            return Ok(());
112
+        }
113
+        if data.len() <= 0x3F {
114
+            buf.put_u8((data.len() << 2) as u8);
115
+        } else if data.len() <= 0x3FFF {
116
+            buf.put_u16_le((data.len() << 2) as u16 | 0x1);
117
+        } else if data.len() <= 0x3FFFFF {
118
+            let h = (data.len() << 2) as u32 | 0x2;
119
+            buf.put_u16_le((h & 0xFFFF) as u16);
120
+            buf.put_u8((h >> 16) as u8);
121
+        } else if data.len() <= 0x3FFFFFFF {
122
+            buf.put_u32_le((data.len() << 2) as u32 | 0x3);
123
+        } else {
124
+            return Err(io::Error::new(io::ErrorKind::InvalidInput, "Overflow"));
125
+        }
126
+        buf.extend(data);
127
+        Ok(())
128
+    }
129
+}
130
+
131
+#[cfg(test)]
132
+mod tests {
133
+    use super::*;
134
+    #[test]
135
+    fn test_codec1() {
136
+        let mut codec = BytesCodec::new();
137
+        let mut buf = BytesMut::new();
138
+        let mut bytes: Vec<u8> = Vec::new();
139
+        bytes.resize(0x3F, 1);
140
+        assert!(!codec.encode(bytes.into(), &mut buf).is_err());
141
+        let buf_saved = buf.clone();
142
+        assert_eq!(buf.len(), 0x3F + 1);
143
+        if let Ok(Some(res)) = codec.decode(&mut buf) {
144
+            assert_eq!(res.len(), 0x3F);
145
+            assert_eq!(res[0], 1);
146
+        } else {
147
+            assert!(false);
148
+        }
149
+        let mut codec2 = BytesCodec::new();
150
+        let mut buf2 = BytesMut::new();
151
+        if let Ok(None) = codec2.decode(&mut buf2) {
152
+        } else {
153
+            assert!(false);
154
+        }
155
+        buf2.extend(&buf_saved[0..1]);
156
+        if let Ok(None) = codec2.decode(&mut buf2) {
157
+        } else {
158
+            assert!(false);
159
+        }
160
+        buf2.extend(&buf_saved[1..]);
161
+        if let Ok(Some(res)) = codec2.decode(&mut buf2) {
162
+            assert_eq!(res.len(), 0x3F);
163
+            assert_eq!(res[0], 1);
164
+        } else {
165
+            assert!(false);
166
+        }
167
+    }
168
+
169
+    #[test]
170
+    fn test_codec2() {
171
+        let mut codec = BytesCodec::new();
172
+        let mut buf = BytesMut::new();
173
+        let mut bytes: Vec<u8> = Vec::new();
174
+        assert!(!codec.encode("".into(), &mut buf).is_err());
175
+        assert_eq!(buf.len(), 1);
176
+        bytes.resize(0x3F + 1, 2);
177
+        assert!(!codec.encode(bytes.into(), &mut buf).is_err());
178
+        assert_eq!(buf.len(), 0x3F + 2 + 2);
179
+        if let Ok(Some(res)) = codec.decode(&mut buf) {
180
+            assert_eq!(res.len(), 0);
181
+        } else {
182
+            assert!(false);
183
+        }
184
+        if let Ok(Some(res)) = codec.decode(&mut buf) {
185
+            assert_eq!(res.len(), 0x3F + 1);
186
+            assert_eq!(res[0], 2);
187
+        } else {
188
+            assert!(false);
189
+        }
190
+    }
191
+
192
+    #[test]
193
+    fn test_codec3() {
194
+        let mut codec = BytesCodec::new();
195
+        let mut buf = BytesMut::new();
196
+        let mut bytes: Vec<u8> = Vec::new();
197
+        bytes.resize(0x3F - 1, 3);
198
+        assert!(!codec.encode(bytes.into(), &mut buf).is_err());
199
+        assert_eq!(buf.len(), 0x3F + 1 - 1);
200
+        if let Ok(Some(res)) = codec.decode(&mut buf) {
201
+            assert_eq!(res.len(), 0x3F - 1);
202
+            assert_eq!(res[0], 3);
203
+        } else {
204
+            assert!(false);
205
+        }
206
+    }
207
+    #[test]
208
+    fn test_codec4() {
209
+        let mut codec = BytesCodec::new();
210
+        let mut buf = BytesMut::new();
211
+        let mut bytes: Vec<u8> = Vec::new();
212
+        bytes.resize(0x3FFF, 4);
213
+        assert!(!codec.encode(bytes.into(), &mut buf).is_err());
214
+        assert_eq!(buf.len(), 0x3FFF + 2);
215
+        if let Ok(Some(res)) = codec.decode(&mut buf) {
216
+            assert_eq!(res.len(), 0x3FFF);
217
+            assert_eq!(res[0], 4);
218
+        } else {
219
+            assert!(false);
220
+        }
221
+    }
222
+
223
+    #[test]
224
+    fn test_codec5() {
225
+        let mut codec = BytesCodec::new();
226
+        let mut buf = BytesMut::new();
227
+        let mut bytes: Vec<u8> = Vec::new();
228
+        bytes.resize(0x3FFFFF, 5);
229
+        assert!(!codec.encode(bytes.into(), &mut buf).is_err());
230
+        assert_eq!(buf.len(), 0x3FFFFF + 3);
231
+        if let Ok(Some(res)) = codec.decode(&mut buf) {
232
+            assert_eq!(res.len(), 0x3FFFFF);
233
+            assert_eq!(res[0], 5);
234
+        } else {
235
+            assert!(false);
236
+        }
237
+    }
238
+
239
+    #[test]
240
+    fn test_codec6() {
241
+        let mut codec = BytesCodec::new();
242
+        let mut buf = BytesMut::new();
243
+        let mut bytes: Vec<u8> = Vec::new();
244
+        bytes.resize(0x3FFFFF + 1, 6);
245
+        assert!(!codec.encode(bytes.into(), &mut buf).is_err());
246
+        let buf_saved = buf.clone();
247
+        assert_eq!(buf.len(), 0x3FFFFF + 4 + 1);
248
+        if let Ok(Some(res)) = codec.decode(&mut buf) {
249
+            assert_eq!(res.len(), 0x3FFFFF + 1);
250
+            assert_eq!(res[0], 6);
251
+        } else {
252
+            assert!(false);
253
+        }
254
+        let mut codec2 = BytesCodec::new();
255
+        let mut buf2 = BytesMut::new();
256
+        buf2.extend(&buf_saved[0..1]);
257
+        if let Ok(None) = codec2.decode(&mut buf2) {
258
+        } else {
259
+            assert!(false);
260
+        }
261
+        buf2.extend(&buf_saved[1..6]);
262
+        if let Ok(None) = codec2.decode(&mut buf2) {
263
+        } else {
264
+            assert!(false);
265
+        }
266
+        buf2.extend(&buf_saved[6..]);
267
+        if let Ok(Some(res)) = codec2.decode(&mut buf2) {
268
+            assert_eq!(res.len(), 0x3FFFFF + 1);
269
+            assert_eq!(res[0], 6);
270
+        } else {
271
+            assert!(false);
272
+        }
273
+    }
274
+}

+ 50 - 0
libs/hbb_common/src/compress.rs

@@ -0,0 +1,50 @@
1
+use std::cell::RefCell;
2
+use zstd::block::{Compressor, Decompressor};
3
+
4
+thread_local! {
5
+    static COMPRESSOR: RefCell<Compressor> = RefCell::new(Compressor::new());
6
+    static DECOMPRESSOR: RefCell<Decompressor> = RefCell::new(Decompressor::new());
7
+}
8
+
9
+/// The library supports regular compression levels from 1 up to ZSTD_maxCLevel(),
10
+/// which is currently 22. Levels >= 20
11
+/// Default level is ZSTD_CLEVEL_DEFAULT==3.
12
+/// value 0 means default, which is controlled by ZSTD_CLEVEL_DEFAULT
13
+pub fn compress(data: &[u8], level: i32) -> Vec<u8> {
14
+    let mut out = Vec::new();
15
+    COMPRESSOR.with(|c| {
16
+        if let Ok(mut c) = c.try_borrow_mut() {
17
+            match c.compress(data, level) {
18
+                Ok(res) => out = res,
19
+                Err(err) => {
20
+                    crate::log::debug!("Failed to compress: {}", err);
21
+                }
22
+            }
23
+        }
24
+    });
25
+    out
26
+}
27
+
28
+pub fn decompress(data: &[u8]) -> Vec<u8> {
29
+    let mut out = Vec::new();
30
+    DECOMPRESSOR.with(|d| {
31
+        if let Ok(mut d) = d.try_borrow_mut() {
32
+            const MAX: usize = 1024 * 1024 * 64;
33
+            const MIN: usize = 1024 * 1024;
34
+            let mut n = 30 * data.len();
35
+            if n > MAX {
36
+                n = MAX;
37
+            }
38
+            if n < MIN {
39
+                n = MIN;
40
+            }
41
+            match d.decompress(data, n) {
42
+                Ok(res) => out = res,
43
+                Err(err) => {
44
+                    crate::log::debug!("Failed to decompress: {}", err);
45
+                }
46
+            }
47
+        }
48
+    });
49
+    out
50
+}

Разница между файлами не показана из-за своего большого размера
+ 876 - 0
libs/hbb_common/src/config.rs


+ 560 - 0
libs/hbb_common/src/fs.rs

@@ -0,0 +1,560 @@
1
+use crate::{bail, message_proto::*, ResultType};
2
+use std::path::{Path, PathBuf};
3
+// https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html
4
+use crate::{
5
+    compress::{compress, decompress},
6
+    config::{Config, COMPRESS_LEVEL},
7
+};
8
+#[cfg(windows)]
9
+use std::os::windows::prelude::*;
10
+use tokio::{fs::File, io::*};
11
+
12
+pub fn read_dir(path: &PathBuf, include_hidden: bool) -> ResultType<FileDirectory> {
13
+    let mut dir = FileDirectory {
14
+        path: get_string(&path),
15
+        ..Default::default()
16
+    };
17
+    #[cfg(windows)]
18
+    if "/" == &get_string(&path) {
19
+        let drives = unsafe { winapi::um::fileapi::GetLogicalDrives() };
20
+        for i in 0..32 {
21
+            if drives & (1 << i) != 0 {
22
+                let name = format!(
23
+                    "{}:",
24
+                    std::char::from_u32('A' as u32 + i as u32).unwrap_or('A')
25
+                );
26
+                dir.entries.push(FileEntry {
27
+                    name,
28
+                    entry_type: FileType::DirDrive.into(),
29
+                    ..Default::default()
30
+                });
31
+            }
32
+        }
33
+        return Ok(dir);
34
+    }
35
+    for entry in path.read_dir()? {
36
+        if let Ok(entry) = entry {
37
+            let p = entry.path();
38
+            let name = p
39
+                .file_name()
40
+                .map(|p| p.to_str().unwrap_or(""))
41
+                .unwrap_or("")
42
+                .to_owned();
43
+            if name.is_empty() {
44
+                continue;
45
+            }
46
+            let mut is_hidden = false;
47
+            let meta;
48
+            if let Ok(tmp) = std::fs::symlink_metadata(&p) {
49
+                meta = tmp;
50
+            } else {
51
+                continue;
52
+            }
53
+            // docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
54
+            #[cfg(windows)]
55
+            if meta.file_attributes() & 0x2 != 0 {
56
+                is_hidden = true;
57
+            }
58
+            #[cfg(not(windows))]
59
+            if name.find('.').unwrap_or(usize::MAX) == 0 {
60
+                is_hidden = true;
61
+            }
62
+            if is_hidden && !include_hidden {
63
+                continue;
64
+            }
65
+            let (entry_type, size) = {
66
+                if p.is_dir() {
67
+                    if meta.file_type().is_symlink() {
68
+                        (FileType::DirLink.into(), 0)
69
+                    } else {
70
+                        (FileType::Dir.into(), 0)
71
+                    }
72
+                } else {
73
+                    if meta.file_type().is_symlink() {
74
+                        (FileType::FileLink.into(), 0)
75
+                    } else {
76
+                        (FileType::File.into(), meta.len())
77
+                    }
78
+                }
79
+            };
80
+            let modified_time = meta
81
+                .modified()
82
+                .map(|x| {
83
+                    x.duration_since(std::time::SystemTime::UNIX_EPOCH)
84
+                        .map(|x| x.as_secs())
85
+                        .unwrap_or(0)
86
+                })
87
+                .unwrap_or(0) as u64;
88
+            dir.entries.push(FileEntry {
89
+                name: get_file_name(&p),
90
+                entry_type,
91
+                is_hidden,
92
+                size,
93
+                modified_time,
94
+                ..Default::default()
95
+            });
96
+        }
97
+    }
98
+    Ok(dir)
99
+}
100
+
101
+#[inline]
102
+pub fn get_file_name(p: &PathBuf) -> String {
103
+    p.file_name()
104
+        .map(|p| p.to_str().unwrap_or(""))
105
+        .unwrap_or("")
106
+        .to_owned()
107
+}
108
+
109
+#[inline]
110
+pub fn get_string(path: &PathBuf) -> String {
111
+    path.to_str().unwrap_or("").to_owned()
112
+}
113
+
114
+#[inline]
115
+pub fn get_path(path: &str) -> PathBuf {
116
+    Path::new(path).to_path_buf()
117
+}
118
+
119
+#[inline]
120
+pub fn get_home_as_string() -> String {
121
+    get_string(&Config::get_home())
122
+}
123
+
124
+fn read_dir_recursive(
125
+    path: &PathBuf,
126
+    prefix: &PathBuf,
127
+    include_hidden: bool,
128
+) -> ResultType<Vec<FileEntry>> {
129
+    let mut files = Vec::new();
130
+    if path.is_dir() {
131
+        // to-do: symbol link handling, cp the link rather than the content
132
+        // to-do: file mode, for unix
133
+        let fd = read_dir(&path, include_hidden)?;
134
+        for entry in fd.entries.iter() {
135
+            match entry.entry_type.enum_value() {
136
+                Ok(FileType::File) => {
137
+                    let mut entry = entry.clone();
138
+                    entry.name = get_string(&prefix.join(entry.name));
139
+                    files.push(entry);
140
+                }
141
+                Ok(FileType::Dir) => {
142
+                    if let Ok(mut tmp) = read_dir_recursive(
143
+                        &path.join(&entry.name),
144
+                        &prefix.join(&entry.name),
145
+                        include_hidden,
146
+                    ) {
147
+                        for entry in tmp.drain(0..) {
148
+                            files.push(entry);
149
+                        }
150
+                    }
151
+                }
152
+                _ => {}
153
+            }
154
+        }
155
+        Ok(files)
156
+    } else if path.is_file() {
157
+        let (size, modified_time) = if let Ok(meta) = std::fs::metadata(&path) {
158
+            (
159
+                meta.len(),
160
+                meta.modified()
161
+                    .map(|x| {
162
+                        x.duration_since(std::time::SystemTime::UNIX_EPOCH)
163
+                            .map(|x| x.as_secs())
164
+                            .unwrap_or(0)
165
+                    })
166
+                    .unwrap_or(0) as u64,
167
+            )
168
+        } else {
169
+            (0, 0)
170
+        };
171
+        files.push(FileEntry {
172
+            entry_type: FileType::File.into(),
173
+            size,
174
+            modified_time,
175
+            ..Default::default()
176
+        });
177
+        Ok(files)
178
+    } else {
179
+        bail!("Not exists");
180
+    }
181
+}
182
+
183
+pub fn get_recursive_files(path: &str, include_hidden: bool) -> ResultType<Vec<FileEntry>> {
184
+    read_dir_recursive(&get_path(path), &get_path(""), include_hidden)
185
+}
186
+
187
+#[derive(Default)]
188
+pub struct TransferJob {
189
+    id: i32,
190
+    path: PathBuf,
191
+    files: Vec<FileEntry>,
192
+    file_num: i32,
193
+    file: Option<File>,
194
+    total_size: u64,
195
+    finished_size: u64,
196
+    transferred: u64,
197
+}
198
+
199
+#[inline]
200
+fn get_ext(name: &str) -> &str {
201
+    if let Some(i) = name.rfind(".") {
202
+        return &name[i + 1..];
203
+    }
204
+    ""
205
+}
206
+
207
+#[inline]
208
+fn is_compressed_file(name: &str) -> bool {
209
+    let ext = get_ext(name);
210
+    ext == "xz"
211
+        || ext == "gz"
212
+        || ext == "zip"
213
+        || ext == "7z"
214
+        || ext == "rar"
215
+        || ext == "bz2"
216
+        || ext == "tgz"
217
+        || ext == "png"
218
+        || ext == "jpg"
219
+}
220
+
221
+impl TransferJob {
222
+    pub fn new_write(id: i32, path: String, files: Vec<FileEntry>) -> Self {
223
+        let total_size = files.iter().map(|x| x.size as u64).sum();
224
+        Self {
225
+            id,
226
+            path: get_path(&path),
227
+            files,
228
+            total_size,
229
+            ..Default::default()
230
+        }
231
+    }
232
+
233
+    pub fn new_read(id: i32, path: String, include_hidden: bool) -> ResultType<Self> {
234
+        let files = get_recursive_files(&path, include_hidden)?;
235
+        let total_size = files.iter().map(|x| x.size as u64).sum();
236
+        Ok(Self {
237
+            id,
238
+            path: get_path(&path),
239
+            files,
240
+            total_size,
241
+            ..Default::default()
242
+        })
243
+    }
244
+
245
+    #[inline]
246
+    pub fn files(&self) -> &Vec<FileEntry> {
247
+        &self.files
248
+    }
249
+
250
+    #[inline]
251
+    pub fn set_files(&mut self, files: Vec<FileEntry>) {
252
+        self.files = files;
253
+    }
254
+
255
+    #[inline]
256
+    pub fn id(&self) -> i32 {
257
+        self.id
258
+    }
259
+
260
+    #[inline]
261
+    pub fn total_size(&self) -> u64 {
262
+        self.total_size
263
+    }
264
+
265
+    #[inline]
266
+    pub fn finished_size(&self) -> u64 {
267
+        self.finished_size
268
+    }
269
+
270
+    #[inline]
271
+    pub fn transferred(&self) -> u64 {
272
+        self.transferred
273
+    }
274
+
275
+    #[inline]
276
+    pub fn file_num(&self) -> i32 {
277
+        self.file_num
278
+    }
279
+
280
+    pub fn modify_time(&self) {
281
+        let file_num = self.file_num as usize;
282
+        if file_num < self.files.len() {
283
+            let entry = &self.files[file_num];
284
+            let path = self.join(&entry.name);
285
+            let download_path = format!("{}.download", get_string(&path));
286
+            std::fs::rename(&download_path, &path).ok();
287
+            filetime::set_file_mtime(
288
+                &path,
289
+                filetime::FileTime::from_unix_time(entry.modified_time as _, 0),
290
+            )
291
+            .ok();
292
+        }
293
+    }
294
+
295
+    pub fn remove_download_file(&self) {
296
+        let file_num = self.file_num as usize;
297
+        if file_num < self.files.len() {
298
+            let entry = &self.files[file_num];
299
+            let path = self.join(&entry.name);
300
+            let download_path = format!("{}.download", get_string(&path));
301
+            std::fs::remove_file(&download_path).ok();
302
+        }
303
+    }
304
+
305
+    pub async fn write(&mut self, block: FileTransferBlock, raw: Option<&[u8]>) -> ResultType<()> {
306
+        if block.id != self.id {
307
+            bail!("Wrong id");
308
+        }
309
+        let file_num = block.file_num as usize;
310
+        if file_num >= self.files.len() {
311
+            bail!("Wrong file number");
312
+        }
313
+        if file_num != self.file_num as usize || self.file.is_none() {
314
+            self.modify_time();
315
+            if let Some(file) = self.file.as_mut() {
316
+                file.sync_all().await?;
317
+            }
318
+            self.file_num = block.file_num;
319
+            let entry = &self.files[file_num];
320
+            let path = self.join(&entry.name);
321
+            if let Some(p) = path.parent() {
322
+                std::fs::create_dir_all(p).ok();
323
+            }
324
+            let path = format!("{}.download", get_string(&path));
325
+            self.file = Some(File::create(&path).await?);
326
+        }
327
+        let data = if let Some(data) = raw {
328
+            data
329
+        } else {
330
+            &block.data
331
+        };
332
+        if block.compressed {
333
+            let tmp = decompress(data);
334
+            self.file.as_mut().unwrap().write_all(&tmp).await?;
335
+            self.finished_size += tmp.len() as u64;
336
+        } else {
337
+            self.file.as_mut().unwrap().write_all(data).await?;
338
+            self.finished_size += data.len() as u64;
339
+        }
340
+        self.transferred += data.len() as u64;
341
+        Ok(())
342
+    }
343
+
344
+    #[inline]
345
+    fn join(&self, name: &str) -> PathBuf {
346
+        if name.is_empty() {
347
+            self.path.clone()
348
+        } else {
349
+            self.path.join(name)
350
+        }
351
+    }
352
+
353
+    pub async fn read(&mut self) -> ResultType<Option<FileTransferBlock>> {
354
+        let file_num = self.file_num as usize;
355
+        if file_num >= self.files.len() {
356
+            self.file.take();
357
+            return Ok(None);
358
+        }
359
+        let name = &self.files[file_num].name;
360
+        if self.file.is_none() {
361
+            match File::open(self.join(&name)).await {
362
+                Ok(file) => {
363
+                    self.file = Some(file);
364
+                }
365
+                Err(err) => {
366
+                    self.file_num += 1;
367
+                    return Err(err.into());
368
+                }
369
+            }
370
+        }
371
+        const BUF_SIZE: usize = 128 * 1024;
372
+        let mut buf: Vec<u8> = Vec::with_capacity(BUF_SIZE);
373
+        unsafe {
374
+            buf.set_len(BUF_SIZE);
375
+        }
376
+        let mut compressed = false;
377
+        let mut offset: usize = 0;
378
+        loop {
379
+            match self.file.as_mut().unwrap().read(&mut buf[offset..]).await {
380
+                Err(err) => {
381
+                    self.file_num += 1;
382
+                    self.file = None;
383
+                    return Err(err.into());
384
+                }
385
+                Ok(n) => {
386
+                    offset += n;
387
+                    if n == 0 || offset == BUF_SIZE {
388
+                        break;
389
+                    }
390
+                }
391
+            }
392
+        }
393
+        unsafe { buf.set_len(offset) };
394
+        if offset == 0 {
395
+            self.file_num += 1;
396
+            self.file = None;
397
+        } else {
398
+            self.finished_size += offset as u64;
399
+            if !is_compressed_file(name) {
400
+                let tmp = compress(&buf, COMPRESS_LEVEL);
401
+                if tmp.len() < buf.len() {
402
+                    buf = tmp;
403
+                    compressed = true;
404
+                }
405
+            }
406
+            self.transferred += buf.len() as u64;
407
+        }
408
+        Ok(Some(FileTransferBlock {
409
+            id: self.id,
410
+            file_num: file_num as _,
411
+            data: buf.into(),
412
+            compressed,
413
+            ..Default::default()
414
+        }))
415
+    }
416
+}
417
+
418
+#[inline]
419
+pub fn new_error<T: std::string::ToString>(id: i32, err: T, file_num: i32) -> Message {
420
+    let mut resp = FileResponse::new();
421
+    resp.set_error(FileTransferError {
422
+        id,
423
+        error: err.to_string(),
424
+        file_num,
425
+        ..Default::default()
426
+    });
427
+    let mut msg_out = Message::new();
428
+    msg_out.set_file_response(resp);
429
+    msg_out
430
+}
431
+
432
+#[inline]
433
+pub fn new_dir(id: i32, path: String, files: Vec<FileEntry>) -> Message {
434
+    let mut resp = FileResponse::new();
435
+    resp.set_dir(FileDirectory {
436
+        id,
437
+        path,
438
+        entries: files.into(),
439
+        ..Default::default()
440
+    });
441
+    let mut msg_out = Message::new();
442
+    msg_out.set_file_response(resp);
443
+    msg_out
444
+}
445
+
446
+#[inline]
447
+pub fn new_block(block: FileTransferBlock) -> Message {
448
+    let mut resp = FileResponse::new();
449
+    resp.set_block(block);
450
+    let mut msg_out = Message::new();
451
+    msg_out.set_file_response(resp);
452
+    msg_out
453
+}
454
+
455
+#[inline]
456
+pub fn new_receive(id: i32, path: String, files: Vec<FileEntry>) -> Message {
457
+    let mut action = FileAction::new();
458
+    action.set_receive(FileTransferReceiveRequest {
459
+        id,
460
+        path,
461
+        files: files.into(),
462
+        ..Default::default()
463
+    });
464
+    let mut msg_out = Message::new();
465
+    msg_out.set_file_action(action);
466
+    msg_out
467
+}
468
+
469
+#[inline]
470
+pub fn new_send(id: i32, path: String, include_hidden: bool) -> Message {
471
+    let mut action = FileAction::new();
472
+    action.set_send(FileTransferSendRequest {
473
+        id,
474
+        path,
475
+        include_hidden,
476
+        ..Default::default()
477
+    });
478
+    let mut msg_out = Message::new();
479
+    msg_out.set_file_action(action);
480
+    msg_out
481
+}
482
+
483
+#[inline]
484
+pub fn new_done(id: i32, file_num: i32) -> Message {
485
+    let mut resp = FileResponse::new();
486
+    resp.set_done(FileTransferDone {
487
+        id,
488
+        file_num,
489
+        ..Default::default()
490
+    });
491
+    let mut msg_out = Message::new();
492
+    msg_out.set_file_response(resp);
493
+    msg_out
494
+}
495
+
496
+#[inline]
497
+pub fn remove_job(id: i32, jobs: &mut Vec<TransferJob>) {
498
+    *jobs = jobs.drain(0..).filter(|x| x.id() != id).collect();
499
+}
500
+
501
+#[inline]
502
+pub fn get_job(id: i32, jobs: &mut Vec<TransferJob>) -> Option<&mut TransferJob> {
503
+    jobs.iter_mut().filter(|x| x.id() == id).next()
504
+}
505
+
506
+pub async fn handle_read_jobs(
507
+    jobs: &mut Vec<TransferJob>,
508
+    stream: &mut crate::Stream,
509
+) -> ResultType<()> {
510
+    let mut finished = Vec::new();
511
+    for job in jobs.iter_mut() {
512
+        match job.read().await {
513
+            Err(err) => {
514
+                stream
515
+                    .send(&new_error(job.id(), err, job.file_num()))
516
+                    .await?;
517
+            }
518
+            Ok(Some(block)) => {
519
+                stream.send(&new_block(block)).await?;
520
+            }
521
+            Ok(None) => {
522
+                finished.push(job.id());
523
+                stream.send(&new_done(job.id(), job.file_num())).await?;
524
+            }
525
+        }
526
+    }
527
+    for id in finished {
528
+        remove_job(id, jobs);
529
+    }
530
+    Ok(())
531
+}
532
+
533
+pub fn remove_all_empty_dir(path: &PathBuf) -> ResultType<()> {
534
+    let fd = read_dir(path, true)?;
535
+    for entry in fd.entries.iter() {
536
+        match entry.entry_type.enum_value() {
537
+            Ok(FileType::Dir) => {
538
+                remove_all_empty_dir(&path.join(&entry.name)).ok();
539
+            }
540
+            Ok(FileType::DirLink) | Ok(FileType::FileLink) => {
541
+                std::fs::remove_file(&path.join(&entry.name)).ok();
542
+            }
543
+            _ => {}
544
+        }
545
+    }
546
+    std::fs::remove_dir(path).ok();
547
+    Ok(())
548
+}
549
+
550
+#[inline]
551
+pub fn remove_file(file: &str) -> ResultType<()> {
552
+    std::fs::remove_file(get_path(file))?;
553
+    Ok(())
554
+}
555
+
556
+#[inline]
557
+pub fn create_dir(dir: &str) -> ResultType<()> {
558
+    std::fs::create_dir_all(get_path(dir))?;
559
+    Ok(())
560
+}

+ 211 - 0
libs/hbb_common/src/lib.rs

@@ -0,0 +1,211 @@
1
+pub mod compress;
2
+#[path = "./protos/message.rs"]
3
+pub mod message_proto;
4
+#[path = "./protos/rendezvous.rs"]
5
+pub mod rendezvous_proto;
6
+pub use bytes;
7
+pub use futures;
8
+pub use protobuf;
9
+use std::{
10
+    fs::File,
11
+    io::{self, BufRead},
12
+    net::{Ipv4Addr, SocketAddr, SocketAddrV4},
13
+    path::Path,
14
+    time::{self, SystemTime, UNIX_EPOCH},
15
+};
16
+pub use tokio;
17
+pub use tokio_util;
18
+pub mod socket_client;
19
+pub mod tcp;
20
+pub mod udp;
21
+pub use env_logger;
22
+pub use log;
23
+pub mod bytes_codec;
24
+#[cfg(feature = "quic")]
25
+pub mod quic;
26
+pub use anyhow::{self, bail};
27
+pub use futures_util;
28
+pub mod config;
29
+pub mod fs;
30
+#[cfg(not(any(target_os = "android", target_os = "ios")))]
31
+pub use mac_address;
32
+pub use rand;
33
+pub use regex;
34
+pub use sodiumoxide;
35
+pub use tokio_socks;
36
+pub use tokio_socks::IntoTargetAddr;
37
+pub use tokio_socks::TargetAddr;
38
+pub use lazy_static;
39
+
40
+#[cfg(feature = "quic")]
41
+pub type Stream = quic::Connection;
42
+#[cfg(not(feature = "quic"))]
43
+pub type Stream = tcp::FramedStream;
44
+
45
+#[inline]
46
+pub async fn sleep(sec: f32) {
47
+    tokio::time::sleep(time::Duration::from_secs_f32(sec)).await;
48
+}
49
+
50
+#[macro_export]
51
+macro_rules! allow_err {
52
+    ($e:expr) => {
53
+        if let Err(err) = $e {
54
+            log::debug!(
55
+                "{:?}, {}:{}:{}:{}",
56
+                err,
57
+                module_path!(),
58
+                file!(),
59
+                line!(),
60
+                column!()
61
+            );
62
+        } else {
63
+        }
64
+    };
65
+}
66
+
67
+#[inline]
68
+pub fn timeout<T: std::future::Future>(ms: u64, future: T) -> tokio::time::Timeout<T> {
69
+    tokio::time::timeout(std::time::Duration::from_millis(ms), future)
70
+}
71
+
72
+pub type ResultType<F, E = anyhow::Error> = anyhow::Result<F, E>;
73
+
74
+/// Certain router and firewalls scan the packet and if they
75
+/// find an IP address belonging to their pool that they use to do the NAT mapping/translation, so here we mangle the ip address
76
+
77
+pub struct AddrMangle();
78
+
79
+impl AddrMangle {
80
+    pub fn encode(addr: SocketAddr) -> Vec<u8> {
81
+        match addr {
82
+            SocketAddr::V4(addr_v4) => {
83
+                let tm = (SystemTime::now()
84
+                    .duration_since(UNIX_EPOCH)
85
+                    .unwrap()
86
+                    .as_micros() as u32) as u128;
87
+                let ip = u32::from_le_bytes(addr_v4.ip().octets()) as u128;
88
+                let port = addr.port() as u128;
89
+                let v = ((ip + tm) << 49) | (tm << 17) | (port + (tm & 0xFFFF));
90
+                let bytes = v.to_le_bytes();
91
+                let mut n_padding = 0;
92
+                for i in bytes.iter().rev() {
93
+                    if i == &0u8 {
94
+                        n_padding += 1;
95
+                    } else {
96
+                        break;
97
+                    }
98
+                }
99
+                bytes[..(16 - n_padding)].to_vec()
100
+            }
101
+            _ => {
102
+                panic!("Only support ipv4");
103
+            }
104
+        }
105
+    }
106
+
107
+    pub fn decode(bytes: &[u8]) -> SocketAddr {
108
+        let mut padded = [0u8; 16];
109
+        padded[..bytes.len()].copy_from_slice(&bytes);
110
+        let number = u128::from_le_bytes(padded);
111
+        let tm = (number >> 17) & (u32::max_value() as u128);
112
+        let ip = (((number >> 49) - tm) as u32).to_le_bytes();
113
+        let port = (number & 0xFFFFFF) - (tm & 0xFFFF);
114
+        SocketAddr::V4(SocketAddrV4::new(
115
+            Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]),
116
+            port as u16,
117
+        ))
118
+    }
119
+}
120
+
121
+pub fn get_version_from_url(url: &str) -> String {
122
+    let n = url.chars().count();
123
+    let a = url
124
+        .chars()
125
+        .rev()
126
+        .enumerate()
127
+        .filter(|(_, x)| x == &'-')
128
+        .next()
129
+        .map(|(i, _)| i);
130
+    if let Some(a) = a {
131
+        let b = url
132
+            .chars()
133
+            .rev()
134
+            .enumerate()
135
+            .filter(|(_, x)| x == &'.')
136
+            .next()
137
+            .map(|(i, _)| i);
138
+        if let Some(b) = b {
139
+            if a > b {
140
+                if url
141
+                    .chars()
142
+                    .skip(n - b)
143
+                    .collect::<String>()
144
+                    .parse::<i32>()
145
+                    .is_ok()
146
+                {
147
+                    return url.chars().skip(n - a).collect();
148
+                } else {
149
+                    return url.chars().skip(n - a).take(a - b - 1).collect();
150
+                }
151
+            } else {
152
+                return url.chars().skip(n - a).collect();
153
+            }
154
+        }
155
+    }
156
+    "".to_owned()
157
+}
158
+
159
+pub fn gen_version() {
160
+    let mut file = File::create("./src/version.rs").unwrap();
161
+    for line in read_lines("Cargo.toml").unwrap() {
162
+        if let Ok(line) = line {
163
+            let ab: Vec<&str> = line.split("=").map(|x| x.trim()).collect();
164
+            if ab.len() == 2 && ab[0] == "version" {
165
+                use std::io::prelude::*;
166
+                file.write_all(format!("pub const VERSION: &str = {};", ab[1]).as_bytes())
167
+                    .ok();
168
+                file.sync_all().ok();
169
+                break;
170
+            }
171
+        }
172
+    }
173
+}
174
+
175
+fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
176
+where
177
+    P: AsRef<Path>,
178
+{
179
+    let file = File::open(filename)?;
180
+    Ok(io::BufReader::new(file).lines())
181
+}
182
+
183
+pub fn is_valid_custom_id(id: &str) -> bool {
184
+    regex::Regex::new(r"^[a-zA-Z]\w{5,15}$")
185
+        .unwrap()
186
+        .is_match(id)
187
+}
188
+
189
+pub fn get_version_number(v: &str) -> i64 {
190
+    let mut n = 0;
191
+    for x in v.split(".") {
192
+        n = n * 1000 + x.parse::<i64>().unwrap_or(0);
193
+    }
194
+    n
195
+}
196
+
197
+pub fn get_modified_time(path: &std::path::Path) -> SystemTime {
198
+    std::fs::metadata(&path)
199
+        .map(|m| m.modified().unwrap_or(UNIX_EPOCH))
200
+        .unwrap_or(UNIX_EPOCH)
201
+}
202
+
203
+#[cfg(test)]
204
+mod tests {
205
+    use super::*;
206
+    #[test]
207
+    fn test_mangle() {
208
+        let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
209
+        assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
210
+    }
211
+}

+ 135 - 0
libs/hbb_common/src/quic.rs

@@ -0,0 +1,135 @@
1
+use crate::{allow_err, anyhow::anyhow, ResultType};
2
+use protobuf::Message;
3
+use std::{net::SocketAddr, sync::Arc};
4
+use tokio::{self, stream::StreamExt, sync::mpsc};
5
+
6
+const QUIC_HBB: &[&[u8]] = &[b"hbb"];
7
+const SERVER_NAME: &str = "hbb";
8
+
9
+type Sender = mpsc::UnboundedSender<Value>;
10
+type Receiver = mpsc::UnboundedReceiver<Value>;
11
+
12
+pub fn new_server(socket: std::net::UdpSocket) -> ResultType<(Server, SocketAddr)> {
13
+    let mut transport_config = quinn::TransportConfig::default();
14
+    transport_config.stream_window_uni(0);
15
+    let mut server_config = quinn::ServerConfig::default();
16
+    server_config.transport = Arc::new(transport_config);
17
+    let mut server_config = quinn::ServerConfigBuilder::new(server_config);
18
+    server_config.protocols(QUIC_HBB);
19
+    // server_config.enable_keylog();
20
+    // server_config.use_stateless_retry(true);
21
+    let mut endpoint = quinn::Endpoint::builder();
22
+    endpoint.listen(server_config.build());
23
+    let (end, incoming) = endpoint.with_socket(socket)?;
24
+    Ok((Server { incoming }, end.local_addr()?))
25
+}
26
+
27
+pub async fn new_client(local_addr: &SocketAddr, peer: &SocketAddr) -> ResultType<Connection> {
28
+    let mut endpoint = quinn::Endpoint::builder();
29
+    let mut client_config = quinn::ClientConfigBuilder::default();
30
+    client_config.protocols(QUIC_HBB);
31
+    //client_config.enable_keylog();
32
+    endpoint.default_client_config(client_config.build());
33
+    let (endpoint, _) = endpoint.bind(local_addr)?;
34
+    let new_conn = endpoint.connect(peer, SERVER_NAME)?.await?;
35
+    Connection::new_for_client(new_conn.connection).await
36
+}
37
+
38
+pub struct Server {
39
+    incoming: quinn::Incoming,
40
+}
41
+
42
+impl Server {
43
+    #[inline]
44
+    pub async fn next(&mut self) -> ResultType<Option<Connection>> {
45
+        Connection::new_for_server(&mut self.incoming).await
46
+    }
47
+}
48
+
49
+pub struct Connection {
50
+    conn: quinn::Connection,
51
+    tx: quinn::SendStream,
52
+    rx: Receiver,
53
+}
54
+
55
+type Value = ResultType<Vec<u8>>;
56
+
57
+impl Connection {
58
+    async fn new_for_server(incoming: &mut quinn::Incoming) -> ResultType<Option<Self>> {
59
+        if let Some(conn) = incoming.next().await {
60
+            let quinn::NewConnection {
61
+                connection: conn,
62
+                // uni_streams,
63
+                mut bi_streams,
64
+                ..
65
+            } = conn.await?;
66
+            let (tx, rx) = mpsc::unbounded_channel::<Value>();
67
+            tokio::spawn(async move {
68
+                loop {
69
+                    let stream = bi_streams.next().await;
70
+                    if let Some(stream) = stream {
71
+                        let stream = match stream {
72
+                            Err(e) => {
73
+                                tx.send(Err(e.into())).ok();
74
+                                break;
75
+                            }
76
+                            Ok(s) => s,
77
+                        };
78
+                        let cloned = tx.clone();
79
+                        tokio::spawn(async move {
80
+                            allow_err!(handle_request(stream.1, cloned).await);
81
+                        });
82
+                    } else {
83
+                        tx.send(Err(anyhow!("Reset by the peer"))).ok();
84
+                        break;
85
+                    }
86
+                }
87
+                log::info!("Exit connection outer loop");
88
+            });
89
+            let tx = conn.open_uni().await?;
90
+            Ok(Some(Self { conn, tx, rx }))
91
+        } else {
92
+            Ok(None)
93
+        }
94
+    }
95
+
96
+    async fn new_for_client(conn: quinn::Connection) -> ResultType<Self> {
97
+        let (tx, rx_quic) = conn.open_bi().await?;
98
+        let (tx_mpsc, rx) = mpsc::unbounded_channel::<Value>();
99
+        tokio::spawn(async move {
100
+            allow_err!(handle_request(rx_quic, tx_mpsc).await);
101
+        });
102
+        Ok(Self { conn, tx, rx })
103
+    }
104
+
105
+    #[inline]
106
+    pub async fn next(&mut self) -> Option<Value> {
107
+        // None is returned when all Sender halves have dropped,
108
+        // indicating that no further values can be sent on the channel.
109
+        self.rx.recv().await
110
+    }
111
+
112
+    #[inline]
113
+    pub fn remote_address(&self) -> SocketAddr {
114
+        self.conn.remote_address()
115
+    }
116
+
117
+    #[inline]
118
+    pub async fn send_raw(&mut self, bytes: &[u8]) -> ResultType<()> {
119
+        self.tx.write_all(bytes).await?;
120
+        Ok(())
121
+    }
122
+
123
+    #[inline]
124
+    pub async fn send(&mut self, msg: &dyn Message) -> ResultType<()> {
125
+        match msg.write_to_bytes() {
126
+            Ok(bytes) => self.send_raw(&bytes).await?,
127
+            err => allow_err!(err),
128
+        }
129
+        Ok(())
130
+    }
131
+}
132
+
133
+async fn handle_request(rx: quinn::RecvStream, tx: Sender) -> ResultType<()> {
134
+    Ok(())
135
+}

+ 91 - 0
libs/hbb_common/src/socket_client.rs

@@ -0,0 +1,91 @@
1
+use crate::{
2
+    config::{Config, NetworkType},
3
+    tcp::FramedStream,
4
+    udp::FramedSocket,
5
+    ResultType,
6
+};
7
+use anyhow::Context;
8
+use std::net::SocketAddr;
9
+use tokio::net::ToSocketAddrs;
10
+use tokio_socks::{IntoTargetAddr, TargetAddr};
11
+
12
+fn to_socket_addr(host: &str) -> ResultType<SocketAddr> {
13
+    use std::net::ToSocketAddrs;
14
+    host.to_socket_addrs()?.next().context("Failed to solve")
15
+}
16
+
17
+pub fn get_target_addr(host: &str) -> ResultType<TargetAddr<'static>> {
18
+    let addr = match Config::get_network_type() {
19
+        NetworkType::Direct => to_socket_addr(&host)?.into_target_addr()?,
20
+        NetworkType::ProxySocks => host.into_target_addr()?,
21
+    }
22
+    .to_owned();
23
+    Ok(addr)
24
+}
25
+
26
+pub fn test_if_valid_server(host: &str) -> String {
27
+    let mut host = host.to_owned();
28
+    if !host.contains(":") {
29
+        host = format!("{}:{}", host, 0);
30
+    }
31
+
32
+    match Config::get_network_type() {
33
+        NetworkType::Direct => match to_socket_addr(&host) {
34
+            Err(err) => err.to_string(),
35
+            Ok(_) => "".to_owned(),
36
+        },
37
+        NetworkType::ProxySocks => match &host.into_target_addr() {
38
+            Err(err) => err.to_string(),
39
+            Ok(_) => "".to_owned(),
40
+        },
41
+    }
42
+}
43
+
44
+pub async fn connect_tcp<'t, T: IntoTargetAddr<'t>>(
45
+    target: T,
46
+    local: SocketAddr,
47
+    ms_timeout: u64,
48
+) -> ResultType<FramedStream> {
49
+    let target_addr = target.into_target_addr()?;
50
+
51
+    if let Some(conf) = Config::get_socks() {
52
+        FramedStream::connect(
53
+            conf.proxy.as_str(),
54
+            target_addr,
55
+            local,
56
+            conf.username.as_str(),
57
+            conf.password.as_str(),
58
+            ms_timeout,
59
+        )
60
+        .await
61
+    } else {
62
+        let addr = std::net::ToSocketAddrs::to_socket_addrs(&target_addr)?
63
+            .next()
64
+            .context("Invalid target addr")?;
65
+        Ok(FramedStream::new(addr, local, ms_timeout).await?)
66
+    }
67
+}
68
+
69
+pub async fn new_udp<T: ToSocketAddrs>(local: T, ms_timeout: u64) -> ResultType<FramedSocket> {
70
+    match Config::get_socks() {
71
+        None => Ok(FramedSocket::new(local).await?),
72
+        Some(conf) => {
73
+            let socket = FramedSocket::new_proxy(
74
+                conf.proxy.as_str(),
75
+                local,
76
+                conf.username.as_str(),
77
+                conf.password.as_str(),
78
+                ms_timeout,
79
+            )
80
+            .await?;
81
+            Ok(socket)
82
+        }
83
+    }
84
+}
85
+
86
+pub async fn rebind_udp<T: ToSocketAddrs>(local: T) -> ResultType<Option<FramedSocket>> {
87
+    match Config::get_network_type() {
88
+        NetworkType::Direct => Ok(Some(FramedSocket::new(local).await?)),
89
+        _ => Ok(None),
90
+    }
91
+}

+ 285 - 0
libs/hbb_common/src/tcp.rs

@@ -0,0 +1,285 @@
1
+use crate::{bail, bytes_codec::BytesCodec, ResultType};
2
+use bytes::{BufMut, Bytes, BytesMut};
3
+use futures::{SinkExt, StreamExt};
4
+use protobuf::Message;
5
+use sodiumoxide::crypto::secretbox::{self, Key, Nonce};
6
+use std::{
7
+    io::{self, Error, ErrorKind},
8
+    net::SocketAddr,
9
+    ops::{Deref, DerefMut},
10
+    pin::Pin,
11
+    task::{Context, Poll},
12
+};
13
+use tokio::{
14
+    io::{AsyncRead, AsyncWrite, ReadBuf},
15
+    net::{lookup_host, TcpListener, TcpSocket, ToSocketAddrs},
16
+};
17
+use tokio_socks::{tcp::Socks5Stream, IntoTargetAddr, ToProxyAddrs};
18
+use tokio_util::codec::Framed;
19
+
20
+pub trait TcpStreamTrait: AsyncRead + AsyncWrite + Unpin {}
21
+pub struct DynTcpStream(Box<dyn TcpStreamTrait + Send + Sync>);
22
+
23
+pub struct FramedStream(
24
+    Framed<DynTcpStream, BytesCodec>,
25
+    SocketAddr,
26
+    Option<(Key, u64, u64)>,
27
+    u64,
28
+);
29
+
30
+impl Deref for FramedStream {
31
+    type Target = Framed<DynTcpStream, BytesCodec>;
32
+
33
+    fn deref(&self) -> &Self::Target {
34
+        &self.0
35
+    }
36
+}
37
+
38
+impl DerefMut for FramedStream {
39
+    fn deref_mut(&mut self) -> &mut Self::Target {
40
+        &mut self.0
41
+    }
42
+}
43
+
44
+impl Deref for DynTcpStream {
45
+    type Target = Box<dyn TcpStreamTrait + Send + Sync>;
46
+
47
+    fn deref(&self) -> &Self::Target {
48
+        &self.0
49
+    }
50
+}
51
+
52
+impl DerefMut for DynTcpStream {
53
+    fn deref_mut(&mut self) -> &mut Self::Target {
54
+        &mut self.0
55
+    }
56
+}
57
+
58
+fn new_socket(addr: std::net::SocketAddr, reuse: bool) -> Result<TcpSocket, std::io::Error> {
59
+    let socket = match addr {
60
+        std::net::SocketAddr::V4(..) => TcpSocket::new_v4()?,
61
+        std::net::SocketAddr::V6(..) => TcpSocket::new_v6()?,
62
+    };
63
+    if reuse {
64
+        // windows has no reuse_port, but it's reuse_address
65
+        // almost equals to unix's reuse_port + reuse_address,
66
+        // though may introduce nondeterministic behavior
67
+        #[cfg(unix)]
68
+        socket.set_reuseport(true)?;
69
+        socket.set_reuseaddr(true)?;
70
+    }
71
+    socket.bind(addr)?;
72
+    Ok(socket)
73
+}
74
+
75
+impl FramedStream {
76
+    pub async fn new<T1: ToSocketAddrs, T2: ToSocketAddrs>(
77
+        remote_addr: T1,
78
+        local_addr: T2,
79
+        ms_timeout: u64,
80
+    ) -> ResultType<Self> {
81
+        for local_addr in lookup_host(&local_addr).await? {
82
+            for remote_addr in lookup_host(&remote_addr).await? {
83
+                let stream = super::timeout(
84
+                    ms_timeout,
85
+                    new_socket(local_addr, true)?.connect(remote_addr),
86
+                )
87
+                .await??;
88
+                stream.set_nodelay(true).ok();
89
+                let addr = stream.local_addr()?;
90
+                return Ok(Self(
91
+                    Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
92
+                    addr,
93
+                    None,
94
+                    0,
95
+                ));
96
+            }
97
+        }
98
+        bail!("could not resolve to any address");
99
+    }
100
+
101
+    pub async fn connect<'a, 't, P, T1, T2>(
102
+        proxy: P,
103
+        target: T1,
104
+        local: T2,
105
+        username: &'a str,
106
+        password: &'a str,
107
+        ms_timeout: u64,
108
+    ) -> ResultType<Self>
109
+    where
110
+        P: ToProxyAddrs,
111
+        T1: IntoTargetAddr<'t>,
112
+        T2: ToSocketAddrs,
113
+    {
114
+        if let Some(local) = lookup_host(&local).await?.next() {
115
+            if let Some(proxy) = proxy.to_proxy_addrs().next().await {
116
+                let stream =
117
+                    super::timeout(ms_timeout, new_socket(local, true)?.connect(proxy?)).await??;
118
+                stream.set_nodelay(true).ok();
119
+                let stream = if username.trim().is_empty() {
120
+                    super::timeout(
121
+                        ms_timeout,
122
+                        Socks5Stream::connect_with_socket(stream, target),
123
+                    )
124
+                    .await??
125
+                } else {
126
+                    super::timeout(
127
+                        ms_timeout,
128
+                        Socks5Stream::connect_with_password_and_socket(
129
+                            stream, target, username, password,
130
+                        ),
131
+                    )
132
+                    .await??
133
+                };
134
+                let addr = stream.local_addr()?;
135
+                return Ok(Self(
136
+                    Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
137
+                    addr,
138
+                    None,
139
+                    0,
140
+                ));
141
+            };
142
+        };
143
+        bail!("could not resolve to any address");
144
+    }
145
+
146
+    pub fn local_addr(&self) -> SocketAddr {
147
+        self.1
148
+    }
149
+
150
+    pub fn set_send_timeout(&mut self, ms: u64) {
151
+        self.3 = ms;
152
+    }
153
+
154
+    pub fn from(stream: impl TcpStreamTrait + Send + Sync + 'static, addr: SocketAddr) -> Self {
155
+        Self(
156
+            Framed::new(DynTcpStream(Box::new(stream)), BytesCodec::new()),
157
+            addr,
158
+            None,
159
+            0,
160
+        )
161
+    }
162
+
163
+    pub fn set_raw(&mut self) {
164
+        self.0.codec_mut().set_raw();
165
+        self.2 = None;
166
+    }
167
+
168
+    pub fn is_secured(&self) -> bool {
169
+        self.2.is_some()
170
+    }
171
+
172
+    #[inline]
173
+    pub async fn send(&mut self, msg: &impl Message) -> ResultType<()> {
174
+        self.send_raw(msg.write_to_bytes()?).await
175
+    }
176
+
177
+    #[inline]
178
+    pub async fn send_raw(&mut self, msg: Vec<u8>) -> ResultType<()> {
179
+        let mut msg = msg;
180
+        if let Some(key) = self.2.as_mut() {
181
+            key.1 += 1;
182
+            let nonce = Self::get_nonce(key.1);
183
+            msg = secretbox::seal(&msg, &nonce, &key.0);
184
+        }
185
+        self.send_bytes(bytes::Bytes::from(msg)).await?;
186
+        Ok(())
187
+    }
188
+
189
+    #[inline]
190
+    pub async fn send_bytes(&mut self, bytes: Bytes) -> ResultType<()> {
191
+        if self.3 > 0 {
192
+            super::timeout(self.3, self.0.send(bytes)).await??;
193
+        } else {
194
+            self.0.send(bytes).await?;
195
+        }
196
+        Ok(())
197
+    }
198
+
199
+    #[inline]
200
+    pub async fn next(&mut self) -> Option<Result<BytesMut, Error>> {
201
+        let mut res = self.0.next().await;
202
+        if let Some(key) = self.2.as_mut() {
203
+            if let Some(Ok(bytes)) = res.as_mut() {
204
+                key.2 += 1;
205
+                let nonce = Self::get_nonce(key.2);
206
+                match secretbox::open(&bytes, &nonce, &key.0) {
207
+                    Ok(res) => {
208
+                        bytes.clear();
209
+                        bytes.put_slice(&res);
210
+                    }
211
+                    Err(()) => {
212
+                        return Some(Err(Error::new(ErrorKind::Other, "decryption error")));
213
+                    }
214
+                }
215
+            }
216
+        }
217
+        res
218
+    }
219
+
220
+    #[inline]
221
+    pub async fn next_timeout(&mut self, ms: u64) -> Option<Result<BytesMut, Error>> {
222
+        if let Ok(res) = super::timeout(ms, self.next()).await {
223
+            res
224
+        } else {
225
+            None
226
+        }
227
+    }
228
+
229
+    pub fn set_key(&mut self, key: Key) {
230
+        self.2 = Some((key, 0, 0));
231
+    }
232
+
233
+    fn get_nonce(seqnum: u64) -> Nonce {
234
+        let mut nonce = Nonce([0u8; secretbox::NONCEBYTES]);
235
+        nonce.0[..std::mem::size_of_val(&seqnum)].copy_from_slice(&seqnum.to_le_bytes());
236
+        nonce
237
+    }
238
+}
239
+
240
+const DEFAULT_BACKLOG: u32 = 128;
241
+
242
+#[allow(clippy::never_loop)]
243
+pub async fn new_listener<T: ToSocketAddrs>(addr: T, reuse: bool) -> ResultType<TcpListener> {
244
+    if !reuse {
245
+        Ok(TcpListener::bind(addr).await?)
246
+    } else {
247
+        for addr in lookup_host(&addr).await? {
248
+            let socket = new_socket(addr, true)?;
249
+            return Ok(socket.listen(DEFAULT_BACKLOG)?);
250
+        }
251
+        bail!("could not resolve to any address");
252
+    }
253
+}
254
+
255
+impl Unpin for DynTcpStream {}
256
+
257
+impl AsyncRead for DynTcpStream {
258
+    fn poll_read(
259
+        mut self: Pin<&mut Self>,
260
+        cx: &mut Context<'_>,
261
+        buf: &mut ReadBuf<'_>,
262
+    ) -> Poll<io::Result<()>> {
263
+        AsyncRead::poll_read(Pin::new(&mut self.0), cx, buf)
264
+    }
265
+}
266
+
267
+impl AsyncWrite for DynTcpStream {
268
+    fn poll_write(
269
+        mut self: Pin<&mut Self>,
270
+        cx: &mut Context<'_>,
271
+        buf: &[u8],
272
+    ) -> Poll<io::Result<usize>> {
273
+        AsyncWrite::poll_write(Pin::new(&mut self.0), cx, buf)
274
+    }
275
+
276
+    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
277
+        AsyncWrite::poll_flush(Pin::new(&mut self.0), cx)
278
+    }
279
+
280
+    fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
281
+        AsyncWrite::poll_shutdown(Pin::new(&mut self.0), cx)
282
+    }
283
+}
284
+
285
+impl<R: AsyncRead + AsyncWrite + Unpin> TcpStreamTrait for R {}

+ 165 - 0
libs/hbb_common/src/udp.rs

@@ -0,0 +1,165 @@
1
+use crate::{bail, ResultType};
2
+use anyhow::anyhow;
3
+use bytes::{Bytes, BytesMut};
4
+use futures::{SinkExt, StreamExt};
5
+use protobuf::Message;
6
+use socket2::{Domain, Socket, Type};
7
+use std::net::SocketAddr;
8
+use tokio::net::{ToSocketAddrs, UdpSocket};
9
+use tokio_socks::{udp::Socks5UdpFramed, IntoTargetAddr, TargetAddr, ToProxyAddrs};
10
+use tokio_util::{codec::BytesCodec, udp::UdpFramed};
11
+
12
+pub enum FramedSocket {
13
+    Direct(UdpFramed<BytesCodec>),
14
+    ProxySocks(Socks5UdpFramed),
15
+}
16
+
17
+fn new_socket(addr: SocketAddr, reuse: bool, buf_size: usize) -> Result<Socket, std::io::Error> {
18
+    let socket = match addr {
19
+        SocketAddr::V4(..) => Socket::new(Domain::ipv4(), Type::dgram(), None),
20
+        SocketAddr::V6(..) => Socket::new(Domain::ipv6(), Type::dgram(), None),
21
+    }?;
22
+    if reuse {
23
+        // windows has no reuse_port, but it's reuse_address
24
+        // almost equals to unix's reuse_port + reuse_address,
25
+        // though may introduce nondeterministic behavior
26
+        #[cfg(unix)]
27
+        socket.set_reuse_port(true)?;
28
+        socket.set_reuse_address(true)?;
29
+    }
30
+    if buf_size > 0 {
31
+        socket.set_recv_buffer_size(buf_size).ok();
32
+    }
33
+    log::info!(
34
+        "Receive buf size of udp {}: {:?}",
35
+        addr,
36
+        socket.recv_buffer_size()
37
+    );
38
+    socket.bind(&addr.into())?;
39
+    Ok(socket)
40
+}
41
+
42
+impl FramedSocket {
43
+    pub async fn new<T: ToSocketAddrs>(addr: T) -> ResultType<Self> {
44
+        let socket = UdpSocket::bind(addr).await?;
45
+        Ok(Self::Direct(UdpFramed::new(socket, BytesCodec::new())))
46
+    }
47
+
48
+    #[allow(clippy::never_loop)]
49
+    pub async fn new_reuse<T: std::net::ToSocketAddrs>(addr: T) -> ResultType<Self> {
50
+        for addr in addr.to_socket_addrs()? {
51
+            let socket = new_socket(addr, true, 0)?.into_udp_socket();
52
+            return Ok(Self::Direct(UdpFramed::new(
53
+                UdpSocket::from_std(socket)?,
54
+                BytesCodec::new(),
55
+            )));
56
+        }
57
+        bail!("could not resolve to any address");
58
+    }
59
+
60
+    pub async fn new_with_buf_size<T: std::net::ToSocketAddrs>(
61
+        addr: T,
62
+        buf_size: usize,
63
+    ) -> ResultType<Self> {
64
+        for addr in addr.to_socket_addrs()? {
65
+            return Ok(Self::Direct(UdpFramed::new(
66
+                UdpSocket::from_std(new_socket(addr, false, buf_size)?.into_udp_socket())?,
67
+                BytesCodec::new(),
68
+            )));
69
+        }
70
+        bail!("could not resolve to any address");
71
+    }
72
+
73
+    pub async fn new_proxy<'a, 't, P: ToProxyAddrs, T: ToSocketAddrs>(
74
+        proxy: P,
75
+        local: T,
76
+        username: &'a str,
77
+        password: &'a str,
78
+        ms_timeout: u64,
79
+    ) -> ResultType<Self> {
80
+        let framed = if username.trim().is_empty() {
81
+            super::timeout(ms_timeout, Socks5UdpFramed::connect(proxy, Some(local))).await??
82
+        } else {
83
+            super::timeout(
84
+                ms_timeout,
85
+                Socks5UdpFramed::connect_with_password(proxy, Some(local), username, password),
86
+            )
87
+            .await??
88
+        };
89
+        log::trace!(
90
+            "Socks5 udp connected, local addr: {:?}, target addr: {}",
91
+            framed.local_addr(),
92
+            framed.socks_addr()
93
+        );
94
+        Ok(Self::ProxySocks(framed))
95
+    }
96
+
97
+    #[inline]
98
+    pub async fn send(
99
+        &mut self,
100
+        msg: &impl Message,
101
+        addr: impl IntoTargetAddr<'_>,
102
+    ) -> ResultType<()> {
103
+        let addr = addr.into_target_addr()?.to_owned();
104
+        let send_data = Bytes::from(msg.write_to_bytes()?);
105
+        let _ = match self {
106
+            Self::Direct(f) => match addr {
107
+                TargetAddr::Ip(addr) => f.send((send_data, addr)).await?,
108
+                _ => {}
109
+            },
110
+            Self::ProxySocks(f) => f.send((send_data, addr)).await?,
111
+        };
112
+        Ok(())
113
+    }
114
+
115
+    // https://stackoverflow.com/a/68733302/1926020
116
+    #[inline]
117
+    pub async fn send_raw(
118
+        &mut self,
119
+        msg: &'static [u8],
120
+        addr: impl IntoTargetAddr<'static>,
121
+    ) -> ResultType<()> {
122
+        let addr = addr.into_target_addr()?.to_owned();
123
+
124
+        let _ = match self {
125
+            Self::Direct(f) => match addr {
126
+                TargetAddr::Ip(addr) => f.send((Bytes::from(msg), addr)).await?,
127
+                _ => {}
128
+            },
129
+            Self::ProxySocks(f) => f.send((Bytes::from(msg), addr)).await?,
130
+        };
131
+        Ok(())
132
+    }
133
+
134
+    #[inline]
135
+    pub async fn next(&mut self) -> Option<ResultType<(BytesMut, TargetAddr<'static>)>> {
136
+        match self {
137
+            Self::Direct(f) => match f.next().await {
138
+                Some(Ok((data, addr))) => {
139
+                    Some(Ok((data, addr.into_target_addr().ok()?.to_owned())))
140
+                }
141
+                Some(Err(e)) => Some(Err(anyhow!(e))),
142
+                None => None,
143
+            },
144
+            Self::ProxySocks(f) => match f.next().await {
145
+                Some(Ok((data, _))) => Some(Ok((data.data, data.dst_addr))),
146
+                Some(Err(e)) => Some(Err(anyhow!(e))),
147
+                None => None,
148
+            },
149
+        }
150
+    }
151
+
152
+    #[inline]
153
+    pub async fn next_timeout(
154
+        &mut self,
155
+        ms: u64,
156
+    ) -> Option<ResultType<(BytesMut, TargetAddr<'static>)>> {
157
+        if let Ok(res) =
158
+            tokio::time::timeout(std::time::Duration::from_millis(ms), self.next()).await
159
+        {
160
+            res
161
+        } else {
162
+            None
163
+        }
164
+    }
165
+}