/spring_89.0/rts/lib/lobby/Connection.cpp
# · C++ · 571 lines · 524 code · 44 blank · 3 comment · 130 complexity · a7c1d7aa0a71bb9bae3cf7f3f49793dd MD5 · raw file
- /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
- #ifdef _MSC_VER
- #include "lib/streflop/streflop_cond.h"
- #endif
- #include "Connection.h"
- #include "RawTextMessage.h"
- #include <bitset>
- #include <boost/asio.hpp>
- #include <boost/bind.hpp>
- #include "System/Net/Socket.h"
- #include "lib/md5/md5.h"
- #include "lib/md5/base64.h"
- #include "lib/streflop/streflop_cond.h"
- #if BOOST_VERSION < 103600
- using namespace boost::system::posix_error;
- #else
- using namespace boost::system::errc;
- #endif
- using namespace boost::asio;
- Connection::Connection() : sock(netservice), timer(netservice)
- {
- }
- Connection::~Connection()
- {
- if (sock.is_open()) {
- SendData("EXIT\n");
- }
- sock.shutdown(boost::asio::ip::udp::socket::shutdown_both);
- sock.close();
- netservice.poll();
- netservice.reset();
- }
- void Connection::Connect(const std::string& server, int port)
- {
- using namespace boost::asio;
- boost::system::error_code err;
- ip::address tempAddr = netcode::WrapIP(server, &err);
- if (err)
- {
- // error, maybe a hostname?
- ip::tcp::resolver resolver(netservice);
- std::ostringstream portbuf;
- portbuf << port;
- ip::tcp::resolver::query query(server, portbuf.str());
- ip::tcp::resolver::iterator iter = netcode::WrapResolve(resolver, query, &err);
- if (err)
- {
- DoneConnecting(false, err.message());
- return;
- }
- tempAddr = iter->endpoint().address();
- }
- ip::tcp::endpoint serverep(tempAddr, port);
- sock.async_connect(serverep, boost::bind(&Connection::ConnectCallback, this, placeholders::error));
- }
- void Connection::Disconnect()
- {
- if (sock.is_open()) {
- SendData("EXIT\n");
- }
- sock.close();
- Disconnected();
- }
- std::string MD5Base64(const std::string& plain)
- {
- md5_state_t state;
- md5_init(&state);
- md5_append(&state, (md5_byte_t*)plain.c_str(), plain.size());
- unsigned char digest[16];
- md5_finish(&state, digest);
- return base64_encode(digest, 16);
- }
- void Connection::Register(const std::string& name, const std::string& password)
- {
- std::ostringstream out;
- out << "REGISTER " << name << " " << MD5Base64(password) << "\n";
- SendData(out.str());
- }
- void Connection::Login(const std::string& name, const std::string& password)
- {
- std::ostringstream out;
- out << "LOGIN " << name << " " << MD5Base64(password) << " 0 localhost libLobby v0.1\n";
- SendData(out.str());
- myUserName = name;
- }
- void Connection::ConfirmAggreement()
- {
- SendData("CONFIRMAGREEMENT\n");
- }
- void Connection::Rename(const std::string& newName)
- {
- std::ostringstream out;
- out << "RENAMEACCOUNT " << newName << "\n";
- SendData(out.str());
- }
- void Connection::ChangePass(const std::string& oldpass, const std::string& newpass)
- {
- std::ostringstream out;
- out << "CHANGEPASSWORD " << MD5Base64(oldpass) << " " << MD5Base64(newpass) << "\n";
- SendData(out.str());
- }
- void Connection::StatusUpdate(bool ingame, bool away)
- {
- std::bitset<8> statusbf;
- statusbf.set(0, ingame);
- statusbf.set(1, away);
- int trank = myStatus.rank;
- if (trank >= 4)
- {
- statusbf.set(4);
- trank -= 4;
- }
- if (trank >= 2)
- {
- statusbf.set(3);
- trank -= 2;
- }
- if (trank == 1)
- {
- statusbf.set(2);
- }
- statusbf.set(5, myStatus.moderator);
- statusbf.set(6, myStatus.bot);
-
- std::ostringstream out;
- out << "MYSTATUS " << static_cast<unsigned>(statusbf.to_ulong()) << "\n";
- SendData(out.str());
- }
- void Connection::Channels()
- {
- SendData("CHANNELS\n");
- }
- void Connection::RequestMutelist(const std::string& channel)
- {
- std::ostringstream out;
- out << "MUTELIST " << channel << std::endl;
- SendData(out.str());
- }
- void Connection::JoinChannel(const std::string& channame, const std::string& password)
- {
- std::ostringstream out;
- out << "JOIN " << channame;
- if (!password.empty())
- out << " " << password;
- out << std::endl;
- SendData(out.str());
- }
- void Connection::LeaveChannel(const std::string& channame)
- {
- std::ostringstream out;
- out << "LEAVE " << channame << std::endl;
- SendData(out.str());
- }
- void Connection::KickChannelMember(const std::string& channame, const std::string& user, const std::string& reason)
- {
- std::ostringstream out;
- out << "FORCELEAVECHANNEL " << channame << " " << user;
- if (!reason.empty())
- out << " " << reason;
- out << std::endl;
- SendData(out.str());
- }
- void Connection::ChangeTopic(const std::string& channame, const std::string& topic)
- {
- std::ostringstream out;
- out << "CHANNELTOPIC " << channame << " " << topic << std::endl;
- SendData(out.str());
- }
- void Connection::Say(const std::string& channel, const std::string& text)
- {
- std::ostringstream out;
- out << "SAY " << channel << " " << text << std::endl;
- SendData(out.str());
- }
- void Connection::SayEx(const std::string& channel, const std::string& text)
- {
- std::ostringstream out;
- out << "SAYEX " << channel << " " << text << std::endl;
- SendData(out.str());
- }
- void Connection::SayPrivate(const std::string& user, const std::string& text)
- {
- std::ostringstream out;
- out << "SAYPRIVATE " << user << " " << text << std::endl;
- SendData(out.str());
- }
- void Connection::Ping()
- {
- if (sock.is_open())
- {
- SendData("PING\n");
-
- timer.expires_from_now(boost::posix_time::seconds(10));
- timer.async_wait(boost::bind(&Connection::Ping, this));
- }
- }
- void Connection::SendData(const std::string& msg)
- {
- if (sock.is_open())
- {
- sock.send(boost::asio::buffer(msg));
- }
- else
- {
- NetworkError("Already disconnected");
- }
- }
- void Connection::Poll()
- {
- netservice.poll();
- }
- void Connection::Run()
- {
- netservice.run();
- netservice.reset();
- }
- void Connection::DataReceived(const std::string& command, const std::string& msg)
- {
- if (command == "TASServer")
- {
- if (!msg.empty())
- {
- RawTextMessage buf(msg);
- std::string serverVer = buf.GetWord();
- std::string clientVer = buf.GetWord();
- int udpport = buf.GetInt();
- int mode = buf.GetInt();
- ServerGreeting(serverVer, clientVer, udpport, mode);
- }
- Ping();
- }
- else if (command == "DENIED")
- {
- LoginDenied(msg);
- }
- else if (command == "LOGININFOEND")
- {
- LoginEnd();
- }
- else if (command == "REGISTRATIONDENIED")
- {
- RegisterDenied(msg);
- }
- else if (command == "REGISTRATIONACCEPTED")
- {
- RegisterAccepted();
- }
- else if (command == "ADDUSER")
- {
- RawTextMessage buf(msg);
- std::string name = buf.GetWord();
- std::string country = buf.GetWord();
- int cpu = buf.GetInt();
- AddUser(name, country, cpu);
- }
- else if (command == "REMOVEUSER")
- {
- RawTextMessage buf(msg);
- std::string name = buf.GetWord();
- RemoveUser(name);
- }
- else if (command == "CLIENTSTATUS")
- {
- RawTextMessage buf(msg);
- std::string name = buf.GetWord();
- ClientStatus status;
- std::bitset<8> statusbf(buf.GetInt());
- status.ingame = statusbf[0];
- status.away = statusbf[1];
- status.rank = (statusbf[2]? 1 : 0) + (statusbf[3]? 2 : 0) + (statusbf[4]? 4 : 0);
- status.moderator = statusbf[5];
- status.bot = statusbf[6];
- if (name == myUserName)
- myStatus = status;
- UserStatusUpdate(name, status);
- }
- else if (command == "JOIN")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- Joined(channame);
- }
- else if (command == "JOINFAILED")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string reason = buf.GetWord();
- JoinFailed(channame, reason);
- }
- else if (command == "CLIENTS")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string client;
- while (!(client = buf.GetWord()).empty())
- {
- ChannelMember(channame, client, false);
- }
- }
- else if (command == "JOINED")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string client = buf.GetWord();
- ChannelMember(channame, client, true);
- }
- else if (command == "LEFT")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string client = buf.GetWord();
- std::string reason = buf.GetSentence();
- ChannelMemberLeft(channame, client, reason);
- }
- else if (command == "FORCELEAVECHANNEL")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string client = buf.GetWord();
- std::string reason = buf.GetSentence();
- ChannelMemberKicked(channame, client, reason);
- }
- else if (command == "CHANNELTOPIC")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string author = buf.GetWord();
- long unsigned time = buf.GetTime();
- std::string topic = buf.GetSentence();
- ChannelTopic(channame, author, time, topic);
- }
- else if (command == "CHANNELMESSAGE")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string message = buf.GetSentence();
- ChannelMessage(channame, message);
- }
- else if (command == "AGREEMENT")
- {
- aggreementbuf += msg + "\n";
- }
- else if (command == "AGREEMENTEND")
- {
- Aggreement(Connection::RTFToPlain(aggreementbuf));
- }
- else if (command == "MOTD")
- {
- Motd(msg);
- }
- else if (command == "SERVERMSG")
- {
- ServerMessage(msg);
- }
- else if (command == "CHANNEL")
- {
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- unsigned users = buf.GetInt();
- ChannelInfo(channame, users);
- }
- else if (command == "ENDOFCHANNELS")
- {
- ChannelInfoEnd();
- }
- else if (command == "MUTELISTBEGIN")
- {
- inMutelistChannel = msg;
- mutelistBuf.clear();
- }
- else if (command == "MUTELIST")
- {
- mutelistBuf.push_back(msg);
- }
- else if (command == "MUTELISTEND")
- {
- Mutelist(inMutelistChannel, mutelistBuf);
- inMutelistChannel.clear();
- mutelistBuf.clear();
- }
- else if (command == "SERVERMSGBOX")
- {
- RawTextMessage buf(msg);
- std::string message = buf.GetSentence();
- std::string url = buf.GetSentence();
- ServerMessageBox(message, url);
- }
- else if (command == "SAID")
- {
-
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string user = buf.GetWord();
- std::string text = buf.GetSentence();
- Said(channame, user, text);
- }
- else if (command == "SAIDEX")
- {
-
- RawTextMessage buf(msg);
- std::string channame = buf.GetWord();
- std::string user = buf.GetWord();
- std::string text = buf.GetSentence();
- SaidEx(channame, user, text);
- }
- else if (command == "SAIDPRIVATE")
- {
-
- RawTextMessage buf(msg);
- std::string user = buf.GetWord();
- std::string text = buf.GetSentence();
- SaidPrivate(user, text);
- }
- else if (command == "BATTLEOPENED")
- {
-
- RawTextMessage buf(msg);
- int id = buf.GetInt();
- bool replay = !buf.GetInt();
- bool nat = buf.GetInt();
- std::string founder = buf.GetWord();
- std::string ip = buf.GetWord();
- int port = buf.GetInt();
- int maxplayers = buf.GetInt();
- bool password = buf.GetInt();
- int rank = buf.GetInt();
- int maphash = buf.GetInt();
- std::string map = buf.GetSentence();
- std::string title = buf.GetSentence();
- std::string mod = buf.GetSentence();
- BattleOpened(id, replay, nat, founder, ip, port, maxplayers, password, rank, maphash, title, map, mod);
- }
- else if (command == "UPDATEBATTLEINFO")
- {
- RawTextMessage buf(msg);
- int id = buf.GetInt();
- int spectators = buf.GetInt();
- bool locked = buf.GetInt();
- int maphash = buf.GetInt();
- std::string map = buf.GetSentence();
- BattleUpdated(id, spectators, locked, maphash, map);
- }
- else if (command == "BATTLECLOSED")
- {
-
- RawTextMessage buf(msg);
- int id = buf.GetInt();
- BattleClosed(id);
- }
- else
- {
- // std::cout << "Unhandled command: " << command << " " << msg << std::endl;
- }
- }
- void Connection::ConnectCallback(const boost::system::error_code& error)
- {
- if (!error)
- {
- DoneConnecting(true, "");
- boost::asio::async_read_until(sock, incomeBuffer, "\n", boost::bind(&Connection::ReceiveCallback, this, placeholders::error, placeholders::bytes_transferred));
- }
- else
- {
- DoneConnecting(false, error.message());
- }
- }
- void Connection::ReceiveCallback(const boost::system::error_code& error, size_t bytes)
- {
- if (!error)
- {
- std::string msg;
- std::string command;
- std::istream buf(&incomeBuffer);
- buf >> command;
- std::getline(buf, msg);
- if (!msg.empty())
- msg = msg.substr(1);
- DataReceived(command, msg);
- }
- else
- {
- if (error.value() == connection_reset || error.value() == boost::asio::error::eof)
- {
- sock.close();
- Disconnected();
- }
- else if (sock.is_open()) //! ignore error messages after connect was closed
- {
- NetworkError(error.message());
- }
- }
- if (sock.is_open())
- {
- boost::asio::async_read_until(sock, incomeBuffer, "\n", boost::bind(&Connection::ReceiveCallback, this, placeholders::error, placeholders::bytes_transferred));
- }
- }
- void Connection::SendCallback(const boost::system::error_code& error)
- {
- if (!error)
- {
- }
- else
- {
- }
- }
- std::string Connection::RTFToPlain(const std::string& rich)
- {
- static const std::string screwTag = "\\pard";
- static const std::string lineend = "\\par";
- std::string out = rich.substr(rich.find_first_of('{')+1, (rich.find_last_of('}') - rich.find_first_of('{')) -2);
- out = out.substr(out.find_last_of('}')+1);
- size_t pos = 0;
- while ((pos = out.find(screwTag)) != std::string::npos)
- {
- out.erase(pos, screwTag.size());
- }
- while ((pos = out.find(lineend)) != std::string::npos)
- {
- out.replace(pos, lineend.size(), "\n");
- }
- while ((pos = out.find('\\')) != std::string::npos)
- {
- size_t pos2 = out.find_first_of("\\ \t\n}", pos+1);
- if (pos2 != std::string::npos)
- {
- out.erase(pos, pos2-pos);
- }
- else
- {
- break;
- }
- }
- return out;
- }