初始化

This commit is contained in:
SmallMain
2022-06-25 00:23:03 +08:00
commit ef0589e8e5
2264 changed files with 617829 additions and 0 deletions

View File

@@ -0,0 +1,530 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//#include "mozilla/Assertions.h"
//#include "mozilla/EndianUtils.h"
#include "SHA1.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include <string.h>
#include <assert.h>
#if defined(_MSC_VER)
# include <stdlib.h>
# pragma intrinsic(_byteswap_ushort)
# pragma intrinsic(_byteswap_ulong)
# pragma intrinsic(_byteswap_uint64)
#endif
#define MOZ_ASSERT(cond, ...) assert(cond)
//using se::NativeEndian;
using se::SHA1Sum;
namespace {
#if defined(_WIN64)
# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
# define MOZ_LITTLE_ENDIAN 1
# else
# error "CPU type is unknown"
# endif
#elif defined(_WIN32)
# if defined(_M_IX86)
# define MOZ_LITTLE_ENDIAN 1
# elif defined(_M_ARM)
# define MOZ_LITTLE_ENDIAN 1
# else
# error "CPU type is unknown"
# endif
#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__)
# if __LITTLE_ENDIAN__
# define MOZ_LITTLE_ENDIAN 1
# elif __BIG_ENDIAN__
# define MOZ_BIG_ENDIAN 1
# endif
#elif defined(__GNUC__) && \
defined(__BYTE_ORDER__) && \
defined(__ORDER_LITTLE_ENDIAN__) && \
defined(__ORDER_BIG_ENDIAN__)
/*
* Some versions of GCC provide architecture-independent macros for
* this. Yes, there are more than two values for __BYTE_ORDER__.
*/
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define MOZ_LITTLE_ENDIAN 1
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define MOZ_BIG_ENDIAN 1
# else
# error "Can't handle mixed-endian architectures"
# endif
/*
* We can't include useful headers like <endian.h> or <sys/isa_defs.h>
* here because they're not present on all platforms. Instead we have
* this big conditional that ideally will catch all the interesting
* cases.
*/
#elif defined(__sparc) || defined(__sparc__) || \
defined(_POWER) || defined(__hppa) || \
defined(_MIPSEB) || defined(__ARMEB__) || \
defined(__s390__) || defined(__AARCH64EB__) || \
(defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \
(defined(__ia64) && defined(__BIG_ENDIAN__))
# define MOZ_BIG_ENDIAN 1
#elif defined(__i386) || defined(__i386__) || \
defined(__x86_64) || defined(__x86_64__) || \
defined(_MIPSEL) || defined(__ARMEL__) || \
defined(__alpha__) || defined(__AARCH64EL__) || \
(defined(__sh__) && defined(__BIG_ENDIAN__)) || \
(defined(__ia64) && !defined(__BIG_ENDIAN__))
# define MOZ_LITTLE_ENDIAN 1
#endif
#if MOZ_BIG_ENDIAN
# define MOZ_LITTLE_ENDIAN 0
#elif MOZ_LITTLE_ENDIAN
# define MOZ_BIG_ENDIAN 0
#else
# error "Cannot determine endianness"
#endif
#if defined(__clang__)
# if __has_builtin(__builtin_bswap16)
# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
# endif
#elif defined(__GNUC__)
# define MOZ_HAVE_BUILTIN_BYTESWAP16 __builtin_bswap16
#elif defined(_MSC_VER)
# define MOZ_HAVE_BUILTIN_BYTESWAP16 _byteswap_ushort
#endif
enum Endianness { Little, Big };
#if MOZ_BIG_ENDIAN
# define MOZ_NATIVE_ENDIANNESS Big
#else
# define MOZ_NATIVE_ENDIANNESS Little
#endif
/*
* We need wrappers here because free functions with default template
* arguments and/or partial specialization of function templates are not
* supported by all the compilers we use.
*/
template<typename T, size_t Size = sizeof(T)>
struct Swapper;
template<typename T>
struct Swapper<T, 2>
{
static T swap(T aValue)
{
#if defined(MOZ_HAVE_BUILTIN_BYTESWAP16)
return MOZ_HAVE_BUILTIN_BYTESWAP16(aValue);
#else
return T(((aValue & 0x00ff) << 8) | ((aValue & 0xff00) >> 8));
#endif
}
};
template<typename T>
struct Swapper<T, 4>
{
static T swap(T aValue)
{
#if defined(__clang__) || defined(__GNUC__)
return T(__builtin_bswap32(aValue));
#elif defined(_MSC_VER)
return T(_byteswap_ulong(aValue));
#else
return T(((aValue & 0x000000ffU) << 24) |
((aValue & 0x0000ff00U) << 8) |
((aValue & 0x00ff0000U) >> 8) |
((aValue & 0xff000000U) >> 24));
#endif
}
};
template<typename T>
struct Swapper<T, 8>
{
static inline T swap(T aValue)
{
#if defined(__clang__) || defined(__GNUC__)
return T(__builtin_bswap64(aValue));
#elif defined(_MSC_VER)
return T(_byteswap_uint64(aValue));
#else
return T(((aValue & 0x00000000000000ffULL) << 56) |
((aValue & 0x000000000000ff00ULL) << 40) |
((aValue & 0x0000000000ff0000ULL) << 24) |
((aValue & 0x00000000ff000000ULL) << 8) |
((aValue & 0x000000ff00000000ULL) >> 8) |
((aValue & 0x0000ff0000000000ULL) >> 24) |
((aValue & 0x00ff000000000000ULL) >> 40) |
((aValue & 0xff00000000000000ULL) >> 56));
#endif
}
};
template<Endianness ThisEndian>
class Endian
{
public:
template<typename T>
static T swapToBigEndian(T aValue)
{
return maybeSwap<ThisEndian, Big>(aValue);
}
private:
/**
* Return |aValue| converted from SourceEndian encoding to DestEndian
* encoding.
*/
template<Endianness SourceEndian, Endianness DestEndian, typename T>
static inline T maybeSwap(T aValue)
{
if (SourceEndian == DestEndian) {
return aValue;
}
return Swapper<T>::swap(aValue);
}
};
class NativeEndian final : public Endian<MOZ_NATIVE_ENDIANNESS>
{
private:
typedef Endian<MOZ_NATIVE_ENDIANNESS> super;
public:
using super::swapToBigEndian;
};
} // namespace {
static inline uint32_t
SHA_ROTL(uint32_t aT, uint32_t aN)
{
MOZ_ASSERT(aN < 32);
return (aT << aN) | (aT >> (32 - aN));
}
static void
shaCompress(volatile unsigned* aX, const uint32_t* aBuf);
#define SHA_F1(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
#define SHA_F2(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define SHA_F3(X, Y, Z) (((X) & (Y)) | ((Z) & ((X) | (Y))))
#define SHA_F4(X, Y, Z) ((X) ^ (Y) ^ (Z))
#define SHA_MIX(n, a, b, c) XW(n) = SHA_ROTL(XW(a) ^ XW(b) ^ XW(c) ^XW(n), 1)
SHA1Sum::SHA1Sum()
: mSize(0), mDone(false)
{
// Initialize H with constants from FIPS180-1.
mH[0] = 0x67452301L;
mH[1] = 0xefcdab89L;
mH[2] = 0x98badcfeL;
mH[3] = 0x10325476L;
mH[4] = 0xc3d2e1f0L;
}
/*
* Explanation of H array and index values:
*
* The context's H array is actually the concatenation of two arrays
* defined by SHA1, the H array of state variables (5 elements),
* and the W array of intermediate values, of which there are 16 elements.
* The W array starts at H[5], that is W[0] is H[5].
* Although these values are defined as 32-bit values, we use 64-bit
* variables to hold them because the AMD64 stores 64 bit values in
* memory MUCH faster than it stores any smaller values.
*
* Rather than passing the context structure to shaCompress, we pass
* this combined array of H and W values. We do not pass the address
* of the first element of this array, but rather pass the address of an
* element in the middle of the array, element X. Presently X[0] is H[11].
* So we pass the address of H[11] as the address of array X to shaCompress.
* Then shaCompress accesses the members of the array using positive AND
* negative indexes.
*
* Pictorially: (each element is 8 bytes)
* H | H0 H1 H2 H3 H4 W0 W1 W2 W3 W4 W5 W6 W7 W8 W9 Wa Wb Wc Wd We Wf |
* X |-11-10 -9 -8 -7 -6 -5 -4 -3 -2 -1 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 |
*
* The byte offset from X[0] to any member of H and W is always
* representable in a signed 8-bit value, which will be encoded
* as a single byte offset in the X86-64 instruction set.
* If we didn't pass the address of H[11], and instead passed the
* address of H[0], the offsets to elements H[16] and above would be
* greater than 127, not representable in a signed 8-bit value, and the
* x86-64 instruction set would encode every such offset as a 32-bit
* signed number in each instruction that accessed element H[16] or
* higher. This results in much bigger and slower code.
*/
#define H2X 11 /* X[0] is H[11], and H[0] is X[-11] */
#define W2X 6 /* X[0] is W[6], and W[0] is X[-6] */
/*
* SHA: Add data to context.
*/
void
SHA1Sum::update(const void* aData, uint32_t aLen)
{
MOZ_ASSERT(!mDone, "SHA1Sum can only be used to compute a single hash.");
const uint8_t* data = static_cast<const uint8_t*>(aData);
if (aLen == 0) {
return;
}
/* Accumulate the byte count. */
unsigned int lenB = static_cast<unsigned int>(mSize) & 63U;
mSize += aLen;
/* Read the data into W and process blocks as they get full. */
unsigned int togo;
if (lenB > 0) {
togo = 64U - lenB;
if (aLen < togo) {
togo = aLen;
}
memcpy(mU.mB + lenB, data, togo);
aLen -= togo;
data += togo;
lenB = (lenB + togo) & 63U;
if (!lenB) {
shaCompress(&mH[H2X], mU.mW);
}
}
while (aLen >= 64U) {
aLen -= 64U;
shaCompress(&mH[H2X], reinterpret_cast<const uint32_t*>(data));
data += 64U;
}
if (aLen > 0) {
memcpy(mU.mB, data, aLen);
}
}
/*
* SHA: Generate hash value
*/
void
SHA1Sum::finish(SHA1Sum::Hash& aHashOut)
{
MOZ_ASSERT(!mDone, "SHA1Sum can only be used to compute a single hash.");
uint64_t size = mSize;
uint32_t lenB = uint32_t(size) & 63;
static const uint8_t bulk_pad[64] =
{ 0x80,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
/* Pad with a binary 1 (e.g. 0x80), then zeroes, then length in bits. */
update(bulk_pad, (((55 + 64) - lenB) & 63) + 1);
MOZ_ASSERT((uint32_t(mSize) & 63) == 56);
/* Convert size from bytes to bits. */
size <<= 3;
mU.mW[14] = NativeEndian::swapToBigEndian(uint32_t(size >> 32));
mU.mW[15] = NativeEndian::swapToBigEndian(uint32_t(size));
shaCompress(&mH[H2X], mU.mW);
/* Output hash. */
mU.mW[0] = NativeEndian::swapToBigEndian(mH[0]);
mU.mW[1] = NativeEndian::swapToBigEndian(mH[1]);
mU.mW[2] = NativeEndian::swapToBigEndian(mH[2]);
mU.mW[3] = NativeEndian::swapToBigEndian(mH[3]);
mU.mW[4] = NativeEndian::swapToBigEndian(mH[4]);
memcpy(aHashOut, mU.mW, 20);
mDone = true;
}
/*
* SHA: Compression function, unrolled.
*
* Some operations in shaCompress are done as 5 groups of 16 operations.
* Others are done as 4 groups of 20 operations.
* The code below shows that structure.
*
* The functions that compute the new values of the 5 state variables
* A-E are done in 4 groups of 20 operations (or you may also think
* of them as being done in 16 groups of 5 operations). They are
* done by the SHA_RNDx macros below, in the right column.
*
* The functions that set the 16 values of the W array are done in
* 5 groups of 16 operations. The first group is done by the
* LOAD macros below, the latter 4 groups are done by SHA_MIX below,
* in the left column.
*
* gcc's optimizer observes that each member of the W array is assigned
* a value 5 times in this code. It reduces the number of store
* operations done to the W array in the context (that is, in the X array)
* by creating a W array on the stack, and storing the W values there for
* the first 4 groups of operations on W, and storing the values in the
* context's W array only in the fifth group. This is undesirable.
* It is MUCH bigger code than simply using the context's W array, because
* all the offsets to the W array in the stack are 32-bit signed offsets,
* and it is no faster than storing the values in the context's W array.
*
* The original code for sha_fast.c prevented this creation of a separate
* W array in the stack by creating a W array of 80 members, each of
* whose elements is assigned only once. It also separated the computations
* of the W array values and the computations of the values for the 5
* state variables into two separate passes, W's, then A-E's so that the
* second pass could be done all in registers (except for accessing the W
* array) on machines with fewer registers. The method is suboptimal
* for machines with enough registers to do it all in one pass, and it
* necessitates using many instructions with 32-bit offsets.
*
* This code eliminates the separate W array on the stack by a completely
* different means: by declaring the X array volatile. This prevents
* the optimizer from trying to reduce the use of the X array by the
* creation of a MORE expensive W array on the stack. The result is
* that all instructions use signed 8-bit offsets and not 32-bit offsets.
*
* The combination of this code and the -O3 optimizer flag on GCC 3.4.3
* results in code that is 3 times faster than the previous NSS sha_fast
* code on AMD64.
*/
static void
shaCompress(volatile unsigned* aX, const uint32_t* aBuf)
{
unsigned A, B, C, D, E;
#define XH(n) aX[n - H2X]
#define XW(n) aX[n - W2X]
#define K0 0x5a827999L
#define K1 0x6ed9eba1L
#define K2 0x8f1bbcdcL
#define K3 0xca62c1d6L
#define SHA_RND1(a, b, c, d, e, n) \
a = SHA_ROTL(b, 5) + SHA_F1(c, d, e) + a + XW(n) + K0; c = SHA_ROTL(c, 30)
#define SHA_RND2(a, b, c, d, e, n) \
a = SHA_ROTL(b, 5) + SHA_F2(c, d, e) + a + XW(n) + K1; c = SHA_ROTL(c, 30)
#define SHA_RND3(a, b, c, d, e, n) \
a = SHA_ROTL(b, 5) + SHA_F3(c, d, e) + a + XW(n) + K2; c = SHA_ROTL(c, 30)
#define SHA_RND4(a, b, c, d, e, n) \
a = SHA_ROTL(b ,5) + SHA_F4(c, d, e) + a + XW(n) + K3; c = SHA_ROTL(c, 30)
#define LOAD(n) XW(n) = NativeEndian::swapToBigEndian(aBuf[n])
A = XH(0);
B = XH(1);
C = XH(2);
D = XH(3);
E = XH(4);
LOAD(0); SHA_RND1(E,A,B,C,D, 0);
LOAD(1); SHA_RND1(D,E,A,B,C, 1);
LOAD(2); SHA_RND1(C,D,E,A,B, 2);
LOAD(3); SHA_RND1(B,C,D,E,A, 3);
LOAD(4); SHA_RND1(A,B,C,D,E, 4);
LOAD(5); SHA_RND1(E,A,B,C,D, 5);
LOAD(6); SHA_RND1(D,E,A,B,C, 6);
LOAD(7); SHA_RND1(C,D,E,A,B, 7);
LOAD(8); SHA_RND1(B,C,D,E,A, 8);
LOAD(9); SHA_RND1(A,B,C,D,E, 9);
LOAD(10); SHA_RND1(E,A,B,C,D,10);
LOAD(11); SHA_RND1(D,E,A,B,C,11);
LOAD(12); SHA_RND1(C,D,E,A,B,12);
LOAD(13); SHA_RND1(B,C,D,E,A,13);
LOAD(14); SHA_RND1(A,B,C,D,E,14);
LOAD(15); SHA_RND1(E,A,B,C,D,15);
SHA_MIX( 0, 13, 8, 2); SHA_RND1(D,E,A,B,C, 0);
SHA_MIX( 1, 14, 9, 3); SHA_RND1(C,D,E,A,B, 1);
SHA_MIX( 2, 15, 10, 4); SHA_RND1(B,C,D,E,A, 2);
SHA_MIX( 3, 0, 11, 5); SHA_RND1(A,B,C,D,E, 3);
SHA_MIX( 4, 1, 12, 6); SHA_RND2(E,A,B,C,D, 4);
SHA_MIX( 5, 2, 13, 7); SHA_RND2(D,E,A,B,C, 5);
SHA_MIX( 6, 3, 14, 8); SHA_RND2(C,D,E,A,B, 6);
SHA_MIX( 7, 4, 15, 9); SHA_RND2(B,C,D,E,A, 7);
SHA_MIX( 8, 5, 0, 10); SHA_RND2(A,B,C,D,E, 8);
SHA_MIX( 9, 6, 1, 11); SHA_RND2(E,A,B,C,D, 9);
SHA_MIX(10, 7, 2, 12); SHA_RND2(D,E,A,B,C,10);
SHA_MIX(11, 8, 3, 13); SHA_RND2(C,D,E,A,B,11);
SHA_MIX(12, 9, 4, 14); SHA_RND2(B,C,D,E,A,12);
SHA_MIX(13, 10, 5, 15); SHA_RND2(A,B,C,D,E,13);
SHA_MIX(14, 11, 6, 0); SHA_RND2(E,A,B,C,D,14);
SHA_MIX(15, 12, 7, 1); SHA_RND2(D,E,A,B,C,15);
SHA_MIX( 0, 13, 8, 2); SHA_RND2(C,D,E,A,B, 0);
SHA_MIX( 1, 14, 9, 3); SHA_RND2(B,C,D,E,A, 1);
SHA_MIX( 2, 15, 10, 4); SHA_RND2(A,B,C,D,E, 2);
SHA_MIX( 3, 0, 11, 5); SHA_RND2(E,A,B,C,D, 3);
SHA_MIX( 4, 1, 12, 6); SHA_RND2(D,E,A,B,C, 4);
SHA_MIX( 5, 2, 13, 7); SHA_RND2(C,D,E,A,B, 5);
SHA_MIX( 6, 3, 14, 8); SHA_RND2(B,C,D,E,A, 6);
SHA_MIX( 7, 4, 15, 9); SHA_RND2(A,B,C,D,E, 7);
SHA_MIX( 8, 5, 0, 10); SHA_RND3(E,A,B,C,D, 8);
SHA_MIX( 9, 6, 1, 11); SHA_RND3(D,E,A,B,C, 9);
SHA_MIX(10, 7, 2, 12); SHA_RND3(C,D,E,A,B,10);
SHA_MIX(11, 8, 3, 13); SHA_RND3(B,C,D,E,A,11);
SHA_MIX(12, 9, 4, 14); SHA_RND3(A,B,C,D,E,12);
SHA_MIX(13, 10, 5, 15); SHA_RND3(E,A,B,C,D,13);
SHA_MIX(14, 11, 6, 0); SHA_RND3(D,E,A,B,C,14);
SHA_MIX(15, 12, 7, 1); SHA_RND3(C,D,E,A,B,15);
SHA_MIX( 0, 13, 8, 2); SHA_RND3(B,C,D,E,A, 0);
SHA_MIX( 1, 14, 9, 3); SHA_RND3(A,B,C,D,E, 1);
SHA_MIX( 2, 15, 10, 4); SHA_RND3(E,A,B,C,D, 2);
SHA_MIX( 3, 0, 11, 5); SHA_RND3(D,E,A,B,C, 3);
SHA_MIX( 4, 1, 12, 6); SHA_RND3(C,D,E,A,B, 4);
SHA_MIX( 5, 2, 13, 7); SHA_RND3(B,C,D,E,A, 5);
SHA_MIX( 6, 3, 14, 8); SHA_RND3(A,B,C,D,E, 6);
SHA_MIX( 7, 4, 15, 9); SHA_RND3(E,A,B,C,D, 7);
SHA_MIX( 8, 5, 0, 10); SHA_RND3(D,E,A,B,C, 8);
SHA_MIX( 9, 6, 1, 11); SHA_RND3(C,D,E,A,B, 9);
SHA_MIX(10, 7, 2, 12); SHA_RND3(B,C,D,E,A,10);
SHA_MIX(11, 8, 3, 13); SHA_RND3(A,B,C,D,E,11);
SHA_MIX(12, 9, 4, 14); SHA_RND4(E,A,B,C,D,12);
SHA_MIX(13, 10, 5, 15); SHA_RND4(D,E,A,B,C,13);
SHA_MIX(14, 11, 6, 0); SHA_RND4(C,D,E,A,B,14);
SHA_MIX(15, 12, 7, 1); SHA_RND4(B,C,D,E,A,15);
SHA_MIX( 0, 13, 8, 2); SHA_RND4(A,B,C,D,E, 0);
SHA_MIX( 1, 14, 9, 3); SHA_RND4(E,A,B,C,D, 1);
SHA_MIX( 2, 15, 10, 4); SHA_RND4(D,E,A,B,C, 2);
SHA_MIX( 3, 0, 11, 5); SHA_RND4(C,D,E,A,B, 3);
SHA_MIX( 4, 1, 12, 6); SHA_RND4(B,C,D,E,A, 4);
SHA_MIX( 5, 2, 13, 7); SHA_RND4(A,B,C,D,E, 5);
SHA_MIX( 6, 3, 14, 8); SHA_RND4(E,A,B,C,D, 6);
SHA_MIX( 7, 4, 15, 9); SHA_RND4(D,E,A,B,C, 7);
SHA_MIX( 8, 5, 0, 10); SHA_RND4(C,D,E,A,B, 8);
SHA_MIX( 9, 6, 1, 11); SHA_RND4(B,C,D,E,A, 9);
SHA_MIX(10, 7, 2, 12); SHA_RND4(A,B,C,D,E,10);
SHA_MIX(11, 8, 3, 13); SHA_RND4(E,A,B,C,D,11);
SHA_MIX(12, 9, 4, 14); SHA_RND4(D,E,A,B,C,12);
SHA_MIX(13, 10, 5, 15); SHA_RND4(C,D,E,A,B,13);
SHA_MIX(14, 11, 6, 0); SHA_RND4(B,C,D,E,A,14);
SHA_MIX(15, 12, 7, 1); SHA_RND4(A,B,C,D,E,15);
XH(0) += A;
XH(1) += B;
XH(2) += C;
XH(3) += D;
XH(4) += E;
}
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Simple class for computing SHA1. */
#pragma once
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
//#include "mozilla/Types.h"
#include <stddef.h>
#include <stdint.h>
#ifdef MFBT_API
#undef MFBT_API
#endif
#define MFBT_API
namespace se {
/**
* This class computes the SHA1 hash of a byte sequence, or of the concatenation
* of multiple sequences. For example, computing the SHA1 of two sequences of
* bytes could be done as follows:
*
* void SHA1(const uint8_t* buf1, uint32_t size1,
* const uint8_t* buf2, uint32_t size2,
* SHA1Sum::Hash& hash)
* {
* SHA1Sum s;
* s.update(buf1, size1);
* s.update(buf2, size2);
* s.finish(hash);
* }
*
* The finish method may only be called once and cannot be followed by calls
* to update.
*/
class SHA1Sum
{
union
{
uint32_t mW[16]; /* input buffer */
uint8_t mB[64];
} mU;
uint64_t mSize; /* count of hashed bytes. */
unsigned mH[22]; /* 5 state variables, 16 tmp values, 1 extra */
bool mDone;
public:
MFBT_API SHA1Sum();
static const size_t kHashSize = 20;
typedef uint8_t Hash[kHashSize];
/* Add len bytes of dataIn to the data sequence being hashed. */
MFBT_API void update(const void* aData, uint32_t aLength);
/* Compute the final hash of all data into hashOut. */
MFBT_API void finish(SHA1Sum::Hash& aHashOut);
};
} /* namespace se */
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,194 @@
#ifndef SRC_BASE64_H_
#define SRC_BASE64_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "util.h"
#include <stddef.h>
namespace node {
//// Base 64 ////
#define base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4)
// Doesn't check for padding at the end. Can be 1-2 bytes over.
static inline size_t base64_decoded_size_fast(size_t size) {
size_t remainder = size % 4;
size = (size / 4) * 3;
if (remainder) {
if (size == 0 && remainder == 1) {
// special case: 1-byte input cannot be decoded
size = 0;
} else {
// non-padded input, add 1 or 2 extra bytes
size += 1 + (remainder == 3);
}
}
return size;
}
template <typename TypeName>
size_t base64_decoded_size(const TypeName* src, size_t size) {
if (size == 0)
return 0;
if (src[size - 1] == '=')
size--;
if (size > 0 && src[size - 1] == '=')
size--;
return base64_decoded_size_fast(size);
}
extern const int8_t unbase64_table[256];
#define unbase64(x) \
static_cast<uint8_t>(unbase64_table[static_cast<uint8_t>(x)])
template <typename TypeName>
bool base64_decode_group_slow(char* const dst, const size_t dstlen,
const TypeName* const src, const size_t srclen,
size_t* const i, size_t* const k) {
uint8_t hi;
uint8_t lo;
#define V(expr) \
for (;;) { \
const uint8_t c = src[*i]; \
lo = unbase64(c); \
*i += 1; \
if (lo < 64) \
break; /* Legal character. */ \
if (c == '=' || *i >= srclen) \
return false; /* Stop decoding. */ \
} \
expr; \
if (*i >= srclen) \
return false; \
if (*k >= dstlen) \
return false; \
hi = lo;
V(/* Nothing. */);
V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
#undef V
return true; // Continue decoding.
}
template <typename TypeName>
size_t base64_decode_fast(char* const dst, const size_t dstlen,
const TypeName* const src, const size_t srclen,
const size_t decoded_size) {
const size_t available = dstlen < decoded_size ? dstlen : decoded_size;
const size_t max_k = available / 3 * 3;
size_t max_i = srclen / 4 * 4;
size_t i = 0;
size_t k = 0;
while (i < max_i && k < max_k) {
const uint32_t v =
unbase64(src[i + 0]) << 24 |
unbase64(src[i + 1]) << 16 |
unbase64(src[i + 2]) << 8 |
unbase64(src[i + 3]);
// If MSB is set, input contains whitespace or is not valid base64.
if (v & 0x80808080) {
if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k))
return k;
max_i = i + (srclen - i) / 4 * 4; // Align max_i again.
} else {
dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F);
i += 4;
k += 3;
}
}
if (i < srclen && k < dstlen) {
base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k);
}
return k;
}
template <typename TypeName>
size_t base64_decode(char* const dst, const size_t dstlen,
const TypeName* const src, const size_t srclen) {
const size_t decoded_size = base64_decoded_size(src, srclen);
return base64_decode_fast(dst, dstlen, src, srclen, decoded_size);
}
static size_t base64_encode(const char* src,
size_t slen,
char* dst,
size_t dlen) {
// We know how much we'll write, just make sure that there's space.
CHECK(dlen >= base64_encoded_size(slen) &&
"not enough space provided for base64 encode");
dlen = base64_encoded_size(slen);
unsigned a;
unsigned b;
unsigned c;
unsigned i;
unsigned k;
unsigned n;
static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
i = 0;
k = 0;
n = slen / 3 * 3;
while (i < n) {
a = src[i + 0] & 0xff;
b = src[i + 1] & 0xff;
c = src[i + 2] & 0xff;
dst[k + 0] = table[a >> 2];
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
dst[k + 3] = table[c & 0x3f];
i += 3;
k += 4;
}
if (n != slen) {
switch (slen - n) {
case 1:
a = src[i + 0] & 0xff;
dst[k + 0] = table[a >> 2];
dst[k + 1] = table[(a & 3) << 4];
dst[k + 2] = '=';
dst[k + 3] = '=';
break;
case 2:
a = src[i + 0] & 0xff;
b = src[i + 1] & 0xff;
dst[k + 0] = table[a >> 2];
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
dst[k + 2] = table[(b & 0x0f) << 2];
dst[k + 3] = '=';
break;
}
}
return dlen;
}
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_BASE64_H_

View File

