mirror of
https://github.com/oven-sh/bun
synced 2026-02-13 12:29:07 +00:00
feat(node/net): add SocketAddress (in C++)
This commit is contained in:
@@ -1,63 +1,255 @@
|
||||
#include "JSSocketAddress.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
#include "BunClientData.h"
|
||||
#include "JavaScriptCore/JSCast.h"
|
||||
#include "JavaScriptCore/JSObjectInlines.h"
|
||||
#include "JavaScriptCore/ObjectConstructor.h"
|
||||
#include "JavaScriptCore/JSCast.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
#include "JavaScriptCore/JSCell.h"
|
||||
#include "ErrorCode.h"
|
||||
|
||||
#include "JSSocketAddress.h"
|
||||
#include "JSSocketAddressConstructor.h"
|
||||
#include "JSSocketAddressPrototype.h"
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
namespace Bun {
|
||||
namespace JSSocketAddress {
|
||||
|
||||
// Using a structure with inlined offsets should be more lightweight than a class.
|
||||
Structure* createStructure(VM& vm, JSGlobalObject* globalObject)
|
||||
static constexpr PropertyOffset addressOffset = 0;
|
||||
static constexpr PropertyOffset addressFamilyOffset = 1;
|
||||
static constexpr PropertyOffset portOffset = 2;
|
||||
static constexpr PropertyOffset flowLabelOffset = 3;
|
||||
|
||||
inline JSC::JSString* JSSocketAddress::address() const
|
||||
{
|
||||
JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype(
|
||||
auto value = this->getDirect(addressOffset);
|
||||
JSC::JSString* str = jsCast<JSC::JSString*>(value);
|
||||
return str;
|
||||
// return value.getString(globalObject());
|
||||
}
|
||||
|
||||
inline uint8_t JSSocketAddress::addressFamily() const
|
||||
{
|
||||
uint32_t af = this->getDirect(addressFamilyOffset).asUInt32();
|
||||
ASSERT(af == AF_INET6 || af == AF_INET);
|
||||
return af;
|
||||
}
|
||||
|
||||
inline in_port_t JSSocketAddress::port() const
|
||||
{
|
||||
auto port = this->getDirect(portOffset).asUInt32();
|
||||
ASSERT(port <= 0xFFFF);
|
||||
return port;
|
||||
}
|
||||
|
||||
inline uint32_t JSSocketAddress::flowLabel() const
|
||||
{
|
||||
return this->getDirect(flowLabelOffset).asUInt32();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
JSSocketAddress* JSSocketAddress::create(JSC::VM& vm,
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
JSC::Structure* structure,
|
||||
JSC::JSString* address,
|
||||
in_port_t port,
|
||||
bool isIPv6)
|
||||
{
|
||||
return create(vm, globalObject, structure, address, port, isIPv6 ? AF_INET6 : AF_INET, 0);
|
||||
}
|
||||
|
||||
JSSocketAddress* JSSocketAddress::create(JSC::VM& vm,
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
JSC::Structure* structure,
|
||||
JSC::JSString* address,
|
||||
in_port_t port,
|
||||
uint8_t addressFamily, // AF_INET | AF_INET6
|
||||
uint32_t flowLabel)
|
||||
{
|
||||
static const NeverDestroyed<String> IPv4 = MAKE_STATIC_STRING_IMPL("IPv4");
|
||||
static const NeverDestroyed<String> IPv6 = MAKE_STATIC_STRING_IMPL("IPv6");
|
||||
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
address_t addr;
|
||||
|
||||
const char* address_bytes = address->value(globalObject)->ascii().data();
|
||||
switch (inet_pton(addressFamily, address_bytes, &addr)) {
|
||||
case 1: // ok
|
||||
break;
|
||||
case 0: // invalid address
|
||||
// node throws ERR_INVALID_ADDRESS
|
||||
Bun::throwError(globalObject, scope, ErrorCode::ERR_INVALID_IP_ADDRESS, "Invalid address"_s);
|
||||
return nullptr;
|
||||
case -1: // syserr
|
||||
// TODO: how to handle system errors?
|
||||
Bun::throwError(globalObject, scope, ErrorCode::ERR_INVALID_IP_ADDRESS, "Invalid address"_s);
|
||||
return nullptr;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
auto* af_str = jsString(vm, addressFamily == AF_INET6 ? IPv6 : IPv4);
|
||||
|
||||
JSSocketAddress* ptr = new (NotNull, JSC::allocateCell<JSSocketAddress>(vm)) JSSocketAddress(vm, structure);
|
||||
ptr->m_address = addr;
|
||||
ptr->finishCreation(vm);
|
||||
|
||||
ptr->putDirectOffset(vm, flowLabelOffset, jsNumber(flowLabel));
|
||||
ptr->putDirectOffset(vm, addressOffset, address);
|
||||
ptr->putDirectOffset(vm, addressFamilyOffset, af_str);
|
||||
ptr->putDirectOffset(vm, portOffset, jsNumber(port));
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void JSSocketAddress::destroy(JSC::JSCell* cell)
|
||||
{
|
||||
auto* thisObject = jsCast<JSSocketAddress*>(cell);
|
||||
thisObject->~JSSocketAddress();
|
||||
}
|
||||
|
||||
JSC::GCClient::IsoSubspace* JSSocketAddress::subspaceForImpl(JSC::VM& vm)
|
||||
{
|
||||
// return WebCore::subspaceForImpl<JSSocketAddress, WebCore::UseCustomHeapCellType::No>(
|
||||
// vm,
|
||||
// [](auto& spaces) { return spaces.m_clientSubspaceForJSSocketAddress.get(); },
|
||||
// [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSSocketAddress = std::forward<decltype(space)>(space); },
|
||||
// [](auto& spaces) { return spaces.m_subspaceForJSSocketAddress.get(); },
|
||||
// [](auto& spaces, auto&& space) { spaces.m_subspaceForJSSocketAddress
|
||||
// = std::forward<decltype(space)>(space); });
|
||||
return &vm.plainObjectSpace();
|
||||
}
|
||||
|
||||
JSC::JSObject* JSSocketAddress::createPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
|
||||
{
|
||||
auto* structure = JSSocketAddressPrototype::createStructure(vm, globalObject, globalObject->objectPrototype());
|
||||
structure->setMayBePrototype(true);
|
||||
return JSSocketAddressPrototype::create(vm, globalObject, structure);
|
||||
}
|
||||
|
||||
JSC::Structure* JSSocketAddress::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||
{
|
||||
auto* structure = JSC::Structure::create(vm,
|
||||
globalObject,
|
||||
globalObject->objectPrototype(),
|
||||
3);
|
||||
prototype,
|
||||
JSC::TypeInfo(JSC::ObjectType, StructureFlags),
|
||||
info(),
|
||||
NonArray,
|
||||
4);
|
||||
|
||||
JSC::PropertyOffset offset;
|
||||
// TODO: add identifiers to CommonIdentifiers?
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "address"_s),
|
||||
0,
|
||||
static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete),
|
||||
offset);
|
||||
ASSERT(offset == addressOffset);
|
||||
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "family"_s),
|
||||
0,
|
||||
static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete),
|
||||
offset);
|
||||
ASSERT(offset == addressFamilyOffset);
|
||||
|
||||
structure = structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "port"_s),
|
||||
0,
|
||||
static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete),
|
||||
offset);
|
||||
ASSERT(offset == portOffset);
|
||||
|
||||
structure->addPropertyTransition(
|
||||
vm,
|
||||
structure,
|
||||
JSC::Identifier::fromString(vm, "flowLabel"_s),
|
||||
static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::DontDelete),
|
||||
offset);
|
||||
ASSERT(offset == flowLabelOffset);
|
||||
|
||||
return structure;
|
||||
}
|
||||
|
||||
} // namespace JSSocketAddress
|
||||
JSSocketAddress::~JSSocketAddress()
|
||||
{
|
||||
}
|
||||
|
||||
void JSSocketAddress::finishCreation(JSC::VM& vm)
|
||||
{
|
||||
Base::finishCreation(vm);
|
||||
ASSERT(inherits(info()));
|
||||
// initializeProperties(vm, globalObject, prototype);
|
||||
// TODO: idk how to get a globalobject here
|
||||
// this->m_address.initLater([](const LazyProperty<JSSocketAddress, address_t>::Initializer& init) {
|
||||
// auto af = init->owner->addressFamily();
|
||||
// auto address = init->owner->address();
|
||||
// address.value()
|
||||
// address.value(init->vm.)
|
||||
// });
|
||||
// ASSERT(inherits(info()));
|
||||
// reifyStaticProperties(vm, JSSocketAddress::info(),
|
||||
// JSSocketAddressPrototypeTableValues, *this);
|
||||
// JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
||||
}
|
||||
|
||||
// void JSSocketAddress::initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* prototype)
|
||||
|
||||
const ClassInfo JSSocketAddress::s_info
|
||||
= {
|
||||
"SocketAddress"_s,
|
||||
&Base::s_info,
|
||||
nullptr,
|
||||
nullptr,
|
||||
CREATE_METHOD_TABLE(JSSocketAddress)
|
||||
};
|
||||
|
||||
template<typename Visitor>
|
||||
void JSSocketAddress::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
{
|
||||
JSSocketAddress* thisObject = jsCast<JSSocketAddress*>(cell);
|
||||
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
|
||||
Base::visitChildren(thisObject, visitor);
|
||||
thisObject->visitAdditionalChildren<Visitor>(visitor);
|
||||
}
|
||||
DEFINE_VISIT_CHILDREN(JSSocketAddress);
|
||||
|
||||
template<typename Visitor>
|
||||
void JSSocketAddress::visitAdditionalChildren(Visitor& visitor)
|
||||
{
|
||||
JSSocketAddress* thisObject = this;
|
||||
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
|
||||
|
||||
// TODO: do properties added via putDirectOffset need visiting?
|
||||
// visitor.append(thisObject->m_address);
|
||||
}
|
||||
DEFINE_VISIT_ADDITIONAL_CHILDREN(JSSocketAddress);
|
||||
|
||||
template<typename Visitor>
|
||||
void JSSocketAddress::visitOutputConstraintsImpl(JSCell* cell, Visitor& visitor)
|
||||
{
|
||||
|
||||
auto* thisObject = jsCast<JSSocketAddress*>(cell);
|
||||
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
|
||||
Base::visitOutputConstraints(thisObject, visitor);
|
||||
thisObject->visitAdditionalChildren(visitor);
|
||||
}
|
||||
DEFINE_VISIT_OUTPUT_CONSTRAINTS(JSSocketAddress);
|
||||
|
||||
} // namespace Bun
|
||||
|
||||
extern "C" JSObject* JSSocketAddress__create(JSGlobalObject* globalObject, JSString* value, int32_t port, bool isIPv6)
|
||||
{
|
||||
static const NeverDestroyed<String> IPv4 = MAKE_STATIC_STRING_IMPL("IPv4");
|
||||
static const NeverDestroyed<String> IPv6 = MAKE_STATIC_STRING_IMPL("IPv6");
|
||||
|
||||
VM& vm = globalObject->vm();
|
||||
|
||||
auto* global = jsCast<Zig::GlobalObject*>(globalObject);
|
||||
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
|
||||
|
||||
JSObject* thisObject = constructEmptyObject(vm, global->JSSocketAddressStructure());
|
||||
thisObject->putDirectOffset(vm, 0, value);
|
||||
thisObject->putDirectOffset(vm, 1, isIPv6 ? jsString(vm, IPv6) : jsString(vm, IPv4));
|
||||
thisObject->putDirectOffset(vm, 2, jsNumber(port));
|
||||
if (UNLIKELY(port < 0 || port > std::numeric_limits<in_port_t>::max())) {
|
||||
throwRangeError(global, scope, "Port out of range"_s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return thisObject;
|
||||
return Bun::JSSocketAddress::create(globalObject->vm(), globalObject, global->JSSocketAddressStructure(), value, port, isIPv6 ? AF_INET6 : AF_INET, 0);
|
||||
}
|
||||
|
||||
@@ -3,14 +3,127 @@
|
||||
#include "root.h"
|
||||
#include "JavaScriptCore/JSObjectInlines.h"
|
||||
|
||||
extern "C" {
|
||||
#if OS(WINDOWS)
|
||||
#include <WinSock2.h> // in_addr - https://learn.microsoft.com/en-us/windows/win32/api/winsock2/
|
||||
#include <in6addr.h> // in6_addr - https://learn.microsoft.com/en-us/windows/win32/api/ws2def/
|
||||
#include <ws2tcpip.h> // inet_ntop, inet_pton - https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/
|
||||
#include <Ws2def.h> // AF_INET, AF_INET6
|
||||
typedef union address {
|
||||
struct in_addr ipv4;
|
||||
struct in6_addr ipv6;
|
||||
} address_t;
|
||||
#define in_port_t USHORT
|
||||
#else
|
||||
#include <netinet/in.h> // in_addr, in6_addr
|
||||
#include <arpa/inet.h> // inet_pton, inet_ntop
|
||||
typedef union address {
|
||||
struct in_addr ipv4;
|
||||
struct in6_addr ipv6;
|
||||
} address_t;
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
namespace Bun {
|
||||
namespace JSSocketAddress {
|
||||
|
||||
Structure* createStructure(VM& vm, JSGlobalObject* globalObject);
|
||||
/// `SocketAddress` is written in Zig
|
||||
// struct SocketAddress;
|
||||
|
||||
// class JSSocketAddress : public JSC::JSDestructibleObject {
|
||||
// public:
|
||||
// using Base = JSC::JSDestructibleObject;
|
||||
// using DOMWrapped = SocketAddress;
|
||||
// static J Structure* createStructure(VM& vm, JSGlobalObject* globalObject);
|
||||
|
||||
// }; // class JSSocketAddress
|
||||
|
||||
class JSSocketAddress final : public JSC::JSObject {
|
||||
public:
|
||||
using Base = JSC::JSObject;
|
||||
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||
// static constexpr JSC::DestructionMode needsDestruction = NeedsDestruction;
|
||||
|
||||
/// Native SocketAddress used in/by Zig code.
|
||||
// SocketAddress* m_sockaddr { nullptr };
|
||||
// SocketAddress* m_address
|
||||
// uint8_t m_address[16];
|
||||
// LazyProperty<JSSocketAddress, address_t> m_address;
|
||||
address_t m_address;
|
||||
JSC::JSString* address() const;
|
||||
uint8_t addressFamily() const;
|
||||
in_port_t port() const;
|
||||
uint32_t flowLabel() const;
|
||||
|
||||
/// Returns `nullptr` if the address is invalid. A js exception will be thrown.
|
||||
static JSSocketAddress* create(JSC::VM& vm,
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
JSC::Structure* structure,
|
||||
JSC::JSString* address,
|
||||
in_port_t port,
|
||||
bool isIPv6);
|
||||
|
||||
/// Returns `nullptr` if the address is invalid. A js exception will be thrown.
|
||||
static JSSocketAddress* create(JSC::VM& vm,
|
||||
JSC::JSGlobalObject* globalObject,
|
||||
JSC::Structure* structure,
|
||||
JSC::JSString* address,
|
||||
in_port_t port,
|
||||
uint8_t addressFamily, // AF_INET | AF_INET6
|
||||
uint32_t flowLabel);
|
||||
|
||||
static void destroy(JSC::JSCell*);
|
||||
|
||||
template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||
{
|
||||
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
|
||||
return nullptr;
|
||||
return subspaceForImpl(vm);
|
||||
}
|
||||
static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
|
||||
|
||||
static JSObject* createPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
|
||||
// static JSObject* createConstructor(JSC::VM& vm, JSC::JSGlobalObject* globalObject);
|
||||
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype);
|
||||
// {
|
||||
// return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
|
||||
// }
|
||||
|
||||
// void detach()
|
||||
// {
|
||||
// this->sockaddr
|
||||
// }
|
||||
|
||||
// static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
|
||||
// static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSSocketAddress, m_ctx); }
|
||||
|
||||
// /**
|
||||
// * Estimated size of the object from Zig including the JS wrapper.
|
||||
// */
|
||||
// static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm);
|
||||
|
||||
// /**
|
||||
// * Memory cost of the object from Zig, without necessarily having a JS wrapper alive.
|
||||
// */
|
||||
// static size_t memoryCost(void* ptr);
|
||||
|
||||
JSSocketAddress(JSC::VM& vm, JSC::Structure* structure)
|
||||
: Base(vm, structure)
|
||||
{
|
||||
}
|
||||
~JSSocketAddress();
|
||||
|
||||
void finishCreation(JSC::VM&);
|
||||
|
||||
DECLARE_EXPORT_INFO;
|
||||
|
||||
DECLARE_VISIT_CHILDREN;
|
||||
template<typename Visitor> void visitAdditionalChildren(Visitor&);
|
||||
DECLARE_VISIT_OUTPUT_CONSTRAINTS;
|
||||
|
||||
}; // class JSSocketAddress
|
||||
|
||||
} // namespace JSSocketAddress
|
||||
} // namespace Bun
|
||||
|
||||
extern "C" JSObject* JSSocketAddress__create(JSGlobalObject* globalObject, JSString* value, int port, bool isIPv6);
|
||||
|
||||
105
src/bun.js/bindings/JSSocketAddressConstructor.cpp
Normal file
105
src/bun.js/bindings/JSSocketAddressConstructor.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
#include "JSSocketAddressConstructor.h"
|
||||
#include "JSSocketAddress.h"
|
||||
#include "JavaScriptCore/Lookup.h"
|
||||
#include "NodeValidator.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
|
||||
using namespace JSC;
|
||||
namespace Bun {
|
||||
|
||||
const ClassInfo JSSocketAddressConstructor::s_info = {
|
||||
"SocketAddressConstructor"_s,
|
||||
&Base::s_info,
|
||||
nullptr,
|
||||
nullptr,
|
||||
CREATE_METHOD_TABLE(JSSocketAddressConstructor)
|
||||
};
|
||||
// todo
|
||||
// static const JSSocketAddressConstructorTableValues[] = {
|
||||
// { "isSocketAddress"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsScketAddressConstructorFunction_isSocketAddress, 1 },
|
||||
// { "parse"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), JSC::NoIntrinsic, { JSC::HashTableValue::NativeFunctionType, jsScketAddressConstructorFunction_parse, 1 } },
|
||||
// };
|
||||
|
||||
// void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* global, JSSocketAddressPrototype* prototype)
|
||||
// {
|
||||
// }
|
||||
|
||||
JSSocketAddressConstructor* JSSocketAddressConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
|
||||
{
|
||||
JSSocketAddressConstructor* ptr = new (NotNull, JSC::allocateCell<JSSocketAddressConstructor>(vm)) JSSocketAddressConstructor(vm, structure);
|
||||
ptr->finishCreation(vm);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// new SocketAddress(AF, address, port?, flowLabel?)
|
||||
JSC::EncodedJSValue JSSocketAddressConstructor::construct(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
|
||||
{
|
||||
Zig::GlobalObject* global = reinterpret_cast<Zig::GlobalObject*>(globalObject);
|
||||
static const NeverDestroyed<String> port_name = MAKE_STATIC_STRING_IMPL("port");
|
||||
auto& vm = global->vm();
|
||||
auto scope = DECLARE_THROW_SCOPE(vm);
|
||||
|
||||
JSValue af_arg = callFrame->argument(0);
|
||||
JSValue address_arg = callFrame->argument(1);
|
||||
JSValue port_arg = callFrame->argument(2);
|
||||
JSValue flowLabel_arg = callFrame->argument(3);
|
||||
|
||||
// addressFamily
|
||||
V::validateUint32(scope, global, af_arg, "addressFamily"_s, jsBoolean(false));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
uint32_t af = af_arg.toUInt32(global);
|
||||
if (UNLIKELY(af != AF_INET && af != AF_INET6)) {
|
||||
throwTypeError(global, scope, "Invalid address family"_s);
|
||||
return encodedJSUndefined();
|
||||
}
|
||||
|
||||
// address
|
||||
V::validateString(scope, global, address_arg, "address"_s);
|
||||
RETURN_IF_EXCEPTION(scope, encodedJSUndefined());
|
||||
JSC::JSString* address = jsCast<JSC::JSString*>(address_arg);
|
||||
|
||||
// port
|
||||
in_port_t port = 0;
|
||||
if (LIKELY(!port_arg.isUndefined())) {
|
||||
V::validatePort(scope, global, port_arg, jsString(vm, port_name), true);
|
||||
RETURN_IF_EXCEPTION(scope, encodedJSUndefined());
|
||||
uint32_t port32 = port_arg.toUInt32(global);
|
||||
ASSERT(port32 <= std::numeric_limits<in_port_t>().max());
|
||||
port = static_cast<in_port_t>(port32);
|
||||
}
|
||||
|
||||
// flowLabel
|
||||
uint32_t flowLabel = 0;
|
||||
if (UNLIKELY(!flowLabel_arg.isUndefined())) {
|
||||
V::validateUint32(scope, global, flowLabel_arg, "flowlabel"_s, jsBoolean(false));
|
||||
RETURN_IF_EXCEPTION(scope, encodedJSUndefined());
|
||||
flowLabel = flowLabel_arg.toUInt32(global);
|
||||
}
|
||||
|
||||
auto* structure = global->JSSocketAddressStructure();
|
||||
auto* sockaddr = JSSocketAddress::create(vm, global, structure, address, port, af, flowLabel);
|
||||
// throws if inet_pton fails
|
||||
RETURN_IF_EXCEPTION(scope, encodedJSUndefined());
|
||||
return JSValue::encode(sockaddr);
|
||||
}
|
||||
|
||||
JSC::EncodedJSValue JSSocketAddressConstructor::call(JSC::JSGlobalObject* global, JSC::CallFrame* callFrame)
|
||||
{
|
||||
auto scope = DECLARE_THROW_SCOPE(global->vm());
|
||||
throwTypeError(global, scope, "Cannot construct SocketAddress"_s);
|
||||
return encodedJSUndefined();
|
||||
}
|
||||
|
||||
JSSocketAddressConstructor::JSSocketAddressConstructor(JSC::VM& vm, JSC::Structure* structure)
|
||||
: Base(vm, structure, call, construct)
|
||||
{
|
||||
}
|
||||
|
||||
// TODO: reifyStaticProperties
|
||||
// void JSSocketAddressConstructor::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* global, JSSocketAddressPrototype* prototype)
|
||||
// {
|
||||
// Base::finishCreation(vm);
|
||||
// reifyStaticProperties(vm, JSSocketAddress::info(), JSSocketAddressConstructorTableValues, *this);
|
||||
// }
|
||||
|
||||
} // namespace Bun
|
||||
49
src/bun.js/bindings/JSSocketAddressConstructor.h
Normal file
49
src/bun.js/bindings/JSSocketAddressConstructor.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "root.h"
|
||||
#include "JSSocketAddressPrototype.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
class JSSocketAddressConstructor final : public JSC::InternalFunction {
|
||||
public:
|
||||
using Base = JSC::InternalFunction;
|
||||
static JSSocketAddressConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure);
|
||||
|
||||
static constexpr unsigned StructureFlags = Base::StructureFlags;
|
||||
static constexpr JSC::DestructionMode needsDestruction = JSC::DoesNotNeedDestruction;
|
||||
|
||||
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* prototype)
|
||||
{
|
||||
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
|
||||
}
|
||||
|
||||
template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||
{
|
||||
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
|
||||
return nullptr;
|
||||
return &vm.internalFunctionSpace();
|
||||
// TODO: use separate subspace??
|
||||
|
||||
// return WebCore::subspaceForImpl<JSSocketAddressConstructor, WebCore::UseCustomHeapCellType::No>(
|
||||
// vm,
|
||||
// [](auto& spaces) { return spaces.m_clientSubspaceForBunClassConstructor.get(); },
|
||||
// [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForBunClassConstructor = std::forward<decltype(space)>(space); },
|
||||
// [](auto& spaces) { return spaces.m_subspaceForBunClassConstructor.get(); },
|
||||
// [](auto& spaces, auto&& space) { spaces.m_subspaceForBunClassConstructor = std::forward<decltype(space)>(space); });
|
||||
}
|
||||
|
||||
// void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSSocketAddressPrototype* prototype);
|
||||
|
||||
// Must be defined for each specialization class.
|
||||
static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
|
||||
static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES call(JSC::JSGlobalObject*, JSC::CallFrame*);
|
||||
|
||||
DECLARE_EXPORT_INFO;
|
||||
|
||||
protected:
|
||||
JSSocketAddressConstructor(JSC::VM& vm, JSC::Structure* structure);
|
||||
DECLARE_DEFAULT_FINISH_CREATION;
|
||||
};
|
||||
|
||||
} // namespace Bun
|
||||
13
src/bun.js/bindings/JSSocketAddressPrototype.cpp
Normal file
13
src/bun.js/bindings/JSSocketAddressPrototype.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "JSSocketAddressPrototype.h"
|
||||
|
||||
// const ClassInfo JSX509CertificatePrototype::s_info = { "X509Certificate"_s,
|
||||
// &Base::s_info, nullptr, nullptr,
|
||||
// CREATE_METHOD_TABLE(JSX509CertificatePrototype) };
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
namespace Bun {
|
||||
|
||||
const ClassInfo JSSocketAddressPrototype::s_info = { "SocketAddress"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSocketAddressPrototype) };
|
||||
|
||||
} // namespace Bun
|
||||
42
src/bun.js/bindings/JSSocketAddressPrototype.h
Normal file
42
src/bun.js/bindings/JSSocketAddressPrototype.h
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "root.h"
|
||||
|
||||
namespace Bun {
|
||||
|
||||
class JSSocketAddressPrototype final : public JSC::JSNonFinalObject {
|
||||
public:
|
||||
using Base = JSC::JSNonFinalObject;
|
||||
|
||||
static JSSocketAddressPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
|
||||
{
|
||||
JSSocketAddressPrototype* ptr = new (NotNull, JSC::allocateCell<JSSocketAddressPrototype>(vm)) JSSocketAddressPrototype(vm, globalObject, structure);
|
||||
ptr->finishCreation(vm);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
DECLARE_INFO;
|
||||
template<typename CellType, JSC::SubspaceAccess>
|
||||
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
|
||||
{
|
||||
STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSSocketAddressPrototype, Base);
|
||||
return &vm.plainObjectSpace();
|
||||
}
|
||||
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
|
||||
{
|
||||
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
|
||||
}
|
||||
|
||||
protected:
|
||||
JSSocketAddressPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
|
||||
: Base(vm, structure)
|
||||
{
|
||||
}
|
||||
|
||||
// void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
|
||||
// void finishCreation(JSC::VM& vm) { Base::finishCreation(vm); }
|
||||
DECLARE_DEFAULT_FINISH_CREATION;
|
||||
};
|
||||
|
||||
} // namespace Bun
|
||||
@@ -254,7 +254,13 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validatePort, (JSC::JSGlobalObject * globalO
|
||||
if (allowZero.isUndefined()) allowZero = jsBoolean(true);
|
||||
|
||||
auto allowZero_b = allowZero.toBoolean(globalObject);
|
||||
if (!port.isNumber() && !port.isString()) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
|
||||
return V::validatePort(scope, globalObject, port, name, allowZero_b);
|
||||
}
|
||||
|
||||
JSC::EncodedJSValue V::validatePort(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue port, JSValue name, bool allowZero)
|
||||
{
|
||||
if (!port.isNumber() && !port.isString()) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
|
||||
if (port.isString()) {
|
||||
auto port_str = port.getString(globalObject);
|
||||
@@ -290,19 +296,19 @@ JSC_DEFINE_HOST_FUNCTION(jsFunction_validatePort, (JSC::JSGlobalObject * globalO
|
||||
return false;
|
||||
});
|
||||
if (trimmed.length() == 0) {
|
||||
return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
}
|
||||
}
|
||||
|
||||
auto port_num = port.toNumber(globalObject);
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
|
||||
if (std::isnan(port_num)) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
if (std::isinf(port_num)) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
if (std::fmod(port_num, 1.0) != 0) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
if (port_num < 0) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
if (port_num > 0xffff) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
if (port_num == 0 && !allowZero_b) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero_b);
|
||||
if (std::isnan(port_num)) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
if (std::isinf(port_num)) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
if (std::fmod(port_num, 1.0) != 0) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
if (port_num < 0) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
if (port_num > 0xffff) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
if (port_num == 0 && !allowZero) return Bun::ERR::SOCKET_BAD_PORT(scope, globalObject, name, port, allowZero);
|
||||
|
||||
return JSValue::encode(port);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ JSC::EncodedJSValue validateArray(JSC::ThrowScope& scope, JSC::JSGlobalObject* g
|
||||
JSC::EncodedJSValue validateArray(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name, JSValue minLength);
|
||||
JSC::EncodedJSValue validateUint32(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, JSValue name, JSValue positive);
|
||||
JSC::EncodedJSValue validateUint32(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue value, ASCIILiteral name, JSValue positive);
|
||||
JSC::EncodedJSValue validatePort(JSC::ThrowScope& scope, JSC::JSGlobalObject* globalObject, JSValue port, JSC::JSValue name, bool allowZero);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -115,6 +115,8 @@
|
||||
#include "JSReadableStreamDefaultReader.h"
|
||||
#include "JSSink.h"
|
||||
#include "JSSocketAddress.h"
|
||||
#include "JSSocketAddressConstructor.h"
|
||||
#include "JSSocketAddressPrototype.h"
|
||||
#include "JSSQLStatement.h"
|
||||
#include "JSStringDecoder.h"
|
||||
#include "JSTextEncoder.h"
|
||||
@@ -2914,11 +2916,6 @@ void GlobalObject::finishCreation(VM& vm)
|
||||
init.vm, reinterpret_cast<Zig::GlobalObject*>(init.owner)));
|
||||
});
|
||||
|
||||
m_JSSocketAddressStructure.initLater(
|
||||
[](const Initializer<Structure>& init) {
|
||||
init.set(JSSocketAddress::createStructure(init.vm, init.owner));
|
||||
});
|
||||
|
||||
m_errorConstructorPrepareStackTraceInternalValue.initLater(
|
||||
[](const Initializer<JSFunction>& init) {
|
||||
init.set(JSFunction::create(init.vm, init.owner, 2, "ErrorPrepareStackTrace"_s, jsFunctionDefaultErrorPrepareStackTrace, ImplementationVisibility::Public));
|
||||
@@ -3286,6 +3283,17 @@ void GlobalObject::finishCreation(VM& vm)
|
||||
init.setConstructor(constructor);
|
||||
});
|
||||
|
||||
m_JSSocketAddressClassStructure.initLater(
|
||||
[](LazyClassStructure::Initializer& init) {
|
||||
auto* prototype = JSSocketAddressPrototype::create(init.vm, init.global, JSSocketAddressPrototype::createStructure(init.vm, init.global, init.global->objectPrototype()));
|
||||
auto* structure = JSSocketAddress::createStructure(init.vm, init.global, prototype);
|
||||
auto* constructor = JSSocketAddressConstructor::create(
|
||||
init.vm, init.global, JSSocketAddressConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()));
|
||||
init.setPrototype(prototype);
|
||||
init.setStructure(structure);
|
||||
init.setConstructor(constructor);
|
||||
});
|
||||
|
||||
m_JSBufferClassStructure.initLater(
|
||||
[](LazyClassStructure::Initializer& init) {
|
||||
auto prototype = WebCore::createBufferPrototype(init.vm, init.global);
|
||||
@@ -3890,8 +3898,8 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
|
||||
thisObject->m_JSHTTPSResponseControllerPrototype.visit(visitor);
|
||||
thisObject->m_JSHTTPSResponseSinkClassStructure.visit(visitor);
|
||||
thisObject->m_JSNetworkSinkClassStructure.visit(visitor);
|
||||
thisObject->m_JSSocketAddressClassStructure.visit(visitor);
|
||||
thisObject->m_JSFetchTaskletChunkedRequestControllerPrototype.visit(visitor);
|
||||
thisObject->m_JSSocketAddressStructure.visit(visitor);
|
||||
thisObject->m_JSSQLStatementStructure.visit(visitor);
|
||||
thisObject->m_V8GlobalInternals.visit(visitor);
|
||||
thisObject->m_JSStringDecoderClassStructure.visit(visitor);
|
||||
|
||||
@@ -216,6 +216,10 @@ public:
|
||||
JSC::JSValue NetworkSinkPrototype() const { return m_JSNetworkSinkClassStructure.prototypeInitializedOnMainThread(this); }
|
||||
JSC::JSValue JSReadableNetworkSinkControllerPrototype() const { return m_JSFetchTaskletChunkedRequestControllerPrototype.getInitializedOnMainThread(this); }
|
||||
|
||||
JSC::Structure* JSSocketAddressStructure() const { return m_JSSocketAddressClassStructure.getInitializedOnMainThread(this); }
|
||||
JSC::JSObject* JSSocketAdddress() { return m_JSSocketAddressClassStructure.constructorInitializedOnMainThread(this); }
|
||||
JSC::JSValue JSSocketAddressPrototype() const { return m_JSSocketAddressClassStructure.prototypeInitializedOnMainThread(this); }
|
||||
|
||||
JSC::Structure* JSBufferListStructure() const { return m_JSBufferListClassStructure.getInitializedOnMainThread(this); }
|
||||
JSC::JSObject* JSBufferList() { return m_JSBufferListClassStructure.constructorInitializedOnMainThread(this); }
|
||||
JSC::JSValue JSBufferListPrototype() const { return m_JSBufferListClassStructure.prototypeInitializedOnMainThread(this); }
|
||||
@@ -261,8 +265,6 @@ public:
|
||||
Structure* ImportMetaObjectStructure() const { return m_importMetaObjectStructure.getInitializedOnMainThread(this); }
|
||||
Structure* AsyncContextFrameStructure() const { return m_asyncBoundFunctionStructure.getInitializedOnMainThread(this); }
|
||||
|
||||
Structure* JSSocketAddressStructure() const { return m_JSSocketAddressStructure.getInitializedOnMainThread(this); }
|
||||
|
||||
JSWeakMap* vmModuleContextMap() const { return m_vmModuleContextMap.getInitializedOnMainThread(this); }
|
||||
|
||||
Structure* NapiExternalStructure() const { return m_NapiExternalStructure.getInitializedOnMainThread(this); }
|
||||
@@ -531,6 +533,7 @@ public:
|
||||
LazyClassStructure m_JSHTTPResponseSinkClassStructure;
|
||||
LazyClassStructure m_JSHTTPSResponseSinkClassStructure;
|
||||
LazyClassStructure m_JSNetworkSinkClassStructure;
|
||||
LazyClassStructure m_JSSocketAddressClassStructure;
|
||||
|
||||
LazyClassStructure m_JSStringDecoderClassStructure;
|
||||
LazyClassStructure m_NapiClassStructure;
|
||||
@@ -575,7 +578,6 @@ public:
|
||||
LazyProperty<JSGlobalObject, Structure> m_cachedNodeVMGlobalObjectStructure;
|
||||
LazyProperty<JSGlobalObject, Structure> m_cachedGlobalProxyStructure;
|
||||
LazyProperty<JSGlobalObject, Structure> m_commonJSModuleObjectStructure;
|
||||
LazyProperty<JSGlobalObject, Structure> m_JSSocketAddressStructure;
|
||||
LazyProperty<JSGlobalObject, Structure> m_memoryFootprintStructure;
|
||||
LazyProperty<JSGlobalObject, JSObject> m_requireFunctionUnbound;
|
||||
LazyProperty<JSGlobalObject, JSObject> m_requireResolveFunctionUnbound;
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSS3Bucket;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSS3File;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSX509Certificate;
|
||||
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForJSSocketAddress;
|
||||
#include "ZigGeneratedClasses+DOMClientIsoSubspaces.h"
|
||||
/* --- bun --- */
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSS3Bucket;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSS3File;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSX509Certificate;
|
||||
std::unique_ptr<IsoSubspace> m_subspaceForJSSocketAddress;
|
||||
#include "ZigGeneratedClasses+DOMIsoSubspaces.h"
|
||||
/*-- BUN --*/
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ using namespace JSC;
|
||||
macro(abortSteps) \
|
||||
macro(addAbortAlgorithmToSignal) \
|
||||
macro(addEventListener) \
|
||||
macro(address) \
|
||||
macro(appendFromJS) \
|
||||
macro(argv) \
|
||||
macro(assignToStream) \
|
||||
|
||||
Reference in New Issue
Block a user