Skip to content

Commit fb90f11

Browse files
a-sivacommit-bot@chromium.org
authored andcommitted
[dart:io] - Fix incorrect setting of socket options for UNIX-DOMAIN sockets
- setting of UNIX-DOMAIN socket options was not throwing the correct error - listen in HTTPServer was trying to set TCP_NODELAY for UNIX-DOMAIN sockets Fixes : #45977 #45978 #45975 TEST=new test cases added Change-Id: Ie0341f26b1ba0f9423c08a8de968053a2af1c730 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/199640 Commit-Queue: Siva Annamalai <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]>
1 parent 245705e commit fb90f11

File tree

7 files changed

+472
-6
lines changed

7 files changed

+472
-6
lines changed

pkg/compiler/test/analyses/api_allowed.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,12 @@
115115
"Dynamic access of 'connectionInfo'.": 4,
116116
"Dynamic access of 'localPort'.": 1,
117117
"Dynamic access of 'remoteAddress'.": 2,
118-
"Dynamic access of 'address'.": 3,
118+
"Dynamic access of 'address'.": 4,
119119
"Dynamic access of 'remotePort'.": 2,
120120
"Dynamic access of 'message'.": 3,
121121
"Dynamic invocation of 'call'.": 1,
122122
"Dynamic invocation of 'destroy'.": 2,
123+
"Dynamic access of 'type'.": 1,
123124
"Dynamic invocation of 'setOption'.": 1,
124125
"Dynamic access of 'host'.": 2,
125126
"Dynamic access of 'port'.": 2,