@@ -0,0 +1,122 @@
#include "env.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "uv.h"
using namespace v8;
namespace node {
void Environment::Start(int argc,
const char* const* argv,
int exec_argc,
const char* const* exec_argv,
bool start_profiler_idle_notifier)
{
HandleScope handle_scope(isolate());
Context::Scope context_scope(context());
// uv_check_init(event_loop(), immediate_check_handle());
// uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
//
// uv_idle_init(event_loop(), immediate_idle_handle());
//
// // Inform V8's CPU profiler when we're idle. The profiler is sampling-based
// // but not all samples are created equal; mark the wall clock time spent in
// // epoll_wait() and friends so profiling tools can filter it out. The samples
// // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
// // REFINE(bnoordhuis) Depends on a libuv implementation detail that we should
// // probably fortify in the API contract, namely that the last started prepare
// // or check watcher runs first. It's not 100% foolproof; if an add-on starts
// // a prepare or check watcher after us, any samples attributed to its callback
// // will be recorded with state=IDLE.
// uv_prepare_init(event_loop(), &idle_prepare_handle_);
// uv_check_init(event_loop(), &idle_check_handle_);
// uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
// uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
//
// uv_timer_init(event_loop(), destroy_ids_timer_handle());
//
// auto close_and_finish = [](Environment* env, uv_handle_t* handle, void* arg) {
// handle->data = env;
//
// uv_close(handle, [](uv_handle_t* handle) {
// static_cast<Environment*>(handle->data)->FinishHandleCleanup(handle);
// });
// };
//
// RegisterHandleCleanup(
// reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
// close_and_finish,
// nullptr);
// RegisterHandleCleanup(
// reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
// close_and_finish,
// nullptr);
// RegisterHandleCleanup(
// reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
// close_and_finish,
// nullptr);
// RegisterHandleCleanup(
// reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
// close_and_finish,
// nullptr);
if (start_profiler_idle_notifier) {
StartProfilerIdleNotifier();
}
auto process_template = FunctionTemplate::New(isolate());
process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate(), "process"));
auto process_object =
process_template->GetFunction(context()).ToLocalChecked()->NewInstance(context()).ToLocalChecked();
set_process_object(process_object);
SetupProcessObject(this, argc, argv, exec_argc, exec_argv);
// LoadAsyncWrapperInfo(this);
}
void Environment::AssignToContext(v8::Local<v8::Context> context)
{
context->SetAlignedPointerInEmbedderData(kContextEmbedderDataIndex, this);
}
void Environment::CleanupHandles()
{
// while (HandleCleanup* hc = handle_cleanup_queue_.PopFront()) {
// handle_cleanup_waiting_++;
// hc->cb_(this, hc->handle_, hc->arg_);
// delete hc;
// }
//
// while (handle_cleanup_waiting_ != 0)
// uv_run(event_loop(), UV_RUN_ONCE);
//
// while (handle_cleanup_waiting_ != 0)
// uv_run(event_loop(), UV_RUN_ONCE);
}
void Environment::StartProfilerIdleNotifier()
{
// uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
// Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
// env->isolate()->GetCpuProfiler()->SetIdle(true);
// });
//
// uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
// Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
// env->isolate()->GetCpuProfiler()->SetIdle(false);
// });
}
void Environment::StopProfilerIdleNotifier()
{
// uv_prepare_stop(&idle_prepare_handle_);
// uv_check_stop(&idle_check_handle_);
}
} // namespace node {
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,629 @@
#pragma once
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "inspector_agent.h"
#include "v8.h"
#include "uv.h"
#include "util.h"
#include "node.h"
namespace node {
// Pick an index that's hopefully out of the way when we're embedded inside
// another application. Performance-wise or memory-wise it doesn't matter:
// Context::SetAlignedPointerInEmbedderData() is backed by a FixedArray,
// worst case we pay a one-time penalty for resizing the array.
#ifndef NODE_CONTEXT_EMBEDDER_DATA_INDEX
#define NODE_CONTEXT_EMBEDDER_DATA_INDEX 32
#endif
// PER_ISOLATE_* macros: We have a lot of per-isolate properties
// and adding and maintaining their getters and setters by hand would be
// difficult so let's make the preprocessor generate them for us.
//
// In each macro, `V` is expected to be the name of a macro or function which
// accepts the number of arguments provided in each tuple in the macro body,
// typically two. The named function will be invoked against each tuple.
//
// Make sure that any macro V defined for use with the PER_ISOLATE_* macros is
// undefined again after use.
// Private symbols are per-isolate primitives but Environment proxies them
// for the sake of convenience. Strings should be ASCII-only and have a
// "node:" prefix to avoid name clashes with third-party code.
#define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \
V(alpn_buffer_private_symbol, "node:alpnBuffer") \
V(arrow_message_private_symbol, "node:arrowMessage") \
V(contextify_context_private_symbol, "node:contextify:context") \
V(contextify_global_private_symbol, "node:contextify:global") \
V(inspector_delegate_private_symbol, "node:inspector:delegate") \
V(decorated_private_symbol, "node:decorated") \
V(npn_buffer_private_symbol, "node:npnBuffer") \
V(processed_private_symbol, "node:processed") \
V(selected_npn_buffer_private_symbol, "node:selectedNpnBuffer") \
// Strings are per-isolate primitives but Environment proxies them
// for the sake of convenience. Strings should be ASCII-only.
#define PER_ISOLATE_STRING_PROPERTIES(V) \
V(address_string, "address") \
V(args_string, "args") \
V(async, "async") \
V(buffer_string, "buffer") \
V(bytes_string, "bytes") \
V(bytes_parsed_string, "bytesParsed") \
V(bytes_read_string, "bytesRead") \
V(cached_data_string, "cachedData") \
V(cached_data_produced_string, "cachedDataProduced") \
V(cached_data_rejected_string, "cachedDataRejected") \
V(callback_string, "callback") \
V(change_string, "change") \
V(channel_string, "channel") \
V(oncertcb_string, "oncertcb") \
V(onclose_string, "_onclose") \
V(code_string, "code") \
V(configurable_string, "configurable") \
V(cwd_string, "cwd") \
V(dest_string, "dest") \
V(detached_string, "detached") \
V(disposed_string, "_disposed") \
V(dns_a_string, "A") \
V(dns_aaaa_string, "AAAA") \
V(dns_cname_string, "CNAME") \
V(dns_mx_string, "MX") \
V(dns_naptr_string, "NAPTR") \
V(dns_ns_string, "NS") \
V(dns_ptr_string, "PTR") \
V(dns_soa_string, "SOA") \
V(dns_srv_string, "SRV") \
V(dns_txt_string, "TXT") \
V(domain_string, "domain") \
V(emitting_top_level_domain_error_string, "_emittingTopLevelDomainError") \
V(exchange_string, "exchange") \
V(enumerable_string, "enumerable") \
V(idle_string, "idle") \
V(irq_string, "irq") \
V(encoding_string, "encoding") \
V(enter_string, "enter") \
V(entries_string, "entries") \
V(env_pairs_string, "envPairs") \
V(errno_string, "errno") \
V(error_string, "error") \
V(events_string, "_events") \
V(exiting_string, "_exiting") \
V(exit_code_string, "exitCode") \
V(exit_string, "exit") \
V(expire_string, "expire") \
V(exponent_string, "exponent") \
V(exports_string, "exports") \
V(ext_key_usage_string, "ext_key_usage") \
V(external_stream_string, "_externalStream") \
V(family_string, "family") \
V(fatal_exception_string, "_fatalException") \
V(fd_string, "fd") \
V(file_string, "file") \
V(fingerprint_string, "fingerprint") \
V(flags_string, "flags") \
V(get_string, "get") \
V(get_data_clone_error_string, "_getDataCloneError") \
V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \
V(gid_string, "gid") \
V(handle_string, "handle") \
V(homedir_string, "homedir") \
V(hostmaster_string, "hostmaster") \
V(ignore_string, "ignore") \
V(immediate_callback_string, "_immediateCallback") \
V(infoaccess_string, "infoAccess") \
V(inherit_string, "inherit") \
V(input_string, "input") \
V(internal_string, "internal") \
V(ipv4_string, "IPv4") \
V(ipv6_string, "IPv6") \
V(isalive_string, "isAlive") \
V(isclosing_string, "isClosing") \
V(issuer_string, "issuer") \
V(issuercert_string, "issuerCertificate") \
V(kill_signal_string, "killSignal") \
V(length_string, "length") \
V(mac_string, "mac") \
V(max_buffer_string, "maxBuffer") \
V(message_string, "message") \
V(minttl_string, "minttl") \
V(model_string, "model") \
V(modulus_string, "modulus") \
V(name_string, "name") \
V(netmask_string, "netmask") \
V(nice_string, "nice") \
V(nsname_string, "nsname") \
V(ocsp_request_string, "OCSPRequest") \
V(onchange_string, "onchange") \
V(onclienthello_string, "onclienthello") \
V(oncomplete_string, "oncomplete") \
V(onconnection_string, "onconnection") \
V(ondone_string, "ondone") \
V(onerror_string, "onerror") \
V(onexit_string, "onexit") \
V(onhandshakedone_string, "onhandshakedone") \
V(onhandshakestart_string, "onhandshakestart") \
V(onmessage_string, "onmessage") \
V(onnewsession_string, "onnewsession") \
V(onnewsessiondone_string, "onnewsessiondone") \
V(onocspresponse_string, "onocspresponse") \
V(onread_string, "onread") \
V(onreadstart_string, "onreadstart") \
V(onreadstop_string, "onreadstop") \
V(onselect_string, "onselect") \
V(onshutdown_string, "onshutdown") \
V(onsignal_string, "onsignal") \
V(onstop_string, "onstop") \
V(onwrite_string, "onwrite") \
V(output_string, "output") \
V(order_string, "order") \
V(owner_string, "owner") \
V(parse_error_string, "Parse Error") \
V(path_string, "path") \
V(pbkdf2_error_string, "PBKDF2 Error") \
V(pid_string, "pid") \
V(pipe_string, "pipe") \
V(port_string, "port") \
V(preference_string, "preference") \
V(priority_string, "priority") \
V(produce_cached_data_string, "produceCachedData") \
V(raw_string, "raw") \
V(read_host_object_string, "_readHostObject") \
V(readable_string, "readable") \
V(received_shutdown_string, "receivedShutdown") \
V(refresh_string, "refresh") \
V(regexp_string, "regexp") \
V(rename_string, "rename") \
V(replacement_string, "replacement") \
V(retry_string, "retry") \
V(serial_string, "serial") \
V(scopeid_string, "scopeid") \
V(sent_shutdown_string, "sentShutdown") \
V(serial_number_string, "serialNumber") \
V(service_string, "service") \
V(servername_string, "servername") \
V(session_id_string, "sessionId") \
V(set_string, "set") \
V(shell_string, "shell") \
V(signal_string, "signal") \
V(size_string, "size") \
V(sni_context_err_string, "Invalid SNI context") \
V(sni_context_string, "sni_context") \
V(speed_string, "speed") \
V(stack_string, "stack") \
V(status_string, "status") \
V(stdio_string, "stdio") \
V(subject_string, "subject") \
V(subjectaltname_string, "subjectaltname") \
V(sys_string, "sys") \
V(syscall_string, "syscall") \
V(tick_callback_string, "_tickCallback") \
V(tick_domain_cb_string, "_tickDomainCallback") \
V(ticketkeycallback_string, "onticketkeycallback") \
V(timeout_string, "timeout") \
V(times_string, "times") \
V(tls_ticket_string, "tlsTicket") \
V(ttl_string, "ttl") \
V(type_string, "type") \
V(uid_string, "uid") \
V(unknown_string, "<unknown>") \
V(user_string, "user") \
V(username_string, "username") \
V(valid_from_string, "valid_from") \
V(valid_to_string, "valid_to") \
V(value_string, "value") \
V(verify_error_string, "verifyError") \
V(version_string, "version") \
V(weight_string, "weight") \
V(windows_verbatim_arguments_string, "windowsVerbatimArguments") \
V(wrap_string, "wrap") \
V(writable_string, "writable") \
V(write_host_object_string, "_writeHostObject") \
V(write_queue_size_string, "writeQueueSize") \
V(x_forwarded_string, "x-forwarded-for") \
V(zero_return_string, "ZERO_RETURN") \
#define ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V) \
V(as_external, v8::External) \
V(async_hooks_destroy_function, v8::Function) \
V(async_hooks_init_function, v8::Function) \
V(async_hooks_before_function, v8::Function) \
V(async_hooks_after_function, v8::Function) \
V(binding_cache_object, v8::Object) \
V(buffer_constructor_function, v8::Function) \
V(buffer_prototype_object, v8::Object) \
V(context, v8::Context) \
V(domain_array, v8::Array) \
V(domains_stack_array, v8::Array) \
V(jsstream_constructor_template, v8::FunctionTemplate) \
V(module_load_list_array, v8::Array) \
V(pbkdf2_constructor_template, v8::ObjectTemplate) \
V(pipe_constructor_template, v8::FunctionTemplate) \
V(process_object, v8::Object) \
V(promise_reject_function, v8::Function) \
V(promise_wrap_template, v8::ObjectTemplate) \
V(push_values_to_array_function, v8::Function) \
V(randombytes_constructor_template, v8::ObjectTemplate) \
V(script_context_constructor_template, v8::FunctionTemplate) \
V(script_data_constructor_function, v8::Function) \
V(secure_context_constructor_template, v8::FunctionTemplate) \
V(tcp_constructor_template, v8::FunctionTemplate) \
V(tick_callback_function, v8::Function) \
V(tls_wrap_constructor_function, v8::Function) \
V(tls_wrap_constructor_template, v8::FunctionTemplate) \
V(tty_constructor_template, v8::FunctionTemplate) \
V(udp_constructor_function, v8::Function) \
V(url_constructor_function, v8::Function) \
V(write_wrap_constructor_function, v8::Function) \
class IsolateData {
public:
inline IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
uint32_t* zero_fill_field = nullptr);
inline uv_loop_t* event_loop() const;
inline uint32_t* zero_fill_field() const;
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define V(TypeName, PropertyName) \
inline v8::Local<TypeName> PropertyName(v8::Isolate* isolate) const;
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V
#undef VS
#undef VP
private:
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define V(TypeName, PropertyName) \
v8::Eternal<TypeName> PropertyName ## _;
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V
#undef VS
#undef VP
uv_loop_t* const event_loop_;
uint32_t* const zero_fill_field_;
NODE_DISALLOW_COPY_AND_ASSIGN(IsolateData);
};
class Environment
{
public:
static const int kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX;
static inline Environment* GetCurrent(v8::Isolate* isolate);
static inline Environment* GetCurrent(v8::Local<v8::Context> context);
static inline Environment* GetCurrent(const v8::FunctionCallbackInfo<v8::Value>& info);
template <typename T>
static inline Environment* GetCurrent(const v8::PropertyCallbackInfo<T>& info);
inline Environment(IsolateData* isolate_data, v8::Local<v8::Context> context);
inline ~Environment();
void Start(int argc,
const char* const* argv,
int exec_argc,
const char* const* exec_argv,
bool start_profiler_idle_notifier);
void AssignToContext(v8::Local<v8::Context> context);
void CleanupHandles();
void StartProfilerIdleNotifier();
void StopProfilerIdleNotifier();
inline v8::Isolate* isolate() const
{
return isolate_;
}
inline IsolateData* isolate_data() const
{
return isolate_data_;
}
inline uv_loop_t* event_loop() const
{
return isolate_data()->event_loop();
}
inline inspector::Agent* inspector_agent() {
return &inspector_agent_;
}
// Strings and private symbols are shared across shared contexts
// The getters simply proxy to the per-isolate primitive.
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define V(TypeName, PropertyName) \
inline v8::Local<TypeName> PropertyName() const;
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V
#undef VS
#undef VP
#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> PropertyName() const; \
inline void set_ ## PropertyName(v8::Local<TypeName> value);
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V
inline void ThrowError(const char* errmsg);
inline void ThrowTypeError(const char* errmsg);
inline void ThrowRangeError(const char* errmsg);
inline void ThrowErrnoException(int errorno,
const char* syscall = nullptr,
const char* message = nullptr,
const char* path = nullptr);
inline void ThrowUVException(int errorno,
const char* syscall = nullptr,
const char* message = nullptr,
const char* path = nullptr,
const char* dest = nullptr);
inline v8::Local<v8::FunctionTemplate>
NewFunctionTemplate(v8::FunctionCallback callback,
v8::Local<v8::Signature> signature =
v8::Local<v8::Signature>());
// Convenience methods for NewFunctionTemplate().
inline void SetMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback);
class AsyncCallbackScope {
public:
AsyncCallbackScope() = delete;
explicit AsyncCallbackScope(Environment* env);
~AsyncCallbackScope();
inline bool in_makecallback();
private:
Environment* env_;
NODE_DISALLOW_COPY_AND_ASSIGN(AsyncCallbackScope);
};
private:
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
const char* errmsg);
v8::Isolate* const isolate_;
IsolateData* const isolate_data_;
#define V(PropertyName, TypeName) \
v8::Persistent<TypeName> PropertyName ## _;
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V
inspector::Agent inspector_agent_;
size_t makecallback_cntr_;
};
inline IsolateData::IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop,
uint32_t* zero_fill_field) :
// Create string and private symbol properties as internalized one byte strings.
//
// Internalized because it makes property lookups a little faster and because
// the string is created in the old space straight away. It's going to end up
// in the old space sooner or later anyway but now it doesn't go through
// v8::Eternal's new space handling first.
//
// One byte because our strings are ASCII and we can safely skip V8's UTF-8
// decoding step. It's a one-time cost, but why pay it when you don't have to?
#define V(PropertyName, StringValue) \
PropertyName ## _( \
isolate, \
v8::Private::New( \
isolate, \
v8::String::NewFromOneByte( \
isolate, \
reinterpret_cast<const uint8_t*>(StringValue), \
v8::NewStringType::kInternalized, \
sizeof(StringValue) - 1).ToLocalChecked())),
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
#undef V
#define V(PropertyName, StringValue) \
PropertyName ## _( \
isolate, \
v8::String::NewFromOneByte( \
isolate, \
reinterpret_cast<const uint8_t*>(StringValue), \
v8::NewStringType::kInternalized, \
sizeof(StringValue) - 1).ToLocalChecked()),
PER_ISOLATE_STRING_PROPERTIES(V)
#undef V
event_loop_(event_loop), zero_fill_field_(zero_fill_field) {}
inline uv_loop_t* IsolateData::event_loop() const {
return event_loop_;
}
inline uint32_t* IsolateData::zero_fill_field() const {
return zero_fill_field_;
}
inline Environment* Environment::GetCurrent(v8::Isolate* isolate) {
return GetCurrent(isolate->GetCurrentContext());
}
inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
return static_cast<Environment*>(
context->GetAlignedPointerFromEmbedderData(kContextEmbedderDataIndex));
}
inline Environment* Environment::GetCurrent(
const v8::FunctionCallbackInfo<v8::Value>& info) {
CHECK(info.Data()->IsExternal());
return static_cast<Environment*>(info.Data().As<v8::External>()->Value());
}
template <typename T>
inline Environment* Environment::GetCurrent(
const v8::PropertyCallbackInfo<T>& info) {
CHECK(info.Data()->IsExternal());
// XXX(bnoordhuis) Work around a g++ 4.9.2 template type inferrer bug
// when the expression is written as info.Data().As<v8::External>().
v8::Local<v8::Value> data = info.Data();
return static_cast<Environment*>(data.As<v8::External>()->Value());
}
inline Environment::Environment(IsolateData* isolate_data, v8::Local<v8::Context> context)
: isolate_(context->GetIsolate()),
isolate_data_(isolate_data),
makecallback_cntr_(0),
inspector_agent_(this),
context_(context->GetIsolate(), context) {
// We'll be creating new objects so make sure we've entered the context.
v8::HandleScope handle_scope(isolate());
v8::Context::Scope context_scope(context);
set_as_external(v8::External::New(isolate(), this));
set_binding_cache_object(v8::Object::New(isolate()));
set_module_load_list_array(v8::Array::New(isolate()));
AssignToContext(context);
//cjh destroy_ids_list_.reserve(512);
}
inline Environment::~Environment() {
v8::HandleScope handle_scope(isolate());
context()->SetAlignedPointerInEmbedderData(kContextEmbedderDataIndex,
nullptr);
#define V(PropertyName, TypeName) PropertyName ## _.Reset();
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V
// delete[] heap_statistics_buffer_;
// delete[] heap_space_statistics_buffer_;
// delete[] http_parser_buffer_;
}
inline void Environment::SetMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback) {
v8::Local<v8::Function> function =
NewFunctionTemplate(callback)->GetFunction(context()).ToLocalChecked();
// kInternalized strings are created in the old space.
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->Set(context(), name_string, function);
function->SetName(name_string); // NODE_SET_METHOD() compatibility.
}
inline void Environment::ThrowError(const char* errmsg) {
ThrowError(v8::Exception::Error, errmsg);
}
inline void Environment::ThrowTypeError(const char* errmsg) {
ThrowError(v8::Exception::TypeError, errmsg);
}
inline void Environment::ThrowRangeError(const char* errmsg) {
ThrowError(v8::Exception::RangeError, errmsg);
}
inline void Environment::ThrowError(
v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
const char* errmsg) {
v8::HandleScope handle_scope(isolate());
isolate()->ThrowException(fun(OneByteString(isolate(), errmsg)));
}
inline void Environment::ThrowErrnoException(int errorno,
const char* syscall,
const char* message,
const char* path) {
isolate()->ThrowException(
ErrnoException(isolate(), errorno, syscall, message, path));
}
inline void Environment::ThrowUVException(int errorno,
const char* syscall,
const char* message,
const char* path,
const char* dest) {
isolate()->ThrowException(
UVException(isolate(), errorno, syscall, message, path, dest));
}
inline v8::Local<v8::FunctionTemplate>
Environment::NewFunctionTemplate(v8::FunctionCallback callback,
v8::Local<v8::Signature> signature) {
v8::Local<v8::External> external = as_external();
return v8::FunctionTemplate::New(isolate(), callback, external, signature);
}
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define V(TypeName, PropertyName) \
inline \
v8::Local<TypeName> IsolateData::PropertyName(v8::Isolate* isolate) const { \
/* Strings are immutable so casting away const-ness here is okay. */ \
return const_cast<IsolateData*>(this)->PropertyName ## _.Get(isolate); \
}
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V
#undef VS
#undef VP
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define V(TypeName, PropertyName) \
inline v8::Local<TypeName> Environment::PropertyName() const { \
return isolate_data()->PropertyName(isolate()); \
}
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_STRING_PROPERTIES(VS)
#undef V
#undef VS
#undef VP
#define V(PropertyName, TypeName) \
inline v8::Local<TypeName> Environment::PropertyName() const { \
return StrongPersistentToLocal(PropertyName ## _); \
} \
inline void Environment::set_ ## PropertyName(v8::Local<TypeName> value) { \
PropertyName ## _.Reset(isolate(), value); \
}
ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
#undef V
inline Environment::AsyncCallbackScope::AsyncCallbackScope(Environment* env)
: env_(env) {
env_->makecallback_cntr_++;
}
inline Environment::AsyncCallbackScope::~AsyncCallbackScope() {
env_->makecallback_cntr_--;
}
inline bool Environment::AsyncCallbackScope::in_makecallback() {
return env_->makecallback_cntr_ > 1;
}
} // namespace node {
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,369 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* 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 http_parser_h
#define http_parser_h
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 7
#define HTTP_PARSER_VERSION_PATCH 0
#include <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__) && \
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
#include <BaseTsd.h>
#include <stddef.h>
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
/* Callbacks should return non-zero to indicate an error. The parser will
* then halt execution.
*
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
* returning '1' from on_headers_complete will tell the parser that it
* should not expect a body. This is used when receiving a response to a
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body.
*
* Returning `2` from on_headers_complete will tell parser that it should not
* expect neither a body nor any futher responses on this connection. This is
* useful for handling responses to a CONNECT request which may not contain
* `Upgrade` or `Connection: upgrade` headers.
*
* http_data_cb does not return data chunks. It will be called arbitrarily
* many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data.
*/
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* WebDAV */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
/* subversion */ \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
/* upnp */ \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
/* CalDAV */ \
XX(30, MKCALENDAR, MKCALENDAR) \
/* RFC-2068, section 19.6.1.2 */ \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
enum http_method
{
#define XX(num, name, string) HTTP_##name = num,
HTTP_METHOD_MAP(XX)
#undef XX
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
, F_CONTENTLENGTH = 1 << 7
};
/* Map for errno-related constants
*
* The provided argument should be a macro that takes 2 arguments.
*/
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
XX(CB_chunk_header, "the on_chunk_header callback failed") \
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
XX(UNEXPECTED_CONTENT_LENGTH, \
"unexpected content-length header") \
XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred")
/* Define HPE_* values for each errno value above */
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
#undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
/** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 7; /* enum state from http_parser.c */
unsigned int header_state : 7; /* enum header_state from http_parser.c */
unsigned int index : 7; /* index into current matcher */
unsigned int lenient_http_headers : 1;
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
/* Returns the library version. Bits 16-23 contain the major version number,
* bits 8-15 the minor version number and bits 0-7 the patch level.
* Usage example:
*
* unsigned long version = http_parser_version();
* unsigned major = (version >> 16) & 255;
* unsigned minor = (version >> 8) & 255;
* unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/
unsigned long http_parser_version(void);
void http_parser_init(http_parser *parser, enum http_parser_type type);
/* Initialize http_parser_settings members to 0
*/
void http_parser_settings_init(http_parser_settings *settings);
/* Executes the parser. Returns number of parsed bytes. Sets
* `parser->http_errno` on error. */
size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len);
/* If http_should_keep_alive() in the on_headers_complete or
* on_message_complete callback returns 0, then this should be
* the last message on the connection.
* If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection.
*/
int http_should_keep_alive(const http_parser *parser);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Initialize all http_parser_url members to 0 */
void http_parser_url_init(struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
/* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser);
#ifdef __cplusplus
}
#endif
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif

View File

@@ -0,0 +1,815 @@
#include "inspector_agent.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "inspector_io.h"
#include "env.h"
#include "node.h"
#include "v8-inspector.h"
#include "v8-platform.h"
#include "util.h"
#include "zlib.h"
#include "libplatform/libplatform.h"
#include <string.h>
#include <unordered_map>
#include <vector>
#ifdef __POSIX__
#include <unistd.h> // setuid, getuid
#endif // __POSIX__
namespace node {
namespace inspector {
namespace {
using v8::Context;
using v8::External;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Maybe;
using v8::MaybeLocal;
using v8::NewStringType;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
using v8_inspector::StringBuffer;
using v8_inspector::StringView;
using v8_inspector::V8Inspector;
using v8_inspector::V8InspectorClient;
static uv_sem_t start_io_thread_semaphore;
static uv_async_t start_io_thread_async;
class StartIoTask : public v8::Task {
public:
explicit StartIoTask(Agent* agent) : agent(agent) {}
void Run() override {
agent->StartIoThread(false);
}
private:
Agent* agent;
};
std::unique_ptr<StringBuffer> ToProtocolString(Isolate* isolate,
Local<Value> value) {
TwoByteValue buffer(isolate, value);
return StringBuffer::create(StringView(*buffer, buffer.length()));
}
// Called on the main thread.
void StartIoThreadAsyncCallback(uv_async_t* handle) {
static_cast<Agent*>(handle->data)->StartIoThread(false);
}
void StartIoInterrupt(Isolate* isolate, void* agent) {
static_cast<Agent*>(agent)->StartIoThread(false);
}
#ifdef __POSIX__
static void StartIoThreadWakeup(int signo) {
uv_sem_post(&start_io_thread_semaphore);
}
inline void* StartIoThreadMain(void* unused) {
for (;;) {
uv_sem_wait(&start_io_thread_semaphore);
Agent* agent = static_cast<Agent*>(start_io_thread_async.data);
if (agent != nullptr)
agent->RequestIoThreadStart();
}
return nullptr;
}
static int StartDebugSignalHandler() {
// Start a watchdog thread for calling v8::Debug::DebugBreak() because
// it's not safe to call directly from the signal handler, it can
// deadlock with the thread it interrupts.
CHECK_EQ(0, uv_sem_init(&start_io_thread_semaphore, 0));
pthread_attr_t attr;
CHECK_EQ(0, pthread_attr_init(&attr));
// Don't shrink the thread's stack on FreeBSD. Said platform decided to
// follow the pthreads specification to the letter rather than in spirit:
// https://lists.freebsd.org/pipermail/freebsd-current/2014-March/048885.html
#ifndef __FreeBSD__
CHECK_EQ(0, pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN));
#endif // __FreeBSD__
CHECK_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
sigset_t sigmask;
// Mask all signals.
sigfillset(&sigmask);
CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &sigmask));
pthread_t thread;
const int err = pthread_create(&thread, &attr,
StartIoThreadMain, nullptr);
// Restore original mask
CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr));
CHECK_EQ(0, pthread_attr_destroy(&attr));
if (err != 0) {
SE_LOGE("node[%d]: pthread_create: %s\n", getpid(), strerror(err));
// Leave SIGUSR1 blocked. We don't install a signal handler,
// receiving the signal would terminate the process.
return -err;
}
RegisterSignalHandler(SIGUSR1, StartIoThreadWakeup);
// Unblock SIGUSR1. A pending SIGUSR1 signal will now be delivered.
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGUSR1);
CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sigmask, nullptr));
return 0;
}
#endif // __POSIX__
#ifdef _WIN32
DWORD WINAPI StartIoThreadProc(void* arg) {
Agent* agent = static_cast<Agent*>(start_io_thread_async.data);
if (agent != nullptr)
agent->RequestIoThreadStart();
return 0;
}
static int GetDebugSignalHandlerMappingName(DWORD pid, wchar_t* buf,
size_t buf_len) {
return _snwprintf(buf, buf_len, L"node-debug-handler-%u", pid);
}
static int StartDebugSignalHandler() {
wchar_t mapping_name[32];
HANDLE mapping_handle;
DWORD pid;
LPTHREAD_START_ROUTINE* handler;
pid = GetCurrentProcessId();
if (GetDebugSignalHandlerMappingName(pid,
mapping_name,
arraysize(mapping_name)) < 0) {
return -1;
}
mapping_handle = CreateFileMappingW(INVALID_HANDLE_VALUE,
nullptr,
PAGE_READWRITE,
0,
sizeof *handler,
mapping_name);
if (mapping_handle == nullptr) {
return -1;
}
handler = reinterpret_cast<LPTHREAD_START_ROUTINE*>(
MapViewOfFile(mapping_handle,
FILE_MAP_ALL_ACCESS,
0,
0,
sizeof *handler));
if (handler == nullptr) {
CloseHandle(mapping_handle);
return -1;
}
*handler = StartIoThreadProc;
UnmapViewOfFile(static_cast<void*>(handler));
return 0;
}
#endif // _WIN32
class JsBindingsSessionDelegate : public InspectorSessionDelegate {
public:
JsBindingsSessionDelegate(Environment* env,
Local<Object> session,
Local<Object> receiver,
Local<Function> callback)
: env_(env),
session_(env->isolate(), session),
receiver_(env->isolate(), receiver),
callback_(env->isolate(), callback) {
session_.SetWeak(this, JsBindingsSessionDelegate::Release,
v8::WeakCallbackType::kParameter);
}
~JsBindingsSessionDelegate() override {
session_.Reset();
receiver_.Reset();
callback_.Reset();
}
bool WaitForFrontendMessageWhilePaused() override {
return false;
}
void SendMessageToFrontend(const v8_inspector::StringView& message) override {
Isolate* isolate = env_->isolate();
v8::HandleScope handle_scope(isolate);
Context::Scope context_scope(env_->context());
MaybeLocal<String> v8string =
String::NewFromTwoByte(isolate, message.characters16(),
NewStringType::kNormal, message.length());
Local<Value> argument = v8string.ToLocalChecked().As<Value>();
Local<Function> callback = callback_.Get(isolate);
Local<Object> receiver = receiver_.Get(isolate);
callback->Call(env_->context(), receiver, 1, &argument)
.FromMaybe(Local<Value>());
}
void Disconnect() {
Agent* agent = env_->inspector_agent();
if (agent->delegate() == this)
agent->Disconnect();
}
private:
static void Release(
const v8::WeakCallbackInfo<JsBindingsSessionDelegate>& info) {
info.SetSecondPassCallback(ReleaseSecondPass);
info.GetParameter()->session_.Reset();
}
static void ReleaseSecondPass(
const v8::WeakCallbackInfo<JsBindingsSessionDelegate>& info) {
JsBindingsSessionDelegate* delegate = info.GetParameter();
delegate->Disconnect();
delete delegate;
}
Environment* env_;
Persistent<Object> session_;
Persistent<Object> receiver_;
Persistent<Function> callback_;
};
void SetDelegate(Environment* env, Local<Object> inspector,
JsBindingsSessionDelegate* delegate) {
inspector->SetPrivate(env->context(),
env->inspector_delegate_private_symbol(),
v8::External::New(env->isolate(), delegate));
}
Maybe<JsBindingsSessionDelegate*> GetDelegate(
const FunctionCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
Local<Value> delegate;
MaybeLocal<Value> maybe_delegate =
info.This()->GetPrivate(env->context(),
env->inspector_delegate_private_symbol());
if (maybe_delegate.ToLocal(&delegate)) {
CHECK(delegate->IsExternal());
void* value = delegate.As<External>()->Value();
if (value != nullptr) {
return v8::Just(static_cast<JsBindingsSessionDelegate*>(value));
}
}
env->ThrowError("Inspector is not connected");
return v8::Nothing<JsBindingsSessionDelegate*>();
}
void Dispatch(const FunctionCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
if (!info[0]->IsString()) {
env->ThrowError("Inspector message must be a string");
return;
}
Maybe<JsBindingsSessionDelegate*> maybe_delegate = GetDelegate(info);
if (maybe_delegate.IsNothing())
return;
Agent* inspector = env->inspector_agent();
CHECK_EQ(maybe_delegate.ToChecked(), inspector->delegate());
inspector->Dispatch(ToProtocolString(env->isolate(), info[0])->string());
}
void Disconnect(const FunctionCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
Maybe<JsBindingsSessionDelegate*> delegate = GetDelegate(info);
if (delegate.IsNothing()) {
return;
}
delegate.ToChecked()->Disconnect();
SetDelegate(env, info.This(), nullptr);
delete delegate.ToChecked();
}
void ConnectJSBindingsSession(const FunctionCallbackInfo<Value>& info) {
Environment* env = Environment::GetCurrent(info);
if (!info[0]->IsFunction()) {
env->ThrowError("Message callback is required");
return;
}
Agent* inspector = env->inspector_agent();
if (inspector->delegate() != nullptr) {
env->ThrowError("Session is already attached");
return;
}
Local<Object> session = Object::New(env->isolate());
env->SetMethod(session, "dispatch", Dispatch);
env->SetMethod(session, "disconnect", Disconnect);
info.GetReturnValue().Set(session);
JsBindingsSessionDelegate* delegate =
new JsBindingsSessionDelegate(env, session, info.Holder(),
info[0].As<Function>());
inspector->Connect(delegate);
SetDelegate(env, session, delegate);
}
void InspectorConsoleCall(const v8::FunctionCallbackInfo<Value>& info) {
Isolate* isolate = info.GetIsolate();
HandleScope handle_scope(isolate);
Local<Context> context = isolate->GetCurrentContext();
CHECK_LT(2, info.Length());
std::vector<Local<Value>> call_args;
for (int i = 3; i < info.Length(); ++i) {
call_args.push_back(info[i]);
}
Environment* env = Environment::GetCurrent(isolate);
if (env->inspector_agent()->enabled()) {
Local<Value> inspector_method = info[0];
CHECK(inspector_method->IsFunction());
Local<Value> config_value = info[2];
CHECK(config_value->IsObject());
Local<Object> config_object = config_value.As<Object>();
Local<String> in_call_key = FIXED_ONE_BYTE_STRING(isolate, "in_call");
if (!config_object->Has(context, in_call_key).FromMaybe(false)) {
CHECK(config_object->Set(context,
in_call_key,
v8::True(isolate)).FromJust());
CHECK(!inspector_method.As<Function>()->Call(context,
info.Holder(),
call_args.size(),
call_args.data()).IsEmpty());
}
CHECK(config_object->Delete(context, in_call_key).FromJust());
}
Local<Value> node_method = info[1];
CHECK(node_method->IsFunction());
node_method.As<Function>()->Call(context,
info.Holder(),
call_args.size(),
call_args.data()).FromMaybe(Local<Value>());
}
void CallAndPauseOnStart(
const v8::FunctionCallbackInfo<v8::Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_GT(args.Length(), 1);
CHECK(args[0]->IsFunction());
std::vector<v8::Local<v8::Value>> call_args;
for (int i = 2; i < args.Length(); i++) {
call_args.push_back(args[i]);
}
env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
v8::MaybeLocal<v8::Value> retval =
args[0].As<v8::Function>()->Call(env->context(), args[1],
call_args.size(), call_args.data());
if (!retval.IsEmpty()) {
args.GetReturnValue().Set(retval.ToLocalChecked());
}
}
// Used in NodeInspectorClient::currentTimeMS() below.
const int NANOS_PER_MSEC = 1000000;
const int CONTEXT_GROUP_ID = 1;
class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
public:
explicit ChannelImpl(V8Inspector* inspector,
InspectorSessionDelegate* delegate)
: delegate_(delegate) {
session_ = inspector->connect(1, this, StringView());
}
virtual ~ChannelImpl() {}
void dispatchProtocolMessage(const StringView& message) {
session_->dispatchProtocolMessage(message);
}
bool waitForFrontendMessage() {
return delegate_->WaitForFrontendMessageWhilePaused();
}
void schedulePauseOnNextStatement(const std::string& reason) {
std::unique_ptr<StringBuffer> buffer = Utf8ToStringView(reason);
session_->schedulePauseOnNextStatement(buffer->string(), buffer->string());
}
InspectorSessionDelegate* delegate() {
return delegate_;
}
private:
void sendResponse(
int callId,
std::unique_ptr<v8_inspector::StringBuffer> message) override {
sendMessageToFrontend(message->string());
}
void sendNotification(
std::unique_ptr<v8_inspector::StringBuffer> message) override {
sendMessageToFrontend(message->string());
}
void flushProtocolNotifications() override { }
void sendMessageToFrontend(const StringView& message) {
delegate_->SendMessageToFrontend(message);
}
InspectorSessionDelegate* const delegate_;
std::unique_ptr<v8_inspector::V8InspectorSession> session_;
};
class InspectorTimer {
public:
InspectorTimer(uv_loop_t* loop,
double interval_s,
V8InspectorClient::TimerCallback callback,
void* data) : timer_(),
callback_(callback),
data_(data) {
uv_timer_init(loop, &timer_);
int64_t interval_ms = 1000 * interval_s;
uv_timer_start(&timer_, OnTimer, interval_ms, interval_ms);
}
InspectorTimer(const InspectorTimer&) = delete;
void Stop() {
uv_timer_stop(&timer_);
uv_close(reinterpret_cast<uv_handle_t*>(&timer_), TimerClosedCb);
}
private:
static void OnTimer(uv_timer_t* uvtimer) {
InspectorTimer* timer = node::ContainerOf(&InspectorTimer::timer_, uvtimer);
timer->callback_(timer->data_);
}
static void TimerClosedCb(uv_handle_t* uvtimer) {
InspectorTimer* timer =
node::ContainerOf(&InspectorTimer::timer_,
reinterpret_cast<uv_timer_t*>(uvtimer));
delete timer;
}
~InspectorTimer() {}
uv_timer_t timer_;
V8InspectorClient::TimerCallback callback_;
void* data_;
};
class InspectorTimerHandle {
public:
InspectorTimerHandle(uv_loop_t* loop, double interval_s,
V8InspectorClient::TimerCallback callback, void* data) {
timer_ = new InspectorTimer(loop, interval_s, callback, data);
}
InspectorTimerHandle(const InspectorTimerHandle&) = delete;
~InspectorTimerHandle() {
CHECK_NE(timer_, nullptr);
timer_->Stop();
timer_ = nullptr;
}
private:
InspectorTimer* timer_;
};
} // namespace
class NodeInspectorClient : public V8InspectorClient {
public:
NodeInspectorClient(node::Environment* env,
v8::Platform* platform) : env_(env),
platform_(platform),
terminated_(false),
running_nested_loop_(false) {
client_ = V8Inspector::create(env->isolate(), this);
}
void runMessageLoopOnPause(int context_group_id) override {
CHECK_NE(channel_, nullptr);
if (running_nested_loop_)
return;
terminated_ = false;
running_nested_loop_ = true;
while (!terminated_ && channel_->waitForFrontendMessage()) {
while (v8::platform::PumpMessageLoop(platform_, env_->isolate()))
{}
}
terminated_ = false;
running_nested_loop_ = false;
}
double currentTimeMS() override {
return uv_hrtime() * 1.0 / NANOS_PER_MSEC;
}
void contextCreated(Local<Context> context, const std::string& name) {
std::unique_ptr<StringBuffer> name_buffer = Utf8ToStringView(name);
v8_inspector::V8ContextInfo info(context, CONTEXT_GROUP_ID,
name_buffer->string());
client_->contextCreated(info);
}
void contextDestroyed(Local<Context> context) {
client_->contextDestroyed(context);
}
void quitMessageLoopOnPause() override {
terminated_ = true;
}
void connectFrontend(InspectorSessionDelegate* delegate) {
CHECK_EQ(channel_, nullptr);
channel_ = std::unique_ptr<ChannelImpl>(
new ChannelImpl(client_.get(), delegate));
}
void disconnectFrontend() {
quitMessageLoopOnPause();
channel_.reset();
}
void dispatchMessageFromFrontend(const StringView& message) {
CHECK_NE(channel_, nullptr);
channel_->dispatchProtocolMessage(message);
}
Local<Context> ensureDefaultContextInGroup(int contextGroupId) override {
return env_->context();
}
void FatalException(Local<Value> error, Local<v8::Message> message) {
Local<Context> context = env_->context();
int script_id = message->GetScriptOrigin().ScriptID()->Value();
Local<v8::StackTrace> stack_trace = message->GetStackTrace();
if (!stack_trace.IsEmpty() &&
stack_trace->GetFrameCount() > 0 &&
script_id == stack_trace->GetFrame(env_->isolate(), 0)->GetScriptId()) {
script_id = 0;
}
const uint8_t DETAILS[] = "Uncaught";
Isolate* isolate = context->GetIsolate();
client_->exceptionThrown(
context,
StringView(DETAILS, sizeof(DETAILS) - 1),
error,
ToProtocolString(isolate, message->Get())->string(),
ToProtocolString(isolate, message->GetScriptResourceName())->string(),
message->GetLineNumber(context).FromMaybe(0),
message->GetStartColumn(context).FromMaybe(0),
client_->createStackTrace(stack_trace),
script_id);
}
ChannelImpl* channel() {
return channel_.get();
}
void startRepeatingTimer(double interval_s,
TimerCallback callback,
void* data) override {
timers_.emplace(std::piecewise_construct, std::make_tuple(data),
std::make_tuple(env_->event_loop(), interval_s, callback,
data));
}
void cancelTimer(void* data) override {
timers_.erase(data);
}
private:
node::Environment* env_;
v8::Platform* platform_;
bool terminated_;
bool running_nested_loop_;
std::unique_ptr<V8Inspector> client_;
std::unique_ptr<ChannelImpl> channel_;
std::unordered_map<void*, InspectorTimerHandle> timers_;
};
Agent::Agent(Environment* env) : parent_env_(env),
client_(nullptr),
platform_(nullptr),
enabled_(false) {}
// Destructor needs to be defined here in implementation file as the header
// does not have full definition of some classes.
Agent::~Agent() {
}
bool Agent::Start(v8::Platform* platform, const char* path,
const DebugOptions& options) {
path_ = path == nullptr ? "" : path;
debug_options_ = options;
client_ =
std::unique_ptr<NodeInspectorClient>(
new NodeInspectorClient(parent_env_, platform));
client_->contextCreated(parent_env_->context(), "Node.js Main Context");
platform_ = platform;
CHECK_EQ(0, uv_async_init(uv_default_loop(),
&start_io_thread_async,
StartIoThreadAsyncCallback));
start_io_thread_async.data = this;
uv_unref(reinterpret_cast<uv_handle_t*>(&start_io_thread_async));
// Ignore failure, SIGUSR1 won't work, but that should not block node start.
StartDebugSignalHandler();
if (options.inspector_enabled()) {
// This will return false if listen failed on the inspector port.
return StartIoThread(options.wait_for_connect());
}
return true;
}
bool Agent::StartIoThread(bool wait_for_connect) {
if (io_ != nullptr)
return true;
CHECK_NE(client_, nullptr);
enabled_ = true;
io_ = std::unique_ptr<InspectorIo>(
new InspectorIo(parent_env_, platform_, path_, debug_options_,
wait_for_connect));
if (!io_->Start()) {
client_.reset();
return false;
}
v8::Isolate* isolate = parent_env_->isolate();
// Send message to enable debug in workers
HandleScope handle_scope(isolate);
Local<Object> process_object = parent_env_->process_object();
Local<Value> emit_fn =
process_object->Get(isolate->GetCurrentContext(), FIXED_ONE_BYTE_STRING(isolate, "emit")).ToLocalChecked();
// In case the thread started early during the startup
if (!emit_fn->IsFunction())
return true;
Local<Object> message = Object::New(isolate);
message->Set(parent_env_->context(), FIXED_ONE_BYTE_STRING(isolate, "cmd"),
FIXED_ONE_BYTE_STRING(isolate, "NODE_DEBUG_ENABLED"));
Local<Value> argv[] = {
FIXED_ONE_BYTE_STRING(isolate, "internalMessage"),
message
};
MakeCallback(parent_env_->isolate(), process_object, emit_fn.As<Function>(),
arraysize(argv), argv, {0, 0});
return true;
}
void Agent::Stop() {
if (io_ != nullptr) {
io_->Stop();
io_.reset();
}
}
void Agent::Connect(InspectorSessionDelegate* delegate) {
enabled_ = true;
client_->connectFrontend(delegate);
}
bool Agent::IsConnected() {
return io_ && io_->IsConnected();
}
void Agent::WaitForDisconnect() {
CHECK_NE(client_, nullptr);
client_->contextDestroyed(parent_env_->context());
if (io_ != nullptr) {
io_->WaitForDisconnect();
}
}
void Agent::FatalException(Local<Value> error, Local<v8::Message> message) {
if (!IsStarted())
return;
client_->FatalException(error, message);
WaitForDisconnect();
}
void Agent::Dispatch(const StringView& message) {
CHECK_NE(client_, nullptr);
client_->dispatchMessageFromFrontend(message);
}
void Agent::Disconnect() {
CHECK_NE(client_, nullptr);
client_->disconnectFrontend();
}
void Agent::RunMessageLoop() {
CHECK_NE(client_, nullptr);
client_->runMessageLoopOnPause(CONTEXT_GROUP_ID);
}
InspectorSessionDelegate* Agent::delegate() {
CHECK_NE(client_, nullptr);
ChannelImpl* channel = client_->channel();
if (channel == nullptr)
return nullptr;
return channel->delegate();
}
void Agent::PauseOnNextJavascriptStatement(const std::string& reason) {
ChannelImpl* channel = client_->channel();
if (channel != nullptr)
channel->schedulePauseOnNextStatement(reason);
}
void Open(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
inspector::Agent* agent = env->inspector_agent();
bool wait_for_connect = false;
if (args.Length() > 0 && args[0]->IsUint32()) {
uint32_t port = args[0]->Uint32Value(env->context()).ToChecked();
agent->options().set_port(static_cast<int>(port));
}
if (args.Length() > 1 && args[1]->IsString()) {
node::Utf8Value host(env->isolate(), args[1].As<String>());
agent->options().set_host_name(*host);
}
if (args.Length() > 2 && args[2]->IsBoolean()) {
wait_for_connect = args[2]->BooleanValue(env->isolate());
}
agent->StartIoThread(wait_for_connect);
}
void Url(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
inspector::Agent* agent = env->inspector_agent();
inspector::InspectorIo* io = agent->io();
if (!io) return;
std::vector<std::string> ids = io->GetTargetIds();
if (ids.empty()) return;
std::string url = FormatWsAddress(io->host(), io->port(), ids[0], true);
args.GetReturnValue().Set(OneByteString(env->isolate(), url.c_str()));
}
// static
void Agent::InitInspector(Local<Object> target, Local<Value> unused,
Local<Context> context, void* priv) {
Environment* env = Environment::GetCurrent(context);
Agent* agent = env->inspector_agent();
env->SetMethod(target, "consoleCall", InspectorConsoleCall);
if (agent->debug_options_.wait_for_connect())
env->SetMethod(target, "callAndPauseOnStart", CallAndPauseOnStart);
env->SetMethod(target, "connect", ConnectJSBindingsSession);
env->SetMethod(target, "open", Open);
env->SetMethod(target, "url", Url);
}
void Agent::RequestIoThreadStart() {
// We need to attempt to interrupt V8 flow (in case Node is running
// continuous JS code) and to wake up libuv thread (in case Node is waiting
// for IO events)
uv_async_send(&start_io_thread_async);
v8::Isolate* isolate = parent_env_->isolate();
platform_->CallOnForegroundThread(isolate, new StartIoTask(this));
isolate->RequestInterrupt(StartIoInterrupt, this);
uv_async_send(&start_io_thread_async);
}
} // namespace inspector
} // namespace node
//cjh NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector,
// node::inspector::Agent::InitInspector);
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,118 @@
#ifndef SRC_INSPECTOR_AGENT_H_
#define SRC_INSPECTOR_AGENT_H_
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include <memory>
#include <stddef.h>
#if !HAVE_INSPECTOR
#error("This header can only be used when inspector is enabled")
#endif
#include "node_debug_options.h"
// Forward declaration to break recursive dependency chain with src/env.h.
namespace node {
class Environment;
} // namespace node
namespace v8 {
class Context;
template <typename V>
class FunctionCallbackInfo;
template<typename T>
class Local;
class Message;
class Object;
class Platform;
class Value;
} // namespace v8
namespace v8_inspector {
class StringView;
} // namespace v8_inspector
namespace node {
namespace inspector {
class InspectorSessionDelegate {
public:
virtual ~InspectorSessionDelegate() = default;
virtual bool WaitForFrontendMessageWhilePaused() = 0;
virtual void SendMessageToFrontend(const v8_inspector::StringView& message)
= 0;
};
class InspectorIo;
class NodeInspectorClient;
class Agent {
public:
explicit Agent(node::Environment* env);
~Agent();
// Create client_, may create io_ if option enabled
bool Start(v8::Platform* platform, const char* path,
const DebugOptions& options);
// Stop and destroy io_
void Stop();
bool IsStarted() { return !!client_; }
// IO thread started, and client connected
bool IsConnected();
void WaitForDisconnect();
void FatalException(v8::Local<v8::Value> error,
v8::Local<v8::Message> message);
// These methods are called by the WS protocol and JS binding to create
// inspector sessions. The inspector responds by using the delegate to send
// messages back.
void Connect(InspectorSessionDelegate* delegate);
void Disconnect();
void Dispatch(const v8_inspector::StringView& message);
InspectorSessionDelegate* delegate();
void RunMessageLoop();
bool enabled() { return enabled_; }
void PauseOnNextJavascriptStatement(const std::string& reason);
// Initialize 'inspector' module bindings
static void InitInspector(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv);
InspectorIo* io() {
return io_.get();
}
// Can only be called from the the main thread.
bool StartIoThread(bool wait_for_connect);
// Calls StartIoThread() from off the main thread.
void RequestIoThreadStart();
DebugOptions& options() { return debug_options_; }
private:
node::Environment* parent_env_;
std::unique_ptr<NodeInspectorClient> client_;
std::unique_ptr<InspectorIo> io_;
v8::Platform* platform_;
bool enabled_;
std::string path_;
DebugOptions debug_options_;
};
} // namespace inspector
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif // SRC_INSPECTOR_AGENT_H_

View File

@@ -0,0 +1,535 @@
#include "inspector_io.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "inspector_socket_server.h"
#include "env.h"
#include "node.h"
//cjh #include "node_crypto.h"
#include "node_mutex.h"
#include "v8-inspector.h"
#include "util.h"
#include "zlib.h"
#include "libplatform/libplatform.h"
#include <sstream>
//cjh #include <unicode/unistr.h>
#include <string.h>
#include <vector>
#include "base/ccUTF8.h" //cjh added
namespace node {
namespace inspector {
namespace {
using AsyncAndAgent = std::pair<uv_async_t, Agent*>;
using v8_inspector::StringBuffer;
using v8_inspector::StringView;
template<typename Transport>
using TransportAndIo = std::pair<Transport*, InspectorIo*>;
std::string GetProcessTitle() {
char title[2048];
int err = uv_get_process_title(title, sizeof(title));
if (err == 0) {
return title;
} else {
// Title is too long, or could not be retrieved.
return "Node.js";
}
}
std::string ScriptPath(uv_loop_t* loop, const std::string& script_name) {
std::string script_path;
if (!script_name.empty()) {
uv_fs_t req;
req.ptr = nullptr;
if (0 == uv_fs_realpath(loop, &req, script_name.c_str(), nullptr)) {
CHECK_NE(req.ptr, nullptr);
script_path = std::string(static_cast<char*>(req.ptr));
}
uv_fs_req_cleanup(&req);
}
return script_path;
}
// UUID RFC: https://www.ietf.org/rfc/rfc4122.txt
// Used ver 4 - with numbers
std::string GenerateID() {
// uint16_t buffer[8];
//cjh same uuid
uint16_t buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
//cjh
//cjh CHECK(crypto::EntropySource(reinterpret_cast<unsigned char*>(buffer),
// sizeof(buffer)));
char uuid[256];
snprintf(uuid, sizeof(uuid), "%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
buffer[0], // time_low
buffer[1], // time_mid
buffer[2], // time_low
(buffer[3] & 0x0fff) | 0x4000, // time_hi_and_version
(buffer[4] & 0x3fff) | 0x8000, // clk_seq_hi clk_seq_low
buffer[5], // node
buffer[6],
buffer[7]);
return uuid;
}
std::string StringViewToUtf8(const StringView& view) {
if (view.is8Bit()) {
return std::string(reinterpret_cast<const char*>(view.characters8()),
view.length());
}
const uint16_t* source = view.characters16();
std::u16string u16Str((char16_t*)source);
std::string ret;
cocos2d::StringUtils::UTF16ToUTF8(u16Str, ret);
return ret;
// const UChar* unicodeSource = reinterpret_cast<const UChar*>(source);
// static_assert(sizeof(*source) == sizeof(*unicodeSource),
// "sizeof(*source) == sizeof(*unicodeSource)");
//
// size_t result_length = view.length() * sizeof(*source);
// std::string result(result_length, '\0');
//cjh UnicodeString utf16(unicodeSource, view.length());
// // ICU components for std::string compatibility are not enabled in build...
// bool done = false;
// while (!done) {
// CheckedArrayByteSink sink(&result[0], result_length);
// utf16.toUTF8(sink);
// result_length = sink.NumberOfBytesAppended();
// result.resize(result_length);
// done = !sink.Overflowed();
// }
// return result;
return "";
}
void HandleSyncCloseCb(uv_handle_t* handle) {
*static_cast<bool*>(handle->data) = true;
}
int CloseAsyncAndLoop(uv_async_t* async) {
bool is_closed = false;
async->data = &is_closed;
uv_close(reinterpret_cast<uv_handle_t*>(async), HandleSyncCloseCb);
while (!is_closed)
uv_run(async->loop, UV_RUN_ONCE);
async->data = nullptr;
return uv_loop_close(async->loop);
}
// Delete main_thread_req_ on async handle close
void ReleasePairOnAsyncClose(uv_handle_t* async) {
AsyncAndAgent* pair = node::ContainerOf(&AsyncAndAgent::first,
reinterpret_cast<uv_async_t*>(async));
delete pair;
}
} // namespace
std::unique_ptr<StringBuffer> Utf8ToStringView(const std::string& message) {
//cjh UnicodeString utf16 =
// UnicodeString::fromUTF8(StringPiece(message.data(), message.length()));
std::u16string u16Str;
cocos2d::StringUtils::UTF8ToUTF16(message, u16Str);
// StringView view(reinterpret_cast<const uint16_t*>(utf16.getBuffer()),
// utf16.length());
StringView view(reinterpret_cast<const uint16_t*>(u16Str.c_str()),
u16Str.length());
return StringBuffer::create(view);
}
class IoSessionDelegate : public InspectorSessionDelegate {
public:
explicit IoSessionDelegate(InspectorIo* io) : io_(io) { }
bool WaitForFrontendMessageWhilePaused() override;
void SendMessageToFrontend(const v8_inspector::StringView& message) override;
private:
InspectorIo* io_;
};
// Passed to InspectorSocketServer to handle WS inspector protocol events,
// mostly session start, message received, and session end.
class InspectorIoDelegate: public node::inspector::SocketServerDelegate {
public:
InspectorIoDelegate(InspectorIo* io, const std::string& script_path,
const std::string& script_name, bool wait);
// Calls PostIncomingMessage() with appropriate InspectorAction:
// kStartSession
bool StartSession(int session_id, const std::string& target_id) override;
// kSendMessage
void MessageReceived(int session_id, const std::string& message) override;
// kEndSession
void EndSession(int session_id) override;
std::vector<std::string> GetTargetIds() override;
std::string GetTargetTitle(const std::string& id) override;
std::string GetTargetUrl(const std::string& id) override;
bool IsConnected() { return connected_; }
void ServerDone() override {
io_->ServerDone();
}
private:
InspectorIo* io_;
bool connected_;
int session_id_;
const std::string script_name_;
const std::string script_path_;
const std::string target_id_;
bool waiting_;
};
void InterruptCallback(v8::Isolate*, void* agent) {
InspectorIo* io = static_cast<Agent*>(agent)->io();
if (io != nullptr)
io->DispatchMessages();
}
class DispatchMessagesTask : public v8::Task {
public:
explicit DispatchMessagesTask(Agent* agent) : agent_(agent) {}
void Run() override {
InspectorIo* io = agent_->io();
if (io != nullptr)
io->DispatchMessages();
}
private:
Agent* agent_;
};
InspectorIo::InspectorIo(Environment* env, v8::Platform* platform,
const std::string& path, const DebugOptions& options,
bool wait_for_connect)
: options_(options), thread_(), delegate_(nullptr),
state_(State::kNew), parent_env_(env),
thread_req_(), platform_(platform),
dispatching_messages_(false), session_id_(0),
script_name_(path),
wait_for_connect_(wait_for_connect), port_(-1) {
main_thread_req_ = new AsyncAndAgent({uv_async_t(), env->inspector_agent()});
CHECK_EQ(0, uv_async_init(env->event_loop(), &main_thread_req_->first,
InspectorIo::MainThreadReqAsyncCb));
uv_unref(reinterpret_cast<uv_handle_t*>(&main_thread_req_->first));
CHECK_EQ(0, uv_sem_init(&thread_start_sem_, 0));
}
InspectorIo::~InspectorIo() {
uv_sem_destroy(&thread_start_sem_);
uv_close(reinterpret_cast<uv_handle_t*>(&main_thread_req_->first),
ReleasePairOnAsyncClose);
if (main_thread_req_)
{
delete main_thread_req_;
main_thread_req_ = nullptr;
}
}
bool InspectorIo::Start() {
CHECK_EQ(state_, State::kNew);
CHECK_EQ(uv_thread_create(&thread_, InspectorIo::ThreadMain, this), 0);
uv_sem_wait(&thread_start_sem_);
if (state_ == State::kError) {
return false;
}
state_ = State::kAccepting;
if (wait_for_connect_) {
DispatchMessages();
}
return true;
}
void InspectorIo::Stop() {
CHECK(state_ == State::kAccepting || state_ == State::kConnected);
Write(TransportAction::kKill, 0, StringView());
int err = uv_thread_join(&thread_);
CHECK_EQ(err, 0);
state_ = State::kShutDown;
DispatchMessages();
}
bool InspectorIo::IsConnected() {
return delegate_ != nullptr && delegate_->IsConnected();
}
bool InspectorIo::IsStarted() {
return platform_ != nullptr;
}
void InspectorIo::WaitForDisconnect() {
if (state_ == State::kAccepting)
state_ = State::kDone;
if (state_ == State::kConnected) {
state_ = State::kShutDown;
Write(TransportAction::kStop, 0, StringView());
SE_LOGD("Waiting for the debugger to disconnect...\n");
parent_env_->inspector_agent()->RunMessageLoop();
}
}
// static
void InspectorIo::ThreadMain(void* io) {
static_cast<InspectorIo*>(io)->ThreadMain<InspectorSocketServer>();
}
// static
template <typename Transport>
void InspectorIo::IoThreadAsyncCb(uv_async_t* async) {
TransportAndIo<Transport>* transport_and_io =
static_cast<TransportAndIo<Transport>*>(async->data);
if (transport_and_io == nullptr) {
return;
}
Transport* transport = transport_and_io->first;
InspectorIo* io = transport_and_io->second;
MessageQueue<TransportAction> outgoing_message_queue;
io->SwapBehindLock(&io->outgoing_message_queue_, &outgoing_message_queue);
for (const auto& outgoing : outgoing_message_queue) {
switch (std::get<0>(outgoing)) {
case TransportAction::kKill:
transport->TerminateConnections();
// Fallthrough
case TransportAction::kStop:
transport->Stop(nullptr);
break;
case TransportAction::kSendMessage:
std::string message = StringViewToUtf8(std::get<2>(outgoing)->string());
transport->Send(std::get<1>(outgoing), message);
break;
}
}
}
template<typename Transport>
void InspectorIo::ThreadMain() {
uv_loop_t loop;
loop.data = nullptr;
int err = uv_loop_init(&loop);
CHECK_EQ(err, 0);
thread_req_.data = nullptr;
err = uv_async_init(&loop, &thread_req_, IoThreadAsyncCb<Transport>);
CHECK_EQ(err, 0);
std::string script_path = ScriptPath(&loop, script_name_);
InspectorIoDelegate delegate(this, script_path, script_name_,
wait_for_connect_);
delegate_ = &delegate;
Transport server(&delegate, &loop, options_.host_name(), options_.port());
TransportAndIo<Transport> queue_transport(&server, this);
thread_req_.data = &queue_transport;
if (!server.Start()) {
state_ = State::kError; // Safe, main thread is waiting on semaphore
CHECK_EQ(0, CloseAsyncAndLoop(&thread_req_));
uv_sem_post(&thread_start_sem_);
return;
}
port_ = server.Port(); // Safe, main thread is waiting on semaphore.
if (!wait_for_connect_) {
uv_sem_post(&thread_start_sem_);
}
uv_run(&loop, UV_RUN_DEFAULT);
thread_req_.data = nullptr;
CHECK_EQ(uv_loop_close(&loop), 0);
delegate_ = nullptr;
}
template <typename ActionType>
bool InspectorIo::AppendMessage(MessageQueue<ActionType>* queue,
ActionType action, int session_id,
std::unique_ptr<StringBuffer> buffer) {
Mutex::ScopedLock scoped_lock(state_lock_);
bool trigger_pumping = queue->empty();
queue->push_back(std::make_tuple(action, session_id, std::move(buffer)));
return trigger_pumping;
}
template <typename ActionType>
void InspectorIo::SwapBehindLock(MessageQueue<ActionType>* vector1,
MessageQueue<ActionType>* vector2) {
Mutex::ScopedLock scoped_lock(state_lock_);
vector1->swap(*vector2);
}
void InspectorIo::PostIncomingMessage(InspectorAction action, int session_id,
const std::string& message) {
if (AppendMessage(&incoming_message_queue_, action, session_id,
Utf8ToStringView(message))) {
Agent* agent = main_thread_req_->second;
v8::Isolate* isolate = parent_env_->isolate();
platform_->CallOnForegroundThread(isolate,
new DispatchMessagesTask(agent));
isolate->RequestInterrupt(InterruptCallback, agent);
CHECK_EQ(0, uv_async_send(&main_thread_req_->first));
}
NotifyMessageReceived();
}
std::vector<std::string> InspectorIo::GetTargetIds() const {
return delegate_ ? delegate_->GetTargetIds() : std::vector<std::string>();
}
void InspectorIo::WaitForFrontendMessageWhilePaused() {
dispatching_messages_ = false;
Mutex::ScopedLock scoped_lock(state_lock_);
if (incoming_message_queue_.empty())
incoming_message_cond_.Wait(scoped_lock);
}
void InspectorIo::NotifyMessageReceived() {
Mutex::ScopedLock scoped_lock(state_lock_);
incoming_message_cond_.Broadcast(scoped_lock);
}
void InspectorIo::DispatchMessages() {
// This function can be reentered if there was an incoming message while
// V8 was processing another inspector request (e.g. if the user is
// evaluating a long-running JS code snippet). This can happen only at
// specific points (e.g. the lines that call inspector_ methods)
if (dispatching_messages_)
return;
dispatching_messages_ = true;
bool had_messages = false;
do {
if (dispatching_message_queue_.empty())
SwapBehindLock(&incoming_message_queue_, &dispatching_message_queue_);
had_messages = !dispatching_message_queue_.empty();
while (!dispatching_message_queue_.empty()) {
MessageQueue<InspectorAction>::value_type task;
std::swap(dispatching_message_queue_.front(), task);
dispatching_message_queue_.pop_front();
StringView message = std::get<2>(task)->string();
switch (std::get<0>(task)) {
case InspectorAction::kStartSession:
CHECK_EQ(session_delegate_, nullptr);
session_id_ = std::get<1>(task);
state_ = State::kConnected;
SE_LOGD("Debugger attached.\n");
session_delegate_ = std::unique_ptr<InspectorSessionDelegate>(
new IoSessionDelegate(this));
parent_env_->inspector_agent()->Connect(session_delegate_.get());
break;
case InspectorAction::kEndSession:
CHECK_NE(session_delegate_, nullptr);
if (state_ == State::kShutDown) {
state_ = State::kDone;
} else {
state_ = State::kAccepting;
}
parent_env_->inspector_agent()->Disconnect();
session_delegate_.reset();
break;
case InspectorAction::kSendMessage:
parent_env_->inspector_agent()->Dispatch(message);
break;
}
}
} while (had_messages);
dispatching_messages_ = false;
}
// static
void InspectorIo::MainThreadReqAsyncCb(uv_async_t* req) {
AsyncAndAgent* pair = node::ContainerOf(&AsyncAndAgent::first, req);
// Note that this may be called after io was closed or even after a new
// one was created and ran.
InspectorIo* io = pair->second->io();
if (io != nullptr)
io->DispatchMessages();
}
void InspectorIo::Write(TransportAction action, int session_id,
const StringView& inspector_message) {
AppendMessage(&outgoing_message_queue_, action, session_id,
StringBuffer::create(inspector_message));
int err = uv_async_send(&thread_req_);
CHECK_EQ(0, err);
}
InspectorIoDelegate::InspectorIoDelegate(InspectorIo* io,
const std::string& script_path,
const std::string& script_name,
bool wait)
: io_(io),
connected_(false),
session_id_(0),
script_name_(script_name),
script_path_(script_path),
target_id_(GenerateID()),
waiting_(wait) { }
bool InspectorIoDelegate::StartSession(int session_id,
const std::string& target_id) {
if (connected_)
return false;
connected_ = true;
session_id_++;
io_->PostIncomingMessage(InspectorAction::kStartSession, session_id, "");
return true;
}
void InspectorIoDelegate::MessageReceived(int session_id,
const std::string& message) {
// REFINE(pfeldman): Instead of blocking execution while debugger
// engages, node should wait for the run callback from the remote client
// and initiate its startup. This is a change to node.cc that should be
// upstreamed separately.
if (waiting_) {
if (message.find("\"Runtime.runIfWaitingForDebugger\"") !=
std::string::npos) {
waiting_ = false;
io_->ResumeStartup();
}
}
io_->PostIncomingMessage(InspectorAction::kSendMessage, session_id,
message);
}
void InspectorIoDelegate::EndSession(int session_id) {
connected_ = false;
io_->PostIncomingMessage(InspectorAction::kEndSession, session_id, "");
}
std::vector<std::string> InspectorIoDelegate::GetTargetIds() {
return { target_id_ };
}
std::string InspectorIoDelegate::GetTargetTitle(const std::string& id) {
return script_name_.empty() ? GetProcessTitle() : script_name_;
}
std::string InspectorIoDelegate::GetTargetUrl(const std::string& id) {
return "file://" + script_path_;
}
bool IoSessionDelegate::WaitForFrontendMessageWhilePaused() {
io_->WaitForFrontendMessageWhilePaused();
return true;
}
void IoSessionDelegate::SendMessageToFrontend(
const v8_inspector::StringView& message) {
io_->Write(TransportAction::kSendMessage, io_->session_id_, message);
}
} // namespace inspector
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,180 @@
#ifndef SRC_INSPECTOR_IO_H_
#define SRC_INSPECTOR_IO_H_
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "inspector_socket_server.h"
#include "node_debug_options.h"
#include "node_mutex.h"
#include "uv.h"
#include <deque>
#include <memory>
#include <stddef.h>
#if !HAVE_INSPECTOR
#error("This header can only be used when inspector is enabled")
#endif
// Forward declaration to break recursive dependency chain with src/env.h.
namespace node {
class Environment;
} // namespace node
namespace v8_inspector {
class StringBuffer;
class StringView;
} // namespace v8_inspector
namespace node {
namespace inspector {
std::string FormatWsAddress(const std::string& host, int port,
const std::string& target_id,
bool include_protocol);
class InspectorIoDelegate;
enum class InspectorAction {
kStartSession,
kEndSession,
kSendMessage
};
// kKill closes connections and stops the server, kStop only stops the server
enum class TransportAction {
kKill,
kSendMessage,
kStop
};
class InspectorIo {
public:
InspectorIo(node::Environment* env, v8::Platform* platform,
const std::string& path, const DebugOptions& options,
bool wait_for_connect);
~InspectorIo();
// Start the inspector agent thread, waiting for it to initialize,
// and waiting as well for a connection if wait_for_connect.
bool Start();
// Stop the inspector agent thread.
void Stop();
bool IsStarted();
bool IsConnected();
void WaitForDisconnect();
// Called from thread to queue an incoming message and trigger
// DispatchMessages() on the main thread.
void PostIncomingMessage(InspectorAction action, int session_id,
const std::string& message);
void ResumeStartup() {
uv_sem_post(&thread_start_sem_);
}
void ServerDone() {
uv_close(reinterpret_cast<uv_handle_t*>(&thread_req_), nullptr);
}
int port() const { return port_; }
std::string host() const { return options_.host_name(); }
std::vector<std::string> GetTargetIds() const;
private:
template <typename Action>
using MessageQueue =
std::deque<std::tuple<Action, int,
std::unique_ptr<v8_inspector::StringBuffer>>>;
enum class State {
kNew,
kAccepting,
kConnected,
kDone,
kError,
kShutDown
};
// Callback for main_thread_req_'s uv_async_t
static void MainThreadReqAsyncCb(uv_async_t* req);
// Wrapper for agent->ThreadMain()
static void ThreadMain(void* agent);
// Runs a uv_loop_t
template <typename Transport> void ThreadMain();
// Called by ThreadMain's loop when triggered by thread_req_, writes
// messages from outgoing_message_queue to the InspectorSockerServer
template <typename Transport> static void IoThreadAsyncCb(uv_async_t* async);
void SetConnected(bool connected);
void DispatchMessages();
// Write action to outgoing_message_queue, and wake the thread
void Write(TransportAction action, int session_id,
const v8_inspector::StringView& message);
// Thread-safe append of message to a queue. Return true if the queue
// used to be empty.
template <typename ActionType>
bool AppendMessage(MessageQueue<ActionType>* vector, ActionType action,
int session_id,
std::unique_ptr<v8_inspector::StringBuffer> buffer);
// Used as equivalent of a thread-safe "pop" of an entire queue's content.
template <typename ActionType>
void SwapBehindLock(MessageQueue<ActionType>* vector1,
MessageQueue<ActionType>* vector2);
// Wait on incoming_message_cond_
void WaitForFrontendMessageWhilePaused();
// Broadcast incoming_message_cond_
void NotifyMessageReceived();
const DebugOptions options_;
// The IO thread runs its own uv_loop to implement the TCP server off
// the main thread.
uv_thread_t thread_;
// Used by Start() to wait for thread to initialize, or for it to initialize
// and receive a connection if wait_for_connect was requested.
uv_sem_t thread_start_sem_;
InspectorIoDelegate* delegate_;
State state_;
node::Environment* parent_env_;
// Attached to the uv_loop in ThreadMain()
uv_async_t thread_req_;
// Note that this will live while the async is being closed - likely, past
// the parent object lifespan
std::pair<uv_async_t, Agent*>* main_thread_req_;
std::unique_ptr<InspectorSessionDelegate> session_delegate_;
v8::Platform* platform_;
// Message queues
ConditionVariable incoming_message_cond_;
Mutex state_lock_; // Locked before mutating either queue.
MessageQueue<InspectorAction> incoming_message_queue_;
MessageQueue<TransportAction> outgoing_message_queue_;
MessageQueue<InspectorAction> dispatching_message_queue_;
bool dispatching_messages_;
int session_id_;
std::string script_name_;
std::string script_path_;
const bool wait_for_connect_;
int port_;
friend class DispatchMessagesTask;
friend class IoSessionDelegate;
friend void InterruptCallback(v8::Isolate*, void* agent);
};
std::unique_ptr<v8_inspector::StringBuffer> Utf8ToStringView(
const std::string& message);
} // namespace inspector
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif // SRC_INSPECTOR_IO_H_

View File

@@ -0,0 +1,640 @@
#include "inspector_socket.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "util.h"
#include "base64.h"
//#include "openssl/sha.h" // Sha-1 hash
#include "SHA1.h"
#include <string.h>
#include <vector>
#define ACCEPT_KEY_LENGTH base64_encoded_size(20)
#define BUFFER_GROWTH_CHUNK_SIZE 1024
#define DUMP_READS 0
#define DUMP_WRITES 0
namespace node {
namespace inspector {
static const char CLOSE_FRAME[] = {'\x88', '\x00'};
enum ws_decode_result {
FRAME_OK, FRAME_INCOMPLETE, FRAME_CLOSE, FRAME_ERROR
};
#if DUMP_READS || DUMP_WRITES
static void dump_hex(const char* buf, size_t len) {
const char* ptr = buf;
const char* end = ptr + len;
const char* cptr;
char c;
int i;
while (ptr < end) {
cptr = ptr;
for (i = 0; i < 16 && ptr < end; i++) {
printf("%2.2X ", static_cast<unsigned char>(*(ptr++)));
}
for (i = 72 - (i * 4); i > 0; i--) {
printf(" ");
}
for (i = 0; i < 16 && cptr < end; i++) {
c = *(cptr++);
printf("%c", (c > 0x19) ? c : '.');
}
printf("\n");
}
printf("\n\n");
}
#endif
static void remove_from_beginning(std::vector<char>* buffer, size_t count) {
buffer->erase(buffer->begin(), buffer->begin() + count);
}
static void dispose_inspector(uv_handle_t* handle) {
InspectorSocket* inspector = inspector_from_stream(handle);
inspector_cb close =
inspector->ws_mode ? inspector->ws_state->close_cb : nullptr;
inspector->buffer.clear();
delete inspector->ws_state;
inspector->ws_state = nullptr;
if (close) {
close(inspector, 0);
}
}
static void close_connection(InspectorSocket* inspector) {
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->tcp);
if (!uv_is_closing(socket)) {
uv_read_stop(reinterpret_cast<uv_stream_t*>(socket));
uv_close(socket, dispose_inspector);
}
}
struct WriteRequest {
WriteRequest(InspectorSocket* inspector, const char* data, size_t size)
: inspector(inspector)
, storage(data, data + size)
, buf(uv_buf_init(&storage[0], storage.size())) {}
static WriteRequest* from_write_req(uv_write_t* req) {
return node::ContainerOf(&WriteRequest::req, req);
}
InspectorSocket* const inspector;
std::vector<char> storage;
uv_write_t req;
uv_buf_t buf;
};
// Cleanup
static void write_request_cleanup(uv_write_t* req, int status) {
delete WriteRequest::from_write_req(req);
}
static int write_to_client(InspectorSocket* inspector,
const char* msg,
size_t len,
uv_write_cb write_cb = write_request_cleanup) {
#if DUMP_WRITES
printf("%s (%ld bytes):\n", __FUNCTION__, len);
dump_hex(msg, len);
#endif
// Freed in write_request_cleanup
WriteRequest* wr = new WriteRequest(inspector, msg, len);
uv_stream_t* stream = reinterpret_cast<uv_stream_t*>(&inspector->tcp);
return uv_write(&wr->req, stream, &wr->buf, 1, write_cb) < 0;
}
// Constants for hybi-10 frame format.
typedef int OpCode;
const OpCode kOpCodeContinuation = 0x0;
const OpCode kOpCodeText = 0x1;
const OpCode kOpCodeBinary = 0x2;
const OpCode kOpCodeClose = 0x8;
const OpCode kOpCodePing = 0x9;
const OpCode kOpCodePong = 0xA;
const unsigned char kFinalBit = 0x80;
const unsigned char kReserved1Bit = 0x40;
const unsigned char kReserved2Bit = 0x20;
const unsigned char kReserved3Bit = 0x10;
const unsigned char kOpCodeMask = 0xF;
const unsigned char kMaskBit = 0x80;
const unsigned char kPayloadLengthMask = 0x7F;
const size_t kMaxSingleBytePayloadLength = 125;
const size_t kTwoBytePayloadLengthField = 126;
const size_t kEightBytePayloadLengthField = 127;
const size_t kMaskingKeyWidthInBytes = 4;
static std::vector<char> encode_frame_hybi17(const char* message,
size_t data_length) {
std::vector<char> frame;
OpCode op_code = kOpCodeText;
frame.push_back(kFinalBit | op_code);
if (data_length <= kMaxSingleBytePayloadLength) {
frame.push_back(static_cast<char>(data_length));
} else if (data_length <= 0xFFFF) {
frame.push_back(kTwoBytePayloadLengthField);
frame.push_back((data_length & 0xFF00) >> 8);
frame.push_back(data_length & 0xFF);
} else {
frame.push_back(kEightBytePayloadLengthField);
char extended_payload_length[8];
size_t remaining = data_length;
// Fill the length into extended_payload_length in the network byte order.
for (int i = 0; i < 8; ++i) {
extended_payload_length[7 - i] = remaining & 0xFF;
remaining >>= 8;
}
frame.insert(frame.end(), extended_payload_length,
extended_payload_length + 8);
CHECK_EQ(0, remaining);
}
frame.insert(frame.end(), message, message + data_length);
return frame;
}
static ws_decode_result decode_frame_hybi17(const std::vector<char>& buffer,
bool client_frame,
int* bytes_consumed,
std::vector<char>* output,
bool* compressed) {
*bytes_consumed = 0;
if (buffer.size() < 2)
return FRAME_INCOMPLETE;
auto it = buffer.begin();
unsigned char first_byte = *it++;
unsigned char second_byte = *it++;
bool final = (first_byte & kFinalBit) != 0;
bool reserved1 = (first_byte & kReserved1Bit) != 0;
bool reserved2 = (first_byte & kReserved2Bit) != 0;
bool reserved3 = (first_byte & kReserved3Bit) != 0;
int op_code = first_byte & kOpCodeMask;
bool masked = (second_byte & kMaskBit) != 0;
*compressed = reserved1;
if (!final || reserved2 || reserved3)
return FRAME_ERROR; // Only compression extension is supported.
bool closed = false;
switch (op_code) {
case kOpCodeClose:
closed = true;
break;
case kOpCodeText:
break;
case kOpCodeBinary: // We don't support binary frames yet.
case kOpCodeContinuation: // We don't support binary frames yet.
case kOpCodePing: // We don't support binary frames yet.
case kOpCodePong: // We don't support binary frames yet.
default:
return FRAME_ERROR;
}
// In Hybi-17 spec client MUST mask its frame.
if (client_frame && !masked) {
return FRAME_ERROR;
}
uint64_t payload_length64 = second_byte & kPayloadLengthMask;
if (payload_length64 > kMaxSingleBytePayloadLength) {
int extended_payload_length_size;
if (payload_length64 == kTwoBytePayloadLengthField) {
extended_payload_length_size = 2;
} else if (payload_length64 == kEightBytePayloadLengthField) {
extended_payload_length_size = 8;
} else {
return FRAME_ERROR;
}
if ((buffer.end() - it) < extended_payload_length_size)
return FRAME_INCOMPLETE;
payload_length64 = 0;
for (int i = 0; i < extended_payload_length_size; ++i) {
payload_length64 <<= 8;
payload_length64 |= static_cast<unsigned char>(*it++);
}
}
static const uint64_t max_payload_length = 0x7FFFFFFFFFFFFFFFull;
static const size_t max_length = SIZE_MAX;
if (payload_length64 > max_payload_length ||
payload_length64 > max_length - kMaskingKeyWidthInBytes) {
// WebSocket frame length too large.
return FRAME_ERROR;
}
size_t payload_length = static_cast<size_t>(payload_length64);
if (buffer.size() - kMaskingKeyWidthInBytes < payload_length)
return FRAME_INCOMPLETE;
std::vector<char>::const_iterator masking_key = it;
std::vector<char>::const_iterator payload = it + kMaskingKeyWidthInBytes;
for (size_t i = 0; i < payload_length; ++i) // Unmask the payload.
output->insert(output->end(),
payload[i] ^ masking_key[i % kMaskingKeyWidthInBytes]);
size_t pos = it + kMaskingKeyWidthInBytes + payload_length - buffer.begin();
*bytes_consumed = pos;
return closed ? FRAME_CLOSE : FRAME_OK;
}
static void invoke_read_callback(InspectorSocket* inspector,
int status, const uv_buf_t* buf) {
if (inspector->ws_state->read_cb) {
inspector->ws_state->read_cb(
reinterpret_cast<uv_stream_t*>(&inspector->tcp), status, buf);
}
}
static void shutdown_complete(InspectorSocket* inspector) {
close_connection(inspector);
}
static void on_close_frame_written(uv_write_t* req, int status) {
WriteRequest* wr = WriteRequest::from_write_req(req);
InspectorSocket* inspector = wr->inspector;
delete wr;
inspector->ws_state->close_sent = true;
if (inspector->ws_state->received_close) {
shutdown_complete(inspector);
}
}
static void close_frame_received(InspectorSocket* inspector) {
inspector->ws_state->received_close = true;
if (!inspector->ws_state->close_sent) {
invoke_read_callback(inspector, 0, 0);
write_to_client(inspector, CLOSE_FRAME, sizeof(CLOSE_FRAME),
on_close_frame_written);
} else {
shutdown_complete(inspector);
}
}
static int parse_ws_frames(InspectorSocket* inspector) {
int bytes_consumed = 0;
std::vector<char> output;
bool compressed = false;
ws_decode_result r = decode_frame_hybi17(inspector->buffer,
true /* client_frame */,
&bytes_consumed, &output,
&compressed);
// Compressed frame means client is ignoring the headers and misbehaves
if (compressed || r == FRAME_ERROR) {
invoke_read_callback(inspector, UV_EPROTO, nullptr);
close_connection(inspector);
bytes_consumed = 0;
} else if (r == FRAME_CLOSE) {
close_frame_received(inspector);
bytes_consumed = 0;
} else if (r == FRAME_OK && inspector->ws_state->alloc_cb
&& inspector->ws_state->read_cb) {
uv_buf_t buffer;
size_t len = output.size();
inspector->ws_state->alloc_cb(
reinterpret_cast<uv_handle_t*>(&inspector->tcp),
len, &buffer);
CHECK_GE(buffer.len, len);
memcpy(buffer.base, &output[0], len);
invoke_read_callback(inspector, len, &buffer);
}
return bytes_consumed;
}
static void prepare_buffer(uv_handle_t* stream, size_t len, uv_buf_t* buf) {
*buf = uv_buf_init(new char[len], len);
}
static void reclaim_uv_buf(InspectorSocket* inspector, const uv_buf_t* buf,
ssize_t read) {
if (read > 0) {
std::vector<char>& buffer = inspector->buffer;
buffer.insert(buffer.end(), buf->base, buf->base + read);
}
delete[] buf->base;
}
static void websockets_data_cb(uv_stream_t* stream, ssize_t nread,
const uv_buf_t* buf) {
InspectorSocket* inspector = inspector_from_stream(stream);
reclaim_uv_buf(inspector, buf, nread);
if (nread < 0 || nread == UV_EOF) {
inspector->connection_eof = true;
if (!inspector->shutting_down && inspector->ws_state->read_cb) {
inspector->ws_state->read_cb(stream, nread, nullptr);
}
if (inspector->ws_state->close_sent &&
!inspector->ws_state->received_close) {
shutdown_complete(inspector); // invoke callback
}
} else {
#if DUMP_READS
printf("%s read %ld bytes\n", __FUNCTION__, nread);
if (nread > 0) {
dump_hex(inspector->buffer.data() + inspector->buffer.size() - nread,
nread);
}
#endif
// 2. Parse.
int processed = 0;
do {
processed = parse_ws_frames(inspector);
// 3. Fix the buffer size & length
if (processed > 0) {
remove_from_beginning(&inspector->buffer, processed);
}
} while (processed > 0 && !inspector->buffer.empty());
}
}
int inspector_read_start(InspectorSocket* inspector,
uv_alloc_cb alloc_cb, uv_read_cb read_cb) {
CHECK(inspector->ws_mode);
CHECK(!inspector->shutting_down || read_cb == nullptr);
inspector->ws_state->close_sent = false;
inspector->ws_state->alloc_cb = alloc_cb;
inspector->ws_state->read_cb = read_cb;
int err =
uv_read_start(reinterpret_cast<uv_stream_t*>(&inspector->tcp),
prepare_buffer,
websockets_data_cb);
if (err < 0) {
close_connection(inspector);
}
return err;
}
void inspector_read_stop(InspectorSocket* inspector) {
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->tcp));
inspector->ws_state->alloc_cb = nullptr;
inspector->ws_state->read_cb = nullptr;
}
static void generate_accept_string(const std::string& client_key,
char (*buffer)[ACCEPT_KEY_LENGTH]) {
// Magic string from websockets spec.
static const char ws_magic[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
std::string input(client_key + ws_magic);
// char hash[SHA_DIGEST_LENGTH];
// SHA1(reinterpret_cast<const unsigned char*>(&input[0]), input.size(),
// reinterpret_cast<unsigned char*>(hash));
se::SHA1Sum::Hash hash = {0};
se::SHA1Sum s;
s.update(reinterpret_cast<const unsigned char*>(&input[0]), (uint32_t)input.size());
s.finish(hash);
node::base64_encode((char*)hash, sizeof(hash), *buffer, sizeof(*buffer));
}
static int header_value_cb(http_parser* parser, const char* at, size_t length) {
static const char SEC_WEBSOCKET_KEY_HEADER[] = "Sec-WebSocket-Key";
auto inspector = static_cast<InspectorSocket*>(parser->data);
auto state = inspector->http_parsing_state;
state->parsing_value = true;
if (state->current_header.size() == sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1 &&
node::StringEqualNoCaseN(state->current_header.data(),
SEC_WEBSOCKET_KEY_HEADER,
sizeof(SEC_WEBSOCKET_KEY_HEADER) - 1)) {
state->ws_key.append(at, length);
}
return 0;
}
static int header_field_cb(http_parser* parser, const char* at, size_t length) {
auto inspector = static_cast<InspectorSocket*>(parser->data);
auto state = inspector->http_parsing_state;
if (state->parsing_value) {
state->parsing_value = false;
state->current_header.clear();
}
state->current_header.append(at, length);
return 0;
}
static int path_cb(http_parser* parser, const char* at, size_t length) {
auto inspector = static_cast<InspectorSocket*>(parser->data);
auto state = inspector->http_parsing_state;
state->path.append(at, length);
return 0;
}
static void handshake_complete(InspectorSocket* inspector) {
uv_read_stop(reinterpret_cast<uv_stream_t*>(&inspector->tcp));
handshake_cb callback = inspector->http_parsing_state->callback;
inspector->ws_state = new ws_state_s();
inspector->ws_mode = true;
callback(inspector, kInspectorHandshakeUpgraded,
inspector->http_parsing_state->path);
}
static void cleanup_http_parsing_state(InspectorSocket* inspector) {
delete inspector->http_parsing_state;
inspector->http_parsing_state = nullptr;
}
static void report_handshake_failure_cb(uv_handle_t* handle) {
dispose_inspector(handle);
InspectorSocket* inspector = inspector_from_stream(handle);
handshake_cb cb = inspector->http_parsing_state->callback;
cleanup_http_parsing_state(inspector);
cb(inspector, kInspectorHandshakeFailed, std::string());
}
static void close_and_report_handshake_failure(InspectorSocket* inspector) {
uv_handle_t* socket = reinterpret_cast<uv_handle_t*>(&inspector->tcp);
if (uv_is_closing(socket)) {
report_handshake_failure_cb(socket);
} else {
uv_read_stop(reinterpret_cast<uv_stream_t*>(socket));
uv_close(socket, report_handshake_failure_cb);
}
}
static void then_close_and_report_failure(uv_write_t* req, int status) {
InspectorSocket* inspector = WriteRequest::from_write_req(req)->inspector;
write_request_cleanup(req, status);
close_and_report_handshake_failure(inspector);
}
static void handshake_failed(InspectorSocket* inspector) {
const char HANDSHAKE_FAILED_RESPONSE[] =
"HTTP/1.0 400 Bad Request\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"WebSockets request was expected\r\n";
write_to_client(inspector, HANDSHAKE_FAILED_RESPONSE,
sizeof(HANDSHAKE_FAILED_RESPONSE) - 1,
then_close_and_report_failure);
}
// init_handshake references message_complete_cb
static void init_handshake(InspectorSocket* socket);
static int message_complete_cb(http_parser* parser) {
InspectorSocket* inspector = static_cast<InspectorSocket*>(parser->data);
struct http_parsing_state_s* state = inspector->http_parsing_state;
if (parser->method != HTTP_GET) {
handshake_failed(inspector);
} else if (!parser->upgrade) {
if (state->callback(inspector, kInspectorHandshakeHttpGet, state->path)) {
init_handshake(inspector);
} else {
handshake_failed(inspector);
}
} else if (state->ws_key.empty()) {
handshake_failed(inspector);
} else if (state->callback(inspector, kInspectorHandshakeUpgrading,
state->path)) {
char accept_string[ACCEPT_KEY_LENGTH];
generate_accept_string(state->ws_key, &accept_string);
const char accept_ws_prefix[] = "HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: ";
const char accept_ws_suffix[] = "\r\n\r\n";
std::string reply(accept_ws_prefix, sizeof(accept_ws_prefix) - 1);
reply.append(accept_string, sizeof(accept_string));
reply.append(accept_ws_suffix, sizeof(accept_ws_suffix) - 1);
if (write_to_client(inspector, &reply[0], reply.size()) >= 0) {
handshake_complete(inspector);
inspector->http_parsing_state->done = true;
} else {
close_and_report_handshake_failure(inspector);
}
} else {
handshake_failed(inspector);
}
return 0;
}
static void data_received_cb(uv_stream_s* tcp, ssize_t nread,
const uv_buf_t* buf) {
#if DUMP_READS
if (nread >= 0) {
printf("%s (%ld bytes)\n", __FUNCTION__, nread);
dump_hex(buf->base, nread);
} else {
printf("[%s:%d] %s\n", __FUNCTION__, __LINE__, uv_err_name(nread));
}
#endif
InspectorSocket* inspector = inspector_from_stream(tcp);
reclaim_uv_buf(inspector, buf, nread);
if (nread < 0 || nread == UV_EOF) {
close_and_report_handshake_failure(inspector);
} else {
http_parsing_state_s* state = inspector->http_parsing_state;
http_parser* parser = &state->parser;
http_parser_execute(parser, &state->parser_settings,
inspector->buffer.data(), nread);
remove_from_beginning(&inspector->buffer, nread);
if (parser->http_errno != HPE_OK) {
handshake_failed(inspector);
}
if (inspector->http_parsing_state->done) {
cleanup_http_parsing_state(inspector);
}
}
}
static void init_handshake(InspectorSocket* socket) {
http_parsing_state_s* state = socket->http_parsing_state;
CHECK_NE(state, nullptr);
state->current_header.clear();
state->ws_key.clear();
state->path.clear();
state->done = false;
http_parser_init(&state->parser, HTTP_REQUEST);
state->parser.data = socket;
http_parser_settings* settings = &state->parser_settings;
http_parser_settings_init(settings);
settings->on_header_field = header_field_cb;
settings->on_header_value = header_value_cb;
settings->on_message_complete = message_complete_cb;
settings->on_url = path_cb;
}
int inspector_accept(uv_stream_t* server, InspectorSocket* socket,
handshake_cb callback) {
CHECK_NE(callback, nullptr);
CHECK_EQ(socket->http_parsing_state, nullptr);
socket->http_parsing_state = new http_parsing_state_s();
uv_stream_t* tcp = reinterpret_cast<uv_stream_t*>(&socket->tcp);
int err = uv_tcp_init(server->loop, &socket->tcp);
if (err == 0) {
err = uv_accept(server, tcp);
}
if (err == 0) {
init_handshake(socket);
socket->http_parsing_state->callback = callback;
err = uv_read_start(tcp, prepare_buffer,
data_received_cb);
}
if (err != 0) {
uv_close(reinterpret_cast<uv_handle_t*>(tcp), NULL);
}
return err;
}
void inspector_write(InspectorSocket* inspector, const char* data,
size_t len) {
if (inspector->ws_mode) {
std::vector<char> output = encode_frame_hybi17(data, len);
write_to_client(inspector, &output[0], output.size());
} else {
write_to_client(inspector, data, len);
}
}
void inspector_close(InspectorSocket* inspector,
inspector_cb callback) {
// libuv throws assertions when closing stream that's already closed - we
// need to do the same.
CHECK(!uv_is_closing(reinterpret_cast<uv_handle_t*>(&inspector->tcp)));
CHECK(!inspector->shutting_down);
inspector->shutting_down = true;
inspector->ws_state->close_cb = callback;
if (inspector->connection_eof) {
close_connection(inspector);
} else {
inspector_read_stop(inspector);
write_to_client(inspector, CLOSE_FRAME, sizeof(CLOSE_FRAME),
on_close_frame_written);
inspector_read_start(inspector, nullptr, nullptr);
}
}
bool inspector_is_active(const InspectorSocket* inspector) {
const uv_handle_t* tcp =
reinterpret_cast<const uv_handle_t*>(&inspector->tcp);
return !inspector->shutting_down && !uv_is_closing(tcp);
}
void InspectorSocket::reinit() {
http_parsing_state = nullptr;
ws_state = nullptr;
buffer.clear();
ws_mode = false;
shutting_down = false;
connection_eof = false;
}
} // namespace inspector
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,105 @@
#ifndef SRC_INSPECTOR_SOCKET_H_
#define SRC_INSPECTOR_SOCKET_H_
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "http_parser.h"
#include "util.h"
#include "uv.h"
#include <string>
#include <vector>
namespace node {
namespace inspector {
enum inspector_handshake_event {
kInspectorHandshakeUpgrading,
kInspectorHandshakeUpgraded,
kInspectorHandshakeHttpGet,
kInspectorHandshakeFailed
};
class InspectorSocket;
typedef void (*inspector_cb)(InspectorSocket*, int);
// Notifies as handshake is progressing. Returning false as a response to
// kInspectorHandshakeUpgrading or kInspectorHandshakeHttpGet event will abort
// the connection. inspector_write can be used from the callback.
typedef bool (*handshake_cb)(InspectorSocket*,
enum inspector_handshake_event state,
const std::string& path);
struct http_parsing_state_s {
http_parser parser;
http_parser_settings parser_settings;
handshake_cb callback;
bool done;
bool parsing_value;
std::string ws_key;
std::string path;
std::string current_header;
};
struct ws_state_s {
uv_alloc_cb alloc_cb;
uv_read_cb read_cb;
inspector_cb close_cb;
bool close_sent;
bool received_close;
};
// HTTP Wrapper around a uv_tcp_t
class InspectorSocket {
public:
InspectorSocket() : data(nullptr), http_parsing_state(nullptr),
ws_state(nullptr), buffer(0), ws_mode(false),
shutting_down(false), connection_eof(false) { }
void reinit();
void* data;
struct http_parsing_state_s* http_parsing_state;
struct ws_state_s* ws_state;
std::vector<char> buffer;
uv_tcp_t tcp;
bool ws_mode;
bool shutting_down;
bool connection_eof;
private:
NODE_DISALLOW_COPY_AND_ASSIGN(InspectorSocket);
};
int inspector_accept(uv_stream_t* server, InspectorSocket* inspector,
handshake_cb callback);
void inspector_close(InspectorSocket* inspector,
inspector_cb callback);
// Callbacks will receive stream handles. Use inspector_from_stream to get
// InspectorSocket* from the stream handle.
int inspector_read_start(InspectorSocket* inspector, uv_alloc_cb,
uv_read_cb);
void inspector_read_stop(InspectorSocket* inspector);
void inspector_write(InspectorSocket* inspector,
const char* data, size_t len);
bool inspector_is_active(const InspectorSocket* inspector);
inline InspectorSocket* inspector_from_stream(uv_tcp_t* stream) {
return node::ContainerOf(&InspectorSocket::tcp, stream);
}
inline InspectorSocket* inspector_from_stream(uv_stream_t* stream) {
return inspector_from_stream(reinterpret_cast<uv_tcp_t*>(stream));
}
inline InspectorSocket* inspector_from_stream(uv_handle_t* stream) {
return inspector_from_stream(reinterpret_cast<uv_tcp_t*>(stream));
}
} // namespace inspector
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif // SRC_INSPECTOR_SOCKET_H_

View File

@@ -0,0 +1,652 @@
#include "inspector_socket_server.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "node.h"
#include "uv.h"
#include "zlib.h"
#include <algorithm>
#include <map>
#include <set>
#include <sstream>
namespace node {
namespace inspector {
// Function is declared in inspector_io.h so the rest of the node does not
// depend on inspector_socket_server.h
std::string FormatWsAddress(const std::string& host, int port,
const std::string& target_id,
bool include_protocol) {
// Host is valid (socket was bound) so colon means it's a v6 IP address
bool v6 = host.find(':') != std::string::npos;
std::ostringstream url;
if (include_protocol)
url << "ws://";
if (v6) {
url << '[';
}
url << host;
if (v6) {
url << ']';
}
url << ':' << port << '/' << target_id;
return url.str();
}
namespace {
static const uint8_t PROTOCOL_JSON[] = {
#include "v8_inspector_protocol_json.h" // NOLINT(build/include_order)
};
template<typename T>
static std::string to_string(T arg)
{
std::stringstream ss;
ss << arg;
return ss.str();
}
void Escape(std::string* string) {
for (char& c : *string) {
c = (c == '\"' || c == '\\') ? '_' : c;
}
}
std::string MapToString(const std::map<std::string, std::string>& object) {
bool first = true;
std::ostringstream json;
json << "{\n";
for (const auto& name_value : object) {
if (!first)
json << ",\n";
first = false;
json << " \"" << name_value.first << "\": \"";
json << name_value.second << "\"";
}
json << "\n} ";
return json.str();
}
std::string MapsToString(
const std::vector<std::map<std::string, std::string>>& array) {
bool first = true;
std::ostringstream json;
json << "[ ";
for (const auto& object : array) {
if (!first)
json << ", ";
first = false;
json << MapToString(object);
}
json << "]\n\n";
return json.str();
}
const char* MatchPathSegment(const char* path, const char* expected) {
size_t len = strlen(expected);
if (StringEqualNoCaseN(path, expected, len)) {
if (path[len] == '/') return path + len + 1;
if (path[len] == '\0') return path + len;
}
return nullptr;
}
void OnBufferAlloc(uv_handle_t* handle, size_t len, uv_buf_t* buf) {
buf->base = new char[len];
buf->len = len;
}
void PrintDebuggerReadyMessage(const std::string& host,
int port,
const std::vector<std::string>& ids,
FILE* out) {
if (out == NULL) {
return;
}
for (const std::string& id : ids) {
SE_LOGD("Debugger listening..., visit [ devtools://devtools/bundled/js_app.html?v8only=true&ws=%s ] in chrome browser to debug!\n",
FormatWsAddress(host, port, id, false).c_str());
}
SE_LOGD("For help see %s\n",
"https://nodejs.org/en/docs/inspector");
}
void SendHttpResponse(InspectorSocket* socket, const std::string& response) {
const char HEADERS[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: application/json; charset=UTF-8\r\n"
"Cache-Control: no-cache\r\n"
"Content-Length: %zu\r\n"
"\r\n";
char header[sizeof(HEADERS) + 20];
int header_len = snprintf(header, sizeof(header), HEADERS, response.size());
inspector_write(socket, header, header_len);
inspector_write(socket, response.data(), response.size());
}
void SendVersionResponse(InspectorSocket* socket) {
std::map<std::string, std::string> response;
response["Browser"] = "Cocos2d-x Games"; //cjh
response["Protocol-Version"] = "1.1";
SendHttpResponse(socket, MapToString(response));
}
void SendProtocolJson(InspectorSocket* socket) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
CHECK_EQ(Z_OK, inflateInit(&strm));
static const size_t kDecompressedSize =
PROTOCOL_JSON[0] * 0x10000u +
PROTOCOL_JSON[1] * 0x100u +
PROTOCOL_JSON[2];
strm.next_in = const_cast<uint8_t*>(PROTOCOL_JSON + 3);
strm.avail_in = sizeof(PROTOCOL_JSON) - 3;
std::string data(kDecompressedSize, '\0');
strm.next_out = reinterpret_cast<Byte*>(&data[0]);
strm.avail_out = data.size();
CHECK_EQ(Z_STREAM_END, inflate(&strm, Z_FINISH));
CHECK_EQ(0, strm.avail_out);
CHECK_EQ(Z_OK, inflateEnd(&strm));
SendHttpResponse(socket, data);
}
int GetSocketHost(uv_tcp_t* socket, std::string* out_host) {
char ip[INET6_ADDRSTRLEN];
sockaddr_storage addr;
int len = sizeof(addr);
int err = uv_tcp_getsockname(socket,
reinterpret_cast<struct sockaddr*>(&addr),
&len);
if (err != 0)
return err;
if (addr.ss_family == AF_INET6) {
const sockaddr_in6* v6 = reinterpret_cast<const sockaddr_in6*>(&addr);
err = uv_ip6_name(v6, ip, sizeof(ip));
} else {
const sockaddr_in* v4 = reinterpret_cast<const sockaddr_in*>(&addr);
err = uv_ip4_name(v4, ip, sizeof(ip));
}
if (err != 0)
return err;
*out_host = ip;
return err;
}
} // namespace
class Closer {
public:
explicit Closer(InspectorSocketServer* server) : server_(server),
close_count_(0) { }
void AddCallback(InspectorSocketServer::ServerCallback callback) {
if (callback == nullptr)
return;
callbacks_.insert(callback);
}
void DecreaseExpectedCount() {
--close_count_;
NotifyIfDone();
}
void IncreaseExpectedCount() {
++close_count_;
}
void NotifyIfDone() {
if (close_count_ == 0) {
for (auto callback : callbacks_) {
callback(server_);
}
InspectorSocketServer* server = server_;
delete server->closer_;
server->closer_ = nullptr;
}
}
private:
InspectorSocketServer* server_;
std::set<InspectorSocketServer::ServerCallback> callbacks_;
int close_count_;
};
class SocketSession {
public:
static int Accept(InspectorSocketServer* server, int server_port,
uv_stream_t* server_socket);
void Send(const std::string& message);
void Close();
int id() const { return id_; }
bool IsForTarget(const std::string& target_id) const {
return target_id_ == target_id;
}
static int ServerPortForClient(InspectorSocket* client) {
return From(client)->server_port_;
}
private:
SocketSession(InspectorSocketServer* server, int server_port);
static SocketSession* From(InspectorSocket* socket) {
return node::ContainerOf(&SocketSession::socket_, socket);
}
enum class State { kHttp, kWebSocket, kClosing, kEOF, kDeclined };
static bool HandshakeCallback(InspectorSocket* socket,
enum inspector_handshake_event state,
const std::string& path);
static void ReadCallback(uv_stream_t* stream, ssize_t read,
const uv_buf_t* buf);
static void CloseCallback(InspectorSocket* socket, int code);
void FrontendConnected();
void SetDeclined() { state_ = State::kDeclined; }
void SetTargetId(const std::string& target_id) {
CHECK(target_id_.empty());
target_id_ = target_id;
}
const int id_;
InspectorSocket socket_;
InspectorSocketServer* server_;
std::string target_id_;
State state_;
const int server_port_;
};
class ServerSocket {
public:
static int Listen(InspectorSocketServer* inspector_server,
sockaddr* addr, uv_loop_t* loop);
void Close() {
uv_close(reinterpret_cast<uv_handle_t*>(&tcp_socket_),
SocketClosedCallback);
}
int port() const { return port_; }
private:
explicit ServerSocket(InspectorSocketServer* server)
: tcp_socket_(uv_tcp_t()), server_(server), port_(-1) {}
template<typename UvHandle>
static ServerSocket* FromTcpSocket(UvHandle* socket) {
return node::ContainerOf(&ServerSocket::tcp_socket_,
reinterpret_cast<uv_tcp_t*>(socket));
}
static void SocketConnectedCallback(uv_stream_t* tcp_socket, int status);
static void SocketClosedCallback(uv_handle_t* tcp_socket);
static void FreeOnCloseCallback(uv_handle_t* tcp_socket_) {
delete FromTcpSocket(tcp_socket_);
}
int DetectPort();
uv_tcp_t tcp_socket_;
InspectorSocketServer* server_;
int port_;
};
InspectorSocketServer::InspectorSocketServer(SocketServerDelegate* delegate,
uv_loop_t* loop,
const std::string& host,
int port,
FILE* out) : loop_(loop),
delegate_(delegate),
host_(host),
port_(port),
closer_(nullptr),
next_session_id_(0),
out_(out) {
state_ = ServerState::kNew;
}
bool InspectorSocketServer::SessionStarted(SocketSession* session,
const std::string& id) {
if (TargetExists(id) && delegate_->StartSession(session->id(), id)) {
connected_sessions_[session->id()] = session;
return true;
} else {
return false;
}
}
void InspectorSocketServer::SessionTerminated(SocketSession* session) {
int id = session->id();
if (connected_sessions_.erase(id) != 0) {
delegate_->EndSession(id);
if (connected_sessions_.empty()) {
if (state_ == ServerState::kRunning && !server_sockets_.empty()) {
PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
delegate_->GetTargetIds(), out_);
}
if (state_ == ServerState::kStopped) {
delegate_->ServerDone();
}
}
}
delete session;
}
bool InspectorSocketServer::HandleGetRequest(InspectorSocket* socket,
const std::string& path) {
const char* command = MatchPathSegment(path.c_str(), "/json");
if (command == nullptr)
return false;
if (MatchPathSegment(command, "list") || command[0] == '\0') {
SendListResponse(socket);
return true;
} else if (MatchPathSegment(command, "protocol")) {
SendProtocolJson(socket);
return true;
} else if (MatchPathSegment(command, "version")) {
SendVersionResponse(socket);
return true;
} else if (const char* target_id = MatchPathSegment(command, "activate")) {
if (TargetExists(target_id)) {
SendHttpResponse(socket, "Target activated");
return true;
}
return false;
}
return false;
}
void InspectorSocketServer::SendListResponse(InspectorSocket* socket) {
std::vector<std::map<std::string, std::string>> response;
for (const std::string& id : delegate_->GetTargetIds()) {
response.push_back(std::map<std::string, std::string>());
std::map<std::string, std::string>& target_map = response.back();
target_map["description"] = "node.js instance";
target_map["faviconUrl"] = "https://nodejs.org/static/favicon.ico";
target_map["id"] = id;
target_map["title"] = delegate_->GetTargetTitle(id);
Escape(&target_map["title"]);
target_map["type"] = "node";
// This attribute value is a "best effort" URL that is passed as a JSON
// string. It is not guaranteed to resolve to a valid resource.
target_map["url"] = delegate_->GetTargetUrl(id);
Escape(&target_map["url"]);
bool connected = false;
for (const auto& session : connected_sessions_) {
if (session.second->IsForTarget(id)) {
connected = true;
break;
}
}
if (!connected) {
std::string host;
int port = SocketSession::ServerPortForClient(socket);
GetSocketHost(&socket->tcp, &host);
std::ostringstream frontend_url;
frontend_url << "devtools://devtools/bundled";
frontend_url << "/js_app.html?experiments=true&v8only=true&ws=";
frontend_url << FormatWsAddress(host, port, id, false);
target_map["devtoolsFrontendUrl"] += frontend_url.str();
target_map["webSocketDebuggerUrl"] =
FormatWsAddress(host, port, id, true);
}
}
SendHttpResponse(socket, MapsToString(response));
}
bool InspectorSocketServer::Start() {
CHECK_EQ(state_, ServerState::kNew);
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_NUMERICSERV;
hints.ai_socktype = SOCK_STREAM;
uv_getaddrinfo_t req;
const std::string port_string = to_string(port_);
int err = uv_getaddrinfo(loop_, &req, nullptr, host_.c_str(),
port_string.c_str(), &hints);
if (err < 0) {
SE_LOGE("Unable to resolve \"%s\": %s\n", host_.c_str(),
uv_strerror(err));
return false;
}
for (addrinfo* address = req.addrinfo; address != nullptr;
address = address->ai_next) {
err = ServerSocket::Listen(this, address->ai_addr, loop_);
}
uv_freeaddrinfo(req.addrinfo);
if (!connected_sessions_.empty()) {
return true;
}
// We only show error if we failed to start server on all addresses. We only
// show one error, for the last address.
if (server_sockets_.empty()) {
SE_LOGE("Starting inspector on %s:%d failed: %s\n",
host_.c_str(), port_, uv_strerror(err));
if(err == UV_EADDRINUSE) {
SE_LOGE("[FATAL ERROR]: Port [:%s] is occupied by other processes, try to kill the previous debug process or change the port number in `jsb_enable_debugger`.\n", port_string.c_str());
} else {
SE_LOGE("[FATAL ERROR]: Failed to bind port [%s], error code: %d.\n", port_string.c_str(), err);
}
assert(false);//failed to start socket server for chrome debugger
return false;
}
state_ = ServerState::kRunning;
// getaddrinfo sorts the addresses, so the first port is most relevant.
PrintDebuggerReadyMessage(host_, server_sockets_[0]->port(),
delegate_->GetTargetIds(), out_);
return true;
}
void InspectorSocketServer::Stop(ServerCallback cb) {
CHECK_EQ(state_, ServerState::kRunning);
if (closer_ == nullptr) {
closer_ = new Closer(this);
}
closer_->AddCallback(cb);
closer_->IncreaseExpectedCount();
state_ = ServerState::kStopping;
for (ServerSocket* server_socket : server_sockets_)
server_socket->Close();
closer_->NotifyIfDone();
}
void InspectorSocketServer::TerminateConnections() {
for (const auto& session : connected_sessions_) {
session.second->Close();
}
}
bool InspectorSocketServer::TargetExists(const std::string& id) {
const std::vector<std::string>& target_ids = delegate_->GetTargetIds();
const auto& found = std::find(target_ids.begin(), target_ids.end(), id);
return found != target_ids.end();
}
void InspectorSocketServer::Send(int session_id, const std::string& message) {
auto session_iterator = connected_sessions_.find(session_id);
if (session_iterator != connected_sessions_.end()) {
session_iterator->second->Send(message);
}
}
void InspectorSocketServer::ServerSocketListening(ServerSocket* server_socket) {
server_sockets_.push_back(server_socket);
}
void InspectorSocketServer::ServerSocketClosed(ServerSocket* server_socket) {
CHECK_EQ(state_, ServerState::kStopping);
server_sockets_.erase(std::remove(server_sockets_.begin(),
server_sockets_.end(), server_socket),
server_sockets_.end());
if (!server_sockets_.empty())
return;
if (closer_ != nullptr) {
closer_->DecreaseExpectedCount();
}
if (connected_sessions_.empty()) {
delegate_->ServerDone();
}
state_ = ServerState::kStopped;
}
int InspectorSocketServer::Port() const {
if (!server_sockets_.empty()) {
return server_sockets_[0]->port();
}
return port_;
}
// InspectorSession tracking
SocketSession::SocketSession(InspectorSocketServer* server, int server_port)
: id_(server->GenerateSessionId()),
server_(server),
state_(State::kHttp),
server_port_(server_port) { }
void SocketSession::Close() {
CHECK_NE(state_, State::kClosing);
state_ = State::kClosing;
inspector_close(&socket_, CloseCallback);
}
// static
int SocketSession::Accept(InspectorSocketServer* server, int server_port,
uv_stream_t* server_socket) {
// Memory is freed when the socket closes.
SocketSession* session = new SocketSession(server, server_port);
int err = inspector_accept(server_socket, &session->socket_,
HandshakeCallback);
if (err != 0) {
delete session;
}
return err;
}
// static
bool SocketSession::HandshakeCallback(InspectorSocket* socket,
inspector_handshake_event event,
const std::string& path) {
SocketSession* session = SocketSession::From(socket);
InspectorSocketServer* server = session->server_;
const std::string& id = path.empty() ? path : path.substr(1);
switch (event) {
case kInspectorHandshakeHttpGet:
return server->HandleGetRequest(socket, path);
case kInspectorHandshakeUpgrading:
if (server->SessionStarted(session, id)) {
session->SetTargetId(id);
return true;
} else {
session->SetDeclined();
return false;
}
case kInspectorHandshakeUpgraded:
session->FrontendConnected();
return true;
case kInspectorHandshakeFailed:
server->SessionTerminated(session);
return false;
default:
UNREACHABLE();
return false;
}
}
// static
void SocketSession::CloseCallback(InspectorSocket* socket, int code) {
SocketSession* session = SocketSession::From(socket);
CHECK_EQ(State::kClosing, session->state_);
session->server_->SessionTerminated(session);
}
void SocketSession::FrontendConnected() {
CHECK_EQ(State::kHttp, state_);
state_ = State::kWebSocket;
inspector_read_start(&socket_, OnBufferAlloc, ReadCallback);
}
// static
void SocketSession::ReadCallback(uv_stream_t* stream, ssize_t read,
const uv_buf_t* buf) {
InspectorSocket* socket = inspector_from_stream(stream);
SocketSession* session = SocketSession::From(socket);
if (read > 0) {
session->server_->MessageReceived(session->id_,
std::string(buf->base, read));
} else {
session->Close();
}
if (buf != nullptr && buf->base != nullptr)
delete[] buf->base;
}
void SocketSession::Send(const std::string& message) {
inspector_write(&socket_, message.data(), message.length());
}
// ServerSocket implementation
int ServerSocket::DetectPort() {
sockaddr_storage addr;
int len = sizeof(addr);
int err = uv_tcp_getsockname(&tcp_socket_,
reinterpret_cast<struct sockaddr*>(&addr), &len);
if (err != 0)
return err;
int port;
if (addr.ss_family == AF_INET6)
port = reinterpret_cast<const sockaddr_in6*>(&addr)->sin6_port;
else
port = reinterpret_cast<const sockaddr_in*>(&addr)->sin_port;
port_ = ntohs(port);
return err;
}
// static
int ServerSocket::Listen(InspectorSocketServer* inspector_server,
sockaddr* addr, uv_loop_t* loop) {
ServerSocket* server_socket = new ServerSocket(inspector_server);
uv_tcp_t* server = &server_socket->tcp_socket_;
CHECK_EQ(0, uv_tcp_init(loop, server));
int err = uv_tcp_bind(server, addr, 0);
if (err == 0) {
err = uv_listen(reinterpret_cast<uv_stream_t*>(server), 1,
ServerSocket::SocketConnectedCallback);
}
if (err == 0) {
err = server_socket->DetectPort();
}
if (err == 0) {
inspector_server->ServerSocketListening(server_socket);
} else {
uv_close(reinterpret_cast<uv_handle_t*>(server), FreeOnCloseCallback);
}
return err;
}
// static
void ServerSocket::SocketConnectedCallback(uv_stream_t* tcp_socket,
int status) {
if (status == 0) {
ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
// Memory is freed when the socket closes.
SocketSession::Accept(server_socket->server_, server_socket->port_,
tcp_socket);
}
}
// static
void ServerSocket::SocketClosedCallback(uv_handle_t* tcp_socket) {
ServerSocket* server_socket = ServerSocket::FromTcpSocket(tcp_socket);
server_socket->server_->ServerSocketClosed(server_socket);
delete server_socket;
}
} // namespace inspector
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,104 @@
#ifndef SRC_INSPECTOR_SOCKET_SERVER_H_
#define SRC_INSPECTOR_SOCKET_SERVER_H_
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "inspector_agent.h"
#include "inspector_socket.h"
#include "uv.h"
#include <map>
#include <string>
#include <vector>
#if !HAVE_INSPECTOR
#error("This header can only be used when inspector is enabled")
#endif
namespace node {
namespace inspector {
class Closer;
class SocketSession;
class ServerSocket;
class SocketServerDelegate {
public:
virtual bool StartSession(int session_id, const std::string& target_id) = 0;
virtual void EndSession(int session_id) = 0;
virtual void MessageReceived(int session_id, const std::string& message) = 0;
virtual std::vector<std::string> GetTargetIds() = 0;
virtual std::string GetTargetTitle(const std::string& id) = 0;
virtual std::string GetTargetUrl(const std::string& id) = 0;
virtual void ServerDone() = 0;
};
// HTTP Server, writes messages requested as TransportActions, and responds
// to HTTP requests and WS upgrades.
class InspectorSocketServer {
public:
using ServerCallback = void (*)(InspectorSocketServer*);
InspectorSocketServer(SocketServerDelegate* delegate,
uv_loop_t* loop,
const std::string& host,
int port,
FILE* out = stderr);
// Start listening on host/port
bool Start();
// Called by the TransportAction sent with InspectorIo::Write():
// kKill and kStop
void Stop(ServerCallback callback);
// kSendMessage
void Send(int session_id, const std::string& message);
// kKill
void TerminateConnections();
int Port() const;
// Server socket lifecycle. There may be multiple sockets
void ServerSocketListening(ServerSocket* server_socket);
void ServerSocketClosed(ServerSocket* server_socket);
// Session connection lifecycle
bool HandleGetRequest(InspectorSocket* socket, const std::string& path);
bool SessionStarted(SocketSession* session, const std::string& id);
void SessionTerminated(SocketSession* session);
void MessageReceived(int session_id, const std::string& message) {
delegate_->MessageReceived(session_id, message);
}
int GenerateSessionId() {
return next_session_id_++;
}
private:
void SendListResponse(InspectorSocket* socket);
bool TargetExists(const std::string& id);
enum class ServerState {kNew, kRunning, kStopping, kStopped};
uv_loop_t* loop_;
SocketServerDelegate* const delegate_;
const std::string host_;
int port_;
std::string path_;
std::vector<ServerSocket*> server_sockets_;
Closer* closer_;
std::map<int, SocketSession*> connected_sessions_;
int next_session_id_;
FILE* out_;
ServerState state_;
friend class Closer;
};
} // namespace inspector
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif // SRC_INSPECTOR_SOCKET_SERVER_H_

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,165 @@
#pragma once
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "v8.h"
#include <stddef.h>
#ifdef _WIN32
# ifndef BUILDING_NODE_EXTENSION
# define NODE_EXTERN __declspec(dllexport)
# else
# define NODE_EXTERN __declspec(dllimport)
# endif
#else
# define NODE_EXTERN /* nothing */
#endif
#include <assert.h>
#include <stdint.h>
#ifndef NODE_STRINGIFY
#define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n)
#define NODE_STRINGIFY_HELPER(n) #n
#endif
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char (&ArraySizeHelper(T (&array)[N]))[N];
#if !V8_CC_MSVC
// That gcc wants both of these prototypes seems mysterious. VC, for
// its part, can't decide which to use (another mystery). Matching of
// template overloads: the final frontier.
template <typename T, size_t N>
char (&ArraySizeHelper(const T (&array)[N]))[N];
#endif
#ifdef __POSIX__
void RegisterSignalHandler(int signal,
void (*handler)(int signal),
bool reset_handler = false);
#endif // __POSIX__
namespace node {
NODE_EXTERN v8::Local<v8::Value> ErrnoException(v8::Isolate* isolate,
int errorno,
const char* syscall = NULL,
const char* message = NULL,
const char* path = NULL);
NODE_EXTERN v8::Local<v8::Value> UVException(v8::Isolate* isolate,
int errorno,
const char* syscall = NULL,
const char* message = NULL,
const char* path = NULL);
NODE_EXTERN v8::Local<v8::Value> UVException(v8::Isolate* isolate,
int errorno,
const char* syscall,
const char* message,
const char* path,
const char* dest);
typedef double async_id;
struct async_context {
::node::async_id async_id;
::node::async_id trigger_async_id;
};
/* An API specific to emit before/after callbacks is unnecessary because
* MakeCallback will automatically call them for you.
*
* These methods may create handles on their own, so run them inside a
* HandleScope.
*
* `asyncId` and `triggerAsyncId` should correspond to the values returned by
* `EmitAsyncInit()` and `AsyncHooksGetTriggerAsyncId()`, respectively, when the
* invoking resource was created. If these values are unknown, 0 can be passed.
* */
v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
v8::Local<v8::Object> recv,
v8::Local<v8::Function> callback,
int argc,
v8::Local<v8::Value>* argv,
async_context asyncContext);
v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
v8::Local<v8::Object> recv,
const char* method,
int argc,
v8::Local<v8::Value>* argv,
async_context asyncContext);
v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
v8::Local<v8::Object> recv,
v8::Local<v8::String> symbol,
int argc,
v8::Local<v8::Value>* argv,
async_context asyncContext);
/*
* These methods need to be called in a HandleScope.
*
* It is preferred that you use the `MakeCallback` overloads taking
* `async_id` arguments.
*/
v8::Local<v8::Value> MakeCallback(
v8::Isolate* isolate,
v8::Local<v8::Object> recv,
const char* method,
int argc,
v8::Local<v8::Value>* argv);
v8::Local<v8::Value> MakeCallback(
v8::Isolate* isolate,
v8::Local<v8::Object> recv,
v8::Local<v8::String> symbol,
int argc,
v8::Local<v8::Value>* argv);
v8::Local<v8::Value> MakeCallback(
v8::Isolate* isolate,
v8::Local<v8::Object> recv,
v8::Local<v8::Function> callback,
int argc,
v8::Local<v8::Value>* argv);
class IsolateData;
class Environment;
NODE_EXTERN IsolateData* CreateIsolateData(v8::Isolate* isolate,
struct uv_loop_s* loop);
NODE_EXTERN void FreeIsolateData(IsolateData* isolate_data);
NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data,
v8::Local<v8::Context> context,
int argc,
const char* const* argv,
int exec_argc,
const char* const* exec_argv);
NODE_EXTERN void FreeEnvironment(Environment* env);
void SetupProcessObject(Environment* env,
int argc,
const char* const* argv,
int exec_argc,
const char* const* exec_argv);
} // namespace node {
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,141 @@
#include "node_debug_options.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
namespace node {
namespace {
const int default_inspector_port = 9229;
inline std::string remove_brackets(const std::string& host) {
if (!host.empty() && host.front() == '[' && host.back() == ']')
return host.substr(1, host.size() - 2);
else
return host;
}
int parse_and_validate_port(const std::string& port) {
char* endptr;
errno = 0;
const long result = strtol(port.c_str(), &endptr, 10); // NOLINT(runtime/int)
if (errno != 0 || *endptr != '\0'||
(result != 0 && result < 1024) || result > 65535) {
SE_LOGE("Debug port must be 0 or in range 1024 to 65535.\n");
exit(12);
}
return static_cast<int>(result);
}
std::pair<std::string, int> split_host_port(const std::string& arg) {
// remove_brackets only works if no port is specified
// so if it has an effect only an IPv6 address was specified
std::string host = remove_brackets(arg);
if (host.length() < arg.length())
return {host, -1};
size_t colon = arg.rfind(':');
if (colon == std::string::npos) {
// Either a port number or a host name. Assume that
// if it's not all decimal digits, it's a host name.
for (char c : arg) {
if (c < '0' || c > '9') {
return {arg, -1};
}
}
return {"", parse_and_validate_port(arg)};
}
// host and port found
return std::make_pair(remove_brackets(arg.substr(0, colon)),
parse_and_validate_port(arg.substr(colon + 1)));
}
} // namespace
DebugOptions::DebugOptions() :
inspector_enabled_(false),
deprecated_debug_(false),
break_first_line_(false),
host_name_("127.0.0.1"), port_(-1) { }
bool DebugOptions::ParseOption(const char* argv0, const std::string& option) {
bool has_argument = false;
std::string option_name;
std::string argument;
auto pos = option.find("=");
if (pos == std::string::npos) {
option_name = option;
} else {
option_name = option.substr(0, pos);
argument = option.substr(pos + 1);
if (argument.length() > 0)
has_argument = true;
else
argument.clear();
}
// Note that --debug-port and --debug-brk in conjunction with --inspect
// work but are undocumented.
// --debug is no longer valid.
// Ref: https://github.com/nodejs/node/issues/12630
// Ref: https://github.com/nodejs/node/pull/12949
if (option_name == "--inspect") {
inspector_enabled_ = true;
} else if (option_name == "--debug") {
deprecated_debug_ = true;
} else if (option_name == "--inspect-brk") {
inspector_enabled_ = true;
break_first_line_ = true;
} else if (option_name == "--debug-brk") {
break_first_line_ = true;
deprecated_debug_ = true;
} else if (option_name == "--debug-port" ||
option_name == "--inspect-port") {
if (!has_argument) {
SE_LOGE("%s: %s requires an argument\n",
argv0, option.c_str());
exit(9);
}
} else {
return false;
}
#if !HAVE_INSPECTOR
if (inspector_enabled_) {
SE_LOGE("Inspector support is not available with this Node.js build\n");
}
inspector_enabled_ = false;
return false;
#endif
// argument can be specified for *any* option to specify host:port
if (has_argument) {
std::pair<std::string, int> host_port = split_host_port(argument);
if (!host_port.first.empty()) {
host_name_ = host_port.first;
}
if (host_port.second >= 0) {
port_ = host_port.second;
}
}
return true;
}
int DebugOptions::port() const {
int port = port_;
if (port < 0) {
port = default_inspector_port;
}
return port;
}
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,45 @@
#ifndef SRC_NODE_DEBUG_OPTIONS_H_
#define SRC_NODE_DEBUG_OPTIONS_H_
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include <string>
// Forward declaration to break recursive dependency chain with src/env.h.
namespace node {
class DebugOptions {
public:
DebugOptions();
bool ParseOption(const char* argv0, const std::string& option);
void set_inspector_enabled(bool enabled) { inspector_enabled_ = enabled; }
bool inspector_enabled() const { return inspector_enabled_; }
bool deprecated_invocation() const {
return deprecated_debug_ &&
inspector_enabled_ &&
break_first_line_;
}
bool invalid_invocation() const {
return deprecated_debug_ && !inspector_enabled_;
}
void set_wait_for_connect(bool wait) { break_first_line_ = wait; }
bool wait_for_connect() const { return break_first_line_; }
std::string host_name() const { return host_name_; }
void set_host_name(std::string host_name) { host_name_ = host_name; }
int port() const;
void set_port(int port) { port_ = port; }
private:
bool inspector_enabled_;
bool deprecated_debug_;
bool break_first_line_;
std::string host_name_;
int port_;
};
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif // SRC_NODE_DEBUG_OPTIONS_H_

View File

@@ -0,0 +1,192 @@
#ifndef SRC_NODE_MUTEX_H_
#define SRC_NODE_MUTEX_H_
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#include "util.h"
#include "uv.h"
namespace node {
template <typename Traits> class ConditionVariableBase;
template <typename Traits> class MutexBase;
struct LibuvMutexTraits;
using ConditionVariable = ConditionVariableBase<LibuvMutexTraits>;
using Mutex = MutexBase<LibuvMutexTraits>;
template <typename Traits>
class MutexBase {
public:
inline MutexBase();
inline ~MutexBase();
inline void Lock();
inline void Unlock();
class ScopedLock;
class ScopedUnlock;
class ScopedLock {
public:
inline explicit ScopedLock(const MutexBase& mutex);
inline explicit ScopedLock(const ScopedUnlock& scoped_unlock);
inline ~ScopedLock();
private:
template <typename> friend class ConditionVariableBase;
friend class ScopedUnlock;
const MutexBase& mutex_;
NODE_DISALLOW_COPY_AND_ASSIGN(ScopedLock);
};
class ScopedUnlock {
public:
inline explicit ScopedUnlock(const ScopedLock& scoped_lock);
inline ~ScopedUnlock();
private:
friend class ScopedLock;
const MutexBase& mutex_;
NODE_DISALLOW_COPY_AND_ASSIGN(ScopedUnlock);
};
private:
template <typename> friend class ConditionVariableBase;
mutable typename Traits::MutexT mutex_;
NODE_DISALLOW_COPY_AND_ASSIGN(MutexBase);
};
template <typename Traits>
class ConditionVariableBase {
public:
using ScopedLock = typename MutexBase<Traits>::ScopedLock;
inline ConditionVariableBase();
inline ~ConditionVariableBase();
inline void Broadcast(const ScopedLock&);
inline void Signal(const ScopedLock&);
inline void Wait(const ScopedLock& scoped_lock);
private:
typename Traits::CondT cond_;
NODE_DISALLOW_COPY_AND_ASSIGN(ConditionVariableBase);
};
struct LibuvMutexTraits {
using CondT = uv_cond_t;
using MutexT = uv_mutex_t;
static inline int cond_init(CondT* cond) {
return uv_cond_init(cond);
}
static inline int mutex_init(MutexT* mutex) {
return uv_mutex_init(mutex);
}
static inline void cond_broadcast(CondT* cond) {
uv_cond_broadcast(cond);
}
static inline void cond_destroy(CondT* cond) {
uv_cond_destroy(cond);
}
static inline void cond_signal(CondT* cond) {
uv_cond_signal(cond);
}
static inline void cond_wait(CondT* cond, MutexT* mutex) {
uv_cond_wait(cond, mutex);
}
static inline void mutex_destroy(MutexT* mutex) {
uv_mutex_destroy(mutex);
}
static inline void mutex_lock(MutexT* mutex) {
uv_mutex_lock(mutex);
}
static inline void mutex_unlock(MutexT* mutex) {
uv_mutex_unlock(mutex);
}
};
template <typename Traits>
ConditionVariableBase<Traits>::ConditionVariableBase() {
CHECK_EQ(0, Traits::cond_init(&cond_));
}
template <typename Traits>
ConditionVariableBase<Traits>::~ConditionVariableBase() {
Traits::cond_destroy(&cond_);
}
template <typename Traits>
void ConditionVariableBase<Traits>::Broadcast(const ScopedLock&) {
Traits::cond_broadcast(&cond_);
}
template <typename Traits>
void ConditionVariableBase<Traits>::Signal(const ScopedLock&) {
Traits::cond_signal(&cond_);
}
template <typename Traits>
void ConditionVariableBase<Traits>::Wait(const ScopedLock& scoped_lock) {
Traits::cond_wait(&cond_, &scoped_lock.mutex_.mutex_);
}
template <typename Traits>
MutexBase<Traits>::MutexBase() {
CHECK_EQ(0, Traits::mutex_init(&mutex_));
}
template <typename Traits>
MutexBase<Traits>::~MutexBase() {
Traits::mutex_destroy(&mutex_);
}
template <typename Traits>
void MutexBase<Traits>::Lock() {
Traits::mutex_lock(&mutex_);
}
template <typename Traits>
void MutexBase<Traits>::Unlock() {
Traits::mutex_unlock(&mutex_);
}
template <typename Traits>
MutexBase<Traits>::ScopedLock::ScopedLock(const MutexBase& mutex)
: mutex_(mutex) {
Traits::mutex_lock(&mutex_.mutex_);
}
template <typename Traits>
MutexBase<Traits>::ScopedLock::ScopedLock(const ScopedUnlock& scoped_unlock)
: MutexBase(scoped_unlock.mutex_) {}
template <typename Traits>
MutexBase<Traits>::ScopedLock::~ScopedLock() {
Traits::mutex_unlock(&mutex_.mutex_);
}
template <typename Traits>
MutexBase<Traits>::ScopedUnlock::ScopedUnlock(const ScopedLock& scoped_lock)
: mutex_(scoped_lock.mutex_) {
Traits::mutex_unlock(&mutex_.mutex_);
}
template <typename Traits>
MutexBase<Traits>::ScopedUnlock::~ScopedUnlock() {
Traits::mutex_lock(&mutex_.mutex_);
}
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif // SRC_NODE_MUTEX_H_

View File

@@ -0,0 +1,428 @@
// 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_UTIL_INL_H_
#define SRC_UTIL_INL_H_
#ifndef NODE_UTIL_H_INCLUDE
#error "util-inl.h could only be included in util.h"
#endif
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "util.h"
#include <cstring>
#if defined(_MSC_VER)
#include <intrin.h>
#define BSWAP_2(x) _byteswap_ushort(x)
#define BSWAP_4(x) _byteswap_ulong(x)
#define BSWAP_8(x) _byteswap_uint64(x)
#else
#define BSWAP_2(x) ((x) << 8) | ((x) >> 8)
#define BSWAP_4(x) \
(((x) & 0xFF) << 24) | \
(((x) & 0xFF00) << 8) | \
(((x) >> 8) & 0xFF00) | \
(((x) >> 24) & 0xFF)
#define BSWAP_8(x) \
(((x) & 0xFF00000000000000ull) >> 56) | \
(((x) & 0x00FF000000000000ull) >> 40) | \
(((x) & 0x0000FF0000000000ull) >> 24) | \
(((x) & 0x000000FF00000000ull) >> 8) | \
(((x) & 0x00000000FF000000ull) << 8) | \
(((x) & 0x0000000000FF0000ull) << 24) | \
(((x) & 0x000000000000FF00ull) << 40) | \
(((x) & 0x00000000000000FFull) << 56)
#endif
namespace node {
template <typename T>
ListNode<T>::ListNode() : prev_(this), next_(this) {}
template <typename T>
ListNode<T>::~ListNode() {
Remove();
}
template <typename T>
void ListNode<T>::Remove() {
prev_->next_ = next_;
next_->prev_ = prev_;
prev_ = this;
next_ = this;
}
template <typename T>
bool ListNode<T>::IsEmpty() const {
return prev_ == this;
}
template <typename T, ListNode<T> (T::*M)>
ListHead<T, M>::Iterator::Iterator(ListNode<T>* node) : node_(node) {}
template <typename T, ListNode<T> (T::*M)>
T* ListHead<T, M>::Iterator::operator*() const {
return ContainerOf(M, node_);
}
template <typename T, ListNode<T> (T::*M)>
const typename ListHead<T, M>::Iterator&
ListHead<T, M>::Iterator::operator++() {
node_ = node_->next_;
return *this;
}
template <typename T, ListNode<T> (T::*M)>
bool ListHead<T, M>::Iterator::operator!=(const Iterator& that) const {
return node_ != that.node_;
}
template <typename T, ListNode<T> (T::*M)>
ListHead<T, M>::~ListHead() {
while (IsEmpty() == false)
head_.next_->Remove();
}
template <typename T, ListNode<T> (T::*M)>
void ListHead<T, M>::MoveBack(ListHead* that) {
if (IsEmpty())
return;
ListNode<T>* to = &that->head_;
head_.next_->prev_ = to->prev_;
to->prev_->next_ = head_.next_;
head_.prev_->next_ = to;
to->prev_ = head_.prev_;
head_.prev_ = &head_;
head_.next_ = &head_;
}
template <typename T, ListNode<T> (T::*M)>
void ListHead<T, M>::PushBack(T* element) {
ListNode<T>* that = &(element->*M);
head_.prev_->next_ = that;
that->prev_ = head_.prev_;
that->next_ = &head_;
head_.prev_ = that;
}
template <typename T, ListNode<T> (T::*M)>
void ListHead<T, M>::PushFront(T* element) {
ListNode<T>* that = &(element->*M);
head_.next_->prev_ = that;
that->prev_ = &head_;
that->next_ = head_.next_;
head_.next_ = that;
}
template <typename T, ListNode<T> (T::*M)>
bool ListHead<T, M>::IsEmpty() const {
return head_.IsEmpty();
}
template <typename T, ListNode<T> (T::*M)>
T* ListHead<T, M>::PopFront() {
if (IsEmpty())
return nullptr;
ListNode<T>* node = head_.next_;
node->Remove();
return ContainerOf(M, node);
}
template <typename T, ListNode<T> (T::*M)>
typename ListHead<T, M>::Iterator ListHead<T, M>::begin() const {
return Iterator(head_.next_);
}
template <typename T, ListNode<T> (T::*M)>
typename ListHead<T, M>::Iterator ListHead<T, M>::end() const {
return Iterator(const_cast<ListNode<T>*>(&head_));
}
template <typename Inner, typename Outer>
ContainerOfHelper<Inner, Outer>::ContainerOfHelper(Inner Outer::*field,
Inner* pointer)
: pointer_(reinterpret_cast<Outer*>(
reinterpret_cast<uintptr_t>(pointer) -
reinterpret_cast<uintptr_t>(&(static_cast<Outer*>(0)->*field)))) {
}
template <typename Inner, typename Outer>
template <typename TypeName>
ContainerOfHelper<Inner, Outer>::operator TypeName*() const {
return static_cast<TypeName*>(pointer_);
}
template <typename Inner, typename Outer>
inline ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
Inner* pointer) {
return ContainerOfHelper<Inner, Outer>(field, pointer);
}
template <class TypeName>
inline v8::Local<TypeName> PersistentToLocal(
v8::Isolate* isolate,
const v8::Persistent<TypeName>& persistent) {
if (persistent.IsWeak()) {
return WeakPersistentToLocal(isolate, persistent);
} else {
return StrongPersistentToLocal(persistent);
}
}
template <class TypeName>
inline v8::Local<TypeName> StrongPersistentToLocal(
const v8::Persistent<TypeName>& persistent) {
return *reinterpret_cast<v8::Local<TypeName>*>(
const_cast<v8::Persistent<TypeName>*>(&persistent));
}
template <class TypeName>
inline v8::Local<TypeName> WeakPersistentToLocal(
v8::Isolate* isolate,
const v8::Persistent<TypeName>& persistent) {
return v8::Local<TypeName>::New(isolate, persistent);
}
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
const char* data,
int length) {
return v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(data),
v8::NewStringType::kNormal,
length).ToLocalChecked();
}
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
const signed char* data,
int length) {
return v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(data),
v8::NewStringType::kNormal,
length).ToLocalChecked();
}
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
const unsigned char* data,
int length) {
return v8::String::NewFromOneByte(isolate,
reinterpret_cast<const uint8_t*>(data),
v8::NewStringType::kNormal,
length).ToLocalChecked();
}
template <typename TypeName>
void Wrap(v8::Local<v8::Object> object, TypeName* pointer) {
CHECK_EQ(false, object.IsEmpty());
CHECK_GT(object->InternalFieldCount(), 0);
object->SetAlignedPointerInInternalField(0, pointer);
}
void ClearWrap(v8::Local<v8::Object> object) {
Wrap<void>(object, nullptr);
}
template <typename TypeName>
TypeName* Unwrap(v8::Local<v8::Object> object) {
CHECK_EQ(false, object.IsEmpty());
CHECK_GT(object->InternalFieldCount(), 0);
void* pointer = object->GetAlignedPointerFromInternalField(0);
return static_cast<TypeName*>(pointer);
}
void SwapBytes16(char* data, size_t nbytes) {
CHECK_EQ(nbytes % 2, 0);
#if defined(_MSC_VER)
int align = reinterpret_cast<uintptr_t>(data) % sizeof(uint16_t);
if (align == 0) {
// MSVC has no strict aliasing, and is able to highly optimize this case.
uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
size_t len16 = nbytes / sizeof(*data16);
for (size_t i = 0; i < len16; i++) {
data16[i] = BSWAP_2(data16[i]);
}
return;
}
#endif
uint16_t temp;
for (size_t i = 0; i < nbytes; i += sizeof(temp)) {
memcpy(&temp, &data[i], sizeof(temp));
temp = BSWAP_2(temp);
memcpy(&data[i], &temp, sizeof(temp));
}
}
void SwapBytes32(char* data, size_t nbytes) {
CHECK_EQ(nbytes % 4, 0);
#if defined(_MSC_VER)
int align = reinterpret_cast<uintptr_t>(data) % sizeof(uint32_t);
// MSVC has no strict aliasing, and is able to highly optimize this case.
if (align == 0) {
uint32_t* data32 = reinterpret_cast<uint32_t*>(data);
size_t len32 = nbytes / sizeof(*data32);
for (size_t i = 0; i < len32; i++) {
data32[i] = BSWAP_4(data32[i]);
}
return;
}
#endif
uint32_t temp;
for (size_t i = 0; i < nbytes; i += sizeof(temp)) {
memcpy(&temp, &data[i], sizeof(temp));
temp = BSWAP_4(temp);
memcpy(&data[i], &temp, sizeof(temp));
}
}
void SwapBytes64(char* data, size_t nbytes) {
CHECK_EQ(nbytes % 8, 0);
#if defined(_MSC_VER)
int align = reinterpret_cast<uintptr_t>(data) % sizeof(uint64_t);
if (align == 0) {
// MSVC has no strict aliasing, and is able to highly optimize this case.
uint64_t* data64 = reinterpret_cast<uint64_t*>(data);
size_t len64 = nbytes / sizeof(*data64);
for (size_t i = 0; i < len64; i++) {
data64[i] = BSWAP_8(data64[i]);
}
return;
}
#endif
uint64_t temp;
for (size_t i = 0; i < nbytes; i += sizeof(temp)) {
memcpy(&temp, &data[i], sizeof(temp));
temp = BSWAP_8(temp);
memcpy(&data[i], &temp, sizeof(temp));
}
}
char ToLower(char c) {
return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
}
bool StringEqualNoCase(const char* a, const char* b) {
do {
if (*a == '\0')
return *b == '\0';
if (*b == '\0')
return *a == '\0';
} while (ToLower(*a++) == ToLower(*b++));
return false;
}
bool StringEqualNoCaseN(const char* a, const char* b, size_t length) {
for (size_t i = 0; i < length; i++) {
if (ToLower(a[i]) != ToLower(b[i]))
return false;
if (a[i] == '\0')
return true;
}
return true;
}
inline size_t MultiplyWithOverflowCheck(size_t a, size_t b) {
size_t ret = a * b;
if (a != 0)
CHECK_EQ(b, ret / a);
return ret;
}
// These should be used in our code as opposed to the native
// versions as they abstract out some platform and or
// compiler version specific functionality.
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
// that the standard allows them to either return a unique pointer or a
// nullptr for zero-sized allocation requests. Normalize by always using
// a nullptr.
template <typename T>
T* UncheckedRealloc(T* pointer, size_t n) {
size_t full_size = MultiplyWithOverflowCheck(sizeof(T), n);
if (full_size == 0) {
free(pointer);
return nullptr;
}
void* allocated = realloc(pointer, full_size);
if (UNLIKELY(allocated == nullptr)) {
// Tell V8 that memory is low and retry.
LowMemoryNotification();
allocated = realloc(pointer, full_size);
}
return static_cast<T*>(allocated);
}
// As per spec realloc behaves like malloc if passed nullptr.
template <typename T>
inline T* UncheckedMalloc(size_t n) {
if (n == 0) n = 1;
return UncheckedRealloc<T>(nullptr, n);
}
template <typename T>
inline T* UncheckedCalloc(size_t n) {
if (n == 0) n = 1;
MultiplyWithOverflowCheck(sizeof(T), n);
return static_cast<T*>(calloc(n, sizeof(T)));
}
template <typename T>
inline T* Realloc(T* pointer, size_t n) {
T* ret = UncheckedRealloc(pointer, n);
if (n > 0) CHECK_NE(ret, nullptr);
return ret;
}
template <typename T>
inline T* Malloc(size_t n) {
T* ret = UncheckedMalloc<T>(n);
if (n > 0) CHECK_NE(ret, nullptr);
return ret;
}
template <typename T>
inline T* Calloc(size_t n) {
T* ret = UncheckedCalloc<T>(n);
if (n > 0) CHECK_NE(ret, nullptr);
return ret;
}
// Shortcuts for char*.
inline char* Malloc(size_t n) { return Malloc<char>(n); }
inline char* Calloc(size_t n) { return Calloc<char>(n); }
inline char* UncheckedMalloc(size_t n) { return UncheckedMalloc<char>(n); }
inline char* UncheckedCalloc(size_t n) { return UncheckedCalloc<char>(n); }
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_UTIL_INL_H_

View File

@@ -0,0 +1,118 @@
// 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.
#include "util.h"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
//cjh #include "string_bytes.h"
//#include "node_buffer.h"
//#include "node_internals.h"
#include <stdio.h>
namespace node {
using v8::Isolate;
using v8::Local;
using v8::String;
using v8::Value;
template <typename T>
static void MakeUtf8String(Isolate* isolate,
Local<Value> value,
T* target) {
Local<String> string;
if (! value->ToString(isolate->GetCurrentContext()).ToLocal(&string) )
return;
const size_t storage = 3 * string->Length() + 1;
target->AllocateSufficientStorage(storage);
const int flags =
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8;
const int length = string->WriteUtf8(isolate, target->out(), (int)storage, 0, flags);
target->SetLengthAndZeroTerminate(length);
}
Utf8Value::Utf8Value(Isolate* isolate, Local<Value> value) {
if (value.IsEmpty())
return;
MakeUtf8String(isolate, value, this);
}
TwoByteValue::TwoByteValue(Isolate* isolate, Local<Value> value) {
if (value.IsEmpty()) {
return;
}
Local<String> string;
if (! value->ToString(isolate->GetCurrentContext()).ToLocal(&string) )
if (string.IsEmpty())
return;
// Allocate enough space to include the null terminator
const size_t storage = string->Length() + 1;
AllocateSufficientStorage(storage);
const int flags = String::NO_NULL_TERMINATION;
const int length = string->Write(isolate, out(), 0, (int)storage, flags);
SetLengthAndZeroTerminate(length);
}
BufferValue::BufferValue(Isolate* isolate, Local<Value> value) {
// Slightly different take on Utf8Value. If value is a String,
// it will return a Utf8 encoded string. If value is a Buffer,
// it will copy the data out of the Buffer as is.
if (value.IsEmpty()) {
// Dereferencing this object will return nullptr.
Invalidate();
return;
}
if (value->IsString()) {
MakeUtf8String(isolate, value, this);
//cjh } else if (Buffer::HasInstance(value)) {
// const size_t len = Buffer::Length(value);
// // Leave place for the terminating '\0' byte.
// AllocateSufficientStorage(len + 1);
// memcpy(out(), Buffer::Data(value), len);
// SetLengthAndZeroTerminate(len);
} else {
Invalidate();
}
}
void LowMemoryNotification() {
// if (v8_initialized) {
auto isolate = v8::Isolate::GetCurrent();
if (isolate != nullptr) {
isolate->LowMemoryNotification();
}
// }
}
void DumpBacktrace(FILE* fp) {
}
} // namespace node
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR

