Skip to content

Commit 4d3c740

Browse files
authored
Merge pull request #13 from Goddchen/fix/hanging
fix: fix hanging (introduce RawSocket.readSync(...) helper)
2 parents ce1cb66 + fb88c66 commit 4d3c740

File tree

7 files changed

+136
-226
lines changed

7 files changed

+136
-226
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,7 @@
2828
- Add CopyRect encoding support
2929
- Add SetEncodings message support
3030
- Add SetPixelFormat message support
31+
32+
## 0.4.1
33+
34+
- Fix [issue #9](https://github.com/Goddchen/dart-rfb/issues/9) (hanging after some time)

lib/src/client/remote_frame_buffer_client.dart

Lines changed: 47 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:dart_rfb/src/client/remote_frame_buffer_client_update.dart';
1111
import 'package:dart_rfb/src/constants.dart';
1212
import 'package:dart_rfb/src/extensions/byte_data_extensions.dart';
1313
import 'package:dart_rfb/src/extensions/int_extensions.dart';
14+
import 'package:dart_rfb/src/extensions/raw_socket_extensions.dart';
1415
import 'package:dart_rfb/src/protocol/client_init_message.dart';
1516
import 'package:dart_rfb/src/protocol/encoding_type.dart';
1617
import 'package:dart_rfb/src/protocol/frame_buffer_update_message.dart';
@@ -156,31 +157,19 @@ class RemoteFrameBufferClient {
156157
);
157158
_readLoopRunning = true;
158159
while (_readLoopRunning) {
159-
while (socket.available() < 1) {
160-
await Future<void>.delayed(Constants.socketReadWaitDuration);
161-
}
162-
final int messageType = optionOf(socket.read(1))
163-
.map(
164-
(final Uint8List bytes) =>
165-
ByteData.sublistView(bytes).getUint8(0),
166-
)
167-
.getOrElse(
168-
() => throw Exception(
169-
'Error reading incoming message type',
170-
),
171-
);
160+
final int messageType = (await socket
161+
.readSync(
162+
length: 1,
163+
readWaitDuration:
164+
some(Constants.socketReadWaitDuration),
165+
)
166+
.run())
167+
.getUint8(0);
172168
logger.log(Level.INFO, '< messageType: $messageType');
173169
switch (messageType) {
174170
case 0:
175-
while (socket.available() < 1) {
176-
await Future<void>.delayed(
177-
Constants.socketReadWaitDuration,
178-
);
179-
}
180171
// read and ignore padding
181-
optionOf(socket.read(1)).getOrElse(
182-
() => throw Exception('Error reading padding'),
183-
);
172+
await socket.readSync(length: 1).run();
184173
(await RemoteFrameBufferFrameBufferUpdateMessage
185174
.readFromSocket(config: config, socket: socket)
186175
.run())
@@ -219,54 +208,17 @@ class RemoteFrameBufferClient {
219208
);
220209
break;
221210
case 1: // SetColorMapEntries
222-
while (socket.available() < 5) {
223-
await Future<void>.delayed(
224-
Constants.socketReadWaitDuration,
225-
);
226-
}
227-
final int numberOfColors = optionOf(socket.read(5))
228-
.map(
229-
(final Uint8List bytes) =>
230-
ByteData.sublistView(bytes).getUint16(3),
231-
)
232-
.getOrElse(
233-
() =>
234-
throw Exception('Error reading number of colors'),
235-
);
236-
while (socket.available() < numberOfColors * 6) {
237-
await Future<void>.delayed(
238-
Constants.socketReadWaitDuration,
239-
);
240-
}
241-
optionOf(socket.read(numberOfColors * 6)).getOrElse(
242-
() => throw Exception('Error reading colors'),
243-
);
211+
final int numberOfColors =
212+
(await socket.readSync(length: 5).run()).getUint16(3);
213+
socket.readSync(length: numberOfColors * 6);
244214
break;
245215
case 2: // Bell
246216
// no data, just ignore for now
247217
break;
248218
case 3: // ServerCutText
249-
while (socket.available() < 7) {
250-
await Future<void>.delayed(
251-
Constants.socketReadWaitDuration,
252-
);
253-
}
254-
final int length = optionOf(socket.read(7))
255-
.map(
256-
(final Uint8List bytes) =>
257-
ByteData.sublistView(bytes).getUint32(3),
258-
)
259-
.getOrElse(
260-
() => throw Exception('Error reading length'),
261-
);
262-
while (socket.available() < length) {
263-
await Future<void>.delayed(
264-
Constants.socketReadWaitDuration,
265-
);
266-
}
267-
optionOf(socket.read(length)).getOrElse(
268-
() => throw Exception('Error reading content'),
269-
);
219+
final int length =
220+
(await socket.readSync(length: 7).run()).getUint32(3);
221+
socket.readSync(length: length);
270222
break;
271223
default:
272224
logger.log(
@@ -293,14 +245,7 @@ class RemoteFrameBufferClient {
293245
() => TaskEither<Object, void>.of(null),
294246
(final String password) => TaskEither<Object, void>.tryCatch(
295247
() async {
296-
while (socket.available() < 16) {
297-
await Future<void>.delayed(Constants.socketReadWaitDuration);
298-
}
299-
final ByteData challenge = ByteData.sublistView(
300-
optionOf(socket.read(16)).getOrElse(
301-
() => throw Exception('Error reading security challenge'),
302-
),
303-
);
248+
final ByteData challenge = await socket.readSync(length: 16).run();
304249
logger.info('< Security challenge');
305250
final ByteData encodedAndTruncatedPassword = ByteData.sublistView(
306251
Uint8List.fromList(ascii.encode(password).take(8).toList()),
@@ -356,24 +301,15 @@ class RemoteFrameBufferClient {
356301
}) =>
357302
TaskEither<Object, void>.tryCatch(
358303
() async {
359-
while (socket.available() <
360-
RemoteFrameBufferProtocolVersionHandshakeMessage.length) {
361-
await Future<void>.delayed(Constants.socketReadWaitDuration);
362-
}
363304
final RemoteFrameBufferProtocolVersionHandshakeMessage
364305
protocolVersionHandshakeMessage =
365306
RemoteFrameBufferProtocolVersionHandshakeMessage.fromBytes(
366-
bytes: ByteData.sublistView(
367-
optionOf(
368-
socket.read(
369-
RemoteFrameBufferProtocolVersionHandshakeMessage.length,
370-
),
371-
).getOrElse(
372-
() => throw Exception(
373-
'Error reading protocol version handshake message',
374-
),
375-
),
376-
),
307+
bytes: await socket
308+
.readSync(
309+
length:
310+
RemoteFrameBufferProtocolVersionHandshakeMessage.length,
311+
)
312+
.run(),
377313
);
378314
logger.log(Level.INFO, '< $protocolVersionHandshakeMessage');
379315
if (protocolVersionHandshakeMessage.version
@@ -395,55 +331,37 @@ class RemoteFrameBufferClient {
395331
final TaskEither<Object, void> taskEitherWithList =
396332
TaskEither<Object, void>.tryCatch(
397333
() async {
398-
while (socket.available() < 1) {
399-
await Future<void>.delayed(Constants.socketReadWaitDuration);
400-
}
401-
final int numberOfSecurityTypes = optionOf(socket.read(1)).getOrElse(
402-
() => throw Exception('Error reading number of security types'),
403-
)[0];
334+
final int numberOfSecurityTypes =
335+
(await socket.readSync(length: 1).run()).getUint8(0);
404336
logger.log(
405337
Level.INFO,
406338
'< numberOfSecurityTypes=$numberOfSecurityTypes',
407339
);
408340
if (numberOfSecurityTypes == 0) {
409341
// Error, next 4 bytes is reason-length, then reason-string
410-
while (socket.available() < 4) {
411-
await Future<void>.delayed(
412-
Constants.socketReadWaitDuration,
413-
);
414-
}
415-
final int reasonLength = ByteData.sublistView(
416-
optionOf(socket.read(4)).getOrElse(
417-
() => throw Exception('Error getting reason length'),
418-
),
419-
).getUint32(0);
420-
while (socket.available() < reasonLength) {
421-
await Future<void>.delayed(
422-
Constants.socketReadWaitDuration,
423-
);
424-
}
425-
final String reason = optionOf(socket.read(reasonLength))
426-
.map((final Uint8List bytes) => ascii.decode(bytes))
427-
.getOrElse(() => throw Exception('Error reading reason'));
342+
final int reasonLength =
343+
(await socket.readSync(length: 4).run()).getUint32(0);
344+
final String reason = ascii.decode(
345+
(await socket.readSync(length: reasonLength).run())
346+
.buffer
347+
.asUint8List(),
348+
);
428349
throw Exception(
429350
'Error reading security handshake message: $reason',
430351
);
431352
} else {
432-
while (socket.available() < numberOfSecurityTypes) {
433-
await Future<void>.delayed(
434-
Constants.socketReadWaitDuration,
435-
);
436-
}
437353
final RemoteFrameBufferSecurityHandshakeMessage
438354
securityResultHandshakeMessage =
439355
RemoteFrameBufferSecurityHandshakeMessage.fromBytes(
440356
bytes: ByteData.sublistView(
441357
Uint8List.fromList(
442358
<int>[
443359
numberOfSecurityTypes,
444-
...optionOf(socket.read(numberOfSecurityTypes)).getOrElse(
445-
() => throw Exception('Error reading security types'),
446-
)
360+
...(await socket
361+
.readSync(length: numberOfSecurityTypes)
362+
.run())
363+
.buffer
364+
.asUint8List(),
447365
],
448366
),
449367
),
@@ -472,16 +390,9 @@ class RemoteFrameBufferClient {
472390
final TaskEither<Object, void> taskEitherWithoutList =
473391
TaskEither<Object, void>.tryCatch(
474392
() async {
475-
while (socket.available() < 4) {
476-
await Future<void>.delayed(Constants.socketReadWaitDuration);
477-
}
478393
final RemoteFrameBufferSecurityType securityType =
479394
RemoteFrameBufferSecurityType.fromBytes(
480-
bytes: ByteData.sublistView(
481-
optionOf(socket.read(4)).getOrElse(
482-
() => throw Exception('Error reading security type'),
483-
),
484-
),
395+
bytes: await socket.readSync(length: 4).run(),
485396
);
486397
logger.info('< $securityType');
487398

@@ -520,39 +431,20 @@ class RemoteFrameBufferClient {
520431
final TaskEither<Object, void> taskEitherWithErrorMessage =
521432
TaskEither<Object, void>.tryCatch(
522433
() async {
523-
while (socket.available() < 4) {
524-
await Future<void>.delayed(Constants.socketReadWaitDuration);
525-
}
526434
final RemoteFrameBufferSecurityResultHandshakeMessage
527435
securityResultHandshakeMessage =
528436
RemoteFrameBufferSecurityResultHandshakeMessage.fromBytes(
529-
bytes: ByteData.sublistView(
530-
optionOf(socket.read(4)).getOrElse(
531-
() => throw Exception(
532-
'Error reading security result message',
533-
),
534-
),
535-
),
437+
bytes: await socket.readSync(length: 4).run(),
536438
);
537439
logger.log(Level.INFO, '< $securityResultHandshakeMessage');
538440
if (!securityResultHandshakeMessage.success) {
539-
while (socket.available() < 4) {
540-
await Future<void>.delayed(Constants.socketReadWaitDuration);
541-
}
542-
final int reasonLength = optionOf(socket.read(4))
543-
.map(
544-
(final Uint8List bytes) =>
545-
ByteData.sublistView(bytes).getUint32(0),
546-
)
547-
.getOrElse(
548-
() => throw Exception('Error reading reason length'),
549-
);
550-
while (socket.available() < reasonLength) {
551-
await Future<void>.delayed(Constants.socketReadWaitDuration);
552-
}
553-
final String reason = optionOf(socket.read(reasonLength))
554-
.map((final Uint8List bytes) => ascii.decode(bytes))
555-
.getOrElse(() => throw Exception('Error reading reason'));
441+
final int reasonLength =
442+
(await socket.readSync(length: 4).run()).getUint32(0);
443+
final String reason = ascii.decode(
444+
(await socket.readSync(length: reasonLength).run())
445+
.buffer
446+
.asUint8List(),
447+
);
556448
throw Exception('Error reading security result message: $reason');
557449
}
558450
},
@@ -561,19 +453,10 @@ class RemoteFrameBufferClient {
561453
final TaskEither<Object, void> taskEitherWithoutErrorMessage =
562454
TaskEither<Object, void>.tryCatch(
563455
() async {
564-
while (socket.available() < 4) {
565-
await Future<void>.delayed(Constants.socketReadWaitDuration);
566-
}
567456
final RemoteFrameBufferSecurityResultHandshakeMessage
568457
securityResultHandshakeMessage =
569458
RemoteFrameBufferSecurityResultHandshakeMessage.fromBytes(
570-
bytes: ByteData.sublistView(
571-
optionOf(socket.read(4)).getOrElse(
572-
() => throw Exception(
573-
'Error reading security result message',
574-
),
575-
),
576-
),
459+
bytes: await socket.readSync(length: 4).run(),
577460
);
578461
logger.log(Level.INFO, '< $securityResultHandshakeMessage');
579462
if (!securityResultHandshakeMessage.success) {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import 'dart:io';
2+
import 'dart:math';
3+
import 'dart:typed_data';
4+
5+
import 'package:fpdart/fpdart.dart';
6+
7+
extension RawSocketExtensions on RawSocket {
8+
Task<ByteData> readSync({
9+
required final int length,
10+
final Option<Duration> readWaitDuration = const None<Duration>(),
11+
}) =>
12+
Task<ByteData>(
13+
() async {
14+
final BytesBuilder bytesBuilder = BytesBuilder();
15+
while (bytesBuilder.length < length) {
16+
optionOf(
17+
read(
18+
min(length, length - bytesBuilder.length),
19+
),
20+
).match(
21+
() {},
22+
bytesBuilder.add,
23+
);
24+
if (bytesBuilder.length < length) {
25+
await readWaitDuration.match(
26+
() async {},
27+
(final Duration duration) async =>
28+
await Future<void>.delayed(duration),
29+
);
30+
}
31+
}
32+
return ByteData.sublistView(bytesBuilder.toBytes());
33+
},
34+
);
35+
}

0 commit comments

Comments
 (0)