Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Bind uv_listen()

  • Loading branch information...
commit effeeb5cf20479be2064bbc115cfce286d0efebf 1 parent 0627591
ry ry authored

Showing 1 changed file with 97 additions and 7 deletions. Show diff stats Hide diff stats

  1. +97 7 src/tcp_wrap.cc
104 src/tcp_wrap.cc
@@ -49,20 +49,29 @@ using v8::Context;
49 49 using v8::Arguments;
50 50 using v8::Integer;
51 51
  52 +static Persistent<Function> constructor;
  53 +static Persistent<String> deck;
52 54
53 55 class TCPWrap {
54 56 public:
  57 +
55 58 static void Initialize(Handle<Object> target) {
56 59 HandleScope scope;
57 60
58   - Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
59   - constructor->InstanceTemplate()->SetInternalFieldCount(1);
60   - constructor->SetClassName(String::NewSymbol("TCP"));
  61 + deck = Persistent<String>::New(String::New("deck"));
  62 +
  63 + Local<FunctionTemplate> t = FunctionTemplate::New(New);
  64 + t->SetClassName(String::NewSymbol("TCP"));
  65 +
  66 + t->InstanceTemplate()->SetInternalFieldCount(1);
61 67
62   - NODE_SET_PROTOTYPE_METHOD(constructor, "bind", Bind);
63   - NODE_SET_PROTOTYPE_METHOD(constructor, "close", Close);
  68 + NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
  69 + NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
  70 + NODE_SET_PROTOTYPE_METHOD(t, "close", Close);
64 71
65   - target->Set(String::NewSymbol("TCP"), constructor->GetFunction());
  72 + constructor = Persistent<Function>::New(t->GetFunction());
  73 +
  74 + target->Set(String::NewSymbol("TCP"), constructor);
66 75 }
67 76
68 77 private:
@@ -73,13 +82,14 @@ class TCPWrap {
73 82 assert(args.IsConstructCall());
74 83
75 84 HandleScope scope;
76   - TCPWrap *wrap = new TCPWrap(args.This());
  85 + TCPWrap* wrap = new TCPWrap(args.This());
77 86 assert(wrap);
78 87
79 88 return scope.Close(args.This());
80 89 }
81 90
82 91 TCPWrap(Handle<Object> object) {
  92 + on_deck_ = false;
83 93 int r = uv_tcp_init(&handle_);
84 94 handle_.data = this;
85 95 assert(r == 0); // How do we proxy this error up to javascript?
@@ -91,6 +101,17 @@ class TCPWrap {
91 101 }
92 102
93 103 ~TCPWrap() {
  104 + // If there was a client on deck then close it.
  105 + if (on_deck_) {
  106 + HandleScope scope;
  107 + Local<Value> client_v = object_->GetHiddenValue(deck);
  108 + assert(!client_v.IsEmpty());
  109 + Local<Object> client_obj = client_v->ToObject();
  110 + TCPWrap* client_wrap =
  111 + static_cast<TCPWrap*>(client_obj->GetPointerFromInternalField(0));
  112 + uv_close((uv_handle_t*) &client_wrap->handle_, OnClose);
  113 + }
  114 +
94 115 assert(!object_.IsEmpty());
95 116 object_->SetPointerInInternalField(0, NULL);
96 117 object_.Dispose();
@@ -119,6 +140,74 @@ class TCPWrap {
119 140 return scope.Close(Integer::New(r));
120 141 }
121 142
  143 + static Handle<Value> Listen(const Arguments& args) {
  144 + HandleScope scope;
  145 +
  146 + UNWRAP
  147 +
  148 + int backlog = args[0]->Int32Value();
  149 +
  150 + int r = uv_listen(&wrap->handle_, backlog, OnConnection);
  151 +
  152 + // Error starting the tcp.
  153 + if (r) SetErrno(uv_last_error().code);
  154 +
  155 + return scope.Close(Integer::New(r));
  156 + }
  157 +
  158 + static void OnConnection(uv_tcp_t* handle, int status) {
  159 + HandleScope scope;
  160 +
  161 + TCPWrap* wrap = static_cast<TCPWrap*>(handle->data);
  162 +
  163 + assert(&wrap->handle_ == handle);
  164 +
  165 + if (status != 0) {
  166 + // TODO Handle server error (call onerror?)
  167 + assert(0);
  168 + uv_close((uv_handle_t*) handle, OnClose);
  169 + return;
  170 + }
  171 +
  172 + // Check the deck to see if we already have a client object that can
  173 + // be used. (The 'deck' terminology comes from baseball.)
  174 + Local<Object> client_obj;
  175 +
  176 + if (wrap->on_deck_) {
  177 + Local<Value> client_v = wrap->object_->GetHiddenValue(deck);
  178 + assert(!client_v.IsEmpty());
  179 + client_obj = client_v->ToObject();
  180 + } else {
  181 + client_obj = constructor->NewInstance();
  182 + }
  183 +
  184 + // Unwrap the client.
  185 + assert(client_obj->InternalFieldCount() > 0);
  186 + TCPWrap* client_wrap =
  187 + static_cast<TCPWrap*>(client_obj->GetPointerFromInternalField(0));
  188 +
  189 + int r = uv_accept(handle, &client_wrap->handle_);
  190 +
  191 + if (r) {
  192 + uv_err_t err = uv_last_error();
  193 + if (err.code == UV_EAGAIN) {
  194 + // We need to retry in a bit. Put the client_obj on deck.
  195 + wrap->on_deck_ = true;
  196 + wrap->object_->SetHiddenValue(deck, client_obj);
  197 + } else {
  198 + // TODO handle real error!
  199 + assert(0);
  200 + }
  201 + return;
  202 + }
  203 +
  204 + // Successful accept. Clear the deck and pass the client_obj to the user.
  205 + wrap->on_deck_ = false;
  206 + wrap->object_->DeleteHiddenValue(deck);
  207 + Local<Value> argv[1] = { client_obj };
  208 + MakeCallback(wrap->object_, "onconnection", 1, argv);
  209 + }
  210 +
122 211 // TODO: share me?
123 212 static Handle<Value> Close(const Arguments& args) {
124 213 HandleScope scope;
@@ -134,6 +223,7 @@ class TCPWrap {
134 223
135 224 uv_tcp_t handle_;
136 225 Persistent<Object> object_;
  226 + bool on_deck_;
137 227 };
138 228
139 229

0 comments on commit effeeb5

Please sign in to comment.
Something went wrong with that request. Please try again.