// 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 SRC_UDP_WRAP_H_ #define SRC_UDP_WRAP_H_ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "handle_wrap.h" #include "req_wrap.h" #include "node_sockaddr.h" #include "uv.h" #include "v8.h" namespace node { class UDPWrapBase; // A listener that can be attached to an `UDPWrapBase` object and generally // manages its I/O activity. This is similar to `StreamListener`. class UDPListener { public: virtual ~UDPListener(); // Called right before data is received from the socket. Must return a // buffer suitable for reading data into, that is then passed to OnRecv. virtual uv_buf_t OnAlloc(size_t suggested_size) = 0; // Called right after data is received from the socket, and includes // information about the source address. If `nread` is negative, an error // has occurred, and it represents a libuv error code. virtual void OnRecv(ssize_t nread, const uv_buf_t& buf, const sockaddr* addr, unsigned int flags) = 0; // Called when an asynchronous request for writing data is created. // The `msg_size` value contains the total size of the data to be sent, // but may be ignored by the implementation of this Method. // The return value is later passed to OnSendDone. virtual ReqWrap* CreateSendWrap(size_t msg_size) = 0; // Called when an asynchronous request for writing data has finished. // If status is negative, an error has occurred, and it represents a libuv // error code. virtual void OnSendDone(ReqWrap* wrap, int status) = 0; // Optional callback that is called after the socket has been bound. virtual void OnAfterBind() {} inline UDPWrapBase* udp() const { return wrap_; } protected: UDPWrapBase* wrap_ = nullptr; friend class UDPWrapBase; }; class UDPWrapBase { public: // While UDPWrapBase itself does not extend from HandleWrap, classes // derived from it will (like UDPWrap) enum InternalFields { kUDPWrapBaseField = HandleWrap::kInternalFieldCount, kInternalFieldCount }; virtual ~UDPWrapBase(); // Start emitting OnAlloc() + OnRecv() events on the listener. virtual int RecvStart() = 0; // Stop emitting OnAlloc() + OnRecv() events on the listener. virtual int RecvStop() = 0; // Send a chunk of data over this socket. This may call CreateSendWrap() // on the listener if an async transmission is necessary. virtual ssize_t Send(uv_buf_t* bufs, size_t nbufs, const sockaddr* addr) = 0; virtual SocketAddress GetPeerName() = 0; virtual SocketAddress GetSockName() = 0; // Returns an AsyncWrap object with the same lifetime as this object. virtual AsyncWrap* GetAsyncWrap() = 0; void set_listener(UDPListener* listener); UDPListener* listener() const; static UDPWrapBase* FromObject(v8::Local obj); static void RecvStart(const v8::FunctionCallbackInfo& args); static void RecvStop(const v8::FunctionCallbackInfo& args); static void AddMethods(Environment* env, v8::Local t); private: UDPListener* listener_ = nullptr; }; class UDPWrap final : public HandleWrap, public UDPWrapBase, public UDPListener { public: enum SocketType { SOCKET }; static void Initialize(v8::Local target, v8::Local unused, v8::Local context, void* priv); static void GetFD(const v8::FunctionCallbackInfo& args); static void New(const v8::FunctionCallbackInfo& args); static void Open(const v8::FunctionCallbackInfo& args); static void Bind(const v8::FunctionCallbackInfo& args); static void Connect(const v8::FunctionCallbackInfo& args); static void Send(const v8::FunctionCallbackInfo& args); static void Bind6(const v8::FunctionCallbackInfo& args); static void Connect6(const v8::FunctionCallbackInfo& args); static void Send6(const v8::FunctionCallbackInfo& args); static void Disconnect(const v8::FunctionCallbackInfo& args); static void AddMembership(const v8::FunctionCallbackInfo& args); static void DropMembership(const v8::FunctionCallbackInfo& args); static void AddSourceSpecificMembership( const v8::FunctionCallbackInfo& args); static void DropSourceSpecificMembership( const v8::FunctionCallbackInfo& args); static void SetMulticastInterface( const v8::FunctionCallbackInfo& args); static void BufferSize(const v8::FunctionCallbackInfo& args); static void GetSendQueueSize(const v8::FunctionCallbackInfo& args); static void GetSendQueueCount( const v8::FunctionCallbackInfo& args); // UDPListener implementation uv_buf_t OnAlloc(size_t suggested_size) override; void OnRecv(ssize_t nread, const uv_buf_t& buf, const sockaddr* addr, unsigned int flags) override; ReqWrap* CreateSendWrap(size_t msg_size) override; void OnSendDone(ReqWrap* wrap, int status) override; // UDPWrapBase implementation int RecvStart() override; int RecvStop() override; ssize_t Send(uv_buf_t* bufs, size_t nbufs, const sockaddr* addr) override; SocketAddress GetPeerName() override; SocketAddress GetSockName() override; AsyncWrap* GetAsyncWrap() override; inline uv_udp_t* GetLibuvHandle() { return &handle_; } static v8::MaybeLocal Instantiate(Environment* env, AsyncWrap* parent, SocketType type); SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(UDPWrap) SET_SELF_SIZE(UDPWrap) private: typedef uv_udp_t HandleType; template friend void GetSockOrPeerName(const v8::FunctionCallbackInfo&); UDPWrap(Environment* env, v8::Local object); static void DoBind(const v8::FunctionCallbackInfo& args, int family); static void DoConnect(const v8::FunctionCallbackInfo& args, int family); static void DoSend(const v8::FunctionCallbackInfo& args, int family); static void SetMembership(const v8::FunctionCallbackInfo& args, uv_membership membership); static void SetSourceMembership( const v8::FunctionCallbackInfo& args, uv_membership membership); static void OnAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf); static void OnRecv(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned int flags); uv_udp_t handle_; bool current_send_has_callback_; v8::Local current_send_req_wrap_; }; int sockaddr_for_family(int address_family, const char* address, const unsigned short port, sockaddr_storage* addr); } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_UDP_WRAP_H_