runtime/bin/socket.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,9 +1077,8 @@ void FUNCTION_NAME(Socket_SetOption)(Dart_NativeArguments args) {
10771077
Socket* socket =
10781078
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
10791079
int64_t option = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
1080-
int64_t protocol = DartUtils::GetInt64ValueCheckRange(
1081-
Dart_GetNativeArgument(args, 2), SocketAddress::TYPE_IPV4,
1082-
SocketAddress::TYPE_IPV6);
1080+
intptr_t protocol = static_cast<intptr_t>(
1081+
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2)));
10831082
switch (option) {
10841083
case 0: // TCP_NODELAY.
10851084
result = SocketBase::SetNoDelay(

sdk/lib/_http/http_impl.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2442,7 +2442,9 @@ class _ConnectionTarget {
24422442
}
24432443
return socketFuture.then((socket) {
24442444
_connecting--;
2445-
socket.setOption(SocketOption.tcpNoDelay, true);
2445+
if (socket.address.type != InternetAddressType.unix) {
2446+
socket.setOption(SocketOption.tcpNoDelay, true);
2447+
}
24462448
var connection =
24472449
new _HttpClientConnection(key, socket, client, false, context);
24482450
if (isSecure && !proxy.isDirect) {
@@ -3177,7 +3179,9 @@ class _HttpServer extends Stream<HttpRequest>
31773179
StreamSubscription<HttpRequest> listen(void onData(HttpRequest event)?,
31783180
{Function? onError, void onDone()?, bool? cancelOnError}) {
31793181
_serverSocket.listen((Socket socket) {
3180-
socket.setOption(SocketOption.tcpNoDelay, true);
3182+
if (socket.address.type != InternetAddressType.unix) {
3183+
socket.setOption(SocketOption.tcpNoDelay, true);
3184+
}
31813185
// Accept the client connection.
31823186
_HttpConnection connection = new _HttpConnection(socket, this);
31833187
_idleConnections.add(connection);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
import 'dart:io';
7+
import 'dart:convert';
8+
9+
import 'package:expect/expect.dart';
10+
11+
Future testHttpServer(String name) async {
12+
var sockname = "$name/sock";
13+
var address = InternetAddress('$sockname', type: InternetAddressType.unix);
14+
var httpServer = await HttpServer.bind(address, 0);
15+
var sub;
16+
sub = httpServer.listen((HttpRequest request) {
17+
request.response.write('Hello, world!');
18+
request.response.close();
19+
sub.cancel();
20+
}, onDone: () {
21+
httpServer.close();
22+
});
23+
24+
var option = "--unix-socket $sockname";
25+
var result =
26+
await Process.run("curl", ["--unix-socket", "$sockname", "localhost"]);
27+
Expect.isTrue(result.stdout.toString().contains('Hello, world!'));
28+
}
29+
30+
main() async {
31+
var tmpDir = Directory.systemTemp.createTempSync('http_on_unix_socket_test');
32+
try {
33+
await testHttpServer(tmpDir.path);
34+
} catch (e) {
35+
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
36+
Expect.fail("Unexpected exception $e is thrown");
37+
} else {
38+
Expect.isTrue(e is SocketException);
39+
Expect.isTrue(e.toString().contains('not available'));
40+
}
41+
} finally {
42+
tmpDir.deleteSync(recursive: true);
43+
}
44+
}

tests/standalone/io/unix_socket_test.dart

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,187 @@ Future testExistingFile(String name) async {
180180
Expect.fail("bind should fail with existing file");
181181
}
182182

183+
Future testSetSockOpt(String name) async {
184+
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
185+
var server = await ServerSocket.bind(address, 0, shared: false);
186+
187+
var sub;
188+
sub = server.listen((s) {
189+
sub.cancel();
190+
server.close();
191+
});
192+
193+
var socket = await Socket.connect(address, server.port);
194+
socket.write(" socket content");
195+
196+
// Get some socket options.
197+
for (int i = 0; i < 5; i++) {
198+
try {
199+
RawSocketOption option =
200+
RawSocketOption.fromBool(RawSocketOption.levelTcp, i, false);
201+
var result = socket.getRawOption(option);
202+
} catch (e) {
203+
Expect.isTrue(e.toString().contains('Operation not supported'));
204+
}
205+
}
206+
207+
for (int i = 0; i < 5; i++) {
208+
try {
209+
RawSocketOption option =
210+
RawSocketOption.fromBool(RawSocketOption.levelUdp, i, false);
211+
var result = socket.getRawOption(option);
212+
} catch (e) {
213+
Expect.isTrue(e.toString().contains('Operation not supported'));
214+
}
215+
}
216+
217+
for (int i = 0; i < 5; i++) {
218+
try {
219+
RawSocketOption option =
220+
RawSocketOption.fromBool(RawSocketOption.levelIPv4, i, false);
221+
var result = socket.getRawOption(option);
222+
} catch (e) {
223+
Expect.isTrue(e.toString().contains('Operation not supported'));
224+
}
225+
}
226+
227+
for (int i = 0; i < 5; i++) {
228+
try {
229+
RawSocketOption option =
230+
RawSocketOption.fromBool(RawSocketOption.levelIPv6, i, false);
231+
var result = socket.getRawOption(option);
232+
} catch (e) {
233+
Expect.isTrue(e.toString().contains('Operation not supported'));
234+
}
235+
}
236+
237+
for (int i = 0; i < 5; i++) {
238+
try {
239+
RawSocketOption option =
240+
RawSocketOption.fromBool(RawSocketOption.levelSocket, i, false);
241+
var result = socket.getRawOption(option);
242+
} catch (e) {
243+
Expect.isTrue(e.toString().contains('Protocol not available'));
244+
}
245+
}
246+
247+
for (int i = 0; i < 5; i++) {
248+
try {
249+
RawSocketOption option = RawSocketOption.fromBool(
250+
RawSocketOption.IPv4MulticastInterface, i, false);
251+
var result = socket.getRawOption(option);
252+
} catch (e) {
253+
Expect.isTrue(e.toString().contains('Operation not supported'));
254+
}
255+
}
256+
257+
for (int i = 0; i < 5; i++) {
258+
try {
259+
RawSocketOption option = RawSocketOption.fromBool(
260+
RawSocketOption.IPv6MulticastInterface, i, false);
261+
var result = socket.getRawOption(option);
262+
} catch (e) {
263+
Expect.isTrue(e.toString().contains('Operation not supported'));
264+
}
265+
}
266+
267+
// Set some socket options
268+
try {
269+
socket.setOption(SocketOption.tcpNoDelay, true);
270+
} catch (e) {
271+
Expect.isTrue(e.toString().contains('Operation not supported'));
272+
}
273+
274+
for (int i = 0; i < 5; i++) {
275+
try {
276+
RawSocketOption option =
277+
RawSocketOption.fromBool(RawSocketOption.levelTcp, i, false);
278+
var result = socket.setRawOption(option);
279+
} catch (e) {
280+
Expect.isTrue(e.toString().contains('Operation not supported'));
281+
}
282+
}
283+
284+
for (int i = 0; i < 5; i++) {
285+
try {
286+
RawSocketOption option =
287+
RawSocketOption.fromBool(RawSocketOption.levelUdp, i, false);
288+
var result = socket.setRawOption(option);
289+
} catch (e) {
290+
Expect.isTrue(e.toString().contains('Operation not supported'));
291+
}
292+
}
293+
294+
for (int i = 0; i < 5; i++) {
295+
try {
296+
RawSocketOption option =
297+
RawSocketOption.fromBool(RawSocketOption.levelIPv4, i, false);
298+
var result = socket.setRawOption(option);
299+
} catch (e) {
300+
Expect.isTrue(e.toString().contains('Operation not supported'));
301+
}
302+
}
303+
304+
for (int i = 0; i < 5; i++) {
305+
try {
306+
RawSocketOption option =
307+
RawSocketOption.fromBool(RawSocketOption.levelIPv6, i, false);
308+
var result = socket.setRawOption(option);
309+
} catch (e) {
310+
Expect.isTrue(e.toString().contains('Operation not supported'));
311+
}
312+
}
313+
314+
for (int i = 0; i < 5; i++) {
315+
try {
316+
RawSocketOption option =
317+
RawSocketOption.fromBool(RawSocketOption.levelSocket, i, false);
318+
var result = socket.setRawOption(option);
319+
} catch (e) {
320+
Expect.isTrue(e.toString().contains('Protocol not available'));
321+
}
322+
}
323+
324+
for (int i = 0; i < 5; i++) {
325+
try {
326+
RawSocketOption option = RawSocketOption.fromBool(
327+
RawSocketOption.IPv4MulticastInterface, i, false);
328+
var result = socket.setRawOption(option);
329+
} catch (e) {
330+
Expect.isTrue(e.toString().contains('Operation not supported'));
331+
}
332+
}
333+
334+
for (int i = 0; i < 5; i++) {
335+
try {
336+
RawSocketOption option = RawSocketOption.fromBool(
337+
RawSocketOption.IPv6MulticastInterface, i, false);
338+
var result = socket.setRawOption(option);
339+
} catch (e) {
340+
Expect.isTrue(e.toString().contains('Operation not supported'));
341+
}
342+
}
343+
344+
socket.destroy();
345+
await server.close();
346+
}
347+
348+
Future testHttpServer(String name) async {
349+
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
350+
var httpServer = await HttpServer.bind(address, 0);
351+
352+
var sub;
353+
sub = httpServer.listen((s) {
354+
sub.cancel();
355+
httpServer.close();
356+
});
357+
358+
var socket = await Socket.connect(address, httpServer.port);
359+
360+
socket.destroy();
361+
await httpServer.close();
362+
}
363+
183364
// Create socket in temp directory
184365
Future withTempDir(String prefix, Future<void> test(Directory dir)) async {
185366
var tempDir = Directory.systemTemp.createTempSync(prefix);
@@ -211,6 +392,12 @@ void main() async {
211392
await withTempDir('unix_socket_test', (Directory dir) async {
212393
await testExistingFile('${dir.path}');
213394
});
395+
await withTempDir('unix_socket_test', (Directory dir) async {
396+
await testSetSockOpt('${dir.path}');
397+
});
398+
await withTempDir('unix_socket_test', (Directory dir) async {
399+
await testHttpServer('${dir.path}');
400+
});
214401
} catch (e) {
215402
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
216403
Expect.fail("Unexpected exception $e is thrown");
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:async';
6+
import 'dart:io';
7+
import 'dart:convert';
8+
9+
import 'package:expect/expect.dart';
10+
11+
Future testHttpServer(String name) async {
12+
var sockname = "$name/sock";
13+
var address = InternetAddress('$sockname', type: InternetAddressType.unix);
14+
var httpServer = await HttpServer.bind(address, 0);
15+
var sub;
16+
sub = httpServer.listen((HttpRequest request) {
17+
request.response.write('Hello, world!');
18+
request.response.close();
19+
sub.cancel();
20+
}, onDone: () {
21+
httpServer.close();
22+
});
23+
24+
var option = "--unix-socket $sockname";
25+
var result =
26+
await Process.run("curl", ["--unix-socket", "$sockname", "localhost"]);
27+
Expect.isTrue(result.stdout.toString().contains('Hello, world!'));
28+
}
29+
30+
main() async {
31+
var tmpDir = Directory.systemTemp.createTempSync('http_on_unix_socket_test');
32+
try {
33+
await testHttpServer(tmpDir.path);
34+
} catch (e) {
35+
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
36+
Expect.fail("Unexpected exception $e is thrown");
37+
} else {
38+
Expect.isTrue(e is SocketException);
39+
Expect.isTrue(e.toString().contains('not available'));
40+
}
41+
} finally {
42+
tmpDir.deleteSync(recursive: true);
43+
}
44+
}

0 commit comments

Comments
 (0)