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 cf988dc55..ca8ae2a0a 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) @@ -383,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 ca408097b..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 pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${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/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..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 pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${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 52ac28235..a20a0f9c2 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -10,12 +10,7 @@ #include "transport/Config.h" #include "transport/Logging.h" -#include "transport/NetworkPlugin.h" -#include "transport/SQLite3Backend.h" -#include "transport/MySQLBackend.h" -#include "transport/PQXXBackend.h" -#include "transport/StorageBackend.h" -#include +#include "transport/BoostNetworkPlugin.h" #include #include "unistd.h" #include "signal.h" @@ -23,60 +18,32 @@ #include "sys/signal.h" #include #include - -Swift::SimpleEventLoop *loop_; +#include #include #include using namespace boost::filesystem; - using namespace boost::program_options; + using namespace Transport; DEFINE_LOGGER(logger, "SMSNetworkPlugin"); -#define INTERNAL_USER "/sms@backend@internal@user" - 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; - StorageBackend *storageBackend; - - SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, StorageBackend *storagebackend, const std::string &host, int port) : NetworkPlugin() { - this->config = config; - 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(); - - // 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; + std::shared_ptr m_timer; + // Maps phone number -> XMPP user JID for SMS routing + std::map m_numberToUser; + + SMSNetworkPlugin(Config *config, const std::string &host, int port) + : BoostNetworkPlugin(config, host, port) { + + m_timer = std::make_shared(io_context, boost::posix_time::seconds(5)); + m_timer->async_wait(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); } @@ -105,18 +72,11 @@ class SMSNetworkPlugin : public NetworkPlugin { 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 << "."); @@ -144,11 +104,9 @@ 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) { - // TODO: Probably std::string data = "To: " + to + "\n"; data += "\n"; data += msg; @@ -165,27 +123,15 @@ 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)) { - 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); @@ -201,14 +147,8 @@ class SMSNetworkPlugin : public NetworkPlugin { 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); @@ -222,17 +162,16 @@ class SMSNetworkPlugin : public NetworkPlugin { 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); } - - - private: - - Config *config; }; static void spectrum_sigchld_handler(int sig) @@ -270,22 +209,8 @@ 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; - } - - Swift::SimpleEventLoop eventLoop; - loop_ = &eventLoop; - np = new SMSNetworkPlugin(cfg, &eventLoop, storageBackend, host, port); - loop_->run(); + np = new SMSNetworkPlugin(cfg, 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..32643ed08 100644 --- a/backends/template/plugin.cpp +++ b/backends/template/plugin.cpp @@ -1,62 +1,56 @@ #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; 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..aa9c6c66e 100644 --- a/backends/template/plugin.h +++ b/backends/template/plugin.h @@ -1,16 +1,13 @@ #pragma once -#include "Swiften/Swiften.h" +#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 +18,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..2f5cffa51 --- /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) override; + void handleExitRequest() override; + 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/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/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 eecf9497d..78159ad2e 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. @@ -292,7 +288,6 @@ class NetworkPlugin { std::string m_data; bool m_pingReceived; double m_init_res; - }; } 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 5e7a8375d..cebb5e051 100644 --- a/libtransport/CMakeLists.txt +++ b/libtransport/CMakeLists.txt @@ -1,68 +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(WIN32) - target_link_libraries(transport psapi.lib bcrypt.lib) -endif() + if(WIN32) + target_link_libraries(transport psapi.lib bcrypt.lib) + endif() + target_compile_features(transport PUBLIC cxx_std_11) -if(PQXX_FOUND) - target_link_libraries(transport ${PQXX_LIBRARIES} ${PQ_LIBRARY}) -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() + 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/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/StorageBackend.cpp b/libtransport/StorageBackend.cpp index 2ee9171a3..a29afe51d 100644 --- a/libtransport/StorageBackend.cpp +++ b/libtransport/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/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..cd58691a2 --- /dev/null +++ b/plugin/cpp/BoostNetworkPlugin.cpp @@ -0,0 +1,72 @@ +/** + * 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; + boost::asio::streambuf sb; + boost::system::error_code read_ec; + while (is_connected && + boost::asio::read(*socket_, sb, boost::asio::transfer_at_least(1), + read_ec)) { + if (read_ec) { + LOG4CXX_ERROR(pluginLogger, "Connection read error: " << read_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([this]() { io_context.run(); }); + thread.join(); +} +} // namespace Transport diff --git a/plugin/cpp/CMakeLists.txt b/plugin/cpp/CMakeLists.txt index f82881cf9..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,12 +17,13 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() endif() +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}) + target_link_libraries(transport-plugin ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES}) else() - target_link_libraries(transport-plugin ${PROTOBUF_LIBRARY} ${LOG4CXX_LIBRARIES} ${Boost_LIBRARIES} 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 cc1dba244..722d83103 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); diff --git a/protocol/CMakeLists.txt b/protocol/CMakeLists.txt new file mode 100644 index 000000000..8313c00cd --- /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} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 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 99% rename from plugin/cpp/MemoryUsage.cpp rename to protocol/MemoryUsage.cpp index e5383f6ec..db92d9c9b 100644 --- a/plugin/cpp/MemoryUsage.cpp +++ b/protocol/MemoryUsage.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include 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/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..f28054173 100644 --- a/tests/libtransport/CMakeLists.txt +++ b/tests/libtransport/CMakeLists.txt @@ -1,32 +1,40 @@ - 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/) - - 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) - - target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES}) endif() + + 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) + install(TARGETS libtransport_test RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + endif() diff --git a/tests/libtransport/HTTPRequest.cpp b/tests/libtransport/HTTPRequest.cpp index 75b62a678..9cb07b683 100644 --- a/tests/libtransport/HTTPRequest.cpp +++ b/tests/libtransport/HTTPRequest.cpp @@ -41,13 +41,6 @@ class HTTPRequestTest : public CPPUNIT_NS :: TestFixture, public BasicTest { 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(); @@ -66,4 +59,3 @@ class HTTPRequestTest : public CPPUNIT_NS :: TestFixture, public BasicTest { }; CPPUNIT_TEST_SUITE_REGISTRATION (HTTPRequestTest); - diff --git a/tests/libtransport/main.cpp b/tests/libtransport/main.cpp index 847cb1340..e31b61c8f 100644 --- a/tests/libtransport/main.cpp +++ b/tests/libtransport/main.cpp @@ -9,7 +9,6 @@ #include "log4cxx/logger.h" #include "log4cxx/fileappender.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