Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HttpServer RawSockets are in the wrong Zone #15367

Closed
nex3 opened this issue Nov 28, 2013 · 13 comments
Closed

HttpServer RawSockets are in the wrong Zone #15367

nex3 opened this issue Nov 28, 2013 · 13 comments
Assignees
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io

Comments

@nex3
Copy link
Member

nex3 commented Nov 28, 2013

The RawSockets created by an HttpServer are incorrectly created in the root Zone, rather than the zone of the HttpServer itself. This means that if the server was created in an error zone, any errors produced by the RawSocket (e.g. "connection reset by peer") will be top-leveled.

This issue is blocking several of my stack chain CLs, so I'd be very pleased if it could be addressed soon.

To see the issue, patch in the following code:

diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 1480f1f..8de1a3e 100644

--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -814,6 +814,7 @­@ class _RawSocket extends Stream<RawSocketEvent>
   }
 
   _RawSocket(this._socket) {

  • print("raw socket zone: ${Zone.current}");
         _controller = new StreamController(sync: true,
             onListen: _onSubscriptionStateChange,
             onCancel: _onSubscriptionStateChange,
    @@ -859,6 +860,7 @­@ class _RawSocket extends Stream<RawSocketEvent>
                                                 {Function onError,
                                                  void onDone(),
                                                  bool cancelOnError}) {
  • print("subscription zone: ${Zone.current}");
         return _controller.stream.listen(
             onData,
             onError: onError,

Then run this program:

    import 'dart:async';
    import 'dart:io';

    main() {
      runZoned(() {
        HttpServer.bind('localhost', 0).then((server) {
          server.listen(null);
          new HttpClient().get('localhost', server.port, '/');
        });
      });
    }

It will print "raw socket zone: Instance of '_RootZone@0x2900bd4a'".

@andersjohnsen
Copy link

Set owner to @skabet.
Added Started label.

@andersjohnsen
Copy link

While it's correct that the RawSocket is created in the ROOT zone, the RawSocket is moved to the right Zone when handed through the RawServerSocket.

Now, the question is if there are any 'loose' errors from the RawSocket, that is not reported through the Http system. If that is the case, then that's a separate issue that we have to handle (would be very critical indeed).

Here is two tests I'm adding, showing that the behavior is as expected:

void testHttpServerZone() {
  asyncStart();
  Expect.equals(Zone.ROOT, Zone.current);
  runZoned(() {
    Expect.notEquals(Zone.ROOT, Zone.current);
    HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
      Expect.notEquals(Zone.ROOT, Zone.current);
      server.listen((request) {
        Expect.notEquals(Zone.ROOT, Zone.current);
        request.response.close();
        server.close();
      });
      new HttpClient().get("127.0.0.1", server.port, '/')
        .then((request) => request.close())
        .then((response) => response.drain())
        .then((_) => asyncEnd());
    });
  });
}

=====================

void testSocketZone() {
  asyncStart();
  Expect.equals(Zone.ROOT, Zone.current);
  runZoned(() {
    Expect.notEquals(Zone.ROOT, Zone.current);
    RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
      Expect.notEquals(Zone.ROOT, Zone.current);
      server.listen((socket) {
        Expect.notEquals(Zone.ROOT, Zone.current);
        socket.close();
        server.close();
      });
      RawSocket.connect("127.0.0.1", server.port).then((socket) {
        socket.listen((event) {
          if (event == RawSocketEvent.READ_CLOSED) {
            socket.close();
            asyncEnd();
          }
        });
      });
    });
  });
}


Added Invalid label.

@nex3
Copy link
Member Author

nex3 commented Nov 28, 2013

I was certainly seeing "connection reset by peer" errors being top-leveled,
and I did enough tracing that I'm confident this was because the errors
were crossing zones in RawSocket. I won't have access to my work computer
for the next few days due to the holiday here, but I think one of two
things is going on:

* Either [RawSocket._controller] is being created in the root zone and
calling [addError] on it is causing the failure;

* or [addError] is being called from the root zone and the error is then
being passed through to the custom zone.

I wasn't able to find a concise reproduction, due to the difficulty of
provoking a "connection reset by peer" error in the first place, but maybe
you'll have more luck.

@sgjesse
Copy link
Contributor

sgjesse commented Nov 28, 2013

We really need a way to mock sockets to easily test all these cases.

