diff options
author | Fedor Indutny <fedor.indutny@gmail.com> | 2012-05-16 23:04:24 +0700 |
---|---|---|
committer | Fedor Indutny <fedor.indutny@gmail.com> | 2012-06-01 20:52:13 +0400 |
commit | af98fc9d5f20a8c5dc0db95121f18355337762f1 (patch) | |
tree | 26348c986cec965b3f6c34edcd1d9a743aa4c106 /src | |
parent | 30a0e58d63a8fb48ee47472a52450539e0656df9 (diff) | |
download | node-af98fc9d5f20a8c5dc0db95121f18355337762f1.tar.gz |
child_process: new stdio API for .spawn() method
Diffstat (limited to 'src')
-rw-r--r-- | src/node.js | 5 | ||||
-rw-r--r-- | src/process_wrap.cc | 100 | ||||
-rw-r--r-- | src/tcp_wrap.cc | 12 | ||||
-rw-r--r-- | src/tcp_wrap.h | 2 | ||||
-rw-r--r-- | src/tty_wrap.cc | 184 | ||||
-rw-r--r-- | src/tty_wrap.h | 58 | ||||
-rw-r--r-- | src/udp_wrap.cc | 52 | ||||
-rw-r--r-- | src/udp_wrap.h | 60 |
8 files changed, 306 insertions, 167 deletions
diff --git a/src/node.js b/src/node.js index fd5c6760b..ba0786d6e 100644 --- a/src/node.js +++ b/src/node.js @@ -482,7 +482,8 @@ // If we were spawned with env NODE_CHANNEL_FD then load that up and // start parsing data from that stream. if (process.env.NODE_CHANNEL_FD) { - assert(parseInt(process.env.NODE_CHANNEL_FD) >= 0); + var fd = parseInt(process.env.NODE_CHANNEL_FD, 10); + assert(fd >= 0); // Make sure it's not accidentally inherited by child processes. delete process.env.NODE_CHANNEL_FD; @@ -494,7 +495,7 @@ // FIXME is this really necessary? process.binding('tcp_wrap'); - cp._forkChild(); + cp._forkChild(fd); assert(process.send); } } diff --git a/src/process_wrap.cc b/src/process_wrap.cc index ce2985356..101d89b3f 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -22,6 +22,10 @@ #include "node.h" #include "handle_wrap.h" #include "pipe_wrap.h" +#include "tty_wrap.h" +#include "tcp_wrap.h" +#include "udp_wrap.h" + #include <string.h> #include <stdlib.h> @@ -36,6 +40,7 @@ using v8::HandleScope; using v8::FunctionTemplate; using v8::String; using v8::Array; +using v8::Number; using v8::Function; using v8::TryCatch; using v8::Context; @@ -82,6 +87,56 @@ class ProcessWrap : public HandleWrap { ProcessWrap(Handle<Object> object) : HandleWrap(object, NULL) { } ~ProcessWrap() { } + static void ParseStdioOptions(Local<Object> js_options, + uv_process_options_t* options) { + Local<Array> stdios = js_options + ->Get(String::NewSymbol("stdio")).As<Array>(); + int len = stdios->Length(); + options->stdio = new uv_stdio_container_t[len]; + options->stdio_count = len; + + for (int i = 0; i < len; i++) { + Local<Object> stdio = stdios + ->Get(Number::New(static_cast<double>(i))).As<Object>(); + Local<Value> type = stdio->Get(String::NewSymbol("type")); + + if (type->Equals(String::NewSymbol("ignore"))) { + options->stdio[i].flags = UV_IGNORE; + } else if (type->Equals(String::NewSymbol("pipe"))) { + options->stdio[i].flags = UV_CREATE_PIPE; + options->stdio[i].data.stream = reinterpret_cast<uv_stream_t*>( + PipeWrap::Unwrap(stdio + ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle()); + } else if (type->Equals(String::NewSymbol("wrap"))) { + uv_stream_t* stream = NULL; + Local<Value> wrapType = stdio->Get(String::NewSymbol("wrapType")); + if (wrapType->Equals(String::NewSymbol("pipe"))) { + stream = reinterpret_cast<uv_stream_t*>(PipeWrap::Unwrap(stdio + ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle()); + } else if (wrapType->Equals(String::NewSymbol("tty"))) { + stream = reinterpret_cast<uv_stream_t*>(TTYWrap::Unwrap(stdio + ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle()); + } else if (wrapType->Equals(String::NewSymbol("tcp"))) { + stream = reinterpret_cast<uv_stream_t*>(TCPWrap::Unwrap(stdio + ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle()); + } else if (wrapType->Equals(String::NewSymbol("udp"))) { + stream = reinterpret_cast<uv_stream_t*>(UDPWrap::Unwrap(stdio + ->Get(String::NewSymbol("handle")).As<Object>())->UVHandle()); + } + assert(stream != NULL); + + options->stdio[i].flags = UV_INHERIT_STREAM; + options->stdio[i].data.stream = stream; + } else { + int fd = static_cast<int>( + stdio->Get(String::NewSymbol("fd"))->IntegerValue()); + + options->stdio[i].flags = UV_INHERIT_FD; + options->stdio[i].data.fd = fd; + } + } + } + static Handle<Value> Spawn(const Arguments& args) { HandleScope scope; @@ -169,47 +224,8 @@ class ProcessWrap : public HandleWrap { options.env[envc] = NULL; } - uv_stdio_container_t stdio[3]; - memset(stdio, 0, sizeof(stdio)); - - options.stdio = stdio; - options.stdio_count = 3; - options.stdio[0].flags = UV_IGNORE; - options.stdio[1].flags = UV_IGNORE; - options.stdio[2].flags = UV_IGNORE; - - // options.stdin_stream - Local<Value> stdin_stream_v = js_options->Get( - String::NewSymbol("stdinStream")); - if (!stdin_stream_v.IsEmpty() && stdin_stream_v->IsObject()) { - PipeWrap* stdin_wrap = PipeWrap::Unwrap(stdin_stream_v->ToObject()); - options.stdio[0].flags = static_cast<uv_stdio_flags>( - UV_CREATE_PIPE | UV_WRITABLE_PIPE); - options.stdio[0].data.stream = reinterpret_cast<uv_stream_t*>( - stdin_wrap->UVHandle()); - } - - // options.stdout_stream - Local<Value> stdout_stream_v = js_options->Get( - String::NewSymbol("stdoutStream")); - if (!stdout_stream_v.IsEmpty() && stdout_stream_v->IsObject()) { - PipeWrap* stdout_wrap = PipeWrap::Unwrap(stdout_stream_v->ToObject()); - options.stdio[1].flags = static_cast<uv_stdio_flags>( - UV_CREATE_PIPE | UV_READABLE_PIPE); - options.stdio[1].data.stream = reinterpret_cast<uv_stream_t*>( - stdout_wrap->UVHandle()); - } - - // options.stderr_stream - Local<Value> stderr_stream_v = js_options->Get( - String::NewSymbol("stderrStream")); - if (!stderr_stream_v.IsEmpty() && stderr_stream_v->IsObject()) { - PipeWrap* stderr_wrap = PipeWrap::Unwrap(stderr_stream_v->ToObject()); - options.stdio[2].flags = static_cast<uv_stdio_flags>( - UV_CREATE_PIPE | UV_READABLE_PIPE); - options.stdio[2].data.stream = reinterpret_cast<uv_stream_t*>( - stderr_wrap->UVHandle()); - } + // options.stdio + ParseStdioOptions(js_options, &options); // options.windows_verbatim_arguments if (js_options->Get(String::NewSymbol("windowsVerbatimArguments"))-> @@ -238,6 +254,8 @@ class ProcessWrap : public HandleWrap { delete [] options.env; } + delete[] options.stdio; + return scope.Close(Integer::New(r)); } diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 3fc8aa80c..5e6f1c2ec 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -128,6 +128,18 @@ void TCPWrap::Initialize(Handle<Object> target) { } +TCPWrap* TCPWrap::Unwrap(Local<Object> obj) { + assert(!obj.IsEmpty()); + assert(obj->InternalFieldCount() > 0); + return static_cast<TCPWrap*>(obj->GetPointerFromInternalField(0)); +} + + +uv_tcp_t* TCPWrap::UVHandle() { + return &handle_; +} + + Handle<Value> TCPWrap::New(const Arguments& args) { // This constructor should not be exposed to public javascript. // Therefore we assert that we are not trying to call this as a diff --git a/src/tcp_wrap.h b/src/tcp_wrap.h index 26e061f48..9b8cd2914 100644 --- a/src/tcp_wrap.h +++ b/src/tcp_wrap.h @@ -31,6 +31,8 @@ class TCPWrap : public StreamWrap { static TCPWrap* Unwrap(v8::Local<v8::Object> obj); static void Initialize(v8::Handle<v8::Object> target); + uv_tcp_t* UVHandle(); + private: TCPWrap(v8::Handle<v8::Object> object); ~TCPWrap(); diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index de43a4f23..f1a189c91 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -24,6 +24,7 @@ #include "req_wrap.h" #include "handle_wrap.h" #include "stream_wrap.h" +#include "tty_wrap.h" namespace node { @@ -42,128 +43,141 @@ using v8::Arguments; using v8::Integer; using v8::Undefined; -class TTYWrap : StreamWrap { - public: - static void Initialize(Handle<Object> target) { - StreamWrap::Initialize(target); - HandleScope scope; +void TTYWrap::Initialize(Handle<Object> target) { + StreamWrap::Initialize(target); - Local<FunctionTemplate> t = FunctionTemplate::New(New); - t->SetClassName(String::NewSymbol("TTY")); + HandleScope scope; - t->InstanceTemplate()->SetInternalFieldCount(1); + Local<FunctionTemplate> t = FunctionTemplate::New(New); + t->SetClassName(String::NewSymbol("TTY")); - NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close); - NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref); + t->InstanceTemplate()->SetInternalFieldCount(1); - NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart); - NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop); + NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close); + NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref); - NODE_SET_PROTOTYPE_METHOD(t, "writeBuffer", StreamWrap::WriteBuffer); - NODE_SET_PROTOTYPE_METHOD(t, "writeAsciiString", StreamWrap::WriteAsciiString); - NODE_SET_PROTOTYPE_METHOD(t, "writeUtf8String", StreamWrap::WriteUtf8String); - NODE_SET_PROTOTYPE_METHOD(t, "writeUcs2String", StreamWrap::WriteUcs2String); + NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart); + NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop); - NODE_SET_PROTOTYPE_METHOD(t, "getWindowSize", TTYWrap::GetWindowSize); - NODE_SET_PROTOTYPE_METHOD(t, "setRawMode", SetRawMode); + NODE_SET_PROTOTYPE_METHOD(t, "writeBuffer", StreamWrap::WriteBuffer); + NODE_SET_PROTOTYPE_METHOD(t, "writeAsciiString", StreamWrap::WriteAsciiString); + NODE_SET_PROTOTYPE_METHOD(t, "writeUtf8String", StreamWrap::WriteUtf8String); + NODE_SET_PROTOTYPE_METHOD(t, "writeUcs2String", StreamWrap::WriteUcs2String); - NODE_SET_METHOD(target, "isTTY", IsTTY); - NODE_SET_METHOD(target, "guessHandleType", GuessHandleType); + NODE_SET_PROTOTYPE_METHOD(t, "getWindowSize", TTYWrap::GetWindowSize); + NODE_SET_PROTOTYPE_METHOD(t, "setRawMode", SetRawMode); - target->Set(String::NewSymbol("TTY"), t->GetFunction()); - } + NODE_SET_METHOD(target, "isTTY", IsTTY); + NODE_SET_METHOD(target, "guessHandleType", GuessHandleType); - private: - static Handle<Value> GuessHandleType(const Arguments& args) { - HandleScope scope; - int fd = args[0]->Int32Value(); - assert(fd >= 0); + target->Set(String::NewSymbol("TTY"), t->GetFunction()); +} - uv_handle_type t = uv_guess_handle(fd); - switch (t) { - case UV_TTY: - return scope.Close(String::New("TTY")); +TTYWrap* TTYWrap::Unwrap(Local<Object> obj) { + assert(!obj.IsEmpty()); + assert(obj->InternalFieldCount() > 0); + return static_cast<TTYWrap*>(obj->GetPointerFromInternalField(0)); +} - case UV_NAMED_PIPE: - return scope.Close(String::New("PIPE")); - case UV_FILE: - return scope.Close(String::New("FILE")); +uv_tty_t* TTYWrap::UVHandle() { + return &handle_; +} - default: - assert(0); - return v8::Undefined(); - } - } - static Handle<Value> IsTTY(const Arguments& args) { - HandleScope scope; - int fd = args[0]->Int32Value(); - assert(fd >= 0); - return uv_guess_handle(fd) == UV_TTY ? v8::True() : v8::False(); - } +Handle<Value> TTYWrap::GuessHandleType(const Arguments& args) { + HandleScope scope; + int fd = args[0]->Int32Value(); + assert(fd >= 0); + + uv_handle_type t = uv_guess_handle(fd); - static Handle<Value> GetWindowSize(const Arguments& args) { - HandleScope scope; + switch (t) { + case UV_TTY: + return scope.Close(String::New("TTY")); - UNWRAP(TTYWrap) + case UV_NAMED_PIPE: + return scope.Close(String::New("PIPE")); - int width, height; - int r = uv_tty_get_winsize(&wrap->handle_, &width, &height); + case UV_FILE: + return scope.Close(String::New("FILE")); - if (r) { - SetErrno(uv_last_error(uv_default_loop())); + default: + assert(0); return v8::Undefined(); - } + } +} - Local<v8::Array> a = v8::Array::New(2); - a->Set(0, Integer::New(width)); - a->Set(1, Integer::New(height)); - return scope.Close(a); - } +Handle<Value> TTYWrap::IsTTY(const Arguments& args) { + HandleScope scope; + int fd = args[0]->Int32Value(); + assert(fd >= 0); + return uv_guess_handle(fd) == UV_TTY ? v8::True() : v8::False(); +} - static Handle<Value> SetRawMode(const Arguments& args) { - HandleScope scope; - UNWRAP(TTYWrap) +Handle<Value> TTYWrap::GetWindowSize(const Arguments& args) { + HandleScope scope; - int r = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue()); + UNWRAP(TTYWrap) - if (r) { - SetErrno(uv_last_error(uv_default_loop())); - } + int width, height; + int r = uv_tty_get_winsize(&wrap->handle_, &width, &height); - return scope.Close(Integer::New(r)); + if (r) { + SetErrno(uv_last_error(uv_default_loop())); + return v8::Undefined(); } - static Handle<Value> New(const Arguments& args) { - HandleScope scope; + Local<v8::Array> a = v8::Array::New(2); + a->Set(0, Integer::New(width)); + a->Set(1, Integer::New(height)); - // This constructor should not be exposed to public javascript. - // Therefore we assert that we are not trying to call this as a - // normal function. - assert(args.IsConstructCall()); + return scope.Close(a); +} - int fd = args[0]->Int32Value(); - assert(fd >= 0); - TTYWrap* wrap = new TTYWrap(args.This(), fd, args[1]->IsTrue()); - assert(wrap); - wrap->UpdateWriteQueueSize(); +Handle<Value> TTYWrap::SetRawMode(const Arguments& args) { + HandleScope scope; - return scope.Close(args.This()); - } + UNWRAP(TTYWrap) + + int r = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue()); - TTYWrap(Handle<Object> object, int fd, bool readable) - : StreamWrap(object, (uv_stream_t*)&handle_) { - uv_tty_init(uv_default_loop(), &handle_, fd, readable); + if (r) { + SetErrno(uv_last_error(uv_default_loop())); } - uv_tty_t handle_; -}; + return scope.Close(Integer::New(r)); +} + + +Handle<Value> TTYWrap::New(const Arguments& args) { + HandleScope scope; + + // This constructor should not be exposed to public javascript. + // Therefore we assert that we are not trying to call this as a + // normal function. + assert(args.IsConstructCall()); + + int fd = args[0]->Int32Value(); + assert(fd >= 0); + + TTYWrap* wrap = new TTYWrap(args.This(), fd, args[1]->IsTrue()); + assert(wrap); + wrap->UpdateWriteQueueSize(); + + return scope.Close(args.This()); +} + + +TTYWrap::TTYWrap(Handle<Object> object, int fd, bool readable) + : StreamWrap(object, (uv_stream_t*)&handle_) { + uv_tty_init(uv_default_loop(), &handle_, fd, readable); +} } // namespace node diff --git a/src/tty_wrap.h b/src/tty_wrap.h new file mode 100644 index 000000000..4a3341a66 --- /dev/null +++ b/src/tty_wrap.h @@ -0,0 +1,58 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef TTY_WRAP_H_ +#define TTY_WRAP_H_ + +#include "handle_wrap.h" +#include "stream_wrap.h" + +namespace node { + +using v8::Object; +using v8::Handle; +using v8::Local; +using v8::Value; +using v8::Arguments; + + +class TTYWrap : StreamWrap { + public: + static void Initialize(Handle<Object> target); + static TTYWrap* Unwrap(Local<Object> obj); + + uv_tty_t* UVHandle(); + + private: + TTYWrap(Handle<Object> object, int fd, bool readable); + + static Handle<Value> GuessHandleType(const Arguments& args); + static Handle<Value> IsTTY(const Arguments& args); + static Handle<Value> GetWindowSize(const Arguments& args); + static Handle<Value> SetRawMode(const Arguments& args); + static Handle<Value> New(const Arguments& args); + + uv_tty_t handle_; +}; + +} // namespace node + +#endif // TTY_WRAP_H_ diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 39ab75021..b0f8bad1f 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -24,6 +24,7 @@ #include "slab_allocator.h" #include "req_wrap.h" #include "handle_wrap.h" +#include "udp_wrap.h" #include <stdlib.h> @@ -60,45 +61,6 @@ static Persistent<String> onmessage_sym; static SlabAllocator slab_allocator(SLAB_SIZE); -class UDPWrap: public HandleWrap { -public: - static void Initialize(Handle<Object> target); - static Handle<Value> New(const Arguments& args); - static Handle<Value> Bind(const Arguments& args); - static Handle<Value> Send(const Arguments& args); - static Handle<Value> Bind6(const Arguments& args); - static Handle<Value> Send6(const Arguments& args); - static Handle<Value> RecvStart(const Arguments& args); - static Handle<Value> RecvStop(const Arguments& args); - static Handle<Value> GetSockName(const Arguments& args); - static Handle<Value> AddMembership(const Arguments& args); - static Handle<Value> DropMembership(const Arguments& args); - static Handle<Value> SetMulticastTTL(const Arguments& args); - static Handle<Value> SetMulticastLoopback(const Arguments& args); - static Handle<Value> SetBroadcast(const Arguments& args); - static Handle<Value> SetTTL(const Arguments& args); - -private: - UDPWrap(Handle<Object> object); - virtual ~UDPWrap(); - - static Handle<Value> DoBind(const Arguments& args, int family); - static Handle<Value> DoSend(const Arguments& args, int family); - static Handle<Value> SetMembership(const Arguments& args, - uv_membership membership); - - static uv_buf_t OnAlloc(uv_handle_t* handle, size_t suggested_size); - static void OnSend(uv_udp_send_t* req, int status); - static void OnRecv(uv_udp_t* handle, - ssize_t nread, - uv_buf_t buf, - struct sockaddr* addr, - unsigned flags); - - uv_udp_t handle_; -}; - - UDPWrap::UDPWrap(Handle<Object> object): HandleWrap(object, (uv_handle_t*)&handle_) { int r = uv_udp_init(uv_default_loop(), &handle_); @@ -426,6 +388,18 @@ void UDPWrap::OnRecv(uv_udp_t* handle, } +UDPWrap* UDPWrap::Unwrap(Local<Object> obj) { + assert(!obj.IsEmpty()); + assert(obj->InternalFieldCount() > 0); + return static_cast<UDPWrap*>(obj->GetPointerFromInternalField(0)); +} + + +uv_udp_t* UDPWrap::UVHandle() { + return &handle_; +} + + } // namespace node NODE_MODULE(node_udp_wrap, node::UDPWrap::Initialize) diff --git a/src/udp_wrap.h b/src/udp_wrap.h new file mode 100644 index 000000000..9ca2eaea9 --- /dev/null +++ b/src/udp_wrap.h @@ -0,0 +1,60 @@ +#ifndef UDP_WRAP_H_ +#define UDP_WRAP_H_ + +#include "node.h" +#include "req_wrap.h" +#include "handle_wrap.h" + +namespace node { + +using v8::Object; +using v8::Handle; +using v8::Local; +using v8::Value; +using v8::String; +using v8::Arguments; + +class UDPWrap: public HandleWrap { + public: + static void Initialize(Handle<Object> target); + static Handle<Value> New(const Arguments& args); + static Handle<Value> Bind(const Arguments& args); + static Handle<Value> Send(const Arguments& args); + static Handle<Value> Bind6(const Arguments& args); + static Handle<Value> Send6(const Arguments& args); + static Handle<Value> RecvStart(const Arguments& args); + static Handle<Value> RecvStop(const Arguments& args); + static Handle<Value> GetSockName(const Arguments& args); + static Handle<Value> AddMembership(const Arguments& args); + static Handle<Value> DropMembership(const Arguments& args); + static Handle<Value> SetMulticastTTL(const Arguments& args); + static Handle<Value> SetMulticastLoopback(const Arguments& args); + static Handle<Value> SetBroadcast(const Arguments& args); + static Handle<Value> SetTTL(const Arguments& args); + static UDPWrap* Unwrap(Local<Object> obj); + + uv_udp_t* UVHandle(); + + private: + UDPWrap(Handle<Object> object); + virtual ~UDPWrap(); + + static Handle<Value> DoBind(const Arguments& args, int family); + static Handle<Value> DoSend(const Arguments& args, int family); + static Handle<Value> SetMembership(const Arguments& args, + uv_membership membership); + + static uv_buf_t OnAlloc(uv_handle_t* handle, size_t suggested_size); + static void OnSend(uv_udp_send_t* req, int status); + static void OnRecv(uv_udp_t* handle, + ssize_t nread, + uv_buf_t buf, + struct sockaddr* addr, + unsigned flags); + + uv_udp_t handle_; +}; + +} // namespace node + +#endif // UDP_WRAP_H_ |