?? qchatserver.cpp
字號:
/*************************************************************************** * Copyright (C) 2007 by Anistratov Oleg * * ower86@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 * * as published by the Free Software Foundation; * * * * 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. * * * ***************************************************************************/#include "qchatserver.h"#include "globals.h"#include "assert.h"#include "message.h"#include "msghistory.h"QChatServer::QChatServer(QObject *parent) : QObject (parent), AbstractChatCore(), m_buffer (NULL), m_bufferSize (65535), m_welcomeMessage("Welcome to qchat"), m_nextUid(101){ m_newConnections = new QList<QChatServerSocket*>; m_buffer = (char*)malloc(m_bufferSize); assert(NULL != m_buffer); if(!m_server.listen(QHostAddress::Any, 61100)) { qWarning("[QChatServer::QChatServer]: could not start listening of incoming connections. Maybe another server is already running."); exit(1); } connect(&m_server, SIGNAL(newConnection()), this, SLOT(processNewConnections())); printf("QChat server version 0.1.1 started\n");}QChatServer::~QChatServer(){}void QChatServer::processNewConnections(){ QChatServerSocket* s; char* buf; while(m_server.hasPendingConnections()) { s = new QChatServerSocket(this, m_server.nextPendingConnection()); if(s->peerAddress() != QHostAddress("127.0.0.1") && m_bannedIPs.contains(s->peerAddress())) { delete s; return; } connect(s, SIGNAL(disconnected()), this, SLOT(processDisconnect())); connect(s, SIGNAL(newDtgrm()) , this, SLOT(processNewData())); buf = (char*)malloc(MAX_PACKET_LEN); assert(NULL != buf); m_newConnections->append(s); }}void QChatServer::processDisconnect(){ QChatServerSocket* s = qobject_cast<QChatServerSocket*>(sender()); User* usr; QString login; if(s) { usr = m_users[s]; if(usr) { login = usr->login(); foreach(QString ch, usr->channels()) { clearParametrs(); addParametr("Channel", ch.toUtf8()); // TODO fill other users data too prepareDatagram(AbstractChatCore::DISCONNECTED, Common, usr->login(), usr->info()->compName(), usr->uid(), "Disconnected"); foreach(QChatServerSocket* soc, m_users.keys()) sendData(soc, usr->uid()); } } printf("%s disconnected\n", QString("%1(%2)").arg(login).arg(s->peerAddress().toString()).toAscii().data()); qDebug("[QChatServer::processDisconnect]: %s disconnected", s->peerAddress().toString().toAscii().data()); delete m_users.take(s); }}void QChatServer::processNewData(){ User* user; int dataSize; uint uid; bool loggedIn; QString expectedLogin; char* ip_port; m_currentSocket = qobject_cast<QChatServerSocket*>(sender()); if(m_currentSocket) { ip_port = QString(m_currentSocket->peerAddress().toString() + ":%1").arg(m_currentSocket->peerPort()).toAscii().data(); qDebug("[QChatServer::processNewData]: New Data from %s", ip_port); loggedIn = m_users.contains(m_currentSocket); dataSize = m_currentSocket->readDtgrm(m_buffer, m_bufferSize); if(dataSize < 0) { qWarning("[QChatServer::processNewData](%s): error while reading from socket", ip_port); return; } if(dataSize < (int)protocolLen()) { qWarning("[QChatServer::processNewData](%s): dataSize < ProtocolLen (%d < %d). Ignoring this packet\n", ip_port, dataSize, AbstractChatCore::protocolLen()); return; } switch(packetType(m_buffer)) { case INSTRUCTION: if(m_currentSocket->peerAddress() == QHostAddress::LocalHost) processInstructions(dataSize); return; } if(!loggedIn) {// if(qstrncmp(m_buffer, programId(), programIdLen() - (protocolVersion() < 4 ? 2 : 0)))// {// qWarning("[QChatServer::processNewData](%s): [ID_ERROR!]. Ignoring this packet\n", ip_port);// return;// } if(packetType(m_buffer) != WANT_LOGIN) { qWarning("[QChatServer::processNewData](%s): Other than WANT_LOGIN packet from not logged in user. Ignoring this packet\n", ip_port); return; } expectedLogin = message(m_buffer, dataSize); setUserLogin(expectedLogin); } else// if(SrcIp(m_buffer) > 1) {// qDebug("[QChatServer::processNewData](%s): data from logged in user(uid=%d)", ip_port, srcIp(m_buffer)); QString nick = userName(m_buffer, dataSize); uint dest_uid = destIp(m_buffer); if(m_users[m_currentSocket]) uid = m_users[m_currentSocket]->uid(); user = m_users[m_currentSocket]; // sending paket only if nickname in this packet corresponds to user's login if(user->login() == nick && uid > 100) { setInputBuffer(m_buffer, dataSize); fillHeader(); QString channel_name = QString().fromUtf8(getParametr("Channel", hdr()->parametrs)); switch(hdr()->type) { case AbstractChatCore::CONNECTED : m_users[m_currentSocket]->addChannel(channel_name); break; case AbstractChatCore::DISCONNECTED : m_users[m_currentSocket]->removeChannel(channel_name); break; case AbstractChatCore::MESSAGE : addMessage(channel_name, new Message(hdr())); break; case AbstractChatCore::MSGS_HISTORY_REQUEST : if(m_channelsHistory.contains(channel_name)) msgsHistoryAnswer(channel_name, hdr()->src_ip, m_channelsHistory[channel_name]->toByteArray(getParametr("MaxMsgsHistorySize", hdr()->parametrs).toLongLong()), (AbstractChatCore::ChannelType)hdr()->chnnl_id, m_currentSocket); return; case AbstractChatCore::MSGS_NUM_REQUEST : if(m_channelsHistory.contains(channel_name)) msgsHistoryAnswer(channel_name, hdr()->src_ip, m_channelsHistory[channel_name]->toByteArray(getParametr("MaxMsgsHistorySize", hdr()->parametrs).toLongLong()), (AbstractChatCore::ChannelType)hdr()->chnnl_id, m_currentSocket); return; } setOutputBuffer(m_buffer, dataSize); // if destination user_id is empty it means msg is broadcast if(dest_uid == 0) { foreach(QChatServerSocket* s, m_users.keys()) sendData(s, uid); } else if(dest_uid == 1) { sendData(m_currentSocket, uid); } else { foreach(QChatServerSocket* s, m_users.keys()) { if(m_users[s]->uid() == dest_uid) { sendData(s, uid); break; } } } } else {// qDebug("[QChatServer::processNewData](%s): !data from logged in user(uid=%d)", ip_port, srcIp(m_buffer)); setInputBuffer(m_buffer, dataSize); fillHeader(); if(hdr()->type == AbstractChatCore::CHANGE_LOGIN) setUserLogin(nick); } } }}QString QChatServer::checkLogin(const QString & login){ if(m_bannedLogins.contains(login)) return tr("This login is banned"); foreach(User* u, m_users.values()) if(login == u->login()) return tr("This login is already in use"); return "";}int QChatServer::sendData(QChatServerSocket* socket, uint src_uid){ /* if(largeDtgrm()) { quint32 ID = m_sender->getValidID(); if(ID) { emit wantSendLargeData(header(), headerSize(), data(), dataSize(), addr, ID); setNULLdataAndHeader(); } } else */ // FIXME setPacketSize(outputBufferSize()); setSrcIp(outputBuffer(), src_uid); int bs = socket->write(outputBuffer(), outputBufferSize()); socket->flush(); qDebug("[QChatServer::sendData]: dtgrm size = %d, sent = %d\n", outputBufferSize(), bs); return bs;// quint16 size = outputBufferSize() <= MAX_PACKET_LEN ? outputBufferSize() : (MAX_PACKET_LEN); clearParametrs();}uint QChatServer::login(QChatServerSocket* socket, const QString & lgn){ User* user = new User; user->setSocket(socket); user->setLogin(lgn); user->setUid(m_nextUid++); m_users.insert(socket, user); m_newConnections->removeAll(socket);// strncpy(m_buffer, AbstractChatCore::programId(), programIdLen());// setInputBuffer(m_buffer, dataSize());// fillHeader(); user->info()->setCompName(compName(m_buffer, m_bufferSize)); return m_nextUid - 1;}void QChatServer::rejectLogin(QChatServerSocket* socket, const QString & reason){ prepareDatagram(AbstractChatCore::LOGIN_REJECTED, socket->peerAddress().toIPv4Address(), "", "", 0, reason); sendData(socket);}void QChatServer::addMessage(const QString& channel, Message* msg){ MsgHistory* history; if(!m_channelsHistory.contains(channel)) { history = new MsgHistory(); m_channelsHistory.insert(channel, history); } else history = m_channelsHistory[channel]; history->addMsg(msg);}void QChatServer::msgsHistoryAnswer(const QString & ch_name_id, quint64 dest_uid, const QByteArray & msgs, AbstractChatCore::ChannelType type, QChatServerSocket* soc){ addParametr("Channel" , ch_name_id.toUtf8()); addParametr("MsgsHistory", msgs); prepareDatagram(AbstractChatCore::MSGS_NUM_ANSWER, dest_uid, "Server", "Server", 0, "", type, 0, 0); sendData(soc);}void QChatServer::msgsNumAnswer(const QString & ch_name_id, quint64 dest_uid, QChatServerSocket* soc){ addParametr("Channel", ch_name_id.toUtf8()); addParametr("MsgsNum", QString().setNum(quint32(100)).toUtf8()); prepareDatagram(AbstractChatCore::MSGS_HISTORY_ANSWER, dest_uid, "Server", "Server", 0, "", Common, 0, 0); sendData(soc);}void QChatServer::sendInstruction(const QString & user, const QString & instruction){ prepareDatagram(INSTRUCTION, 1, user, "Server", 1, instruction, Common, 0, 0); QChatServerSocket socket;// qDebug("[QChatServer::sendKickUser]: connecting to %s:%d", addr.toString().toAscii().data(), port); socket.connectToHost(QHostAddress::LocalHost, 61100); if(socket.waitForConnected(10000)) sendData(&socket, 1);}void QChatServer::kickUser(const QString & user){ QMapIterator<QChatServerSocket*, User*> it(m_users); printf("Kicking user %s...\n", user.toLocal8Bit().data()); while(it.hasNext()) { it.next(); if(it.value()->login() == user) { // TODO send message with reason of disconnection it.key()->disconnectFromHost(); printf("%s was kicked\n", user.toLocal8Bit().data()); return; } } printf("%s was not found on this server\n", user.toLocal8Bit().data());}void QChatServer::processInstructions(int dataSize){ QString user = userName(m_buffer, dataSize); if(destIp(m_buffer) == 1 && srcIp(m_buffer) == 1 && packetType(m_buffer) == INSTRUCTION && compName(m_buffer, dataSize) == "Server") { if(message(m_buffer, dataSize) == "Kick") kickUser(user); else if(message(m_buffer, dataSize) == "Ban") banUser(user); else if(message(m_buffer, dataSize) == "Unban") unbanUser(user); if(message(m_buffer, dataSize) == "KickIp") kickIp(user); else if(message(m_buffer, dataSize) == "BanIp") banIp(user); else if(message(m_buffer, dataSize) == "UnbanIp") unbanIp(user); else if(message(m_buffer, dataSize) == "UnbanAll") m_bannedLogins.clear(); else if(message(m_buffer, dataSize) == "UnbanAllIPs") m_bannedIPs.clear(); }}void QChatServer::banUser(const QString& user){ printf("Banning user %s...\n", user.toLocal8Bit().data()); if(!m_bannedLogins.contains(user)) m_bannedLogins.append(user); kickUser(user);}void QChatServer::unbanUser(const QString& user){ printf("Unbanning user %s...\n", user.toLocal8Bit().data()); m_bannedLogins.removeAll(user);}void QChatServer::kickIp(const QString & ip){ QHostAddress addr; if(addr.setAddress(ip)) foreach(QChatServerSocket* s, m_users.keys()) if(s->peerAddress() == addr) s->disconnectFromHost();}void QChatServer::banIp(const QString & ip){ QHostAddress addr; if(addr.setAddress(ip)) { if(!m_bannedIPs.contains(addr)) m_bannedIPs.append(addr); kickIp(ip); }}void QChatServer::unbanIp(const QString & ip){ QHostAddress addr; if(addr.setAddress(ip)) m_bannedIPs.removeAll(addr);}void QChatServer::setUserLogin(const QString & expectedLogin){ QString error = checkLogin(expectedLogin); User* user = NULL; int uid = 0; if(m_users.contains(m_currentSocket)) user = m_users[m_currentSocket]; if(expectedLogin.isEmpty()) { rejectLogin(m_currentSocket, "Expected Login is empty"); return; } if(error.isEmpty()) { if(user) { user->setLogin(expectedLogin); uid = user->uid(); } else uid = login(m_currentSocket, expectedLogin); prepareDatagram(AbstractChatCore::LOGIN_ACCEPTED, uid, expectedLogin, "Server", uid, m_welcomeMessage); sendData(m_currentSocket, uid); printf("%s is logged in\n", QString("%1(%2)").arg(expectedLogin).arg(m_currentSocket->peerAddress().toString()).toAscii().data()); } else rejectLogin(m_currentSocket, error);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -