Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use cares_get_32bit as a function helper #34944

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions node.gyp
Expand Up @@ -663,6 +663,7 @@
'src/base_object.h',
'src/base_object-inl.h',
'src/base64.h',
'src/base64-inl.h',
'src/callback_queue.h',
'src/callback_queue-inl.h',
'src/connect_wrap.h',
Expand Down
98 changes: 98 additions & 0 deletions src/base64-inl.h
@@ -0,0 +1,98 @@
#ifndef SRC_BASE64_INL_H_
#define SRC_BASE64_INL_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "util.h"

namespace node {

extern const int8_t unbase64_table[256];


inline static int8_t unbase64(uint8_t x) {
return unbase64_table[x];
}


inline uint32_t ReadUint32BE(const unsigned char* p) {
return static_cast<uint32_t>(p[0] << 24U) |
static_cast<uint32_t>(p[1] << 16U) |
static_cast<uint32_t>(p[2] << 8U) |
static_cast<uint32_t>(p[3]);
}


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 unsigned char txt[] = {
static_cast<unsigned char>(unbase64(src[i + 0])),
static_cast<unsigned char>(unbase64(src[i + 1])),
static_cast<unsigned char>(unbase64(src[i + 2])),
static_cast<unsigned char>(unbase64(src[i + 3])),
};

const uint32_t v = ReadUint32BE(txt);
// 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;
}

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_BASE64_INL_H_
78 changes: 3 additions & 75 deletions src/base64.h
Expand Up @@ -4,6 +4,7 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "util.h"
#include "base64-inl.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove this line, and replace #include "base64.h" with #include "base64-inl.h" instead where necessary?

The general idea here is:

  • .h header files contain declarations, and sometimes some definitions that don’t require including other headers (e.g. for getters/setters)
    • .h header files include only other .h headers
  • -inl.h header files contain definitions of inline functions from the corresponding .h header file, i.e. functions marked inline in the declaration or template functions
    • -inl.h header files include the corresponding .h header file, and other .h and -inl.h header files as needed
    • It’s not always necessary to split out the definitions from the .h file into an -inl.h file, but it becomes necessary when the contents of other -inl.h files start being used, and it is very much recommended when the functions are longer than a few lines to keep the corresponding .h file readable
    • All visible definitions from this file should have been declared in the corresponding .h header file
  • .cc files contain definitions of non-inline functions from the corresponding .h header file
    • .cc files also include the corresponding .h header file, and other .h and -inl.h header files as needed

I hope this is helpful?


#include <cstddef>
#include <cstdint>
Expand All @@ -20,6 +21,8 @@ static inline constexpr size_t base64_decoded_size_fast(size_t size) {
return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0;
}

inline uint32_t ReadUint32BE(const unsigned char* p);

template <typename TypeName>
size_t base64_decoded_size(const TypeName* src, size_t size) {
// 1-byte input cannot be decoded
Expand All @@ -34,81 +37,6 @@ size_t base64_decoded_size(const TypeName* src, size_t size) {
return base64_decoded_size_fast(size);
}


extern const int8_t unbase64_table[256];


inline static int8_t unbase64(uint8_t x) {
return unbase64_table[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) {
Expand Down
18 changes: 6 additions & 12 deletions src/cares_wrap.cc
Expand Up @@ -22,6 +22,7 @@
#define CARES_STATICLIB
#include "ares.h"
#include "async_wrap-inl.h"
#include "base64-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node.h"
Expand Down Expand Up @@ -79,13 +80,6 @@ inline uint16_t cares_get_16bit(const unsigned char* p) {
return static_cast<uint32_t>(p[0] << 8U) | (static_cast<uint32_t>(p[1]));
}

inline uint32_t cares_get_32bit(const unsigned char* p) {
return static_cast<uint32_t>(p[0] << 24U) |
static_cast<uint32_t>(p[1] << 16U) |
static_cast<uint32_t>(p[2] << 8U) |
static_cast<uint32_t>(p[3]);
}

const int ns_t_cname_or_a = -1;

#define DNS_ESETSRVPENDING -1000
Expand Down Expand Up @@ -1127,11 +1121,11 @@ int ParseSoaReply(Environment* env,
return ARES_EBADRESP;
}

const unsigned int serial = cares_get_32bit(ptr + 0 * 4);
const unsigned int refresh = cares_get_32bit(ptr + 1 * 4);
const unsigned int retry = cares_get_32bit(ptr + 2 * 4);
const unsigned int expire = cares_get_32bit(ptr + 3 * 4);
const unsigned int minttl = cares_get_32bit(ptr + 4 * 4);
const unsigned int serial = ReadUint32BE(ptr + 0 * 4);
const unsigned int refresh = ReadUint32BE(ptr + 1 * 4);
const unsigned int retry = ReadUint32BE(ptr + 2 * 4);
const unsigned int expire = ReadUint32BE(ptr + 3 * 4);
const unsigned int minttl = ReadUint32BE(ptr + 4 * 4);

Local<Object> soa_record = Object::New(env->isolate());
soa_record->Set(context,
Expand Down
3 changes: 2 additions & 1 deletion src/node_sockaddr.cc
@@ -1,5 +1,6 @@
#include "node_sockaddr-inl.h" // NOLINT(build/include)
#include "env-inl.h"
#include "base64-inl.h"
#include "base_object-inl.h"
#include "memory_tracker-inl.h"
#include "uv.h"
Expand Down Expand Up @@ -302,7 +303,7 @@ bool in_network_ipv6_ipv4(
return false;

ptr += sizeof(mask);
uint32_t check = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
uint32_t check = ReadUint32BE(ptr);

return (check & m) == (htonl(net_in->sin_addr.s_addr) & m);
}
Expand Down