Пример #1
0
        private void threadHandler() //Trata as mensagens que chegam e que são enviadas
        {
            networkStream = this.tcpClient.GetStream();
            protocolSI    = new ProtocolSI();
            Boolean trocaPosicao = false;

            while (protocolSI.GetCmdType() != ProtocolSICmdType.EOT) //Enquanto a thread não receber ordens para terminar
            {
                networkStream.Read(protocolSI.Buffer, 0, protocolSI.Buffer.Length);
                ProtocolSICmdType cmd = protocolSI.GetCmdType();
                string            msg;
                byte[]            msgByte;
                switch (protocolSI.GetCmdType())
                {
                case ProtocolSICmdType.PUBLIC_KEY:
                    security.setPublicKey(protocolSI.GetStringFromData());
                    Console.WriteLine("Recebi uma chave pública");
                    enviaACK();

                    simetricKey = protocolSI.Make(ProtocolSICmdType.SYM_CIPHER_DATA, security.getSimetricKey());
                    networkStream.Write(simetricKey, 0, simetricKey.Length);
                    esperaACK();

                    IV = protocolSI.Make(ProtocolSICmdType.IV, security.getIV());
                    networkStream.Write(IV, 0, IV.Length);
                    esperaACK();
                    break;

                case ProtocolSICmdType.USER_OPTION_1: //Adquire o nome do jogador
                    connection.WaitOne();             //Caso no qual é feito um broadcast e a thread "errada" recebe o ACK e, portanto
                    connection.ReleaseMutex();        //espera até que a thread "correta" receba o ACK para poder voltar a esperar nova mensagem
                    nomeJogador = security.DecifrarTexto(protocolSI.GetStringFromData());
                    Console.WriteLine("Jogador {0} - {1}, conectou-se", clientID, nomeJogador);
                    enviaACK();
                    break;

                case ProtocolSICmdType.USER_OPTION_2:     //Atualiza os jogadores presentes na sala
                    string salaDesejada = security.DecifrarTexto(protocolSI.GetStringFromData());
                    byte[] newJogador;

                    foreach (room sala in rooms)     //Percorre a lista de salas verificando se a sala na qual o cliente deseja conectar-se já existe
                    {
                        if (sala.getName() == salaDesejada)
                        {
                            if (!sala.isFull())     //Verifica se a sala não está cheia
                            {
                                sala.addClientToRoom(this);
                                this.room = sala;
                                break;
                            }
                            else
                            {
                                goto SalaCheia;
                            }
                        }
                    }

                    if (room == null)     //Cria a sala caso a mesma não exista
                    {
                        room = new room(salaDesejada);
                        rooms.Add(room);
                        room.addClientToRoom(this);
                        msg = System.DateTime.Now.ToString();
                        room.writeLog(msg);
                    }

                    Console.WriteLine("{0} entrou na sala {1}", nomeJogador, salaDesejada);
                    enviaACK();

                    if (room.getClientList().Count == 1)     //Se aquele jogador é o único na sala
                    {
                        //Coloca o jogador como o jogador 1
                        room.setJogador(nomeJogador);
                        msg        = String.Format("1/{0}/", nomeJogador);
                        newJogador = protocolSI.Make(ProtocolSICmdType.USER_OPTION_1, security.CifrarTexto(msg));
                        networkStream.Write(newJogador, 0, newJogador.Length);
                        esperaACK();
                    }
                    else if (room.getClientList().Count == 2)      //Se é o 2º jogador a entrar na sala
                    {
                        int posNovoJogador;
                        room.setJogador(nomeJogador);
                        foreach (ClientHandler client in room.getClientList())
                        {
                            if (client.clientID != clientID)
                            {
                                posNovoJogador = room.getNomeJogador(2) == nomeJogador ? 2 : 1;     //Descobre qual será a posição do novo jogador
                                msg            = String.Format("{0}/{1}/{2}", posNovoJogador, nomeJogador, jogadores);
                                newJogador     = protocolSI.Make(ProtocolSICmdType.USER_OPTION_1, client.security.CifrarTexto(msg));

                                broadcast(msg, ProtocolSICmdType.USER_OPTION_1, nomeJogador);

                                //Coloca-se na posição que resta
                                networkStream.Write(newJogador, 0, newJogador.Length);
                                esperaACK();
                            }
                            else     //Envia o nome do jogador que já está na sala para o novo jogador
                            {
                                int posJogadorPresente = room.getNomeJogador(1) != nomeJogador ? 1 : 2;
                                msg     = String.Format("{0}/{1}/{2}", posJogadorPresente, room.getNomeJogador(posJogadorPresente), true == room.isMultiplePlayers() ? "true" : "false");
                                msgByte = protocolSI.Make(ProtocolSICmdType.USER_OPTION_1, security.CifrarTexto(msg));
                                networkStream.Write(msgByte, 0, msgByte.Length);
                                esperaACK();
                            }
                        }
                        //Broadcast que informa que há 2 jogadores na sala e, portanto o jogo pode iniciar
                        broadcast(" ", ProtocolSICmdType.USER_OPTION_3);
                    }
                    else     //Se a sala já tem 2 jogadores
                    {
                        //Coloca os próximos jogadores na fila
                        room.setJogador(nomeJogador);
                        msg = String.Format("3/{0}/{1}/{2}/{3}/{4}/{5}/{6}", room.getNomeJogador(1), room.getNomeJogador(2), room.getPontos(room.getNomeJogador(1)),
                                            room.getPontos(room.getNomeJogador(2)), room.getPontos("empates"), jogadores, room.getProximoJogadores());
                        newJogador = protocolSI.Make(ProtocolSICmdType.USER_OPTION_1, security.CifrarTexto(msg));
                        networkStream.Write(newJogador, 0, newJogador.Length);
                        msg = String.Format("4/{0}/{1}", jogadores, room.getProximoJogadores());
                        broadcast(msg, ProtocolSICmdType.USER_OPTION_1);
                        esperaACK();
                    }
                    break;
SalaCheia:
                    msgByte = protocolSI.Make(ProtocolSICmdType.USER_OPTION_3);
                    networkStream.Write(msgByte, 0, msgByte.Length);
                    esperaACK();
                    break;

                case ProtocolSICmdType.DATA:     //Transmite o que o jogador disse para o chat
                    msg = $"{System.DateTime.Now.ToString("HH:mm:ss")} - {nomeJogador} : {security.DecifrarTexto(protocolSI.GetStringFromData())}";
                    Console.WriteLine(msg);
                    broadcast(msg, ProtocolSICmdType.DATA); //Broadcast da mensagem para todos os jogadores
                    room.writeLog(msg);                     //Escreve para o arquivo de texto as mensagens do chat
                    break;

                case ProtocolSICmdType.USER_OPTION_3:     //Trata da jogada executada utilizando assinaturas digitais
                                                          //Recebe o movimento cifrado
                    string move = security.DecifrarTexto(protocolSI.GetStringFromData());
                    //Espera pelo hash assinado do movimento cifrado com a chave privada
                    networkStream.Read(protocolSI.Buffer, 0, protocolSI.Buffer.Length);
                    while (protocolSI.GetCmdType() != ProtocolSICmdType.USER_OPTION_4)
                    {
                        networkStream.Read(protocolSI.Buffer, 0, protocolSI.Buffer.Length);
                    }
                    string moveSign = security.DecifrarTexto(protocolSI.GetStringFromData());
                    //Verifica a autenticidade do movimento
                    if (security.verifySignData(move, moveSign))
                    {
                        string[] coordenadas  = move.Split('/');
                        int      line         = int.Parse(coordenadas[0]);
                        int      col          = int.Parse(coordenadas[1]);
                        string   symbolPlayer = room.getNomeJogador(1) == this.nomeJogador ? "X" : "O";
                        switch (room.move(line, col, this.nomeJogador))
                        {
                        case -1:         //Movimento é inválido
                            msg = "Movimento inválido, tente novamente!";
                            byte[] invalid = protocolSI.Make(ProtocolSICmdType.USER_OPTION_4, security.CifrarTexto(msg));
                            networkStream.Write(invalid, 0, invalid.Length);
                            break;

                        case 0:         //Movimento válido
                            broadcast(String.Format("{0}{1}/{2}", line, col, symbolPlayer), ProtocolSICmdType.USER_OPTION_5);
                            break;

                        case 1:         //Jogo termina com um ganhador
                            broadcast(String.Format("{0}{1}/{2}", line, col, symbolPlayer), ProtocolSICmdType.USER_OPTION_5);
                            Thread.Sleep(100);
                            broadcast(String.Format("{0}/ganhou!", nomeJogador), ProtocolSICmdType.USER_OPTION_6);
                            Thread.Sleep(100);
                            if (trocaPosicao)
                            {
                                trocaDePosicao(room.isMultiplePlayers() == true ? true : false);
                                trocaPosicao = false;
                            }
                            break;

                        case 2:        //Jogo termina em empate
                            broadcast(String.Format("{0}{1}/{2}", line, col, symbolPlayer), ProtocolSICmdType.USER_OPTION_5);
                            Thread.Sleep(100);
                            broadcast(String.Format("/Empate!", nomeJogador), ProtocolSICmdType.USER_OPTION_6);
                            Thread.Sleep(100);
                            if (trocaPosicao)
                            {
                                trocaDePosicao(room.isMultiplePlayers() == true ? true : false);
                                trocaPosicao = false;
                            }
                            break;

                        case 3:         //Jogador incorreto tentou fazer o movimento
                            msg = "Espere a sua vez!";
                            byte[] jogadorIncorreto = protocolSI.Make(ProtocolSICmdType.USER_OPTION_4, security.CifrarTexto(msg));
                            networkStream.Write(jogadorIncorreto, 0, jogadorIncorreto.Length);
                            break;

                        default:
                            Console.WriteLine("Algo de errado aconteceu ao executar room.move");
                            break;
                        }
                    }
                    else
                    {
                        Console.WriteLine("Mensagem enviada inválida");
                        msg = "Ocorreu algum erro, tente novamente!";
                        byte[] invalid = protocolSI.Make(ProtocolSICmdType.USER_OPTION_7, security.CifrarTexto(msg));
                        networkStream.Write(invalid, 0, invalid.Length);
                    }
                    break;

                case ProtocolSICmdType.USER_OPTION_5:     //Jogador solicitou troca de posição
                    trocaPosicao = true;
                    if (!room.jogo.jogoComecou())
                    {
                        trocaDePosicao();
                    }
                    break;

                case ProtocolSICmdType.USER_OPTION_6:     //Jogador solicitou permitir vários jogadores
                    room.multiplePlayers();
                    msg = "Múltiplos jogadores habilitado";
                    broadcast(msg, ProtocolSICmdType.USER_OPTION_8);
                    break;

                case ProtocolSICmdType.SECRET_KEY:     //Recebe a senha do usuário
                    Console.WriteLine("Recebi a senha");
                    string senha = security.DecifrarTexto(protocolSI.GetStringFromData());
                    if (security.VerifyLogin(this.nomeJogador, senha))
                    {     //Autentica o jogador
                        Console.WriteLine("{0} autenticado com sucesso", this.nomeJogador);
                        msg = String.Format("{0}/{1}", nomeJogador, security.GetPoints(nomeJogador));
                        byte[] ack = protocolSI.Make(ProtocolSICmdType.ACK, security.CifrarTexto(msg));
                        networkStream.Write(ack, 0, ack.Length);
                        jogadores = jogadores + nomeJogador + ',' + security.GetPoints(nomeJogador) + ';';
                    }
                    else
                    {
                        Console.WriteLine("{0} senha incorreta", this.nomeJogador);
                        byte[] msgConnection = protocolSI.Make(ProtocolSICmdType.USER_OPTION_3);
                        networkStream.Write(msgConnection, 0, msgConnection.Length);
                        esperaACK();
                    }
                    break;

                case ProtocolSICmdType.EOT:     //Finaliza a sessão do jogador
                    Console.WriteLine("Ending Thread from {0}", nomeJogador);
                    if (room != null)
                    {
                        security.setPoints(nomeJogador, room.getPontos(nomeJogador) + security.GetPoints(nomeJogador));
                        if (room.getClientList().Count >= 2)
                        {
                            msg = String.Format("Jogador {0} deixou a sala/{1}", nomeJogador, nomeJogador);
                            broadcast(msg, ProtocolSICmdType.USER_OPTION_9, nomeJogador);
                        }
                    }
                    room.novoJogo();
                    break;

                case ProtocolSICmdType.ACK:     //Caso no qual é feito um broadcast e a thread "errada" recebe o ACK e, portanto
                    connection.WaitOne();       //espera até que a thread "correta" receba o ACK para poder voltar a esperar nova mensagem
                    connection.ReleaseMutex();
                    break;

                default:
                    break;
                }
            }
            networkStream.Close();
            this.tcpClient.Close();
            if (room != null)
            {
                this.room.removeClientOfRoom(this);
                this.room = null;
            }
        }