UNIVERSIDADE FEDERAL DE SANTA CATARINA DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA CURSO DE BACHARELADO EM SISTEMAS DE INFORMAÇÃO Rede Peer-to-Peer de gateways VoIP utilizando o padrão SIP. EVANDRO DE ESPÍNDOLA Trabalho de conclusão de curso submetido à Universidade Federal de Santa Catarina como parte dos requisitos para obtenção do grau de Bacharel em Sistemas de Informação Florianópolis - SC 2005/2 ii EVANDRO DE ESPÍNDOLA Rede peer-to-Peer de gateways VoIP utilizando o padrão SIP. Trabalho de conclusão de curso submetido à Universidade Federal de Santa Catarina como parte dos requisitos para obtenção do grau de Bacharel em Sistemas de Informação. Orientador: _________________________________ Prof. Frank Siqueira, Dr. Departamento de Informática e Estatística Universidade Federal de Santa Catarina Banca examinadora: _________________________________ Prof. João Bosco da Mota Alves, Dr. Departamento de Informática e Estatística Universidade Federal de Santa Catarina _________________________________ Prof. Leandro José Komosinski, Dr. Departamento de Informática e Estatística Universidade Federal de Santa Catarina iii Resumo O presente trabalho tem como objetivo demonstrar a viabilidade da criação de uma rede de gateways VoIP que serão conectados via rede Peer-to-Peer. Este trabalho descreve as tecnologias utilizadas para o uso da Voz sobre IP, incluindo os principais protocolos e uma descrição do software utilizado como gateway. Para que fosse possível alterar este software de modo a encontrar os gateways mais adequados para rotear uma ligação, foi necessário o estudo da plataforma JXTA, que permitiu a criação de um protótipo de rede peer-to-peer de gateways VoIP. O protótipo implementado demonstra a viabilidade da criação de uma rede peerto-peer de gateways VoIP, bastando para isto integrar o protótipo implementado com o software dos gateways. Palavras Chaves: Voz sobre IP, SIP, RTP, Asterisk, Gateways VoIP, redes peer-to-peer iv Glossário v Sumário 1 2 Introdução ............................................................................................................... 9 Digitalização da Voz .............................................................................................. 11 2.1 Amostragem ................................................................................................... 11 2.2 Quantização ................................................................................................... 12 2.3 Codificação .................................................................................................... 13 2.3.1 Codecs .................................................................................................... 14 2.4 A Taxa de Bits ................................................................................................ 15 2.5 Problemas na Representação Digital ............................................................. 15 2.5.1 Distorção ................................................................................................. 15 2.6 Requisitos Para Transmissão de Voz ............................................................ 16 2.6.1 Largura de Banda ................................................................................... 16 2.6.2 Vazão (Throughput) ................................................................................ 17 2.6.3 Taxa de Erro ........................................................................................... 17 2.6.4 Atraso Fim-a-Fim .................................................................................... 17 2.6.5 Variação de atraso (Jitter) ....................................................................... 17 2.6.6 Variação de vazão com o tempo............................................................. 18 2.6.7 Dependência temporal ............................................................................ 18 2.6.8 Tolerância a Perda de Pacotes ............................................................... 18 3 Session Initiation Protocol (SIP) RFC-3261 .......................................................... 20 3.1 Estrutura do protocolo .................................................................................... 20 3.2 MENSAGENS ................................................................................................ 22 3.2.1 REQUISIÇÕES ....................................................................................... 22 3.2.2 RESPOSTAS .......................................................................................... 22 3.2.3 Campos do Cabeçalho ........................................................................... 23 3.2.4 Corpo ...................................................................................................... 23 3.2.5 Estabelecimento de uma sessão SIP ..................................................... 23 4 Real-Time-Transport Protocol (RTP) .................................................................... 26 4.1 Características Principais ............................................................................... 26 4.2 Comportamento do RTP ................................................................................ 27 4.2.1 Comportamento do emissor RTP............................................................ 27 4.2.2 Comportamento do Receptor RTP.......................................................... 28 4.3 Sessões RTP ................................................................................................. 29 4.4 O Pacote RTP para transferência de dados .................................................. 29 4.4.1 Elementos do cabeçalho ......................................................................... 30 4.5 Protocolo de controle RTP (RTCP) ................................................................ 32 4.5.1 Formato básico ....................................................................................... 33 4.5.2 Relatório do Receptor (RTCP RR) .......................................................... 35 4.5.3 Relatório do Emissor : RTCP SR ............................................................ 37 4.5.4 Descrição da fonte (Source Description – SDES): .................................. 38 4.5.5 Controle de membros da sessão (RTCP BYE) ....................................... 39 4.5.6 Pacotes Definidos Pela Aplicação (RTCP APP) ..................................... 40 5 ASTERISK ............................................................................................................ 41 5.1 Tecnologias suportadas ................................................................................. 42 5.1.1 Hardware Zaptel ..................................................................................... 42 5.1.2 Hardware Não Zaptel .............................................................................. 43 5.1.3 Pacotes de voz ....................................................................................... 43 5.2 Visão geral da arquitetura .............................................................................. 43 5.2.1 Canais ..................................................................................................... 44 vi 5.2.2 CODECS Suportados ............................................................................. 45 5.2.3 Plano de discagem ................................................................................. 45 5.2.4 Processo de instalação e configuração .................................................. 46 6 JXTA ..................................................................................................................... 48 6.1 CAMADAS ..................................................................................................... 49 6.2 Componentes principais do JXTA .................................................................. 50 6.2.1 Peer ........................................................................................................ 50 6.2.2 Grupo de Peers....................................................................................... 50 6.2.3 Serviços de Rede.................................................................................... 51 6.2.4 Dutos(pipes)............................................................................................ 51 6.2.5 Mensagens ............................................................................................. 52 6.2.6 Anúncios (Advertisements) ..................................................................... 52 6.2.7 Identificadores (IDs) ................................................................................ 53 6.3 Protocolos JXTA ............................................................................................ 53 7 A REDE DE GATEWAYS PEER-TO-PEER .......................................................... 54 7.1 Descrição da aplicação .................................................................................. 54 7.2 Tecnologias utilizadas .................................................................................... 54 7.3 Escopo da aplicação ...................................................................................... 55 7.4 Desenvolvimento da aplicação ...................................................................... 55 7.4.1 Implementação da rede .......................................................................... 56 7.4.2 Interface Gráfica ..................................................................................... 58 8 CONCLUSÃO ....................................................................................................... 62 9 Bibliografia ............................................................................................................ 63 10 Anexos............................................................................................................... 65 vii Lista de Figuras Figura 2.1– Processo de amostragem ......................................................................... 12 Figura 2.2 – Processo de quantização. ........................................................................ 13 Figura 2.3 – Sinal codificado ........................................................................................ 13 Figura 3.1- Estrutura de camadas SIP ........................................................................ 21 Figura 3.2 - Estabelecimento de uma ligação VoIP usando SIP .................................. 24 Figura 3.3 - Mensagem INVITE enviada de Alice para Bob ......................................... 25 Figura 3.4 - Resposta de atendimento ......................................................................... 25 Figura 4.1 – Diagrama de blocos para um emissor RTP - Fonte: PERKINS, 2003 .... 27 Figura 4.2 – Diagrama de blocos para um receptor RTP - Fonte: PERKINS, 2003 ..... 28 Figura 4.3 - Pacote de dados RTP ............................................................................... 30 Figura 4.4 - Formato básico do pacote RTCP .............................................................. 34 Figura 4.5 - Exemplo de um pacote RTCP composto ................................................. 35 Figura 4.6 - Formato do pacote Relatório do Receptor RTCP...................................... 35 Figura 4.7 - Formato do pacote de relatório do emissor RTCP ................................... 37 Figura 4.8 - Formato do pacote de descrição da fonte RTCP ...................................... 39 Figura 4.9- Formato do pacote de Controle de membros da sessão RTCP ................. 40 Figura 5.1 – Arquitetura básica do Asterisk .................................................................. 44 Figura 6.1 - Rede Virtual .............................................................................................. 48 Figura 6.2 - Camadas da plataforma JXTA .................................................................. 49 Figura 7.1 - Diagrama principal .................................................................................... 56 Figura 7.2 - Classes do pacote redepeertopeer ........................................................... 57 Figura 7.3 – Tela inicial do programa ........................................................................... 59 Figura 7.4 – Valor e resultados da pesquisa ................................................................ 60 Figura 7.5 - Mensagens recebidas ............................................................................... 61 viii Lista de Tabelas Tabela 2-1 – Codecs mais populares ........................................................................... 15 Tabela 5-1 – Funções suportadas pelo Asterisk .......................................................... 41 Tabela 5-2 - Tabela de Hardwares zaptel mais comuns .............................................. 42 Tabela 5-3 Lista de hardwares não Zaptel ................................................................... 43 Tabela 5-4 - Protocolos suportados ............................................................................. 43 9 1 Introdução O crescimento da Internet, que nos últimos anos se popularizou como um meio de comunicação de alcance global e de baixo custo, aliado a um aumento constante na velocidade dos enlaces utilizados, criou um ambiente que viabiliza a criação de uma tecnologia para aplicações de transmissão de áudio digital em tempo real. Esta tecnologia chama-se Voz sobre IP ou VoIP [MONTEIRO, 2000]. Soluções baseadas em Internet Protocol (IP) têm sido propostas para substituir com inúmeras vantagens os modelos de telefonia convencional. Com a utilização de redes de pacotes para transportar voz elimina-se a necessidade da presença de um circuito dedicado. Assim, a voz é empacotada e transmitida por meio de redes de computadores juntamente com os dados. O IP é o protocolo usado nesse processo. Para que seja possível a conexão de soluções VoIP com as centrais públicas de comutação (PSTN) é necessário utilizar gateways, esses gateways podem ser modems do tipo voicemodem ou até mesmo placas especiais que suportam 30 linhas. A proposta deste trabalho é implementar uma rede Peer-to-Peer (P2P) de gateways VoIP (voz sobre IP) que estabeleçam a ligação entre a rede Internet e a rede pública de telefonia em vários pontos geograficamente distribuídos. Os gateways devem ser implementados em software, utilizando um computador e um modem convencional. O computador deve estar conectado à Internet via ADSL ou rede local. Um software aplicativo de telefonia, através de uma conexão com a rede P2P, será responsável por encontrar o gateway mais adequado para completar a ligação com a rede pública de telefonia. A comunicação de voz sobre IP será efetuada utilizando o padrão SIP, e a codificação utilizará o padrão de compressão G.711, que é equivalente à telefonia convencional em termos de qualidade e taxa de bits gerada. As vantagens deste tipo de rede podem ser bem variadas, como a redução do custo de ligações interurbanas e internacionais, outra vantagem é a utilização de equipamentos de baixo custo com software livre. Como se trata de uma rede peer-topeer não há a necessidade do uso de tecnologias do tipo cliente servidor, não havendo um servidor central. Este tipo de rede apresenta como principal característica a não existência de um servidor central, que normalmente é um computador potente e consideravelmente caro. Este trabalho está organizado da seguinte maneira: no capítulo 2 será descrito o processo de amostragem e codificação da voz e os problemas provenientes deste 10 processo, também descreveremos os requisitos mínimos para transmissão da voz. No capítulo 3 será descrito o protocolo SIP, veremos suas características principais, como é estruturado, características de conexão, e um breve exemplo de como é estabelecido uma conexão simples. No capítulo 4 será descrito o protocolo RTP, uma visão geral sobre as principais características, como ele se comporta no estabelecimento de uma sessão, uma visão mais aprofundada do pacote RTP para transferência dos dados, neste capítulo também será descrito o protocolo de controle RTP o RTCP e suas principais características. No capítulo 5 será descrito o software Asterisk, pra que serve, como funciona será mostrado também uma visão geral de sua arquitetura. No capitulo 6 será descrito a plataforma JXTA, suas camadas e seus componentes. No capítulo 7 tratará sobre a parte prática, contendo informações de como deverão ser instalados configurados os gateways e também a descrição de como a rede peer-to-peer foi implementada. 11 2 Digitalização da Voz A voz humana é uma onda sonora que pode ser transmitida por diversos meios de transmissão. A faixa de freqüência que uma pessoa normalmente ouve é de 20 a 20.000 Hertz (Hz). No entanto, as principais freqüências da voz humana estão em uma faixa mais reduzida, situada entre 300 e 3.400 Hz. Segundo (MONTEIRO 2003) A codificação da voz tem como objetivo, produzir um conjunto de códigos de voz a uma taxa mínima para a transmissão, de modo que o equipamento receptor possa reconstruir o sinal de voz original e também que a transmissão seja otimizada. 2.1 Amostragem O processo de amostragem consiste basicamente em obter amostras de áudio em intervalos regulares; estes intervalos, segundo o teorema de Nyquist, devem ter no mínimo o dobro da maior freqüência que será amostrada. A freqüência de amostragem adotada pela telefonia convencional é de 8 KHz. Para que seja obedecido o teorema de Nyquist, as centrais telefônicas são equipadas com filtros que limitam a freqüência do canal de voz em 3.4KHz. O circuito que permite amostrar o sinal é uma simples chave que se fecha por um brevíssimo instante, na cadência da freqüência de amostragem. Como a chave se fecha por um tempo extremamente curto, teremos na sua saída um sinal em forma de pulsos estreitos, com amplitude igual ao valor instantâneo do sinal, chamados pulsos PAM (pulsos modulados em amplitude). 12 Figura 2.1– Processo de amostragem Fonte: http://paginas.terra.com.br/lazer/py4zbz/teoria/digitaliz.htm 2.2 Quantização Na quantização, os valores da amostra são convertidos em valores discretos. Neste processo, o domínio do sinal é dividido em um número fixo de intervalos. Para cada amostra dentro de um intervalo é atribuído o valor do intervalo. Esse processo gera um ruído denominado ruído de quantização, que é determinado pela diferença do sinal de entrada pelo sinal de saída. A telefonia convencional utiliza 256 intervalos de quantização (8 bits), e adota o padrão de quantização e codificação não linear, ou seja, os valores de menor amplitude tem maior representação, o que só é possível usando circuitos especiais. Na informática, devido a restrições de hardware, a quantização é linear, ou seja os passos de quantização são iguais. 13 Figura 2.2 – Processo de quantização. Fonte: http://paginas.terra.com.br/lazer/py4zbz/teoria/quantiz.htm 2.3 Codificação No processo de codificação, cada amostra quantizada recebe um valor binário referente ao valor do intervalo de quantização. Dependendo da codificação usada, cada intervalo é representado por 8 bits, para algumas aplicações é importante que este valor por ser aumentado, podendo chegar a até 16 bits, o que permite representar 65.536 intervalos de quantização. Figura 2.3 – Sinal codificado Fonte http://paginas.terra.com.br/lazer/py4zbz/teoria/quantiz.htm 14 2.3.1 Codecs G.711: Segundo FERNANDES(2003), o padrão de códificação G.711 teve sua aprovação em 1972 (não havendo registro mais preciso) seu consumo de banda é de 64Kbps e utiliza a codificação PCM (Modulação por Código de Pulso). Fernandes afirma também que a norma não define um escopo específico para a utilização deste protocolo, mas que ele foi concebido para ser tratado de maneira mais eficiente pelos sistemas digitais de comunicação. Com relação ao atraso, Fernandes afirma que o atraso é de 0,125 ms, pois, são realizadas 8000 amostras por segundo sendo quantizado em 256 níveis, utilizando 8 níveis para a representação G.721 : Segundo MONTEIRO(2003) o padrão G.721 melhorar a relação sinal/ruído e diminui a banda devido ao seu funcionamento que é da seguinte forma: o fluxo de áudio é codificado usando o G.711 e sobre este fluxo são aplicados cálculos estatísticos onde é gerado uma estimativa baseada em duas amostras. A recomendação G.727 do ITU especifica um algoritmo de modulação diferencial adaptativo (ADPCM) onde são utilizados 5, 4, 3 e 2 bits por amostra, gerando desta forma taxas de 40, 32, 24 e 16 Kbps respectivamente. G.728: Segundo FERNANDES(2003) a data de aprovação desta especificação foi em 1º de setembro de 1992 e seu consumo de banda é de 16kbps. O tipo de codificação é a LD-CELP (Low- Delay Code Excited Linear Prediction). Fernandes afirma que o atraso mínimo desta recomendação é de 0,625 ms. A codificação é feita da seguinte forma, um bloco formado por 5 amostras seqüenciais codificados usando o G.711, para cada bloco é feito a comparação com todos os 1024 vetores armazenados no dicionário de vetores quantizados, a comparação mais próxima dada pelo módulo de minimização de erro, indicará o índice do dicionário que deverá ser transmitido pelo codificador. G.729: MONTEIRO(2003) afirma que o padrão G.729 é também conhecido como: Conjugate-Structure Agebraic Code Excited Linear Prediction – CS-ACEL. É um algoritmo de codificação que gera uma taxa de 8kbps e com boa qualidade de voz. A concepção desta especificação foi para ambientes sem fio, mas, podendo também, ser usado em comunicação de multimídia e em redes de dados, o atraso deste codec é de 15ms. O G.729 funciona da seguinte forma: A cada espaço de tempo de 10ms do sinal de voz, são analisadas 80 amostras de 8 bits (PCM) para geração de 10 códigos de 8 bits. 15 Tabela 2-1 – Codecs mais populares Standard Description Bandwidth(Kbps) MOS Coding Delay G.711 PCM 64 4.3 1.0μs G.721 ADPCM 32,16,24,40 4.0 1.25μs G.728 LD-CELP 16 4,0 2.5μs G.729 CS-ACELP 8 4.0 15.0μs Fonte: MONTEIRO, 2003 2.4 A Taxa de Bits A taxa de Bits gerada é determinada pelo produto entre a taxa de amostragem e o número de bits usados no processo de quantificação. Se a freqüência de amostragem for de 8 kHz e a quantidade de bits da quantização for de 8 bits por amostra, teremos então uma taxa de bits de 64Kbps. 2.5 Problemas na Representação Digital Mesmo tendo inúmeras vantagens, a digitalização, especificamente de áudio, apresenta inúmeras deficiências. Estas deficiências são inerentes ao processo de digitalização, não sendo possível eliminá-las totalmente, mas apenas reduzi-los utilizando técnicas que procurem restaurar fielmente o áudio analógico original (ou seja, anterior ao processo de digitalização). 2.5.1 Distorção O maior problema que ocorre na digitalização de sinais analógicos é que, não há como ter um sinal de saída de um decodificador (equipamento que faz o processo inverso ao de codificação) igual ao sinal de entrada. Este tipo de distorção é conhecida como distorção de codificação (amostragem, quantificação e codificação dos valores). Dependendo do tipo de distorção, o sinal pode ser recuperado e entendido perfeitamente. O padrão G.711 especifica os níveis máximos de ruído que podem ser inseridos na codificação analógica/digital. 16 Uma forma de diminuir o nível de ruído é aumentar a taxa de amostragem e o número de bits usado para codificação. Tanto o aumento da taxa de amostragem quanto o aumento dos bits de codificação geram automaticamente uma taxa de bits por segundo maior. As limitações para que isto seja possível são a necessidade de grandes espaços para armazenamento e de maior largura de banda para transmissão do sinal. Como o usuário final é normalmente um humano, a qualidade do dado convertido de digital para o analógico não precisa ser extremamente fiel ao dado analógico da entrada, tendo em vista que normalmente o cérebro humano é capaz de “ignorar” pequenas distorções. No caso do som há freqüências que o ouvido não diferencia e outras que ele não distingue. A especificação do padrão de digitalização G.711 especifica os níveis máximos de ruídos aceitáveis para uma codificação analógico/digital e depois para uma conversão digital/analógico. 2.6 Requisitos Para Transmissão de Voz A transmissão de voz é muito sensível a problemas de rede. Na rede telefônica estes problemas são minimizados, pois toda a rede de telefonia foi projetada para o tráfego de voz; já a internet não apresenta a mesma qualidade na transmissão, pois não garante atraso mínimo e também não garante que todos os dados transmitidos chegarão ao seu destino. Neste capítulo mostraremos alguns requisitos para a transmissão de voz pela internet. 2.6.1 Largura de Banda O número de dígitos binários trocados entre dois sistemas comunicantes que a rede é capaz de transportar é denominada de taxa de bits. A taxa de bits pode ser expressa em bps (bits por segundo) ou em múltiplos desta unidade (Kbps - Kilo bits por segundo, Mbps - Mega bits por segundo, etc.). O codec convencionalmente utilizado na telefonia convencional gera uma taxa de 64 Kbps. 17 2.6.2 Vazão (Throughput) A vazão de uma rede é a taxa de bits efetiva, ou seja, a taxa de bits total da comunicação menos a sobrecarga (overhead) causada pela tecnologia empregada na conexão devido ao envio de informações de controle (cabeçalhos, confirmações, códigos de detecção de erro, etc.). A vazão pode apresentar variações no tempo, seja devido a falhas em algum nó da rede, seja devido a congestionamentos. 2.6.3 Taxa de Erro A taxa de erro é um parâmetro importante para determinarmos a qualidade de uma rede. São utilizadas duas métricas para a determinação da taxa de erro: uma é a taxa de erro de bits (BER- Bit error rate) que é a razão entre bits errados e o total de bits transmitidos; a outra métrica é a taxa de erro de pacote (PER) que é definido pela razão entre o número de pacotes com erro e o número de pacotes transmitidos. 2.6.4 Atraso Fim-a-Fim Um dos principais parâmetros de qualidade da rede é o atraso fim-a-fim, que consiste no tempo necessário para transmitir um bloco de dados de um emissor para um receptor. Este atraso pode ser composto pelos seguintes componentes: - Atraso na interface: É o tempo que demora do pacote estar pronto para ser transmitido até a rede estar pronta para esta transmissão. Este item é mais relevante em redes orientadas a conexão, como a X.25 ou token-ring. - Atraso de trânsito: Tempo necessário para enviar um bit de um local a outro através de um enlace; este atraso só é relevante quando é utilizado um enlace via satélite, pois nos outros meios este atraso pode ser desprezado, já que a velocidade de propagação do sinal é igual à velocidade da luz. - Atraso de transmissão: Tempo necessário para transmitir um bloco de dados fim-a-fim. É dependente da taxa de bits da rede e do processamento dos nós intermediários. 2.6.5 Variação de atraso (Jitter) A variação de atraso entre a chegada de um pacote e outro é normalmente chamado de jitter, segundo Fernandes: “A existência de variações entre os intervalos 18 de tempo necessários para que pacotes consecutivamente transmitidos, percorram a distância entre pontos origem e destinos de um sistema de comunicação” (FERNANDES, 2003). A característica da rede IP na transmissão não garante que os pacotes sejam entregues com a mesma diferença de tempo. Para que esta característica não afete a qualidade da comunicação de voz é necessário o uso do buffer de jitter, que será descrito na seção 4.5.2. 2.6.6 Variação de vazão com o tempo A taxa de bits gerada por um codec VoIP pode ser constante (por exemplo, codecs que não utilizam supressão de silêncio) ou variável (por exemplo, codecs que utilizam supressão de silêncio). O codec G.711 gera uma taxa de bits constante, sendo assim a rede deve possuir uma taxa constante de bits, caso contrário há a necessidade de buffers para corrigir essas variações. 2.6.7 Dependência temporal Quando tratamos de comunicação entre pessoas há a necessidade de que o atraso não prejudique a interatividade. Segundo FERNANDES(2003) “A recomendação G.114 discorre sobre especificações do tempo de transmissão, incluindo o processamento em equipamentos e o tempo de propagação na rede.” FERNANDES(2003) afirma que os limites de atraso aceitáveis para uma transmissão fim-a-fim são: - Ideal: de 0 até 150ms; - Aceitável para usuários mais tolerantes: de 150 a até 400ms. Para atrasos de mais de 400ms a comunicação se torna de difícil entendimento. 2.6.8 Tolerância a Perda de Pacotes Veremos na sessão 4.1 que, as aplicações VoIP não utilizam retransmissão de pacote perdidos. A perda de um pacote isolado não gera grandes problemas para esse tipo de comunicação, já que o ruído gerado não passará de um pequeno “estalo” ou um pequeno silêncio (20ms para o G.711), o que para o ouvido humano é quase 19 imperceptível. Já a perda de pacotes em rajadas (em seqüência) pode prejudicar significativamente a qualidade do áudio, podendo chegar a inviabilizar a comunicação. 20 3 Session Initiation Protocol (SIP) RFC-3261 O SIP é um protocolo da camada de aplicação que serve para estabelecer, modificar e finalizar sessões multimídia (conferências) como se fossem ligações telefônicas. Novas mídias podem ser inseridas, e/ou removidas, de uma sessão já existente. O SIP suporta de forma transparente o mapeamento de nomes e o redirecionamento de serviços, assim como o http. O protocolo SIP pode ser descrito em cinco facetas para o início e o término de uma sessão multimídia. Estas facetas são: Localização do usuário: É a determinação do sistema da extremidade que será utilizado na comunicação. Disponibilidade do usuário: É a definição da possibilidade do usuário chamado participar da comunicação. Capacidades do usuário: Determina qual mídia e quais parâmetros serão usados. Estabelecimento da sessão: Estabelece a os parâmetros da sessão entre o chamado e o chamador. Gerenciamento da sessão: Inclui transferências e términos de sessões, modificações de parâmetros e invocações de serviços. Como o SIP foi desenvolvido pelo IETF (HTTP, SMTP, etc.) ele apresenta algumas características semelhantes a estes protocolos como: ser baseado no modelo cliente-servidor; utilizar formato texto para a troca de mensagens fazer uso de endereços “similares” a endereços SMTP, uma parte formada pelo telefone ou usuário e a outra parte formada pelo domínio. No item 3.2.5 temos um exemplo de uma sessão SIP sendo estabelecida. 3.1 Estrutura do protocolo O SIP está estruturado em camadas como mostrado na Figura 3.1, que apresentam comportamentos diferenciados e possuem um baixo acoplamento. Temos na seqüência uma breve descrição de cada camada e de sua responsabilidade. 21 Figura 3.1- Estrutura de camadas SIP Fonte: O’Doerth, 2003 Camada inferior: Camada responsável pela codificação e sintaxe do protocolo. Segunda Camada: Camada de transporte. Define como o cliente envia requisições e recebe as respostas, e como um servidor recebe as requisições e envia as respostas. Todos os elementos SIP possuem camada de transporte. Terceira camada: Camada de transação. Uma transação é uma requisição enviada por um cliente de transação (usando a camada de transporte) para um servidor de transação. Todas as respostas referentes a uma requisição são enviadas para o cliente de transação. Esta camada manipula as retransmissões da camada de aplicação, faz o casamento das respostas com as requisições e trata os time-outs da camada de aplicação. Qualquer tarefa que um Agente usuário cliente (User Agent Client - UAC) realiza ocorre usando uma série de transações. A camada de transação pode ser encontrada nos Agentes usuários (User Agents – UA) como no proxy com estado (stateful). Já os proxies sem estado (Stateless) não possuem esta camada. Ela contém componentes referentes ao cliente e ao servidor e é representada por uma máquina de estados finitos. A camada acima da camada de transação é chamada de Usuário de transação (Transaction User - TU). Toda entidade SIP, com exceção do proxy sem 22 estado, é um TU. O usuário que criou a transação pode cancelá-la através do comando CANCEL. 3.2 MENSAGENS 3.2.1 REQUISIÇÕES A RFC3261 define seis métodos para o registro, estabelecimento, manutenção e término da sessão. Os métodos são: Register que registra informações de contato, INVITE, ACK e CANCEL que definem o estabelecimento de sessões, BYE que serve para finalizar uma sessão e por ultimo o OPTIONS, para verificar qual a capacidade dos servidores. 3.2.2 RESPOSTAS As respostas das requisições são caracterizadas por terem uma linha de status na primeira linha, que é formada pela versão do SIP, pelo código de STATUS (que é interpretado pelo receptor através de um autômato) e por uma frase correspondente ao valor do código (esta frase serve para apresentação ao usuário). O valor do código é composto por um inteiro de três algarismos, onde o primeiro algarismo define a classe de resposta. As classes ou categorias de resposta estão divididas em seis grupos, como vemos a seguir: Categoria -1xx – Provisional: requisição recebida, continuando a processar a requisição. Categoria - 2xx – Sucess: Ação foi recebida com sucesso. Categoria – 3xx – Redirection: É necessário o envio de mais ações para completar a requisição. Categoria – 4xx – Client Error: A requisição possui erro de sintaxe ou o servidor não pode atendê-la. 23 Categoria – 5xx – Server Error: O servidor não pode atender uma requisição aparentemente válida. Categoria – 6xx – Global Error: A requisição não pôde se atendida em nenhum servidor. 3.2.3 Campos do Cabeçalho Os campos do cabeçalho SIP são semelhantes ao do HTTP, tanto na semântica quanto na sintaxe. Conforme a definição [H 4.2], que especifica a possibilidade de haver múltiplos valores para um mesmo campo, apenas separados por vírgula. Seguindo a forma genérica especificada na seção 2.2 da RFC 2822, o campo do cabeçalho é composto pelo nome seguido do ”:” e finalizado com o valor do campo (se forem múltiplos valores eles devem ser separados por vírgula). Não é necessário que os campos estejam em ordem, mas a RFC 3261 sugere fortemente que os campos que são utilizados para o processamento dos proxies estejam no início (para evitar atrasos na interpretação do cabeçalho). Também é definido na RFC que os campos com valores múltiplos podem ser representados de três formas diferentes: a primeira, como já foi comentado anteriormente, é expressar os valores separados por vírgula; a segunda é repetir o modelo “<Campo : Valor do campo>”; e a terceira seria uma combinação dos dois anteriores. 3.2.4 Corpo A interpretação do corpo da mensagem irá depender da requisição de cada método. Para as mensagens de resposta, a interpretação do corpo da mensagem irá depender do método de requisição e do código do Status da resposta. O tipo de corpo da mensagem deve ser fornecido pelo campo “CONTENT-TYPE” especificado no cabeçalho, a codificação de caracteres deve ser “UTF-8” caso não haja um parâmetro especificando outro padrão de codificação. 3.2.5 Estabelecimento de uma sessão SIP 24 Nesta sessão descreveremos um exemplo típico no estabelecimento de uma sessão SIP. Consideraremos dois usuários, Alice, registrada no servidor atlanta.com e o usuário Bob, registrado no servidor biloxi.com. A Figura 3.2 mostra o estabelecimento e o encerramento com sucesso de uma ligação utilizando o protocolo SIP. Figura 3.2 - Estabelecimento de uma ligação VoIP usando SIP Fonte: Rosenberg, 2002 A primeira parte da ligação como mostrado na Figura 3.2 representa o envio por parte da Alice de uma mensagem do tipo INVITE (Figura 3.3) para seu proxy SIP, contendo a informação do destino, o proxy verificando que o usuário é de outro proxy repassa o pedido de INVITE para o proxy onde Bob está registrado e envia uma resposta para Alice informando que está tentando estabelecer a ligação. O proxy onde Bob está localizado recebe e encaminha o INVITE para Bob (F4) respondendo para o proxy onde Alice está registrada que ele está tentando se conectar. Após o recebimento da mensagem INVITE, o telefone SIP de Bob irá responder para o proxy onde está registrado que está “chamando” (ringing); esta mensagem será encaminhada para o proxy atlanta.com e em seguida será encaminhada para o 25 Telefone SIP de Alice. Se Bob decide atender a ligação, o telefone SIP dele irá enviar uma resposta do tipo 200 – OK (Figura 3.4) que será encaminhada até o telefone SIP de Alice; este, ao receber a resposta, enviará um ACK (a partir deste momento nesta sessão a comunicação entre Alice e Bob será direta, sem interferência dos proxies) informando que recebeu a confirmação (F12). Neste momento é estabelecida a sessão de mídia, normalmente com o uso do protocolo RTP que será mostrado na sessão 4. Figura 3.3 - Mensagem INVITE enviada de Alice para Bob Fonte: Rosenberg, 2002 Figura 3.4 - Resposta de atendimento Fonte: Rosenberg, 2002 Ao término da sessão, Bob decide finalizar a ligação e seu Telefone SIP enviará para Alice uma mensagem BYE, e o telefone SIP de Alice irá apresentar uma resposta do tipo 200. 26 4 Real-Time-Transport Protocol (RTP) Atualmente o RTP é um dos protocolos de transporte mais usados para o transporte de mídia em tempo real, por exemplo: para a transmissão VoIP as duas principais especificações (SIP e H.323) fazem uso do RTP. Este protocolo provê serviços úteis ao transporte de mídia em tempo real, como áudio e vídeo, sobre redes IP. Estes serviços incluem detecção de erro, timing recovery, identificação do Payload e da fonte, retorno de qualidade de recepção, sincronismo de mídia e gerenciamento de membro de um grupo multicast. O RTP foi desenvolvido pelo Internet Engineering Task Force(IETF) e com o intuito de ser utilizado em conferências multicast usando o modelo de sessão leve. Desde o início ele foi vantajoso para uma grande gama de aplicações distintas. Sua primeira versão foi finalizada em Janeiro de 1996 (RFC 1889) e o International Telecommunications Union (ITU) o adotou, como parte das recomendações do H. 323. Atualmente a sua versão é definida pela RFC 3550. O RTP necessita de personalização para funcionar com alguns tipos de aplicação, a RFC 3551 define um dos perfis mais importantes pra VoIP, nesses perfis também constam as especificações do formato de Payload e de extensões. 4.1 Características Principais Normalmente as aplicações rodam o RTP no topo da pilha UDP, o que contribui com as funcionalidades do protocolo de transporte. Os algoritmos RTP não são usualmente implementados como camadas separadas, eles fazem parte do código da aplicação. O RTP não oferece nenhum mecanismo que garanta a transmissão em tempo real, não há garantia de confiabilidade e QoS. As especificações do RTP definam dois protocolos: - O protocolo RTP (Real time Transport Protocol) que serve para transporte da mídia. - O protocolo RTCP (Real-Time Control Protocol), que tem como objetivo o monitoramento da qualidade de serviço e distribuir informações acerca dos participantes das sessões. O RTCP não controla completamente a sessão na 27 comunicação de uma aplicação. Para este tipo de controle pode existir um protocolo de sessão com implementação separada. 4.2 Comportamento do RTP O protocolo RTO é o elemento principal na geração de fluxos de áudio e vídeo. Este protocolo oferece uma camada de transporte de mídia independente do protocolo de sinalização e de aplicação. Veremos a seguir as responsabilidades das partes envolvidas na comunicação. 4.2.1 Comportamento do emissor RTP O emissor tem a responsabilidade de capturar e converter a informação de áudio e/ou vídeo para a transmissão, assim como gerar os pacotes RTP. Ele pode participar na correção de erros e controle de congestionamento com a adequação do fluxo de mídia transmitido em uma resposta a um relatório enviado pelo receptor. A Figura 4.1 mostra o diagrama de blocos para uma comunicação do tipo VoIP. Figura 4.1 – Diagrama de blocos para um emissor RTP - Fonte: PERKINS, 2003 O fluxo de áudio é capturado e enviado para o codec, que irá compactar e gerar quadros, esses quadros, dependendo do tamanho, podem ser fragmentados em dois ou mais pacotes RTP(isso pode ocorrer com quadros de vídeo) ou vários quadros podem ser colocados juntos em um único pacote RTP (normalmente ocorre com fluxo de áudio). Um codificador de canal pode ser utilizado para diminuir problemas com perda de pacotes. 28 Cabe a quem está enviando o fluxo de mídia enviar periodicamente relatórios de status, onde devem constar informações para sincronização labial, informações sobre o codec utilizado e informações sobre os pacotes enviados. 4.2.2 Comportamento do Receptor RTP A responsabilidade de um receptor RTP é coletar os pacotes RTP da rede, corrigir eventuais perdas, reordenar os pacotes, decodificar as mídias e mostrar o resultado final ao usuário. A Figura 4.2 mostra um possível diagrama de blocos da recepção de um fluxo de mídia, mais especificamente de áudio. Figura 4.2 – Diagrama de blocos para um receptor RTP - Fonte: PERKINS, 2003 O primeiro passo é coletar os pacotes RTP da rede, validando-os e inserindo-os em uma fila de entrada, se for o caso, aplicar uma rotina de decodificação de canal, para a correção de perdas. Após isso os pacotes serão enfileirados em um buffer de apresentação (também conhecido como buffer de jitter). Nesta fila os pacotes são ordenados através da sua marca temporal, corrigindo assim qualquer falta de sincronismo da rede. Dependendo da mídia transportada os pacotes são armazenados na fila de exibição até que os quadros tenham sido completamente recebidos. Uma das funções do buffer de apresentação é a de diminuir eventuais atrasos na rede. Em seguida os quadros são decodificados e se for necessário, e o codec permitir, corrigir eventuais erros. O próximo passo é efetuar uma compensação entre o relógio da mídia ao tempo de apresentação. Essa compensação é necessária para que não haja falhas na 29 apresentação. Finalmente a mídia poderá ser apresentada para o usuário, se houver mais de um fluxo de áudio será necessário mixar todas as fontes em um único fluxo. Como podemos notar, a operação de recepção é mais complexa que a de emissão, boa parte desta complexidade é necessária para corrigir problemas com perdas e atrasos dos pacotes na rede. 4.3 Sessões RTP Um grupo de participantes se comunicando constituem uma sessão RTP. As sessões são concebidas para transportar um único tipo de mídia. Elas podem ser unicast, no caso do VoIP, ou multicast, que é o caso da videoconferência. Um participante pode ser ativo em várias sessões RTP, por exemplo, uma sessão para troca de dados de áudio e uma sessão para toca de dados de vídeo. 4.4 O Pacote RTP para transferência de dados O pacote RTP pode ser dividido em quatro partes principais que podem ser identificadas como: O cabeçalho RTP principal Cabeçalho de extensão (opcional) Um cabeçalho do Payload (opcional) Payload propriamente dito. 30 Figura 4.3 - Pacote de dados RTP Fonte: PERKINS, 2003 4.4.1 Elementos do cabeçalho Version (V, 2 bits) – Este campo identifica a versão do padrão RTP usada. A versão atual é a versão 2. Padding (P 1 bit) – Este campo indica se há bytes adicionais ao final do payload. Se há um padding o bit P deve ser setado em 1 e o ultimo byte do payload indica o número de bytes do padding. Extension (X, 1bit) – Campo que indica se há extensão do cabeçalho. Marker (M, 1 bit)Este campo tem sua função definida pelo tipo de mídia transportada. No caso da voz, este campo serve para identificar o primeiro pacote de uma rajada de voz após um período de silêncio (quando a supressão de silêncio está sendo usada). CSRC count(CC, 4bits) e CSRC list(CSRC identifier, cada fonte tem 32 bits) – O campo CC possui 4 bits e indica o tamanho da lista (campo CSRC) de fontes que contribuíram para formar o pacote RTP. Um exemplo de uso do campo CC e CSRC é o de uma áudio conferência. 31 Payload Type (PT, 7bits) – Este campo identifica o tipo de mídia transportada, A interpretação do valor deste campo irá depender do perfil utilizado, segundo WILLRICH(2004) o perfil mais comum para a transferência de áudio é o especificado na [RFC 3551] que são os mostrados na Tabela 4-1Error! Reference source not found.. Tabela 4-1 Valores do campo PT Fonte: WILLRICH (2004) Número de Seqüência (Sequence number, 16bits) – Contém o contador do número de seqüência dos pacotes RTP que é incrementado em um a cada envio de pacote. Além de identificar o pacote permite ao receptor a identificação de pacotes perdidos. Este campo não é usado para reordenar pacotes dispersos por atrasos na rede. PERKINS(2003) afirma que, “Uma típica aplicação de voz-sobre-IP enviando pacotes de áudio a cada 20 milisegundos irá zerar a seqüência em aproximadamente 20 minutos. Isso ocorre devido ao pequeno tamanho do campo PT que é de 16 bits. 32 Marca Temporal (TimeStamp,32 bits) – A marca temporal do pacote RTP denota o instante em que foi amostrado o primeiro octeto do dado contido no pacote. Seu valor é zerado quando é atingido o valor máximo. WILLRICH(2004) afirma que o valor inicial da marca temporal é escolhido de forma aleatória, não iniciando com zero, para prevenir ataques ao texto-plano conhecido de um fluxo RTP criptografado. SSRC (32 bits) – Este campo identifica os participantes dentro de uma sessão RTP. Este identificador é mapeado por um nome canônico, CNAME, através do protocolo RTCP. Payload - O Payload vem logo após qualquer cabeçalho e pode conter um ou mais quadros de áudio ou partes ou quadros inteiros de vídeo. Segundo WILLRICH(2004) o tamanho e o formato do payload varia de acordo com o formato de mídia negociados durante a configuração da sessão. 4.5 Protocolo de controle RTP (RTCP) O protocolo de controle RTP conhecido como RTCP fornece suporte para conferencia com grupos de tamanhos variados, segundo FERNANDES(2003) o protocolo RTCP “é baseado na transmissão periódica de pacotes de controle por todos os participantes de uma sessão, afim de monitorizar a qualidade de serviço e transportar informações destes participantes” (FERNANDES, 2003). WILLRICH (2004) afirma que o RTP permite: - Monitoramento da qualidade de serviço e controle de congestionamento: periodicamente os participantes das sessões enviam relatórios para todos os emissores, estes relatórios contém, o número de seqüência do ultimo dado recebido, o número de pacotes perdidos e uma medida da variação temporal entre transmissão e recepção. - Sincronização intermídia: aplicações que enviam dados recentemente emitem um relatório que contém informações sobre a mídia transmitida. Esta informação pode 33 ser utilizada para a sincronização intermídia, também conhecida como sincronização labial - Identificação da fonte: Como não há identificação da fonte no pacotes de dados RTP, essas e opcionalmente outras informações são transmitidas via RTCP. Segundo PERKINS(2003) uma implementação RTCP possui 3 partes, que são: - Formato de pacotes: Existem 5 tipos de formato de pacotes: Relatório de recepção (Receiver Report – RR), Relatório de Envio (Sender Report – SR), descrição da fonte (Source Description - SDES), gerenciamento de membros (Membership managment - BYE) e Aplication definetd (APP). - Regra de temporização: Definem a periodicidade com que serão enviados os pacotes RTCP. O intervalo de tempo entre pacotes RTCP é conhecido como intervalo de relatório (reporting Interval). Todas as atividades RTCP ocorrem em múltiplos desse intervalo de tempo. Nesses intervalos são calculadas as estatísticas da qualidade de recepção, e o tempo entre atualizações de descrição da fonte e informações sobre sincronização labial. O intervalo varia de acordo com o tamanho da sessão e também com o formato da mídia. - Base de dados de participantes. Base de dados construída com as informações coletadas dos pacotes RTCP recebidos. Esta base é usada no preenchimento dos pacotes de relatórios de recepção enviados periodicamente, a base também pode ser usada para sincronização labial e para manter informações de descrição de fonte. 4.5.1 Formato básico Os cinco formatos de mensagens RTCP possuem uma estrutura básica e comum no formato do pacote RTCP, como apresentado na Figura 4.4. 34 Figura 4.4 - Formato básico do pacote RTCP Fonte: PERKINS, 2003 A Figura 4.4 mostra o formato comum de um pacote RTCP. O cabeçalho que os cinco formatos possuem em comum é composto por 4 bytes que estão compreendidos em cinco campos, que são: - Número de versão (Version Number, V). Este campo tem sempre o valor 2, o que representa a versão atual do RTCP. - Padding (P) . Bit que indica a presença de padding ou não. Havendo um padding o tamanho do mesmo é especificado no seu ultimo Byte. - Iten Count (IC). Alguns pacotes possuem uma lista de itens. Este campo serve para indicar o número de itens do pacote e esse número de itens pode chegar a no máximo 31. - Tipo do Pacote (Packet Type – PT). Identifica o tipo de pacote. - Length. Indica o tamanho do conteúdo do pacote (em múltiplos de 32 bits). Normalmente os pacotes RTCP não são transmitidos individualmente, mas sim agrupados para formar um pacote composto. Este pacote composto é encapsulado pela camada de transporte (normalmente UDP). Se há criptografia no pacote composto o grupo de pacotes RTCP é prefixado por um valor aleatório de 32 bits. Conforme demonstrado na Figura 4.5 35 Figura 4.5 - Exemplo de um pacote RTCP composto Fonte: PERKINS, 2003 4.5.2 Relatório do Receptor (RTCP RR) O uso do RTCP tem como um dos principais objetivos a transmissão de relatórios sobre a qualidade de Recepção. Estes relatórios são enviados por todos os participantes das sessões que recebem dados. A Figura 4.6 mostra o formato do pacote de um relatório de recepção. Figura 4.6 - Formato do pacote Relatório do Receptor RTCP 36 Fonte: PERKINS, 2003 Como demonstrado na Figura 4.6 o valor do campo “tipo de pacote” é 201. - O campo Repórter SSRC identifica o participante que enviou o relatório. - O campo Reportee SSRC é a identificação da fonte de dados que está sendo reportada. - Fração de perdas, campo que indica o número de pacotes perdidos pelo número de pacotes esperados. - Número Acumulativo de pacotes perdidos. Este campo é um inteiro não sinalizado de 24 bits e indica o número de pacotes esperados menos o número de pacotes realmente recebidos. O número de pacotes recebidos é definido como sendo o ultimo número de seqüência estendido menos o número inicial da seqüência. - Maior número de seqüência estendido. Contem o número de seqüência estendido gerado pelo ultimo pacote RTP recebido. - Variância entre chegadas, também denominado Jitter. O Jitter entre chegadas é uma estimativa da variância estatística do tempo de transito dos pacotes de dados enviados pela fonte na sincronização reportada na rede. Este campo é informado em unidades de tempo e o tamanho do campo é de 32 bits. Como normalmente os relógios do emissor e do receptor não são sincronizados a aferição do tempo de transito absoluto se torna muito difícil. Para contornar este problema é feito o calculo do tempo de transito relativo. Este calculo é feito como sendo a diferença entre a marca de relógio temporal do pacote RTP e o clock RTP do receptor no tempo da chegada. O jitter entre chegadas J é definido como a diferença D correspondente ao espaço de tempo entre a chegada de um par de pacotes, comparado com os tempos estampados neste par de pacotes no momento do envio. Logo seja o timeStamp RTP do pacote i e Ri o tempo de chegada de unidades de timestamp RTP do pacote i, então dois pacotes i e j, D podem ser expresso como: O jitter entre chegadas é calculado continuamente por uma equação filtrada desta diferença. Toda vez que um relatório de recepção RR for montado, o valor corrente deste J é amostrado. A RFC 1889 prescreve este calculo de jitter. O jitter entre chegadas é calculado quando cada pacote é recebido, sendo calculado como uma média em movimento, de acordo com a seguinte fórmula: 37 toda vez em que um relatório de recebimento é gerado o Ji é calculado e inserido no campo interarrival jitter. - Marca temporal do último relatório emissor (LSR). É a ultima marca temporal inclusa no último pacote SR recebido da fonte reportada. - Atraso desde o último relatório emissor (Delay since last sender report received – DLSR). Tempo decorrido entre o recebimento do último relatório da fonte (SR) até o envio do relatório de recepção. Unidade expressa em 1/65536 segundos. 4.5.3 Relatório do Emissor : RTCP SR Os pacotes denominados Relatórios do emissor são enviados pelos participantes que enviaram informações recentemente para uma sessão RTP. Este tipo de relatório fornece informações a respeito do que está sendo enviada e serve principalmente para sincronização entre mídias. Como, por exemplo, áudio e vídeo. O número de identificação de um pacote do tipo SR é 200 e seu formato é como demonstrado na Figura 4.7. Figura 4.7 - Formato do pacote de relatório do emissor RTCP Fonte: PERKINS, 2003 38 Como podemos verificar na Figura 4.7 Payload tem o tamanho de 24 bytes e pode ser seguido por zero ou mais blocos contendo relatórios de recebimento, cujo número de blocos são indicados no campo RC. Normalmente os blocos do relatório de recebimento estão presentes quando o emissor também é um receptor. - Marca temporal NTP. Valor não sinalizado de 64 bits e representa a hora no formato NTP, que é a contagem em segundos desde 1 de janeiro de 1900(para os 32 bits superiores) e frações de segundo (para isso são usados os 32 bits inferiores) , do momento do envio do relatório. Marca temporal RTP. Corresponde ao mesmo momento da marca temporal NTP, mas é expresso na unidade do clock da mídia RTP. Normalmente este valor não será o mesmo da marca temporal do pacote de dados mais recente, já que esta provavelmente foi amostrado há mais tempo. Segundo WILLRICH(2004) “as marcas temporais são usadas para obter uma correspondência entre o relógio de mídia e uma referência externa conhecida(o relógio no formato NTP)”. Contador de pacotes e de octetos do emissor Contagem de pacotes enviados é a contagem de todos os pacotes de dados enviados desde o início da sessão, já o contador de octetos é a contagem de bytes contidos no payload dos pacotes de dados enviados(desconsiderando qualquer cabeçalho). Com esses dois dados é possível para a aplicação poder calcular a taxa média de dados de payload e a média dos pacotes enviados. WILLRICH(2004) afirma que o valor da razão entre os dois será o tamanho médio do payload. 4.5.4 Descrição da fonte (Source Description – SDES): Os pacotes do tipo SDES permitem a identificação dos participantes, esta identificação pode conter detalhes como, localização, e-mail, telefone. WILLRICH(2004) afirma que a descrição da fonte normalmente é informada pelo usuário e é normal que seja apresentada em uma interface gráfica da aplicação. A Figura 4.8 ilustra um pacote SDES. Poderemos verificar que o campo PT possui o valor 202. PERKINS afirma que os pacotes SDES podem conter zero ou mais 39 listas de itens SDES e que essa quantidade exata é informada no campo do cabeçalho SC. Figura 4.8 - Formato do pacote de descrição da fonte RTCP Fonte: PERKINS, 2003 PERKINS afirma que é possível uma aplicação gerar pacotes com o campo SC igual a zero, mas normalmente este campo possui o valor 1. WILLRICH(2004) afirma que mixes e tradutores podem gerar uma lista maior de itens SDES. Cada lista de itens SDES são iniciadas SSRC da fonte sendo descrita. Seguida por uma ou mais entradas. Cada entrada inicia com o campo tipo e tamanho, seguido pelo texto do item no formato UTF-8. 4.5.5 Controle de membros da sessão (RTCP BYE) Os pacotes do tipo RTCP BYE permitem a identificação de que o participante emissor irá deixar a sessão ou quando é necessário alterar o seu SSRC devido a alguma colisão. O valor do campo PT para esse tipo de pacote é 203, como demonstrado na Figura 4.9. Segundo PERKINS(2003) o campo RC indica o número de identificadores SSRC no pacote. WILLRICH(2004) afirma que “Na recepção de um pacote BYE, uma implementação deveria assumir que os participantes contidos na lista de fontes deixaram a sessão e ignorar qualquer pacote RTP ou RTCP vindo destas fontes (possivelmente atrasados pela rede).” 40 Figura 4.9- Formato do pacote de Controle de membros da sessão RTCP Fonte: PERKINS, 2003 Um pacote do tipo RTCP BYE pode conter as razões sobre o abandono da sessão, esta informação pode ser mostrada na interface para o usuário. 4.5.6 Pacotes Definidos Pela Aplicação (RTCP APP) Os pacotes do tipo RTCP APP permitem extensões definidas pela aplicação. O valor do campo PT para este tipo de pacote é 204. Os pacotes definidos pela aplicação são usados para exceções não padrões do RTCP e para testes de novas funcionalidades. 41 5 ASTERISK SPENCER(2003) diz que: “O Asterisk é um software TDM híbrido de código aberto, uma plataforma IVR com funcionalidades ACD e uma plataforma de pacotes de voz PBX”. SPENCER(2003) afirma também que possivelmente o Asterisk seja a melhor ferramenta para integração de telecomunicações, devido a sua flexibilidade e extensibilidade. O nome Asterisk provém do símbolo “*” que no UNIX é um caractere coringa que representa qualquer nome de arquivo. O Asterisk PBX foi concebido para integrar qualquer peça de telefonia, podendo ser disponibilizado em hardware ou software. Normalmente os produtos utilizados em telefonia são concebidos para atender um objetivo específico, mas muitas aplicações em telefonia compartilham um grande acordo tecnológico e o Asterisk toma vantagem desta característica criando um único ambiente que tem a possibilidade de ser moldado para agregar aplicações em particular ou várias aplicações, variando de acordo com a escolha do usuário. A Tabela 5-1Error! Reference source not found. mostra as aplicações onde é possível o uso do asterisk, podendo ele atender uma aplicação em específico ou todas as aplicações simultaneamente sem que seja necessário nenhuma alteração entre as interfaces. Tabela 5-1 – Funções suportadas pelo Asterisk Gateway VoIP Heterogêneo (MGCP, SIP, IAX, H.323) PABX Servidor IVR Softswitch Servidor de Audioconferência Tradução de Número Aplicação de Cartão Telefônico Discador Preditivo Fila de Chamadas com Agentes Remotos Estágio Remoto offices para PABS existentes Fonte: Spencer, 2003. A forma mais indicada para a obtenção da versão mais atual do Asterisk é através do repositório anônimo localizado em cvs.digium.com. A distribuição do asterisk está sob os termos do GNU ou GPL; esta licença permite a distribuição do 42 código e dos binários do Asterisk com ou sem modificações, sem qualquer restrição de uso ou de redistribuição do código. Esta licença não se estende ao hardware ou a softwares utilizados pelo asterisk. 5.1 Tecnologias suportadas Segundo SPENCER(2003), o Asterisk foi desenvolvido para que seja possível a agregação de novas tecnologias e interfaces. A meta para isso é suportar todo o tipo de tecnologia telefônica possível. Uma lista atualizada de hardware e protocolos suportados pelo Asterisk pode ser encontrada no site da digium (.http://www.digium.com). Normalmente as interfaces são divididas em três categorias, sendo elas: Hardware Zaptel Hardware não Zaptel Pacotes de voz 5.1.1 Hardware Zaptel Estas interfaces de hardware provêem integração com a telefonia convencional, sendo ela digital ou analógica (incluindo conexões com a rede pública de comutação). Adicionalmente, as interfaces que suportam Pseudo TDM da Zaptel podem ser conectadas entre si, diminuindo a latência a um nível bem baixo. As interfaces de rede do zaptel incluem conexões com: PSTN, POTS, T1, E1, PRI, PRA, E&M, Wink e funcionalidades para Grupos D. As interfaces zaptel constam na Tabela 5-2. Tabela 5-2 - Tabela de Hardwares zaptel mais comuns Hardware TE410P TE450P TDM400P T100P E100P X100P Descrição 4xE1/T1-3,3V PCI 4xE1/T1 5V PCI 4FXS/FXO 1 T1 1 E1 1 FXO Fonte: GONÇALVES, 2005 43 5.1.2 Hardware Não Zaptel As interfaces de hardware não zaptel provêem conexão aos serviços telefônicos convencionais e também a serviços telefônicos legados, mas neste caso não há suporte de chaveamento Pseudo TDM. Dentre as Interfaces de hardwares não zaptel estão inclusas: Tabela 5-3 Lista de hardwares não Zaptel ISDN4Linux . Basic Rate ISDN interface for Linux OSS/Alsa . Sound card interfaces Linux Telephony Interface (LTI) . Quicknet Internet Phonejack/Linejack Dialogic hardware1 . Full-duplex Intel/Dialogic hardware Fonte: Spencer, 2003 5.1.3 Pacotes de voz Estes são os protocolos padrão para a comunicação através de redes de pacotes (IP e Frame Relay) e são as únicas interfaces que não necessitam de um hardware especializado para funcionar. A Tabela 5-3 informa quais são os protocolos suportados. Tabela 5-4 - Protocolos suportados Session Initiation Protocol (SIP) Inter-Asterisk eXchange (IAX) versions 1 and 2 Media Gateway Control Protocol (MGCP) ITU H.3232 Voice over Frame Relay (VOFR) Fonte: Spencer, 2003 5.2 Visão geral da arquitetura 44 Figura 5.1 – Arquitetura básica do Asterisk Fonte:GONÇALVES, 2005 A Figura 5.1 demonstra como é a arquitetura básica do Asterisk, explicaremos a seguir os conceitos mais importantes relacionados a figura acima. 5.2.1 Canais Segundo GONÇALVES (2005), um canal se equipara a uma linha telefônica na forma de um circuito de voz digital, ou analógico. Normalmente consiste de um sinal analógico em um sistemas POTS (Plain Old Telephony System) ou de alguma combinação de CODEC e protocolo de sinalização (G.711 com SIP, GSM com IAX). Os canais suportados pelo asterisk são: Agent: Um canal de agente DAC Console: Cliente do Shell do Linux, driver para placas de som (OSS ou ALSA) H323: Protocolo VoIP IAX e IAX2: Inter Asterisk Exchange Protocol, protocolo nativo do Asterisk. MGCP: Media Gateway Control Protocol, outro protocolo de VoIP 45 Modem: Utilizados em linhas ISDN NBS: Utilizado para broadcast de som. Phone. Canal de telefonia do Linux. SIP Skinny: Um driver para o protocolo de telefones IP da CISCO. VOFR: Voz sobre Frame Relay VPB: Linhas telefônicas para placas Voicetronix ZAP: Driver para conectar telefones e placas da Digium 5.2.2 CODECS Suportados Como vimos na seção 2.3.1 os codecs tem por objetivo utilizar da melhor forma possível as características da rede. O Asterisk suporta os seguintes codecs: G.711 uLAw (Norte americano) e aLaw(Brasil e Europa) G.723.1 – Precisa de licenciamento e sua taxa de transmissão varia de 5.3 até 6 Kbps G.726 - 32Kbps G.729 – Precisa de licença, a não ser que seja para fins educacionais. Sua taxa de transmissão é de 8 Kbps GSM – possui taxa de transmissão de 12 a 13 Kbps iLBC – taxa de transmissão de 15 Kbps LPC10 – este codec possui taxa de transmissão de 2,5Kbps Speex – Sua taxa varia entre 2,15 a 44,2 Kbps 5.2.3 Plano de discagem Segundo GONÇALVES (2005) o plano de discagem é uma das peças mais importantes do asterisk, pois ele define como serão tratados as ligações efetuadas e recebidas. “É no extensions.conf que você controla todas as conexões através do seu PABX” (GONÇALVES, 2005). O arquivo extensions.conf pode ser separado em contextos e estensões, Golçalves afirma que os contextos são um agrupamento de extenções, que tem por objetivo principal, organizar e dar segurança ao plano de discagem. GONÇALVES (2005) também afirma que o contexto está ligado diretamente aos canais. Quando há uma ligação por um canal ela é processada por 46 esse canal. SPENCER(2003) afirma que após uma modificação no arquivo extensions.conf é necessário recarregar n mínimo o plano de discagem novamente, isso se da de forma manual, através do comando “extensions reload”, digitado na interface com o Cliente (CLI). 5.2.4 Processo de instalação e configuração O Asterisk foi instalado em uma distribuição do Debian 3.1 testing usando a versão do kernel 2.6.13. Já a versão instalada do Asterisk foi a 1.0.9, que é a distribuição estável no momento. Para que o modem seja reconhecido como um hardware do tipo FXO foi preciso instalar os drivers da Zaptel (disponíveis no site ou via CVS). Após a descompactação é necessário compilar e instalar o driver através dos comandos: make clean make linux26 make install Após a instalação dos módulos é necessário que eles sejam carregados. Para isso utilizamos os comandos: modprobe zaptel. modprobe wcfxo Após a instalação dos módulos é necessário configurar corretamente os drivers. A configuração é feita através do arquivo zaptel.conf (Anexo I) localizado no diretório /etc. Terminado o processo de configuração do módulo de telefonia o Asterisk já pode ser instalado. Como informado no capítulo 5 ele pode ser obtido através do site http://www.asterisk.org ou via CVS. Após o download e descompactação dos arquivos, os comandos para efetuar a instalação do asterisk foram os seguintes: make clean make make install make samples 47 O comando make samples gera os arquivos de configuração já bastante completos, os arquivos que necessitaram de algum tipo de modificação constam em anexo, foram os arquivos: zapata.conf (Anexo II), o sip.conf (Anexo III) e o extensions.conf (Anexo IV). Os demais aquivos permaneceram inalterados. 48 6 JXTA JXTA é uma plataforma aberta para o desenvolvimento de redes peer-to-peer. Ele é composto por blocos e serviços de fácil desenvolvimento. O JXTA provê um conjunto de protocolos abertos e uma implementação baseada em código aberto para o desenvolvimento de aplicações que fazem uso de redes peer-to-peer. A plataforma JXTA possibilita a criação de uma rede virtual sobre uma rede já existente, ocultando características complexas, com NAT e firewall. Ao contrário das aplicações clienteservidor tradicionais para troca de mensagens a rede virtual JXTA permite que qualquer ponto interagir outro ponto da rede ou recurso diretamente, sem ser afetado por Firewalls ou tecnologias de rede. A Figura 6.1 mostra um exemplo de como pode funcionar uma rede virtual. Figura 6.1 - Rede Virtual Fonte: Sun Microsystems Criado pela Sun, o JXTA foi desenvolvido para ser independente da linguagem de programação e também do protocolo de transporte. As linguagens de programação em que os protocolos podem ser implementados são: JAVA, C/C++, Perl e várias outras linguagens. 49 6.1 CAMADAS A arquitetura do JXTA é dividida em camadas, como mostrada na Figura 6.2. Figura 6.2 - Camadas da plataforma JXTA Fonte: JXTA v2.3.x: Java Program Guide (2005) Como demonstrado na Figura 6.2, a plataforma JXTA é dividida em três camadas, sendo elas: Camada da Plataforma ou Núcleo, Camada de serviços, e camada de Aplicação. Camada da plataforma (núcleo): A camada da plataforma, também conhecida como Núcleo JXTA, encapsula as primitivas mínimas, essenciais e comuns para as redes Peer-to-peer. Isso inclui blocos chaves para aplicações P2P como, por exemplo, descoberta, transporte, criação de peers, criação de grupos e as primitivas de segurança necessárias. Camada de serviços: esta camada inclui serviços de redes que não são estritamente necessárias para o funcionamento das redes P2P, mas que podem ser inclusos em um ambiente P2P. Dentre estes serviços estão compreendidos os serviços de indexação, de diretórios, compartilhamento de arquivos, protocolos de tradução, autenticação e serviços de PKI (Infra-estrutura de Chaves Públicas). Camada de Aplicação: estão inclusos nesta camada as implementações das aplicações integradas, mensagens instantâneas P2P, compartilhamento de documentos e recursos, etc. 50 Normalmente o limiar entre serviço e aplicação não é muito rígido, pois o que pode ser visto como aplicação por um pode ser visto como serviço pra outros. O sistema inteiro foi desenvolvido para ser modular, permitindo que o desenvolvedor escolha quais tipos de serviços serão utilizados. 6.2 Componentes principais do JXTA 6.2.1 Peer Um peer é qualquer dispositivo conectado a rede e que implementa um ou mais protocolos da plataforma JXTA, podendo ser um computador, um sensor, um PDA. Cada peer opera de forma assíncrona e de forma independente de qualquer outro peer. Um peer recebe um ID único que o identifica. 6.2.2 Grupo de Peers Um grupo de peers é uma coleção de peers que agregam uma série de serviços comuns. Normalmente os peers se auto organizam em grupos, que são identificados através de um identificador único (ID). Qualquer grupo pode estabelecer uma política de ingresso no grupo, aumentando assim a segurança e proteção. Os peers podem participar de mais de um grupo ao mesmo tempo. E por padrão o primeiro grupo que é instanciado é o “Net Peer Group” e posteriormente os peers podem escolher entrar em algum grupo adicional. Os protocolos JXTA descrevem como peers poderão divulgar, descobrir, entrar e monitorar esses grupos de peers. Há uma série de motivos para a criação e utilização de grupos, os principais motivos são: Criar um ambiente seguro – As políticas de segurança do grupo podem variar de acordo com a necessidade. Esta política pode ser simples, como enviar o nome de usuário e senha através de um arquivo de texto plano, ou complexa com o uso da estrutura de chaves públicas. Criar um ambiente de interesses mútuos – O exemplo mais comum de interesses mútuos é o auto-agrupamento para compartilhamento de documentos e recursos de processamento. Criar um ambiente para monitoramento – Os grupos de peers permitem que exista o monitoramento do estado de um conjunto de peers para algum propósito específico. 51 Os grupos podem possuir hierarquia de pais e filhos. No caso de alguma pesquisa no grupo filho essa pesquisa é repassada para o grupo pai. Normalmente os grupos de peers oferecem uma série de serviços. O JXTA define uma série de serviços oferecidos pelos grupos, mas serviços adicionais podem ser implementados pelo desenvolvedor. Para que possa haver interação entre os peers através dos serviços do grupo é necessário que os peers façam parte deste grupo. 6.2.3 Serviços de Rede Os peers cooperam entre si e comunicam-se para publicação, descoberta e invocação dos serviços de rede. Normalmente os peers podem publicar múltiplos serviços de rede. Os serviços de rede são descobertos através do Peer discovery Protocol (PDP). Os protocolos da plataforma JXTA conhecem dois níveis de serviços, os Serviços de peers e os Serviços dos grupos de peers. 6.2.4 Dutos(pipes) Os dutos são usados para o envio e recebimento de mensagens de um peer para outro. A comunicação entre os dutos é assíncrona e unidirecional e sem confiabilidade. O mecanismo de dutos pode ser utilizado para a comunicação ou transferência de dados e eles suportam a transferência de qualquer tipo de objeto. Incluindo código binário, cadeia de dados e objetos baseados na tecnologia JAVA. Os dutos das extremidades são referenciados como sendo dutos de entrada (input pipes) e dutos de saída (outputs pipes) é como são referenciados os dutos usados para o envio. Os dutos são uma comunicação virtual entre os peers, não tendo a necessidade de uma conexão física entre os dois equipamentos das pontas. Em alguns casos peers intermediários podem ser utilizados para prover a conexão. Os dutos fornecem dois modos de comunicação, um é ponto a ponto e o outro por propagação. 52 6.2.5 Mensagens As mensagens são objetos enviados através dos peers. Elas são a base para troca de dados entre os peers. Os serviço dos dutos (Pipe services) são utilizados normalmente para criar, enviar e receber as mensagens, outra forma pra troca de mensagens. Pode ser pelos serviços dos terminais (endpoint services). Uma mensagem é ordenada seqüencialmente pelo nome e conteúdo descrito, chamado de elemento da mensagem. As mensagens são basicamente um conjunto de pares nome/conteúdos. Existem dois tipos de representação para as mensagens: em formato XML ou binários. A plataforma JXTA J2SF faz o uso do formato binário para o envio do payload das mensagens. Os serviços podem enviar as mensagens no formato mais apropriado para a situação. 6.2.6 Anúncios (Advertisements) Todos os recursos de rede JXTA são representados através de um anúncio(advertisement). Os anúncios são uma linguagem meta-dados neutra e são representadas como sendo documentos XML. Os protocolos JXTA fazem uso desses anúncios para efetuar a publicação da existência dos recursos de um peer. Os recursos são descobertos pelos peers através da procura de seu anúncio correspondente. O resultado da busca pode ser armazenado localmente para possível próxima utilização. Cada anúncio é publicado com um tempo de vida especificando a disponibilidade do serviço associado ao anúncio. Os recursos com tempo de vida terminados podem ser removidos sem qualquer controle centralizado. Um anúncio pode ser republicado para que este tenha seu tempo de vida prolongado. Os protocolos JXTA definem vários tipos de anúncios. Os mais conhecidos são: Anúncios de peers (Peers Advertisement) Contem informações referentes aos recursos disponíveis nos peers. O uso principal deste tipo de anuncio é manter informações a respeito do peer, como nome, ID, etc. Anúncios de Grupos de peers (Peers Group Advertisement) Descreve os recursos específicos daquele grupo. Como Nome, ID, descrição, etc. Anúncio de encontro (Rendezvous Advertisement) Descreve como um peer irá encontrar outro peer num grupo. 53 6.2.7 Identificadores (IDs) Todos os componentes, recursos necessitam ser exclusivamente identificados. Os identificadores (ID) JXTA são usados como uma das únicas formas de conhecer as entidade e servidores, como um nome canônico de referência desta unidade. Atualmente há seis tipo sde identificadores, que são: peers, grupos de peers, dutos, conteúdos, classes de módulos e especificações de módulos. 6.3 Protocolos JXTA A especificação da plataforma JXTA define uma série de formatos para as mensagens XML, ou protocolos, para a comunicação entre os peers. Estes protocolos são utilizados pelos peers para, descobrir um ao outro, trocar mensagens, descobrir serviços de rede e descobrir a rota das mensagens trocadas entre eles. Os principais protocolos são: Peer Discovery Protocol (PDP) – Usado pelos peers para anunciar os recursos próprios e também para descobrir recursos de outros peers. Peer Information Plrotocol (PIP) – Usado pelos peers para obter informações a respeito de outros peers (status, tempo ativo, tráfego recente) Peer Resolver Protocol (PRP) – Este protocolo permite que os peers enviem uma consulta genérica para um ou mais peers e receba uma ou mais respostas para esta consulta. Ao contrário do PIP e do PDP, que utilizam informações específicas e pré-definidas para consultas, o PRP permite que o serviço do peer defina arbitrariamente a informação que ele necessite procurar. Pipe Binding Protocol (BPB) – usado pelos peers para estabelecer um canal de comunicação, ou um duto entre um ou mais peers. Endpoint Routing Protocol (ERP) – usado pelos peers para encontrar rotas para as portas de destino dos outros peers. Rendezvous Protocol (RVP) – Mecanismo que permite aos peers se associar ou permitir que outros se associem a um serviço de propagação. O RVP é utilizado pelo PRP e pelo PBP pra a propagação de mensagens. 54 7 A REDE DE GATEWAYS PEER-TO-PEER 7.1 Descrição da aplicação Atualmente a maioria das soluções de Gateway VoIP envolve um custo elevado e um trabalho complexo para configuração dos gateways. Uma das intenções deste trabalho foi encontrar uma solução que fosse acessível para a maioria das pessoas, tanto economicamente quanto em relação à complexidade envolvida para configuração. Este trabalho se propõe a criar uma rede de gateways de baixo custo conectados através de uma rede peer-to-peer que permita o roteamento da chamada entre os gateways que fazem parte da rede. 7.2 Tecnologias utilizadas A primeira parte deste trabalho foi encontrar uma forma de criar um gateway VoIP/PSTN. Após uma extensiva pesquisa sobre a viabilidade de se criar uma ferramenta que funcionasse de acordo com o esperado, foi resolvido adotarmos uma ferramenta disponível atualmente no mercado. A escolha do ASTERISK se deu pelo fato de ser de código aberto, e já fornecer suporte para modems do tipo voicemodem, como canal de conexão com o sistema de telefonia convencional. A segunda parte do trabalho consiste no desenvolvimento de uma rede peer-topeer para a conexão e comunicação entre os gateways. Esta aplicação deverá funcionar em conjunto com a ferramenta ASTERISK. A linguagem de programação utilizada para a criação da aplicação foi a linguagem JAVA da Sun Microsystems. devido a um maior domínio desta linguagem. A API utilizada para a construção da rede de gateways foi a JXTA também desenvolvida pela Sun. Para demonstrarmos a conexão com a rede peer-to-peer, utilizaremos uma aplicação simples que fará a conexão, a entrada no grupo, a descoberta dos peers na rede e também o envio e recebimento de mensagens (requisitos mínimos para funcionamento da rede de gateways). 55 7.3 Escopo da aplicação Na atual fase do trabalho, a aplicação ficará restrita à construção de um programa para troca de mensagens entre os nós da rede P2P, ficando a integração com o asterisk para uma etapa posterior. A aplicação deve ter as seguintes funcionalidades: - Permitir a conexão com a rede peer-to-peer - Permitir o ingresso no grupo “VoIPGateways”, criado especificamente para este esta aplicação - Permitir busca por peers na rede P2P. - Permitir o envio de mensagens para peers conhecidos; como não é intenção da aplicação o envio de mensagens do tipo multicast, as mensagens devem ser enviadas para um peer de cada vez. - Permitir o recebimento de mensagens de peers conhecidos e desconhecidos. 7.4 Desenvolvimento da aplicação A aplicação está estruturada em três pacotes principais: o Gerente, que é responsável por criar as duas outras classes, a casse ResponsavelRede, localizada no pacote redepeertopeer e a classe InterfaceGrafica localizada no pacote interfacegrafica. O objetivo de a aplicação ser desenvolvida em pacotes é justamente separar a implementação dos serviços de rede, dos serviços referentes à interface e do gerenciamento da aplicação. 56 Figura 7.1 - Diagrama principal Como é mostrado na Figura 7.1, a Classe Gerente (Anexo V) é responsável pela criação e integração entre a interface e a rede. A classe interface possui os métodos específicos da interface gráfica e alguns métodos de validação, para garantir que não haja inconsistências nos dados fornecidos a classe ResponsavelRede. 7.4.1 Implementação da rede O pacote redepeertopeer possui as classes mostradas na Figura 7.2 e o código fonte da aplicação se encontra no Anexo VI. 57 Figura 7.2 - Classes do pacote redepeertopeer O pacote redepeertopeer é composto por seis classes que juntas dão as funcionalidades utilizadas na rede peer-to-peer, que são a conexão na rede, a entrada no grupo, a localização de peers e a troca de mensagens utilizando dutos (pipes). As classes são as seguintes: ResponsavelRede: Classe que efetua a criação dos objetos responsáveis pela rede e pela delegação de tarefas. Esta classe serve como interface com os métodos da rede. Os principais métodos são: o ResponsavelRede: Método que inicializa os parâmetros da rede. o Conecta: Método cujos objetivos são conectar ao grupo (rendezvous), entrar no grupo “VoIPGateways” e definir como monitor das mensagens recebidas a classe RecebedorDeMSG utilizando a classe CriadorDeAdv para gerar um documento válido e com um ID fixo. o Desconecta: Este método serve para parar o “Rendezvous”. o getMensagensRecebidas: este método tem como retorno um array de String onde os índices de valor par são o identificador da fonte que está enviando e o valor impar subseqüente consiste na mensagem recebida. 58 o descubraPeers: Método responsável pela localização dos peers através de um conjunto de caracteres passados pela interface do usuário. Este valor representa na rede peer-to-peer o código de país e código de área do gateway que efetuará a conexão com a rede pública de telefonia. o envia_MsgPeer: Método com a função de enviar uma mensagem específica para um peer específico. CriadorDeAdv: Classe responsável por criar os PipesAdversments que são documentos que contém informações que possibilitam a troca de mensagens entre dois peers; o documento está em XML, como demonstra este exemplo de documento a seguir: <!DOCTYPE jxta:PipeAdvertisement> <jxta:PipeAdvertisement xmlns:jxta="http://jxta.org"> <Id> urn:jxta:uuid-3230313534384736B531B035373938372D31333235324032B436B604 </Id> <Type> JxtaUnicast </Type> <Name> Inominavel... </Name> </jxta:PipeAdvertisement> EnviadorDeMsg: Classe responsável pelo envio das mensagens repassadas pela classe ResponsavelRede, que possui dois métodos principais: enviaMsg, que cria a mensagem propriamente dita, incluindo na mensagem o destinatário e gerando um evento para o método outputPipeEvent, que é a forma de enviar a mensagem gerada pelo método enviaMensagem. IngressadorGrupo: Esta classe é responsável por enviar a pesquisa pelo grupo VoIPGateways e caso não localize um gateway para estabelecer a ligação, cria um grupo com este nome, e com um ID específico. Se o grupo existir ele será obtido pela classe EscutadorGrupo. RecebedorDeMsg: Classe responsável pelo recebimento e armazenamento temporário das mensagens. 7.4.2 Interface Gráfica 59 A interface gráfica foi desenvolvida de forma simples e rápida; para isso utilizamos a ferramenta de desenvolvimento NetBeans. Foi priorizada a elaboração de uma interface simples e amigável que servisse ao propósito da aplicação, possibilitando a demonstração da funcionalidade do pacote redepeertopeer. A maioria dos componentes utilizados na interface faz parte da biblioteca Swing, que faz parte da biblioteca padrão do JAVA. A Figura 7.3 mostra como é a interface com o usuário. Figura 7.3 – Tela inicial do programa As opções de conectar, desconectar e sair pode ser encontradas nos botões mostrados na Figura 7.3 ou no menu “Arquivo”. O Botão Envia MSG abrirá a janela para a digitação da mensagem somente se a aplicação estiver conectada e a pesquisa retornar no mínimo um peer e ele estiver selecionado. O botão Limpar Resultados limpa a lista de peers localizados. Ver Detalhes apresenta uma janela com os dados do peer selecionado. 60 O botão Pesquisar serve para localizar peers cujo valores iniciam com 2 caracteres numéricos que serão usados para a localização dos peers, estes valores representam o código de país seguido pelo código de área, ao final da procura o resultado mostrado para o usuário como mostrado na Figura 7.4. Figura 7.4 – Valor e resultados da pesquisa As mensagens recebidas e armazenadas pelo pacote redepeertopeer são mostradas na parte inferior da janela, como mostrado na Figura 7.5. Para que a verificação de mensagens ocorra sem a necessidade de o usuário executar um comando, as mensagens são carregadas de forma automática na interface, através de uma thread. 61 Figura 7.5 - Mensagens recebidas O código fonte da interface gráfica se encontra no anexo Anexo VII 62 8 CONCLUSÃO A telefonia IP hoje em dia está muito presa ao valor dos equipamentos que possibilitam a conexão entre o VoIP e a telefonia convencional. Neste trabalho verificamos a existência de uma ferramenta que possibilite a conexão do VoIP com a telefonia convencional de uma forma consideravelmente barata, tendo como único custo necessário a aquisição de um modem específico. A plataforma JXTA se mostrou essencial para a criação da rede peer-to-peer para a conexão dos peers. O fato de a tecnologia ser aberta e devido sua independência de plataforma e protocolo de comunicação esta provavelmente será uma das áreas que terá um crescimento considerável em pouco tempo. Na construção de nossa aplicação conseguimos demonstrar a possibilidade de conectamos via rede peer-to-peer várias máquinas geograficamente separadas. Mesmo sem conhecer os membros que estão conectados a rede peer-to-peer a plataforma JXTA possibilita a localização dos peers, que, até então, eram desconhecidos, e possibilite a troca de informações através dos componentes fornecidos pelo JXTA, As dificuldades encontradas no decorrer do desenvolvimento do trabalho em sua maioria referentes à tentativa de integrarmos a ferramenta de rede com o gateway VoIP. Coisa que não foi possível devido a limitação de tempo e conhecimento da linguagem em que o Gateways foi desenvolvido. Outra dificuldade encontrada no desenvolvimento do trabalho foi referente a Plataforma JXTA que tem sua bibliografia consideravelmente restrita e em determinados momentos de difícil entendimento. As sugestões para trabalhos futuros é a mudança de plataforma da aplicação para a linguagem C++ pra Linux e fazer a conexão com o Gateway VoIP. 63 9 Bibliografia FERNANDES, N. L. L. RELAÇÃO ENTRE A QUALIDADE DAS RESPOSTAS DAS RECOMENDAÇÕES G.723.1 E G.729, E O COMPORTAMENTO DA REDE IP DE SUPORTE. 2003. 170f. Dissertação (Mestrado em Ciências em Engenharia De Sistemas e Computação). – Faculdade de Engenharia de Sistemas e Computação, Universidade Federal do Rio de Janeiro, Rio de Janeiro 2003. MONTEIRO, T. L. SOLUÇÃO DE TELEFONIA IP EM UMA REDE PRIVATIVA DE SOLUÇÕES MISTAS. 2003. 160f Dissertação (Mestrado em Ciências da Computação). – Faculdade de Ciências da Computação, Universidade Federal de Santa Catarina, Florianópolis 2003. MONTEIRO, R. F. Implementação de Transporte Robusto de Voz em Redes Baseadas em Protocolos IP. 2000. 85 f. Dissertação de Mestrado (Engenharia Elétrica) - Universidade Federal de Minas Gerais, Belo Horizonte. 2000 ZURMELY, R. Digitalização - Digitalização De Um Sinal Analógico – Disponível em http://paginas.terra.com.br/lazer/py4zbz/teoria/digitaliz.htm acessado em 15 de novembro de 2005. ZURMELY, R. Digitalização - Quantização E Codificação – Disponível em http://paginas.terra.com.br/lazer/py4zbz/teoria/quantiz.htm acessado em 15 de novembro de 2005. ROSENBERG, et. al. RFC 3261 - SIP: Session Initiation Protoco. EUA, 2002. 260 p. O’DOHERTY, P. JAIN SIP Tutorial: Serving the Developer Community. Sun Microsystem. EUA 2003. 49 p. PERKINS, C. RTP: Audio and Video for the Internet. EUA, 2003. 472 p. SPENCER, M Asterisk Handbook - Draft. EUA: Digium, 2003. 71 p. GONÇALVES, F, E de A. ASTERISK pbx: Guia de configuração. Florianópolis: V.Office Networks, 2005. 251 p 64 JXTA v2.3.x: Java™ Programmer’s Guide. Sun Microsystems, 2005. 147 p. Project JXTA Technology: Creating Connected Communities. Sun Microsystems, 2002 WILLRICH, R. Sistemas Multimídia Florianópolis: UFSC, 2004. 151 p. 65 10 Anexos Anexo I. – Arquivo zaptel.conf. #========================================= #Zaptel.conf #arquivo de configuração Para a Placa genériaca XP100 da Digium # loadzone = us defaultzone = us fxsks = 1 #================================== Anexo II. Arquivo de Configuração zapata.conf ;======================================== ; Zapata telephony interface ; ; Arquivo de Configuracao zapata.conf [trunkgroups] [channels] context=default switchtype=national signalling=fxo_ls rxwink=300 usecallerid=yes hidecallerid=no callwaiting=yes usecallingpres=yes callwaitingcallerid=yes threewaycalling=yes transfer=yes cancallforward=yes callreturn=yes echocancel=yes echocancelwhenbridged=yes rxgain=0.0 txgain=0.0 group=1 callgroup=1 pickupgroup=1 immediate=no ;================================================ ;fim arquivo zapata.conf ;=================================================== Anexo III. Arquivo de configuração sip.conf ;==================================== ; Aquivo sip.conf 66 ;===================================== [general] context=default port=5060 bindaddr=0.0.0.0 srvlookup=yes disallow=all allow=ulaw [1001] type=friend username=redips secret=minha_senha host=dynamic mailbox=1001 [2002] type=friend username=dips secret=outra_senha host=dynamic mailbox=2002 ;======================================== ; Fim arquivo SIP.conf ;======================================== Anexo IV. Arquvo de Configuração Extension.conf ;========================================= ; Arquivo extensions.conf ;========================================= [general] [globals] CONSOLE=Zap/1 [default] ;--------------------------------; Ligacoes entrantes sao encaminhadas para o usuario sip dips exten => s,1,Dial(SIP/1001,10,tT) exten => s,2,Hangup ; ---------------------------------------------; ;------------------------------------------; Ligacao internas com 4 digitos sao encaminhadas para o usuario sip correspondente ; exten => _XXXX,1,Dial(SIP/${EXTEN},20) exten => _XXXX,2,Hangup ;-------------------------------------------------;----------------------------------------------------;---------------------------------------------------;ligacoes internas com 8 digitos sao realizadas como ligacoes locais. 67 exten => _XXXXXXXX,1,Dial(${CONSOLE}/${EXTEN},20) exten => _XXXXXXXX,2,Hangup ;======================================== ;Fim Arquivo extensions.conf ;============================================= 68 Anexo V. - Código Fonte Gerente.java package gerenciamento; import interfacegrafica.InterfaceGrafica; import redepeertopeer.ResponsavelRede; /** * * @author REDIPS */ public class Gerente { private ResponsavelRede umCaraDaRede; private InterfaceGrafica umaI; /** Creates a new instance of Gerente */ public Gerente() { umCaraDaRede = new ResponsavelRede(); umaI = new InterfaceGrafica(); umaI.conhecaResponsavelRede(umCaraDaRede); } public void vai(){ umaI.show(); umaI.run(); } /** * @param args the command line arguments */ public static void main(String[] args) { Gerente umGerente = new Gerente(); umGerente.vai(); // TODO code application logic here } } 69 Anexo VI. Código Fonte das classes pertencentes ao pacote redepeertopeer - CriadorDeAdv.java package redepeertopeer; import import import import import import net.jxta.id.IDFactory; net.jxta.peer.PeerID; net.jxta.peergroup.PeerGroup; net.jxta.peergroup.PeerGroupID; net.jxta.protocol.PipeAdvertisement; net.jxta.util.PipeUtilities; /** * * @author REDIPS */ public class CriadorDeAdv { private PeerGroupID pGID; /** * Creates a new instance of CriadorDeAdv */ public CriadorDeAdv() { } public synchronized PipeAdvertisement getPipeadv(){ PipeAdvertisement pipeAdv = null; try{ pipeAdv = PipeUtilities.createPipeAdvertisement(); pipeAdv.setPipeID(IDFactory.newPipeID(this.pGID, (this.pGID.hashCode()+"").getBytes())); pipeAdv.setName("Inominavel..."); System.out.println(pipeAdv.toString()); }catch(Exception e){System.out.println("Deu erro no Adv#"+e.getLocalizedMessage());} return pipeAdv; } public synchronized PipeAdvertisement getPipeadv(PeerGroupID pGID){ PipeAdvertisement pipeAdv = null; try{ pipeAdv = PipeUtilities.createPipeAdvertisement(); pipeAdv.setPipeID(IDFactory.newPipeID(pGID, (this.pGID.hashCode()+"").getBytes()));// Usando o ID do grupo como seed ainda sem uso.... pipeAdv.setName("Inominavel..."); System.out.println(pipeAdv.toString()); }catch(Exception e){System.out.println("Deu erro no Adv#"+e.getLocalizedMessage());} return pipeAdv; } public synchronized PipeAdvertisement getPipeadv(PeerGroupID pGID, PeerID idPeer){ PipeAdvertisement pipeAdv = null; 70 try{ pipeAdv = PipeUtilities.createPipeAdvertisement(); pipeAdv.setPipeID(IDFactory.newPipeID(pGID, idPeer.toString().getBytes())); pipeAdv.setName("Inominavel..."); System.out.println("Peer Local......"+pipeAdv.toString()); }catch(Exception e){System.out.println("Deu erro no Adv#"+e.getLocalizedMessage());} return pipeAdv; } public synchronized PipeAdvertisement getPipeadv(PeerID idPeer){ PipeAdvertisement pipeAdv = null; try{ pipeAdv = PipeUtilities.createPipeAdvertisement(); pipeAdv.setPipeID(IDFactory.newPipeID(this.pGID, (idPeer.hashCode()+"").getBytes()));// Usando o ID do grupo como seed ainda sem uso....toString().getBytes())); // Usando o ID do destino como seed variaremos o id pra conectar.... pipeAdv.setName("Inominavel..."); System.out.println("Peer Local......"+pipeAdv.toString()); }catch(Exception e){System.out.println("Deu erro no Adv#"+e.getLocalizedMessage());} return pipeAdv; } /** * Setter for property pGID. * @param pGID New value of property pGID. */ public void setPGID(PeerGroupID pGID) { this.pGID = pGID; // Define o pGID como sendo o ID do Grupo... necessário para a criação de um pipe... } } 71 Classe EnviadorDeMensagens.java /* * EnviadorDeMensagens.java * * Created on 1 de Novembro de 2005, 03:22 * * To change this template, choose Tools | Options and locate the template under * the Source Creation and Management node. Right-click the template and choose * Open. You can then make changes to the template in the Source Editor. */ package redepeertopeer; import import import import import java.io.IOException; net.jxta.discovery.DiscoveryService; net.jxta.endpoint.Message; net.jxta.endpoint.StringMessageElement; net.jxta.pipe.*; import import import import import import import import import import import import import import import import import import import import import import import import import import import import java.io.IOException; java.io.StringWriter; java.util.ArrayList; net.jxta.discovery.DiscoveryService; net.jxta.exception.PeerGroupException; net.jxta.peergroup.PeerGroup; net.jxta.peergroup.PeerGroupFactory; net.jxta.rendezvous.RendezVousService; net.jxta.discovery.DiscoveryEvent; net.jxta.discovery.DiscoveryListener; net.jxta.protocol.DiscoveryResponseMsg; net.jxta.protocol.PeerGroupAdvertisement; java.util.Enumeration; java.util.Vector; net.jxta.credential.AuthenticationCredential; net.jxta.credential.Credential; net.jxta.document.*; net.jxta.endpoint.Message; net.jxta.endpoint.MessageElement; net.jxta.endpoint.StringMessageElement; net.jxta.id.IDFactory; net.jxta.membership.Authenticator; net.jxta.membership.MembershipService; net.jxta.peer.PeerID; net.jxta.peergroup.PeerGroupID; net.jxta.protocol.PeerAdvertisement; net.jxta.protocol.PipeAdvertisement; net.jxta.util.PipeUtilities; /** * * @author REDIPS */ public class EnviadorDeMensagens implements OutputPipeListener{ static PeerGroup netPeerGroup = null; 72 static PeerGroup teste = null; private RendezVousService rdv; boolean descobriu = false; private ArrayList listaPeers; private Message msg; private InputPipe pipeIn = null; private IngressadorGrupo ingressadorGrupo; /** Creates a new instance of EnviadorDeMensagens */ private DiscoveryService descobridor; public EnviadorDeMensagens() { this.msg = new Message(); } public synchronized void enviaMsg(String mensagem, PipeAdvertisement pipeADV) { System.out.println("inicio metodo envia msn do enviador"); this.msg.clear(); enviou = false; try { descobridor.getRemoteAdvertisements(null, DiscoveryService.ADV, null, null, 1, null); if (msg!=null){ this.msg.addMessageElement(new StringMessageElement(null, mensagem, null)); } pipe.createOutputPipe(pipeADV, this); System.out.println("Chegou até aqui...."); } catch (IOException e) { System.out.println("OutputPipe creation failure"); e.printStackTrace(); System.exit(-1); } System.out.println("Chegou até aqui....(Fim método enviaMSG"+pipeADV); } public synchronized void enviaMsg(String mensagem, String sender, PipeAdvertisement pipeADV) { this.msg.clear(); enviou = false; System.out.println("inicio metodo envia msn do enviador"); try { descobridor.getRemoteAdvertisements(null, DiscoveryService.ADV, null, null, 1, null); if (msg!=null){ this.msg.addMessageElement("Sender", new StringMessageElement("Sender", sender, null)); this.msg.addMessageElement(new StringMessageElement(null, mensagem, null)); } pipe.createOutputPipe(pipeADV, this); System.out.println("Chegou até aqui...."); } catch (IOException e) { System.out.println("OutputPipe creation failure"); 73 e.printStackTrace(); System.exit(-1); } System.out.println("Chegou até aqui....(Fim método enviaMSG"); } public synchronized void outputPipeEvent(OutputPipeEvent event) { System.out.println(" Ativou o outputEvent..."); OutputPipe op = event.getOutputPipe(); Message msg = null; try { op.send(this.msg); } catch (IOException e) { System.out.println("failed to send message"); e.printStackTrace(); System.exit(-1); } op.close(); System.out.println("message sent"); this.enviou = true; } /** * Setter for property descobridor. * @param descobridor New value of property descobridor. */ public void setDescobridor(DiscoveryService descobridor) { this.descobridor = descobridor; } /** * Holds value of property enviou. */ private boolean enviou; /** * Getter for property enviou. * @return Value of property enviou. */ public boolean isEnviou() { return this.enviou; } /** * Holds value of property pipe. */ private PipeService pipe; public void setPipe(PipeService pipe) { this.pipe = pipe; } } 74 Classe EscutadorGrupo.java /* * EscutadorGrupo.java * * Created on 30 de Outubro de 2005, 16:07 * * To change this template, choose Tools | Options and locate the template under * the Source Creation and Management node. Right-click the template and choose * Open. You can then make changes to the template in the Source Editor. */ package redepeertopeer; import import import import import import import import java.util.Enumeration; net.jxta.discovery.DiscoveryEvent; net.jxta.discovery.DiscoveryListener; net.jxta.discovery.DiscoveryService; net.jxta.peergroup.PeerGroup; net.jxta.protocol.DiscoveryResponseMsg; net.jxta.protocol.PeerAdvertisement; net.jxta.protocol.PeerGroupAdvertisement; /** * * @author REDIPS */ public class EscutadorGrupo implements DiscoveryListener private boolean encontrou; private PeerGroupAdvertisement grupoAdv; { /** Creates a new instance of EscutadorGrupo */ public EscutadorGrupo() { encontrou = false; grupoAdv = null; } public synchronized void discoveryEvent(DiscoveryEvent ev) { this.setEncontrouFalso(); if(!encontrou) { DiscoveryResponseMsg res = ev.getResponse(); // // int tipoEvento = res.getDiscoveryType(); PeerGroup pg; System.out.println(" Got a Discovery Response [" + res.getResponseCount()+ " elements]"); PeerGroupAdvertisement adv = null; Enumeration en = res.getAdvertisements(); if (en != null ) { encontrou = true; while (en.hasMoreElements()) { adv = (PeerGroupAdvertisement) en.nextElement(); System.out.println(" Peer Group Name = " + adv.getName()); System.out.println(" Peer Group description = " + adv.getDescription()); 75 System.out.println(" Peer Group ID = " + adv.getID()); encontrou = true; this.grupoAdv = adv; } } } } /** * Getter for property encontrou. * @return Value of property encontrou. */ public boolean isEncontrou() { return this.encontrou; } /** * Holds value of property grupoAdv. */ /** * Getter for property grupo. * @return Value of property grupo. */ public PeerGroupAdvertisement getGrupoAdv() { return this.grupoAdv; } /** * Setter for property encontrou. * @param encontrou New value of property encontrou. */ public void setEncontrouFalso() { this.encontrou = false; } } 76 Classe IngressadorGrupo.java package redepeertopeer; import java.io.StringWriter; import java.util.ArrayList; import net.jxta.credential.AuthenticationCredential; import net.jxta.credential.Credential; import net.jxta.discovery.DiscoveryListener; import net.jxta.peergroup.PeerGroup; import net.jxta.discovery.DiscoveryService; import net.jxta.document.MimeMediaType; import net.jxta.document.StructuredDocument; import net.jxta.document.StructuredTextDocument; import net.jxta.endpoint.Message; import net.jxta.id.IDFactory; import net.jxta.membership.Authenticator; import net.jxta.membership.MembershipService; import net.jxta.peergroup.PeerGroupID; import net.jxta.pipe.InputPipe; import net.jxta.pipe.PipeService; import net.jxta.protocol.ModuleImplAdvertisement; import net.jxta.protocol.PeerGroupAdvertisement; import net.jxta.protocol.PipeAdvertisement; import net.jxta.rendezvous.RendezVousService; public class IngressadorGrupo{ EscutadorGrupo ouvidor; // static PeerGroup netPeerGroup = null; private DiscoveryService discovery; private RendezVousService rdv; static PeerGroup teste = null; boolean descobriu = false; private ArrayList listaPeers; private PipeAdvertisement pipeAdv, pipeAdvEntrada; private PipeService pipe; private Message msg; private InputPipe pipeIn = null; public IngressadorGrupo() { ouvidor = new EscutadorGrupo(); } private void mandarequisicao() { ouvidor.setEncontrouFalso(); this.discovery.addDiscoveryListener((DiscoveryListener)ouvidor); int cont = 0; try { // Add ourselves as a DiscoveryListener for DiscoveryResponse events while ((!(ouvidor.isEncontrou())&&(cont<5))) { System.out.println("Sending a Discovery Message"); discovery.getRemoteAdvertisements(null, DiscoveryService.GROUP, 77 "Name", "VoIPGateways", 1); cont++; try { Thread.sleep( 5* 1000); } catch(Exception e) {} } } catch(Exception e) { e.printStackTrace(); } // System.exit(0); } public synchronized PeerGroup crieGrupo(PeerGroup nPG, DiscoveryService discovery ) { PeerGroup retorno; this.discovery = discovery; PeerGroupAdvertisement adv; // advertisement for the new Peer group System.out.println("Creating a new group advertisement"); this.mandarequisicao(); try { if(!(ouvidor.isEncontrou())){ System.out.println("Não encontrou? Encontrou!!!!!"); // create a new all purpose peergroup. ModuleImplAdvertisement implAdv = nPG.getAllPurposePeerGroupImplAdvertisement(); // nPG. retorno = nPG.newGroup(IDFactory.newPeerGroupID("201548765105798765207289654213232985 463136546".getBytes()) , // Assign new group ID implAdv, // The implem. adv "VoIPGateways", // The name "grupo de gateways Voip"); // Helpful descr. // print the name of the group and the Peer group ID adv = retorno.getPeerGroupAdvertisement(); PeerGroupID GID = adv.getPeerGroupID(); System.out.println(" Group = " +adv.getName() + "\n Group ID = " + GID.toString()); } else{ System.out.println(" Encontrou!!!!!"); // create a new all purpose peergroup. retorno = nPG.newGroup(ouvidor.getGrupoAdv()); // print the name of the group and the Peer group ID adv = nPG.getPeerGroupAdvertisement(); PeerGroupID GID = adv.getPeerGroupID(); System.out.println(" Group = " +adv.getName() + "\n Group ID = " + GID.toString()); 78 } // publish this advertisement // (send out to other peers and rendezvous Peer) discovery.remotePublish(adv); nPG.globalRegistry.registerInstance(adv.getPeerGroupID(),retorno); System.out.println("Group published successfully.\n"); System.out.println("ID PEER depois de pegar no grupo...."+nPG.getPeerAdvertisement().getID().toString()); } catch (Exception e) { System.out.println("Error publishing group advertisement"); e.printStackTrace(); return (null); } return(retorno); } private void startJxta() { try { // netPeerGroup = PeerGroupFactory.newNetPeerGroup(); // } catch ( PeerGroupException e) { /*/ // could not instantiate the group, print the stack and exit System.out.println("fatal error : group creation failure"); e.printStackTrace(); System.exit(1); } */ peer group // Extract the discovery and rendezvous services from our // // discovery = netPeerGroup.getDiscoveryService(); rdv = netPeerGroup.getRendezVousService(); // Wait until we connect to a rendezvous peer System.out.print("Waiting to connect to rendezvous..."); while (! rdv.isConnectedToRendezVous()) { try { Thread.sleep(2000); } catch (InterruptedException ex) { // nothing, keep going } } System.out.println("connected!"); // crieGrupo(netPeerGroup).toString(); } public void entraNoGrupo(PeerGroup grp) { System.out.println("Joining peer group..."); StructuredDocument creds = null; try { // Generate the credentials for the Peer Group AuthenticationCredential authCred = new AuthenticationCredential( grp, null, creds ); 79 // Get the MembershipService from the Peer group MembershipService membership = grp.getMembershipService(); // Get the Authenticator from the Authentication creds Authenticator auth = membership.apply( authCred ); // Check if everything is okay to join the group if (auth.isReadyForJoin()){ Credential myCred = membership.join(auth); // display the credential as a plain text document. StructuredTextDocument doc = (StructuredTextDocument) myCred.getDocument(new MimeMediaType("text/plain")); StringWriter out = new StringWriter(); doc.sendToWriter(out); System.out.println(out.toString()); out.close(); } else System.out.println("Failure: unable to join group"); } catch (Exception e){ System.out.println("Failure in authentication."); e.printStackTrace(); } } public static void main(String[] args) { IngressadorGrupo n.startJxta(); n = new IngressadorGrupo(); // TODO code application logic here } } 80 Classe Peer.java /* * Peer.java * * Created on 28 de Outubro de 2005, 11:06 * * To change this template, choose Tools | Options and locate the template under * the Source Creation and Management node. Right-click the template and choose * Open. You can then make changes to the template in the Source Editor. */ package redepeertopeer; import net.jxta.peer.PeerID; /** * * @author REDIPS */ public class Peer { private String nome; private PeerID id; /** * Creates a new instance of Peer */ public Peer() { } public Peer(String nome, PeerID id){ this.nome = nome; this.id = id; } /** * Getter for property nome. * @return Value of property nome. */ public String getNome() { return this.nome; } /** * Setter for property nome. * @param nome New value of property nome. * * @throws PropertyVetoException if some vetoable listeners reject the new value */ public void setNome(String nome) throws java.beans.PropertyVetoException { this.nome = nome; } /** * Holds value of property id. 81 */ /** * Getter for property id. * @return Value of property id. */ public PeerID getId() { return this.id; } /** * Setter for property id. * @param id New value of property id. */ public void setId(PeerID id) { this.id = id; } } 82 Classe ResponsavelRede.java /** * * @author REDIPS */ public class ResponsavelRede implements DiscoveryListener, PipeMsgListener { private CriadorDeAdv criadorDeAdv; static PeerGroup netPeerGroup = null; static PeerGroup grupoVoIP; private DiscoveryService discovery; private RendezVousService rdv; boolean descobriu = false; private ArrayList listaPeers; private PipeAdvertisement pipeAdv, pipeAdvEntrada; private PipeService pipe; private Message msg; private InputPipe pipeIn = null; private IngressadorGrupo ingressadorGrupo; private EnviadorDeMensagens enviadorDeMSG; private ArrayList msgRecebidas; public ResponsavelRede() { ingressadorGrupo = new IngressadorGrupo(); criadorDeAdv = new CriadorDeAdv(); enviadorDeMSG = new EnviadorDeMensagens(); msgRecebidas = new ArrayList(); listaPeers = new ArrayList(); this.inicializaJXTA(); } public void descubraPeers(String nomePeer){ descobriu = false; listaPeers.clear(); discovery.addDiscoveryListener(this); // while(!descobriu){ try{ System.out.println("Sending a Discovery Message"); discovery.getRemoteAdvertisements(null, DiscoveryService.PEER, "Name", nomePeer+"*", 5); Thread.sleep(15*1000); //Dorme 10 seg para aguardar a resposta de pelo menos 1 Peer... } catch(Exception e){ //Erro no tempo.... } // } } public synchronized boolean envia_MsgPeer(int carinha,String mensagem){ boolean resposta = false; Peer aux = (Peer)listaPeers.get(carinha); System.out.println("mmmmmmmmmmmmmmmmmmmmmmmmmmmMétodo enviaMSG"); 83 PipeAdvertisement pipeADV = this.criadorDeAdv.getPipeadv(aux.getId()); this.enviadorDeMSG.enviaMsg(mensagem,netPeerGroup.getPeerName(), pipeADV); try{ Thread.sleep(10*1000); }catch(Exception e){} resposta = this.enviadorDeMSG.isEnviou(); return resposta; } public synchronized String[] getListaNomes(){ String [] resposta = new String[listaPeers.size()]; Peer auxiliar; for (int i=0; i< listaPeers.size(); i++){ auxiliar = (Peer)listaPeers.get(i); resposta[i] = auxiliar.getNome(); } return resposta; } private void inicializaJXTA() { try { netPeerGroup = PeerGroupFactory.newNetPeerGroup(); discovery = netPeerGroup.getDiscoveryService(); rdv = netPeerGroup.getRendezVousService(); pipe = netPeerGroup.getPipeService(); enviadorDeMSG.setDescobridor(discovery); enviadorDeMSG.setPipe(pipe); } catch ( PeerGroupException e) { System.out.println("Erro na criação do Grupo..."); e.printStackTrace(); System.exit(1); } } public boolean conecta(){ System.out.print("Aguardando conexão com rendezvous..."); while (! rdv.isConnectedToRendezVous()) { try { wait(); // Thread.sleep(1000); } catch (Exception ex) { } } grupoVoIP = ingressadorGrupo.crieGrupo(netPeerGroup, discovery); ingressadorGrupo.entraNoGrupo(grupoVoIP); criadorDeAdv.setPGID(grupoVoIP.getPeerGroupID()); PipeAdvertisement adv = criadorDeAdv.getPipeadv(netPeerGroup.getPeerID()); System.out.println("adv"+adv.toString()); try{ 84 pipeIn = pipe.createInputPipe(adv, this); System.out.println("Creating input pipe"); } catch (Exception e) { System.out.println("IXXI DEU ERRO no pipe in..."+e.getMessage()); return false; } if (pipeIn == null) { System.out.println(" cannot open InputPipe"); System.exit(-1); } // System.out.println("Waiting for msgs on input pipe"); System.out.println("Xablim!!!!! Está conectado..."); return true; } public boolean desconecta(){ rdv.stopRendezVous(); return true; } public void pipeMsgEvent(PipeMsgEvent event) { Message msg=null; try { // grab the message from the event msg = event.getMessage(); if (msg == null) { return; } } catch (Exception e) { e.printStackTrace(); return; } Message.ElementIterator en = msg.getMessageElements(); MessageElement msgElement; if (!en.hasNext()) { return; } while (en.hasNext()){ msgElement = (MessageElement)en.next(); System.out.println("mensagem...."+msgElement.toString()); this.adicionaMensagem(msgElement.toString()); } } public synchronized void discoveryEvent(DiscoveryEvent ev) { DiscoveryResponseMsg res = ev.getResponse(); int tipoEvento = res.getDiscoveryType(); switch (tipoEvento){ case DiscoveryService.PEER:{ System.out.println("Got a Discovery Response [" + 85 res.getResponseCount() + " elements] from peer: "); PeerAdvertisement adv = null; Enumeration en = res.getAdvertisements(); if (en != null ) { descobriu = true; Peer p; while (en.hasMoreElements()) { adv = (PeerAdvertisement) en.nextElement(); p = new Peer(adv.getName(), adv.getPeerID()); if(!this.verificaSeExiste(listaPeers, p)) listaPeers.add(p); System.out.println("peer Descoberto..."+adv.getName()); descobriu = true; } } break;} } } private synchronized boolean verificaSeExiste(ArrayList lista, Peer p){ Peer aux; boolean auxiliar; for (int i=0; i < lista.size();i++){ auxiliar = ((Peer)lista.get(i)).getNome().equals(p.getNome()); if (auxiliar) return true; } return false; } public boolean possuiMSG(){ if(msgRecebidas.size()==0) return false; else return true; } private void zeraMsgRecebidas() { msgRecebidas.clear(); } public String[] getMensagensRecebidas(){ String[] resposta = new String[msgRecebidas.size()]; for(int i =0; i<msgRecebidas.size();i++){ resposta[i] = (String) msgRecebidas.get(i); } for(int i =0; i<msgRecebidas.size();i++){ System.out.println("MSG RECEBDAS "+ (String) msgRecebidas.get(i)); } 86 this.zeraMsgRecebidas(); return resposta; } public void adicionaMensagem(String msgRecebida) { this.msgRecebidas.add(msgRecebida); } } 87 Anexo VII. Interface gráfica Classe InterfaceGrafica.java /* * InterfaceGrafica.java * * Created on 26 de Outubro de 2005, 20:41 */ package interfacegrafica; import java.awt.Color; import java.awt.event.ActionEvent; import javax.swing.DefaultListModel; import javax.swing.JOptionPane; import redepeertopeer.ResponsavelRede; import redepeertopeer.Peer; /** * * @author REDIPS */ public class InterfaceGrafica extends javax.swing.JFrame{ /** * Creates new form InterfaceGrafica */ public InterfaceGrafica() { initComponents(); painel = new JOptionPane(); conectado = false; listaPencontrados = new DefaultListModel(); listaIDMSGRecebidas = new DefaultListModel(); listaMSGRecebidas = new DefaultListModel(); this.jLteste.setModel(listaPencontrados); this.jList2.setModel(listaIDMSGRecebidas); this.jList1.setModel(listaMSGRecebidas); //this.run(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ public void conhecaResponsavelRede(ResponsavelRede umCaraDaRede){ this.umcaraDaRede = umCaraDaRede; System.out.println("conheceu"); } private void mandaProcurar(){ if (!(this.jTFPesquisar.getText().length() !=2)){ // Alterar pra 4 na hora do vamso ver! this.listaPencontrados.removeAllElements(); if(this.isConectado()){ String[] lista; int aux; 88 this.jLStatus.setForeground(this.AZUL); this.jLStatus.setText(" pesquisando...."); Peer auxiliar; this.umcaraDaRede.descubraPeers(this.jTFPesquisar.getText()); /* try{ Thread.sleep(5 * 1000);// Descanço pra ver se pega o número de peers }catch(Exception e){}*/ lista = this.umcaraDaRede.getListaNomes(); for(int i = 0; i < lista.length; i++){ listaPencontrados.addElement(lista[i]); } this.jLStatus.setText( "Pesquisa Concluída....encontrados "+ lista.length+" elementos."); this.jLStatus.setForeground(this.PRETO); } else painel.showMessageDialog(this,"Voce não está conectado!!!", "ATENCAO!!!",painel.ERROR_MESSAGE); } else painel.showMessageDialog(this,"Digite apenas 4 caracteres", "ATENCAO!!!",painel.ERROR_MESSAGE); } public void run(){ System.out.println("Vamos ver se esse método é executado, pelo menos uma vez....."); while(true){ try{ Thread.sleep(30*1000); }catch(Exception e){} if (this.umcaraDaRede.possuiMSG()){ String[] listaMensagens; listaMensagens = this.umcaraDaRede.getMensagensRecebidas(); for( int i = 0; i < listaMensagens.length; i = i + 2){ this.listaIDMSGRecebidas.addElement(listaMensagens[i]); this.listaMSGRecebidas.addElement(listaMensagens[i+1]); } } } } // <editor-fold defaultstate="collapsed" desc=" Generated Code "> private void initComponents() { jPanel2 = new javax.swing.JPanel(); jTFPesquisar = new javax.swing.JTextField(); jBTProcura = new javax.swing.JButton(); jPanel5 = new javax.swing.JPanel(); jLStatus = new javax.swing.JLabel(); jPanel8 = new javax.swing.JPanel(); jScrollPane2 = new javax.swing.JScrollPane(); jList1 = new javax.swing.JList(); jPanel9 = new javax.swing.JPanel(); jScrollPane3 = new javax.swing.JScrollPane(); jList2 = new javax.swing.JList(); jPanel10 = new javax.swing.JPanel(); jLabel2 = new javax.swing.JLabel(); jLMsgRec = new javax.swing.JLabel(); 89 jLabel1 = new javax.swing.JLabel(); jPanel3 = new javax.swing.JPanel(); jLbPeersLocalizados = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); jLteste = new javax.swing.JList(); jPanel7 = new javax.swing.JPanel(); jPanel4 = new javax.swing.JPanel(); jBTenviaMSG = new javax.swing.JButton(); jBLimpaResultado = new javax.swing.JButton(); jPanel6 = new javax.swing.JPanel(); JBTVerDetalhes = new javax.swing.JButton(); jPanel1 = new javax.swing.JPanel(); jBTConecta = new javax.swing.JButton(); jBTDesconecta = new javax.swing.JButton(); jBTSaiFora = new javax.swing.JButton(); jMenuBar2 = new javax.swing.JMenuBar(); jMArquivo = new javax.swing.JMenu(); jMIConecta = new javax.swing.JMenuItem(); jMIDesconecta = new javax.swing.JMenuItem(); jSeparator1 = new javax.swing.JSeparator(); jMISair = new javax.swing.JMenuItem(); jMAjuda = new javax.swing.JMenu(); jMIAjuda = new javax.swing.JMenuItem(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("Gatewaysss VOIP"); jPanel2.setLayout(new java.awt.BorderLayout()); jPanel2.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0))); jTFPesquisar.addKeyListener(new java.awt.event.KeyAdapter() { public void keyPressed(java.awt.event.KeyEvent evt) { jTFPesquisarKeyPressed(evt); } }); jPanel2.add(jTFPesquisar, java.awt.BorderLayout.CENTER); jBTProcura.setMnemonic('P'); jBTProcura.setText("Pesquisar"); jBTProcura.setToolTipText("Localise o gateway"); jBTProcura.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jBTProcuraActionPerformed(evt); } }); jPanel2.add(jBTProcura, java.awt.BorderLayout.EAST); jPanel5.setLayout(new java.awt.BorderLayout()); jPanel5.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0))); jLStatus.setText("Desconectado"); jPanel5.add(jLStatus, java.awt.BorderLayout.SOUTH); jScrollPane2.setViewportView(jList1); jPanel8.add(jScrollPane2); jPanel5.add(jPanel8, java.awt.BorderLayout.EAST); 90 jScrollPane3.setViewportView(jList2); jPanel9.add(jScrollPane3); jPanel5.add(jPanel9, java.awt.BorderLayout.WEST); jPanel10.setLayout(new java.awt.GridLayout(1, 2)); jLabel2.setText(" jPanel10.add(jLabel2); Remetente"); jLMsgRec.setText("Mensagem Recebida"); jPanel10.add(jLMsgRec); jLMsgRec.getAccessibleContext().setAccessibleName("Mensagem Recebida"); jPanel5.add(jPanel10, java.awt.BorderLayout.NORTH); jPanel2.add(jPanel5, java.awt.BorderLayout.SOUTH); jLabel1.setText(" Localiza\u00e7\u00e3o de Gateways"); jLabel1.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0))); jPanel2.add(jLabel1, java.awt.BorderLayout.NORTH); getContentPane().add(jPanel2, java.awt.BorderLayout.SOUTH); jPanel3.setLayout(new java.awt.BorderLayout()); jPanel3.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0))); jLbPeersLocalizados.setText(" Peers encontrados"); jPanel3.add(jLbPeersLocalizados, java.awt.BorderLayout.NORTH); jLteste.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0))); jLteste.setValueIsAdjusting(true); jScrollPane1.setViewportView(jLteste); jPanel3.add(jScrollPane1, java.awt.BorderLayout.CENTER); getContentPane().add(jPanel3, java.awt.BorderLayout.CENTER); jPanel7.setLayout(new java.awt.GridLayout(2, 0, 0, 5)); jPanel4.setLayout(new java.awt.GridLayout(2, 0, 0, 2)); jPanel4.setAutoscrolls(true); jBTenviaMSG.setMnemonic('n'); jBTenviaMSG.setText("Envia MSG"); jBTenviaMSG.setHorizontalAlignment(javax.swing.SwingConstants.LEADING); jBTenviaMSG.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT); jBTenviaMSG.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jBTenviaMSGActionPerformed(evt); } }); 91 jPanel4.add(jBTenviaMSG); jBLimpaResultado.setText("Limpa Resultados"); jBLimpaResultado.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jBLimpaResultadoActionPerformed(evt); } }); jPanel4.add(jBLimpaResultado); jPanel7.add(jPanel4); jPanel6.setLayout(new java.awt.GridLayout(1, 0)); JBTVerDetalhes.setMnemonic('C'); JBTVerDetalhes.setText("Ver Detalhes"); JBTVerDetalhes.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { JBTVerDetalhesActionPerformed(evt); } }); jPanel6.add(JBTVerDetalhes); jPanel7.add(jPanel6); getContentPane().add(jPanel7, java.awt.BorderLayout.EAST); jPanel1.setLayout(new java.awt.GridLayout(1, 3)); jBTConecta.setMnemonic('C'); jBTConecta.setText("Conectar"); jBTConecta.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jBTConectaActionPerformed(evt); } }); jPanel1.add(jBTConecta); jBTDesconecta.setMnemonic('D'); jBTDesconecta.setText("Desconectar"); jBTDesconecta.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jBTDesconectaActionPerformed(evt); } }); jPanel1.add(jBTDesconecta); jBTSaiFora.setMnemonic('S'); jBTSaiFora.setText("Sartar Fora!!!"); jBTSaiFora.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jBTSaiForaActionPerformed(evt); } }); 92 jPanel1.add(jBTSaiFora); getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH); jMArquivo.setText("Arquivo"); jMIConecta.setMnemonic('C'); jMIConecta.setText("Conectar"); jMIConecta.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMIConectaActionPerformed(evt); } }); jMArquivo.add(jMIConecta); jMIDesconecta.setMnemonic('D'); jMIDesconecta.setText("Desconecta"); jMIDesconecta.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMIDesconectaActionPerformed(evt); } }); jMArquivo.add(jMIDesconecta); jMArquivo.add(jSeparator1); jMISair.setMnemonic('S'); jMISair.setText("Sair"); jMISair.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jMISairActionPerformed(evt); } }); jMArquivo.add(jMISair); jMenuBar2.add(jMArquivo); jMAjuda.setText("Ajuda"); jMIAjuda.setMnemonic('S'); jMIAjuda.setText("Sobre"); jMAjuda.add(jMIAjuda); jMenuBar2.add(jMAjuda); setJMenuBar(jMenuBar2); pack(); } // </editor-fold> private void JBTVerDetalhesActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: } private void jTFPesquisarKeyPressed(java.awt.event.KeyEvent evt) { if(evt.getKeyCode()==evt.VK_ENTER){ 93 this.mandaProcurar(); } } private void jBTenviaMSGActionPerformed(java.awt.event.ActionEvent evt) { String mensagem = painel.showInputDialog(this,"Digite uma mensagem...."); System.out.println(" Valor de s = "+mensagem); System.out.println(" valor" +this.jLteste.getSelectedIndex()); if (umcaraDaRede.envia_MsgPeer(this.jLteste.getSelectedIndex(), mensagem)){ this.jLStatus.setForeground(this.VERDE); this.jLStatus.setText("Mensagem enviada com sucesso...."); }else{ this.jLStatus.setForeground(this.VERMELHO); this.jLStatus.setText("ERRO NO ENVIO...."); } // TODO add your handling code here:) } private void jBLimpaResultadoActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: this.listaPencontrados.clear(); } private void jBTSaiForaActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: jMISairActionPerformed(evt); } private void jMISairActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: System.exit(0); } private void jMIDesconectaActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: jBTDesconectaActionPerformed(evt); } private void jMIConectaActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: jBTConectaActionPerformed(evt); } private void jBTDesconectaActionPerformed(java.awt.event.ActionEvent evt) { 94 this.jLStatus.setText("Desconectando"); if(this.umcaraDaRede.desconecta()){ painel.showMessageDialog(this,"Desconectado com Sucesso","Desconectado",painel.INFORMATION_MESSAGE); this.setConectado(false); } this.jLStatus.setText(" Desconectado...."); this.jLStatus.setForeground(this.VERMELHO); // TODO add your handling code here: } private void jBTConectaActionPerformed(java.awt.event.ActionEvent evt) { this.jLStatus.setForeground(this.VERDE); this.jLStatus.setText("Conectando.........."); if(this.umcaraDaRede.conecta()){ // painel.showMessageDialog(this,"Conectado","Conectado",painel.INFORMATION_MESS AGE); this.setConectado(true); } this.jLStatus.setText(" Conectado"); this.jLStatus.setForeground(this.PRETO); // TODO add your handling code here: } private void jBTProcuraActionPerformed(java.awt.event.ActionEvent evt) { this.mandaProcurar(); } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new InterfaceGrafica().setVisible(true); } }); } // Variables declaration - do not modify private javax.swing.JButton JBTVerDetalhes; private javax.swing.JButton jBLimpaResultado; private javax.swing.JButton jBTConecta; private javax.swing.JButton jBTDesconecta; private javax.swing.JButton jBTProcura; private javax.swing.JButton jBTSaiFora; private javax.swing.JButton jBTenviaMSG; private javax.swing.JLabel jLMsgRec; private javax.swing.JLabel jLStatus; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLbPeersLocalizados; private javax.swing.JList jList1; private javax.swing.JList jList2; private javax.swing.JList jLteste; private javax.swing.JMenu jMAjuda; private javax.swing.JMenu jMArquivo; 95 private javax.swing.JMenuItem jMIAjuda; private javax.swing.JMenuItem jMIConecta; private javax.swing.JMenuItem jMIDesconecta; private javax.swing.JMenuItem jMISair; private javax.swing.JMenuBar jMenuBar2; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel10; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JPanel jPanel4; private javax.swing.JPanel jPanel5; private javax.swing.JPanel jPanel6; private javax.swing.JPanel jPanel7; private javax.swing.JPanel jPanel8; private javax.swing.JPanel jPanel9; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JScrollPane jScrollPane3; private javax.swing.JSeparator jSeparator1; private javax.swing.JTextField jTFPesquisar; // End of variables declaration private ResponsavelRede umcaraDaRede; private JOptionPane painel; private DefaultListModel listaPencontrados; private DefaultListModel listaIDMSGRecebidas; private DefaultListModel listaMSGRecebidas; private final Color PRETO = new Color(0.0f,0.0f,0.0f); private final Color VERDE = new Color(0.0f,1.0f,0.0f); private final Color VERMELHO = new Color(1.0f,0.0f,0.0f); private final Color AZUL = new Color(0.0f,0.0f,1.0f); private boolean conectado; public boolean isConectado() { return this.conectado; } public void setConectado(boolean conectado) { this.conectado = conectado; } }