From 0d1956435039ed624da7a15d705adb52a4def62d Mon Sep 17 00:00:00 2001 From: jyelon Date: Tue, 14 Feb 2023 13:15:41 -0500 Subject: [PATCH] More changes for dll refactor --- luprex/core/cpp/driver-common.cpp | 539 ------------------------------ luprex/core/cpp/driver-linux.cpp | 269 --------------- luprex/core/cpp/driver-mingw.cpp | 295 ---------------- luprex/core/cpp/driver-ssl.cpp | 200 ----------- luprex/core/cpp/driver-ssl.hpp | 59 ---- luprex/core/cpp/driver-util.cpp | 528 ----------------------------- luprex/core/cpp/driver-util.hpp | 149 --------- luprex/core/obj/.gitkeep | 0 8 files changed, 2039 deletions(-) delete mode 100644 luprex/core/cpp/driver-common.cpp delete mode 100644 luprex/core/cpp/driver-linux.cpp delete mode 100644 luprex/core/cpp/driver-mingw.cpp delete mode 100644 luprex/core/cpp/driver-ssl.cpp delete mode 100644 luprex/core/cpp/driver-ssl.hpp delete mode 100644 luprex/core/cpp/driver-util.cpp delete mode 100644 luprex/core/cpp/driver-util.hpp delete mode 100644 luprex/core/obj/.gitkeep diff --git a/luprex/core/cpp/driver-common.cpp b/luprex/core/cpp/driver-common.cpp deleted file mode 100644 index 32adb630..00000000 --- a/luprex/core/cpp/driver-common.cpp +++ /dev/null @@ -1,539 +0,0 @@ - -#define CHBUF_SIZE (256 * 1024) -#define POLLVEC_SIZE (DrivenEngine::MAX_CHAN + 1) - -static MonoClock monoclock; - -namespace util { - -double profiling_clock() { return monoclock.get(); } - -} // namespace util - -static void if_error_print_and_exit(const std::string &str) { - if (!str.empty()) { - std::cerr << std::endl << "error: " << str << std::endl; - exit(1); - } -} - -static std::string_view read_file(const char *fn, char *buf, int bufsize, - std::string &err) { - FILE *f = fopen(fn, "r"); - if (f == 0) { - err = std::string("cannot read file") + fn; - buf[0] = 0; - return std::string_view(buf, 0); - } - int nread = fread(buf, 1, bufsize, f); - if (nread < 0) { - err = std::string("cannot read file: ") + fn; - buf[0] = 0; - return std::string_view(buf, 0); - } - if (nread == bufsize) { - err = std::string("file too large: ") + fn; - buf[0] = 0; - return std::string_view(buf, 0); - } - err = ""; - return std::string_view(buf, nread); -} -class Driver { - public: - enum ChanState { - CHAN_INACTIVE, - CHAN_PLAINTEXT, - CHAN_SSL_CONNECTING, - CHAN_SSL_ACCEPTING, - CHAN_SSL_READWRITE, - }; - struct ChanInfo { - int chid; - SOCKET socket; - SSL *ssl; - - ChanState state; - int nbytes; - const char *bytes; - bool ready_now; - bool ready_on_pollin; - bool ready_on_pollout; - bool ready_on_outgoing; - int last_write_nbytes; - - bool marked_for_deletion() const { return state == CHAN_INACTIVE; } - }; - - std::vector chans_; - std::map listen_sockets_; - bool read_console_recently_; - std::unique_ptr chbuf_; - std::unique_ptr pollvec_; - drv::ReplayRecorder recorder_; - - drvssl::UniqueCTX ssl_server_ctx_; - drvssl::UniqueCTX ssl_client_secure_ctx_; - drvssl::UniqueCTX ssl_client_insecure_ctx_; - - void handle_listen_ports() { - const auto &listenports = recorder_.drv_get_listen_ports(); - for (int port : listenports) { - if (listen_sockets_.find(port) == listen_sockets_.end()) { - std::string err; - SOCKET sock = listen_on_port(port, err); - if_error_print_and_exit(err); - assert(sock != INVALID_SOCKET); - listen_sockets_[port] = sock; - } - } - } - - void handle_lua_source() { - if (recorder_.drv_get_rescan_lua_source()) { - std::string err; - std::string_view ctrl = - read_file("lua/control.lst", chbuf_.get(), CHBUF_SIZE, err); - if_error_print_and_exit(err); - std::vector names = drv::parse_control_lst(ctrl); - recorder_.drv_clear_lua_source(); - for (const std::string &str : names) { - std::string lfn = std::string("lua/") + str; - std::string_view data = - read_file(lfn.c_str(), chbuf_.get(), CHBUF_SIZE, err); - if_error_print_and_exit(err); - recorder_.drv_add_lua_source(str, data); - } - } - } - - void close_channel(ChanInfo &chan, std::string_view err) { - // std::cerr << "Closing channel " << chan.chid << std::endl; - assert(chan.state != CHAN_INACTIVE); - // Close and release the SSL channel. - if (chan.ssl != nullptr) { - SSL_free(chan.ssl); - chan.ssl = nullptr; - } - // Close and release the socket. - assert(chan.socket != INVALID_SOCKET); - assert(socket_close(chan.socket) == 0); - chan.socket = INVALID_SOCKET; - // Close everything else. - recorder_.drv_notify_close(chan.chid, err); - chan.state = CHAN_INACTIVE; - chan.chid = -1; - chan.nbytes = 0; - chan.bytes = 0; - chan.ready_now = false; - chan.ready_on_pollin = false; - chan.ready_on_pollout = false; - chan.ready_on_outgoing = false; - chan.last_write_nbytes = 0; - } - - void handle_console_output() { - while (true) { - std::string_view s = recorder_.drv_peek_outgoing(0); - if (s.size() == 0) break; - int nwrote = console_write(s.data(), s.size()); - if (nwrote <= 0) break; - recorder_.drv_sent_outgoing(0, nwrote); - } - } - - void handle_console_input() { - char buffer[256]; - read_console_recently_ = false; - while (true) { - int nread = console_read(buffer, 256); - if (nread <= 0) break; - read_console_recently_ = true; - recorder_.drv_recv_incoming(0, std::string_view(buffer, nread)); - } - } - - void make_channel(SOCKET sock, int chid, SSL_CTX *ctx, ChanState state) { - ChanInfo newchan; - newchan.chid = chid; - newchan.socket = sock; - newchan.ssl = SSL_new(ctx); - newchan.state = state; - newchan.nbytes = 0; - newchan.bytes = 0; - newchan.ready_now = false; - newchan.ready_on_pollin = false; - newchan.ready_on_pollout = true; - newchan.ready_on_outgoing = false; - newchan.last_write_nbytes = 0; - SSL_set_fd(newchan.ssl, newchan.socket); - // SSL_set_msg_callback(newchan.ssl, SSL_trace); - // SSL_set_msg_callback_arg(newchan.ssl, BIO_new_fp(stderr,0)); - chans_.push_back(newchan); - } - - void handle_new_outgoing_sockets() { - const auto &chans = recorder_.drv_get_new_outgoing(); - for (int chid : chans) { - std::string err, cert, host, port; - std::string target(recorder_.drv_get_target(chid)); - drv::split_target(target, cert, host, port); - if (cert.empty() || host.empty() || port.empty()) { - recorder_.drv_notify_close( - chid, std::string("invalid target: ") + target); - continue; - } - SSL_CTX *ctx = nullptr; - if (cert == "cert") { - ctx = ssl_client_secure_ctx_.get(); - } else if (cert == "nocert") { - ctx = ssl_client_insecure_ctx_.get(); - } else { - recorder_.drv_notify_close( - chid, std::string("invalid cert rule: ") + target); - continue; - } - SOCKET sock = open_connection(host.c_str(), port.c_str(), err); - if (sock == INVALID_SOCKET) { - recorder_.drv_notify_close(chid, err); - continue; - } - // std::cerr << "Opening channel " << chid << std::endl; - make_channel(sock, chid, ctx, CHAN_SSL_CONNECTING); - } - if (!chans.empty()) { - recorder_.drv_clear_new_outgoing(); - } - } - - void accept_connection(int port, SOCKET sock) { - std::string err; - SOCKET socket = accept_on_socket(sock, err); - if_error_print_and_exit(err); - if (socket != INVALID_SOCKET) { - int chid = recorder_.drv_notify_accept(port); - // std::cerr << "Accepted channel " << chid << std::endl; - make_channel(socket, chid, ssl_server_ctx_.get(), - CHAN_SSL_ACCEPTING); - } - } - - void advance_plaintext(ChanInfo &chan) { - std::string err; - - // Try to write plaintext to the channel. - std::string_view s = recorder_.drv_peek_outgoing(chan.chid); - if (s.size() > 0) { - int sbytes = s.size(); - if (sbytes > 65536) sbytes = 65536; - int wbytes = socket_send(chan.socket, s.data(), sbytes, err); - if (wbytes < 0) { - close_channel(chan, err); - } else { - recorder_.drv_sent_outgoing(chan.chid, wbytes); - } - } - - // Try to read plaintext from the channel. - // Someday, find a way to avoid this copy. - int nrecv = socket_recv(chan.socket, chbuf_.get(), 65536, err); - if (nrecv < 0) { - close_channel(chan, err); - } else { - recorder_.drv_recv_incoming(chan.chid, - std::string_view(chbuf_.get(), nrecv)); - } - - // Update the ready-flags for next time. - chan.ready_on_outgoing = true; - chan.ready_on_pollin = true; - } - - void process_ssl_error(ChanInfo &chan, int retval) { - int error = SSL_get_error(chan.ssl, retval); - // std::cerr << "SSL error code = " << error << " "; - if (error == SSL_ERROR_WANT_READ) { - chan.ready_on_pollin = true; - } else if (error == SSL_ERROR_WANT_WRITE) { - chan.ready_on_pollout = true; - } else { - std::string error = drvssl::error_string(); - if (error == "") error = "unknown error"; - close_channel(chan, error); - } - } - - void advance_ssl_connecting(ChanInfo &chan) { - // std::cerr << "In advance_ssl_connecting" << std::endl; - int retval = SSL_connect(chan.ssl); - if (retval == 1) { - // Connection successful. - chan.state = CHAN_SSL_READWRITE; - chan.ready_now = true; - } else { - // std::cerr << "ssl_connect_error"; - process_ssl_error(chan, retval); - } - } - - void advance_ssl_accepting(ChanInfo &chan) { - // std::cerr << "In advance_ssl_accepting" << std::endl; - int retval = SSL_accept(chan.ssl); - if (retval == 1) { - // Connection successful. - chan.state = CHAN_SSL_READWRITE; - chan.ready_now = true; - } else { - process_ssl_error(chan, retval); - } - } - - void advance_ssl_readwrite(ChanInfo &chan) { - // std::cerr << "In advance_ssl_readwrite" << std::endl; - // Try to read data. - int read_result = SSL_read(chan.ssl, chbuf_.get(), 65536); - if (read_result > 0) { - recorder_.drv_recv_incoming( - chan.chid, std::string_view(chbuf_.get(), read_result)); - chan.ready_now = true; - } else { - process_ssl_error(chan, read_result); - if (chan.state == CHAN_INACTIVE) return; - } - - // Try to write data. - int wbytes; - if (chan.last_write_nbytes > 0) { - wbytes = chan.last_write_nbytes; - assert(wbytes < chan.nbytes); - } else { - wbytes = chan.nbytes; - if (wbytes > 65536) wbytes = 65536; - } - if (wbytes > 0) { - int write_result = SSL_write(chan.ssl, chan.bytes, wbytes); - if (write_result > 0) { - recorder_.drv_sent_outgoing(chan.chid, write_result); - chan.last_write_nbytes = 0; - chan.ready_on_outgoing = true; - } else { - chan.last_write_nbytes = wbytes; - process_ssl_error(chan, write_result); - if (chan.state == CHAN_INACTIVE) return; - } - } else { - chan.ready_on_outgoing = true; - } - // std::cerr << "rpi=" << chan.ready_on_pollin << ".rpo=" << - // chan.ready_on_pollout << ".rn=" << chan.ready_now << ".rog=" << - // chan.ready_on_outgoing << " "; - } - - void advance_channel(ChanInfo &chan) { - drvssl::clear_all_errors(); - switch (chan.state) { - case CHAN_PLAINTEXT: - advance_plaintext(chan); - break; - case CHAN_SSL_CONNECTING: - advance_ssl_connecting(chan); - break; - case CHAN_SSL_ACCEPTING: - advance_ssl_accepting(chan); - break; - case CHAN_SSL_READWRITE: - advance_ssl_readwrite(chan); - break; - default: - assert(false); - break; - } - } - - void handle_socket_input_output() { - std::string err; - int mstimeout = read_console_recently_ ? 100 : 1000; - - // Peek output buffers and determine channel release flags. - bool any_released = false; - for (ChanInfo &chan : chans_) { - std::string_view s = recorder_.drv_peek_outgoing(chan.chid); - chan.nbytes = s.size(); - chan.bytes = s.data(); - if (chan.nbytes == 0) { - if (recorder_.drv_get_channel_released(chan.chid)) { - close_channel(chan, ""); - any_released = true; - } - } - } - - // Delete any released channels - if (any_released) { - util::remove_marked_items(chans_); - } - - // Construct the struct pollfd vector. - int pollsize = 0; - for (const auto &p : listen_sockets_) { - struct pollfd &pfd = pollvec_[pollsize++]; - pfd.fd = p.second; - pfd.events = POLLIN; - pfd.revents = 0; - } - for (const ChanInfo &chan : chans_) { - struct pollfd &pfd = pollvec_[pollsize++]; - assert(chan.socket != INVALID_SOCKET); - pfd.fd = chan.socket; - pfd.events = 0; - pfd.revents = 0; - if (chan.ready_now) mstimeout = 0; - if (chan.ready_on_pollin) pfd.events |= POLLIN; - if (chan.ready_on_pollout) pfd.events |= POLLOUT; - if (chan.ready_on_outgoing && (chan.nbytes > 0)) - pfd.events |= POLLOUT; - // std::cerr << "evt=" << pfd.events << ".nb=" << chan.nbytes << - // std::endl; - } - - // Do the poll. - socket_poll(pollvec_.get(), pollsize, mstimeout, err); - if_error_print_and_exit(err); - - // Check listening sockets. - int index = 0; - for (auto &p : listen_sockets_) { - struct pollfd &pfd = pollvec_[index++]; - if (pfd.revents & (POLLIN | POLLERR)) { - accept_connection(p.first, p.second); - } - } - - // Advance channels where possible. - for (ChanInfo &chan : chans_) { - struct pollfd &pfd = pollvec_[index++]; - bool pollin = ((pfd.revents & POLLIN) != 0); - bool pollout = ((pfd.revents & POLLOUT) != 0); - bool pollerr = ((pfd.revents & (POLLERR | POLLHUP)) != 0); - if (chan.ready_now || pollerr || - (chan.ready_on_pollin && pollin) || - (chan.ready_on_pollout && pollout) || - (chan.ready_on_outgoing && (chan.nbytes > 0) && pollout)) { - chan.ready_now = false; - chan.ready_on_pollin = false; - chan.ready_on_pollout = false; - chan.ready_on_outgoing = false; - advance_channel(chan); - } - chan.nbytes = 0; - chan.bytes = 0; - } - - // Delete any newly-inactive channels - util::remove_marked_items(chans_); - } - - int replay_logfile(const char *fn, bool verbose) { - drv::ReplayPlayer player; - player.open_logfile(fn); - if (verbose) { - player.enable_stdout(); - } - while (true) { - drv::ReplayPlayer::Status st = player.step(); - if (st != drv::ReplayPlayer::ST_REPLAYING) { - player.print_status(std::cerr); - return (st == drv::ReplayPlayer::ST_CLEAN_EXIT) ? 0 : 1; - } - } - } - - int drive(int argc, char *argv[]) { - // Remove the program name from argv. - if (argc < 1) { - DrivenEngine::print_usage(std::cerr, ""); - exit(1); - } - std::string program = argv[0]; - argc -= 1; - argv += 1; - - // If argv contains "replay ", do a replay, - // and then skip everything else. - if (argc >= 1) { - std::string cmd(argv[0]); - if ((cmd == "replay") || (cmd == "vreplay")) { - if (argc != 2) { - std::cerr << "usage: " << program << " replay " - << std::endl; - return 1; - } - return replay_logfile(argv[1], cmd == "vreplay"); - } - } - - // If argv contains "record ", start recording, - // and remove the "record " from argv. - if (argc >= 1) { - std::string cmd = argv[0]; - if (cmd == "record") { - if (argc < 2) { - DrivenEngine::print_usage(std::cerr, program); - return 1; - } - bool ok = recorder_.open_logfile(argv[1]); - if (!ok) { - std::cerr << "Could not open logfile: " << argv[1] - << std::endl; - return 1; - } - argc -= 2; - argv += 2; - } - } - - // Create the engine. - if (argc < 1) { - DrivenEngine::print_usage(std::cerr, program); - return 1; - } - bool engine_made = recorder_.create_engine(argv[0]); - if (!engine_made) { - DrivenEngine::print_usage(std::cerr, program); - return 1; - } - - read_console_recently_ = false; - - chbuf_.reset(new char[CHBUF_SIZE]); - pollvec_.reset(new struct pollfd[POLLVEC_SIZE]); - - ssl_server_ctx_.reset(drvssl::new_context(SSL_VERIFY_NONE)); - ssl_client_secure_ctx_.reset(drvssl::new_context(SSL_VERIFY_PEER)); - ssl_client_insecure_ctx_.reset(drvssl::new_context(SSL_VERIFY_NONE)); - ssl_load_certificate_authorities(ssl_client_secure_ctx_.get()); - drvssl::ctx_load_dummy_cert(ssl_server_ctx_.get()); - - handle_lua_source(); - recorder_.drv_invoke_event_init(argc, argv); - handle_listen_ports(); - - while (!recorder_.drv_get_stop_driver()) { - handle_lua_source(); - handle_console_output(); - handle_new_outgoing_sockets(); - handle_socket_input_output(); - handle_console_input(); - handle_console_output(); - recorder_.drv_invoke_event_update(monoclock.get()); - } - - for (ChanInfo &chan : chans_) { - close_channel(chan, ""); - } - - DrivenEngine::set(nullptr); - recorder_.clean_exit(); - return 0; - } -}; diff --git a/luprex/core/cpp/driver-linux.cpp b/luprex/core/cpp/driver-linux.cpp deleted file mode 100644 index 4bdecbbd..00000000 --- a/luprex/core/cpp/driver-linux.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include "wrap-map.hpp" -#include "wrap-vector.hpp" -#include "wrap-string.hpp" - -#include "driver-util.hpp" -#include "driver-ssl.hpp" -#include "drivenengine.hpp" -#include "util.hpp" -#include "source.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using SOCKET=int; -const int INVALID_SOCKET = -1; - -struct termios orig_termios; - -std::string strerror_str(int err) { - char errbuf[256]; - return strerror_r(err, errbuf, 256); -} - -void set_nonblocking(int fd) { - int flags = fcntl(fd, F_GETFL, 0); - assert(flags != -1); - int status = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - assert(status != -1); -} - -static void disable_tty_raw() { - tcsetattr(0, TCSAFLUSH, &orig_termios); -} - -static void enable_tty_raw() { - int status = tcgetattr(0, &orig_termios); - assert(status >= 0); - atexit(disable_tty_raw); - struct termios raw = orig_termios; - raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); - raw.c_lflag &= ~(ECHO | ICANON); - raw.c_oflag |= OPOST; - raw.c_cc[VMIN] = 0; - raw.c_cc[VTIME] = 0; - status = tcsetattr(0, TCSAFLUSH, &raw); - assert(status >= 0); -} - -static SOCKET open_connection(const char *host, const char *port, std::string &err) { - struct addrinfo *addrs = nullptr; - struct addrinfo *goodaddr = nullptr; - struct addrinfo hints; - SOCKET sock = INVALID_SOCKET; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_NUMERICSERV; - - err.clear(); - int status = getaddrinfo(host, port, &hints, &addrs); - if (status != 0) { - err = gai_strerror(status); - goto error_general; - } - if (addrs == nullptr) { - err = "no such host found"; - goto error_general; - } - goodaddr = addrs; - assert(goodaddr->ai_family == AF_INET); - assert(goodaddr->ai_socktype == SOCK_STREAM); - assert(goodaddr->ai_protocol == IPPROTO_TCP); - sock = socket(goodaddr->ai_family, goodaddr->ai_socktype, goodaddr->ai_protocol); - if (sock <= 0) goto error_errno; - - set_nonblocking(sock); - - status = connect(sock, goodaddr->ai_addr, goodaddr->ai_addrlen); - if ((status != 0) && (errno != EINPROGRESS)) goto error_errno; - - freeaddrinfo(addrs); - return sock; - -error_errno: - err = strerror_str(errno); -error_general: - if (sock != INVALID_SOCKET) close(sock); - if (addrs != nullptr) freeaddrinfo(addrs); - return INVALID_SOCKET; -} - -static SOCKET listen_on_port(int port, std::string &err) { - int status, enable; - err.clear(); - - SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock <= 0) goto error_errno; - - enable = 1; - status = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)); - if (status != 0) goto error_errno; - - struct sockaddr_in server; - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = htons(port); - - status = bind(sock, (struct sockaddr *)&server, sizeof(server)); - if (status != 0) goto error_errno; - - status = listen(sock, 10); - if (status != 0) goto error_errno; - - set_nonblocking(sock); - return sock; - -error_errno: - err = strerror_str(errno); - if (sock >= 0) close(sock); - return INVALID_SOCKET; -} - -static SOCKET accept_on_socket(SOCKET listen_socket, std::string &err) { - err.clear(); - SOCKET chsock = accept(listen_socket, nullptr, nullptr); - if (chsock >= 0) { - set_nonblocking(chsock); - return chsock; - } else { - if ((errno != EAGAIN) && (errno != EWOULDBLOCK) && (errno != ECONNABORTED)) { - err = strerror_str(errno); - } - return INVALID_SOCKET; - } -} - -// the return values for socket_send and socket_recv are: -// -// positive: sent or received bytes successfully -// zero: would block -// negative: channel closed, possibly cleanly or possibly with error -// -static int socket_send(SOCKET socket, const char *bytes, int nbytes, std::string &err) { - err.clear(); - int wbytes = send(socket, bytes, nbytes, 0); - if (wbytes < 0) { - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { - return 0; - } else { - err = strerror_str(errno); - return -1; - } - } else { - return wbytes; - } -} - -static int socket_recv(SOCKET socket, char *bytes, int nbytes, std::string &err) { - err.clear(); - int nrecv = recv(socket, bytes, nbytes, 0); - if (nrecv < 0) { - if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) { - err = strerror_str(errno); - return -1; - } else { - return 0; - } - } else if (nrecv == 0) { - return -1; - } else { - return nrecv; - } -} - -static int socket_close(SOCKET socket) { - return close(socket); -} - -static int socket_poll(struct pollfd *pollvec, int pollcount, int mstimeout, std::string &err) { - // socket_poll is implicitly expected to also poll stdin, - // if the OS allows that. Linux does, so we add stdin to the - // poll vector. The poll vector is required to have at - // least one free space in order to do this. - pollvec[pollcount].fd = 0; - pollvec[pollcount].events = POLLIN; - pollcount += 1; - - // Do the poll. - int status = poll(pollvec, pollcount, mstimeout); - if (status < 0) { - err = strerror_str(errno); - return -1; - } - return 0; -} - -static int console_write(const char *bytes, int nbytes) { - return write(1, bytes, nbytes); -} - -static int console_read(char *bytes, int nbytes) { - return read(0, bytes, nbytes); -} - -static void ssl_load_certificate_authorities(SSL_CTX *ctx) { - assert(SSL_CTX_set_default_verify_paths(ctx) == 1); -} - -static void disable_randomization(int argc, char *argv[]) { - const int old_personality = personality(ADDR_NO_RANDOMIZE); - if (!(old_personality & ADDR_NO_RANDOMIZE)) { - const int new_personality = personality(ADDR_NO_RANDOMIZE); - if (new_personality & ADDR_NO_RANDOMIZE) { - execv(argv[0], argv); - } - } -} - - -class MonoClock { -private: - struct timespec base_; -public: - MonoClock() { - int status = clock_gettime(CLOCK_MONOTONIC, &base_); - assert(status == 0); - } - double get() { - struct timespec t; - int status = clock_gettime(CLOCK_MONOTONIC, &t); - assert(status == 0); - double tv_sec = t.tv_sec - base_.tv_sec; - double tv_nsec = t.tv_nsec - base_.tv_nsec; - return tv_sec + (tv_nsec * 1.0E-9); - } -}; - -#include "driver-common.cpp" - - -int main(int argc, char **argv) -{ - disable_randomization(argc, argv); - enable_tty_raw(); - assert(OPENSSL_init_ssl(0, NULL) == 1); - drvssl::clear_all_errors(); - SourceDB::register_lua_builtins(); - Driver driver; - return driver.drive(argc, argv); -} - diff --git a/luprex/core/cpp/driver-mingw.cpp b/luprex/core/cpp/driver-mingw.cpp deleted file mode 100644 index b025ec67..00000000 --- a/luprex/core/cpp/driver-mingw.cpp +++ /dev/null @@ -1,295 +0,0 @@ -#define WINVER 0x0600 -#define _WIN32_WINNT 0x0600 - -#include "wrap-map.hpp" -#include "wrap-string.hpp" -#include "wrap-vector.hpp" - -#include "driver-util.hpp" -#include "driver-ssl.hpp" -#include "drivenengine.hpp" -#include "util.hpp" -#include "source.hpp" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void set_nonblocking(SOCKET sock) { - u_long mode = 1; // 1 to enable non-blocking socket - int status = ioctlsocket(sock, FIONBIO, &mode); - assert(status == 0); -} - -std::string strerror_str(int errcode) { - std::ostringstream oss; - oss << "error " << errcode; - return oss.str(); -} - -static PADDRINFOA find_good_addr(PADDRINFOA addrinfo) { - for (PADDRINFOA addr = addrinfo; addr != nullptr; addr = addr->ai_next) { - if (addr->ai_family == AF_INET) { - return addr; - } - } - return nullptr; -} - -static SOCKET open_connection(const char *host, const char *port, std::string &err) { - PADDRINFOA addrs = nullptr; - PADDRINFOA goodaddr = nullptr; - SOCKET sock = INVALID_SOCKET; - - err.clear(); - int status = getaddrinfo(host, port, nullptr, &addrs); - while (status == WSATRY_AGAIN) { - status = getaddrinfo(host, port, nullptr, &addrs); - } - if (status == WSAHOST_NOT_FOUND) { - err = "host not found"; - goto error; - } - if (status != 0) { - err = "DNS resolution malfunction"; - goto error; - } - goodaddr = find_good_addr(addrs); - if (goodaddr == nullptr) { - err = "host not an internet host"; - goto error; - } - sock = socket(goodaddr->ai_family, SOCK_STREAM, IPPROTO_TCP); - if (sock == INVALID_SOCKET) { - err = "could not create a socket"; - goto error; - } - set_nonblocking(sock); - status = connect(sock, goodaddr->ai_addr, goodaddr->ai_addrlen); - if (status != 0) { - int errcode = WSAGetLastError(); - if (errcode != WSAEWOULDBLOCK) { - err = "connect failure"; - goto error; - } - } - freeaddrinfo(addrs); - return sock; - -error: - if (sock != INVALID_SOCKET) closesocket(sock); - if (addrs != nullptr) freeaddrinfo(addrs); - return SOCKET_ERROR; -} - -SOCKET listen_on_port(int port, std::string &err) { - int status; - err.clear(); - SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock == INVALID_SOCKET) { - err = "could not create a socket"; - goto error; - } - - struct sockaddr_in server; - server.sin_family = AF_INET; - server.sin_addr.s_addr = INADDR_ANY; - server.sin_port = htons(port); - - status = bind(sock, (struct sockaddr *)&server, sizeof(server)); - if (status < 0) { - err = "could not bind port"; - goto error; - } - status = listen(sock, 10); - if (status < 0) { - err = "could not listen on socket"; - goto error; - } - set_nonblocking(sock); - std::cerr << "listening socket is " << sock << std::endl; - return sock; - -error: - if (sock != INVALID_SOCKET) closesocket(sock); - return SOCKET_ERROR; -} - -static SOCKET accept_on_socket(SOCKET listen_socket, std::string &err) { - SOCKET chsock = accept(listen_socket, nullptr, nullptr); - if (chsock != INVALID_SOCKET) { - set_nonblocking(chsock); - return chsock; - } else { - int errcode = WSAGetLastError(); - if ((errcode == WSAEWOULDBLOCK) || (errcode == WSAECONNRESET)) { - return INVALID_SOCKET; - } else { - err = "accept failed"; - return INVALID_SOCKET; - } - } -} - -static int socket_send(SOCKET socket, const char *bytes, int nbytes, std::string &err) { - err.clear(); - int wbytes = send(socket, bytes, nbytes, 0); - if (wbytes == SOCKET_ERROR) { - int errcode = WSAGetLastError(); - if (errcode == WSAEWOULDBLOCK) { - return 0; - } else { - err = "send failure"; - return -1; - } - } else { - assert(wbytes > 0); - return wbytes; - } -} - -static int socket_recv(SOCKET socket, char *bytes, int nbytes, std::string &err) { - err.clear(); - int nrecv = recv(socket, bytes, nbytes, 0); - if (nrecv < 0) { - int errcode = WSAGetLastError(); - if (errcode == WSAEWOULDBLOCK) { - return 0; - } else { - err = "recv failure"; - return -1; - } - } else if (nrecv == 0) { - return -1; - } else { - return nrecv; - } -} - -static int socket_close(SOCKET socket) { - return closesocket(socket); -} - -static int socket_poll(struct pollfd *pollvec, int pollcount, int mstimeout, std::string &err) { - if (pollcount == 0) { - if (mstimeout > 0) Sleep(mstimeout); - return 0; - } - int status = WSAPoll(pollvec, pollcount, mstimeout); - if (status < 0) { - err = strerror_str(WSAGetLastError()); - return -1; - } - return status; -} - -static void init_winsock() { - WSADATA data; - int errcode = WSAStartup(2, &data); - if (errcode != 0) { - fprintf(stderr, "Winsock didn't initalize, error %d", errcode); - exit(1); - } -} - -static int console_write(const char *bytes, int nbytes) { - if (nbytes == 0) return 0; - HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE); - assert(hstdout != INVALID_HANDLE_VALUE); - DWORD nwrote; - if (nbytes > 10000) nbytes = 10000; - assert(WriteConsoleA(hstdout, bytes, nbytes, &nwrote, nullptr)); - assert(nwrote > 0); - return nwrote; -} - -static int console_read(char *bytes, int nbytes) { - HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE); - assert(hstdin != INVALID_HANDLE_VALUE); - INPUT_RECORD inrecords[512]; - DWORD nread, nevents; - int nascii = 0; - if (GetNumberOfConsoleInputEvents(hstdin, &nevents)) { - if (int(nevents) > nbytes) nevents = nbytes; - ReadConsoleInputA(hstdin, inrecords, nevents, &nread); - for (int i = 0; i < int(nread); i++) { - const INPUT_RECORD &inr = inrecords[i]; - if (inr.EventType != KEY_EVENT) continue; - const KEY_EVENT_RECORD &key = inr.Event.KeyEvent; - if (!key.bKeyDown) continue; - char c = key.uChar.AsciiChar; - bytes[nascii++] = c; - } - return nascii; - } else { - return 0; - } -} - -static void ssl_load_certificate_authorities(SSL_CTX *ctx) { - HCERTSTORE hStore = CertOpenSystemStoreW(0, L"ROOT"); - PCCERT_CONTEXT pContext = NULL; - X509 *x509; - X509_STORE *store = SSL_CTX_get_cert_store(ctx); - - if (!hStore) { - fprintf(stderr, "Cannot open system certificate store.\n"); - exit(1); - } - - while ((pContext = CertEnumCertificatesInStore(hStore, pContext))) { - const unsigned char *encoded_cert = pContext->pbCertEncoded; - x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded); - if (x509) { - X509_STORE_add_cert(store, x509); - X509_free(x509); - } - } - - CertCloseStore(hStore, 0); -} - -class MonoClock { -public: - double freq_; - - MonoClock() { - LARGE_INTEGER x; - BOOL status = QueryPerformanceFrequency(&x); - assert(status != 0); - freq_ = 1.0 / double(x.QuadPart); - } - - double get() { - LARGE_INTEGER x; - BOOL status = QueryPerformanceCounter(&x); - assert(status != 0); - return double(x.QuadPart) * freq_; - } -}; - -#include "driver-common.cpp" - -int main(int argc, char **argv) -{ - init_winsock(); - OPENSSL_init_ssl(0, NULL); - SourceDB::register_lua_builtins(); - Driver driver; - return driver.drive(argc, argv); -} - diff --git a/luprex/core/cpp/driver-ssl.cpp b/luprex/core/cpp/driver-ssl.cpp deleted file mode 100644 index fddf19e9..00000000 --- a/luprex/core/cpp/driver-ssl.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "driver-ssl.hpp" -#include -#include -#include -#include - -extern std::string strerror_str(int err); - -namespace drvssl { - -const char *dummy_cert = - "-----BEGIN CERTIFICATE-----\n" - "MIIDezCCAmOgAwIBAgIUajKmxrLMr9zBMlphrTJU5qKG8FgwDQYJKoZIhvcNAQEL\n" - "BQAwTDELMAkGA1UEBhMCVVMxFTATBgNVBAgMDFBlbm5zeWx2YW5pYTESMBAGA1UE\n" - "CgwJbG9jYWxob3N0MRIwEAYDVQQDDAlsb2NhbGhvc3QwIBcNMjIwMzIyMTczMzA4\n" - "WhgPMjEyMjAyMjYxNzMzMDhaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQIDAxQZW5u\n" - "c3lsdmFuaWExEjAQBgNVBAoMCWxvY2FsaG9zdDESMBAGA1UEAwwJbG9jYWxob3N0\n" - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5OWIaKqYae4nPxvu5EP3\n" - "VilcjApYcMT4+2ypfQoB6PEep5lwguA929rNsTKnhGsEiQAZ0eZPEZN7VhUwf/hz\n" - "26jIyTT43ELkt6k97wwSZSXuT65RpSiemwEs6g2mMwzpgP6nv+yam4HjE9AKiHGN\n" - "YeTV72Nw1EN70t6IjIf4jsJRXqDJkUx5sSSD6j0WBTOhzozIDgZHTDwiLhatE66m\n" - "SNoD8oWC0PscbUgOJkFpbaCAS8RJmpsdgkTFae2rzL9cOFLGw6OgV/BV1J1s0ks8\n" - "+veoMMtIO6fese+OZ+DyQbuGaoaltZUXzY6QjD5l34m2mGplelT7BrpcqJTBHwmh\n" - "CwIDAQABo1MwUTAdBgNVHQ4EFgQUXQM5TVfJ9gpUXg8fZ8yfuUVcBP8wHwYDVR0j\n" - "BBgwFoAUXQM5TVfJ9gpUXg8fZ8yfuUVcBP8wDwYDVR0TAQH/BAUwAwEB/zANBgkq\n" - "hkiG9w0BAQsFAAOCAQEAqYX/ZGv0Qh/xdXppjnqojm8mH0giDW4tvwMqHcW3YRa3\n" - "9J2yYot+rHjU5g4n6HEmWDBE0eqLz9n3Y3fkFzT8RWZwBaST965CgsfGofyuA2hC\n" - "Ddn4Am3B5tTPmi8WWRZg8amhpGVD/mwkoVFIK0M337b1aZUJYPE+Kc9WetSL2KqB\n" - "EhqSQpkAWhVadzP85dq2T9EDjAvhlFTFlDEBx1GDUcc8M0KQ9NEvLT7LgoUcbMiT\n" - "PerlSZQTB0crchXTRSERgiwu80r7D6STn/RcPL9Fg5PkA94/d87jGbmV4sxSRsvM\n" - "z+DnJGjHrV1J/jHPrnVvVLpigBlGno3C5O/sRw3gcQ==\n" - "-----END CERTIFICATE-----\n"; - -const char *dummy_key = - "-----BEGIN PRIVATE KEY-----\n" - "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDk5Yhoqphp7ic/\n" - "G+7kQ/dWKVyMClhwxPj7bKl9CgHo8R6nmXCC4D3b2s2xMqeEawSJABnR5k8Rk3tW\n" - "FTB/+HPbqMjJNPjcQuS3qT3vDBJlJe5PrlGlKJ6bASzqDaYzDOmA/qe/7JqbgeMT\n" - "0AqIcY1h5NXvY3DUQ3vS3oiMh/iOwlFeoMmRTHmxJIPqPRYFM6HOjMgOBkdMPCIu\n" - "Fq0TrqZI2gPyhYLQ+xxtSA4mQWltoIBLxEmamx2CRMVp7avMv1w4UsbDo6BX8FXU\n" - "nWzSSzz696gwy0g7p96x745n4PJBu4ZqhqW1lRfNjpCMPmXfibaYamV6VPsGulyo\n" - "lMEfCaELAgMBAAECggEBAJa1AiFX4U4tva1xqNKmZV1XklWqIhzts7lnDBkF08gZ\n" - "qcNT5Z5mIpR09eVropwvEidZ56Yp63l5D0XYYbyAS1gfQ0QnGot7h7fdOKgB3MK4\n" - "PLY94gfKPNN17KqWHg2SvNNv1+cn04v78xUCb0zy5tHDp5Acexdm70ohtupARElJ\n" - "LSHdS7ebsqZUFXbbM3BpPEsQLi3PrzNs1DrKkZ3rR6eMGrsDqExXx8/foi9aZKsd\n" - "BGM2/kcTJ5aY6NhSv5iqO1oK46sbMrjVW/bYNsOyl0eFjwTRahn+Zhp/JMewZYeu\n" - "715g6kzbZNwEzBLgrhNPF6E2ycEr/C6z5bE78g5QCkECgYEA8s07UUY25bjYiWWy\n" - "W38pT7d/OXBSyKnq16N6MjVahl29r7nezFiDeLhLC0QiwXu/+qyxVZkB95MMGZXS\n" - "AsaKFNis3AJ6eR4SYyhpSScYKNvlKIiW37TtR4FDcy7y5LL6tFpiDDIGH3LuyWNo\n" - "d76142MBpv5aStnLGYU3pcZj43sCgYEA8VbNM4nqgSCQcbnHYjvsgphEMNSaoVie\n" - "xob2uigXdV6Te0ayoUFBnVNKVsRhk+sswuTV4k1pK/On+USVl2tQ16tcaVMjTfSD\n" - "HLYTJLmt6s4DcywWj5dfkbDoe5PulGXNZE960qXmOC62Lf0VMRwJ5x4FBRvGTjKC\n" - "zvekI2/kO7ECgYEAhBGeclb/BXXGUvY+TgadMf9d9KBkZ0IFu8Xwcd8TnoLe6vbv\n" - "ebery75zE228egIWKwREcYsIxuH1cvVLhrb35N73J7UxaTAyUD1rB598RL1XqPSj\n" - "HIwNhReK2NxwwnWYaQHA02FiczjRKjooWPojdcwk2fEArDZLg1YzLrj7HIECgYEA\n" - "htdx1Y8ESFtyeShMv5UtoxYCW6oeL3H9XH0CE6bc3IYYLvOkULbOO2HTEkGtJ2Fp\n" - "5AbJfiS0U4tS2dI5Jp4eUDH9cxexjRfFvd/5ODbKdnver5X9kQMJsbQ/YPSZg66R\n" - "oK9Lt7Bbvh5TScSy93psCgba1SzckspkDdGNkwMsaTECgYEAnFWaxormLUpXQRLs\n" - "tKzMMHgVnHlsHiqXH432zmT2fpGZHYoWbsGuQjjrHGnSiu3QbDhnzM6y/T2GRs6z\n" - "zHteIo/tzIyxg4MvJGJ9qANA7HoiKBdQ7G/I/NLJIyWAjj+e7/hgzKFcf+dpjpDq\n" - "HcKc9a4WXhC7yu79e5BnKWltHXY=\n" - "-----END PRIVATE KEY-----\n"; - -std::string error_string() { - // Get the last code. - int code = 0; - while (true) { - int icode = ERR_get_error(); - if (icode == 0) break; - code = icode; - } - - // Fetch and clear errno. - int terrno = errno; - errno = 0; - - if (code != 0) { - const char *rc = ERR_reason_error_string(code); - if (rc != nullptr) { - return rc; - } else { - return strerror_str(ERR_GET_REASON(code)); - } - } else if (terrno != 0) { - return strerror_str(terrno); - } else { - return ""; - } -} - -void clear_all_errors() { - ERR_clear_error(); - errno = 0; -} - -SSL_CTX *new_context(int verify) { - SSL_CTX *ctx = SSL_CTX_new(TLS_method()); - SSL_CTX_set_mode(ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); - SSL_CTX_set_verify(ctx, verify, nullptr); - return ctx; -} - -static int ctx_use_certificate_str(SSL_CTX *ctx, const char *str) { - UniqueBIO bio(BIO_new(BIO_s_mem())); - BIO_puts(bio.get(), str); - UniqueX509 certificate(PEM_read_bio_X509(bio.get(), NULL, NULL, NULL)); - return SSL_CTX_use_certificate(ctx, certificate.get()); -} - -static int ctx_use_privatekey_str(SSL_CTX *ctx, const char *str) { - UniqueBIO bio(BIO_new(BIO_s_mem())); - BIO_puts(bio.get(), str); - UniquePKEY pkey(PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL)); - return SSL_CTX_use_PrivateKey(ctx, pkey.get()); -} - -void ctx_load_dummy_cert(SSL_CTX *ctx) { - ERR_clear_error(); - if (ctx_use_certificate_str(ctx, dummy_cert) <= 0) { - ERR_print_errors_fp(stderr); - exit(1); - } - if (ctx_use_privatekey_str(ctx, dummy_key) <= 0) { - ERR_print_errors_fp(stderr); - exit(1); - } -} - -static int count_certificates(const char *fn) { - static char null_passwd; - ErrClearErrorOnExit ece; - UniqueBIO bio(BIO_new(BIO_s_file())); - assert(bio != nullptr); - if (BIO_read_filename(bio.get(), fn) <= 0) { - std::cerr << "Cannot open file: " << fn << std::endl; - exit(1); - } - int total = 0; - while (true) { - UniqueX509 x(PEM_read_bio_X509_AUX(bio.get(), nullptr, nullptr, &null_passwd)); - if (x == nullptr) break; - total += 1; - } - return total; -} - -static bool contains_privatekey(const char *fn) { - static char null_passwd; - ErrClearErrorOnExit ece; - UniqueBIO bio(BIO_new(BIO_s_file())); - assert(bio != nullptr); - if (BIO_read_filename(bio.get(), fn) <= 0) { - std::cerr << "Cannot open file: " << fn << std::endl; - exit(1); - } - UniquePKEY k(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, &null_passwd)); - return k != nullptr; -} - -void ctx_load_cert_from_directory(SSL_CTX *ctx, const std::string &dir) { - std::vector key_paths; - std::vector cert_paths; - - for (const auto & entry : std::filesystem::directory_iterator(dir)) { - std::string fn = entry.path(); - if (count_certificates(fn.c_str()) >= 1) { - cert_paths.push_back(fn); - } - if (contains_privatekey(fn.c_str())) { - key_paths.push_back(fn); - } - } - - if (cert_paths.size() > 1) { - std::cerr << "Directory contains multiple certs: " << dir << std::endl; - exit(1); - } - if (key_paths.size() > 1) { - std::cerr << "Directory contains multiple keys: " << dir << std::endl; - exit(1); - } - if (cert_paths.empty()) { - std::cerr << "Directory doesn't contain a cert: " << dir << std::endl; - exit(1); - } - if (key_paths.empty()) { - std::cerr << "Directory doesn't contain a key: " << dir << std::endl; - exit(1); - } - - int status; - status = SSL_CTX_use_PrivateKey_file(ctx, key_paths[0].c_str(), SSL_FILETYPE_PEM); - assert(status == 1); - status = SSL_CTX_use_certificate_chain_file(ctx, cert_paths[0].c_str()); - assert(status == 1); -} - -} // namespace drvssl - diff --git a/luprex/core/cpp/driver-ssl.hpp b/luprex/core/cpp/driver-ssl.hpp deleted file mode 100644 index 27db5569..00000000 --- a/luprex/core/cpp/driver-ssl.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef DRIVER_SSL_HPP -#define DRIVER_SSL_HPP - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace drvssl { - -struct SSL_Deleter { - void operator()(SSL *ssl) { SSL_free(ssl); } -}; - -struct CTX_Deleter { - void operator()(SSL_CTX *ctx) { SSL_CTX_free(ctx); } -}; - -struct BIO_Deleter { - void operator()(BIO *bio) { BIO_free(bio); } -}; - -struct X509_Deleter { - void operator()(X509 *x) { X509_free(x); } -}; - -struct PKEY_Deleter { - void operator()(EVP_PKEY *p) { EVP_PKEY_free(p); } -}; - -using UniqueSSL = std::unique_ptr; -using UniqueCTX = std::unique_ptr; -using UniqueBIO = std::unique_ptr; -using UniqueX509 = std::unique_ptr; -using UniquePKEY = std::unique_ptr; - -struct ErrClearErrorOnExit { - ~ErrClearErrorOnExit() { - ERR_clear_error(); - } -}; - -// Return the OpenSSL error as a string. -std::string error_string(); -void clear_all_errors(); -SSL_CTX *new_context(int verify); -void ctx_load_dummy_cert(SSL_CTX *ctx); -void ctx_load_cert_from_directory(SSL_CTX *ctx, const std::string &dir); - -} // namespace drvssl - -#endif // DRIVER_SSL_HPP - diff --git a/luprex/core/cpp/driver-util.cpp b/luprex/core/cpp/driver-util.cpp deleted file mode 100644 index 1997544b..00000000 --- a/luprex/core/cpp/driver-util.cpp +++ /dev/null @@ -1,528 +0,0 @@ - -#include "wrap-string.hpp" -#include "wrap-vector.hpp" -#include "util.hpp" -#include "spookyv2.hpp" -#include "driver-util.hpp" -#include "luastack.hpp" - -#include -#include -#include -#include - -#define RLOG_BUFSIZE (1024 * 1024) -#define MAX_ARGC 1024 - -namespace drv { - -std::vector split_view(std::string_view v, char sep) { - std::vector result; - while (true) { - size_t pos = v.find(sep); - if (pos == std::string_view::npos) break; - result.push_back(v.substr(0, pos)); - v = v.substr(pos + 1); - } - result.push_back(v); - return result; -} - -void split_target(std::string_view target, std::string &cert, std::string &host, std::string &port) { - std::vector split = split_view(target, ':'); - if (split.size() != 3) { - cert.clear(); host.clear(); port.clear(); - return; - } - if (split[0].empty() || split[1].empty() || split[2].empty()) { - cert.clear(); host.clear(); port.clear(); - return; - } - cert = std::string(split[0]); - host = std::string(split[1]); - port = std::string(split[2]); -} - -std::vector parse_control_lst(std::string_view ctrl) { - std::vector result; - while (!ctrl.empty()) { - std::string_view line = sv::read_to_line(ctrl); - std::string_view trimmed = sv::trim(line); - if ((trimmed.size() > 0) && (trimmed[0] != '#')) { - result.emplace_back(trimmed); - } - } - return result; -} - - -enum DrvAction { - CREATE_ENGINE, - CLEAN_EXIT, - DRV_CLEAR_NEW_OUTGOING, - DRV_SENT_OUTGOING, - DRV_RECV_INCOMING, - DRV_NOTIFY_CLOSE, - DRV_NOTIFY_ACCEPT, - DRV_CLEAR_LUA_SOURCE, - DRV_ADD_LUA_SOURCE, - DRV_INVOKE_EVENT_INIT, - DRV_INVOKE_EVENT_UPDATE -}; - -inline static const char *action_string(DrvAction act) { - switch(act) { - case CREATE_ENGINE: return "CREATE_ENGINE"; - case CLEAN_EXIT: return "CLEAN_EXIT"; - case DRV_CLEAR_NEW_OUTGOING: return "DRV_CLEAR_NEW_OUTGOING"; - case DRV_SENT_OUTGOING: return "DRV_SENT_OUTGOING"; - case DRV_RECV_INCOMING: return "DRV_RECV_INCOMING"; - case DRV_NOTIFY_CLOSE: return "DRV_NOTIFY_CLOSE"; - case DRV_NOTIFY_ACCEPT: return "DRV_NOTIFY_ACCEPT"; - case DRV_CLEAR_LUA_SOURCE: return "DRV_CLEAR_LUA_SOURCE"; - case DRV_ADD_LUA_SOURCE: return "DRV_ADD_LUA_SOURCE"; - case DRV_INVOKE_EVENT_INIT: return "DRV_INVOKE_EVENT_INIT"; - case DRV_INVOKE_EVENT_UPDATE: return "DRV_INVOKE_EVENT_UPDATE"; - default: return "unknown"; - } -} - -static void wlog_uint8(std::ofstream &s, uint8_t v) { - s.put((char)v); -} - -static void wlog_uint16(std::ofstream &s, uint16_t v) { - s.write((const char *)&v, 2); -} - -static void wlog_uint32(std::ofstream &s, uint32_t v) { - s.write((const char *)&v, 4); -} - -static void wlog_uint64(std::ofstream &s, uint64_t v) { - s.write((const char *)&v, 8); -} - -static void wlog_double(std::ofstream &s, double v) { - s.write((const char *)&v, 8); -} - -static void wlog_string(std::ofstream &s, std::string_view v) { - assert(v.size() < RLOG_BUFSIZE); - if (v.size() >= 255) { - wlog_uint8(s, 0xFF); - wlog_uint32(s, v.size()); - } else { - wlog_uint8(s, v.size()); - } - s.write(v.data(), v.size()); -} - -static void wlog_cmd_hash(std::ofstream &s, DrvAction act, uint32_t hash) { - // std::cerr << "Logging " << action_string(act) << " " << hash << std::endl; - wlog_uint8(s, act); - wlog_uint32(s, hash); -} - -// After doing an rlog operation, you should check the stream -// for "s.good()" to find out if there was any error. -static uint8_t rlog_uint8(std::ifstream &s) { - uint8_t result; - s.read((char *)&result, 1); - if (!s.good()) return 0; - return result; -} - -static uint16_t rlog_uint16(std::ifstream &s) { - uint16_t result; - s.read((char *)&result, 2); - if (!s.good()) return 0; - return result; -} - -static uint32_t rlog_uint32(std::ifstream &s) { - uint32_t result; - s.read((char *)&result, 4); - if (!s.good()) return 0; - return result; -} - -static uint64_t rlog_uint64(std::ifstream &s) { - uint64_t result; - s.read((char *)&result, 8); - if (!s.good()) return 0; - return result; -} - -static double rlog_double(std::ifstream &s) { - double result; - s.read((char *)&result, 8); - if (!s.good()) return 0.0; - return result; -} - -std::string_view rlog_string(std::ifstream &s, char *rlog_buf) { - uint32_t len = rlog_uint8(s); - if (len == 255) { - len = rlog_uint32(s); - } - assert(len <= RLOG_BUFSIZE); - if (len > 0) s.read(rlog_buf, len); - if (!s.good()) return std::string_view(); - return std::string_view(rlog_buf, len); -} - -ReplayPlayer::ReplayPlayer() { - status_ = ST_REPLAYING; - enable_stdout_ = false; - buf_.reset(new char[RLOG_BUFSIZE]); -} - -void ReplayRecorder::flush() { - f_.flush(); - if (!f_.good()) { - std::cerr << "Logfile write failed, replay logging abandoned." << std::endl; - f_.close(); - f_.clear(); - logging_ = false; - } -} - -bool ReplayRecorder::open_logfile(const char *fn) { - f_.open(fn, std::ios_base::out | std::ios_base::binary | std::ios_base::trunc); - if (f_.good()) { - logging_ = true; - return true; - } else { - f_.close(); - f_.clear(); - return false; - } -} - - -ReplayPlayer::Status ReplayPlayer::step() { - if (status_ != ST_REPLAYING) return status_; - uint8_t code = rlog_uint8(f_); - if (f_.eof()) { - set_status(ST_LOGFILE_ENDS_ABRUPTLY); - return status_; - } - int hash = rlog_uint32(f_); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return status_; - } - // std::cerr << "Executing: " << action_string(DrvAction(code)) << " " << eng::memhash() << std::endl; - if (hash != eng::memhash()) { - set_status(ST_NONDERMINISTIC); - return status_; - } - switch (code) { - case CREATE_ENGINE: create_engine(); break; - case CLEAN_EXIT: clean_exit(); break; - case DRV_CLEAR_NEW_OUTGOING: drv_clear_new_outgoing(); break; - case DRV_SENT_OUTGOING: drv_sent_outgoing(); break; - case DRV_RECV_INCOMING: drv_recv_incoming(); break; - case DRV_NOTIFY_CLOSE: drv_notify_close(); break; - case DRV_NOTIFY_ACCEPT: drv_notify_accept(); break; - case DRV_CLEAR_LUA_SOURCE: drv_clear_lua_source(); break; - case DRV_ADD_LUA_SOURCE: drv_add_lua_source(); break; - case DRV_INVOKE_EVENT_INIT: drv_invoke_event_init(); break; - case DRV_INVOKE_EVENT_UPDATE: drv_invoke_event_update(); break; - default: - assert(false && "Replay Log contains invalid command."); - } - return status_; -} - -void ReplayPlayer::set_status(Status e) { - status_ = e; - f_.close(); - f_.clear(); -} - -void ReplayPlayer::print_status(std::ostream &s) { - switch (status_) { - case ST_REPLAYING: - s << "No errors detected: " << logfn_ << std::endl; - return; - case ST_CLEAN_EXIT: - s << "Engine exited cleanly without errors: " << logfn_ << std::endl; - return; - case ST_ERR_OPENING_LOGFILE: - s << "Could not open logfile: " << logfn_ << std::endl; - return; - case ST_LOGFILE_ENDS_ABRUPTLY: - s << "Logfile reached end-of-file: " << logfn_ << std::endl; - return; - case ST_LOGFILE_CORRUPT: - s << "Logfile corrupt: " << logfn_ << std::endl; - return; - case ST_NONDERMINISTIC: - s << "Nondeterminism detected: " << logfn_ << std::endl; - return; - case ST_COULDNT_CREATE_ENGINE: - s << "Could not create engine: " << logfn_ << " " << engine_ << std::endl; - return; - } -} - -bool ReplayPlayer::open_logfile(const char *fn) { - logfn_ = fn; - f_.clear(); - f_.open(fn, std::ios_base::in | std::ios_base::binary); - if (!f_.good()) { - set_status(ST_ERR_OPENING_LOGFILE); - return false; - } - return true; -} - -bool ReplayRecorder::create_engine(const char *kind) { - if (logging_) { - wlog_cmd_hash(f_, CREATE_ENGINE, eng::memhash()); - wlog_string(f_, kind); - flush(); - } - e_ = DrivenEngine::make(kind); - DrivenEngine::set(e_.get()); - return e_ != nullptr; -} - -void ReplayPlayer::create_engine() { - std::string_view kind = rlog_string(f_, buf_.get()); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - engine_ = std::string(kind); - e_ = DrivenEngine::make(kind); - DrivenEngine::set(e_.get()); - if (e_ == nullptr) { - set_status(ST_COULDNT_CREATE_ENGINE); - return; - } -} - -void ReplayRecorder::clean_exit() { - if (logging_) { - wlog_cmd_hash(f_, CLEAN_EXIT, eng::memhash()); - flush(); - } -} - -void ReplayPlayer::clean_exit() { - set_status(ST_CLEAN_EXIT); -} - -void ReplayRecorder::drv_clear_new_outgoing() { - if (logging_) { - wlog_cmd_hash(f_, DRV_CLEAR_NEW_OUTGOING, eng::memhash()); - flush(); - } - e_->drv_clear_new_outgoing(); -} - -void ReplayPlayer::drv_clear_new_outgoing() { - e_->drv_clear_new_outgoing(); -} - -void ReplayRecorder::drv_sent_outgoing(int chid, int nbytes) { - assert ((nbytes >= 0) && (nbytes <= 65535)); - if (logging_) { - std::string_view data = e_->drv_peek_outgoing(chid); - assert(nbytes <= int(data.size())); - wlog_cmd_hash(f_, DRV_SENT_OUTGOING, eng::memhash()); - wlog_uint16(f_, chid); - wlog_uint16(f_, nbytes); - wlog_uint64(f_, SpookyHash::QkHash64(data.data(), nbytes)); - flush(); - } - e_->drv_sent_outgoing(chid, nbytes); -} - -void ReplayPlayer::drv_sent_outgoing() { - int chid = rlog_uint16(f_); - int nbytes = rlog_uint16(f_); - uint64_t hash = rlog_uint64(f_); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - std::string_view data = e_->drv_peek_outgoing(chid); - if (nbytes > int(data.size())) { - set_status(ST_NONDERMINISTIC); - return; - } - if (hash != SpookyHash::QkHash64(data.data(), nbytes)) { - set_status(ST_NONDERMINISTIC); - return; - } - if ((chid == 0) && (enable_stdout_)) { - std::string_view sub = data.substr(0, nbytes); - std::cout << sub; - } - e_->drv_sent_outgoing(chid, nbytes); -} - -void ReplayRecorder::drv_recv_incoming(int chid, std::string_view data) { - if (logging_) { - wlog_cmd_hash(f_, DRV_RECV_INCOMING, eng::memhash()); - wlog_uint16(f_, chid); - wlog_string(f_, data); - flush(); - } - e_->drv_recv_incoming(chid, data); -} - -void ReplayPlayer::drv_recv_incoming() { - int chid = rlog_uint16(f_); - std::string_view data = rlog_string(f_, buf_.get()); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - e_->drv_recv_incoming(chid, data); -} - -void ReplayRecorder::drv_notify_close(int chid, std::string_view err) { - if (logging_) { - wlog_cmd_hash(f_, DRV_NOTIFY_CLOSE, eng::memhash()); - wlog_uint16(f_, chid); - wlog_string(f_, err); - flush(); - } - e_->drv_notify_close(chid, err); -} - -void ReplayPlayer::drv_notify_close() { - int chid = rlog_uint16(f_); - std::string_view err = rlog_string(f_, buf_.get()); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - e_->drv_notify_close(chid, err); -} - -int ReplayRecorder::drv_notify_accept(int port) { - if (logging_) { - wlog_cmd_hash(f_, DRV_NOTIFY_ACCEPT, eng::memhash()); - wlog_uint16(f_, port); - flush(); - } - return e_->drv_notify_accept(port); -} - -void ReplayPlayer::drv_notify_accept() { - int port = rlog_uint16(f_); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - e_->drv_notify_accept(port); -} - -void ReplayRecorder::drv_clear_lua_source() { - if (logging_) { - wlog_cmd_hash(f_, DRV_CLEAR_LUA_SOURCE, eng::memhash()); - flush(); - } - e_->drv_clear_lua_source(); -} - -void ReplayPlayer::drv_clear_lua_source() { - e_->drv_clear_lua_source(); -} - -void ReplayRecorder::drv_add_lua_source(std::string_view fn, std::string_view data) { - if (logging_) { - wlog_cmd_hash(f_, DRV_ADD_LUA_SOURCE, eng::memhash()); - wlog_string(f_, fn); - wlog_string(f_, data); - flush(); - } - e_->drv_add_lua_source(fn, data); -} - -void ReplayPlayer::drv_add_lua_source() { - std::string fn(rlog_string(f_, buf_.get())); - std::string_view data = rlog_string(f_, buf_.get()); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - e_->drv_add_lua_source(fn, data); -} - -void ReplayRecorder::drv_invoke_event_init(int argc, char *argv[]) { - assert(argc <= MAX_ARGC); - if (logging_) { - wlog_cmd_hash(f_, DRV_INVOKE_EVENT_INIT, eng::memhash()); - wlog_uint16(f_, argc); - for (int i = 0; i < argc; i++) { - wlog_string(f_, argv[i]); - } - flush(); - } - e_->drv_invoke_event_init(argc, argv); -} - -void ReplayPlayer::drv_invoke_event_init() { - std::vector argv; - int argc = rlog_uint16(f_); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - if (argc > MAX_ARGC) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - for (int i = 0; i < argc; i++) { - std::string_view arg = rlog_string(f_, buf_.get()); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - argv.emplace_back(arg); - } - std::vector cargv; - for (int i = 0; i < argc; i++) { - cargv.emplace_back(const_cast(argv[i].c_str())); - } - e_->drv_invoke_event_init(argc, &(cargv[0])); -} - -void ReplayRecorder::drv_invoke_event_update(double clock) { - if (logging_) { - wlog_cmd_hash(f_, DRV_INVOKE_EVENT_UPDATE, eng::memhash()); - wlog_double(f_, clock); - flush(); - } - e_->drv_invoke_event_update(clock); -} - -void ReplayPlayer::drv_invoke_event_update() { - double clock = rlog_double(f_); - if (!f_.good()) { - set_status(ST_LOGFILE_CORRUPT); - return; - } - e_->drv_invoke_event_update(clock); -} - -} // namespace drv - -LuaDefine(unittests_driverutil, "", "some unit tests") { - // Test split_target - std::string cert, host, port; - drv::split_target("cert:stanford.edu:80", cert, host, port); - LuaAssertStrEq(L, cert, "cert"); - LuaAssertStrEq(L, host, "stanford.edu"); - LuaAssertStrEq(L, port, "80"); - - return 0; -} - diff --git a/luprex/core/cpp/driver-util.hpp b/luprex/core/cpp/driver-util.hpp deleted file mode 100644 index 88666aae..00000000 --- a/luprex/core/cpp/driver-util.hpp +++ /dev/null @@ -1,149 +0,0 @@ - -#ifndef DRIVER_UTIL_HPP -#define DRIVER_UTIL_HPP - -#include "wrap-string.hpp" -#include "wrap-vector.hpp" -#include -#include -#include -#include "drivenengine.hpp" - -namespace drv { - -void split_target(std::string_view target, std::string &cert, std::string &host, std::string &port); - - -std::vector parse_control_lst(std::string_view ctrl); - - -class ReplayRecorder { -private: - std::ofstream f_; - UniqueDrivenEngine e_; - bool logging_; - - void flush(); -public: - // Initialization consists of three steps: - // - // 1. The constructor, which creates an empty ReplayRecorder. - // 2. Open the logfile for writing, if desired, using open_logfile. - // 3. Make the engine, using create_engine. - // - // After that, you can use drv_xxx methods to send messages to the - // engine. These messages will get logged if the replay log is open. - // - ReplayRecorder() : logging_(false) {} - - // Open the logfile. - // - // If you're going to open a logfile, you must do so before - // creating the engine. Returns false if the logfile couldn't be - // opened. - // - bool open_logfile(const char *fn); - - // Create the DrivenEngine. - // - // Returns false if the DrivenEngine couldn't be created. - // - bool create_engine(const char *kind); - - // Report to the logger that the engine is about to exit cleanly, - // without any error. - // - void clean_exit(); - - // These don't need to be logged. - // - const eng::vector &drv_get_listen_ports() const { return e_->drv_get_listen_ports(); } - const eng::vector &drv_get_new_outgoing() const { return e_->drv_get_new_outgoing(); } - std::string_view drv_get_target(int chid) const { return e_->drv_get_target(chid); } - bool drv_outgoing_empty(int chid) const { return e_->drv_outgoing_empty(chid); } - bool drv_get_channel_released(int chid) const { return e_->drv_get_channel_released(chid); } - std::string_view drv_peek_outgoing(int chid) const { return e_->drv_peek_outgoing(chid); } - bool drv_get_rescan_lua_source() const { return e_->drv_get_rescan_lua_source(); } - bool drv_get_stop_driver() const { return e_->drv_get_stop_driver(); } - - // These operations do need to be logged. - // - void drv_clear_new_outgoing(); - void drv_sent_outgoing(int chid, int nbytes); - void drv_recv_incoming(int chid, std::string_view data); - void drv_notify_close(int chid, std::string_view err); - int drv_notify_accept(int port); - void drv_clear_lua_source(); - void drv_add_lua_source(std::string_view fn, std::string_view data); - void drv_invoke_event_init(int argc, char *argv[]); - void drv_invoke_event_update(double clock); -}; - -class ReplayPlayer { -public: - enum Status { - ST_REPLAYING, - ST_CLEAN_EXIT, - ST_ERR_OPENING_LOGFILE, - ST_LOGFILE_ENDS_ABRUPTLY, - ST_LOGFILE_CORRUPT, - ST_NONDERMINISTIC, - ST_COULDNT_CREATE_ENGINE, - }; -private: - std::ifstream f_; - UniqueDrivenEngine e_; - std::unique_ptr buf_; - Status status_; - std::string logfn_; - std::string engine_; - bool enable_stdout_; - - void set_status(Status e); - - void create_engine(); - void clean_exit(); - void drv_clear_new_outgoing(); - void drv_sent_outgoing(); - void drv_recv_incoming(); - void drv_notify_close(); - void drv_notify_accept(); - void drv_clear_lua_source(); - void drv_add_lua_source(); - void drv_invoke_event_init(); - void drv_invoke_event_update(); -public: - ReplayPlayer(); - - // Open the logfile for reading. - // - // Returns false if the logfile can't be opened. - // - bool open_logfile(const char *fn); - - // Enable stdout. - // - // Normally, stdout is suppressed during replay. - // If you enable stdout, then the engine will print - // all the same messages it did when running in the - // first place. - // - void enable_stdout() { enable_stdout_ = true; } - - // Execute a single step from the replay log. - // - // Returns a status code, which is usually ST_REPLAYING. - // If it's anything else, display the status and stop. - // - Status step(); - - // Print a status message. - // - // Print a message associated with the most recent status report. - // - void print_status(std::ostream &s); -}; - -} // namespace drv - -#endif // DRIVER_UTIL_HPP diff --git a/luprex/core/obj/.gitkeep b/luprex/core/obj/.gitkeep deleted file mode 100644 index e69de29b..00000000