View File

@@ -0,0 +1,446 @@
// 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_UTIL_H_
#define SRC_UTIL_H_
#include "../../config.hpp"
#if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#define NODE_WANT_INTERNALS 1 //cjh added
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "v8.h"
#include <assert.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <type_traits> // std::remove_reference
namespace node {
// These should be used in our code as opposed to the native
// versions as they abstract out some platform and or
// compiler version specific functionality
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
// that the standard allows them to either return a unique pointer or a
// nullptr for zero-sized allocation requests. Normalize by always using
// a nullptr.
template <typename T>
inline T* UncheckedRealloc(T* pointer, size_t n);
template <typename T>
inline T* UncheckedMalloc(size_t n);
template <typename T>
inline T* UncheckedCalloc(size_t n);
// Same things, but aborts immediately instead of returning nullptr when
// no memory is available.
template <typename T>
inline T* Realloc(T* pointer, size_t n);
template <typename T>
inline T* Malloc(size_t n);
template <typename T>
inline T* Calloc(size_t n);
inline char* Malloc(size_t n);
inline char* Calloc(size_t n);
inline char* UncheckedMalloc(size_t n);
inline char* UncheckedCalloc(size_t n);
// Used by the allocation functions when allocation fails.
// Thin wrapper around v8::Isolate::LowMemoryNotification() that checks
// whether V8 is initialized.
void LowMemoryNotification();
#ifdef __GNUC__
#define NO_RETURN __attribute__((noreturn))
#else
#define NO_RETURN
#endif
// The slightly odd function signature for Assert() is to ease
// instruction cache pressure in calls from CHECK.
NO_RETURN void Abort();
NO_RETURN void Assert(const char* const (*args)[4]);
void DumpBacktrace(FILE* fp);
template <typename T> using remove_reference = std::remove_reference<T>;
#define FIXED_ONE_BYTE_STRING(isolate, string) \
(node::OneByteString((isolate), (string), sizeof(string) - 1))
#define NODE_DISALLOW_COPY_AND_ASSIGN(TypeName) \
void operator=(const TypeName&) = delete; \
void operator=(TypeName&&) = delete; \
TypeName(const TypeName&) = delete; \
TypeName(TypeName&&) = delete
// Windows 8+ does not like abort() in Release mode
#ifdef _WIN32
#define ABORT_NO_BACKTRACE() raise(SIGABRT)
#else
#define ABORT_NO_BACKTRACE() abort()
#endif
#define ABORT() node::Abort()
#ifdef __GNUC__
#define LIKELY(expr) __builtin_expect(!!(expr), 1)
#define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
#define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
#else
#define LIKELY(expr) expr
#define UNLIKELY(expr) expr
#define PRETTY_FUNCTION_NAME ""
#endif
#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)
#define CHECK(expr) \
do { \
if (UNLIKELY(!(expr))) { \
static const char* const args[] = { __FILE__, STRINGIFY(__LINE__), \
#expr, PRETTY_FUNCTION_NAME }; \
node::Assert(&args); \
} \
} while (0)
#define CHECK_EQ(a, b) CHECK((a) == (b))
#define CHECK_GE(a, b) CHECK((a) >= (b))
#define CHECK_GT(a, b) CHECK((a) > (b))
#define CHECK_LE(a, b) CHECK((a) <= (b))
#define CHECK_LT(a, b) CHECK((a) < (b))
#define CHECK_NE(a, b) CHECK((a) != (b))
#define UNREACHABLE() ABORT()
#define ASSIGN_OR_RETURN_UNWRAP(ptr, obj, ...) \
do { \
*ptr = \
Unwrap<typename node::remove_reference<decltype(**ptr)>::type>(obj); \
if (*ptr == nullptr) \
return __VA_ARGS__; \
} while (0)
// TAILQ-style intrusive list node.
template <typename T>
class ListNode;
// TAILQ-style intrusive list head.
template <typename T, ListNode<T> (T::*M)>
class ListHead;
template <typename T>
class ListNode {
public:
inline ListNode();
inline ~ListNode();
inline void Remove();
inline bool IsEmpty() const;
private:
template <typename U, ListNode<U> (U::*M)> friend class ListHead;
ListNode* prev_;
ListNode* next_;
NODE_DISALLOW_COPY_AND_ASSIGN(ListNode);
};
template <typename T, ListNode<T> (T::*M)>
class ListHead {
public:
class Iterator {
public:
inline T* operator*() const;
inline const Iterator& operator++();
inline bool operator!=(const Iterator& that) const;
private:
friend class ListHead;
inline explicit Iterator(ListNode<T>* node);
ListNode<T>* node_;
};
inline ListHead() = default;
inline ~ListHead();
inline void MoveBack(ListHead* that);
inline void PushBack(T* element);
inline void PushFront(T* element);
inline bool IsEmpty() const;
inline T* PopFront();
inline Iterator begin() const;
inline Iterator end() const;
private:
ListNode<T> head_;
NODE_DISALLOW_COPY_AND_ASSIGN(ListHead);
};
// The helper is for doing safe downcasts from base types to derived types.
template <typename Inner, typename Outer>
class ContainerOfHelper {
public:
inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
template <typename TypeName>
inline operator TypeName*() const;
private:
Outer* const pointer_;
};
// Calculate the address of the outer (i.e. embedding) struct from
// the interior pointer to a data member.
template <typename Inner, typename Outer>
inline ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
Inner* pointer);
// If persistent.IsWeak() == false, then do not call persistent.Reset()
// while the returned Local<T> is still in scope, it will destroy the
// reference to the object.
template <class TypeName>
inline v8::Local<TypeName> PersistentToLocal(
v8::Isolate* isolate,
const v8::Persistent<TypeName>& persistent);
// Unchecked conversion from a non-weak Persistent<T> to Local<TLocal<T>,
// use with care!
//
// Do not call persistent.Reset() while the returned Local<T> is still in
// scope, it will destroy the reference to the object.
template <class TypeName>
inline v8::Local<TypeName> StrongPersistentToLocal(
const v8::Persistent<TypeName>& persistent);
template <class TypeName>
inline v8::Local<TypeName> WeakPersistentToLocal(
v8::Isolate* isolate,
const v8::Persistent<TypeName>& persistent);
// Convenience wrapper around v8::String::NewFromOneByte().
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
const char* data,
int length = -1);
// For the people that compile with -funsigned-char.
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
const signed char* data,
int length = -1);
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
const unsigned char* data,
int length = -1);
inline void Wrap(v8::Local<v8::Object> object, void* pointer);
inline void ClearWrap(v8::Local<v8::Object> object);
template <typename TypeName>
inline TypeName* Unwrap(v8::Local<v8::Object> object);
// Swaps bytes in place. nbytes is the number of bytes to swap and must be a
// multiple of the word size (checked by function).
inline void SwapBytes16(char* data, size_t nbytes);
inline void SwapBytes32(char* data, size_t nbytes);
inline void SwapBytes64(char* data, size_t nbytes);
// tolower() is locale-sensitive. Use ToLower() instead.
inline char ToLower(char c);
// strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead.
inline bool StringEqualNoCase(const char* a, const char* b);
// strncasecmp() is locale-sensitive. Use StringEqualNoCaseN() instead.
inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length);
// Allocates an array of member type T. For up to kStackStorageSize items,
// the stack is used, otherwise malloc().
template <typename T, size_t kStackStorageSize = 1024>
class MaybeStackBuffer {
public:
const T* out() const {
return buf_;
}
T* out() {
return buf_;
}
// operator* for compatibility with `v8::String::(Utf8)Value`
T* operator*() {
return buf_;
}
const T* operator*() const {
return buf_;
}
T& operator[](size_t index) {
CHECK_LT(index, length());
return buf_[index];
}
const T& operator[](size_t index) const {
CHECK_LT(index, length());
return buf_[index];
}
size_t length() const {
return length_;
}
// Current maximum capacity of the buffer with which SetLength() can be used
// without first calling AllocateSufficientStorage().
size_t capacity() const {
return IsAllocated() ? capacity_ :
IsInvalidated() ? 0 : kStackStorageSize;
}
// Make sure enough space for `storage` entries is available.
// This method can be called multiple times throughout the lifetime of the
// buffer, but once this has been called Invalidate() cannot be used.
// Content of the buffer in the range [0, length()) is preserved.
void AllocateSufficientStorage(size_t storage) {
CHECK(!IsInvalidated());
if (storage > capacity()) {
bool was_allocated = IsAllocated();
T* allocated_ptr = was_allocated ? buf_ : nullptr;
buf_ = Realloc(allocated_ptr, storage);
capacity_ = storage;
if (!was_allocated && length_ > 0)
memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
}
length_ = storage;
}
void SetLength(size_t length) {
// capacity() returns how much memory is actually available.
CHECK_LE(length, capacity());
length_ = length;
}
void SetLengthAndZeroTerminate(size_t length) {
// capacity() returns how much memory is actually available.
CHECK_LE(length + 1, capacity());
SetLength(length);
// T() is 0 for integer types, nullptr for pointers, etc.
buf_[length] = T();
}
// Make derefencing this object return nullptr.
// This method can be called multiple times throughout the lifetime of the
// buffer, but once this has been called AllocateSufficientStorage() cannot
// be used.
void Invalidate() {
CHECK(!IsAllocated());
length_ = 0;
buf_ = nullptr;
}
// If the buffer is stored in the heap rather than on the stack.
bool IsAllocated() const {
return !IsInvalidated() && buf_ != buf_st_;
}
// If Invalidate() has been called.
bool IsInvalidated() const {
return buf_ == nullptr;
}
// Release ownership of the malloc'd buffer.
// Note: This does not free the buffer.
void Release() {
CHECK(IsAllocated());
buf_ = buf_st_;
length_ = 0;
capacity_ = 0;
}
MaybeStackBuffer() : length_(0), capacity_(0), buf_(buf_st_) {
// Default to a zero-length, null-terminated buffer.
buf_[0] = T();
}
explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
AllocateSufficientStorage(storage);
}
~MaybeStackBuffer() {
if (IsAllocated())
free(buf_);
}
private:
size_t length_;
// capacity of the malloc'ed buf_
size_t capacity_;
T* buf_;
T buf_st_[kStackStorageSize];
};
class Utf8Value : public MaybeStackBuffer<char> {
public:
explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
};
class TwoByteValue : public MaybeStackBuffer<uint16_t> {
public:
explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
};
class BufferValue : public MaybeStackBuffer<char> {
public:
explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
};
#define THROW_AND_RETURN_UNLESS_BUFFER(env, obj) \
do { \
if (!Buffer::HasInstance(obj)) \
return env->ThrowTypeError("argument should be a Buffer"); \
} while (0)
#define SPREAD_BUFFER_ARG(val, name) \
CHECK((val)->IsArrayBufferView()); \
v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>(); \
v8::ArrayBuffer::Contents name##_c = name->Buffer()->GetContents(); \
const size_t name##_offset = name->ByteOffset(); \
const size_t name##_length = name->ByteLength(); \
char* const name##_data = \
static_cast<char*>(name##_c.Data()) + name##_offset; \
if (name##_length > 0) \
CHECK_NE(name##_data, nullptr);
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#define NODE_UTIL_H_INCLUDE
#include "util-inl.h"
#endif // #if (SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_V8) && SE_ENABLE_INSPECTOR
#endif // SRC_UTIL_H_

View File

@@ -0,0 +1,501 @@
0,205,180,120,218,237,125,107,111,220,56,182,224,95,33,140,11,196,1,42,
158,153,187,192,221,197,220,139,5,18,39,153,246,69,30,134,157,204,44,176,
200,7,149,196,114,177,163,146,106,69,201,142,103,208,255,125,207,139,15,73,
148,74,101,187,95,51,1,26,105,151,68,145,135,228,225,121,159,195,127,156,
20,245,46,51,149,61,249,243,255,253,199,73,94,239,118,89,85,240,143,70,
183,93,35,47,76,171,119,240,215,63,78,254,173,209,155,147,63,159,188,166,
143,78,126,90,157,180,247,123,13,15,178,166,201,238,79,86,39,85,182,195,
159,174,211,213,73,161,109,222,152,125,107,234,10,158,191,51,182,85,245,70,
217,110,191,175,155,86,23,74,90,158,157,252,244,101,117,178,133,193,75,221,
224,152,39,235,166,190,179,186,129,46,26,93,21,186,129,63,191,248,254,111,
116,251,122,98,136,43,6,123,106,8,254,1,237,174,243,173,222,101,163,207,
47,155,250,214,192,35,101,170,77,221,236,50,124,172,178,117,221,181,170,221,
106,181,111,234,182,206,235,82,89,250,252,236,132,87,128,87,9,94,238,117,
211,26,249,41,75,99,219,198,84,55,97,109,232,127,195,97,121,54,10,223,
1,156,171,201,143,111,97,117,240,139,137,239,229,53,79,85,186,168,215,63,
234,188,133,47,76,17,118,110,244,125,248,133,251,211,155,42,47,25,246,137,
128,77,226,72,191,195,55,183,89,217,241,234,53,218,118,101,123,22,38,193,
15,224,183,96,211,149,222,213,173,254,200,112,226,24,131,174,190,229,154,33,
43,116,155,153,210,98,87,53,61,201,202,147,63,183,77,167,125,215,218,181,
125,205,77,195,32,111,134,111,126,10,232,164,25,88,220,150,125,214,192,179,
150,145,112,114,27,244,183,61,76,34,185,19,111,252,43,213,214,202,245,204,
155,58,4,122,162,119,222,177,191,52,117,183,31,117,127,125,191,91,215,165,
201,213,13,190,38,132,129,221,202,90,149,103,149,90,107,213,89,192,120,24,
184,209,165,206,172,86,59,88,105,179,47,181,226,78,237,44,32,235,186,134,
175,170,0,137,169,242,178,43,244,57,239,249,59,83,233,151,151,23,9,228,
129,245,218,193,75,171,238,182,26,112,167,81,242,133,194,79,20,124,163,236,
182,238,202,2,33,204,110,97,249,179,53,128,84,116,56,111,66,54,237,209,
229,56,0,173,41,117,213,142,32,186,168,20,191,81,187,186,128,222,221,222,
91,24,12,232,74,229,134,14,195,170,172,209,170,170,91,88,56,33,27,8,
126,81,211,179,125,6,203,10,189,232,188,35,16,213,71,56,104,13,145,137,
255,202,97,128,255,109,117,123,137,109,62,86,30,205,254,235,15,244,70,217,
214,111,255,96,39,247,58,55,27,67,164,6,214,205,228,219,48,130,202,235,
170,213,223,90,220,73,32,41,72,137,226,37,82,23,114,68,29,178,42,99,
85,189,51,45,194,221,95,78,117,103,202,18,151,93,186,129,6,48,28,182,
113,67,200,113,7,10,9,0,97,7,251,236,70,207,28,49,249,238,162,136,
207,150,192,125,238,223,29,179,137,76,69,94,221,255,21,128,30,147,198,191,
9,74,33,144,76,57,112,182,112,2,25,90,88,33,68,42,245,223,215,31,
63,8,146,243,129,8,24,103,17,17,214,247,10,23,69,31,135,95,55,186,
210,13,108,224,101,163,111,141,190,131,23,56,112,99,118,208,101,248,58,13,
240,158,191,137,0,113,189,21,10,182,34,154,208,113,48,1,158,53,127,209,
22,214,76,31,5,79,192,174,0,81,219,104,130,39,67,44,52,173,161,31,
176,84,56,134,67,148,207,23,199,193,151,221,101,166,5,62,186,51,118,122,
55,71,192,224,71,180,44,123,254,82,54,22,22,168,46,111,117,225,113,94,
80,0,176,54,66,114,64,8,60,167,153,146,97,87,202,180,207,44,162,184,
53,40,59,120,52,169,20,28,220,186,17,89,32,197,177,52,225,150,35,225,
240,223,77,89,175,179,82,80,139,87,98,154,237,201,248,110,95,213,223,240,
244,225,137,65,238,220,232,31,25,103,9,17,149,217,248,185,222,193,250,187,
183,79,200,40,113,8,160,63,249,87,248,183,201,114,141,235,228,201,239,147,
115,209,193,190,15,56,233,128,64,23,128,176,72,253,154,72,220,192,15,163,
217,203,19,158,110,76,110,226,101,248,103,38,53,79,64,86,70,88,254,178,
40,148,136,217,196,92,28,2,154,118,171,110,204,173,174,252,35,153,160,41,
14,225,252,121,6,56,254,219,23,242,114,0,243,109,87,229,248,250,99,117,
60,130,186,13,175,21,246,164,54,210,149,66,145,101,32,186,29,64,214,9,
177,207,245,248,90,231,37,128,214,38,229,252,240,206,193,229,1,17,200,120,
187,188,198,150,216,171,172,185,233,144,97,156,5,40,241,249,75,121,60,173,
214,185,15,109,98,111,102,198,177,103,234,37,146,193,222,51,144,76,65,23,
92,235,178,70,17,176,166,169,88,148,102,255,27,40,212,53,117,165,238,234,
166,36,222,132,47,91,248,84,183,61,58,252,79,41,37,254,106,164,140,101,
208,239,98,211,119,177,233,24,177,9,79,186,13,68,40,98,36,69,76,171,
120,77,248,133,28,97,197,68,81,52,217,122,51,192,85,83,193,132,13,237,
58,64,55,69,2,230,172,84,151,108,143,185,119,198,141,186,153,38,109,158,
93,245,103,39,32,6,203,78,207,58,227,250,24,146,21,224,41,149,23,25,
163,143,213,105,93,149,247,110,170,160,161,35,254,193,154,91,93,110,158,207,
48,60,35,61,94,6,3,211,106,52,219,139,126,163,222,172,127,13,126,11,
59,213,131,247,193,236,150,183,56,94,198,13,162,226,131,120,110,56,117,19,
115,5,178,223,131,122,0,38,192,134,173,5,38,27,3,197,172,12,249,5,
109,178,176,180,254,38,175,232,188,193,43,248,201,6,54,132,75,229,91,54,
176,29,1,103,150,231,160,162,212,77,0,246,35,140,186,136,176,141,38,225,
250,234,97,42,31,100,221,194,134,253,193,210,255,158,211,196,254,83,57,108,
140,155,7,190,136,93,194,153,213,6,233,213,111,145,107,216,20,21,187,26,
239,39,224,97,246,51,16,44,79,111,200,62,247,209,25,103,31,113,58,168,
163,163,206,67,98,250,212,9,42,161,216,210,75,4,129,152,59,53,32,5,
190,179,84,46,179,157,46,178,110,214,241,74,139,85,124,26,106,86,64,34,
200,45,235,101,65,186,116,59,73,29,246,103,210,85,23,155,191,1,23,5,
32,223,214,205,107,189,238,110,110,200,239,208,31,236,147,70,62,23,172,100,
240,87,155,85,57,49,92,232,3,85,109,224,196,168,200,223,113,103,132,118,
133,116,71,48,180,160,138,111,123,131,235,10,53,241,177,13,153,30,91,145,
50,137,164,108,198,198,65,96,212,40,134,224,19,16,61,118,112,148,8,105,
89,214,212,3,147,220,57,75,44,78,222,212,183,40,255,43,56,61,149,96,
177,27,9,240,21,228,68,2,192,217,18,145,126,57,51,34,9,133,102,183,
211,5,10,61,64,231,112,150,58,35,227,165,177,212,195,8,208,222,148,11,
99,147,115,126,205,207,151,79,122,216,107,158,53,5,76,22,228,30,253,166,
2,156,75,144,239,215,220,10,37,156,178,228,109,140,132,126,20,229,115,238,
128,76,214,168,175,8,191,79,209,33,167,91,232,246,28,52,153,122,199,103,
225,45,57,141,224,12,240,30,22,147,199,98,68,253,100,205,197,205,50,173,
110,95,20,142,8,240,211,25,198,205,13,98,74,112,237,158,252,42,26,120,
189,219,131,190,197,48,60,189,175,69,186,159,245,159,217,186,107,114,253,249,
234,221,152,244,208,27,213,53,165,8,189,176,177,158,115,184,149,78,114,104,
103,174,66,223,155,109,253,236,166,172,253,119,145,102,38,32,23,50,64,196,
189,164,55,93,60,133,235,64,122,7,50,245,235,186,14,244,216,79,48,235,
67,24,43,27,188,94,177,137,246,144,117,234,170,251,61,120,32,97,107,166,
142,197,252,233,23,246,19,205,237,168,67,255,175,130,73,191,71,231,235,63,
165,213,234,55,239,81,254,125,153,213,126,89,19,218,239,212,68,5,44,192,
58,202,213,83,105,144,10,57,205,32,200,170,113,148,16,124,218,154,68,188,
142,60,151,216,24,68,128,26,21,145,200,118,221,72,139,88,52,23,29,37,
62,153,128,209,59,131,128,123,26,161,70,161,51,172,94,123,213,26,84,140,
222,39,76,130,24,4,255,8,118,112,165,152,182,225,177,135,142,80,120,245,
99,118,149,249,127,232,130,12,138,229,136,142,225,142,109,186,134,246,84,122,
5,250,10,75,14,74,15,80,137,198,220,152,96,228,98,16,113,45,208,211,
201,244,125,7,179,109,238,97,40,96,216,100,194,191,167,70,108,25,64,120,
129,146,154,22,84,8,33,151,192,217,26,153,169,252,206,72,125,163,45,35,
165,55,130,197,10,7,49,77,79,87,236,7,100,13,73,60,69,64,93,7,
254,216,223,211,207,188,38,130,40,97,105,210,2,37,245,53,80,172,39,122,
244,158,180,126,143,186,234,118,24,233,118,81,109,208,136,140,198,155,15,217,
7,248,247,69,244,228,197,31,79,190,172,210,131,127,174,44,40,37,89,105,
254,142,180,47,77,175,46,65,107,1,109,244,86,139,207,153,137,17,108,51,
30,42,216,105,36,84,47,184,91,132,76,164,205,65,32,155,3,212,71,146,
57,107,47,252,217,85,133,222,224,142,195,223,129,149,118,187,53,169,208,129,
130,88,98,157,169,185,8,109,161,199,19,230,87,124,151,166,84,14,52,111,
205,237,202,18,255,7,236,137,34,7,111,0,205,176,87,14,238,218,101,248,
3,24,26,252,123,167,179,175,252,27,255,226,103,166,69,34,89,35,228,66,
48,233,111,34,44,40,152,53,245,183,123,254,191,80,64,4,172,224,177,167,
103,102,187,245,220,228,228,181,218,26,212,200,157,64,198,231,143,57,48,175,
187,99,186,212,152,118,211,146,65,238,168,208,178,188,204,172,253,144,138,64,
20,104,168,129,58,69,250,10,29,229,176,0,207,217,254,242,212,144,101,85,
100,125,191,77,34,239,85,207,24,37,65,19,64,169,81,180,170,49,120,162,
135,219,22,201,7,49,94,249,121,26,76,50,141,134,115,136,218,212,243,148,
58,53,121,72,212,196,41,1,178,175,153,47,109,51,248,138,215,130,190,149,
165,88,169,117,215,178,41,165,221,26,111,86,188,159,145,104,187,228,105,22,
145,54,117,212,143,216,245,120,186,35,153,54,201,35,122,102,198,212,154,77,
145,54,117,138,216,81,213,213,139,225,246,204,57,56,22,153,240,135,155,198,
50,142,4,215,224,28,178,245,26,31,146,152,227,86,92,6,127,24,250,78,
194,187,159,181,80,203,20,24,120,39,171,165,182,203,29,74,178,31,93,46,
233,243,188,215,116,50,202,183,167,207,14,119,252,125,79,120,112,60,157,12,
110,142,169,71,114,76,140,2,201,177,206,23,64,191,44,50,122,171,51,16,
233,102,141,44,219,204,190,170,139,251,216,244,183,113,22,183,69,129,66,242,
209,218,84,69,252,214,5,134,28,25,102,20,66,34,55,230,230,240,248,95,
190,51,215,9,230,250,251,224,158,79,66,71,167,80,187,6,189,123,83,214,
99,173,238,83,67,193,130,27,101,235,157,142,194,229,188,163,10,132,105,54,
120,251,225,250,194,185,42,64,213,65,110,181,49,237,32,58,104,224,41,15,
196,106,194,77,190,159,246,141,186,220,142,62,116,233,241,208,64,127,120,48,
237,205,248,243,193,70,241,200,242,77,26,21,0,37,29,30,160,18,228,237,
27,222,158,33,200,212,199,143,41,34,219,167,239,75,156,149,78,198,74,179,
172,102,44,238,204,144,221,225,150,61,134,240,38,83,82,220,0,81,82,202,
19,210,170,149,247,96,63,134,108,169,151,206,117,205,58,54,41,177,17,2,
222,139,223,157,2,95,171,145,163,251,184,211,159,22,82,63,131,100,246,98,
3,56,87,21,160,202,246,197,14,81,192,83,242,211,7,18,71,165,153,136,
19,51,2,7,181,11,91,189,88,194,248,23,33,225,95,38,143,73,143,210,
44,58,35,105,49,83,200,203,87,125,63,4,17,22,233,69,105,190,106,231,
84,68,178,239,168,208,244,134,66,71,115,251,56,11,132,144,134,17,98,166,
123,75,9,29,15,166,3,200,108,248,4,171,168,85,10,193,63,57,64,21,
40,148,117,206,36,206,155,114,22,40,68,131,89,141,92,52,75,141,150,119,
141,105,147,30,103,225,171,97,73,103,33,133,125,190,71,93,48,223,102,213,
13,52,56,133,51,147,249,69,168,27,198,197,164,126,249,50,10,143,99,99,
176,110,110,49,108,193,162,245,145,98,107,188,89,214,13,183,82,30,251,61,
101,117,7,128,97,110,52,27,71,93,15,167,158,186,37,128,154,92,229,27,
189,220,13,54,59,15,251,232,121,216,199,204,195,206,206,99,10,55,88,112,
239,154,131,248,65,52,135,142,95,164,205,71,0,14,177,3,197,11,179,73,
34,80,161,75,221,11,18,202,235,6,68,198,125,93,21,164,131,45,16,21,
145,170,235,67,64,199,128,218,109,125,103,85,183,247,190,33,238,96,144,238,
233,5,202,234,0,92,139,143,94,102,63,145,79,106,118,109,197,238,127,151,
13,61,88,41,55,206,210,248,56,99,63,30,24,54,136,8,48,227,187,42,
114,141,76,91,61,60,45,20,26,200,45,87,201,46,249,145,200,152,212,60,
102,96,115,168,236,36,164,36,54,79,73,163,137,176,207,249,96,214,24,125,
147,102,223,99,152,196,121,93,97,152,16,77,39,12,16,36,199,95,146,55,
76,173,208,76,128,236,196,74,13,35,29,123,75,166,62,245,142,152,177,213,
179,22,200,88,179,203,74,16,4,111,141,53,232,145,52,85,108,76,193,253,
79,174,245,195,141,164,3,227,229,147,216,55,159,218,76,57,103,214,229,100,
164,71,217,6,167,54,188,151,212,50,54,46,139,162,30,5,175,247,50,84,
206,212,27,246,84,245,245,50,83,244,132,210,139,194,155,124,131,193,51,101,
16,238,47,220,208,120,141,92,178,18,207,24,80,14,50,162,122,126,249,28,
143,197,46,118,33,59,1,180,71,19,17,91,57,114,145,37,223,84,136,68,
42,152,4,93,167,233,144,189,89,201,248,179,115,33,122,213,123,212,137,186,
24,133,70,48,232,247,115,225,38,226,128,139,188,164,189,176,40,14,32,137,
196,95,115,56,246,99,42,214,131,236,36,137,176,178,33,72,220,112,54,178,
44,73,22,127,232,118,25,122,113,179,130,54,157,36,104,110,177,166,88,203,
129,231,121,154,181,122,196,118,158,248,238,219,107,144,63,199,160,131,190,93,
20,160,145,10,138,228,10,90,154,210,100,13,208,46,248,96,198,156,49,92,
186,215,51,198,174,65,185,136,12,253,244,117,201,100,28,115,182,230,248,73,
64,211,97,196,84,2,67,67,228,149,41,102,151,31,33,158,249,26,95,175,
70,161,24,130,148,55,28,184,64,12,200,3,19,194,55,96,139,162,164,217,
228,129,19,32,74,56,173,31,156,201,99,104,163,170,96,255,233,93,56,47,
110,168,178,206,25,209,79,255,248,98,141,158,239,231,243,227,128,166,217,237,
170,137,145,206,233,229,209,99,13,172,153,124,6,47,94,79,119,240,240,184,
211,133,246,150,174,41,199,214,150,171,119,211,16,173,36,22,132,182,245,206,
133,54,187,192,143,204,246,98,160,82,179,142,56,53,167,77,75,214,244,102,
81,214,52,125,242,9,191,136,230,29,158,205,133,21,58,222,178,57,46,61,
123,177,230,54,78,32,112,148,237,142,20,176,176,150,219,108,191,215,213,172,
8,240,128,40,206,9,130,51,138,148,28,69,129,101,20,29,59,174,197,19,
0,62,69,243,55,26,160,158,179,245,111,172,70,88,39,123,97,236,168,232,
60,81,152,82,239,168,121,131,37,65,248,201,236,52,236,234,110,28,9,248,
193,159,174,157,41,75,99,53,172,103,97,149,53,152,17,0,24,230,226,252,
151,137,212,78,0,73,58,230,35,164,244,130,202,148,96,29,35,176,11,99,
89,30,26,122,196,57,28,15,228,172,67,208,250,193,68,114,220,107,25,145,
205,167,32,142,227,17,242,30,185,140,199,152,19,43,223,54,169,173,162,211,
78,198,63,206,139,112,49,96,132,159,156,96,0,10,15,226,67,93,217,99,
244,128,7,56,162,128,136,232,210,155,44,34,114,118,166,222,98,156,149,189,
175,114,126,32,49,10,98,158,200,100,39,135,201,229,120,182,66,174,43,190,
227,46,18,41,231,81,78,57,175,211,164,135,39,119,77,236,163,208,254,37,
66,2,103,190,170,187,94,12,94,76,196,105,2,32,242,231,186,32,248,221,
162,172,150,82,221,125,214,176,30,177,132,180,159,187,204,156,77,19,173,166,
171,14,194,114,8,108,125,209,229,178,152,21,73,190,209,52,24,106,226,98,
46,82,114,57,168,60,142,3,194,33,235,92,92,65,216,171,41,180,191,142,
217,91,34,219,159,102,74,185,153,17,146,43,71,157,21,188,179,217,141,150,
236,59,74,42,98,148,159,224,42,146,176,116,40,30,254,37,172,220,29,232,
219,185,100,100,39,52,153,97,229,162,105,110,21,139,188,227,48,210,11,107,
59,39,88,192,160,9,205,197,88,7,71,63,203,107,60,76,219,212,247,135,
39,23,130,253,11,247,137,10,147,120,170,164,138,120,94,201,57,249,193,103,
103,101,207,75,13,71,36,161,101,70,253,35,162,140,62,84,119,40,131,228,
252,57,106,134,174,246,95,111,52,97,248,222,160,56,187,114,158,115,143,164,
197,8,31,218,136,189,203,130,5,142,159,26,123,89,74,199,220,234,58,169,
37,146,82,56,28,151,205,32,195,21,150,230,87,250,182,254,58,147,75,54,
100,15,128,131,54,193,25,174,232,113,172,128,222,109,239,7,64,53,60,212,
60,139,157,211,216,208,182,199,54,1,233,42,12,176,82,153,13,57,8,176,
207,46,85,81,222,127,118,171,32,70,147,179,3,203,233,87,109,110,14,225,
236,99,98,223,203,203,11,36,86,169,181,116,174,210,178,190,161,73,173,59,
138,180,5,209,51,10,1,189,203,154,138,151,186,48,13,255,251,109,135,226,
145,115,49,181,66,32,9,155,201,21,158,53,62,155,36,252,0,37,173,204,
246,150,224,208,85,225,26,48,225,228,16,211,141,161,14,229,175,55,21,54,
205,235,142,88,16,98,46,62,57,210,117,254,201,123,49,244,12,223,30,232,
18,211,181,96,236,201,129,178,47,15,208,68,28,104,180,145,187,172,136,253,
156,15,72,250,73,128,231,79,253,49,148,32,37,231,49,135,206,179,61,150,
20,137,20,206,17,248,15,212,23,103,113,63,78,84,197,177,114,194,234,30,
202,75,50,213,149,139,125,29,163,124,207,194,122,216,125,54,52,66,161,195,
254,16,201,19,205,54,216,92,66,138,23,25,57,245,55,88,226,82,175,216,
137,24,82,64,164,217,233,115,37,5,71,89,21,112,121,185,207,147,229,72,
151,101,85,251,156,108,231,239,145,186,87,152,113,166,206,75,67,54,97,1,
152,114,79,96,58,46,209,139,121,49,126,143,228,115,155,97,217,7,36,236,
146,47,141,242,126,25,59,181,120,8,148,11,100,22,6,201,83,174,205,237,
96,179,14,166,69,247,160,142,32,142,59,177,186,125,5,180,255,235,190,198,
157,121,153,163,125,121,121,2,114,230,218,15,35,85,238,196,70,141,35,175,
67,255,138,63,240,89,96,227,90,99,248,158,42,234,253,1,192,207,252,47,
60,31,113,63,226,111,76,77,231,250,171,217,191,44,75,74,64,179,203,167,
98,225,179,3,19,193,38,156,252,102,167,103,240,62,251,10,175,17,48,194,
4,242,7,53,29,70,197,34,223,190,119,223,159,134,217,172,98,118,87,212,
187,136,53,233,54,127,126,40,91,53,72,124,78,160,13,93,247,50,114,66,
42,78,152,117,104,26,83,198,87,241,211,20,189,127,39,230,179,105,90,239,
12,108,243,65,127,190,21,99,124,4,184,83,96,112,1,107,213,237,113,245,
138,194,180,190,84,113,10,127,95,221,127,38,195,67,122,203,31,106,123,109,
41,206,32,6,46,107,207,158,208,42,137,83,197,68,114,155,24,233,64,42,
98,98,164,43,12,208,74,200,113,240,20,112,15,195,37,42,79,197,0,8,
187,0,10,60,110,222,181,37,129,25,141,119,77,215,209,51,26,198,189,144,
106,109,67,215,211,196,84,142,51,202,124,220,108,16,70,73,9,38,58,255,
232,109,66,123,156,105,15,23,13,192,228,87,98,61,209,80,254,91,41,144,
225,231,188,10,84,152,50,154,169,208,143,109,235,189,35,97,81,39,46,6,
35,42,38,170,125,133,81,44,14,212,116,73,146,115,141,73,35,145,13,163,
183,4,66,248,189,13,223,67,230,178,234,214,247,138,144,177,161,255,81,124,
223,153,250,72,101,74,6,92,200,16,147,94,137,70,38,165,59,224,172,89,
95,141,192,242,36,41,197,37,198,31,127,154,177,39,159,149,232,197,121,79,
6,28,234,120,127,190,122,43,196,107,151,181,249,54,50,205,226,176,164,142,
24,95,73,18,251,179,221,218,162,240,2,83,231,174,3,20,87,2,67,175,
158,137,155,148,184,230,65,144,55,32,43,196,43,72,3,216,174,185,69,190,
69,100,189,209,101,157,21,246,183,64,151,7,68,203,237,241,44,49,61,235,
177,239,46,43,61,49,95,141,201,251,4,161,61,164,75,7,72,70,135,210,
196,234,116,57,51,244,191,252,193,205,6,71,119,80,77,105,87,223,234,185,
29,57,2,147,190,164,210,232,110,245,4,108,211,245,109,230,42,235,209,136,
79,37,55,236,107,203,177,50,209,138,249,47,207,134,37,229,164,113,36,231,
30,194,223,107,212,186,201,32,129,177,121,140,197,89,131,6,216,185,129,251,
184,77,154,251,4,98,15,181,140,226,33,99,169,83,16,20,203,14,67,237,
158,11,246,162,196,25,97,176,230,142,29,109,6,12,37,63,103,102,221,27,
26,114,206,111,87,21,199,29,205,68,109,4,60,173,121,251,169,126,27,2,
255,7,188,28,79,150,203,206,143,102,200,38,111,204,238,22,54,79,181,94,
79,49,81,176,226,204,204,96,230,207,72,34,111,218,217,66,109,110,61,195,
16,125,245,228,76,57,111,23,177,18,194,1,100,88,184,88,188,57,225,203,
168,176,167,64,54,180,29,1,119,236,244,167,58,162,174,139,73,166,251,90,
245,168,245,145,196,210,199,241,83,64,88,222,53,228,139,152,49,255,80,225,
185,243,216,189,50,62,227,169,250,58,12,171,141,12,193,172,211,250,120,18,
47,123,144,38,155,229,219,129,34,11,123,185,199,18,34,9,191,148,222,131,
240,121,43,213,51,72,231,226,42,196,131,175,47,128,175,77,124,77,250,67,
207,47,21,204,88,241,248,93,59,53,124,215,142,92,91,163,46,72,171,75,
116,80,239,189,174,74,238,154,190,167,41,53,27,92,157,174,212,215,50,43,
242,83,45,202,20,138,166,203,158,33,233,169,112,142,187,204,126,37,111,80,
69,193,166,225,245,90,195,49,16,248,104,30,103,42,220,136,67,129,213,98,
136,143,186,33,77,190,163,176,69,223,81,168,14,201,238,27,24,171,170,185,
61,89,235,195,136,232,239,169,184,52,67,114,190,83,230,41,148,243,82,149,
53,232,113,143,91,13,92,245,199,50,171,107,162,192,239,81,230,60,186,254,
171,191,176,136,169,56,9,174,218,14,148,86,124,117,193,134,199,234,65,5,
156,164,119,51,95,198,73,106,142,156,45,241,217,131,212,220,220,79,185,134,
195,136,155,250,200,18,157,152,123,127,173,129,186,39,77,69,190,178,168,155,
144,229,100,125,235,190,56,178,86,144,77,235,191,126,24,42,195,108,93,153,
147,80,136,138,124,0,168,250,36,197,52,4,77,28,149,44,147,201,247,200,
38,92,76,0,109,229,88,41,152,207,67,68,3,83,47,110,72,106,21,232,
130,11,66,162,185,208,197,215,32,67,4,238,245,215,247,116,60,80,20,221,
115,208,205,2,71,249,140,163,253,168,250,82,8,234,57,39,44,76,86,243,
17,86,195,70,109,158,28,219,182,235,130,21,207,108,67,43,190,223,151,247,
46,102,159,147,32,236,164,167,62,94,164,149,80,177,25,185,133,72,213,117,
194,88,238,15,196,178,32,171,232,82,140,249,1,167,253,125,110,196,185,82,
110,104,181,164,241,185,162,224,67,232,1,34,204,147,145,2,219,7,102,140,
178,130,237,195,170,146,199,160,82,209,220,3,72,163,222,149,156,212,8,43,
88,255,34,179,186,227,57,24,116,2,232,131,54,37,245,186,185,167,106,170,
18,140,226,162,134,177,136,174,216,5,162,17,40,98,19,57,186,239,138,176,
50,224,33,71,219,143,111,122,41,76,95,85,99,99,153,42,61,133,154,99,
39,143,11,107,25,208,136,95,229,140,124,233,9,244,32,24,187,0,145,89,
68,13,65,30,189,178,81,225,142,179,254,77,24,126,13,98,188,61,143,30,
166,100,123,130,6,13,238,77,107,242,174,204,26,185,107,131,70,245,9,83,
107,125,99,170,202,39,214,198,155,245,144,51,208,67,130,161,190,249,216,163,
140,152,43,232,213,175,90,190,228,80,79,106,63,161,199,94,136,235,100,185,
230,68,13,63,59,237,1,7,165,76,83,70,119,158,117,55,91,148,104,96,
19,230,242,123,91,78,31,30,100,157,80,97,193,186,138,43,20,238,38,78,
228,107,74,116,176,82,140,176,255,13,59,103,212,57,231,17,160,1,10,229,
23,177,221,176,245,210,181,197,44,11,134,57,238,128,234,209,68,15,206,212,
5,197,177,149,211,195,161,228,194,38,71,92,139,16,142,48,107,35,148,164,
161,187,6,89,124,240,46,234,99,110,66,20,20,248,69,234,145,46,97,102,
238,108,127,172,226,168,199,95,150,78,172,126,139,215,48,178,200,56,42,83,
78,181,82,187,54,24,177,225,247,41,76,6,211,47,1,47,76,33,197,237,
184,84,8,182,137,186,225,104,22,180,235,224,67,198,191,113,161,117,193,198,
231,63,71,221,205,113,149,226,145,247,61,85,118,211,221,117,32,171,92,68,
182,83,180,188,110,50,42,98,8,173,54,89,105,245,247,42,168,223,111,60,
60,14,38,218,210,143,213,53,236,199,155,205,134,99,80,150,67,69,216,9,
29,112,162,155,207,39,2,165,222,32,230,80,135,81,73,196,134,173,26,112,
136,71,40,116,204,181,129,190,174,168,39,135,67,142,252,215,172,49,113,18,
229,66,71,183,205,235,253,148,167,91,162,215,163,228,31,106,173,232,86,2,
11,135,216,74,228,29,63,230,123,71,20,217,108,159,161,97,175,124,182,82,
207,242,178,182,93,163,159,209,249,120,150,163,201,227,153,124,64,165,53,233,
32,17,77,67,137,253,163,88,126,106,124,147,187,125,7,154,97,246,29,103,
132,193,223,36,157,207,95,108,44,139,145,76,129,112,43,53,25,0,206,161,
29,210,104,88,30,163,210,119,131,60,85,199,249,6,183,158,165,229,57,220,
64,102,103,116,200,182,117,89,88,63,216,227,4,94,86,190,173,75,1,221,
132,57,80,97,90,63,178,187,121,68,118,87,22,219,209,179,112,211,53,85,
147,21,71,253,174,107,19,171,31,176,143,180,12,4,143,52,131,215,112,42,
182,203,113,112,151,125,115,95,12,3,102,190,153,93,183,3,162,15,111,41,
53,208,39,9,176,70,131,149,153,116,219,138,25,138,105,235,31,29,37,37,
221,144,15,36,156,29,64,74,137,138,242,165,85,176,98,210,176,67,117,42,
28,230,121,242,120,74,208,23,150,147,112,161,84,227,46,80,205,250,234,21,
138,249,219,30,94,149,208,118,93,127,187,228,248,139,132,28,237,53,198,62,
174,79,23,213,10,61,13,52,65,108,199,161,180,88,168,71,234,27,185,98,
234,78,57,206,183,26,111,248,100,29,0,239,47,32,71,136,64,57,29,219,
116,165,247,37,90,169,136,104,99,198,129,255,196,193,195,10,197,30,131,82,
225,36,84,88,85,235,109,77,81,37,107,104,137,142,20,148,196,49,142,10,
141,238,123,152,227,31,144,143,246,108,105,210,9,130,229,189,254,208,149,247,
253,201,80,103,100,9,195,137,97,238,12,116,11,12,0,195,14,4,164,112,
67,2,48,53,201,1,198,158,158,225,192,48,24,208,39,13,12,59,147,232,
206,149,218,96,249,51,42,45,108,229,50,17,232,147,91,3,101,127,134,212,
191,171,196,32,190,233,202,99,246,93,23,87,116,106,143,213,6,143,55,232,
140,12,217,244,242,178,182,102,222,237,186,151,22,118,50,162,205,237,159,223,
60,235,221,114,146,54,86,197,107,223,176,61,175,183,71,209,6,9,91,113,
27,254,51,109,145,114,19,71,202,135,231,66,202,168,145,47,208,56,47,35,
250,38,250,184,79,86,104,182,114,2,254,154,198,74,28,31,16,93,41,218,
16,102,122,166,248,200,69,146,148,75,22,77,232,172,18,81,48,93,3,60,
68,138,230,217,62,91,155,210,80,73,60,76,139,23,157,192,10,45,228,80,
154,93,125,139,63,162,96,155,149,63,90,36,195,128,106,27,132,212,21,213,
208,174,57,199,49,88,139,224,27,221,230,136,109,190,138,121,239,82,163,61,
108,60,214,251,164,140,51,95,224,60,153,147,195,211,189,164,160,160,227,239,
168,138,130,123,116,241,100,230,204,201,248,187,166,151,184,214,27,156,74,1,
103,213,253,129,204,65,178,62,161,106,148,142,32,172,57,76,173,63,0,82,
55,83,245,130,238,98,59,12,66,70,113,206,206,34,148,221,216,37,80,112,
18,247,84,110,247,3,33,57,144,212,193,106,225,120,238,153,149,60,204,132,
129,120,166,179,137,41,188,211,213,13,139,6,20,236,55,215,249,148,110,234,
188,52,46,199,110,156,233,53,151,41,16,204,30,199,148,138,216,102,118,155,
170,122,67,150,115,124,121,132,249,124,24,71,63,132,246,229,195,139,59,28,
229,93,123,7,136,129,182,240,69,218,212,39,242,184,185,224,40,199,38,108,
164,225,13,34,248,57,150,243,150,221,95,10,67,0,15,223,198,145,190,174,
233,125,182,79,221,216,36,81,183,130,234,187,108,63,170,38,36,80,246,79,
255,210,245,129,77,189,142,110,139,122,224,10,161,207,207,95,58,117,236,6,
189,175,209,155,254,168,237,121,115,253,31,104,33,233,74,125,92,192,110,73,
199,116,217,208,209,136,252,217,129,212,116,180,221,50,195,242,217,177,33,249,
167,79,184,229,242,57,204,150,107,12,178,48,93,60,168,28,195,76,234,235,
132,135,164,15,61,200,13,46,163,229,214,52,232,109,2,132,67,105,86,51,
164,110,1,36,244,148,193,198,192,138,210,214,32,233,52,98,0,65,149,227,
107,21,178,254,194,61,116,78,120,162,224,120,74,39,65,182,238,162,22,7,
81,37,216,244,45,149,70,248,84,19,119,254,206,156,191,51,231,239,204,249,
247,203,156,191,243,189,239,124,239,247,198,247,54,20,76,131,254,46,4,121,
116,188,70,17,235,46,101,227,16,175,10,145,221,227,91,170,30,155,84,241,
146,2,69,82,49,216,11,67,115,231,22,40,206,33,136,178,100,240,230,223,
74,66,84,220,46,147,71,45,149,9,64,126,168,98,198,164,248,36,65,40,
231,33,152,139,138,31,15,118,86,162,209,124,190,154,139,11,248,63,63,92,
65,87,175,63,190,135,127,223,32,130,98,116,36,138,255,132,104,161,38,149,
207,98,39,241,69,92,142,225,222,164,43,253,163,118,193,227,31,169,51,138,
30,197,15,119,107,115,211,213,157,157,9,54,152,168,109,192,209,6,252,242,
40,250,94,164,136,249,184,80,63,109,110,138,182,15,175,58,152,15,17,252,
193,244,115,241,46,94,219,201,152,191,173,105,251,89,14,83,118,229,95,39,
132,104,242,28,204,163,84,47,33,178,137,235,237,53,20,205,44,145,196,72,
43,115,188,77,189,49,89,34,108,120,28,176,120,0,0,249,172,23,75,252,
229,224,93,113,175,250,68,102,146,80,45,186,44,238,188,231,32,90,16,52,
113,54,151,22,230,236,181,44,5,112,168,219,68,229,158,56,107,97,174,162,
231,245,240,230,187,97,189,142,80,208,216,89,20,207,98,19,161,143,147,121,
160,54,241,208,156,222,190,233,122,80,38,236,73,50,84,251,53,21,167,199,
251,242,52,27,54,48,244,31,115,181,199,220,26,46,174,154,150,154,71,92,
197,56,184,180,149,119,81,229,253,26,80,187,80,10,131,200,208,228,92,123,
113,69,115,216,153,62,34,172,111,71,40,107,184,86,60,250,84,141,139,178,
78,17,4,35,209,102,197,19,197,34,205,214,240,251,16,41,191,169,194,102,
156,30,161,92,182,231,48,102,224,40,140,154,32,239,110,172,136,24,204,8,
135,51,9,110,7,134,95,150,223,52,118,109,193,206,79,203,50,228,241,62,
199,104,133,68,244,166,143,100,136,170,109,204,46,32,147,48,108,232,211,222,
153,223,39,191,143,162,80,140,61,58,84,47,148,58,95,107,14,250,226,124,
105,95,51,222,227,0,90,139,90,121,175,36,55,115,114,55,185,217,68,88,
195,160,28,122,170,186,43,174,89,239,2,143,73,74,84,239,19,39,211,73,
132,55,101,189,206,208,228,67,193,35,88,31,201,144,242,36,33,36,248,23,
165,221,172,78,214,208,226,43,150,64,114,183,156,99,84,13,94,57,195,170,
222,145,133,140,174,125,52,74,106,127,63,186,155,237,164,194,183,139,7,39,
44,226,242,135,140,2,12,254,248,74,40,156,133,143,238,226,96,11,19,245,
103,185,252,33,75,244,188,94,255,25,199,55,69,198,31,252,22,175,44,166,
221,109,144,68,229,24,120,10,50,89,101,13,5,221,51,172,254,66,6,74,
138,175,233,130,27,14,5,161,235,53,48,94,61,22,52,87,147,165,123,166,
176,114,161,225,161,98,149,226,136,51,47,42,44,3,205,241,219,179,186,105,
211,190,155,39,13,15,27,89,99,13,160,185,212,215,217,196,248,233,82,173,
190,32,236,209,34,137,183,243,245,178,137,38,214,29,187,13,9,100,137,126,
201,174,67,17,20,81,127,147,165,26,163,140,183,69,217,134,81,118,27,23,
46,213,62,26,126,234,98,165,126,10,248,3,110,86,250,46,109,62,86,218,
156,201,19,118,142,131,107,151,151,74,164,152,238,254,98,214,113,136,226,194,
153,120,104,125,45,87,154,140,195,15,48,25,16,75,35,227,28,92,13,80,
21,249,61,48,40,184,113,17,196,57,85,223,234,221,153,30,176,64,190,126,
89,20,161,238,71,85,19,77,29,27,82,14,214,211,26,66,137,97,80,114,
27,68,35,145,207,220,192,3,77,249,39,142,139,11,154,246,224,238,39,141,
99,1,192,247,242,237,24,12,185,64,120,203,65,103,95,146,182,69,9,44,
161,10,156,88,185,150,12,188,47,168,242,133,187,127,30,206,234,187,26,195,
173,108,171,51,18,101,67,83,127,214,93,24,200,57,207,232,216,40,144,120,
221,15,6,255,247,23,77,66,38,93,153,180,12,187,136,14,172,180,138,100,
109,254,92,150,109,65,13,214,193,38,17,155,229,65,250,218,253,132,252,194,
181,27,127,4,137,220,203,37,149,110,239,234,230,43,21,91,164,190,95,100,
123,67,181,27,235,134,97,205,246,251,28,243,222,233,44,193,42,202,233,177,
58,239,26,190,180,221,217,179,220,94,48,133,196,110,245,236,61,121,233,252,
36,89,13,21,147,228,126,177,202,80,149,210,213,169,236,149,175,156,30,177,
132,221,46,167,7,196,128,45,211,222,31,127,241,130,235,225,224,189,22,71,
86,215,114,219,28,223,199,177,216,178,63,233,59,236,19,90,207,183,9,119,
67,120,3,23,201,22,0,78,255,244,8,178,191,140,224,31,13,199,100,189,
242,254,161,90,205,31,89,111,197,112,84,227,146,11,144,206,5,143,173,66,
132,217,151,213,28,203,72,16,232,65,189,63,172,6,9,24,113,33,17,122,
203,67,146,77,248,34,145,113,41,221,70,145,127,149,218,153,188,169,165,114,
255,217,76,116,246,249,229,103,37,85,88,155,113,79,103,234,189,68,92,139,
18,47,21,24,162,175,168,228,99,221,20,18,168,215,180,163,146,25,88,92,
102,62,185,236,138,122,224,139,205,177,207,179,222,157,188,82,43,54,220,230,
75,15,226,164,228,182,222,31,140,113,69,48,46,1,84,44,29,142,117,58,
24,91,6,235,191,188,82,64,89,158,75,185,218,17,182,35,243,199,219,88,
59,68,105,214,182,169,180,45,242,137,251,26,3,83,13,86,5,85,207,114,
132,67,23,207,144,209,61,195,96,119,247,96,58,214,155,138,188,99,149,117,
210,17,114,153,200,153,114,83,34,111,44,73,185,163,18,19,97,247,124,4,
70,178,51,151,158,108,42,188,84,2,175,243,59,83,111,162,47,88,144,104,
58,74,82,85,184,98,59,243,119,170,221,13,157,112,168,167,197,106,81,113,
181,237,14,241,201,14,240,162,222,143,247,227,176,56,47,50,206,212,66,240,
107,22,99,40,185,204,42,128,84,99,156,45,58,52,6,64,9,238,202,237,
5,28,181,42,77,70,115,59,156,60,205,203,237,103,115,108,57,142,241,30,
146,244,37,53,10,228,14,162,94,10,111,155,125,213,15,89,67,135,164,249,
146,17,87,7,54,85,93,38,177,168,210,186,32,15,42,149,216,235,81,134,
223,212,26,222,232,246,149,182,237,155,13,52,110,127,190,85,68,91,174,30,
52,29,29,52,85,80,37,37,117,147,53,107,108,21,46,221,61,32,242,77,
242,141,177,51,102,116,179,89,229,113,123,224,115,114,182,187,132,23,57,143,
236,218,137,180,35,231,188,93,46,59,108,77,235,232,233,225,133,15,247,211,
16,195,210,214,71,26,208,93,171,104,60,201,184,152,81,189,143,43,130,59,
99,125,207,70,59,128,104,218,227,188,53,101,1,59,122,240,194,246,115,108,
200,96,152,194,30,37,32,22,26,26,94,165,125,192,159,182,206,3,140,83,
98,77,13,121,134,39,82,140,97,222,226,234,47,100,13,84,140,110,114,109,
190,114,52,107,81,99,118,128,123,217,247,211,139,111,230,147,201,191,166,74,
178,92,70,239,47,80,6,255,105,53,121,199,163,44,226,225,77,125,89,73,
230,67,136,254,113,112,168,22,1,57,155,189,30,20,101,130,15,124,241,247,
232,86,83,124,199,104,174,126,160,4,55,68,6,232,90,199,119,47,173,34,
218,134,169,21,88,52,52,103,198,144,251,29,77,223,107,51,90,159,8,156,
73,124,162,238,146,187,92,74,89,166,125,4,185,245,217,29,48,22,42,130,
36,68,215,117,27,29,223,9,163,30,145,222,79,102,55,181,52,94,112,11,
197,227,19,2,228,116,255,32,52,31,232,157,146,169,22,245,237,214,104,24,
224,105,227,195,142,167,90,54,99,218,22,203,109,19,113,5,254,160,31,28,
22,103,229,37,97,20,222,218,59,214,243,127,204,114,164,236,14,158,225,132,
248,28,210,110,21,186,4,58,79,1,51,120,57,215,173,207,38,119,123,235,
55,103,102,46,184,116,175,177,163,249,233,28,56,28,83,7,227,168,219,12,
147,106,230,181,43,48,19,221,102,245,167,69,183,89,181,66,96,14,145,247,
172,5,66,185,238,34,155,148,13,99,206,209,133,33,161,90,100,47,246,209,
158,89,156,106,156,4,37,83,57,172,26,218,177,6,36,235,168,85,37,36,
224,58,209,11,238,244,146,145,36,18,215,123,102,168,254,144,171,44,57,31,
31,251,36,67,65,63,135,174,42,155,209,143,6,151,25,117,81,133,38,30,
83,234,125,206,232,253,44,73,81,186,226,66,113,109,40,166,101,195,193,126,
137,59,237,70,193,110,189,137,76,203,187,46,45,51,121,246,248,45,90,74,
49,235,191,231,121,37,223,74,79,238,156,89,85,39,243,29,41,7,143,23,
54,177,6,11,110,221,61,250,134,191,199,134,239,47,184,233,111,184,95,163,
37,154,220,50,55,241,241,174,185,62,172,11,194,11,62,33,23,173,239,76,
203,75,119,110,160,55,61,193,190,249,120,215,164,221,92,236,199,194,68,174,
89,189,91,124,135,147,153,45,10,142,1,55,220,253,153,240,201,211,231,179,
209,23,222,133,246,144,154,220,173,105,167,185,163,162,183,46,77,28,147,192,
42,127,5,144,212,191,29,194,153,170,202,88,181,193,170,239,88,127,48,155,
25,235,244,99,169,142,51,234,117,92,198,181,191,254,111,77,101,236,246,103,
220,128,55,85,241,160,61,56,104,197,251,53,247,233,160,19,240,128,69,151,
100,55,41,174,240,131,206,246,28,145,96,31,110,86,164,74,13,47,203,80,
89,156,33,140,44,102,79,58,28,59,250,96,5,111,176,180,203,84,37,82,
245,140,219,225,144,215,85,182,183,219,218,127,243,204,221,77,224,202,54,4,
75,62,7,167,89,249,0,113,156,117,86,180,89,85,33,148,213,21,167,224,
67,32,133,66,123,211,198,15,226,177,127,143,243,29,76,73,236,58,127,97,
51,207,1,227,248,155,71,151,88,235,25,187,248,225,171,251,128,65,23,135,
46,207,138,57,110,188,42,254,243,167,170,59,118,191,91,215,165,201,123,37,
199,144,17,230,92,30,207,213,4,17,203,174,218,97,133,49,180,164,115,167,
118,176,202,89,81,92,184,251,184,194,108,15,57,121,177,101,216,70,119,119,
181,47,76,69,21,27,184,214,125,228,199,255,183,111,163,90,98,209,46,109,
251,75,61,187,146,95,14,5,30,208,252,55,218,71,21,176,189,43,46,142,
168,110,77,134,16,157,90,173,149,36,40,168,119,174,196,25,242,249,29,122,
1,92,197,88,104,233,37,149,35,174,112,218,166,214,9,56,26,160,228,30,
111,170,224,146,23,92,6,133,136,114,67,56,25,86,116,176,64,163,165,56,
188,80,1,169,231,145,249,80,186,168,43,51,198,5,45,105,98,97,223,251,
133,45,199,7,34,117,228,8,190,33,167,112,222,191,197,244,107,100,200,25,
187,15,7,38,52,145,231,88,87,237,185,3,215,247,45,218,144,46,107,99,
233,150,76,99,89,141,149,216,76,58,89,78,191,243,38,15,182,100,72,1,
34,9,244,132,198,255,227,223,255,231,127,252,47,233,81,230,185,192,181,231,
125,139,180,190,11,28,125,110,189,112,111,39,156,126,126,73,233,216,56,159,
110,244,193,161,162,32,9,25,121,44,234,2,29,137,81,240,124,219,85,95,
23,11,90,57,181,238,97,3,185,82,4,64,219,207,254,152,226,59,203,61,
197,5,150,55,157,181,185,212,56,217,99,82,22,55,78,184,236,205,2,243,
103,175,181,174,166,143,221,164,17,105,248,229,140,113,49,220,93,153,8,151,
217,196,103,53,212,185,10,33,57,78,170,110,41,131,77,202,2,53,250,6,
139,239,226,125,0,20,187,149,121,87,77,184,63,143,146,131,173,14,87,60,
26,174,63,54,160,111,254,178,77,170,5,13,103,133,239,250,221,58,109,60,
34,148,6,175,169,162,110,57,251,145,64,162,90,81,66,142,137,6,182,89,
107,63,239,11,244,27,15,4,13,46,122,200,254,219,140,244,136,225,50,242,
23,61,37,97,208,231,225,98,94,7,189,32,182,215,219,180,5,31,78,1,
122,180,128,132,188,201,242,173,251,233,110,231,37,219,218,6,104,21,93,42,
17,217,75,101,124,103,224,118,77,224,121,161,191,173,88,65,38,43,107,220,
50,83,132,211,193,140,228,16,194,17,52,215,13,119,208,110,77,147,252,222,
154,191,235,62,75,24,119,113,246,116,120,136,14,26,196,64,213,241,134,227,
80,49,66,184,33,237,146,92,174,31,210,28,116,145,104,179,192,48,243,36,
190,192,41,182,166,203,205,53,44,253,24,159,202,232,18,27,220,27,199,199,
252,174,84,82,29,149,175,22,82,206,69,151,54,220,36,248,201,188,135,38,
242,248,77,121,248,230,156,82,83,227,141,164,94,199,24,105,123,150,187,171,
178,50,220,148,119,156,191,42,80,135,98,150,221,242,242,28,49,191,25,31,
195,23,236,7,228,19,170,103,12,155,178,203,126,172,27,104,241,39,76,147,
48,21,253,253,239,39,63,253,244,255,1,17,146,119,172