From 5ee9b3a22b9ce5343a6cae4e1c8f99e3ec85aef3 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 26 Jan 2022 11:50:43 +0300 Subject: [PATCH 1/7] Drop Swiften dependency from backends --- CMakeLists.txt | 4 +- backends/frotz/CMakeLists.txt | 2 +- backends/frotz/main.cpp | 614 +++++++++--------- backends/libcommuni/CMakeLists.txt | 8 +- backends/libcommuni/ircnetworkplugin.cpp | 2 +- backends/libcommuni/ircnetworkplugin.h | 3 +- backends/libcommuni/main.cpp | 5 +- backends/libcommuni/session.h | 1 - backends/smstools3/CMakeLists.txt | 2 +- backends/smstools3/main.cpp | 53 +- backends/swiften/CMakeLists.txt | 6 +- backends/template/CMakeLists.txt | 12 +- backends/template/main.cpp | 9 +- backends/template/plugin.cpp | 74 +-- backends/template/plugin.h | 23 +- include/transport/BoostNetworkPlugin.h | 45 ++ include/transport/HTTPRequest.h | 87 +-- include/transport/HTTPRequestQueue.h | 40 -- include/transport/NetworkPlugin.h | 7 +- include/transport/ThreadPool.h | 6 +- libtransport/CMakeLists.txt | 4 - libtransport/HTTPRequestQueue.cpp | 64 -- libtransport/OAuth2.cpp | 17 +- libtransport/WebSocketClient.cpp | 20 +- plugin/cpp/BoostNetworkPlugin.cpp | 76 +++ plugin/cpp/CMakeLists.txt | 9 +- {libtransport => plugin/cpp}/HTTPRequest.cpp | 109 +--- plugin/cpp/MemoryUsage.cpp | 1 - {libtransport => plugin/cpp}/MySQLBackend.cpp | 0 {libtransport => plugin/cpp}/PQXXBackend.cpp | 0 .../cpp}/SQLite3Backend.cpp | 0 .../cpp}/StorageBackend.cpp | 25 +- {libtransport => plugin/cpp}/ThreadPool.cpp | 6 +- plugin/cpp/networkplugin.cpp | 14 +- spectrum/src/CMakeLists.txt | 10 +- spectrum/src/frontends/CMakeLists.txt | 2 + spectrum/src/frontends/xmpp/XMPPFrontend.cpp | 2 +- .../src/frontends/xmpp/gatewayresponder.cpp | 2 +- spectrum/src/main.cpp | 2 + tests/libtransport/CMakeLists.txt | 28 +- tests/libtransport/HTTPRequest.cpp | 49 +- tests/libtransport/main.cpp | 8 +- .../{ => slack}/AdminInterface.cpp | 0 .../{ => slack}/BasicSlackTest.cpp | 0 .../libtransport/{ => slack}/BasicSlackTest.h | 0 tests/libtransport/{ => slack}/SlackRTM.cpp | 0 46 files changed, 628 insertions(+), 823 deletions(-) create mode 100644 include/transport/BoostNetworkPlugin.h delete mode 100644 include/transport/HTTPRequestQueue.h delete mode 100644 libtransport/HTTPRequestQueue.cpp create mode 100644 plugin/cpp/BoostNetworkPlugin.cpp rename {libtransport => plugin/cpp}/HTTPRequest.cpp (50%) rename {libtransport => plugin/cpp}/MySQLBackend.cpp (100%) rename {libtransport => plugin/cpp}/PQXXBackend.cpp (100%) rename {libtransport => plugin/cpp}/SQLite3Backend.cpp (100%) rename {libtransport => plugin/cpp}/StorageBackend.cpp (74%) rename {libtransport => plugin/cpp}/ThreadPool.cpp (92%) rename tests/libtransport/{ => slack}/AdminInterface.cpp (100%) rename tests/libtransport/{ => slack}/BasicSlackTest.cpp (100%) rename tests/libtransport/{ => slack}/BasicSlackTest.h (100%) rename tests/libtransport/{ => slack}/SlackRTM.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index cf988dc55..391ebc46a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ option(ENABLE_PURPLE "Build Libpurple plugin" ON) option(ENABLE_SMSTOOLS3 "Build SMSTools3 plugin" ON) option(ENABLE_XMPP "Build XMPP plugin" ON) option(ENABLE_WEBUI "Build Web UI" ON) - +option(ENABLE_SLACK_FRONTEND "Build Slack frontend" OFF) option(ENABLE_DOCS "Build Docs" ON) # option(ENABLE_LOG "Build with logging using Log4cxx" ON) option(ENABLE_TESTS "Build Tests using CppUnit" OFF) @@ -91,6 +91,8 @@ if(WIN32) link_directories("$ENV{CMAKE_PREFIX_PATH}/lib") endif(WIN32) +find_package( Threads ) + set(Boost_FIND_QUIETLY ON) find_package(Boost COMPONENTS program_options date_time system filesystem regex thread locale REQUIRED) diff --git a/backends/frotz/CMakeLists.txt b/backends/frotz/CMakeLists.txt index ca408097b..0a66d5954 100644 --- a/backends/frotz/CMakeLists.txt +++ b/backends/frotz/CMakeLists.txt @@ -5,6 +5,6 @@ file(GLOB SRC *.c *.cpp) add_executable(spectrum2_frotz_backend ${SRC}) target_compile_features(spectrum2_frotz_backend PUBLIC cxx_std_11) -target_link_libraries(spectrum2_frotz_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_frotz_backend transport ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES}) install(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) diff --git a/backends/frotz/main.cpp b/backends/frotz/main.cpp index 05e50b21c..ec68af5a3 100644 --- a/backends/frotz/main.cpp +++ b/backends/frotz/main.cpp @@ -9,349 +9,349 @@ */ #include "transport/Config.h" -#include "transport/NetworkPlugin.h" -#include -#include -#include "unistd.h" +#include "transport/BoostNetworkPlugin.h" +#include + #include "signal.h" -#include "sys/wait.h" #include "sys/signal.h" -Swift::SimpleEventLoop *loop_; +#include "sys/wait.h" +#include "unistd.h" +#include +#include +#include +using namespace boost::asio::ip; using namespace boost::program_options; + using namespace Transport; class FrotzNetworkPlugin; -FrotzNetworkPlugin * np = NULL; +FrotzNetworkPlugin *np = NULL; -#define PARENT_READ p.readpipe[0] -#define CHILD_WRITE p.readpipe[1] -#define CHILD_READ p.writepipe[0] -#define PARENT_WRITE p.writepipe[1] +#define PARENT_READ p.readpipe[0] +#define CHILD_WRITE p.readpipe[1] +#define CHILD_READ p.writepipe[0] +#define PARENT_WRITE p.writepipe[1] typedef struct dfrotz_ { - pid_t pid; - std::string game; - int readpipe[2]; - int writepipe[2]; + pid_t pid; + std::string game; + int readpipe[2]; + int writepipe[2]; } dfrotz; using namespace boost::filesystem; -static const char *howtoplay = "To move around, just type the direction you want to go. Directions can be\n" -"abbreviated: NORTH to N, SOUTH to S, EAST to E, WEST to W, NORTHEAST to\n" -"NE, NORTHWEST to NW, SOUTHEAST to SE, SOUTHWEST to SW, UP to U, and DOWN\n" -"to D. IN and OUT will also work in certain places.\n" -"\n" -"There are many differnet kinds of sentences used in Interactive Fiction.\n" -"Here are some examples:\n" -"\n" -"> WALK TO THE NORTH\n" -"> WEST\n" -"> NE\n" -"> DOWN\n" -"> TAKE THE BIRDCAGE\n" -"> READ ABOUT DIMWIT FLATHEAD\n" -"> LOOK UP MEGABOZ IN THE ENCYCLOPEDIA\n" -"> LIE DOWN IN THE PINK SOFA\n" -"> EXAMINE THE SHINY COIN\n" -"> PUT THE RUSTY KEY IN THE CARDBOARD BOX\n" -"> SHOW MY BOW TIE TO THE BOUNCER\n" -"> HIT THE CRAWLING CRAB WITH THE GIANT NUTCRACKER\n" -"> ASK THE COWARDLY KING ABOUT THE CROWN JEWELS\n" -"\n" -"You can use multiple objects with certain verbs if you separate them by\n" -"the word \"AND\" or by a comma. Here are some examples:\n" -"\n" -"> TAKE THE BOOK AND THE FROG\n" -"> DROP THE JAR OF PEANUT BUTTER, THE SPOON, AND THE LEMMING FOOD\n" -"> PUT THE EGG AND THE PENCIL IN THE CABINET\n" -"\n" -"You can include several inputs on one line if you separate them by the\n" -"word \"THEN\" or by a period. Each input will be handled in order, as\n" -"though you had typed them individually at seperate prompts. For example,\n" -"you could type all of the following at once, before pressing the ENTER (or\n" -"RETURN) key:\n" -"\n" -"> TURN ON THE LIGHT. TAKE THE BOOK THEN READ ABOUT THE JESTER IN THE BOOK\n" -"\n" -"If the story doesn't understand one of the sentences on your input line,\n" -"or if an unusual event occurs, it will ignore the rest of your input line.\n" -"\n" -"The words \"IT\" and \"ALL\" can be very useful. For example:\n" -"\n" -"> EXAMINE THE APPLE. TAKE IT. EAT IT\n" -"> CLOSE THE HEAVY METAL DOOR. LOCK IT\n" -"> PICK UP THE GREEN BOOT. SMELL IT. PUT IT ON.\n" -"> TAKE ALL\n" -"> TAKE ALL THE TOOLS\n" -"> DROP ALL THE TOOLS EXCEPT THE WRENCH AND MINIATURE HAMMER\n" -"> TAKE ALL FROM THE CARTON\n" -"> GIVE ALL BUT THE RUBY SLIPPERS TO THE WICKED WITCH\n" -"\n" -"The word \"ALL\" refers to every visible object except those inside\n" -"something else. If there were an apple on the ground and an orange inside\n" -"a cabinet, \"TAKE ALL\" would take the apple but not the orange.\n" -"\n" -"There are three kinds of questions you can ask: \"WHERE IS (something)\",\n" -"\"WHAT IS (something)\", and \"WHO IS (someone)\". For example:\n" -"\n" -"> WHO IS LORD DIMWIT?\n" -"> WHAT IS A GRUE?\n" -"> WHERE IS EVERYBODY?\n" -"\n" -"When you meet intelligent creatures, you can talk to them by typing their\n" -"name, then a comma, then whatever you want to say to them. Here are some\n" -"examples:\n" -"\n" -"> JESTER, HELLO\n" -"> GUSTAR WOOMAX, TELL ME ABOUT THE COCONUT\n" -"> UNCLE OTTO, GIVE ME YOUR WALLET\n" -"> HORSE, WHERE IS YOUR SADDLE?\n" -"> BOY, RUN HOME THEN CALL THE POLICE\n" -"> MIGHTY WIZARD, TAKE THIS POISONED APPLE. EAT IT\n" -"\n" -"Notice that in the last two examples, you are giving the characters more\n" -"than one command on the same input line. Keep in mind, however, that many\n" -"creatures don't care for idle chatter; your actions will speak louder than\n" -"your words. \n"; - +static const char *howtoplay = + "To move around, just type the direction you want to go. Directions can " + "be\n" + "abbreviated: NORTH to N, SOUTH to S, EAST to E, WEST to W, NORTHEAST to\n" + "NE, NORTHWEST to NW, SOUTHEAST to SE, SOUTHWEST to SW, UP to U, and DOWN\n" + "to D. IN and OUT will also work in certain places.\n" + "\n" + "There are many differnet kinds of sentences used in Interactive Fiction.\n" + "Here are some examples:\n" + "\n" + "> WALK TO THE NORTH\n" + "> WEST\n" + "> NE\n" + "> DOWN\n" + "> TAKE THE BIRDCAGE\n" + "> READ ABOUT DIMWIT FLATHEAD\n" + "> LOOK UP MEGABOZ IN THE ENCYCLOPEDIA\n" + "> LIE DOWN IN THE PINK SOFA\n" + "> EXAMINE THE SHINY COIN\n" + "> PUT THE RUSTY KEY IN THE CARDBOARD BOX\n" + "> SHOW MY BOW TIE TO THE BOUNCER\n" + "> HIT THE CRAWLING CRAB WITH THE GIANT NUTCRACKER\n" + "> ASK THE COWARDLY KING ABOUT THE CROWN JEWELS\n" + "\n" + "You can use multiple objects with certain verbs if you separate them by\n" + "the word \"AND\" or by a comma. Here are some examples:\n" + "\n" + "> TAKE THE BOOK AND THE FROG\n" + "> DROP THE JAR OF PEANUT BUTTER, THE SPOON, AND THE LEMMING FOOD\n" + "> PUT THE EGG AND THE PENCIL IN THE CABINET\n" + "\n" + "You can include several inputs on one line if you separate them by the\n" + "word \"THEN\" or by a period. Each input will be handled in order, as\n" + "though you had typed them individually at seperate prompts. For " + "example,\n" + "you could type all of the following at once, before pressing the ENTER " + "(or\n" + "RETURN) key:\n" + "\n" + "> TURN ON THE LIGHT. TAKE THE BOOK THEN READ ABOUT THE JESTER IN THE " + "BOOK\n" + "\n" + "If the story doesn't understand one of the sentences on your input line,\n" + "or if an unusual event occurs, it will ignore the rest of your input " + "line.\n" + "\n" + "The words \"IT\" and \"ALL\" can be very useful. For example:\n" + "\n" + "> EXAMINE THE APPLE. TAKE IT. EAT IT\n" + "> CLOSE THE HEAVY METAL DOOR. LOCK IT\n" + "> PICK UP THE GREEN BOOT. SMELL IT. PUT IT ON.\n" + "> TAKE ALL\n" + "> TAKE ALL THE TOOLS\n" + "> DROP ALL THE TOOLS EXCEPT THE WRENCH AND MINIATURE HAMMER\n" + "> TAKE ALL FROM THE CARTON\n" + "> GIVE ALL BUT THE RUBY SLIPPERS TO THE WICKED WITCH\n" + "\n" + "The word \"ALL\" refers to every visible object except those inside\n" + "something else. If there were an apple on the ground and an orange " + "inside\n" + "a cabinet, \"TAKE ALL\" would take the apple but not the orange.\n" + "\n" + "There are three kinds of questions you can ask: \"WHERE IS " + "(something)\",\n" + "\"WHAT IS (something)\", and \"WHO IS (someone)\". For example:\n" + "\n" + "> WHO IS LORD DIMWIT?\n" + "> WHAT IS A GRUE?\n" + "> WHERE IS EVERYBODY?\n" + "\n" + "When you meet intelligent creatures, you can talk to them by typing " + "their\n" + "name, then a comma, then whatever you want to say to them. Here are " + "some\n" + "examples:\n" + "\n" + "> JESTER, HELLO\n" + "> GUSTAR WOOMAX, TELL ME ABOUT THE COCONUT\n" + "> UNCLE OTTO, GIVE ME YOUR WALLET\n" + "> HORSE, WHERE IS YOUR SADDLE?\n" + "> BOY, RUN HOME THEN CALL THE POLICE\n" + "> MIGHTY WIZARD, TAKE THIS POISONED APPLE. EAT IT\n" + "\n" + "Notice that in the last two examples, you are giving the characters more\n" + "than one command on the same input line. Keep in mind, however, that " + "many\n" + "creatures don't care for idle chatter; your actions will speak louder " + "than\n" + "your words. \n"; static void start_dfrotz(dfrotz &p, const std::string &game) { -// p.writepipe[0] = -1; + // p.writepipe[0] = -1; - if (pipe(p.readpipe) < 0 || pipe(p.writepipe) < 0) { - } + if (pipe(p.readpipe) < 0 || pipe(p.writepipe) < 0) { + } - std::cout << "dfrotz -p " << game << "\n"; + std::cout << "dfrotz -p " << game << "\n"; - if ((p.pid = fork()) < 0) { - /* FATAL: cannot fork child */ - } - else if (p.pid == 0) { - close(PARENT_WRITE); - close(PARENT_READ); + if ((p.pid = fork()) < 0) { + /* FATAL: cannot fork child */ + } else if (p.pid == 0) { + close(PARENT_WRITE); + close(PARENT_READ); - dup2(CHILD_READ, 0); close(CHILD_READ); - dup2(CHILD_WRITE, 1); close(CHILD_WRITE); + dup2(CHILD_READ, 0); + close(CHILD_READ); + dup2(CHILD_WRITE, 1); + close(CHILD_WRITE); - execlp("dfrotz", "-p", game.c_str(), NULL); + execlp("dfrotz", "-p", game.c_str(), NULL); - } - else { - close(CHILD_READ); - close(CHILD_WRITE); - } + } else { + close(CHILD_READ); + close(CHILD_WRITE); + } } -class FrotzNetworkPlugin : public NetworkPlugin { - public: - Swift::BoostNetworkFactories *m_factories; - Swift::BoostIOServiceThread m_boostIOServiceThread; - std::shared_ptr m_conn; - - FrotzNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { - this->config = config; - m_factories = new Swift::BoostNetworkFactories(loop); - m_conn = m_factories->getConnectionFactory()->createConnection(); - m_conn->onDataRead.connect(boost::bind(&FrotzNetworkPlugin::_handleDataRead, this, _1)); - m_conn->connect(Swift::HostAddressPort(*(Swift::HostAddress::fromString(host)), port)); -// m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1)); -// m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this)); - } - - void sendData(const std::string &string) { - m_conn->write(Swift::createSafeByteArray(string)); - } - - void _handleDataRead(std::shared_ptr data) { - std::string d(data->begin(), data->end()); - handleDataRead(d); - } - - void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password, const std::map &settings) { - np->handleConnected(user); - std::vector groups; - groups.push_back("ZCode"); - np->handleBuddyChanged(user, "zcode", "ZCode", groups, pbnetwork::STATUS_ONLINE); -// sleep(1); -// np->handleMessage(np->m_user, "zork", first_msg); - } - - void handleLogoutRequest(const std::string &user, const std::string &legacyName) { - if (games.find(user) != games.end()) { - kill(games[user].pid, SIGTERM); - games.erase(user); - } -// exit(0); - } - - void readMessage(const std::string &user) { - static char buf[15000]; - buf[0] = 0; - int repeated = 0; - while (strlen(buf) == 0) { - ssize_t len = read(games[user].readpipe[0], buf, 15000); - if (len > 0) { - buf[len] = 0; - } - usleep(1000); - repeated++; - if (repeated > 30) - return; - } - np->handleMessage(user, "zcode", buf); - - std::string msg = "save\n"; - write(games[user].writepipe[1], msg.c_str(), msg.size()); - - msg = user + "_" + games[user].game + ".save\n"; - write(games[user].writepipe[1], msg.c_str(), msg.size()); - ignoreMessage(user); - } - - void ignoreMessage(const std::string &user) { - usleep(1000000); - static char buf[15000]; - buf[0] = 0; - int repeated = 0; - while (strlen(buf) == 0) { - ssize_t len = read(games[user].readpipe[0], buf, 15000); - if (len > 0) { - buf[len] = 0; - } - usleep(1000); - repeated++; - if (repeated > 30) - return; - } - - std::cout << "ignoring: " << buf << "\n"; - } - - std::vector getGames() { - std::vector games; - path p("."); - directory_iterator end_itr; - for (directory_iterator itr(p); itr != end_itr; ++itr) { - if (extension(itr->path()) == ".z5") { +class FrotzNetworkPlugin : public BoostNetworkPlugin { +public: + FrotzNetworkPlugin(Config *config, const std::string &host, int port) + : BoostNetworkPlugin(config, host, port) { + } + + void handleLoginRequest(const std::string &user, + const std::string &legacyName, + const std::string &password, + const std::map &settings) { + np->handleConnected(user); + std::vector groups; + groups.push_back("ZCode"); + np->handleBuddyChanged(user, "zcode", "ZCode", groups, + pbnetwork::STATUS_ONLINE); + // sleep(1); + // np->handleMessage(np->m_user, "zork", first_msg); + } + + void handleLogoutRequest(const std::string &user, + const std::string &legacyName) { + if (games.find(user) != games.end()) { + kill(games[user].pid, SIGTERM); + games.erase(user); + } + // exit(0); + } + + void readMessage(const std::string &user) { + static char buf[15000]; + buf[0] = 0; + int repeated = 0; + while (strlen(buf) == 0) { + ssize_t len = read(games[user].readpipe[0], buf, 15000); + if (len > 0) { + buf[len] = 0; + } + usleep(1000); + repeated++; + if (repeated > 30) + return; + } + np->handleMessage(user, "zcode", buf); + + std::string msg = "save\n"; + write(games[user].writepipe[1], msg.c_str(), msg.size()); + + msg = user + "_" + games[user].game + ".save\n"; + write(games[user].writepipe[1], msg.c_str(), msg.size()); + ignoreMessage(user); + } + + void ignoreMessage(const std::string &user) { + usleep(1000000); + static char buf[15000]; + buf[0] = 0; + int repeated = 0; + while (strlen(buf) == 0) { + ssize_t len = read(games[user].readpipe[0], buf, 15000); + if (len > 0) { + buf[len] = 0; + } + usleep(1000); + repeated++; + if (repeated > 30) + return; + } + + std::cout << "ignoring: " << buf << "\n"; + } + + std::vector getGames() { + std::vector games; + path p("."); + directory_iterator end_itr; + for (directory_iterator itr(p); itr != end_itr; ++itr) { + if (extension(itr->path()) == ".z5") { #if BOOST_FILESYSTEM_VERSION == 3 - games.push_back(itr->path().filename().string()); + games.push_back(itr->path().filename().string()); #else - games.push_back(itr->path().leaf()); + games.push_back(itr->path().leaf()); #endif - } - } - return games; - } - - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") { - std::cout << "aaa\n"; - if (message.find("start") == 0) { - std::string game = message.substr(6); - std::vector lst = getGames(); - if (std::find(lst.begin(), lst.end(), game) == lst.end()) { - np->handleMessage(user, "zcode", "Unknown game"); - return; - } - np->handleMessage(user, "zcode", "Starting the game"); - - dfrotz d; - d.game = game; - start_dfrotz(d, game); - games[user] = d; - fcntl(games[user].readpipe[0], F_SETFL, O_NONBLOCK); - - if (boost::filesystem::exists(user + "_" + games[user].game + ".save")) { - - std::string msg = "restore\n"; - write(games[user].writepipe[1], msg.c_str(), msg.size()); - - msg = user + "_" + games[user].game + ".save\n"; - write(games[user].writepipe[1], msg.c_str(), msg.size()); - - ignoreMessage(user); - - msg = "l\n"; - write(games[user].writepipe[1], msg.c_str(), msg.size()); - } - - readMessage(user); - } - else if (message == "stop" && games.find(user) != games.end()) { - kill(games[user].pid, SIGTERM); - games.erase(user); - np->handleMessage(user, "zcode", "Game stopped"); - } - else if (message == "howtoplay") { - np->handleMessage(user, "zcode", howtoplay); - } - else if (games.find(user) != games.end()) { - std::string msg = message + "\n"; - write(games[user].writepipe[1], msg.c_str(), msg.size()); - readMessage(user); - } - else { - std::string games; - BOOST_FOREACH(const std::string &game, getGames()) { - games += game + "\n"; - } - np->handleMessage(user, "zcode", "Games are saved/loaded automatically. Use \"restart\" to restart existing game. Emulator commands are:\nstart \nstop\nhowtoplay\n\nList of games:\n" + games); - } - } - - void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { - } - - void handleLeaveRoomRequest(const std::string &user, const std::string &room) { - } - - std::map games; - std::string first_msg; - private: - - Config *config; + } + } + return games; + } + + void handleMessageSendRequest(const std::string &user, + const std::string &legacyName, + const std::string &message, + const std::string &xhtml = "", + const std::string &id = "") { + std::cout << "aaa\n"; + if (message.find("start") == 0) { + std::string game = message.substr(6); + std::vector lst = getGames(); + if (std::find(lst.begin(), lst.end(), game) == lst.end()) { + np->handleMessage(user, "zcode", "Unknown game"); + return; + } + np->handleMessage(user, "zcode", "Starting the game"); + + dfrotz d; + d.game = game; + start_dfrotz(d, game); + games[user] = d; + fcntl(games[user].readpipe[0], F_SETFL, O_NONBLOCK); + + if (boost::filesystem::exists(user + "_" + games[user].game + ".save")) { + + std::string msg = "restore\n"; + write(games[user].writepipe[1], msg.c_str(), msg.size()); + + msg = user + "_" + games[user].game + ".save\n"; + write(games[user].writepipe[1], msg.c_str(), msg.size()); + + ignoreMessage(user); + + msg = "l\n"; + write(games[user].writepipe[1], msg.c_str(), msg.size()); + } + + readMessage(user); + } else if (message == "stop" && games.find(user) != games.end()) { + kill(games[user].pid, SIGTERM); + games.erase(user); + np->handleMessage(user, "zcode", "Game stopped"); + } else if (message == "howtoplay") { + np->handleMessage(user, "zcode", howtoplay); + } else if (games.find(user) != games.end()) { + std::string msg = message + "\n"; + write(games[user].writepipe[1], msg.c_str(), msg.size()); + readMessage(user); + } else { + std::string games; + BOOST_FOREACH (const std::string &game, getGames()) { + games += game + "\n"; + } + np->handleMessage( + user, "zcode", + "Games are saved/loaded automatically. Use \"restart\" to restart " + "existing game. Emulator commands are:\nstart " + "\nstop\nhowtoplay\n\nList of games:\n" + + games); + } + } + + void handleJoinRoomRequest(const std::string &user, const std::string &room, + const std::string &nickname, + const std::string &password) {} + + void handleLeaveRoomRequest(const std::string &user, + const std::string &room) {} + + std::map games; + std::string first_msg; }; -static void spectrum_sigchld_handler(int sig) -{ - int status; - pid_t pid; +static void spectrum_sigchld_handler(int sig) { + int status; + pid_t pid; - do { - pid = waitpid(-1, &status, WNOHANG); - } while (pid != 0 && pid != (pid_t)-1); + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); - if ((pid == (pid_t) - 1) && (errno != ECHILD)) { - char errmsg[BUFSIZ]; - snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); - perror(errmsg); - } + if ((pid == (pid_t)-1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } } +int main(int argc, char *argv[]) { + std::string host; + int port; -int main (int argc, char* argv[]) { - std::string host; - int port; - - if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { - std::cout << "SIGCHLD handler can't be set\n"; - return -1; - } + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } - std::string error; - Config *cfg = Config::createFromArgs(argc, argv, error, host, port); - if (cfg == NULL) { - std::cerr << error; - return 1; - } + std::string error; + Config *cfg = Config::createFromArgs(argc, argv, error, host, port); + if (cfg == NULL) { + std::cerr << error; + return 1; + } - Swift::SimpleEventLoop eventLoop; - loop_ = &eventLoop; - np = new FrotzNetworkPlugin(cfg, &eventLoop, host, port); - loop_->run(); + np = new FrotzNetworkPlugin(cfg, host, port); + np->run(); - delete cfg; + delete cfg; - return 0; + return 0; } diff --git a/backends/libcommuni/CMakeLists.txt b/backends/libcommuni/CMakeLists.txt index 544043fdc..7e3152fc9 100644 --- a/backends/libcommuni/CMakeLists.txt +++ b/backends/libcommuni/CMakeLists.txt @@ -14,15 +14,15 @@ target_compile_features(spectrum2_libcommuni_backend PUBLIC cxx_std_11) if(NOT WIN32) if(ENABLE_QT4) - target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt4::QtNetwork Qt4::QtCore transport pthread) + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt4::QtNetwork Qt4::QtCore transport-plugin) else() - target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt5::Network Qt5::Core transport pthread) + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt5::Network Qt5::Core transport-plugin) endif() else() if(ENABLE_QT4) - target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt4::QtNetwork Qt4::QtCore transport) + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt4::QtNetwork Qt4::QtCore transport-plugin) else() - target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt5::Network Qt5::Core transport) + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} Qt5::Network Qt5::Core transport-plugin) endif() endif() diff --git a/backends/libcommuni/ircnetworkplugin.cpp b/backends/libcommuni/ircnetworkplugin.cpp index ce8dd2b91..ac3a476df 100644 --- a/backends/libcommuni/ircnetworkplugin.cpp +++ b/backends/libcommuni/ircnetworkplugin.cpp @@ -27,7 +27,7 @@ DEFINE_LOGGER(logger, "IRCNetworkPlugin"); #define FROM_UTF8(WHAT) QString::fromUtf8((WHAT).c_str(), (WHAT).size()) #define TO_UTF8(WHAT) std::string((WHAT).toUtf8().data(), (WHAT).toUtf8().size()) -IRCNetworkPlugin::IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) { +IRCNetworkPlugin::IRCNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { m_config = config; m_currentServer = 0; m_firstPing = true; diff --git a/backends/libcommuni/ircnetworkplugin.h b/backends/libcommuni/ircnetworkplugin.h index aafa05a61..27de306df 100644 --- a/backends/libcommuni/ircnetworkplugin.h +++ b/backends/libcommuni/ircnetworkplugin.h @@ -26,14 +26,13 @@ #include #include "transport/Config.h" #include "transport/NetworkPlugin.h" -#include "Swiften/EventLoop/Qt/QtEventLoop.h" #endif class IRCNetworkPlugin : public QObject, public NetworkPlugin { Q_OBJECT public: - IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port); + IRCNetworkPlugin(Config *config, const std::string &host, int port); void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password, const std::map &settings); diff --git a/backends/libcommuni/main.cpp b/backends/libcommuni/main.cpp index a5100e03c..c39863fcb 100644 --- a/backends/libcommuni/main.cpp +++ b/backends/libcommuni/main.cpp @@ -22,7 +22,6 @@ #include "transport/Config.h" #include "transport/NetworkPlugin.h" #include "transport/Logging.h" -#include "Swiften/EventLoop/Qt/QtEventLoop.h" #include "ircnetworkplugin.h" using namespace boost::program_options; @@ -45,9 +44,7 @@ int main (int argc, char* argv[]) { QCoreApplication app(argc, argv); - Swift::QtEventLoop eventLoop; - - np = new IRCNetworkPlugin(cfg, &eventLoop, host, port); + np = new IRCNetworkPlugin(cfg, host, port); return app.exec(); } diff --git a/backends/libcommuni/session.h b/backends/libcommuni/session.h index 55a1ee869..70c7b5602 100644 --- a/backends/libcommuni/session.h +++ b/backends/libcommuni/session.h @@ -27,7 +27,6 @@ #include #include #include -#include "Swiften/Swiften.h" #include #include #endif diff --git a/backends/smstools3/CMakeLists.txt b/backends/smstools3/CMakeLists.txt index b4713b92f..4e57a9fb7 100644 --- a/backends/smstools3/CMakeLists.txt +++ b/backends/smstools3/CMakeLists.txt @@ -3,6 +3,6 @@ file(GLOB SRC *.c *.cpp) add_executable(spectrum2_smstools3_backend ${SRC}) target_compile_features(spectrum2_smstools3_backend PUBLIC cxx_std_11) -target_link_libraries(spectrum2_smstools3_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_smstools3_backend transport ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES}) install(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 52ac28235..6fe52bc96 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -10,12 +10,11 @@ #include "transport/Config.h" #include "transport/Logging.h" -#include "transport/NetworkPlugin.h" +#include "transport/BoostNetworkPlugin.h" #include "transport/SQLite3Backend.h" #include "transport/MySQLBackend.h" #include "transport/PQXXBackend.h" #include "transport/StorageBackend.h" -#include #include #include "unistd.h" #include "signal.h" @@ -24,14 +23,13 @@ #include #include -Swift::SimpleEventLoop *loop_; - #include #include +using namespace boost::asio::ip; using namespace boost::filesystem; - using namespace boost::program_options; + using namespace Transport; DEFINE_LOGGER(logger, "SMSNetworkPlugin"); @@ -41,30 +39,18 @@ DEFINE_LOGGER(logger, "SMSNetworkPlugin"); class SMSNetworkPlugin; SMSNetworkPlugin * np = NULL; -class SMSNetworkPlugin : public NetworkPlugin { +class SMSNetworkPlugin : public BoostNetworkPlugin { public: - Swift::BoostNetworkFactories *m_factories; - Swift::BoostIOServiceThread m_boostIOServiceThread; - std::shared_ptr m_conn; - Swift::Timer::ref m_timer; int m_internalUser; + std::shared_ptr m_timer; StorageBackend *storageBackend; - SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port) : NetworkPlugin() { - this->config = config; + SMSNetworkPlugin(Config *config, StorageBackend *storagebackend, const std::string &host, int port) + : BoostNetworkPlugin(config, host, port) { this->storageBackend = storagebackend; - m_factories = new Swift::BoostNetworkFactories(loop); - m_conn = m_factories->getConnectionFactory()->createConnection(); - m_conn->onDataRead.connect(boost::bind(&SMSNetworkPlugin::_handleDataRead, this, _1)); - m_conn->connect(Swift::HostAddressPort(*(Swift::HostAddress::fromString(host)), port)); -// m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1)); -// m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this)); - LOG4CXX_INFO(logger, "Starting the plugin."); - - m_timer = m_factories->getTimerFactory()->createTimer(5000); - m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); - m_timer->start(); + m_timer = std::make_shared(io_context, boost::posix_time::seconds(5)); + m_timer->async_wait(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); // We're reusing our database model here. Buddies of user with JID INTERNAL_USER are there // to match received GSM messages from number N with the XMPP users who sent message to number N. @@ -144,7 +130,6 @@ class SMSNetworkPlugin : public NetworkPlugin { LOG4CXX_ERROR(logger, "Error when removing the SMS: " << ex.what() << "."); } } - m_timer->start(); } void sendSMS(const std::string &to, const std::string &msg) { @@ -165,15 +150,6 @@ class SMSNetworkPlugin : public NetworkPlugin { myfile.close(); } - void sendData(const std::string &string) { - m_conn->write(Swift::createSafeByteArray(string)); - } - - void _handleDataRead(std::shared_ptr data) { - std::string d(data->begin(), data->end()); - handleDataRead(d); - } - void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password, const std::map &settings) { UserInfo info; if (!storageBackend->getUser(user, info)) { @@ -228,11 +204,6 @@ class SMSNetworkPlugin : public NetworkPlugin { void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { } - - - private: - - Config *config; }; static void spectrum_sigchld_handler(int sig) @@ -282,10 +253,8 @@ int main (int argc, char* argv[]) { return -1; } - Swift::SimpleEventLoop eventLoop; - loop_ = &eventLoop; - np = new SMSNetworkPlugin(cfg, &eventLoop, storageBackend, host, port); - loop_->run(); + np = new SMSNetworkPlugin(cfg, storageBackend, host, port); + np->run(); return 0; } diff --git a/backends/swiften/CMakeLists.txt b/backends/swiften/CMakeLists.txt index a01543266..87c3e28a8 100644 --- a/backends/swiften/CMakeLists.txt +++ b/backends/swiften/CMakeLists.txt @@ -4,10 +4,6 @@ add_executable(spectrum2_swiften_backend ${SRC}) target_compile_features(spectrum2_swiften_backend PUBLIC cxx_std_11) -if(NOT WIN32) - target_link_libraries(spectrum2_swiften_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -else() - target_link_libraries(spectrum2_swiften_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -endif() +target_link_libraries(spectrum2_swiften_backend transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) install(TARGETS spectrum2_swiften_backend RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) diff --git a/backends/template/CMakeLists.txt b/backends/template/CMakeLists.txt index 9789d30c4..7103718a3 100644 --- a/backends/template/CMakeLists.txt +++ b/backends/template/CMakeLists.txt @@ -3,14 +3,6 @@ file(GLOB SRC *.c *.cpp) add_executable(spectrum2_template_backend ${SRC}) target_compile_features(spectrum2_template_backend PUBLIC cxx_std_11) -if(CMAKE_COMPILER_IS_GNUCXX) - if(NOT WIN32) - target_link_libraries(spectrum2_template_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) - else() - target_link_libraries(spectrum2_template_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) - endif() -else() - target_link_libraries(spectrum2_template_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) -endif() +target_link_libraries(spectrum2_template_backend transport-plugin ${PROTOBUF_LIBRARY} ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES}) -#install(TARGETS spectrum2_template_backend RUNTIME DESTINATION bin) +#install(TARGETS spectrum2_template_backend RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) diff --git a/backends/template/main.cpp b/backends/template/main.cpp index 5f9df1a81..b6fd2f914 100644 --- a/backends/template/main.cpp +++ b/backends/template/main.cpp @@ -5,9 +5,6 @@ #include "transport/NetworkPlugin.h" #include "transport/Logging.h" -// Swiften -#include "Swiften/Swiften.h" - #ifndef _WIN32 // for signal handler #include "unistd.h" @@ -17,7 +14,6 @@ #endif // Boost #include -using namespace boost::filesystem; using namespace boost::program_options; using namespace Transport; @@ -60,9 +56,8 @@ int main (int argc, char* argv[]) { Logging::initBackendLogging(cfg); - Swift::SimpleEventLoop eventLoop; - Plugin p(cfg, &eventLoop, host, port); - eventLoop.run(); + Plugin p(cfg, host, port); + p.run(); return 0; } diff --git a/backends/template/plugin.cpp b/backends/template/plugin.cpp index 57b828487..23e1279a7 100644 --- a/backends/template/plugin.cpp +++ b/backends/template/plugin.cpp @@ -1,62 +1,58 @@ #include "plugin.h" // Transport includes #include "transport/Config.h" -#include "transport/NetworkPlugin.h" #include "transport/Logging.h" - -// Swiften -#include "Swiften/Swiften.h" +#include "transport/BoostNetworkPlugin.h" // Boost #include -using namespace boost::filesystem; +#include +using namespace boost::asio::ip; using namespace boost::program_options; using namespace Transport; DEFINE_LOGGER(logger, "Backend Template"); -Plugin::Plugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { - this->config = config; - m_factories = new Swift::BoostNetworkFactories(loop); - m_conn = m_factories->getConnectionFactory()->createConnection(); - m_conn->onDataRead.connect(boost::bind(&Plugin::_handleDataRead, this, _1)); - m_conn->connect(Swift::HostAddressPort(*(Swift::HostAddress::fromString(host)), port)); - - LOG4CXX_INFO(logger, "Starting the plugin."); -} - -// NetworkPlugin uses this method to send the data to networkplugin server -void Plugin::sendData(const std::string &string) { - m_conn->write(Swift::createSafeByteArray(string)); +Plugin::Plugin(Config *config, + const std::string &host, int port) + : BoostNetworkPlugin(config, host, port) { } -// This method has to call handleDataRead with all received data from network plugin server -void Plugin::_handleDataRead(std::shared_ptr data) { - std::string d(data->begin(), data->end()); - handleDataRead(d); +void Plugin::handleLoginRequest( + const std::string &user, const std::string &legacyName, + const std::string &password, + const std::map &settings) { + handleConnected(user); + LOG4CXX_INFO(logger, user << ": Added buddy - Echo."); + handleBuddyChanged(user, "echo", "Echo", std::vector(), + pbnetwork::STATUS_ONLINE); } -void Plugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password, const std::map &settings) { - handleConnected(user); - LOG4CXX_INFO(logger, user << ": Added buddy - Echo."); - handleBuddyChanged(user, "echo", "Echo", std::vector(), pbnetwork::STATUS_ONLINE); -} - -void Plugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) { -} +void Plugin::handleLogoutRequest(const std::string &user, + const std::string &legacyName) {} -void Plugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &id) { - LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << "."); - if (legacyName == "echo") { - handleMessage(user, legacyName, message); - } +void Plugin::handleMessageSendRequest(const std::string &user, + const std::string &legacyName, + const std::string &message, + const std::string &xhtml, + const std::string &id) { + LOG4CXX_INFO(logger, + "Sending message from " << user << " to " << legacyName << "."); + if (legacyName == "echo") { + handleMessage(user, legacyName, message); + } } -void Plugin::handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { - LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << "."); - handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); +void Plugin::handleBuddyUpdatedRequest(const std::string &user, + const std::string &buddyName, + const std::string &alias, + const std::vector &groups) { + LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << "."); + handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); } -void Plugin::handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { +void Plugin::handleBuddyRemovedRequest(const std::string &user, + const std::string &buddyName, + const std::vector &groups) { } diff --git a/backends/template/plugin.h b/backends/template/plugin.h index be2d876d8..fe15a79c4 100644 --- a/backends/template/plugin.h +++ b/backends/template/plugin.h @@ -1,16 +1,15 @@ #pragma once -#include "Swiften/Swiften.h" +#include + +#include #include "transport/Config.h" -#include "transport/NetworkPlugin.h" +#include "transport/BoostNetworkPlugin.h" -class Plugin : public Transport::NetworkPlugin { +class Plugin : public Transport::BoostNetworkPlugin { public: - Plugin(Transport::Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port); - - // NetworkPlugin uses this method to send the data to networkplugin server - void sendData(const std::string &string); + Plugin(Transport::Config *config, const std::string &host, int port); void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password, const std::map &settings); @@ -21,14 +20,4 @@ class Plugin : public Transport::NetworkPlugin { void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups); void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups); - - private: - // This method has to call handleDataRead with all received data from network plugin server - void _handleDataRead(std::shared_ptr data); - - private: - Swift::BoostNetworkFactories *m_factories; - Swift::BoostIOServiceThread m_boostIOServiceThread; - std::shared_ptr m_conn; - Transport::Config *config; }; diff --git a/include/transport/BoostNetworkPlugin.h b/include/transport/BoostNetworkPlugin.h new file mode 100644 index 000000000..45c50b84f --- /dev/null +++ b/include/transport/BoostNetworkPlugin.h @@ -0,0 +1,45 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011-2023, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#pragma once + +#include +#include +#include + +#include + +#include + +namespace Transport { + class BoostNetworkPlugin: public NetworkPlugin { + public: + BoostNetworkPlugin(Config *config, const std::string &host, int port); + void sendData(const std::string &string); + void handleExitRequest(); + void run(); + protected: + Transport::Config *config; + boost::asio::io_context io_context; + private: + std::shared_ptr socket_; + bool is_connected; + }; +} diff --git a/include/transport/HTTPRequest.h b/include/transport/HTTPRequest.h index ea3fd6473..ca12b78d4 100644 --- a/include/transport/HTTPRequest.h +++ b/include/transport/HTTPRequest.h @@ -1,73 +1,36 @@ +#ifndef HTTPREQ_H +#define HTTPREQ_H -#pragma once - -#include -#include +#include "curl/curl.h" #include "transport/Logging.h" -#include "transport/ThreadPool.h" #include -#include #include -#include - -namespace Transport { - -class HTTPRequest : public Thread { - public: - typedef enum { Get } Type; - typedef boost::function< void (HTTPRequest *, bool, Json::Value &json, const std::string &data) > Callback; - - HTTPRequest(ThreadPool *tp, Type type, const std::string &url, Callback callback); - HTTPRequest(Type type, const std::string &url); - - virtual ~HTTPRequest(); - - void setProxy(std::string, std::string, std::string, std::string); - bool execute(); - bool execute(Json::Value &json); - std::string getError() {return std::string(curl_errorbuffer);} - const std::string &getRawData() { - return m_data; - } - - void run(); - void finalize(); - const std::string &getURL() { - return m_url; - } - - boost::signals2::signal onRequestFinished; +class HTTPRequest +{ + CURL *curlhandle; + char curl_errorbuffer[1024]; + std::string error; + std::string callbackdata; - static void globalInit() { - curl_global_init(CURL_GLOBAL_ALL); - } + static int curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest *obj); - static void globalCleanup() { - curl_global_cleanup(); + public: + HTTPRequest() { + curlhandle = NULL; + } + + ~HTTPRequest() { + if(curlhandle) { + curl_easy_cleanup(curlhandle); + curlhandle = NULL; } + } - private: - bool init(); - bool GET(std::string url, std::string &output); - bool GET(std::string url, Json::Value &json); - - - CURL *curlhandle; - char curl_errorbuffer[1024]; - std::string error; - std::string callbackdata; - ThreadPool *m_tp; - std::string m_url; - bool m_ok; - Json::Value m_json; - std::string m_data; - Callback m_callback; - Type m_type; - - static int curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest *obj); - + bool init(); + void setProxy(std::string, std::string, std::string, std::string); + bool GET(std::string, std::string &); + std::string getCurlError() {return std::string(curl_errorbuffer);} }; -} - +#endif diff --git a/include/transport/HTTPRequestQueue.h b/include/transport/HTTPRequestQueue.h deleted file mode 100644 index 32475cfa1..000000000 --- a/include/transport/HTTPRequestQueue.h +++ /dev/null @@ -1,40 +0,0 @@ - -#pragma once - -#include "curl/curl.h" -#include "transport/Logging.h" -#include "transport/ThreadPool.h" -#include -#include -#include - -#include "Swiften/Network/Timer.h" - -namespace Transport { - -class HTTPRequest; -class Component; - -class HTTPRequestQueue { - public: - HTTPRequestQueue(Component *component, const std::string &user, int delayBetweenRequests = 1); - - virtual ~HTTPRequestQueue(); - - void queueRequest(HTTPRequest *req); - - void sendNextRequest(); - - private: - void handleRequestFinished(); - - private: - int m_delay; - std::queue m_queue; - HTTPRequest *m_req; - Swift::Timer::ref m_queueTimer; - std::string m_user; -}; - -} - diff --git a/include/transport/NetworkPlugin.h b/include/transport/NetworkPlugin.h index eecf9497d..2df1120d6 100644 --- a/include/transport/NetworkPlugin.h +++ b/include/transport/NetworkPlugin.h @@ -50,7 +50,6 @@ class NetworkPlugin { void setExtraFields(const std::vector &fields) { m_extraFields = fields; } void setRawXML(bool rawXML = false) { m_rawXML = rawXML; } void disableJIDEscaping() { m_disableJIDEscaping = true; } - private: bool m_needPassword; bool m_needRegistration; @@ -63,9 +62,6 @@ class NetworkPlugin { }; /// Creates new NetworkPlugin and connects the Spectrum2 NetworkPluginServer. - /// \param loop Event loop. - /// \param host Host where Spectrum2 NetworkPluginServer runs. - /// \param port Port. NetworkPlugin(); /// Destructor. @@ -267,7 +263,7 @@ class NetworkPlugin { virtual void handleExitRequest() { exit(1); } void handleDataRead(std::string &data); - virtual void sendData(const std::string &string) {} + virtual void sendData(const std::string &string) {}; void checkPing(); @@ -292,7 +288,6 @@ class NetworkPlugin { std::string m_data; bool m_pingReceived; double m_init_res; - }; } diff --git a/include/transport/ThreadPool.h b/include/transport/ThreadPool.h index 87939c2b0..a45aeab47 100644 --- a/include/transport/ThreadPool.h +++ b/include/transport/ThreadPool.h @@ -1,12 +1,12 @@ #pragma once +#include #include #include #include #include #include #include -#include "Swiften/EventLoop/EventLoop.h" namespace Transport { @@ -55,12 +55,12 @@ class ThreadPool boost::mutex count_lock; boost::mutex pool_lock; boost::mutex criticalregion; - Swift::EventLoop *loop; + boost::asio::io_context *loop; boost::signals2::signal < void () > onWorkerAvailable; public: - ThreadPool(Swift::EventLoop *loop, int maxthreads); + ThreadPool(const boost::asio::io_context &loop, int maxthreads); ~ThreadPool(); void runAsThread(Thread *t); int getActiveThreadCount(); diff --git a/libtransport/CMakeLists.txt b/libtransport/CMakeLists.txt index 5e7a8375d..3915a3ef8 100644 --- a/libtransport/CMakeLists.txt +++ b/libtransport/CMakeLists.txt @@ -47,10 +47,6 @@ find_package(CURL) target_link_libraries(transport transport-plugin ${CURL_LIBRARIES} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY} ${PROTOBUF_LIBRARY} JsonCpp::JsonCpp) target_compile_features(transport PUBLIC cxx_std_11) -if(WIN32) - target_link_libraries(transport psapi.lib bcrypt.lib) -endif() - if(PQXX_FOUND) target_link_libraries(transport ${PQXX_LIBRARIES} ${PQ_LIBRARY}) endif() diff --git a/libtransport/HTTPRequestQueue.cpp b/libtransport/HTTPRequestQueue.cpp deleted file mode 100644 index de298806a..000000000 --- a/libtransport/HTTPRequestQueue.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "transport/HTTPRequestQueue.h" -#include "transport/HTTPRequest.h" -#include "transport/Transport.h" - -namespace Transport { - -DEFINE_LOGGER(httpRequestQueueLogger, "HTTPRequestQueue") - -HTTPRequestQueue::HTTPRequestQueue(Component *component, const std::string &user, int delay) { - m_delay = delay; - m_req = NULL; - m_user = user; - - m_queueTimer = component->getNetworkFactories()->getTimerFactory()->createTimer(500); - m_queueTimer->onTick.connect(boost::bind(&HTTPRequestQueue::sendNextRequest, this)); -} - -HTTPRequestQueue::~HTTPRequestQueue() { - m_queueTimer->stop(); - - if (m_req) { - m_req->onRequestFinished.disconnect(boost::bind(&HTTPRequestQueue::handleRequestFinished, this)); - } -} - -void HTTPRequestQueue::handleRequestFinished() { - m_req = NULL; - m_queueTimer->start(); -} - -void HTTPRequestQueue::sendNextRequest() { - if (m_queue.empty()) { - LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": Queue is empty."); - m_req = NULL; - m_queueTimer->stop(); - return; - } - - if (m_req) { - LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": There is already a request being handled."); - return; - } - - m_req = m_queue.front(); - m_queue.pop(); - - LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": Starting request '" << m_req->getURL() << "'."); - m_req->onRequestFinished.connect(boost::bind(&HTTPRequestQueue::handleRequestFinished, this)); - m_req->execute(); -} - -void HTTPRequestQueue::queueRequest(HTTPRequest *req) { - m_queue.push(req); - - if (!m_req) { - sendNextRequest(); - } - else { - LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": Request '" << req->getURL() << "' queued."); - } -} - - -} diff --git a/libtransport/OAuth2.cpp b/libtransport/OAuth2.cpp index bf0f0a592..f6b8e0c3e 100644 --- a/libtransport/OAuth2.cpp +++ b/libtransport/OAuth2.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace Transport { @@ -81,20 +82,21 @@ std::string OAuth2::requestToken(const std::string &code, std::string &token, st url += "&redirect_uri=" + Util::urlencode(m_redirectURL); } - Json::Value resp; - HTTPRequest req(HTTPRequest::Get, url); - if (!req.execute(resp)) { + std::string responseData; + HTTPRequest req; + req.init(); + if (!req.GET(url, responseData)) { LOG4CXX_ERROR(oauth2Logger, url); - LOG4CXX_ERROR(oauth2Logger, req.getError()); - return req.getError(); + LOG4CXX_ERROR(oauth2Logger, req.getCurlError()); + return req.getCurlError(); } - LOG4CXX_ERROR(oauth2Logger, req.getRawData()); + LOG4CXX_ERROR(oauth2Logger, responseData); + Json::Value resp(responseData); Json::Value& access_token = resp["access_token"]; if (!access_token.isString()) { LOG4CXX_ERROR(oauth2Logger, "No 'access_token' object in the reply."); LOG4CXX_ERROR(oauth2Logger, url); - LOG4CXX_ERROR(oauth2Logger, req.getRawData()); return "No 'access_token' object in the reply."; } @@ -102,7 +104,6 @@ std::string OAuth2::requestToken(const std::string &code, std::string &token, st if (token.empty()) { LOG4CXX_ERROR(oauth2Logger, "Empty 'access_token' object in the reply."); LOG4CXX_ERROR(oauth2Logger, url); - LOG4CXX_ERROR(oauth2Logger, req.getRawData()); return "Empty 'access_token' object in the reply."; } diff --git a/libtransport/WebSocketClient.cpp b/libtransport/WebSocketClient.cpp index e643b1ce8..f64065451 100644 --- a/libtransport/WebSocketClient.cpp +++ b/libtransport/WebSocketClient.cpp @@ -32,7 +32,7 @@ namespace Transport { -DEFINE_LOGGER(logger, "WebSocketClient"); +DEFINE_LOGGER(wsLogger, "WebSocketClient"); WebSocketClient::WebSocketClient(Component *component, const std::string &user) { m_component = component; @@ -58,7 +58,7 @@ WebSocketClient::~WebSocketClient() { } void WebSocketClient::connectServer() { - LOG4CXX_INFO(logger, m_user << ": Starting DNS query for " << m_host << " " << m_path); + LOG4CXX_INFO(wsLogger, m_user << ": Starting DNS query for " << m_host << " " << m_path); m_upgraded = false; m_buffer.clear(); @@ -120,7 +120,7 @@ void WebSocketClient::write(const std::string &data) { + payload)); } - LOG4CXX_INFO(logger, m_user << ": > " << data); + LOG4CXX_INFO(wsLogger, m_user << ": > " << data); } void WebSocketClient::handleDataRead(std::shared_ptr data) { @@ -159,7 +159,7 @@ void WebSocketClient::handleDataRead(std::shared_ptr data) // This seems to be Slack bug... sometimes we receive 0x89 followed by 0x81 // For now, in that case we will just ignore the 0x89 and skip it... if (opcode == 9 && mask && size7 == 1) { - LOG4CXX_WARN(logger, m_user << ": Applying Slack workaround because of partial data received from server"); + LOG4CXX_WARN(wsLogger, m_user << ": Applying Slack workaround because of partial data received from server"); m_buffer.erase(0, 1); continue; } @@ -167,7 +167,7 @@ void WebSocketClient::handleDataRead(std::shared_ptr data) unsigned int size = (size16 == 0 ? size7 : size16); if (m_buffer.size() >= size + header_size) { std::string payload = m_buffer.substr(header_size, size); - LOG4CXX_INFO(logger, m_user << ": < " << payload); + LOG4CXX_INFO(wsLogger, m_user << ": < " << payload); onPayloadReceived(payload); m_buffer.erase(0, size + header_size); @@ -187,12 +187,12 @@ void WebSocketClient::handleDataRead(std::shared_ptr data) void WebSocketClient::handleConnected(bool error) { if (error) { - LOG4CXX_ERROR(logger, "Connection to " << m_host << " failed. Will reconnect in 1 second."); + LOG4CXX_ERROR(wsLogger, "Connection to " << m_host << " failed. Will reconnect in 1 second."); m_reconnectTimer->start(); return; } - LOG4CXX_INFO(logger, m_user << ": Connected to " << m_host); + LOG4CXX_INFO(wsLogger, m_user << ": Connected to " << m_host); std::string req = ""; req += "GET " + m_path + " HTTP/1.1\r\n"; @@ -211,20 +211,20 @@ void WebSocketClient::handleDisconnected(const boost::optionalstart(); } void WebSocketClient::handleDNSResult(const std::vector &addrs, boost::optional error) { if (error) { - LOG4CXX_ERROR(logger, m_user << ": DNS resolving error. Will try again in 1 second."); + LOG4CXX_ERROR(wsLogger, m_user << ": DNS resolving error. Will try again in 1 second."); m_reconnectTimer->start(); return; } if (addrs.empty()) { - LOG4CXX_ERROR(logger, m_user << ": DNS name cannot be resolved. Will try again in 1 second."); + LOG4CXX_ERROR(wsLogger, m_user << ": DNS name cannot be resolved. Will try again in 1 second."); m_reconnectTimer->start(); return; } diff --git a/plugin/cpp/BoostNetworkPlugin.cpp b/plugin/cpp/BoostNetworkPlugin.cpp new file mode 100644 index 000000000..ade7c6514 --- /dev/null +++ b/plugin/cpp/BoostNetworkPlugin.cpp @@ -0,0 +1,76 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011-2023, Jan Kaluza + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "transport/BoostNetworkPlugin.h" +#include "transport/Logging.h" + +#include + +DEFINE_LOGGER(pluginLogger, "Backend"); + +namespace Transport { +BoostNetworkPlugin::BoostNetworkPlugin(Config *config, const std::string &host, + int port) + : NetworkPlugin(), io_context() { + this->config = config; + LOG4CXX_INFO(pluginLogger, "Starting the plugin."); + boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string(host), port); + socket_ = std::make_shared(io_context); + socket_.get()->async_connect(ep, [&](boost::system::error_code ec) { + if (!ec) { + LOG4CXX_INFO(pluginLogger, "Connected " << ep.address().to_string()); + this->is_connected = true; + NetworkPlugin::PluginConfig cfg; + cfg.setRawXML(false); + cfg.setNeedRegistration(false); + sendConfig(cfg); + boost::asio::streambuf sb; + boost::system::error_code ec; + while (is_connected && + boost::asio::read(*socket_, sb, boost::asio::transfer_at_least(1), + ec)) { + if (ec) { + LOG4CXX_ERROR(pluginLogger, "Connection read error: " << ec.message()); + break; + } else { + std::string s((std::istreambuf_iterator(&sb)), + std::istreambuf_iterator()); + handleDataRead(s); + } + } + } else { + LOG4CXX_ERROR(pluginLogger, "Connection error: " << ec.message()); + } + }); +} +// NetworkPlugin uses this method to send the data to networkplugin server +void BoostNetworkPlugin::sendData(const std::string &string) { + boost::asio::write(*socket_, boost::asio::buffer(string)); +} +void BoostNetworkPlugin::handleExitRequest() { + this->is_connected = false; + this->io_context.stop(); +} + +void BoostNetworkPlugin::run() { + boost::thread thread([&]() { io_context.run(); }); + thread.join(); +} +} // namespace Transport diff --git a/plugin/cpp/CMakeLists.txt b/plugin/cpp/CMakeLists.txt index f82881cf9..fbf234ce2 100644 --- a/plugin/cpp/CMakeLists.txt +++ b/plugin/cpp/CMakeLists.txt @@ -19,12 +19,15 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() endif() +target_link_libraries(transport-plugin JsonCpp::JsonCpp ${CMAKE_THREAD_LIBS_INIT}) + +find_package(CURL) + if(NOT WIN32) - target_link_libraries(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES}) + target_link_libraries(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ${PQXX_LIBRARIES} ${CURL_LIBRARIES} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES}) else() - target_link_libraries(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ws2_32.lib) + target_link_libraries(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ${PQXX_LIBRARIES} ${CURL_LIBRARIES} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} psapi.lib bcrypt.lib ws2_32.lib) endif() - set_target_properties(transport-plugin PROPERTIES VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} ) diff --git a/libtransport/HTTPRequest.cpp b/plugin/cpp/HTTPRequest.cpp similarity index 50% rename from libtransport/HTTPRequest.cpp rename to plugin/cpp/HTTPRequest.cpp index a3bcdb819..33efef15f 100644 --- a/libtransport/HTTPRequest.cpp +++ b/plugin/cpp/HTTPRequest.cpp @@ -1,50 +1,22 @@ #include "transport/HTTPRequest.h" - -namespace Transport { - DEFINE_LOGGER(httpRequestLogger, "HTTPRequest") -HTTPRequest::HTTPRequest(ThreadPool *tp, Type type, const std::string &url, Callback callback) { - m_type = type; - m_url = url; - m_tp = tp; - m_callback = callback; - curlhandle = NULL; -} - -HTTPRequest::HTTPRequest(Type type, const std::string &url) { - m_type = type; - m_url = url; - m_tp = NULL; - curlhandle = NULL; -} - -HTTPRequest::~HTTPRequest() { - if (curlhandle) { - LOG4CXX_INFO(httpRequestLogger, "Cleaning up CURL handle"); - curl_easy_cleanup(curlhandle); - curlhandle = NULL; - } -} - -bool HTTPRequest::init() { - if (curlhandle) { - return true; - } - +bool HTTPRequest::init() +{ curlhandle = curl_easy_init(); if (curlhandle) { + curlhandle = curl_easy_init(); curl_easy_setopt(curlhandle, CURLOPT_PROXY, NULL); curl_easy_setopt(curlhandle, CURLOPT_PROXYUSERPWD, NULL); curl_easy_setopt(curlhandle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); return true; } - LOG4CXX_ERROR(httpRequestLogger, "Couldn't Initialize curl!"); return false; } -void HTTPRequest::setProxy(std::string IP, std::string port, std::string username, std::string password) { +void HTTPRequest::setProxy(std::string IP, std::string port, std::string username, std::string password) +{ if (curlhandle) { std::string proxyIpPort = IP + ":" + port; curl_easy_setopt(curlhandle, CURLOPT_PROXY, proxyIpPort.c_str()); @@ -57,17 +29,19 @@ void HTTPRequest::setProxy(std::string IP, std::string port, std::string usernam } } -int HTTPRequest::curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest* obj) { +int HTTPRequest::curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest* obj) +{ int writtenSize = 0; if (obj && data) { obj->callbackdata.append(data, size*nmemb); writtenSize = (int)(size*nmemb); } - return writtenSize; } -bool HTTPRequest::GET(std::string url, std::string &data) { + +bool HTTPRequest::GET(std::string url, std::string &data) +{ if (curlhandle) { curl_easy_setopt(curlhandle, CURLOPT_CUSTOMREQUEST, NULL); curl_easy_setopt(curlhandle, CURLOPT_ENCODING, ""); @@ -82,7 +56,7 @@ bool HTTPRequest::GET(std::string url, std::string &data) { /* Set http request and url */ curl_easy_setopt(curlhandle, CURLOPT_HTTPGET, 1); - curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 0); +// curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1); curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str()); /* Send http request and return status*/ @@ -94,66 +68,5 @@ bool HTTPRequest::GET(std::string url, std::string &data) { LOG4CXX_ERROR(httpRequestLogger, "CURL not initialized!"); strcpy(curl_errorbuffer, "CURL not initialized!"); } - LOG4CXX_ERROR(httpRequestLogger, "Error fetching " << url); return false; } - -bool HTTPRequest::GET(std::string url, Json::Value &json) { - if (!GET(url, m_data)) { - return false; - } - - Json::CharReaderBuilder rbuilder; - std::shared_ptr const reader(rbuilder.newCharReader()); - if (!reader->parse(m_data.c_str(), m_data.c_str() + m_data.size(), &json, NULL)) { - LOG4CXX_ERROR(httpRequestLogger, "Error while parsing JSON"); - LOG4CXX_ERROR(httpRequestLogger, m_data); - strcpy(curl_errorbuffer, "Error while parsing JSON"); - return false; - } - - return true; -} - -void HTTPRequest::run() { - if (!init()) { - m_ok = false; - return; - } - - switch (m_type) { - case Get: - m_ok = GET(m_url, m_json); - break; - } - - curl_easy_cleanup(curlhandle); - curlhandle = NULL; -} - -void HTTPRequest::finalize() { - m_callback(this, m_ok, m_json, m_data); - onRequestFinished(); -} - -bool HTTPRequest::execute() { - if (!m_tp) { - return false; - } - - m_tp->runAsThread(this); - return true; -} - -bool HTTPRequest::execute(Json::Value &json) { - init(); - switch (m_type) { - case Get: - m_ok = GET(m_url, json); - break; - } - - return m_ok; -} - -} diff --git a/plugin/cpp/MemoryUsage.cpp b/plugin/cpp/MemoryUsage.cpp index e5383f6ec..db92d9c9b 100644 --- a/plugin/cpp/MemoryUsage.cpp +++ b/plugin/cpp/MemoryUsage.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include diff --git a/libtransport/MySQLBackend.cpp b/plugin/cpp/MySQLBackend.cpp similarity index 100% rename from libtransport/MySQLBackend.cpp rename to plugin/cpp/MySQLBackend.cpp diff --git a/libtransport/PQXXBackend.cpp b/plugin/cpp/PQXXBackend.cpp similarity index 100% rename from libtransport/PQXXBackend.cpp rename to plugin/cpp/PQXXBackend.cpp diff --git a/libtransport/SQLite3Backend.cpp b/plugin/cpp/SQLite3Backend.cpp similarity index 100% rename from libtransport/SQLite3Backend.cpp rename to plugin/cpp/SQLite3Backend.cpp diff --git a/libtransport/StorageBackend.cpp b/plugin/cpp/StorageBackend.cpp similarity index 74% rename from libtransport/StorageBackend.cpp rename to plugin/cpp/StorageBackend.cpp index 2ee9171a3..a29afe51d 100644 --- a/libtransport/StorageBackend.cpp +++ b/plugin/cpp/StorageBackend.cpp @@ -4,9 +4,28 @@ #include "transport/SQLite3Backend.h" #include "transport/MySQLBackend.h" #include "transport/PQXXBackend.h" -#include "Swiften/StringCodecs/Base64.h" +#include +#include +#include +#include + +std::string decode64(const std::string &val) { + using namespace boost::archive::iterators; + using It = transform_width, 8, 6>; + return boost::algorithm::trim_right_copy_if(std::string(It(std::begin(val)), It(std::end(val))), [](char c) { + return c == '\0'; + }); +} + +std::string encode64(const std::string &val) { + using namespace boost::archive::iterators; + using It = base64_from_binary>; + auto tmp = std::string(It(std::begin(val)), It(std::end(val))); + return tmp.append((3 - val.size() % 3) % 3, '='); +} + namespace Transport { StorageBackend *StorageBackend::createBackend(Config *config, std::string &error) { @@ -59,12 +78,12 @@ std::string StorageBackend::encryptPassword(const std::string &password, const s encrypted[i] = c; } - encrypted = Swift::Base64::encode(Swift::createByteArray(encrypted)); + encrypted = encode64(encrypted); return encrypted; } std::string StorageBackend::decryptPassword(std::string &encrypted, const std::string &key) { - encrypted = Swift::byteArrayToString(Swift::Base64::decode(encrypted)); + encrypted = decode64(encrypted); std::string password; password.resize(encrypted.size()); for (unsigned i = 0; i < encrypted.size(); i++) { diff --git a/libtransport/ThreadPool.cpp b/plugin/cpp/ThreadPool.cpp similarity index 92% rename from libtransport/ThreadPool.cpp rename to plugin/cpp/ThreadPool.cpp index 24448442a..5b7ac595c 100644 --- a/libtransport/ThreadPool.cpp +++ b/plugin/cpp/ThreadPool.cpp @@ -1,13 +1,11 @@ #include "transport/ThreadPool.h" #include "transport/Logging.h" - namespace Transport { DEFINE_LOGGER(threadPoolLogger, "ThreadPool") -ThreadPool::ThreadPool(Swift::EventLoop *loop, int maxthreads) : MAX_THREADS(maxthreads) +ThreadPool::ThreadPool(const boost::asio::io_context &io_context, int maxthreads) : MAX_THREADS(maxthreads) { - this->loop = loop; activeThreads = 0; worker = (boost::thread **) malloc(sizeof(boost::thread *) * MAX_THREADS); for (int i=0 ; irun(); - loop->postEvent(boost::bind(&ThreadPool::cleandUp, this, t, wid), std::shared_ptr()); + cleandUp(t, wid); } } diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index cc1dba244..a4a22cb20 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -22,16 +22,9 @@ #include "transport/MemoryUsage.h" #include "transport/Logging.h" -#include +#include -#ifndef WIN32 -#include -#include -#include -#else -#include -#include -#include +#ifdef _WIN32 #define getpid _getpid #endif @@ -511,7 +504,6 @@ void NetworkPlugin::handleDataRead(std::string &data) { else { return; } - pbnetwork::WrapperMessage wrapper; if (wrapper.ParseFromArray(&m_data[4], expected_size) == false) { m_data.erase(m_data.begin(), m_data.begin() + 4 + expected_size); @@ -573,7 +565,7 @@ void NetworkPlugin::handleDataRead(std::string &data) { break; default: return; - } + } } } diff --git a/spectrum/src/CMakeLists.txt b/spectrum/src/CMakeLists.txt index 4d22ab206..147529694 100644 --- a/spectrum/src/CMakeLists.txt +++ b/spectrum/src/CMakeLists.txt @@ -6,7 +6,6 @@ add_subdirectory(frontends) if(WIN32) file(GLOB WIN_SRC win32/*.cpp) include_directories(win32) - include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3") add_executable(spectrum2 ${SRC} ${WIN_SRC}) else() add_executable(spectrum2 ${SRC}) @@ -16,12 +15,15 @@ if (ENABLE_PURPLE AND PURPLE_FOUND) add_dependencies(spectrum2 spectrum2_libpurple_backend) endif() -target_link_libraries(spectrum2 transport spectrum2-xmpp-frontend spectrum2-slack-frontend ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY}) -target_compile_features(spectrum2 PUBLIC cxx_std_11) +target_link_libraries(spectrum2 transport spectrum2-xmpp-frontend ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY}) + +if(ENABLE_SLACK_FRONTEND) + target_link_libraries(spectrum2 spectrum2-slack-frontend) +endif() if(NOT MSVC AND NOT APPLE) # export all symbols (used for loading frontends) - set(CMAKE_EXE_LINKER_FLAGS "-Wl,--export-dynamic") + set(CMAKE_EXE_LINKER_FLAGS "-Wl,-export-dynamic") endif() install(TARGETS spectrum2 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/spectrum/src/frontends/CMakeLists.txt b/spectrum/src/frontends/CMakeLists.txt index eb6249560..44342804f 100644 --- a/spectrum/src/frontends/CMakeLists.txt +++ b/spectrum/src/frontends/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(xmpp) +if(ENABLE_SLACK_FRONTEND) add_subdirectory(slack) +endif() diff --git a/spectrum/src/frontends/xmpp/XMPPFrontend.cpp b/spectrum/src/frontends/xmpp/XMPPFrontend.cpp index 5cd003517..909367326 100644 --- a/spectrum/src/frontends/xmpp/XMPPFrontend.cpp +++ b/spectrum/src/frontends/xmpp/XMPPFrontend.cpp @@ -145,7 +145,7 @@ void XMPPFrontend::init(Component *transport, Swift::EventLoop *loop, Swift::Net } else { - LOG4CXX_WARN(logger, "No PKCS#12 certificate used. TLS is disabled."); + LOG4CXX_INFO(logger, "No PKCS#12 certificate used. TLS is disabled."); } // m_server->start(); m_stanzaChannel = m_server->getStanzaChannel(); diff --git a/spectrum/src/frontends/xmpp/gatewayresponder.cpp b/spectrum/src/frontends/xmpp/gatewayresponder.cpp index 5698f8504..917aadcfe 100644 --- a/spectrum/src/frontends/xmpp/gatewayresponder.cpp +++ b/spectrum/src/frontends/xmpp/gatewayresponder.cpp @@ -63,7 +63,7 @@ bool GatewayResponder::handleSetRequest(const Swift::JID& from, const Swift::JID // This code is here to workaround Gajim (and probably other clients bug too) bug // https://trac.gajim.org/ticket/7277 if (prompt.find("\\40") != std::string::npos) { - LOG4CXX_WARN(gatewayResponderLogger, from.toString() << " Received already escaped JID " << prompt << ". Not escaping again."); + LOG4CXX_INFO(gatewayResponderLogger, from.toString() << " Received already escaped JID " << prompt << ". Not escaping again."); escaped = prompt; } diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index c7934a590..bbdbfadb5 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -14,7 +14,9 @@ #include "transport/Logging.h" #include "transport/Frontend.h" #include "frontends/xmpp/XMPPFrontendPlugin.h" +#ifdef ENABLE_SLACK_FRONTEND #include "frontends/slack/SlackFrontendPlugin.h" +#endif #include "Swiften/EventLoop/SimpleEventLoop.h" #include "Swiften/Network/BoostNetworkFactories.h" #include diff --git a/tests/libtransport/CMakeLists.txt b/tests/libtransport/CMakeLists.txt index a8996a8c3..608f63255 100644 --- a/tests/libtransport/CMakeLists.txt +++ b/tests/libtransport/CMakeLists.txt @@ -15,18 +15,24 @@ string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") endif() - file(GLOB HEADERS ../../include/transport/*.h) - include_directories(../../spectrum/src/frontends/xmpp/) - include_directories(../../spectrum/src/frontends/slack/) +file(GLOB HEADERS ../../include/transport/*.h) +include_directories(../../spectrum/src/frontends/xmpp/) +if(ENABLE_SLACK_FRONTEND) +file(GLOB SRC slack/*.cpp slack/*.h) +include_directories(../../spectrum/src/frontends/slack/) +endif() - if(CPPUNIT_FOUND) - file(GLOB SRC_TEST *.cpp) - file(GLOB SRC_TEST_FRONTEND_XMPP ../../spectrum/src/frontends/xmpp/*.cpp) - file(GLOB SRC_TEST_FRONTEND_SLACK ../../spectrum/src/frontends/slack/*.cpp) - - add_executable(libtransport_test ${SRC_TEST} ${SRC_TEST_FRONTEND_XMPP} ${SRC_TEST_FRONTEND_SLACK}) - target_compile_features(libtransport_test PUBLIC cxx_std_11) - set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) +if(CPPUNIT_FOUND) + file(GLOB SRC_TEST *.cpp) + file(GLOB SRC_TEST_FRONTEND_XMPP ../../spectrum/src/frontends/xmpp/*.cpp) + add_executable(libtransport_test ${SRC_TEST} ${SRC_TEST_FRONTEND_XMPP}) + target_link_libraries(libtransport_test JsonCpp::JsonCpp) + if(ENABLE_SLACK_FRONTEND) + file(GLOB SRC_TEST_FRONTEND_SLACK ../../spectrum/src/frontends/slack/*.cpp) + target_link_libraries(libtransport_test ${SRC_TEST_FRONTEND_SLACK}) + endif() + set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) + target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES}) endif() diff --git a/tests/libtransport/HTTPRequest.cpp b/tests/libtransport/HTTPRequest.cpp index 75b62a678..0fb8ec383 100644 --- a/tests/libtransport/HTTPRequest.cpp +++ b/tests/libtransport/HTTPRequest.cpp @@ -1,68 +1,35 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include "Swiften/Server/ServerStanzaChannel.h" -#include "Swiften/Server/ServerFromClientSession.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include #include "basictest.h" - -#include "transport/ThreadPool.h" #include "transport/HTTPRequest.h" using namespace Transport; class HTTPRequestTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE(HTTPRequestTest); - CPPUNIT_TEST(GETThreadPool); + CPPUNIT_TEST(GET); CPPUNIT_TEST_SUITE_END(); public: - ThreadPool *tp; - bool result; void setUp (void) { setMeUp(); - tp = new ThreadPool(loop, 10); - result = false; } void tearDown (void) { tearMeDown(); - delete tp; } - void handleResult(HTTPRequest *req, bool ok, Json::Value &resp, const std::string &data) { - result = true; - } - void GET() { - Json::Value resp; - HTTPRequest *req = new HTTPRequest(tp, HTTPRequest::Get, "http://spectrum.im/params.json", boost::bind(&HTTPRequestTest::handleResult, this, _1, _2, _3, _4)); - req->execute(resp); - delete req; - } - - void GETThreadPool() { - HTTPRequest *req = new HTTPRequest(tp, HTTPRequest::Get, "http://spectrum.im/params.json", boost::bind(&HTTPRequestTest::handleResult, this, _1, _2, _3, _4)); - req->execute(); - - int i = 0; - while (result == false && i < 5) { - boost::system_time time = boost::get_system_time(); - time += boost::posix_time::seconds(1); - boost::thread::sleep(time); - loop->processEvents(); - i++; - } - CPPUNIT_ASSERT(result); + HTTPRequest req; + req.init(); + std::string responseData; + req.GET("http://spectrum.im/params.json", responseData); + Json::Value resp(responseData); + CPPUNIT_ASSERT(resp); } - }; CPPUNIT_TEST_SUITE_REGISTRATION (HTTPRequestTest); diff --git a/tests/libtransport/main.cpp b/tests/libtransport/main.cpp index 847cb1340..248d3691a 100644 --- a/tests/libtransport/main.cpp +++ b/tests/libtransport/main.cpp @@ -7,9 +7,8 @@ #include #ifdef WITH_LOG4CXX #include "log4cxx/logger.h" -#include "log4cxx/fileappender.h" +#include "log4cxx/consoleappender.h" #include "log4cxx/patternlayout.h" -#include "log4cxx/propertyconfigurator.h" using namespace log4cxx; #endif @@ -33,6 +32,7 @@ int main (int argc, char* argv[]) #else root->addAppender(new FileAppender(new PatternLayout(L"%d %-5p %c: %m%n"), L"libtransport_test.log", false)); #endif + root->setLevel(log4cxx::Level::getWarn()); #endif std::vector testsToRun; @@ -45,8 +45,6 @@ int main (int argc, char* argv[]) testsToRun.push_back(""); } - Transport::HTTPRequest::globalInit(); - // informs test-listener about testresults CPPUNIT_NS :: TestResult testresult; @@ -67,7 +65,6 @@ int main (int argc, char* argv[]) } catch (const std::exception& e) { google::protobuf::ShutdownProtobufLibrary(); - Transport::HTTPRequest::globalCleanup(); std::cerr << "Error: " << e.what() << std::endl; return -1; } @@ -78,7 +75,6 @@ int main (int argc, char* argv[]) compileroutputter.write (); google::protobuf::ShutdownProtobufLibrary(); - Transport::HTTPRequest::globalCleanup(); // return 0 if tests were successful return collectedresults.wasSuccessful () ? 0 : 1; diff --git a/tests/libtransport/AdminInterface.cpp b/tests/libtransport/slack/AdminInterface.cpp similarity index 100% rename from tests/libtransport/AdminInterface.cpp rename to tests/libtransport/slack/AdminInterface.cpp diff --git a/tests/libtransport/BasicSlackTest.cpp b/tests/libtransport/slack/BasicSlackTest.cpp similarity index 100% rename from tests/libtransport/BasicSlackTest.cpp rename to tests/libtransport/slack/BasicSlackTest.cpp diff --git a/tests/libtransport/BasicSlackTest.h b/tests/libtransport/slack/BasicSlackTest.h similarity index 100% rename from tests/libtransport/BasicSlackTest.h rename to tests/libtransport/slack/BasicSlackTest.h diff --git a/tests/libtransport/SlackRTM.cpp b/tests/libtransport/slack/SlackRTM.cpp similarity index 100% rename from tests/libtransport/SlackRTM.cpp rename to tests/libtransport/slack/SlackRTM.cpp From 53056a0ebb3a269cf7cd919c8e8c78df5d22dade Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 17 Jun 2026 17:38:35 +0300 Subject: [PATCH 2/7] Fix missing fileappender.h include --- tests/libtransport/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libtransport/main.cpp b/tests/libtransport/main.cpp index 248d3691a..e31b61c8f 100644 --- a/tests/libtransport/main.cpp +++ b/tests/libtransport/main.cpp @@ -7,7 +7,7 @@ #include #ifdef WITH_LOG4CXX #include "log4cxx/logger.h" -#include "log4cxx/consoleappender.h" +#include "log4cxx/fileappender.h" #include "log4cxx/patternlayout.h" using namespace log4cxx; #endif From 8f245a6c8f7d7fcc0c3c3dc22bdf23ef072acaed Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 17 Jun 2026 18:18:07 +0300 Subject: [PATCH 3/7] Fix Slack test compilation: include slack/*.cpp in SRC_TEST - slack/*.cpp added to SRC_TEST glob (was dead SRC variable) - slack frontend sources added to add_executable, not target_link_libraries - Fixes AdminInterfaceTest and SlackRTMTest not being compiled --- tests/libtransport/CMakeLists.txt | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/tests/libtransport/CMakeLists.txt b/tests/libtransport/CMakeLists.txt index 608f63255..249b02e8f 100644 --- a/tests/libtransport/CMakeLists.txt +++ b/tests/libtransport/CMakeLists.txt @@ -22,17 +22,13 @@ file(GLOB SRC slack/*.cpp slack/*.h) include_directories(../../spectrum/src/frontends/slack/) endif() -if(CPPUNIT_FOUND) - file(GLOB SRC_TEST *.cpp) - file(GLOB SRC_TEST_FRONTEND_XMPP ../../spectrum/src/frontends/xmpp/*.cpp) - add_executable(libtransport_test ${SRC_TEST} ${SRC_TEST_FRONTEND_XMPP}) - target_link_libraries(libtransport_test JsonCpp::JsonCpp) - if(ENABLE_SLACK_FRONTEND) - file(GLOB SRC_TEST_FRONTEND_SLACK ../../spectrum/src/frontends/slack/*.cpp) - target_link_libraries(libtransport_test ${SRC_TEST_FRONTEND_SLACK}) - endif() - set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) - - - target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES}) + if(CPPUNIT_FOUND) + file(GLOB SRC_TEST *.cpp slack/*.cpp) + file(GLOB SRC_TEST_FRONTEND_XMPP ../../spectrum/src/frontends/xmpp/*.cpp) + if(ENABLE_SLACK_FRONTEND) + file(GLOB SRC_TEST_FRONTEND_SLACK ../../spectrum/src/frontends/slack/*.cpp) + endif() + add_executable(libtransport_test ${SRC_TEST} ${SRC_TEST_FRONTEND_XMPP} ${SRC_TEST_FRONTEND_SLACK}) + set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) + target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES} JsonCpp::JsonCpp) endif() From a1ac7398681ccba74ebc463beb067297fede0c18 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 17 Jun 2026 18:58:40 +0300 Subject: [PATCH 4/7] Add slack/ include directory for test compilation --- tests/libtransport/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/libtransport/CMakeLists.txt b/tests/libtransport/CMakeLists.txt index 249b02e8f..c02c999c8 100644 --- a/tests/libtransport/CMakeLists.txt +++ b/tests/libtransport/CMakeLists.txt @@ -23,6 +23,7 @@ include_directories(../../spectrum/src/frontends/slack/) endif() if(CPPUNIT_FOUND) + include_directories(slack) file(GLOB SRC_TEST *.cpp slack/*.cpp) file(GLOB SRC_TEST_FRONTEND_XMPP ../../spectrum/src/frontends/xmpp/*.cpp) if(ENABLE_SLACK_FRONTEND) From 7cdbe3cf34a40c49cad3f6a029b3ab44718bd2d1 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 18 Jun 2026 00:15:17 +0300 Subject: [PATCH 5/7] Remove Swiften dependency from backend plugins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace Swiften networking (Swift::Connection, BoostNetworkFactories, SimpleEventLoop) with Boost.Asio in backend plugins via new BoostNetworkPlugin class. Create transport-protocol library for shared wire protocol and utilities used by both frontend and backend. Key changes: - protocol/: new transport-protocol library — wire protocol, Config, Util, MemoryUsage, Logging - plugin/cpp/BoostNetworkPlugin: Boost.Asio TCP + deadline_timer replaces Swift::Connection + Swift::Timer - Backend plugins link transport-plugin instead of transport - Storage backends stay in libtransport — plugins access via protocol - smstools3: refactored to use protocol-based routing (std::map) instead of direct StorageBackend access - HTTPRequest, HTTPRequestQueue, ThreadPool remain in libtransport - Add ENABLE_SLACK_FRONTEND CMake option (default OFF), enable in CI - Unity build fix: rename duplicate logger in NetworkPluginServer - Various cleanup: dead includes, override keywords, indentation Co-Authored-By: Claude --- .github/workflows/main.yml | 8 +- CMakeLists.txt | 1 + Dockerfile | 6 +- backends/frotz/CMakeLists.txt | 2 +- backends/smstools3/CMakeLists.txt | 2 +- backends/smstools3/main.cpp | 86 ++++---------- backends/template/plugin.cpp | 2 - backends/template/plugin.h | 2 - include/transport/BoostNetworkPlugin.h | 4 +- include/transport/CMakeLists.txt | 2 +- include/transport/Config.h | 2 +- include/transport/HTTPRequest.h | 87 ++++++++++---- include/transport/HTTPRequestQueue.h | 40 +++++++ include/transport/Logging.h | 10 +- include/transport/MemoryUsage.h | 2 +- include/transport/NetworkPlugin.h | 2 +- include/transport/ThreadPool.h | 6 +- include/transport/Util.h | 12 +- libtransport/CMakeLists.txt | 101 ++++++++-------- {plugin/cpp => libtransport}/HTTPRequest.cpp | 109 +++++++++++++++-- libtransport/HTTPRequestQueue.cpp | 64 ++++++++++ {plugin/cpp => libtransport}/MySQLBackend.cpp | 0 libtransport/NetworkPluginServer.cpp | 112 +++++++++--------- libtransport/OAuth2.cpp | 17 ++- {plugin/cpp => libtransport}/PQXXBackend.cpp | 0 .../cpp => libtransport}/SQLite3Backend.cpp | 0 .../cpp => libtransport}/StorageBackend.cpp | 0 {plugin/cpp => libtransport}/ThreadPool.cpp | 6 +- plugin/cpp/BoostNetworkPlugin.cpp | 14 +-- plugin/cpp/CMakeLists.txt | 14 +-- plugin/cpp/networkplugin.cpp | 2 +- protocol/CMakeLists.txt | 31 +++++ {plugin/cpp => protocol}/Config.cpp | 0 {plugin/cpp => protocol}/Logging.cpp | 0 {plugin/cpp => protocol}/MemoryUsage.cpp | 0 {plugin/cpp => protocol}/Util.cpp | 0 tests/libtransport/CMakeLists.txt | 60 +++++----- tests/libtransport/HTTPRequest.cpp | 45 +++++-- 38 files changed, 544 insertions(+), 307 deletions(-) create mode 100644 include/transport/HTTPRequestQueue.h rename {plugin/cpp => libtransport}/HTTPRequest.cpp (50%) create mode 100644 libtransport/HTTPRequestQueue.cpp rename {plugin/cpp => libtransport}/MySQLBackend.cpp (100%) rename {plugin/cpp => libtransport}/PQXXBackend.cpp (100%) rename {plugin/cpp => libtransport}/SQLite3Backend.cpp (100%) rename {plugin/cpp => libtransport}/StorageBackend.cpp (100%) rename {plugin/cpp => libtransport}/ThreadPool.cpp (92%) create mode 100644 protocol/CMakeLists.txt rename {plugin/cpp => protocol}/Config.cpp (100%) rename {plugin/cpp => protocol}/Logging.cpp (100%) rename {plugin/cpp => protocol}/MemoryUsage.cpp (100%) rename {plugin/cpp => protocol}/Util.cpp (100%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a57212183..4d470452a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -115,15 +115,15 @@ jobs: run: | set CMAKE_PREFIX_PATH=%cd%\deps32 set PATH=%PATH%;%cd%\deps32\bin;%cd%\deps32\tools\bin - cmake -G "Visual Studio 17 2022" -A Win32 -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_IRC=OFF -DENABLE_FROTZ=OFF -DENABLE_PURPLE=OFF -DENABLE_MYSQL=OFF -DENABLE_PQXX=OFF -DCMAKE_INSTALL_PREFIX=dist -DCMAKE_CXX_STANDARD=17 . + cmake -G "Visual Studio 17 2022" -A Win32 -DCMAKE_UNITY_BUILD=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_IRC=OFF -DENABLE_FROTZ=OFF -DENABLE_PURPLE=OFF -DENABLE_MYSQL=OFF -DENABLE_PQXX=OFF -DENABLE_SLACK_FRONTEND=ON -DCMAKE_INSTALL_PREFIX=dist -DCMAKE_CXX_STANDARD=17 . shell: cmd - name: Build solution - run: msbuild /t:Build INSTALL.vcxproj /p:Configuration=RelWithDebInfo /p:Platform=Win32 /m + run: cmake --build . --config RelWithDebInfo --target install -- /m - name: Run tests shell: cmd run: | - set PATH=%PATH%;%cd%\deps32\bin - cd tests\libtransport\RelWithDebInfo + set PATH=%PATH%;%cd%\deps32\bin;%cd%\dist\bin + cd dist\bin libtransport_test linux-debian: diff --git a/CMakeLists.txt b/CMakeLists.txt index 391ebc46a..ca8ae2a0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -385,6 +385,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) include_directories(${OPENSSL_INCLUDE_DIR}) endif() +add_subdirectory(protocol) add_subdirectory(libtransport) add_subdirectory(plugin) add_subdirectory(include) diff --git a/Dockerfile b/Dockerfile index dd743aa2b..d3cee2195 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,7 +30,7 @@ ARG APT_LISTCHANGES_FRONTEND=none WORKDIR /spectrum2 -RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_QT4=OFF -DCMAKE_UNITY_BUILD=ON . && make -j4 +RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_QT4=OFF -DENABLE_SLACK_FRONTEND=ON -DCMAKE_UNITY_BUILD=ON . && make -j4 ENTRYPOINT ["make", "extended_test"] @@ -48,7 +48,7 @@ RUN apt-get install --no-install-recommends -y libcppunit-dev clang-13 lld-13 WORKDIR /spectrum2 -RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_QT4=OFF -DCMAKE_UNITY_BUILD=ON -DCMAKE_C_COMPILER=/usr/bin/clang-13 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-13 -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld . && make -j4 +RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_QT4=OFF -DENABLE_SLACK_FRONTEND=ON -DCMAKE_UNITY_BUILD=ON -DCMAKE_C_COMPILER=/usr/bin/clang-13 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-13 -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld -DCMAKE_SHARED_LINKER_FLAGS=-fuse-ld=lld . && make -j4 ENTRYPOINT ["make", "test"] @@ -58,7 +58,7 @@ COPY . /spectrum2/ WORKDIR /spectrum2 -RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_QT4=OFF -DENABLE_WEBUI=OFF -DCMAKE_UNITY_BUILD=ON . && make -j4 +RUN cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_TESTS=ON -DENABLE_QT4=OFF -DENABLE_WEBUI=OFF -DENABLE_SLACK_FRONTEND=ON -DCMAKE_UNITY_BUILD=ON . && make -j4 ENTRYPOINT ["make", "test"] diff --git a/backends/frotz/CMakeLists.txt b/backends/frotz/CMakeLists.txt index 0a66d5954..4cae00fd4 100644 --- a/backends/frotz/CMakeLists.txt +++ b/backends/frotz/CMakeLists.txt @@ -5,6 +5,6 @@ file(GLOB SRC *.c *.cpp) add_executable(spectrum2_frotz_backend ${SRC}) target_compile_features(spectrum2_frotz_backend PUBLIC cxx_std_11) -target_link_libraries(spectrum2_frotz_backend transport ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_frotz_backend transport-plugin ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES}) install(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) diff --git a/backends/smstools3/CMakeLists.txt b/backends/smstools3/CMakeLists.txt index 4e57a9fb7..f833dfa54 100644 --- a/backends/smstools3/CMakeLists.txt +++ b/backends/smstools3/CMakeLists.txt @@ -3,6 +3,6 @@ file(GLOB SRC *.c *.cpp) add_executable(spectrum2_smstools3_backend ${SRC}) target_compile_features(spectrum2_smstools3_backend PUBLIC cxx_std_11) -target_link_libraries(spectrum2_smstools3_backend transport ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_smstools3_backend transport-plugin ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES}) install(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 6fe52bc96..a20a0f9c2 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -11,10 +11,6 @@ #include "transport/Config.h" #include "transport/Logging.h" #include "transport/BoostNetworkPlugin.h" -#include "transport/SQLite3Backend.h" -#include "transport/MySQLBackend.h" -#include "transport/PQXXBackend.h" -#include "transport/StorageBackend.h" #include #include "unistd.h" #include "signal.h" @@ -22,11 +18,11 @@ #include "sys/signal.h" #include #include +#include #include #include -using namespace boost::asio::ip; using namespace boost::filesystem; using namespace boost::program_options; @@ -34,35 +30,20 @@ using namespace Transport; DEFINE_LOGGER(logger, "SMSNetworkPlugin"); -#define INTERNAL_USER "/sms@backend@internal@user" - class SMSNetworkPlugin; SMSNetworkPlugin * np = NULL; class SMSNetworkPlugin : public BoostNetworkPlugin { public: - int m_internalUser; std::shared_ptr m_timer; - StorageBackend *storageBackend; + // Maps phone number -> XMPP user JID for SMS routing + std::map m_numberToUser; - SMSNetworkPlugin(Config *config, StorageBackend *storagebackend, const std::string &host, int port) + SMSNetworkPlugin(Config *config, const std::string &host, int port) : BoostNetworkPlugin(config, host, port) { - this->storageBackend = storagebackend; m_timer = std::make_shared(io_context, boost::posix_time::seconds(5)); m_timer->async_wait(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); - - // We're reusing our database model here. Buddies of user with JID INTERNAL_USER are there - // to match received GSM messages from number N with the XMPP users who sent message to number N. - // BuddyName = GSM number - // Alias = XMPP user JID to which the messages from this number is sent to. - // TODO: This should be per Modem!!! - UserInfo info; - info.jid = INTERNAL_USER; - info.password = ""; - storageBackend->setUser(info); - storageBackend->getUser(INTERNAL_USER, info); - m_internalUser = info.id; } @@ -91,18 +72,11 @@ class SMSNetworkPlugin : public BoostNetworkPlugin { str = str.substr(str.find("\n") + 1); } - std::list roster; - storageBackend->getBuddies(m_internalUser, roster); - - std::string to; - BOOST_FOREACH(BuddyInfo &b, roster) { - if (b.legacyName == from) { - to = b.alias; - } - } + std::string to = m_numberToUser[from]; if (to.empty()) { LOG4CXX_WARN(logger, "Received SMS from " << from << ", but this number is not associated with any XMPP user."); + return; } LOG4CXX_INFO(logger, "Forwarding SMS from " << from << " to " << to << "."); @@ -133,7 +107,6 @@ class SMSNetworkPlugin : public BoostNetworkPlugin { } void sendSMS(const std::string &to, const std::string &msg) { - // TODO: Probably std::string data = "To: " + to + "\n"; data += "\n"; data += msg; @@ -151,17 +124,14 @@ class SMSNetworkPlugin : public BoostNetworkPlugin { } void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password, const std::map &settings) { - UserInfo info; - if (!storageBackend->getUser(user, info)) { - handleDisconnected(user, 0, "Not registered user."); - return; - } - std::list roster; - storageBackend->getBuddies(info.id, roster); + LOG4CXX_INFO(logger, "User " << user << " logged in"); - // Send available presence to every number in the roster. - BOOST_FOREACH(BuddyInfo &b, roster) { - handleBuddyChanged(user, b.legacyName, b.alias, b.groups, pbnetwork::STATUS_ONLINE); + // Send available presence for all numbers that route to this user + for (std::map::iterator it = m_numberToUser.begin(); it != m_numberToUser.end(); ++it) { + if (it->second == user) { + std::vector groups; + handleBuddyChanged(user, it->first, it->second, groups, pbnetwork::STATUS_ONLINE); + } } np->handleConnected(user); @@ -177,14 +147,8 @@ class SMSNetworkPlugin : public BoostNetworkPlugin { n = n.substr(1); } - // Create GSM Number - XMPP user pair to match the potential response and send it to the proper JID. - BuddyInfo info; - info.legacyName = n; - info.alias = user; - info.id = -1; - info.subscription = "both"; - info.flags = 0; - storageBackend->addBuddy(m_internalUser, info); + // Store routing info: phone number -> XMPP user + m_numberToUser[n] = user; LOG4CXX_INFO(logger, "Sending SMS from " << user << " to " << n << "."); sendSMS(n, message); @@ -198,11 +162,15 @@ class SMSNetworkPlugin : public BoostNetworkPlugin { void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << "."); + // Restore routing info: buddyName = phone number, alias contains user JID info + if (!alias.empty()) { + m_numberToUser[buddyName] = alias; + } handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); } void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { - + m_numberToUser.erase(buddyName); } }; @@ -241,19 +209,7 @@ int main (int argc, char* argv[]) { Logging::initBackendLogging(cfg); - StorageBackend *storageBackend = StorageBackend::createBackend(cfg, error); - if (storageBackend == NULL) { - if (!error.empty()) { - std::cerr << error << "\n"; - return -2; - } - } - else if (!storageBackend->connect()) { - std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; - return -1; - } - - np = new SMSNetworkPlugin(cfg, storageBackend, host, port); + np = new SMSNetworkPlugin(cfg, host, port); np->run(); return 0; diff --git a/backends/template/plugin.cpp b/backends/template/plugin.cpp index 23e1279a7..32643ed08 100644 --- a/backends/template/plugin.cpp +++ b/backends/template/plugin.cpp @@ -6,8 +6,6 @@ // Boost #include -#include -using namespace boost::asio::ip; using namespace boost::program_options; using namespace Transport; diff --git a/backends/template/plugin.h b/backends/template/plugin.h index fe15a79c4..aa9c6c66e 100644 --- a/backends/template/plugin.h +++ b/backends/template/plugin.h @@ -2,8 +2,6 @@ #include -#include - #include "transport/Config.h" #include "transport/BoostNetworkPlugin.h" diff --git a/include/transport/BoostNetworkPlugin.h b/include/transport/BoostNetworkPlugin.h index 45c50b84f..2f5cffa51 100644 --- a/include/transport/BoostNetworkPlugin.h +++ b/include/transport/BoostNetworkPlugin.h @@ -32,8 +32,8 @@ namespace Transport { class BoostNetworkPlugin: public NetworkPlugin { public: BoostNetworkPlugin(Config *config, const std::string &host, int port); - void sendData(const std::string &string); - void handleExitRequest(); + void sendData(const std::string &string) override; + void handleExitRequest() override; void run(); protected: Transport::Config *config; diff --git a/include/transport/CMakeLists.txt b/include/transport/CMakeLists.txt index c94113080..66119e8f3 100644 --- a/include/transport/CMakeLists.txt +++ b/include/transport/CMakeLists.txt @@ -1,7 +1,7 @@ if(PROTOBUF_FOUND) add_custom_command( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/protocol.pb.cc ${CMAKE_CURRENT_SOURCE_DIR}/protocol.pb.h - COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_SOURCE_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/protocol.proto + COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_SOURCE_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR} --cpp_opt=dllexport_decl=TRANSPORT_API ${CMAKE_CURRENT_SOURCE_DIR}/protocol.proto COMMENT "Running C++ protocol buffer compiler on protocol.proto" DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol.proto ) diff --git a/include/transport/Config.h b/include/transport/Config.h index e5bd3d096..b03fd1b87 100644 --- a/include/transport/Config.h +++ b/include/transport/Config.h @@ -65,7 +65,7 @@ typedef boost::program_options::variables_map Variables; /// properly. Config files are text files which use "ini" format. Variables are divided into multiple /// sections. Every class is configurable with some variables which change its behavior. Check particular /// class documentation to get a list of all relevant variables for that class. -class Config { +class TRANSPORT_API Config { public: typedef std::map SectionValuesCont; typedef std::map UnregisteredCont; diff --git a/include/transport/HTTPRequest.h b/include/transport/HTTPRequest.h index ca12b78d4..ea3fd6473 100644 --- a/include/transport/HTTPRequest.h +++ b/include/transport/HTTPRequest.h @@ -1,36 +1,73 @@ -#ifndef HTTPREQ_H -#define HTTPREQ_H -#include "curl/curl.h" +#pragma once + +#include +#include #include "transport/Logging.h" +#include "transport/ThreadPool.h" #include +#include #include +#include -class HTTPRequest -{ - CURL *curlhandle; - char curl_errorbuffer[1024]; - std::string error; - std::string callbackdata; - - static int curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest *obj); +namespace Transport { +class HTTPRequest : public Thread { public: - HTTPRequest() { - curlhandle = NULL; - } - - ~HTTPRequest() { - if(curlhandle) { - curl_easy_cleanup(curlhandle); - curlhandle = NULL; + typedef enum { Get } Type; + typedef boost::function< void (HTTPRequest *, bool, Json::Value &json, const std::string &data) > Callback; + + HTTPRequest(ThreadPool *tp, Type type, const std::string &url, Callback callback); + HTTPRequest(Type type, const std::string &url); + + virtual ~HTTPRequest(); + + void setProxy(std::string, std::string, std::string, std::string); + bool execute(); + bool execute(Json::Value &json); + std::string getError() {return std::string(curl_errorbuffer);} + const std::string &getRawData() { + return m_data; + } + + void run(); + void finalize(); + + const std::string &getURL() { + return m_url; + } + + boost::signals2::signal onRequestFinished; + + static void globalInit() { + curl_global_init(CURL_GLOBAL_ALL); } - } - bool init(); - void setProxy(std::string, std::string, std::string, std::string); - bool GET(std::string, std::string &); - std::string getCurlError() {return std::string(curl_errorbuffer);} + static void globalCleanup() { + curl_global_cleanup(); + } + + private: + bool init(); + bool GET(std::string url, std::string &output); + bool GET(std::string url, Json::Value &json); + + + CURL *curlhandle; + char curl_errorbuffer[1024]; + std::string error; + std::string callbackdata; + ThreadPool *m_tp; + std::string m_url; + bool m_ok; + Json::Value m_json; + std::string m_data; + Callback m_callback; + Type m_type; + + static int curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest *obj); + }; -#endif +} + diff --git a/include/transport/HTTPRequestQueue.h b/include/transport/HTTPRequestQueue.h new file mode 100644 index 000000000..32475cfa1 --- /dev/null +++ b/include/transport/HTTPRequestQueue.h @@ -0,0 +1,40 @@ + +#pragma once + +#include "curl/curl.h" +#include "transport/Logging.h" +#include "transport/ThreadPool.h" +#include +#include +#include + +#include "Swiften/Network/Timer.h" + +namespace Transport { + +class HTTPRequest; +class Component; + +class HTTPRequestQueue { + public: + HTTPRequestQueue(Component *component, const std::string &user, int delayBetweenRequests = 1); + + virtual ~HTTPRequestQueue(); + + void queueRequest(HTTPRequest *req); + + void sendNextRequest(); + + private: + void handleRequestFinished(); + + private: + int m_delay; + std::queue m_queue; + HTTPRequest *m_req; + Swift::Timer::ref m_queueTimer; + std::string m_user; +}; + +} + diff --git a/include/transport/Logging.h b/include/transport/Logging.h index 42d23d3ad..4ad88f7ba 100644 --- a/include/transport/Logging.h +++ b/include/transport/Logging.h @@ -56,11 +56,11 @@ class Config; namespace Logging { -void initBackendLogging(Config *config); -void initMainLogging(Config *config); -void initManagerLogging(Config *config); -void shutdownLogging(); -void redirect_stderr(); +TRANSPORT_API void initBackendLogging(Config *config); +TRANSPORT_API void initMainLogging(Config *config); +TRANSPORT_API void initManagerLogging(Config *config); +TRANSPORT_API void shutdownLogging(); +TRANSPORT_API void redirect_stderr(); } diff --git a/include/transport/MemoryUsage.h b/include/transport/MemoryUsage.h index 605dd1570..0c2630ff1 100644 --- a/include/transport/MemoryUsage.h +++ b/include/transport/MemoryUsage.h @@ -29,5 +29,5 @@ #endif namespace Transport { - void process_mem_usage(double& shared, double& resident_set, pid_t pid = 0); + TRANSPORT_API void process_mem_usage(double& shared, double& resident_set, pid_t pid = 0); } diff --git a/include/transport/NetworkPlugin.h b/include/transport/NetworkPlugin.h index 2df1120d6..78159ad2e 100644 --- a/include/transport/NetworkPlugin.h +++ b/include/transport/NetworkPlugin.h @@ -263,7 +263,7 @@ class NetworkPlugin { virtual void handleExitRequest() { exit(1); } void handleDataRead(std::string &data); - virtual void sendData(const std::string &string) {}; + virtual void sendData(const std::string &string) {} void checkPing(); diff --git a/include/transport/ThreadPool.h b/include/transport/ThreadPool.h index a45aeab47..87939c2b0 100644 --- a/include/transport/ThreadPool.h +++ b/include/transport/ThreadPool.h @@ -1,12 +1,12 @@ #pragma once -#include #include #include #include #include #include #include +#include "Swiften/EventLoop/EventLoop.h" namespace Transport { @@ -55,12 +55,12 @@ class ThreadPool boost::mutex count_lock; boost::mutex pool_lock; boost::mutex criticalregion; - boost::asio::io_context *loop; + Swift::EventLoop *loop; boost::signals2::signal < void () > onWorkerAvailable; public: - ThreadPool(const boost::asio::io_context &loop, int maxthreads); + ThreadPool(Swift::EventLoop *loop, int maxthreads); ~ThreadPool(); void runAsThread(Thread *t); int getActiveThreadCount(); diff --git a/include/transport/Util.h b/include/transport/Util.h index 73715de0c..ef7bb58e7 100644 --- a/include/transport/Util.h +++ b/include/transport/Util.h @@ -34,17 +34,17 @@ class Config; namespace Util { -void createDirectories(Transport::Config *config, const boost::filesystem::path& ph); +TRANSPORT_API void createDirectories(Transport::Config *config, const boost::filesystem::path& ph); -void removeEverythingOlderThan(const std::vector &dirs, time_t t); +TRANSPORT_API void removeEverythingOlderThan(const std::vector &dirs, time_t t); -int getRandomPort(const std::string &s); +TRANSPORT_API int getRandomPort(const std::string &s); -std::string char2hex( char dec ); -std::string urlencode( const std::string &c ); +TRANSPORT_API std::string char2hex( char dec ); +TRANSPORT_API std::string urlencode( const std::string &c ); #ifdef _WIN32 - std::wstring utf8ToUtf16(const std::string& str); + TRANSPORT_API std::wstring utf8ToUtf16(const std::string& str); #endif } diff --git a/libtransport/CMakeLists.txt b/libtransport/CMakeLists.txt index 3915a3ef8..cebb5e051 100644 --- a/libtransport/CMakeLists.txt +++ b/libtransport/CMakeLists.txt @@ -1,64 +1,67 @@ -file(GLOB SRC *.cpp *.h) -file(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp) + file(GLOB SRC *.cpp *.h) + file(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp) -# Build without openssl on msvc -if(NOT MSVC) - if(APPLE) - string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") - string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + # Build without openssl on msvc + if(NOT MSVC) + if(APPLE) + string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + else() + string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + endif() else() - string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") - string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") endif() -else() - string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") - string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") -endif() -file(GLOB HEADERS ../include/transport/*.h) -include_directories(../spectrum/src/frontends/xmpp/) + file(GLOB HEADERS ../include/transport/*.h) + include_directories(../spectrum/src/frontends/xmpp/) -if(NOT WIN32) - include_directories(${POPT_INCLUDE_DIR}) -endif() + if(NOT WIN32) + include_directories(${POPT_INCLUDE_DIR}) + endif() -#source_group(headers FILES ${HEADERS}) + #source_group(headers FILES ${HEADERS}) -if(PROTOBUF_FOUND) - if(NOT WIN32) + if(PROTOBUF_FOUND) + if(NOT WIN32) + add_library(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC}) + else() + add_library(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC}) + endif() + add_dependencies(transport pb) + else(PROTOBUF_FOUND) add_library(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC}) - else() - add_library(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC}) - endif() -# set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) - add_dependencies(transport pb) -else(PROTOBUF_FOUND) - add_library(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC}) -endif(PROTOBUF_FOUND) + endif(PROTOBUF_FOUND) -# if(CMAKE_COMPILER_IS_GNUCXX) - if(NOT WIN32) - add_definitions(-fPIC) - endif() -# endif() + # if(CMAKE_COMPILER_IS_GNUCXX) + if(NOT WIN32) + add_definitions(-fPIC) + endif() + # endif() -find_package(CURL) + find_package(CURL) -target_link_libraries(transport transport-plugin ${CURL_LIBRARIES} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY} ${PROTOBUF_LIBRARY} JsonCpp::JsonCpp) -target_compile_features(transport PUBLIC cxx_std_11) + target_link_libraries(transport transport-protocol ${CURL_LIBRARIES} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY} ${PROTOBUF_LIBRARY} JsonCpp::JsonCpp) -if(PQXX_FOUND) - target_link_libraries(transport ${PQXX_LIBRARIES} ${PQ_LIBRARY}) -endif() + if(WIN32) + target_link_libraries(transport psapi.lib bcrypt.lib) + endif() + target_compile_features(transport PUBLIC cxx_std_11) -set_target_properties(transport PROPERTIES - VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} -) -if(APPLE) - target_link_libraries(transport ${APPLE_FRAMEWORKS}) -endif() + if(PQXX_FOUND) + target_link_libraries(transport ${PQXX_LIBRARIES} ${PQ_LIBRARY}) + endif() + + set_target_properties(transport PROPERTIES + VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} + ) + if(APPLE) + target_link_libraries(transport ${APPLE_FRAMEWORKS}) + endif() -install(TARGETS transport LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) + install(TARGETS transport LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) -#configure_file(transport.pc.in "${CMAKE_CURRENT_BINARY_DIR}/transport.pc") -#install(FILES "${CMAKE_CURRENT_BINARY_DIR}/transport.pc" DESTINATION lib/pkgconfig) + #configure_file(transport.pc.in "${CMAKE_CURRENT_BINARY_DIR}/transport.pc") + #install(FILES "${CMAKE_CURRENT_BINARY_DIR}/transport.pc" DESTINATION lib/pkgconfig) diff --git a/plugin/cpp/HTTPRequest.cpp b/libtransport/HTTPRequest.cpp similarity index 50% rename from plugin/cpp/HTTPRequest.cpp rename to libtransport/HTTPRequest.cpp index 33efef15f..a3bcdb819 100644 --- a/plugin/cpp/HTTPRequest.cpp +++ b/libtransport/HTTPRequest.cpp @@ -1,22 +1,50 @@ #include "transport/HTTPRequest.h" + +namespace Transport { + DEFINE_LOGGER(httpRequestLogger, "HTTPRequest") -bool HTTPRequest::init() -{ +HTTPRequest::HTTPRequest(ThreadPool *tp, Type type, const std::string &url, Callback callback) { + m_type = type; + m_url = url; + m_tp = tp; + m_callback = callback; + curlhandle = NULL; +} + +HTTPRequest::HTTPRequest(Type type, const std::string &url) { + m_type = type; + m_url = url; + m_tp = NULL; + curlhandle = NULL; +} + +HTTPRequest::~HTTPRequest() { + if (curlhandle) { + LOG4CXX_INFO(httpRequestLogger, "Cleaning up CURL handle"); + curl_easy_cleanup(curlhandle); + curlhandle = NULL; + } +} + +bool HTTPRequest::init() { + if (curlhandle) { + return true; + } + curlhandle = curl_easy_init(); if (curlhandle) { - curlhandle = curl_easy_init(); curl_easy_setopt(curlhandle, CURLOPT_PROXY, NULL); curl_easy_setopt(curlhandle, CURLOPT_PROXYUSERPWD, NULL); curl_easy_setopt(curlhandle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); return true; } + LOG4CXX_ERROR(httpRequestLogger, "Couldn't Initialize curl!"); return false; } -void HTTPRequest::setProxy(std::string IP, std::string port, std::string username, std::string password) -{ +void HTTPRequest::setProxy(std::string IP, std::string port, std::string username, std::string password) { if (curlhandle) { std::string proxyIpPort = IP + ":" + port; curl_easy_setopt(curlhandle, CURLOPT_PROXY, proxyIpPort.c_str()); @@ -29,19 +57,17 @@ void HTTPRequest::setProxy(std::string IP, std::string port, std::string usernam } } -int HTTPRequest::curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest* obj) -{ +int HTTPRequest::curlCallBack(char* data, size_t size, size_t nmemb, HTTPRequest* obj) { int writtenSize = 0; if (obj && data) { obj->callbackdata.append(data, size*nmemb); writtenSize = (int)(size*nmemb); } + return writtenSize; } - -bool HTTPRequest::GET(std::string url, std::string &data) -{ +bool HTTPRequest::GET(std::string url, std::string &data) { if (curlhandle) { curl_easy_setopt(curlhandle, CURLOPT_CUSTOMREQUEST, NULL); curl_easy_setopt(curlhandle, CURLOPT_ENCODING, ""); @@ -56,7 +82,7 @@ bool HTTPRequest::GET(std::string url, std::string &data) /* Set http request and url */ curl_easy_setopt(curlhandle, CURLOPT_HTTPGET, 1); -// curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1); + curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 0); curl_easy_setopt(curlhandle, CURLOPT_URL, url.c_str()); /* Send http request and return status*/ @@ -68,5 +94,66 @@ bool HTTPRequest::GET(std::string url, std::string &data) LOG4CXX_ERROR(httpRequestLogger, "CURL not initialized!"); strcpy(curl_errorbuffer, "CURL not initialized!"); } + LOG4CXX_ERROR(httpRequestLogger, "Error fetching " << url); return false; } + +bool HTTPRequest::GET(std::string url, Json::Value &json) { + if (!GET(url, m_data)) { + return false; + } + + Json::CharReaderBuilder rbuilder; + std::shared_ptr const reader(rbuilder.newCharReader()); + if (!reader->parse(m_data.c_str(), m_data.c_str() + m_data.size(), &json, NULL)) { + LOG4CXX_ERROR(httpRequestLogger, "Error while parsing JSON"); + LOG4CXX_ERROR(httpRequestLogger, m_data); + strcpy(curl_errorbuffer, "Error while parsing JSON"); + return false; + } + + return true; +} + +void HTTPRequest::run() { + if (!init()) { + m_ok = false; + return; + } + + switch (m_type) { + case Get: + m_ok = GET(m_url, m_json); + break; + } + + curl_easy_cleanup(curlhandle); + curlhandle = NULL; +} + +void HTTPRequest::finalize() { + m_callback(this, m_ok, m_json, m_data); + onRequestFinished(); +} + +bool HTTPRequest::execute() { + if (!m_tp) { + return false; + } + + m_tp->runAsThread(this); + return true; +} + +bool HTTPRequest::execute(Json::Value &json) { + init(); + switch (m_type) { + case Get: + m_ok = GET(m_url, json); + break; + } + + return m_ok; +} + +} diff --git a/libtransport/HTTPRequestQueue.cpp b/libtransport/HTTPRequestQueue.cpp new file mode 100644 index 000000000..de298806a --- /dev/null +++ b/libtransport/HTTPRequestQueue.cpp @@ -0,0 +1,64 @@ +#include "transport/HTTPRequestQueue.h" +#include "transport/HTTPRequest.h" +#include "transport/Transport.h" + +namespace Transport { + +DEFINE_LOGGER(httpRequestQueueLogger, "HTTPRequestQueue") + +HTTPRequestQueue::HTTPRequestQueue(Component *component, const std::string &user, int delay) { + m_delay = delay; + m_req = NULL; + m_user = user; + + m_queueTimer = component->getNetworkFactories()->getTimerFactory()->createTimer(500); + m_queueTimer->onTick.connect(boost::bind(&HTTPRequestQueue::sendNextRequest, this)); +} + +HTTPRequestQueue::~HTTPRequestQueue() { + m_queueTimer->stop(); + + if (m_req) { + m_req->onRequestFinished.disconnect(boost::bind(&HTTPRequestQueue::handleRequestFinished, this)); + } +} + +void HTTPRequestQueue::handleRequestFinished() { + m_req = NULL; + m_queueTimer->start(); +} + +void HTTPRequestQueue::sendNextRequest() { + if (m_queue.empty()) { + LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": Queue is empty."); + m_req = NULL; + m_queueTimer->stop(); + return; + } + + if (m_req) { + LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": There is already a request being handled."); + return; + } + + m_req = m_queue.front(); + m_queue.pop(); + + LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": Starting request '" << m_req->getURL() << "'."); + m_req->onRequestFinished.connect(boost::bind(&HTTPRequestQueue::handleRequestFinished, this)); + m_req->execute(); +} + +void HTTPRequestQueue::queueRequest(HTTPRequest *req) { + m_queue.push(req); + + if (!m_req) { + sendNextRequest(); + } + else { + LOG4CXX_INFO(httpRequestQueueLogger, m_user << ": Request '" << req->getURL() << "' queued."); + } +} + + +} diff --git a/plugin/cpp/MySQLBackend.cpp b/libtransport/MySQLBackend.cpp similarity index 100% rename from plugin/cpp/MySQLBackend.cpp rename to libtransport/MySQLBackend.cpp diff --git a/libtransport/NetworkPluginServer.cpp b/libtransport/NetworkPluginServer.cpp index e11cca7cc..846163dfc 100644 --- a/libtransport/NetworkPluginServer.cpp +++ b/libtransport/NetworkPluginServer.cpp @@ -73,7 +73,7 @@ namespace Transport { static unsigned long backend_id; static unsigned long bytestream_id; -DEFINE_LOGGER(logger, "NetworkPluginServer"); +DEFINE_LOGGER(networkPluginServerLogger, "NetworkPluginServer"); static NetworkPluginServer *_server; @@ -146,7 +146,7 @@ static unsigned long exec_(const std::string& exePath, const char *host, const c if (cmdlineArgs) fullCmdLine << " " << cmdlineArgs; - LOG4CXX_INFO(logger, "Starting new backend " << fullCmdLine.str()); + LOG4CXX_INFO(networkPluginServerLogger, "Starting new backend " << fullCmdLine.str()); // We must provide a non-const buffer to CreateProcess below std::vector rawCommandLineArgs( fullCmdLine.str().size() + 1 ); @@ -171,14 +171,14 @@ static unsigned long exec_(const std::string& exePath, const char *host, const c &pi ) ) { - LOG4CXX_ERROR(logger, "Could not start process"); + LOG4CXX_ERROR(networkPluginServerLogger, "Could not start process"); } return 0; #else // Add host and port. finalExePath += std::string(" --host ") + host + " --port " + port + " --service.backend_id=" + log_id + " " + cmdlineArgs; - LOG4CXX_INFO(logger, "Starting new backend " << finalExePath); + LOG4CXX_INFO(networkPluginServerLogger, "Starting new backend " << finalExePath); // Create array of char * from string using -lpopt library char *p = (char *) malloc(finalExePath.size() + 1); @@ -204,7 +204,7 @@ static unsigned long exec_(const std::string& exePath, const char *host, const c } exit(0); } else if ( pid < 0 ) { - LOG4CXX_ERROR(logger, "Fork failed"); + LOG4CXX_ERROR(networkPluginServerLogger, "Fork failed"); } free(p); @@ -223,11 +223,11 @@ static void SigCatcher(int n) { _server->handlePIDTerminated((unsigned long)result); if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { -// LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status)); +// LOG4CXX_ERROR(networkPluginServerLogger, "Backend can not be started, exit_code=" << WEXITSTATUS(status)); } } else { -// LOG4CXX_ERROR(logger, "Backend can not be started"); +// LOG4CXX_ERROR(networkPluginServerLogger, "Backend can not be started"); } } } @@ -311,7 +311,7 @@ NetworkPluginServer::~NetworkPluginServer() { #endif for (std::list::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) { - LOG4CXX_INFO(logger, "Stopping backend " << *it); + LOG4CXX_INFO(networkPluginServerLogger, "Stopping backend " << *it); std::string message; pbnetwork::WrapperMessage wrap; wrap.set_type(pbnetwork::WrapperMessage_Type_TYPE_EXIT); @@ -334,12 +334,12 @@ NetworkPluginServer::~NetworkPluginServer() { void NetworkPluginServer::start() { m_server->start(); - LOG4CXX_INFO(logger, "Listening on host " << CONFIG_STRING(m_config, "service.backend_host") << " port " << CONFIG_STRING(m_config, "service.backend_port")); + LOG4CXX_INFO(networkPluginServerLogger, "Listening on host " << CONFIG_STRING(m_config, "service.backend_host") << " port " << CONFIG_STRING(m_config, "service.backend_port")); while (true) { unsigned long pid = exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), "1", m_config->getCommandLineArgs().c_str()); - LOG4CXX_INFO(logger, "Tried to spawn first backend with pid " << pid); - LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); + LOG4CXX_INFO(networkPluginServerLogger, "Tried to spawn first backend with pid " << pid); + LOG4CXX_INFO(networkPluginServerLogger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); #ifndef _WIN32 // wait if the backend process will still be alive after 1 second @@ -351,21 +351,21 @@ void NetworkPluginServer::start() { if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { if (status == 254) { - LOG4CXX_ERROR(logger, "Backend can not be started, because it needs database to store data, but the database backend is not configured."); + LOG4CXX_ERROR(networkPluginServerLogger, "Backend can not be started, because it needs database to store data, but the database backend is not configured."); } else { - LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status) << ", possible error: " << strerror(WEXITSTATUS(status))); + LOG4CXX_ERROR(networkPluginServerLogger, "Backend can not be started, exit_code=" << WEXITSTATUS(status) << ", possible error: " << strerror(WEXITSTATUS(status))); if (WEXITSTATUS(status) == ENOENT) { - LOG4CXX_ERROR(logger, "This usually means the path to backend executable defined in config file as '[service] backend=\"...\"' is wrong or the executable does not exists."); + LOG4CXX_ERROR(networkPluginServerLogger, "This usually means the path to backend executable defined in config file as '[service] backend=\"...\"' is wrong or the executable does not exists."); } } - LOG4CXX_ERROR(logger, "Check backend log for more details"); + LOG4CXX_ERROR(networkPluginServerLogger, "Check backend log for more details"); continue; } } else { - LOG4CXX_ERROR(logger, "Backend can not be started"); + LOG4CXX_ERROR(networkPluginServerLogger, "Backend can not be started"); continue; } } @@ -400,7 +400,7 @@ void NetworkPluginServer::handleNewClientConnection(std::shared_ptrlongRun ? std::string(" long-running") : "") + " backend " << client << " connected. Current backend count=" << (m_clients.size() + 1)); + LOG4CXX_INFO(networkPluginServerLogger, "New" + (client->longRun ? std::string(" long-running") : "") + " backend " << client << " connected. Current backend count=" << (m_clients.size() + 1)); m_clients.push_front(client); @@ -415,7 +415,7 @@ void NetworkPluginServer::handleNewClientConnection(std::shared_ptrgetJID().toString()); + LOG4CXX_ERROR(networkPluginServerLogger, "Backend " << c << " (ID=" << c->id << ") disconnected (probably crashed) with active user " << (*it)->getJID().toString()); (*it)->setData(NULL); (*it)->handleDisconnected("Internal Server Error, please reconnect."); } @@ -457,7 +457,7 @@ void NetworkPluginServer::handleConnectedPayload(const std::string &data) { User *user = m_userManager->getUser(payload.user()); if (!user) { - LOG4CXX_ERROR(logger, "Connected payload received for unknown user " << payload.user()); + LOG4CXX_ERROR(networkPluginServerLogger, "Connected payload received for unknown user " << payload.user()); return; } @@ -643,13 +643,13 @@ void NetworkPluginServer::handleRoomChangedPayload(const std::string &data) { User *user = m_userManager->getUser(payload.username()); if (!user) { - LOG4CXX_ERROR(logger, "RoomChangePayload for unknown user " << user); + LOG4CXX_ERROR(networkPluginServerLogger, "RoomChangePayload for unknown user " << user); return; } NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.room()); if (!conv) { - LOG4CXX_ERROR(logger, "RoomChangePayload for unknown conversation " << payload.room()); + LOG4CXX_ERROR(networkPluginServerLogger, "RoomChangePayload for unknown conversation " << payload.room()); return; } @@ -658,16 +658,16 @@ void NetworkPluginServer::handleRoomChangedPayload(const std::string &data) { void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool subject) { pbnetwork::ConversationMessage payload; - LOG4CXX_TRACE(logger, "handleConvMessagePayload"); + LOG4CXX_TRACE(networkPluginServerLogger, "handleConvMessagePayload"); if (payload.ParseFromString(data) == false) { - LOG4CXX_ERROR(logger, "handleConvMessagePayload: cannot parse payload"); + LOG4CXX_ERROR(networkPluginServerLogger, "handleConvMessagePayload: cannot parse payload"); return; } User *user = m_userManager->getUser(payload.username()); if (!user) { - LOG4CXX_ERROR(logger, "handleConvMessagePayload: unknown username " << payload.username()); + LOG4CXX_ERROR(networkPluginServerLogger, "handleConvMessagePayload: unknown username " << payload.username()); return; } @@ -679,7 +679,7 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool // We can't create Conversation for payload with nickname, because this means the message is from room, // but this user is not in any room, so it's OK to just reject this message if (!conv && !payload.nickname().empty()) { - LOG4CXX_WARN(logger, "handleConvMessagePayload: No conversation with name " << payload.buddyname()); + LOG4CXX_WARN(networkPluginServerLogger, "handleConvMessagePayload: No conversation with name " << payload.buddyname()); return; } @@ -723,7 +723,7 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool } // Split the message if configured, or just preprocess - LOG4CXX_TRACE(logger, "handleConvMessagePayload: wrapping media"); + LOG4CXX_TRACE(networkPluginServerLogger, "handleConvMessagePayload: wrapping media"); typedef std::vector > MsgList; MsgList msgs = wrapIncomingMedia(msg); @@ -761,7 +761,7 @@ void NetworkPluginServer::handleConvMessageAckPayload(const std::string &data) { return; if (payload.id().empty()) { - LOG4CXX_WARN(logger, "Received message ack with empty ID, not forwarding to XMPP."); + LOG4CXX_WARN(networkPluginServerLogger, "Received message ack with empty ID, not forwarding to XMPP."); return; } @@ -829,7 +829,7 @@ void NetworkPluginServer::connectWaitingUsers() { User *u = m_waitingUsers.front(); m_waitingUsers.pop_front(); - LOG4CXX_INFO(logger, "Associating " << u->getJID().toString() << " with this backend"); + LOG4CXX_INFO(networkPluginServerLogger, "Associating " << u->getJID().toString() << " with this backend"); // associate backend with user handleUserCreated(u); @@ -905,7 +905,7 @@ void NetworkPluginServer::handleRoomListPayload(const std::string &data) { if (!payload.user().empty()) { User *user = m_userManager->getUser(payload.user()); if (!user) { - LOG4CXX_ERROR(logger, "Room list payload received for unknown user " << payload.user()); + LOG4CXX_ERROR(networkPluginServerLogger, "Room list payload received for unknown user " << payload.user()); return; } @@ -1197,7 +1197,7 @@ void NetworkPluginServer::send(std::shared_ptr &c, const std: } void NetworkPluginServer::pingTimeout() { - LOG4CXX_INFO(logger, "Sending PING to backends"); + LOG4CXX_INFO(networkPluginServerLogger, "Sending PING to backends"); // TODO: move to separate timer, those 2 loops could be expensive // Some users are connected for weeks and they are blocking backend to be destroyed and its memory // to be freed. We are finding users who are inactive for more than "idle_reconnect_time" seconds and @@ -1222,7 +1222,7 @@ void NetworkPluginServer::pingTimeout() { // Move inactive users to long-running backend. BOOST_FOREACH(User *u, usersToMove) { - LOG4CXX_INFO(logger, "Moving user " << u->getJID().toString() << " to long-running backend"); + LOG4CXX_INFO(networkPluginServerLogger, "Moving user " << u->getJID().toString() << " to long-running backend"); if (!moveToLongRunBackend(u)) break; } @@ -1244,11 +1244,11 @@ void NetworkPluginServer::pingTimeout() { sendPing((*it)); } else { - LOG4CXX_INFO(logger, "Tried to send PING to backend without pongReceived= " << (*it)->pongReceived << ": (ID=" << (*it)->id << ")"); + LOG4CXX_INFO(networkPluginServerLogger, "Tried to send PING to backend without pongReceived= " << (*it)->pongReceived << ": (ID=" << (*it)->id << ")"); } } else { - LOG4CXX_INFO(logger, "Disconnecting backend " << (*it) << " (ID=" << (*it)->id << "). PING response not received."); + LOG4CXX_INFO(networkPluginServerLogger, "Disconnecting backend " << (*it) << " (ID=" << (*it)->id << "). PING response not received."); toRemove.push_back(*it); #ifndef WIN32 @@ -1264,7 +1264,7 @@ void NetworkPluginServer::pingTimeout() { } if ((*it)->users.size() == 0) { - LOG4CXX_INFO(logger, "Disconnecting backend " << (*it) << " (ID=" << (*it)->id << "). There are no users."); + LOG4CXX_INFO(networkPluginServerLogger, "Disconnecting backend " << (*it) << " (ID=" << (*it)->id << "). There are no users."); toRemove.push_back(*it); } } @@ -1279,7 +1279,7 @@ void NetworkPluginServer::pingTimeout() { void NetworkPluginServer::collectBackend() { // Stop accepting new users to backend with the biggest memory usage. This prevents backends // which are leaking to eat whole memory by connectin new users to legacy network. - LOG4CXX_INFO(logger, "Collect backend called, finding backend which will be set to die"); + LOG4CXX_INFO(networkPluginServerLogger, "Collect backend called, finding backend which will be set to die"); unsigned long max = 0; Backend *backend = NULL; for (std::list::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) { @@ -1293,7 +1293,7 @@ void NetworkPluginServer::collectBackend() { if (m_collectTimer) { m_collectTimer->start(); } - LOG4CXX_INFO(logger, "Backend " << backend << " (ID=" << backend->id << ") is set to die"); + LOG4CXX_INFO(networkPluginServerLogger, "Backend " << backend << " (ID=" << backend->id << ") is set to die"); backend->acceptUsers = false; } } @@ -1302,13 +1302,13 @@ bool NetworkPluginServer::moveToLongRunBackend(User *user) { // Check if user has already some backend Backend *old = (Backend *) user->getData(); if (!old) { - LOG4CXX_INFO(logger, "User " << user->getJID().toString() << " does not have old backend. Not moving."); + LOG4CXX_INFO(networkPluginServerLogger, "User " << user->getJID().toString() << " does not have old backend. Not moving."); return true; } // if he's already on long run, do nothing if (old->longRun) { - LOG4CXX_INFO(logger, "User " << user->getJID().toString() << " is already on long-running backend. Not moving."); + LOG4CXX_INFO(networkPluginServerLogger, "User " << user->getJID().toString() << " is already on long-running backend. Not moving."); return true; } @@ -1316,7 +1316,7 @@ bool NetworkPluginServer::moveToLongRunBackend(User *user) { // for its connection Backend *backend = getFreeClient(false, true); if (!backend) { - LOG4CXX_INFO(logger, "No free long-running backend for user " << user->getJID().toString() << ". Will try later"); + LOG4CXX_INFO(networkPluginServerLogger, "No free long-running backend for user " << user->getJID().toString() << ". Will try later"); return false; } @@ -1342,7 +1342,7 @@ void NetworkPluginServer::handleUserCreated(User *user) { // Add user to queue if there's no free backend to handle him so far. if (!c) { - LOG4CXX_INFO(logger, "There is no backend to handle user " << user->getJID().toString() << ". Adding him to queue."); + LOG4CXX_INFO(networkPluginServerLogger, "There is no backend to handle user " << user->getJID().toString() << ". Adding him to queue."); m_waitingUsers.push_back(user); return; } @@ -1429,7 +1429,7 @@ void NetworkPluginServer::handleUserPresenceChanged(User *user, Swift::Presence: bool isInvisible = presence->getPayload() != NULL; if (isInvisible) { - LOG4CXX_INFO(logger, "This presence is invisible"); + LOG4CXX_INFO(networkPluginServerLogger, "This presence is invisible"); status.set_status((pbnetwork::STATUS_INVISIBLE)); } else { @@ -1524,7 +1524,7 @@ void NetworkPluginServer::handleUserDestroyed(User *user) { // If backend should handle only one user, it must not accept another one before // we kill it, so set up willDie to true if (c->users.size() == 0 && CONFIG_INT(m_config, "service.users_per_backend") == 1) { - LOG4CXX_INFO(logger, "Backend " << c->id << " will die, because the last user disconnected"); + LOG4CXX_INFO(networkPluginServerLogger, "Backend " << c->id << " will die, because the last user disconnected"); c->willDie = true; } } @@ -1718,7 +1718,7 @@ Swift::Message::ref copySwiftMessage(const Swift::Message* msg, const std::strin //Add new body and XHTML tags this_msg->setBody(body); this_msg->addPayload(std::make_shared(xhtml)); - LOG4CXX_TRACE(logger, "Adding partial message: '" << xhtml << "', '" << body << "'"); + LOG4CXX_TRACE(networkPluginServerLogger, "Adding partial message: '" << xhtml << "', '" << body << "'"); return this_msg; } @@ -1777,9 +1777,9 @@ NetworkPluginServer::wrapIncomingMedia(std::shared_ptr& msg) { // This is not required by XEP and we lose parts of plaintext (e.g. captions). oobMode = OobExclusive; - LOG4CXX_TRACE(logger, "wrapIncomingMedia: mode=" << (int) oobMode); - LOG4CXX_TRACE(logger, "xhtml = " << xhtml); - LOG4CXX_TRACE(logger, "body = " << body); + LOG4CXX_TRACE(networkPluginServerLogger, "wrapIncomingMedia: mode=" << (int) oobMode); + LOG4CXX_TRACE(networkPluginServerLogger, "xhtml = " << xhtml); + LOG4CXX_TRACE(networkPluginServerLogger, "body = " << body); //Find all entries @@ -1800,7 +1800,7 @@ NetworkPluginServer::wrapIncomingMedia(std::shared_ptr& msg) { const std::string& image_url = match[1]; if (firstUrl.empty()) firstUrl = image_url; - LOG4CXX_TRACE(logger, "match: image_tag=" << image_tag << ", image_url="<< image_url); + LOG4CXX_TRACE(networkPluginServerLogger, "match: image_tag=" << image_tag << ", image_url="<< image_url); //Process the part before the match if ((oobMode == OobSplit) && (match[0].first != xhtml_pos)) { @@ -1851,13 +1851,13 @@ NetworkPluginServer::wrapIncomingMedia(std::shared_ptr& msg) { result.push_back(copySwiftMessage(msg.get(), xhtml_prev, body_prev)); } - LOG4CXX_DEBUG(logger, "wrapIncomingMedia: matchCount==" << matchCount); + LOG4CXX_DEBUG(networkPluginServerLogger, "wrapIncomingMedia: matchCount==" << matchCount); if (oobMode != OobSplit) result.push_back(msg); //Push the non-split message only if (matchCount==0) { - LOG4CXX_WARN(logger, "xhtml seems to contain an image, but doesn't match: " + xhtml); + LOG4CXX_WARN(networkPluginServerLogger, "xhtml seems to contain an image, but doesn't match: " + xhtml); } else { // Replace the plaintext. // Normally it's up to the backend to provide us with matching the version. @@ -1952,7 +1952,7 @@ void NetworkPluginServer::handleBlockToggled(Buddy *b) { void NetworkPluginServer::handleVCardUpdated(User *user, std::shared_ptr v) { if (!v) { - LOG4CXX_INFO(logger, user->getJID().toString() << ": Received empty VCard"); + LOG4CXX_INFO(networkPluginServerLogger, user->getJID().toString() << ": Received empty VCard"); return; } @@ -2001,14 +2001,14 @@ void NetworkPluginServer::sendPing(Backend *c) { wrap.SerializeToString(&message); if (c->connection) { - LOG4CXX_INFO(logger, "PING to " << c << " (ID=" << c->id << ")"); + LOG4CXX_INFO(networkPluginServerLogger, "PING to " << c << " (ID=" << c->id << ")"); send(c->connection, message); c->pongReceived = false; } else { - LOG4CXX_WARN(logger, "Tried to send PING to backend without connection: " << c << " (ID=" << c->id << ")"); + LOG4CXX_WARN(networkPluginServerLogger, "Tried to send PING to backend without connection: " << c << " (ID=" << c->id << ")"); } -// LOG4CXX_INFO(logger, "PING to " << c); +// LOG4CXX_INFO(networkPluginServerLogger, "PING to " << c); } void NetworkPluginServer::sendAPIVersion(Backend *c) { @@ -2022,7 +2022,7 @@ void NetworkPluginServer::sendAPIVersion(Backend *c) { WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_API_VERSION); if (c->connection) { - LOG4CXX_INFO(logger, "API Version to " << c << " (ID=" << c->id << ")"); + LOG4CXX_INFO(networkPluginServerLogger, "API Version to " << c << " (ID=" << c->id << ")"); send(c->connection, message); } } @@ -2088,7 +2088,7 @@ NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUser m_loginTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer((diff - (now - m_lastLogin)) * 1000); m_loginTimer->onTick.connect(boost::bind(&NetworkPluginServer::loginDelayFinished, this)); m_loginTimer->start(); - LOG4CXX_INFO(logger, "Postponing login because of service.login_delay setting"); + LOG4CXX_INFO(networkPluginServerLogger, "Postponing login because of service.login_delay setting"); return NULL; } diff --git a/libtransport/OAuth2.cpp b/libtransport/OAuth2.cpp index f6b8e0c3e..bf0f0a592 100644 --- a/libtransport/OAuth2.cpp +++ b/libtransport/OAuth2.cpp @@ -33,7 +33,6 @@ #include #include #include -#include namespace Transport { @@ -82,21 +81,20 @@ std::string OAuth2::requestToken(const std::string &code, std::string &token, st url += "&redirect_uri=" + Util::urlencode(m_redirectURL); } - std::string responseData; - HTTPRequest req; - req.init(); - if (!req.GET(url, responseData)) { + Json::Value resp; + HTTPRequest req(HTTPRequest::Get, url); + if (!req.execute(resp)) { LOG4CXX_ERROR(oauth2Logger, url); - LOG4CXX_ERROR(oauth2Logger, req.getCurlError()); - return req.getCurlError(); + LOG4CXX_ERROR(oauth2Logger, req.getError()); + return req.getError(); } - LOG4CXX_ERROR(oauth2Logger, responseData); - Json::Value resp(responseData); + LOG4CXX_ERROR(oauth2Logger, req.getRawData()); Json::Value& access_token = resp["access_token"]; if (!access_token.isString()) { LOG4CXX_ERROR(oauth2Logger, "No 'access_token' object in the reply."); LOG4CXX_ERROR(oauth2Logger, url); + LOG4CXX_ERROR(oauth2Logger, req.getRawData()); return "No 'access_token' object in the reply."; } @@ -104,6 +102,7 @@ std::string OAuth2::requestToken(const std::string &code, std::string &token, st if (token.empty()) { LOG4CXX_ERROR(oauth2Logger, "Empty 'access_token' object in the reply."); LOG4CXX_ERROR(oauth2Logger, url); + LOG4CXX_ERROR(oauth2Logger, req.getRawData()); return "Empty 'access_token' object in the reply."; } diff --git a/plugin/cpp/PQXXBackend.cpp b/libtransport/PQXXBackend.cpp similarity index 100% rename from plugin/cpp/PQXXBackend.cpp rename to libtransport/PQXXBackend.cpp diff --git a/plugin/cpp/SQLite3Backend.cpp b/libtransport/SQLite3Backend.cpp similarity index 100% rename from plugin/cpp/SQLite3Backend.cpp rename to libtransport/SQLite3Backend.cpp diff --git a/plugin/cpp/StorageBackend.cpp b/libtransport/StorageBackend.cpp similarity index 100% rename from plugin/cpp/StorageBackend.cpp rename to libtransport/StorageBackend.cpp diff --git a/plugin/cpp/ThreadPool.cpp b/libtransport/ThreadPool.cpp similarity index 92% rename from plugin/cpp/ThreadPool.cpp rename to libtransport/ThreadPool.cpp index 5b7ac595c..24448442a 100644 --- a/plugin/cpp/ThreadPool.cpp +++ b/libtransport/ThreadPool.cpp @@ -1,11 +1,13 @@ #include "transport/ThreadPool.h" #include "transport/Logging.h" + namespace Transport { DEFINE_LOGGER(threadPoolLogger, "ThreadPool") -ThreadPool::ThreadPool(const boost::asio::io_context &io_context, int maxthreads) : MAX_THREADS(maxthreads) +ThreadPool::ThreadPool(Swift::EventLoop *loop, int maxthreads) : MAX_THREADS(maxthreads) { + this->loop = loop; activeThreads = 0; worker = (boost::thread **) malloc(sizeof(boost::thread *) * MAX_THREADS); for (int i=0 ; irun(); - cleandUp(t, wid); + loop->postEvent(boost::bind(&ThreadPool::cleandUp, this, t, wid), std::shared_ptr()); } } diff --git a/plugin/cpp/BoostNetworkPlugin.cpp b/plugin/cpp/BoostNetworkPlugin.cpp index ade7c6514..cd58691a2 100644 --- a/plugin/cpp/BoostNetworkPlugin.cpp +++ b/plugin/cpp/BoostNetworkPlugin.cpp @@ -37,17 +37,13 @@ BoostNetworkPlugin::BoostNetworkPlugin(Config *config, const std::string &host, if (!ec) { LOG4CXX_INFO(pluginLogger, "Connected " << ep.address().to_string()); this->is_connected = true; - NetworkPlugin::PluginConfig cfg; - cfg.setRawXML(false); - cfg.setNeedRegistration(false); - sendConfig(cfg); boost::asio::streambuf sb; - boost::system::error_code ec; + boost::system::error_code read_ec; while (is_connected && boost::asio::read(*socket_, sb, boost::asio::transfer_at_least(1), - ec)) { - if (ec) { - LOG4CXX_ERROR(pluginLogger, "Connection read error: " << ec.message()); + read_ec)) { + if (read_ec) { + LOG4CXX_ERROR(pluginLogger, "Connection read error: " << read_ec.message()); break; } else { std::string s((std::istreambuf_iterator(&sb)), @@ -70,7 +66,7 @@ void BoostNetworkPlugin::handleExitRequest() { } void BoostNetworkPlugin::run() { - boost::thread thread([&]() { io_context.run(); }); + boost::thread thread([this]() { io_context.run(); }); thread.join(); } } // namespace Transport diff --git a/plugin/cpp/CMakeLists.txt b/plugin/cpp/CMakeLists.txt index fbf234ce2..86e2be0a5 100644 --- a/plugin/cpp/CMakeLists.txt +++ b/plugin/cpp/CMakeLists.txt @@ -1,16 +1,14 @@ file(GLOB SRC *.cpp *.h) file(GLOB HEADERS ../include/transport/*.h) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) if(NOT WIN32) - add_library(transport-plugin SHARED ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ${EXTRA_SOURCES}) + add_library(transport-plugin SHARED ${HEADERS} ${SRC}) else() - add_library(transport-plugin STATIC ${HEADERS} ${SRC} ${EXTRA_SOURCES} ) + add_library(transport-plugin STATIC ${HEADERS} ${SRC} ) endif() add_dependencies(transport-plugin pb) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) target_compile_features(transport-plugin PUBLIC cxx_std_11) if(CMAKE_COMPILER_IS_GNUCXX) @@ -19,14 +17,12 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() endif() -target_link_libraries(transport-plugin JsonCpp::JsonCpp ${CMAKE_THREAD_LIBS_INIT}) - -find_package(CURL) +target_link_libraries(transport-plugin transport-protocol JsonCpp::JsonCpp ${CMAKE_THREAD_LIBS_INIT}) if(NOT WIN32) - target_link_libraries(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ${PQXX_LIBRARIES} ${CURL_LIBRARIES} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES}) + target_link_libraries(transport-plugin ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES}) else() - target_link_libraries(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ${PQXX_LIBRARIES} ${CURL_LIBRARIES} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} psapi.lib bcrypt.lib ws2_32.lib) + target_link_libraries(transport-plugin ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} ws2_32.lib) endif() set_target_properties(transport-plugin PROPERTIES VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index a4a22cb20..722d83103 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -565,7 +565,7 @@ void NetworkPlugin::handleDataRead(std::string &data) { break; default: return; - } + } } } diff --git a/protocol/CMakeLists.txt b/protocol/CMakeLists.txt new file mode 100644 index 000000000..904268a99 --- /dev/null +++ b/protocol/CMakeLists.txt @@ -0,0 +1,31 @@ +# transport-protocol: wire protocol for communication between Spectrum2 +# frontend and backend plugins, plus shared utilities (Config, Util, +# MemoryUsage). Linked by both libtransport and transport-plugin. + +file(GLOB SRC *.cpp) + +add_library(transport-protocol SHARED + ${SRC} + ${CMAKE_CURRENT_SOURCE_DIR}/../include/transport/protocol.pb.cc +) + +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) +add_dependencies(transport-protocol pb) +target_compile_features(transport-protocol PUBLIC cxx_std_11) + +if(WIN32) + target_compile_definitions(transport-protocol PRIVATE TRANSPORT_API=__declspec\(dllexport\)) + target_compile_definitions(transport-protocol INTERFACE TRANSPORT_API=__declspec\(dllimport\)) + target_link_libraries(transport-protocol psapi.lib bcrypt.lib) +else() + target_compile_definitions(transport-protocol PUBLIC TRANSPORT_API=) +endif() + +target_link_libraries(transport-protocol + ${PROTOBUF_LIBRARY} + ${Boost_LIBRARIES} + ${LOG4CXX_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} +) + +install(TARGETS transport-protocol LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) diff --git a/plugin/cpp/Config.cpp b/protocol/Config.cpp similarity index 100% rename from plugin/cpp/Config.cpp rename to protocol/Config.cpp diff --git a/plugin/cpp/Logging.cpp b/protocol/Logging.cpp similarity index 100% rename from plugin/cpp/Logging.cpp rename to protocol/Logging.cpp diff --git a/plugin/cpp/MemoryUsage.cpp b/protocol/MemoryUsage.cpp similarity index 100% rename from plugin/cpp/MemoryUsage.cpp rename to protocol/MemoryUsage.cpp diff --git a/plugin/cpp/Util.cpp b/protocol/Util.cpp similarity index 100% rename from plugin/cpp/Util.cpp rename to protocol/Util.cpp diff --git a/tests/libtransport/CMakeLists.txt b/tests/libtransport/CMakeLists.txt index c02c999c8..8664e75a8 100644 --- a/tests/libtransport/CMakeLists.txt +++ b/tests/libtransport/CMakeLists.txt @@ -1,35 +1,39 @@ - file(GLOB SRC *.cpp *.h) - file(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp) + file(GLOB SRC *.cpp *.h) + file(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp) - # Build without openssl on msvc - if(NOT MSVC) - if(APPLE) - string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") - string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + # Build without openssl on msvc + if(NOT MSVC) + if(APPLE) + string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + else() + string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + endif() else() - string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") + string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") endif() - else() - string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") - string(REGEX REPLACE "[^;]+;?/SecureTransport/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") - endif() -file(GLOB HEADERS ../../include/transport/*.h) -include_directories(../../spectrum/src/frontends/xmpp/) -if(ENABLE_SLACK_FRONTEND) -file(GLOB SRC slack/*.cpp slack/*.h) -include_directories(../../spectrum/src/frontends/slack/) -endif() + file(GLOB HEADERS ../../include/transport/*.h) + include_directories(../../spectrum/src/frontends/xmpp/) + if(ENABLE_SLACK_FRONTEND) + file(GLOB SRC slack/*.cpp slack/*.h) + include_directories(../../spectrum/src/frontends/slack/) + endif() - if(CPPUNIT_FOUND) - include_directories(slack) - file(GLOB SRC_TEST *.cpp slack/*.cpp) - file(GLOB SRC_TEST_FRONTEND_XMPP ../../spectrum/src/frontends/xmpp/*.cpp) - if(ENABLE_SLACK_FRONTEND) - file(GLOB SRC_TEST_FRONTEND_SLACK ../../spectrum/src/frontends/slack/*.cpp) + if(CPPUNIT_FOUND) + include_directories(slack ${CMAKE_CURRENT_SOURCE_DIR}) + file(GLOB SRC_TEST *.cpp) + if(ENABLE_SLACK_FRONTEND) + file(GLOB SRC_TEST_SLACK slack/*.cpp) + list(APPEND SRC_TEST ${SRC_TEST_SLACK}) + endif() + file(GLOB SRC_TEST_FRONTEND_XMPP ../../spectrum/src/frontends/xmpp/*.cpp) + if(ENABLE_SLACK_FRONTEND) + file(GLOB SRC_TEST_FRONTEND_SLACK ../../spectrum/src/frontends/slack/*.cpp) + endif() + add_executable(libtransport_test ${SRC_TEST} ${SRC_TEST_FRONTEND_XMPP} ${SRC_TEST_FRONTEND_SLACK}) + set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) + target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES} JsonCpp::JsonCpp) endif() - add_executable(libtransport_test ${SRC_TEST} ${SRC_TEST_FRONTEND_XMPP} ${SRC_TEST_FRONTEND_SLACK}) - set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) - target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES} JsonCpp::JsonCpp) - endif() diff --git a/tests/libtransport/HTTPRequest.cpp b/tests/libtransport/HTTPRequest.cpp index 0fb8ec383..9cb07b683 100644 --- a/tests/libtransport/HTTPRequest.cpp +++ b/tests/libtransport/HTTPRequest.cpp @@ -1,36 +1,61 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" #include "basictest.h" + +#include "transport/ThreadPool.h" #include "transport/HTTPRequest.h" using namespace Transport; class HTTPRequestTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE(HTTPRequestTest); - CPPUNIT_TEST(GET); + CPPUNIT_TEST(GETThreadPool); CPPUNIT_TEST_SUITE_END(); public: + ThreadPool *tp; + bool result; void setUp (void) { setMeUp(); + tp = new ThreadPool(loop, 10); + result = false; } void tearDown (void) { tearMeDown(); + delete tp; } - void GET() { - HTTPRequest req; - req.init(); - std::string responseData; - req.GET("http://spectrum.im/params.json", responseData); - Json::Value resp(responseData); - CPPUNIT_ASSERT(resp); + void handleResult(HTTPRequest *req, bool ok, Json::Value &resp, const std::string &data) { + result = true; + } + + void GETThreadPool() { + HTTPRequest *req = new HTTPRequest(tp, HTTPRequest::Get, "http://spectrum.im/params.json", boost::bind(&HTTPRequestTest::handleResult, this, _1, _2, _3, _4)); + req->execute(); + + int i = 0; + while (result == false && i < 5) { + boost::system_time time = boost::get_system_time(); + time += boost::posix_time::seconds(1); + boost::thread::sleep(time); + loop->processEvents(); + i++; + } + CPPUNIT_ASSERT(result); } + }; CPPUNIT_TEST_SUITE_REGISTRATION (HTTPRequestTest); - From 375e43e8ad3760ed867b3ca47b67a907dbd9aea5 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 18 Jun 2026 01:27:55 +0300 Subject: [PATCH 6/7] Add libtransport_test to install target for Windows CI libtransport_test needs to be in the install target so cmake --install copies it to dist/bin/ with all required DLLs (transport-protocol, transport-plugin, transport) for Windows test execution. Co-Authored-By: Claude --- tests/libtransport/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/libtransport/CMakeLists.txt b/tests/libtransport/CMakeLists.txt index 8664e75a8..f28054173 100644 --- a/tests/libtransport/CMakeLists.txt +++ b/tests/libtransport/CMakeLists.txt @@ -36,4 +36,5 @@ add_executable(libtransport_test ${SRC_TEST} ${SRC_TEST_FRONTEND_XMPP} ${SRC_TEST_FRONTEND_SLACK}) set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES} JsonCpp::JsonCpp) + install(TARGETS libtransport_test RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() From 116993693e51fe60f17ad493528f8f8f83d6e934 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Thu, 18 Jun 2026 01:33:36 +0300 Subject: [PATCH 7/7] Fix transport-protocol install: add RUNTIME destination for DLL Shared library on Windows generates a .dll (RUNTIME) and .lib (ARCHIVE). Missing RUNTIME destination meant the DLL was not copied to install prefix. Co-Authored-By: Claude --- protocol/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/CMakeLists.txt b/protocol/CMakeLists.txt index 904268a99..8313c00cd 100644 --- a/protocol/CMakeLists.txt +++ b/protocol/CMakeLists.txt @@ -28,4 +28,4 @@ target_link_libraries(transport-protocol ${CMAKE_THREAD_LIBS_INIT} ) -install(TARGETS transport-protocol LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries) +install(TARGETS transport-protocol LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})