@floitschG
Copy link
Contributor

These two tests only test for the positive case, but not the negative one.

Errors are not allowed to traverse zone-boundaries if the zones contain error-handlers.

@anders: please add tests for failing IO operations, too.

I'm reopening in case this is the issue.


Added Triaged label.

@DartBot
Copy link

DartBot commented Nov 28, 2013

This comment was originally written by Samuel....@gmail.com


I am running following simple server on AWS:

import 'dart:io';
import 'dart:async';
import 'package:http_server/http_server.dart';

main() {
  runZoned(() {
  HttpServer.bind("0.0.0.0", 8081).then((server) {
      server.listen((request) {

          //new Future.delayed(new Duration(seconds: 2)).then((_){
              var s=[];
              for(num i=0;i<100000;i++){
                 s.add('ahoj');
              }
              request.response.write(s.join(''));
              request.response.close();
          //});
       });
              
  });
  }, onError: (e) => print(e));
}

Then I can break it on the remote client by running following code:

wget http://my-remote-aws.com:8080 & sleep 0.1 && pkill -9 wget

It will completely break the server with following error message:

Uncaught Error: SocketException: OS Error: Broken pipe, errno = 32, address = 0.0.0.0, port = 8081
Unhandled exception:
SocketException: OS Error: Broken pipe, errno = 32, address = 0.0.0.0, port = 8081
#­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:677)
#­1 _asyncRunCallback (dart:async/schedule_microtask.dart:18)
#­2 _asyncRunCallback (dart:async/schedule_microtask.dart:21)
#­3 _createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:11)
#­4 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:151)
#­5 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:159)
#­6 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:159)
#­7 _Timer._createTimerHandler.<anonymous closure> (timer_impl.dart:166)
#­8 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:93)

This only happen when using runZoned.

@andersjohnsen
Copy link

Landed fix in r30775.


Added Fixed label.

@DartBot
Copy link

DartBot commented Dec 1, 2013

This comment was originally written by Samuel....@gmail.com


Not fixed in 30779.

Still getting the same error:

SocketException: OS Error: Broken pipe, errno = 32, address = 0.0.0.0, port = 8081
#­0 _rootHandleUncaughtError.<anonymous closure>.<anonymous closure> (dart:async/zone.dart:677)
#­1 _asyncRunCallback (dart:async/schedule_microtask.dart:18)
#­2 _asyncRunCallback (dart:async/schedule_microtask.dart:21)
#­3 _createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:11)
#­4 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:153)
#­5 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:161)
#­6 _Timer._createTimerHandler._handleTimeout (timer_impl.dart:161)
#­7 _Timer._createTimerHandler.<anonymous closure> (timer_impl.dart:168)
#­8 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:95)

@andersjohnsen
Copy link

30779 does not include 30775. Try to build from bleeding edge.

@DartBot
Copy link

DartBot commented Dec 1, 2013

This comment was originally written by Samuel.Hapa...@gmail.com


Thank you for your explanation. Could you please navigate me to a guide where to find the bleeding edge and how to build it? (Or if there are some bleeding edge builds, just to download them?)

Also, I am a bit confused about the revision numbers. I thought, that higher revision number means superset of lower revision number.

Could you please give me some link to manual, wiki, or whatever that could help me to get more oriented in the Dart development?

Thank you very much!

@andersjohnsen
Copy link

Bleeding edge is where all development is happening. It's located here: https://code.google.com/p/dart/source/browse/#svn%2Fbranches%2Fbleeding_edge%2Fdart

Now, when we do a release, a merge is performed from bleeding edge to the given release branch. An example is r30779 (click link to see commit info about merge). A merge will always have a higher commit number than any of the commits merged.

To check out bleeding edge and building it, see:

https://code.google.com/p/dart/wiki/GettingTheSource
https://code.google.com/p/dart/wiki/Building

That should be sufficient to get you started.

Cheers,

  • Anders

@floitschG
Copy link
Contributor

If you don't want to build yourself, you can also download the precompiled bleeding-edge versions:
http://gsdview.appspot.com/dart-archive/channels/be

@kevmoo
Copy link
Member

kevmoo commented May 14, 2014

Removed Area-IO label.
Added Area-Library, library-io labels.

@nex3 nex3 added Type-Defect area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io labels May 14, 2014
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io
Projects
None yet
Development

No branches or pull requests

6 participants