示例#1
0
Player::Player()
    : pony{Pony(this)}
{
    connected=false;
    inGame=0;
    nReceivedDups=0;
    lastPingNumber=0;
    lastPingTime=timestampNow();
    port=0;
    IP=QString();
    receivedDatas = new QByteArray();
    for (int i=0;i<33;i++)
        udpSequenceNumbers[i]=0;
    for (int i=0;i<33;i++)
        udpRecvSequenceNumbers[i]=0;
    udpRecvMissing.clear();

    // Prepare timers
    chatRollCooldownEnd = QDateTime::currentDateTime();
    udpSendReliableTimer =  new QTimer;
    udpSendReliableTimer->setInterval(UDP_RESEND_TIMEOUT);
    udpSendReliableTimer->setSingleShot(true);
    connect(udpSendReliableTimer, SIGNAL(timeout()), this, SLOT(udpResendLast()));
    udpSendReliableGroupTimer =  new QTimer;
    udpSendReliableGroupTimer->setInterval(UDP_GROUPING_TIMEOUT);
    udpSendReliableGroupTimer->setSingleShot(true);
    connect(udpSendReliableGroupTimer, SIGNAL(timeout()), this, SLOT(udpDelayedSend()));
}
void Widget::checkPingTimeouts()
{
    //win.logMessage("CHECKING PING TIMEOUT :");
    for (int i=0;i<udpPlayers.size();i++)
    {
        //if (!udpPlayers[i].connected || !udpPlayers[i].port)
        //    continue;
        int time = (timestampNow()-udpPlayers[i]->lastPingTime);
        //win.logMessage(QString().setNum(time)+"s");
        if (time > pingTimeout)
        {
            logMessage("UDP: Ping timeout ("+QString().setNum(((int)timestampNow()-udpPlayers[i]->lastPingTime))+"s) for "
                       +QString().setNum(udpPlayers[i]->pony.netviewId)+" (player "+udpPlayers[i]->name+")");
            udpPlayers[i]->connected = false;
            sendMessage(udpPlayers[i], MsgDisconnect, "Ping timeout");
            Player::disconnectPlayerCleanup(udpPlayers[i]);
        }
    }
}
示例#3
0
void Player::resetNetwork()
{
    connected=false;
    nReceivedDups=0;
    lastPingNumber=0;
    lastPingTime=timestampNow();
    port=0;
    IP.clear();
    receivedDatas->clear();
    for (int i=0;i<33;i++)
        udpSequenceNumbers[i]=0;
    for (int i=0;i<33;i++)
        udpRecvSequenceNumbers[i]=0;
    udpRecvMissing.clear();
}
void sendMessage(Player* player,quint8 messageType, QByteArray data)
{
    QByteArray msg(3,0);
    // MessageType
    msg[0] = messageType;
    // Sequence
    msg[1] = 0;
    msg[2] = 0;
    if (messageType == MsgPing)
    {
        msg.resize(6);
        // Sequence
        msg[1] = 0;
        msg[2] = 0;
        // Payload size
        msg[3] = 8;
        msg[4] = 0;
        // Ping number
        player->lastPingNumber++;
        msg[5]=(quint8)player->lastPingNumber;
    }
    else if (messageType == MsgPong)
    {
        msg.resize(6);
        // Payload size
        msg[3] = 8*5;
        msg[4] = 0;
        // Ping number
        msg[5]=(quint8)player->lastPingNumber;
        // Timestamp
        msg += floatToData(timestampNow());
    }
    else if (messageType == MsgUserUnreliable)
    {
        msg.resize(5);
        // Sequence
        msg[1] = (quint8)(player->udpSequenceNumbers[32]&0xFF);
        msg[2] = (quint8)((player->udpSequenceNumbers[32]>>8)&0xFF);
        // Data size
        msg[3] = (quint8)((8*(data.size()))&0xFF);
        msg[4] = (quint8)(((8*(data.size())) >> 8)&0xFF);
        // Data
        msg += data;
        player->udpSequenceNumbers[32]++;

        //app.logMessage(QString("Sending sync data :")+msg.toHex());
    }
示例#5
0
void Player::reset()
{
    name.clear();
    connected=false;
    inGame=0;
    nReceivedDups=0;
    lastPingNumber=0;
    lastPingTime=timestampNow();
    port=0;
    IP.clear();
    receivedDatas->clear();
    lastValidReceivedAnimation.clear();
    pony = Pony(this);
    for (int i=0;i<33;i++)
        udpSequenceNumbers[i]=0;
    for (int i=0;i<33;i++)
        udpRecvSequenceNumbers[i]=0;
    udpRecvMissing.clear();
}
示例#6
0
void Sync::sendSyncMessage(Player* source, Player* dest)
{
    QByteArray data(2,0);
    data[0] = (quint8)(source->pony.netviewId&0xFF);
    data[1] = (quint8)((source->pony.netviewId>>8)&0xFF);
    data += floatToData(timestampNow());
    //data += rangedSingleToData(source.pony.pos.x, XMIN, XMAX, PosRSSize);
    //data += rangedSingleToData(source.pony.pos.y, YMIN, YMAX, PosRSSize);
    //data += rangedSingleToData(source.pony.pos.z, ZMIN, ZMAX, PosRSSize);
    data += floatToData(source->pony.pos.x);
    data += floatToData(source->pony.pos.y);
    data += floatToData(source->pony.pos.z);
    //data += rangedSingleToData(source.pony.rot.x, ROTMIN, ROTMAX, RotRSSize);
    data += rangedSingleToData(source->pony.rot.y, ROTMIN, ROTMAX, RotRSSize);
    //data += rangedSingleToData(source.pony.rot.z, ROTMIN, ROTMAX, RotRSSize);
    sendMessage(dest, MsgUserUnreliable, data);

    //win.logMessage("UDP: Syncing "+QString().setNum(source->pony.netviewId)+" to "+QString().setNum(dest->pony.netviewId));
}
// Processes the commands entered directly in the server, not the chat messages
void Widget::sendCmdLine()
{
    if (!enableGameServer)
    {
        logMessage(QObject::tr("This is not a game server, commands are disabled"));
        return;
    }

    QString str = ui->cmdLine->text();

    if (str == "clear")
    {
        ui->log->clear();
        return;
    }
    else if (str == "stop")
    {
        delete this;
        return;
    }
    else if (str == "listTcpPlayers")
    {
        for (int i=0; i<tcpPlayers.size(); i++)
        {
            Player* p = tcpPlayers[i];
            logMessage(p->name+" "+p->IP+":"+QString().setNum(p->port));
        }
        return;
    }
    else if (str.startsWith("setPeer"))
    {
        if (udpPlayers.size() == 1)
        {
            cmdPeer = udpPlayers[0];
            QString peerName = cmdPeer->IP + " " + QString().setNum(cmdPeer->port);
            logMessage(QObject::tr("UDP: Peer set to %1").arg(peerName));
            return;
        }

        str = str.right(str.size()-8);
        QStringList args = str.split(':');
        bool ok;
        if (args.size() != 2)
        {
            if (args.size() != 1)
            {
                logMessage(QObject::tr("UDP: setPeer takes a pony id or ip:port combination"));
                return;
            }
            quint16 id = args[0].toUInt(&ok);
            if (!ok)
            {
                logMessage(QObject::tr("UDP: setPeer takes a pony id as argument"));
                return;
            }
            for (int i=0; i<udpPlayers.size();i++)
            {
                if (udpPlayers[i]->pony.id == id)
                {
                    cmdPeer = Player::findPlayer(udpPlayers,udpPlayers[i]->IP, udpPlayers[i]->port);
                    logMessage(QObject::tr("UDP: Peer set to %1").arg(udpPlayers[i]->pony.name));
                    return;
                }
            }
            logMessage(QObject::tr("UDP: Peer not found (id %1)").arg(args[0]));
            return;
        }

        quint16 port = args[1].toUInt(&ok);
        if (!ok)
        {
            logMessage(QObject::tr("UDP: setPeer takes a port as argument"));
            return;
        }

        cmdPeer = Player::findPlayer(udpPlayers,args[0], port);
        if (cmdPeer->IP!="")
            logMessage(QObject::tr("UDP: Peer set to %1").arg(str));
        else
            logMessage(QObject::tr("UDP: Peer not found (%1)").arg(str));
        return;
    }
    else if (str.startsWith("listPeers"))
    {
        if (str.size()<=10)
        {
            for (int i=0; i<win.udpPlayers.size();i++)
                win.logMessage(QString().setNum(win.udpPlayers[i]->pony.id)
                               +" ("+QString().setNum(win.udpPlayers[i]->pony.netviewId)+")"
                               +"   "+win.udpPlayers[i]->pony.name
                               +"   "+win.udpPlayers[i]->IP
                               +":"+QString().setNum(win.udpPlayers[i]->port)
                               +"   "+QString().setNum((int)timestampNow()-win.udpPlayers[i]->lastPingTime)+"s");
            return;
        }
        str = str.right(str.size()-10);
        Scene* scene = findScene(str);
        if (scene->name.isEmpty())
            win.logMessage(QObject::tr("Can't find scene"));
        else
            for (int i=0; i<scene->players.size();i++)
                win.logMessage(win.udpPlayers[i]->IP
                               +":"+QString().setNum(win.udpPlayers[i]->port)
                               +" "+QString().setNum((int)timestampNow()-win.udpPlayers[i]->lastPingTime)+"s");
        return;
    }
    else if (str.startsWith("listVortexes"))
    {
        for (int i=0; i<scenes.size(); i++)
        {
            win.logMessage("Scene "+scenes[i].name);
            for (int j=0; j<scenes[i].vortexes.size(); j++)
                win.logMessage("Vortex "+QString().setNum(scenes[i].vortexes[j].id)
                               +" to "+scenes[i].vortexes[j].destName+" "
                               +QString().setNum(scenes[i].vortexes[j].destPos.x)+" "
                               +QString().setNum(scenes[i].vortexes[j].destPos.y)+" "
                               +QString().setNum(scenes[i].vortexes[j].destPos.z));
        }
        return;
    }
    else if (str.startsWith("sync"))
    {
        win.logMessage(QObject::tr("UDP: Syncing manually"));
        sync.doSync();
        return;
    }
    // DEBUG global commands from now on
    else if (str==("dbgStressLoad"))
    {
        // Send all the players to the GemMines at the same time
        for (int i=0; i<udpPlayers.size(); i++)
            sendLoadSceneRPC(udpPlayers[i], "GemMines");
        return;
    }
    else if (str.startsWith("dbgStressLoad"))
    {
        str = str.mid(14);
        // Send all the players to the given scene at the same time
        for (int i=0; i<udpPlayers.size(); i++)
            sendLoadSceneRPC(udpPlayers[i], str);
        return;
    }
    else if (str.startsWith("tele"))
    {
        str = str.right(str.size()-5);
        QStringList args = str.split(' ');
        if (args.size() != 2)
        {
            logStatusMessage(QObject::tr("Error: Usage is tele ponyIdToMove destinationPonyId"));
            return;
        }
        bool ok;
        bool ok1;
        bool ok2 = false;
        quint16 sourceID = args[0].toUInt(&ok);
        quint16 destID = args[1].toUInt(&ok1);
        Player* sourcePeer;
        if (!ok && !ok1)
        {
            logStatusMessage(QObject::tr("Error: Usage is tele ponyIdToMove destinationPonyId"));
            return;
        }
        for (int i=0; i<udpPlayers.size();i++)
        {
            if (udpPlayers[i]->pony.id == sourceID)
            {
                sourcePeer = udpPlayers[i];
                ok2 = true;
                break;
            }
        }
        if (!ok2)
        {
            logStatusMessage(QObject::tr("Error: Source peer does not exist!"));
            return;
        }
        for (int i=0; i<udpPlayers.size();i++)
        {
            if (udpPlayers[i]->pony.id == destID)
            {
                logMessage(QObject::tr("UDP: Teleported %1 to %2").arg(sourcePeer->pony.name,udpPlayers[i]->pony.name));
                if (udpPlayers[i]->pony.sceneName.toLower() != sourcePeer->pony.sceneName.toLower())
                    sendLoadSceneRPC(sourcePeer, udpPlayers[i]->pony.sceneName, udpPlayers[i]->pony.pos);
                else
                    sendMove(sourcePeer, udpPlayers[i]->pony.pos.x, udpPlayers[i]->pony.pos.y, udpPlayers[i]->pony.pos.z);
                return;
            }
        }
        logMessage(QObject::tr("Error: Destination peer does not exist!"));
    }
    if (cmdPeer->IP=="")
    {
        logMessage(QObject::tr("Select a peer first with setPeer/listPeers"));
        return;
    }
    else // Refresh peer info
    {
        cmdPeer = Player::findPlayer(udpPlayers,cmdPeer->IP, cmdPeer->port);
        if (cmdPeer->IP=="")
        {
            logMessage(QObject::tr("UDP: Peer not found"));
            return;
        }
    }

    // User commands from now on (requires setPeer)
    if (str.startsWith("disconnect"))
    {
        logMessage(QObject::tr("UDP: Disconnecting"));
        sendMessage(cmdPeer,MsgDisconnect, "Connection closed by the server admin");
        Player::disconnectPlayerCleanup(cmdPeer); // Save game and remove the player
    }
    else if (str.startsWith("load"))
    {
        str = str.mid(5);
        sendLoadSceneRPC(cmdPeer, str);
    }
    else if (str.startsWith("getPos"))
    {
        logMessage(QObject::tr("Pos : ","Short for position") + QString().setNum(cmdPeer->pony.pos.x)
                   + " " + QString().setNum(cmdPeer->pony.pos.y)
                   + " " + QString().setNum(cmdPeer->pony.pos.z));
    }
    else if (str.startsWith("getRot"))
    {
        logMessage(QObject::tr("Rot : x=","Short for rotation") + QString().setNum(cmdPeer->pony.rot.x)
                   + ", y=" + QString().setNum(cmdPeer->pony.rot.y)
                   + ", z=" + QString().setNum(cmdPeer->pony.rot.z)
                   + ", w=" + QString().setNum(cmdPeer->pony.rot.w));
    }
    else if (str.startsWith("getPonyData"))
    {
        logMessage("ponyData : "+cmdPeer->pony.ponyData.toBase64());
    }
    else if (str.startsWith("sendPonies"))
    {
        sendPonies(cmdPeer);
    }
    else if (str.startsWith("sendUtils3"))
    {
        logMessage(QObject::tr("UDP: Sending Utils3 request"));
        QByteArray data(1,3);
        sendMessage(cmdPeer,MsgUserReliableOrdered6,data);
    }
    else if (str.startsWith("setPlayerId"))
    {
        str = str.right(str.size()-12);
        QByteArray data(3,4);
        bool ok;
        unsigned id = str.toUInt(&ok);
        if (ok)
        {
            logMessage(QObject::tr("UDP: Sending setPlayerId request"));
            data[1]=(quint8)(id&0xFF);
            data[2]=(quint8)((id >> 8)&0xFF);
            sendMessage(cmdPeer,MsgUserReliableOrdered6,data);
        }
        else
void receiveMessage(Player* player)
{
    QByteArray msg = *(player->receivedDatas);
    int msgSize=5 + (((unsigned char)msg[3]) + (((unsigned char)msg[4]) << 8))/8;

#if UDP_SIMULATE_PACKETLOSS
    if (qrand() % 100 <= UDP_RECV_PERCENT_DROPPED)
    {
        //app.logMessage("UDP: Received packet dropped !");
        *(player->receivedDatas) = player->receivedDatas->mid(msgSize);
        if (player->receivedDatas->size())
            receiveMessage(player);
        return; // When we're done with the recursion, we still need to skip this message.
    }
    else
    {
        //app.logMessage("UDP: Received packet got through !");
    }
#endif

    // Check the sequence (seq) of the received messag
    if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32)
    {
        quint16 seq = (quint8)msg[1] + ((quint8)msg[2]<<8);
        quint8 channel = ((unsigned char)msg[0])-MsgUserReliableOrdered1;
        if (seq <= player->udpRecvSequenceNumbers[channel] && player->udpRecvSequenceNumbers[channel]!=0)
        {
            // If this is a missing packet, accept it
            MessageHead missingMsg;
            missingMsg.channel = channel;
            missingMsg.seq = seq;
            if (player->udpRecvMissing.contains(missingMsg))
            {
                logMessage(QObject::tr("UDP: Processing retransmission (-%1) from %2")
                               .arg(player->udpRecvSequenceNumbers[channel]-seq).arg(player->pony.netviewId));
                for (int i=0; i<player->udpRecvMissing.size(); i++)
                    if (player->udpRecvMissing[i] == missingMsg)
                        player->udpRecvMissing.remove(i);
            }
            else
            {
                // We already processed this packet, we should discard it
#if DEBUG_LOG
                app.logMessage("UDP: Discarding double message (-"+QString().setNum(player->udpRecvSequenceNumbers[channel]-seq)
                               +") from "+QString().setNum(player->pony.netviewId));
                app.logMessage("UDP: Message was : "+QString(player->receivedDatas->left(msgSize).toHex().data()));
#endif
                player->nReceivedDups++;
                if (player->nReceivedDups >= 100) // Kick the player if he's infinite-looping on us
                {
                    logMessage(QObject::tr("UDP: Kicking %1 : Too many packet dups").arg(player->pony.netviewId));
                    sendMessage(player,MsgDisconnect, "You were kicked for lagging the server, sorry. You can login again.");
                    Player::disconnectPlayerCleanup(player); // Save game and remove the player
                    return;
                }
                *(player->receivedDatas) = player->receivedDatas->mid(msgSize);

                // Ack if needed, so that the client knows to move on already.
                if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32) // UserReliableOrdered
                {
#if DEBUG_LOG
                    app.logMessage("UDP: ACKing discarded message");
#endif
                    QByteArray data(3,0);
                    data[0] = (quint8)(msg[0]); // ack type
                    data[1] = (quint8)(((quint8)msg[1])/2); // seq
                    data[2] = (quint8)(((quint8)msg[2])/2); // seq
                    sendMessage(player, MsgAcknowledge, data);
                }
                if (player->receivedDatas->size())
                    receiveMessage(player);
                return; // When we're done with the recursion, we still need to skip this message.
            }
        }
        else if (seq > player->udpRecvSequenceNumbers[channel]+2) // If a message was skipped, keep going.
        {
            logMessage(QObject::tr("UDP: Unordered message (+%1) received from %2")
                           .arg(seq-player->udpRecvSequenceNumbers[channel]).arg(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;

            // Mark the packets we skipped as missing
            for (int i=player->udpRecvSequenceNumbers[channel]+2; i<seq; i+=2)
            {
                MessageHead missing;
                missing.channel = channel;
                missing.seq = i;
                player->udpRecvMissing.append(missing);
            }
        }
        else
        {
            if (player->nReceivedDups > 0) // If he stopped sending dups, forgive him slowly.
                player->nReceivedDups--;
            //app.logMessage("UDP: Received message (="+QString().setNum(seq)
            //               +") from "+QString().setNum(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;
        }
    }

    // Process the received message
    if ((unsigned char)msg[0] == MsgPing) // Ping
    {
        //app.logMessage("UDP: Ping received from "+player->IP+":"+QString().setNum(player->port)
        //        +" ("+QString().setNum((timestampNow() - player->lastPingTime))+"s)");
        player->lastPingNumber = (quint8)msg[5];
        player->lastPingTime = timestampNow();
        sendMessage(player,MsgPong);
    }
    else if ((unsigned char)msg[0] == MsgPong) // Pong
    {
#if DEBUG_LOG
        //app.logMessage("UDP: Pong received");
#endif
    }
    else if ((unsigned char)msg[0] == MsgConnect) // Connect SYN
    {
        msg.resize(18); // Supprime le message LocalHail et le Timestamp
        msg = msg.right(13); // Supprime le Header
#if DEBUG_LOG
        app.logMessage(QString("UDP: Connecting ..."));
#endif

        for (int i=0; i<32; i++) // Reset sequence counters
            player->udpSequenceNumbers[i]=0;

        if (!player->connected)
            sendMessage(player, MsgConnectResponse, msg);
    }
    else if ((unsigned char)msg[0] == MsgConnectionEstablished) // Connect ACK
    {
        if (player->connected)
            logMessage(QObject::tr("UDP: Received duplicate connect ACK"));
        else
        {
            logMessage(QObject::tr("UDP: Connected to client"));
            player->connected=true;
            for (int i=0; i<32; i++) // Reset sequence counters
                player->udpSequenceNumbers[i]=0;
            onConnectAckReceived(player); // Clean the reliable message queue from SYN|ACKs

            // Start game
    #if DEBUG_LOG
            logMessage(QString("UDP: Starting game"));
    #endif
            // Set player id
            SceneEntity::lastIdMutex.lock();
            player->pony.id = SceneEntity::getNewId();
            player->pony.netviewId = SceneEntity::getNewNetviewId();
            SceneEntity::lastIdMutex.unlock();
            logMessage(QObject::tr("UDP: Set id request : %1/%2").arg(player->pony.id).arg(player->pony.netviewId));
            QByteArray id(3,0); // Set player Id request
            id[0]=4;
            id[1]=(quint8)(player->pony.id&0xFF);
            id[2]=(quint8)((player->pony.id>>8)&0xFF);
            sendMessage(player,MsgUserReliableOrdered6,id);

            // Load characters screen request
            QByteArray data(1,5);
            data += stringToData("characters");
            sendMessage(player,MsgUserReliableOrdered6,data);
        }
    }
    else if ((unsigned char)msg[0] == MsgAcknowledge) // Acknowledge
示例#9
0
void Widget::tcpProcessData(QByteArray data, QTcpSocket* socket)
{
    // Login request (forwarded)
    if (useRemoteLogin && tcpReceivedDatas->contains("commfunction=login&") && tcpReceivedDatas->contains("&version="))
    {
        logMessage("TCP: Remote login not implemented yet.");
        // We need to add the client with his IP/port/passhash to tcpPlayers if he isn't already there
        Player newPlayer;
        newPlayer.IP = socket->peerAddress().toIPv4Address();
        newPlayer.port = socket->peerPort();
        QString passhash = QString(*tcpReceivedDatas);
        passhash = passhash.mid(passhash.indexOf("passhash=")+9);
        passhash.truncate(passhash.indexOf('&'));
        newPlayer.passhash = passhash;
        logMessage("IP:"+newPlayer.IP+", passhash:"+newPlayer.passhash);

        // Then connect to the remote and forward the client's requests
        if (!remoteLoginSock.isOpen())
        {
            remoteLoginSock.connectToHost(remoteLoginIP, remoteLoginPort);
            remoteLoginSock.waitForConnected(remoteLoginTimeout);
            if (!remoteLoginSock.isOpen())
            {
                win.logMessage("TCP: Can't connect to remote login server : timed out.");
                return;
            }
        }
        // We just blindly send everything that we're going to remove from tcpReceivedDatas at the end of tcpProcessData
        QByteArray toSend = *tcpReceivedDatas;
        toSend.left(toSend.indexOf(data) + data.size());
        remoteLoginSock.write(toSend);
    }
    else if (useRemoteLogin && tcpReceivedDatas->contains("Server:")) // Login reply (forwarded)
    {
        logMessage("TCP: Remote login not implemented yet.");
        // First we need to find a player matching the received passhash in tcpPlayers
        // Use the player's IP/port to find a matching socket in tcpClientsList
        // The login headers are all the same, so we can just use loginHeader.bin and send back data
    }
    else if (tcpReceivedDatas->contains("commfunction=login&") && tcpReceivedDatas->contains("&version=")) // Login request
    {
        QString postData = QString(*tcpReceivedDatas);
        *tcpReceivedDatas = tcpReceivedDatas->right(postData.size()-postData.indexOf("version=")-8-4); // 4 : size of version number (ie:version=1344)
        logMessage("TCP: Login request received :");
        QFile file(QString(NETDATAPATH)+"/loginHeader.bin");
        QFile fileServersList(SERVERSLISTFILEPATH);
        QFile fileBadPassword(QString(NETDATAPATH)+"/loginWrongPassword.bin");
        QFile fileAlready(QString(NETDATAPATH)+"/loginAlreadyConnected.bin");
        QFile fileMaxRegistration(QString(NETDATAPATH)+"/loginMaxRegistered.bin");
        QFile fileMaxConnected(QString(NETDATAPATH)+"/loginMaxConnected.bin");
        if (!file.open(QIODevice::ReadOnly) || !fileBadPassword.open(QIODevice::ReadOnly)
        || !fileAlready.open(QIODevice::ReadOnly) || !fileMaxRegistration.open(QIODevice::ReadOnly)
        || !fileMaxConnected.open(QIODevice::ReadOnly) || !fileServersList.open(QIODevice::ReadOnly))
        {
            logStatusMessage("Error reading login data files");
            stopServer();
        }
        else
        {
            bool ok=true;
            postData = postData.right(postData.size()-postData.indexOf("username="******"passhash=")-9);
            QString passhash = postData;
            passhash.truncate(postData.indexOf('&'));
            logMessage(QString("IP : ")+socket->peerAddress().toString());
            logMessage(QString("Username : "******"Passhash : ")+passhash);

            // Add player to the players list
            Player* player = Player::findPlayer(tcpPlayers, username);
            if (player->name != username) // Not found, create a new player
            {
                // Check max registered number
                if (tcpPlayers.size() >= maxRegistered)
                {
                    logMessage("TCP: Registration failed, too many players registered");
                    socket->write(fileMaxRegistration.readAll());
                    ok = false;
                }
                else
                {
                    logMessage("TCP: Creating user "+username+" in database");
                    Player* newPlayer = new Player;
                    newPlayer->name = username;
                    newPlayer->passhash = passhash;
                    newPlayer->IP = socket->peerAddress().toString();
                    newPlayer->connected = false; // The connection checks are done by the game servers

                    tcpPlayers << newPlayer;
                    if (!Player::savePlayers(tcpPlayers))
                        ok = false;
                }
            }
            else // Found, compare passhashes, check if already connected
            {
                if (player->passhash != passhash) // Bad password
                {
                    logMessage("TCP: Login failed, wrong password");
                    socket->write(fileBadPassword.readAll());
                    ok=false;
                }
                /*
                else if (newPlayer.connected) // Already connected
                {
                    logMessage("TCP: Login failed, player already connected");
                    socket->write(fileAlready.readAll());
                    ok=false;
                }
                */
                else // Good password
                {
                    /*
                    // Check too many connected
                    int n=0;
                    for (int i=0;i<tcpPlayers.size();i++)
                        if (tcpPlayers[i].connected)
                            n++;
                    if (n>=maxConnected)
                    {
                        logMessage("TCP: Login failed, too much players connected");
                        socket->write(fileMaxConnected.readAll());
                        ok=false;
                    }
                    else
                    */
                    {
                        //player->reset();
                        player->IP = socket->peerAddress().toString();
                        player->lastPingTime = timestampNow();
                        player->connected = true;
                    }
                }
            }

            if (ok) // Send servers list
            {
                QByteArray customData = file.readAll();

                QByteArray data1 = QByteArray::fromHex("0D0A61757468726573706F6E73653A0A747275650A");
                QByteArray sesskey = QCryptographicHash::hash(QString(passhash + saltPassword).toLatin1(), QCryptographicHash::Md5).toHex();
                sesskey += passhash;
                QByteArray data2 = QByteArray::fromHex("0A310A");
                QByteArray serversList;
                QByteArray line;
                do {
                    line = fileServersList.readLine().trimmed();
                    serversList+=line;
                    serversList+=0x0A;
                } while (!line.isEmpty());
                serversList = serversList.trimmed();
                QByteArray data3 = QByteArray::fromHex("0D0A300D0A0D0A");
                int dataSize = data1.size() + sesskey.size() + data2.size() + serversList.size() - 2;
                QString dataSizeStr = QString().setNum(dataSize, 16);

                customData += dataSizeStr;
                customData += data1;
                customData += sesskey;
                customData += data2;
                customData += serversList;
                customData += data3;

                logMessage("TCP: Login successful, sending servers list");
                socket->write(customData);
                socket->close();
            }
        }
    }
    else if (data.contains("commfunction=removesession"))
    {
        logMessage("TCP: Session closed by client");
    }
    else // Unknown request, erase tcp buffer
    {
        // Display data
        logMessage("TCP: Unknown request received : ");
        logMessage(QString(data.data()));
    }
}
void receiveMessage(Player* player)
{
    QByteArray msg = *(player->receivedDatas);
    int msgSize=5 + (((unsigned char)msg[3]) + (((unsigned char)msg[4]) << 8))/8;

    // Check the sequence (seq) of the received message
    if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32)
    {
        quint16 seq = (quint8)msg[1] + ((quint8)msg[2]<<8);
        quint8 channel = ((unsigned char)msg[0])-MsgUserReliableOrdered1;
        if (seq <= player->udpRecvSequenceNumbers[channel] && player->udpRecvSequenceNumbers[channel]!=0)
        {
            // If this is a missing packet, accept it
            MessageHead missingMsg;
            missingMsg.channel = channel;
            missingMsg.seq = seq;
            if (player->udpRecvMissing.contains(missingMsg))
            {
                win.logMessage("UDP: Processing retransmission (-"+QString().setNum(player->udpRecvSequenceNumbers[channel]-seq)
                               +") from "+QString().setNum(player->pony.netviewId));
                for (int i=0; i<player->udpRecvMissing.size(); i++)
                    if (player->udpRecvMissing[i] == missingMsg)
                        player->udpRecvMissing.remove(i);
            }
            else
            {
                // We already processed this packet, we should discard it
                win.logMessage("UDP: Discarding double message (-"+QString().setNum(player->udpRecvSequenceNumbers[channel]-seq)
                               +") from "+QString().setNum(player->pony.netviewId));
                //win.logMessage("UDP: Message was : "+QString(player->receivedDatas->left(msgSize).toHex().data()));
                player->nReceivedDups++;
                if (player->nReceivedDups >= 100) // Kick the player if he's infinite-looping on us
                {
                    win.logMessage(QString("UDP: Kicking "+QString().setNum(player->pony.netviewId)+" : Too many packet dups."));
                    sendMessage(player,MsgDisconnect, "You were kicked for lagging the server, sorry. You can login again.");
                    Player::disconnectPlayerCleanup(player); // Save game and remove the player
                    return;
                }
                *(player->receivedDatas) = player->receivedDatas->mid(msgSize);

                // Ack if needed, so that the client knows to move on already.
                if ((unsigned char)msg[0] >= MsgUserReliableOrdered1 && (unsigned char)msg[0] <= MsgUserReliableOrdered32) // UserReliableOrdered
                {
                    //win.logMessage("UDP: ACKing discarded message");
                    QByteArray data(3,0);
                    data[0] = (quint8)msg[0]; // ack type
                    data[1] = ((quint8)msg[1])/2; // seq
                    data[2] = ((quint8)msg[2])/2; // seq
                    sendMessage(player, MsgAcknowledge, data);
                }
                if (player->receivedDatas->size())
                    receiveMessage(player);
                return; // When we're done with the recursion, we still need to skip this message.
            }
        }
        else if (seq > player->udpRecvSequenceNumbers[channel]+2) // If a message was skipped, keep going.
        {
            win.logMessage("UDP: Unordered message (+"+QString().setNum(seq-player->udpRecvSequenceNumbers[channel])
                           +") received from "+QString().setNum(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;

            // Mark the packets we skipped as missing
            for (int i=player->udpRecvSequenceNumbers[channel]+2; i<seq; i+=2)
            {
                MessageHead missing;
                missing.channel = channel;
                missing.seq = i;
                player->udpRecvMissing.append(missing);
            }
        }
        else
        {
            if (player->nReceivedDups > 0) // If he stopped sending dups, forgive him slowly.
                player->nReceivedDups--;
            //win.logMessage("UDP: Received message (="+QString().setNum(seq)
            //               +") from "+QString().setNum(player->pony.netviewId));
            player->udpRecvSequenceNumbers[channel] = seq;
        }
    }

    // Process the received message
    if ((unsigned char)msg[0] == MsgPing) // Ping
    {
        //win.logMessage("UDP: Ping received from "+player->IP+":"+QString().setNum(player->port)
        //        +" ("+QString().setNum((timestampNow() - player->lastPingTime))+"s)");
        player->lastPingNumber = (quint8)msg[5];
        player->lastPingTime = timestampNow();
        sendMessage(player,MsgPong);
    }
    else if ((unsigned char)msg[0] == MsgPong) // Pong
    {
        win.logMessage("UDP: Pong received");
    }
    else if ((unsigned char)msg[0] == MsgConnect) // Connect SYN
    {
        msg.resize(18); // Supprime le message LocalHail et le Timestamp
        msg = msg.right(13); // Supprime le Header

        win.logMessage(QString("UDP: Connecting ..."));

        for (int i=0; i<32; i++) // Reset sequence counters
            player->udpSequenceNumbers[i]=0;

        sendMessage(player, MsgConnectResponse, msg);
    }
    else if ((unsigned char)msg[0] == MsgConnectionEstablished) // Connect ACK
    {
        win.logMessage("UDP: Connected to client");
        player->connected=true;
        for (int i=0; i<32; i++) // Reset sequence counters
            player->udpSequenceNumbers[i]=0;

        // Start game
        win.logMessage(QString("UDP: Starting game"));

        // Set local player id
        win.lastId++;
        win.lastNetviewId++;
        player->pony.id = win.lastId;
        player->pony.netviewId = win.lastNetviewId;

        win.logMessage("UDP: Set id request : " + QString().setNum(player->pony.id) + "/" + QString().setNum(player->pony.netviewId));

        // Set player Id request
        QByteArray id(3,0);
        id[0]=4;
        id[1]=player->pony.id;
        id[2]=player->pony.id>>8;
        sendMessage(player,MsgUserReliableOrdered6,id); // Sends a 48

        // Load Characters screen requets
        QByteArray data(1,5);
        data += stringToData("Characters");
        sendMessage(player,MsgUserReliableOrdered6,data); // Sends a 48
    }
示例#11
0
void Widget::tcpProcessData(QByteArray data, QTcpSocket* socket)
{
    if (tcpReceivedDatas->contains("commfunction=login&") && tcpReceivedDatas->contains("&version=")) // Login request
    {
        QString postData = QString(*tcpReceivedDatas);
        *tcpReceivedDatas = tcpReceivedDatas->right(postData.size()-postData.indexOf("version=")-8-4); // 4 : size of version number (ie:version=1344)
        logMessage("TCP: Login request received :");
        QFile file(QString(NETDATAPATH)+"/loginHeader.bin");
        QFile fileServersList(SERVERSLISTFILEPATH);
        QFile fileBadPassword(QString(NETDATAPATH)+"/loginWrongPassword.bin");
        QFile fileAlready(QString(NETDATAPATH)+"/loginAlreadyConnected.bin");
        QFile fileMaxRegistration(QString(NETDATAPATH)+"/loginMaxRegistered.bin");
        QFile fileMaxConnected(QString(NETDATAPATH)+"/loginMaxConnected.bin");
        if (!file.open(QIODevice::ReadOnly) || !fileBadPassword.open(QIODevice::ReadOnly)
        || !fileAlready.open(QIODevice::ReadOnly) || !fileMaxRegistration.open(QIODevice::ReadOnly)
        || !fileMaxConnected.open(QIODevice::ReadOnly) || !fileServersList.open(QIODevice::ReadOnly))
        {
            logStatusMessage("Error reading login data files");
            stopServer();
        }
        else
        {
            bool ok=true;
            postData = postData.right(postData.size()-postData.indexOf("username="******"passhash=")-9);
            QString passhash = postData;
            passhash.truncate(postData.indexOf('&'));
            logMessage(QString("IP : ")+socket->peerAddress().toString());
            logMessage(QString("Username : "******"Passhash : ")+passhash);

            // Add player to the players list
            Player player = Player::findPlayer(tcpPlayers, username);
            if (player.name != username) // Not found, create a new player
            {
                // Check max registered number
                if (tcpPlayers.size() >= maxRegistered)
                {
                    logMessage("TCP: Registration failed, too much players registered");
                    socket->write(fileMaxRegistration.readAll());
                    ok = false;
                }
                else
                {
                    logMessage("TCP: Creating user in database");
                    Player newPlayer;
                    newPlayer.name = username;
                    newPlayer.passhash = passhash;
                    newPlayer.IP = socket->peerAddress().toString();
                    newPlayer.connected = false; // The connection checks are done by the game servers

                    tcpPlayers << newPlayer;
                    if (!Player::savePlayers(tcpPlayers))
                        ok = false;
                }
            }
            else // Found, compare passhashes, check if already connected
            {
                if (player.passhash != passhash) // Bad password
                {
                    logMessage("TCP: Login failed, wrong password");
                    socket->write(fileBadPassword.readAll());
                    ok=false;
                }
                /*
                else if (newPlayer.connected) // Already connected
                {
                    logMessage("TCP: Login failed, player already connected");
                    socket->write(fileAlready.readAll());
                    ok=false;
                }
                */
                else // Good password
                {
                    /*
                    // Check too many connected
                    int n=0;
                    for (int i=0;i<tcpPlayers.size();i++)
                        if (tcpPlayers[i].connected)
                            n++;
                    if (n>=maxConnected)
                    {
                        logMessage("TCP: Login failed, too much players connected");
                        socket->write(fileMaxConnected.readAll());
                        ok=false;
                    }
                    else
                    */
                    {
                        player.reset();
                        player.IP = socket->peerAddress().toString();
                        player.lastPingTime = timestampNow();
                        player.connected = true;
                    }
                }
            }

            if (ok) // Send servers list
            {
                QByteArray customData = file.readAll();

                QByteArray data1 = QByteArray::fromHex("0D0A61757468726573706F6E73653A0A747275650A");
                QByteArray sesskey = QCryptographicHash::hash(QString(passhash + saltPassword).toLatin1(), QCryptographicHash::Md5).toHex();
                sesskey += passhash;
                QByteArray data2 = QByteArray::fromHex("0A310A");
                QByteArray serversList;
                QByteArray line;
                do {
                    line = fileServersList.readLine().trimmed();
                    serversList+=line;
                    serversList+=0x0A;
                } while (!line.isEmpty());
                serversList = serversList.trimmed();
                QByteArray data3 = QByteArray::fromHex("0D0A300D0A0D0A");
                int dataSize = data1.size() + sesskey.size() + data2.size() + serversList.size() - 2;
                QString dataSizeStr = QString().setNum(dataSize, 16);

                customData += dataSizeStr;
                customData += data1;
                customData += sesskey;
                customData += data2;
                customData += serversList;
                customData += data3;

                logMessage("TCP: Login successful, sending servers list");
                socket->write(customData);
            }
        }
    }
    else if (data.contains("commfunction=removesession"))
    {
        logMessage("TCP: Session closed by client");
    }
    else // Unknown request, erase tcp buffer
    {
        // Display data
        logMessage("TCP: Unknow request received : ");
        logMessage(QString(data.data()));
    }

    // Delete the processed message from the buffer
    *tcpReceivedDatas = tcpReceivedDatas->right(tcpReceivedDatas->size() - tcpReceivedDatas->indexOf(data) - data.size());
}