summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Petithory <vincent.petithory@gmail.com>2014-07-06 23:32:57 +0200
committerAndrei Karas <akaras@inbox.ru>2014-07-19 18:20:39 +0300
commit3160d63c696612f460e5d0ebe1eb4dfb2bb3e5a1 (patch)
treeccb5f7bdfb2671208b82f81e14d12c7d52af9f63
parent79d20c8ca1709a73701a1ffd30c7218fb2579a50 (diff)
downloadmv-3160d63c696612f460e5d0ebe1eb4dfb2bb3e5a1.tar.gz
mv-3160d63c696612f460e5d0ebe1eb4dfb2bb3e5a1.tar.bz2
mv-3160d63c696612f460e5d0ebe1eb4dfb2bb3e5a1.tar.xz
mv-3160d63c696612f460e5d0ebe1eb4dfb2bb3e5a1.zip
Add IPC:
Manaplus now accepts connections on the 44007 port. * Uses SDL_Net/SDL_Thread. * Port can be changed with envvar IPC_PORT. * Default port is first checked then incremented until one is available. * start on demand with /ipctoggle (shuts down server socket) It has a simple text protocol: TYPE arg1 [args]... Message types: * CMD: execs a command supported by manaplus, e.g /emote * LTALK: talks in general tab * TALK: talks in current focused tab * [TODO] KEY: do as if the KEY was pressed on keyboard
-rw-r--r--src/Makefile.am2
-rw-r--r--src/commands.cpp21
-rw-r--r--src/commands.h3
-rw-r--r--src/net/ipc.cpp208
-rw-r--r--src/net/ipc.h56
5 files changed, 290 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 39780b5bd..2c45c6dcb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -616,6 +616,8 @@ manaplus_SOURCES += gui/widgets/avatarlistbox.cpp \
net/generalhandler.h \
net/guildhandler.h \
net/inventoryhandler.h \
+ net/ipc.cpp \
+ net/ipc.h \
net/ea/inventoryitem.h \
net/logindata.h \
net/loginhandler.h \
diff --git a/src/commands.cpp b/src/commands.cpp
index 94781aef5..00da06cbb 100644
--- a/src/commands.cpp
+++ b/src/commands.cpp
@@ -63,6 +63,7 @@
#include "net/download.h"
#include "net/gamehandler.h"
#include "net/guildhandler.h"
+#include "net/ipc.h"
#include "net/net.h"
#include "net/uploadcharinfo.h"
#include "net/partyhandler.h"
@@ -289,6 +290,26 @@ impHandler2(help)
helpWindow->requestMoveToTop();
}
+impHandler0(ipcToggle)
+{
+ if (ipc)
+ {
+ IPC::stop();
+ if (!ipc)
+ debugChatTab->chatLog("IPC service stopped.");
+ else
+ debugChatTab->chatLog("Unable to stop IPC service.");
+ }
+ else
+ {
+ IPC::start();
+ if (ipc)
+ debugChatTab->chatLog(strprintf("IPC service available on port %d", ipc->port()));
+ else
+ debugChatTab->chatLog("Unable to start IPC service");
+ }
+}
+
impHandler2(where)
{
std::ostringstream where;
diff --git a/src/commands.h b/src/commands.h
index f4bbf84d3..bdf4f76c4 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -53,6 +53,7 @@ namespace Commands
{
decHandler(announce);
decHandler(help);
+ decHandler(ipcToggle);
decHandler(where);
decHandler(who);
decHandler(msg);
@@ -146,6 +147,7 @@ enum
COMMAND_IGNOREALL,
COMMAND_HELP,
COMMAND_ANNOUNCE,
+ COMMAND_IPC_TOGGLE,
COMMAND_WHERE,
COMMAND_WHO,
COMMAND_MSG,
@@ -247,6 +249,7 @@ static const CommandInfo commands[] =
{"ignoreall", &Commands::ignoreAll, -1, false},
{"help", &Commands::help, -1, false},
{"announce", &Commands::announce, -1, true},
+ {"ipctoggle", &Commands::ipcToggle, -1, false},
{"where", &Commands::where, -1, false},
{"who", &Commands::who, -1, false},
{"msg", Commands::msg, -1, true},
diff --git a/src/net/ipc.cpp b/src/net/ipc.cpp
new file mode 100644
index 000000000..9625e119a
--- /dev/null
+++ b/src/net/ipc.cpp
@@ -0,0 +1,208 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2014 Vincent Petithory <vincent.petithory@gmail.com>
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * 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
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "net/ipc.h"
+
+#include "gui/widgets/tabs/chattab.h"
+#include "gui/windows/chatwindow.h"
+#include "utils/sdlhelper.h"
+#include "utils/stringutils.h"
+#include <iostream>
+
+#include "commandhandler.h"
+#include "logger.h"
+
+IPC *ipc = nullptr;
+
+const std::string IPC_TYPE_CMD = "CMD";
+const std::string IPC_TYPE_TALK = "TALK";
+const std::string IPC_TYPE_LTALK = "LTALK";
+
+IPC::IPC(unsigned short port) :
+ mListen(false),
+ mNumReqs(0),
+ mPort(port),
+ mSocket(nullptr),
+ mThread(nullptr)
+{
+}
+
+IPC::~IPC()
+{
+}
+
+bool IPC::init()
+{
+ IPaddress ip;
+
+ if(SDLNet_ResolveHost(&ip,NULL,mPort) == -1)
+ {
+ logger->log("IPC: SDLNet_ResolveHost: %s\n", SDLNet_GetError());
+ return false;
+ }
+
+ mSocket = SDLNet_TCP_Open(&ip);
+ if (!mSocket)
+ {
+ logger->log("IPC: Error in TcpNet::open(): %s", TcpNet::getError());
+ return false;
+ }
+
+ mThread = SDL::createThread(&IPC::acceptLoop, "ipc", this);
+ if (!mThread)
+ {
+ logger->log("IPC: unable to create acceptLoop thread");
+ return false;
+ }
+ return true;
+}
+
+int IPC::acceptLoop(void *ptr)
+{
+ IPC *const ipc = reinterpret_cast<IPC*>(ptr);
+ const int max_length = 1024;
+ SDLNet_SocketSet set;
+
+ set = SDLNet_AllocSocketSet(1);
+ SDLNet_TCP_AddSocket(set, ipc->mSocket);
+ ipc->mListen = true;
+ try
+ {
+ while (ipc->mListen)
+ {
+ SDLNet_CheckSockets(set, 250);
+ if (!SDLNet_SocketReady(ipc->mSocket))
+ continue;
+
+ TCPsocket sock;
+ sock = SDLNet_TCP_Accept(ipc->mSocket);
+ if (!sock)
+ {
+ logger->log("IPC: unable to accept connection");
+ continue;
+ }
+ char data[max_length] = {0};
+ int result;
+ result = SDLNet_TCP_Recv(sock, data, max_length);
+ if (result <= 0)
+ {
+ logger->log("IPC: unable to accept connection");
+ SDLNet_TCP_Close(sock);
+ continue;
+ }
+
+ // Parse input: TYPE args
+ const std::string req(data);
+ const size_t pos = req.find(' ');
+ const std::string type(req, 0, pos);
+ std::string args(req, pos == std::string::npos
+ ? req.size() : pos + 1);
+ args = trim(args);
+
+ std::string resp;
+ if (type == IPC_TYPE_CMD)
+ {
+ commandHandler->handleCommand(args, debugChatTab);
+ ipc->mNumReqs++;
+ resp = strprintf("[%s](%d) OK\n", IPC_TYPE_CMD.c_str(), ipc->mNumReqs);
+ }
+ else if (type == IPC_TYPE_LTALK)
+ {
+ chatWindow->localChatInput(args);
+ ipc->mNumReqs++;
+ resp = strprintf("[%s](%d) OK\n", IPC_TYPE_LTALK.c_str(), ipc->mNumReqs);
+ }
+ else if (type == IPC_TYPE_TALK)
+ {
+ chatWindow->chatInput(args);
+ ipc->mNumReqs++;
+ resp = strprintf("[%s](%d) OK\n", IPC_TYPE_TALK.c_str(), ipc->mNumReqs);
+ }
+ else
+ {
+ resp = type + ": no handler for this IPC type\n";
+ }
+
+ int len;
+ const char *respc;
+ respc = resp.c_str();
+ len = strlen(respc)+1;
+ result = SDLNet_TCP_Send(sock, respc, len);
+ if (result < len)
+ {
+ logger->log("IPC: SDLNet_TCP_Send: %s\n", SDLNet_GetError());
+ SDLNet_TCP_Close(sock);
+ continue;
+ }
+ SDLNet_TCP_Close(sock);
+ }
+ }
+ catch (std::exception& e)
+ {
+ std::cerr << e.what() << std::endl;
+ SDLNet_TCP_Close(ipc->mSocket);
+ return 1;
+ }
+ SDLNet_TCP_Close(ipc->mSocket);
+ return 0;
+}
+
+unsigned short IPC::port()
+{
+ return mPort;
+}
+
+void IPC::stop()
+{
+ if (!ipc)
+ return;
+
+ logger->log("Stopping IPC...");
+ ipc->mListen = false;
+ int loopRet;
+ SDL_WaitThread(ipc->mThread, &loopRet);
+ ipc = nullptr;
+}
+
+void IPC::start()
+{
+ if (ipc)
+ return;
+
+ unsigned short ipc_port(44007);
+ if (getenv("IPC_PORT"))
+ ipc_port = atoi(getenv("IPC_PORT"));
+
+ logger->log("Starting IPC...");
+ while (true)
+ {
+ logger->log(strprintf(" -> trying port %d...", ipc_port));
+ ipc = new IPC(ipc_port);
+ if (ipc->init())
+ {
+ logger->log(strprintf(" -> Port %d selected", ipc_port));
+ break;
+ }
+ else
+ {
+ ipc_port++;
+ }
+ }
+}
diff --git a/src/net/ipc.h b/src/net/ipc.h
new file mode 100644
index 000000000..28c536efb
--- /dev/null
+++ b/src/net/ipc.h
@@ -0,0 +1,56 @@
+/*
+ * The ManaPlus Client
+ * Copyright (C) 2014 Vincent Petithory <vincent.petithory@gmail.com>
+ *
+ * This file is part of The ManaPlus Client.
+ *
+ * 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
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IPC_H
+#define IPC_H
+
+#include "net/sdltcpnet.h"
+#include <SDL_thread.h>
+
+class IPC
+{
+public:
+ /**
+ * Constructor.
+ */
+ IPC(unsigned short port);
+
+ /**
+ * Destructor.
+ */
+ ~IPC();
+
+ bool init();
+ unsigned short port();
+ static int acceptLoop(void *ptr);
+ static void start();
+ static void stop();
+
+private:
+ bool mListen;
+ unsigned int mNumReqs;
+ unsigned short mPort;
+ TcpNet::Socket mSocket;
+ SDL_Thread *mThread;
+};
+
+extern IPC *ipc;
+
+#endif // IPC_H