iu9-ca-web-chat/src/http_server/engine_engine_number_9/socket_address.cpp

277 lines
11 KiB
C++

#include "socket_address.h"
#include <stddef.h>
#include "baza.h"
#include "baza_inter.h"
#include <libregexis024tools/delayed_matching.h>
#include <libregexis024tools/stringmatching.h>
#include <libregexis024vm/libregexis024vm_interface.h>
#include <vector>
#include <assert.h>
#include <algorithm>
namespace een9 {
struct regexp_cmp_out{
std::vector<uint8_t> prg;
regexis024::track_var_list vars;
};
regexp_cmp_out compile_regexp(const char* expr) {
regexp_cmp_out res;
std::string problem;
int ret = regexis024::compile(expr, res.vars, res.prg, problem);
ASSERT(ret == 0, "Can't compile regexp");
return res;
}
struct SocketAddressParser_Inner {
regexp_cmp_out prg;
regexis024::VirtualMachine vm;
regexis024::tai_t tdiff_k;
std::pair<regexis024::tai_t, regexis024::tai_t> i4_k;
std::pair<regexis024::tai_t, regexis024::tai_t> i6_k;
std::pair<regexis024::tai_t, regexis024::tai_t> ip_k;
regexis024::tai_t skip_k;
#define reg_int4 "#4(0|[1-9][0-9]!r{0;2})"
#define reg_int6 "#6(0|[1-9a-fA-F][0-9a-fA-F]!r{0;3})"
#define reg_6RHT_rep(mt) "(:|(:" reg_int6 ")!r{1;" #mt "})"
#define reg_6LFT_rep(ea) "(" reg_int6 ":)!r{" #ea "}"
#define reg_6zs "#s:0;"
#define reg_intp "#p(0|[1-9][0-9]!r{0;4})"
#define reg_addr_in4 "(#t:1;" reg_int4 "." reg_int4 "." reg_int4 "." reg_int4 ":" reg_intp ")"
#define reg_addr_in6_core "(" reg_6LFT_rep(7) reg_int6 "|" ":" reg_6zs reg_6RHT_rep(6) "|" \
reg_6LFT_rep(1) reg_6zs reg_6RHT_rep(5) "|" \
reg_6LFT_rep(2) reg_6zs reg_6RHT_rep(4) "|" \
reg_6LFT_rep(3) reg_6zs reg_6RHT_rep(3) "|" \
reg_6LFT_rep(4) reg_6zs reg_6RHT_rep(2) "|" \
reg_6LFT_rep(5) reg_6zs reg_6RHT_rep(1) "|" \
reg_6LFT_rep(6) reg_6zs ":" ")"
#define reg_addr_in6 "(#t:2;\\[" reg_addr_in6_core "\\]:" reg_intp ")"
SocketAddressParser_Inner(): prg(compile_regexp(
reg_addr_in4 "|" reg_addr_in6
)), vm(prg.prg.size(), prg.prg.data(), UINT64_MAX, UINT16_MAX, UINT32_MAX, UINT32_MAX, UINT64_MAX)
{
ASSERT_pl(vm.initialize() == 0);
tdiff_k = prg.vars.at("t").colarr_first;
skip_k = prg.vars.at("s").colarr_first;
auto obtain_range = [&](const std::string& name) -> std::pair<regexis024::tai_t, regexis024::tai_t> {
const regexis024::TrackingVariableInfo& vi = prg.vars.at(name);
assert(vi.colarr_first > 0 && vi.colarr_second > 0);
return {(regexis024::tai_t)vi.colarr_first, (regexis024::tai_t)vi.colarr_second};
};
i4_k = obtain_range("4");
i6_k = obtain_range("6");
ip_k = obtain_range("p");
}
};
SocketAddressParser::SocketAddressParser() {
opaque = new SocketAddressParser_Inner();
}
SocketAddressParser::~SocketAddressParser() {
delete (SocketAddressParser_Inner*)opaque;
}
int parse_socket_address(const std::string& addr, SocketAddress& res, SocketAddressParser& pdata) {
#define reveal (*(SocketAddressParser_Inner*)pdata.opaque)
reveal.vm.wipeToInit();
ASSERT_pl(reveal.vm.addNewMatchingThread() == 0);
int ret;
for (size_t i = 0; i < addr.size(); i++) {
ret = reveal.vm.feedCharacter((uint64_t)addr[i], 1);
// if (!reveal.vm.haveSurvivors()) {
// printf("DEBUG: died on %s\n", addr.substr(0, i + 1).c_str());
// break;
// }
}
if (reveal.vm.isMatched()) {
std::vector<regexis024::CAEvent> ca = reveal.vm.getMatchedThreadCABranchReverse();
std::reverse(ca.begin(), ca.end());
size_t ci = 0;
#define curKey() ca[ci].key
#define curValue() ca[ci].value
auto extractRange = [&](std::pair<regexis024::tai_t, regexis024::tai_t> rk) -> std::string {
assert(ca[ci].key == rk.first && ca[ci + 1].key == rk.second);
size_t oci = ci;
ci += 2;
return getSubstring(addr, ca[oci].value, ca[oci + 1].value);
};
assert(curKey() == reveal.tdiff_k);
if (curValue() == 1) {
ci++;
uint32_t res_addr = 0;
for (int i = 0; i < 4; i++) {
std::string h = extractRange(reveal.i4_k);
uint32_t p = std::stoul(h);
if (p > 255)
return -1;
res_addr = ((res_addr << 8) | p);
}
uint32_t res_port = std::stoul(extractRange(reveal.ip_k));
if (res_port > 65535)
return -1;
res.v.gen.sa_family = AF_INET;
res.v.sin.sin_port = htons(res_port); // host to network short
res.v.sin.sin_addr.s_addr = htonl(res_addr); // host to network long
res.addrLen = sizeof(sockaddr_in);
} else if (curValue() == 2){
ci++;
int skipped = 8;
for (const regexis024::CAEvent& ev: ca) {
if (ev.key == reveal.i6_k.first)
skipped--;
}
assert(skipped == 0 || skipped >= 2);
uint16_t res_u6_addr16[8];
size_t bi = 0;
std::string h;
while (bi < 8) {
if (curKey() == reveal.i6_k.first) {
h = extractRange(reveal.i6_k);
assert(h.size() <= 4);
uint32_t v = 0;
for (char ch: h) {
v <<= 4;
if ('0' <= ch && ch <= '9') {
v |= (uint32_t)(ch - '0');
} else if ('a' <= ch && ch <= 'z') {
v |= (uint32_t)(ch - 'a' + 10);
} else if ('A' <= ch && ch <= 'Z') {
v |= (uint32_t)(ch - 'A' + 10);
} else
assert(false);
}
assert(v <= UINT16_MAX);
res_u6_addr16[bi++] = (uint16_t)v;
} else if (curKey() == reveal.skip_k) {
ci++;
for (int j = 0; j < skipped; j++)
res_u6_addr16[bi++] = 0;
} else
assert(false);
}
assert(bi == 8);
uint32_t res_port = std::stoul(extractRange(reveal.ip_k));
if (res_port > 65535)
return -1;
res.v.gen.sa_family = AF_INET6;
res.v.sin6.sin6_port = htons(res_port);
for (int i = 0; i < 8; i++)
res.v.sin6.sin6_addr.__in6_u.__u6_addr16[i] = htons(res_u6_addr16[i]);
res.addrLen = sizeof(sockaddr_in6);
} else
assert(false);
assert(ci == ca.size());
return 0;
}
const std::string& up = "unix:";
if (beginsWith(addr, up)) {
std::string path = addr.substr(up.size());
if (path.empty())
return -1;
if (path.back() == '/')
return -1;
for (char ch: path)
if (ch == 0)
return -1;
res.v.gen.sa_family = AF_UNIX;
if (sizeof(res.v.sun.sun_path) > path.size())
THROW("path is too big");
memcpy(res.v.sun.sun_path, path.c_str(), path.size());
res.addrLen = offsetof(sockaddr_un, sun_path) + path.size();
return 0;
}
return -1;
}
std::string short2hex(uint16_t v) {
if (v == 0)
return "0";
std::string result;
while (v) {
result += (char)((v & 0xf) > 9 ? (v & 0xf) - 10 + 'a' : (v & 0xf) + '0');
v >>= 4;
}
std::reverse(result.begin(), result.end());
return result;
}
std::string stringify_socket_address(const SocketAddress &addr) {
if (addr.v.gen.sa_family == AF_INET) {
char buf[22];
uint32_t IP = ntohl(addr.v.sin.sin_addr.s_addr);
uint16_t port = ntohs(addr.v.sin.sin_port);
snprintf(buf, 22, "%u.%u.%u.%u:%hu", (IP >> 24) & 0xff, (IP >> 16) & 0xff, (IP >> 8) & 0xff,
(IP >> 0) & 0xff, port);
return buf;
} else if (addr.v.gen.sa_family == AF_INET6) {
uint16_t IP[8];
for (int i = 0; i < 8; i++)
IP[i] = ntohs(addr.v.sin6.sin6_addr.__in6_u.__u6_addr16[i]);
uint16_t port = ntohs(addr.v.sin6.sin6_port);
int largest_sz = 0;
int largest_start = 0;
int cur_sz = 0;
for (int i = 0; i < 8; i++) {
if (IP[i] == 0) {
cur_sz++;
if (largest_sz < cur_sz) {
largest_sz = cur_sz;
largest_start = i + 1 - cur_sz;
}
} else {
cur_sz = 0;
}
}
std::string core;
for (int i = 0; i < 8;) {
if (largest_sz >= 2 && largest_start == i) {
i += largest_sz;
if (i == 8)
core += "::";
else
core += ":";
} else {
if (i > 0)
core += ":";
core += short2hex(IP[i]);
i++;
}
}
assert(core.size() <= 39);
char buf[48];
snprintf(buf, 48, "[%s]:%hu", core.c_str(), port);
return buf;
} else if (addr.v.gen.sa_family == AF_UNIX) {
assert(addr.addrLen > offsetof(sockaddr_un, sun_path));
size_t path_len = addr.addrLen - offsetof(sockaddr_un, sun_path);
assert(path_len <= sizeof(addr.v.sun.sun_path));
std::string path(path_len, ')');
memcpy(path.data(), addr.v.sun.sun_path, path_len);
return "unix:" + path;
} else
return "Socket address of unknown domain";
}
void bind_to_socket_address(int sockfd, const SocketAddress &addr) {
int ret;
if (addr.v.gen.sa_family == AF_INET) {
ret = bind(sockfd, (const sockaddr*)&addr.v.sin, addr.addrLen);
} else if (addr.v.gen.sa_family == AF_INET6) {
ret = bind(sockfd, (const sockaddr*)&addr.v.sin6, addr.addrLen);
} else if (addr.v.gen.sa_family == AF_INET) {
ret = bind(sockfd, (const sockaddr*)&addr.v.sun, addr.addrLen);
} else
THROW("binding socket to address of unsupported domain");
ASSERT_on_iret(ret, "binding socket");
}
void get_peer_name_as_socket_address(int sockfd, SocketAddress &res) {
socklen_t willbecome = sizeof(res.v);
int ret = getpeername(sockfd, &res.v.gen, &willbecome);
ASSERT_on_iret(ret, "getpeername");
assert(willbecome <= sizeof(res.v));
res.addrLen = willbecome;
}
}