-
-
Notifications
You must be signed in to change notification settings - Fork 34.5k
net: add setTOS and getTOS to Socket #61503
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
base: main
Are you sure you want to change the base?
Changes from all commits
eb53d09
9e7a183
14b3fb0
f339cd0
d32f212
71ecbd7
c0407b2
8439cfd
fe329db
778580a
efb5f88
8dce839
1fb4683
1084571
0a90f1c
603445d
f22a74c
b272fda
c6f1153
fe14b34
041c30a
7516aff
83d875c
c03162b
b884430
c39d13e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,10 @@ | |
| // USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
|
|
||
| #include "tcp_wrap.h" | ||
|
|
||
| #ifdef _WIN32 | ||
| #include <winsock2.h> | ||
| #include <ws2tcpip.h> | ||
| #endif | ||
| #include "connect_wrap.h" | ||
| #include "connection_wrap.h" | ||
| #include "env-inl.h" | ||
|
|
@@ -32,9 +35,15 @@ | |
| #include "stream_base-inl.h" | ||
| #include "stream_wrap.h" | ||
| #include "util-inl.h" | ||
|
|
||
| #include <cerrno> | ||
| #include <cstdlib> | ||
amyssnippet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| #ifndef _WIN32 | ||
| #include <netinet/in.h> | ||
| #include <netinet/ip.h> | ||
| #include <netinet/ip6.h> | ||
| #include <sys/socket.h> | ||
| #endif | ||
|
|
||
| namespace node { | ||
|
|
||
|
|
@@ -106,6 +115,8 @@ void TCPWrap::Initialize(Local<Object> target, | |
| GetSockOrPeerName<TCPWrap, uv_tcp_getpeername>); | ||
| SetProtoMethod(isolate, t, "setNoDelay", SetNoDelay); | ||
| SetProtoMethod(isolate, t, "setKeepAlive", SetKeepAlive); | ||
| SetProtoMethod(isolate, t, "setTOS", SetTOS); | ||
| SetProtoMethod(isolate, t, "getTOS", GetTOS); | ||
| SetProtoMethod(isolate, t, "reset", Reset); | ||
|
|
||
| #ifdef _WIN32 | ||
|
|
@@ -145,6 +156,8 @@ void TCPWrap::RegisterExternalReferences(ExternalReferenceRegistry* registry) { | |
| registry->Register(GetSockOrPeerName<TCPWrap, uv_tcp_getpeername>); | ||
| registry->Register(SetNoDelay); | ||
| registry->Register(SetKeepAlive); | ||
| registry->Register(SetTOS); | ||
| registry->Register(GetTOS); | ||
| registry->Register(Reset); | ||
| #ifdef _WIN32 | ||
| registry->Register(SetSimultaneousAccepts); | ||
|
|
@@ -208,6 +221,135 @@ void TCPWrap::SetKeepAlive(const FunctionCallbackInfo<Value>& args) { | |
| args.GetReturnValue().Set(err); | ||
| } | ||
|
|
||
| void TCPWrap::SetTOS(const FunctionCallbackInfo<Value>& args) { | ||
| TCPWrap* wrap; | ||
| ASSIGN_OR_RETURN_UNWRAP( | ||
| &wrap, args.This(), args.GetReturnValue().Set(UV_EBADF)); | ||
| Environment* env = wrap->env(); | ||
|
|
||
| int tos = 0; | ||
| if (!args[0]->Int32Value(env->context()).To(&tos)) return; | ||
|
|
||
| uv_os_fd_t fd; | ||
| int err = uv_fileno(reinterpret_cast<uv_handle_t*>(&wrap->handle_), &fd); | ||
| if (err != 0) { | ||
| args.GetReturnValue().Set(err); | ||
| return; | ||
| } | ||
|
|
||
| // 1. Detect the socket family (IPv4 vs IPv6) | ||
| sockaddr_storage storage; | ||
| int addrlen = sizeof(storage); | ||
| int sock_err = uv_tcp_getsockname(&wrap->handle_, | ||
| reinterpret_cast<sockaddr*>(&storage), | ||
| &addrlen); | ||
|
|
||
| // If we can't determine the family (e.g. closed socket), fail gracefully. | ||
| if (sock_err != 0) { | ||
| args.GetReturnValue().Set(sock_err); | ||
| return; | ||
| } | ||
|
|
||
| // 2. Select the correct protocol level and option name | ||
| int level; | ||
| int option; | ||
|
|
||
| if (storage.ss_family == AF_INET) { | ||
| level = IPPROTO_IP; | ||
| option = IP_TOS; | ||
| } else if (storage.ss_family == AF_INET6) { | ||
| level = IPPROTO_IPV6; | ||
| option = IPV6_TCLASS; | ||
| } else { | ||
| // Unsupported socket family (e.g. AF_UNIX) | ||
| args.GetReturnValue().Set(UV_EINVAL); | ||
| return; | ||
| } | ||
|
|
||
| // 3. Perform the system call (Platform specific casting) | ||
| #ifdef _WIN32 | ||
| if (setsockopt(reinterpret_cast<SOCKET>(fd), | ||
| level, | ||
| option, | ||
| reinterpret_cast<const char*>(&tos), | ||
| static_cast<int>(sizeof(tos))) == 0) { | ||
| args.GetReturnValue().Set(0); | ||
| } else { | ||
| args.GetReturnValue().Set(uv_translate_sys_error(WSAGetLastError())); | ||
| } | ||
| #else | ||
| if (setsockopt(fd, level, option, &tos, sizeof(tos)) == 0) { | ||
| args.GetReturnValue().Set(0); | ||
| } else { | ||
| args.GetReturnValue().Set(uv_translate_sys_error(errno)); | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| void TCPWrap::GetTOS(const FunctionCallbackInfo<Value>& args) { | ||
| TCPWrap* wrap; | ||
| ASSIGN_OR_RETURN_UNWRAP( | ||
| &wrap, args.This(), args.GetReturnValue().Set(UV_EBADF)); | ||
|
|
||
| uv_os_fd_t fd; | ||
| int err = uv_fileno(reinterpret_cast<uv_handle_t*>(&wrap->handle_), &fd); | ||
| if (err != 0) { | ||
| args.GetReturnValue().Set(err); | ||
| return; | ||
| } | ||
|
|
||
| // Detect socket family explicitly | ||
| sockaddr_storage storage; | ||
| int addrlen = sizeof(storage); | ||
| int sock_err = uv_tcp_getsockname(&wrap->handle_, | ||
| reinterpret_cast<sockaddr*>(&storage), | ||
| &addrlen); | ||
|
|
||
| int level; | ||
| int option; | ||
|
|
||
| // Select the correct constant based on family | ||
| if (sock_err == 0) { | ||
| if (storage.ss_family == AF_INET) { | ||
| level = IPPROTO_IP; | ||
| option = IP_TOS; | ||
| } else if (storage.ss_family == AF_INET6) { | ||
| level = IPPROTO_IPV6; | ||
| option = IPV6_TCLASS; | ||
| } else { | ||
| // Unknown or unsupported family | ||
| args.GetReturnValue().Set(UV_EINVAL); | ||
| return; | ||
| } | ||
| } else { | ||
| // If we can't determine the family, we can't safely get the TOS | ||
| args.GetReturnValue().Set(sock_err); | ||
| return; | ||
| } | ||
|
|
||
| int tos = 0; | ||
|
|
||
| // Perform the system call with platform-specific casting | ||
| #ifdef _WIN32 | ||
| int len = sizeof(tos); | ||
| if (getsockopt(reinterpret_cast<SOCKET>(fd), | ||
| level, | ||
| option, | ||
| reinterpret_cast<char*>(&tos), | ||
| &len) == 0) { | ||
| args.GetReturnValue().Set(tos); | ||
| } else { | ||
| args.GetReturnValue().Set(uv_translate_sys_error(WSAGetLastError())); | ||
| } | ||
| #else | ||
| socklen_t len = sizeof(tos); | ||
| if (getsockopt(fd, level, option, &tos, &len) == 0) { | ||
| args.GetReturnValue().Set(tos); | ||
| } else { | ||
| args.GetReturnValue().Set(uv_translate_sys_error(errno)); | ||
| } | ||
| #endif | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't say this needs to block this PR, but upstreaming these additions to https://github.com/libuv/libuv might be a good follow-up change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. even i was thinking the same, if internal members of nodejs will work and do the changes over there to libuv, then additions will be fast, rather than i do. |
||
| } | ||
|
|
||
| #ifdef _WIN32 | ||
| void TCPWrap::SetSimultaneousAccepts(const FunctionCallbackInfo<Value>& args) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our API names in Node.js are generally more verbose than the corresponding OS APIs – would there be anything speaking against calling these
socket.getTypeOfService()andsocket.setTypeOfService()?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that makes sense and i agree to that, i will update to use full names