00001 /* 00002 * Copyright (C) 2009, Edmundo Albuquerque de Souza e Silva. 00003 * 00004 * This file may be distributed under the terms of the Q Public License 00005 * as defined by Trolltech AS of Norway and appearing in the file 00006 * LICENSE.QPL included in the packaging of this file. 00007 * 00008 * THIS FILE IS PROVIDED AS IS WITH NO WARRANTY OF ANY KIND, INCLUDING 00009 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00010 * PURPOSE. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, 00011 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 00012 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 00013 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 00014 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 00015 * 00016 * Thanks: Jose Renato Santos 00017 * 00018 */ 00019 00020 #include <pthread.h> 00021 #include <sys/time.h> 00022 #include <time.h> 00023 // cabecalhos do C++ (STL). 00024 #include <map> 00025 #include <queue> 00026 #include <vector> 00027 00028 #include "RioNeti.h" 00029 #include "RioError.h" 00030 #include "RioUnix.h" 00031 00032 #ifndef STREAMCONTROL_H_ 00033 #define STREAMCONTROL_H_ 00034 00035 #define MAXIDLECOUNT 1000 /** Numero de vezes que teremos que verificar a 00036 * lista de um cliente vazia (sem fragmentos a 00037 * serem enviados) antes de removermos a lista 00038 * deste cliente. 00039 */ 00040 00041 /** Estrutura com as informacoes para cada Fragment. */ 00042 struct FragmentInfo 00043 { 00044 char *FragmentData; /**< ponteiro para os dados do fragmento a ser enviado. 00045 */ 00046 int FragmentSize; /**< Tamanho dos dados deste fragmento. */ 00047 int IP; /**< Endereco IP do destino */ 00048 int Port; /**< Porta do destino */ 00049 unsigned long long int TimeBetweenCredits; /**< Tempo em que os creditos 00050 * associados a estes fragmentos 00051 * devem ser atualizados. */ 00052 }; 00053 00054 /** Lista simplesmente encadeada com objetos do tipo FragmentInfo. Ela sera 00055 * usada como uma fila FIFO. 00056 */ 00057 struct FragmentInfoList 00058 { 00059 struct FragmentInfo *fip; /**< Ponteiro para o fragmento associado a esta 00060 * entrada da lista. */ 00061 struct FragmentInfoList *NextObject; /**< Ponteiro para o proximo fragmento 00062 * da lista */ 00063 }; 00064 00065 /** Classe base usada para gerenciar uma fila FIFO de objetos FragmentInfo. Ela 00066 * e usada como base para as classes CLeakBucket e CFPool (indiretamente 00067 * tambem pela classe CSendData, que como veremos sera derivada de 00068 * CLeakBucket). Ela implementa duas funcoes: Insert para inserir objetos 00069 * FragmentInfo no final da fila e Remove para remover objetos FragmentInfo do 00070 * inicio da fila. Um mutex e usado para acessar a fila, para garantir o 00071 * acesso exclusivo, pois como veremos duas threads diferentes usarao as 00072 * funcoes Insert e Remove (indiratamente, pelas classes que serao derivadas 00073 * dela). 00074 */ 00075 class CFragmentQueue 00076 { 00077 private: 00078 /** Ponteiro para o primeiro objeto da fila FIFO com os objetos 00079 * FragmentInfo. 00080 */ 00081 struct FragmentInfoList *m_Start; 00082 /** Ponteiro para o ultimo objeto da fila FIFO com os objetos 00083 * FragmentInfo. 00084 */ 00085 struct FragmentInfoList *m_End; 00086 #ifdef RIO_DEBUG2 00087 /** Variavel usada para contar o numero de elementos na fila FIFO 00088 * (usada para impressao, para evitar atrasos ao imprimir o tamanho 00089 * da fila). 00090 */ 00091 unsigned int FragmentQueueSize; 00092 #endif 00093 00094 /** 00095 * DeleteFragmentQueue funcao usada para remover a fila FIFO com os 00096 * fragmentos. Usada pelo destrutor ao removermos um objeto da classe. 00097 */ 00098 void DeleteFragmentQueue(); 00099 public: 00100 /** 00101 * CFragmentQueue construtor da classe, chamado quando um objeto e 00102 * criado usando o comando new. 00103 */ 00104 CFragmentQueue(); 00105 00106 /** 00107 * ~CFragmentQueue destrutor da classe, chamado quando um objeto e 00108 * removido usando o comando delete. 00109 */ 00110 virtual ~CFragmentQueue(); 00111 00112 /** 00113 * Insert Insere um objeto FragmentInfo no final da fila. 00114 * @param fip ponteiro para o objeto a ser inserido no final da fila. 00115 * @return S_OK se o objeto foi corretamente inserido na fila, e valor 00116 * diferente de S_OK se algum erro ocorreu ao inserir o objeto. 00117 */ 00118 virtual int Insert( FragmentInfo *fip ); 00119 00120 /** 00121 * Remove remove um objeto FragmentInfo do inicio da fila. 00122 * @result Ponteiro para o objeto que estava no inicio da fila, se a 00123 * fila nao estiver vazia, ou NULL caso ela esteja vazia. 00124 */ 00125 virtual FragmentInfo *Remove(); 00126 00127 /** 00128 * IsEmpty verifica se a fila esta vazia. 00129 * @result valor booleano que sera true se a fila estiver vazia, e false 00130 * se ela nao estiver vazia. 00131 */ 00132 virtual bool IsEmpty(); 00133 00134 #ifdef RIO_DEBUG2 00135 /** 00136 * PrintFragmentQueue Imprime informacoes sobre a fila associada a classe 00137 * CFragmentQueue. 00138 * @param QueueInfo ponteiro para uma mensagem que sera mostrada ao 00139 * imprimirmos as informacoes da fila. 00140 */ 00141 virtual void PrintFragmentQueue( const char *QueueInfo ); 00142 #endif 00143 }; 00144 00145 /** Classe para implementar a estrutura de dados usada pelo Leak Bucket. Esta 00146 * estrutura sera uma fila FIFO. Logo, a funcao de insercao colocara um objeto 00147 * no final da lista e a funcao de remocao retirara o objeto do inicio da 00148 * fila. A classe tambem ira implementar um mutex para acessar a classe, pois 00149 * as funcoes Insert e Remove serao usadas por threads diferentes, assim como 00150 * as funcoes que gerenciam os creditos (AddCredits, MaxCredits, 00151 * AvaliableCredits e VerifyCredits). 00152 */ 00153 00154 class CLeakBucket : public CFragmentQueue 00155 { 00156 private: 00157 /** Numero maximo de creditos. */ 00158 unsigned int m_MaxCredits; 00159 /** Numero de creditos atual. */ 00160 unsigned int m_Credits; 00161 /** Tempo da ultima atualizacao dos creditos (em microsegundos). */ 00162 unsigned long long int m_LastUpdateCredits; 00163 /** Tempo que deve ser passado entre as atualizacoes (em 00164 * microsegundos). 00165 */ 00166 unsigned long long int m_TimeBetweenCredits; 00167 00168 /** 00169 * SetMaxCredits altera o numero maximo de creditos a serem 00170 * contabilizados por um objeto da classe. 00171 * @param Value novo valor para o numero maximo de creditos. 00172 */ 00173 void SetMaxCredits( unsigned int Value ); 00174 00175 /** 00176 * SetTimeBetweenCredits altera o tempo (em microsegundos) entre duas 00177 * atualizacoes do credito de um objeto da classe. 00178 * @param Value novo tempo entre as duas atualizacoes de credito. 00179 */ 00180 void SetTimeBetweenCredits( unsigned long long int Value ); 00181 #ifdef RIO_DEBUG2 00182 /** 00183 * PrintLeakBucketInfo imprime as informacoes (os valores dos campos 00184 * internos) de um objeto associado a classe. 00185 * @param LeakBucketInfo ponteiro para uma mensagem que sera mostrada ao 00186 * imprimirmos as informacoes de um objeto da classe. 00187 */ 00188 void PrintLeakBucketInfo( const char *LeakBucketInfo ); 00189 #endif 00190 protected: 00191 /** 00192 * GetCredits retorna o numero de creditos de um objeto da classe. 00193 * @return numero de creditos do objeto. 00194 */ 00195 unsigned int GetCredits(); 00196 00197 /** 00198 * GetMaxCredits retorna o numero maximo de creditos de um objeto da 00199 * classe. 00200 * @return numero maximo de creditos do objeto. 00201 */ 00202 unsigned int GetMaxCredits(); 00203 00204 /** 00205 * AddCredits adiciona creditos ao numero de creditos de um objeto da 00206 * classe. 00207 * @param Value numero de creditos a serem adicionados ao credito do 00208 * objeto. 00209 */ 00210 virtual void AddCredits( unsigned int Value ); 00211 00212 /** 00213 * DecCredits decrementa o numero de creditos de um objeto da classe em 1 00214 * unidade. 00215 */ 00216 virtual void DecCredits(); 00217 public: 00218 /** 00219 * CLeakBucket construtor da classe, chamado quando um novo objeto e 00220 * criado com o comando new. 00221 * @param MaxCredits valor inteiro (nao sinalizado), definindo o numero 00222 * maximo de creditos a serem contabilizados pelo objeto criado. 00223 * @param TimeBetweenCredits tempo em microsegundos entre duas 00224 * atualizacoes do credito do objeto. 00225 */ 00226 CLeakBucket( unsigned int MaxCredits, 00227 unsigned long long int TimeBetweenCredits ); 00228 00229 /** 00230 * ~CLeakBucket destrutor da classe, chamado quando um objeto e removido 00231 * com o comando delete. 00232 */ 00233 virtual ~CLeakBucket(); 00234 00235 /** 00236 * VerifyCredits verifica se um objeto da classe possui creditos. 00237 * @return true se o objeto possuir creditos, ou false em caso 00238 * contrario. 00239 */ 00240 virtual bool VerifyCredits(); 00241 00242 /** 00243 * Remove remove um dos elementos do inicio da fila FIFO de um objeto da 00244 * classe, se a fila nao estiver vazia e se este objeto possuir 00245 * creditos. Depois da remocao do elemento do inicio da fila, o numero 00246 * de creditos do objeto sera decrementado em 1 unidade. 00247 * @return ponteiro para o elemento do inicio da fila que foi removido, 00248 * se o objeto possuir creditos e a fila nao estiver vazia, ou NULL em 00249 * caso contrario (isto e, se a fila estiver vazia ou se o objeto nao 00250 * possuir creditos). 00251 */ 00252 virtual FragmentInfo *Remove(); 00253 00254 /** 00255 * UpdateCredits atualiza, se necessario, o numero de creditos de um 00256 * objeto da classe. Se o tempo entre as atualizacoes nao passou, o 00257 * credito nao sera atualizado, e se mais tempo passou, o numero de 00258 * creditos sera aumentado de acordo (por exemplo, se decorreu um tempo 00259 * tres vezes maior do que o da atualizacao, o credito sera aumentado em 00260 * 3 unidades). 00261 */ 00262 virtual void UpdateCredits(); 00263 /** 00264 * NextTimeToUpdateCredits retorna o tempo, em microsegundos, da proxima 00265 * atualizacao do credito. Este tempo e o mesmo dado pela funcao 00266 * gettimeofday da biblioteca C do Linux, isto e, o numero de segundos 00267 * decorridos desde 0 horas 0 minutos e 0 segundos de 1 de janeiro de 00268 * 1970 (isso e chamado de "Epoch" no Linux, e e formalmente definido 00269 * como "00:00:00 UTC, January 1, 1970"). 00270 * @return tempo da proxima atualizacao do credito. 00271 */ 00272 virtual unsigned long long int NextTimeToUpdateCredits(); 00273 }; 00274 00275 /** Classe para implementar a fila FIFO dos objetos FragmentInfo que estao 00276 * esperando para serem enviados. A classe e derivada da anterior (LeackBucket) 00277 * e implementa uma variavel de condicao que ira bloquear a thread que chamar a 00278 * funcao Remove caso a fila esteja vazia. 00279 */ 00280 class CSendData : public CLeakBucket 00281 { 00282 private: 00283 /** Mutex para garantir o acesso exclusivo as variaveis MaxCredits e 00284 * Credits. 00285 */ 00286 pthread_mutex_t m_AccessLeakBucket; 00287 /** Mutex para garantir o acesso exclusivo a fila FIFO. */ 00288 pthread_mutex_t m_AccessFragmentQueue; 00289 /** Variavel de condicao usada pela thread que envia os objetos 00290 * FragmentInfo para esperar pelo evento indicando que a fila FIFO da 00291 * classe, com objetos FragmentInfo, deixou de ficar vazia. 00292 */ 00293 pthread_cond_t m_WaitObject; 00294 /** Variavel de condicao usada pela thread que envia os objetos 00295 * FragmentInfo para esperar por creditos para enviar um objeto 00296 * FragmentInfo. 00297 */ 00298 pthread_cond_t m_WaitCredits; 00299 /** Variavel de condicao usada para bloquear a thread que incrementa 00300 * os creditos da classe caso estes ja estejam no maximo. A funcao 00301 * DecCredits, dada a seguir, ira desbloquear a thread ao decrementar 00302 * os creditos. 00303 */ 00304 pthread_cond_t m_WaitUseCredits; 00305 00306 /** 00307 * DecCredits decrementa o numero de creditos de um objeto da classe em 00308 * 1 unidade. Note que esta funcao desbloqueara a thread bloqueada na 00309 * variavel de condicao m_WaitUseCredits (a que incrementa os creditos 00310 * da classe) caso o numero de creditos estivesse em seu valor maximo, 00311 * pois agora a thread pode voltar a incrementar os creditos do objeto. 00312 */ 00313 void DecCredits(); 00314 public: 00315 /** 00316 * CSendData construtor da classe, chamado quando um objeto e criado 00317 * usando o comando new. Esta classe e derivada da classe CLeakBucket, 00318 * descrita anteriormente. 00319 * @param MaxCredits valor inteiro (nao sinalizado), definindo o numero 00320 * maximo de creditos a serem contabilizados pelo objeto criado. 00321 * @param TimeBetweenCredits tempo em microsegundos entre duas 00322 * atualizacoes do credito do objeto. 00323 */ 00324 CSendData( unsigned int MaxCredits, 00325 unsigned long long int TimeBetweenCredits ); 00326 00327 /** 00328 * ~CSendData destrutor da classe, chamado quando um objeto e removido 00329 * com o comando delete. 00330 */ 00331 ~CSendData(); 00332 00333 /** 00334 * Insert Insere um objeto FragmentInfo no final da fila. Se a fila 00335 * estava vazia antes da insercao do elemento, um sinal sera enviado a 00336 * thread que foi bloqueada na variavel de condicao m_WaitObject ao 00337 * executar a funcao Remove dada a seguir, pois agora existem elementos 00338 * a serem removidos da fila. 00339 * @param fip ponteiro para o objeto a ser inserido no final da fila. 00340 * @return S_OK se o objeto foi corretamente inserido na fila, e valor 00341 * diferente de S_OK se algum erro ocorreu ao inserir o objeto. 00342 */ 00343 int Insert( FragmentInfo *fip ); 00344 00345 /** 00346 * Remove remove um dos elementos do inicio da fila FIFO de um objeto da 00347 * classe, se a fila nao estiver vazia e se este objeto possuir 00348 * creditos. Depois da remocao do elemento do inicio da fila, o numero 00349 * de creditos da classe sera decrementado em 1 unidade. Se o objeto na 00350 * classe nao possuir creditos, a thread que chamou a funcao sera 00351 * bloqueada na variavel de condicao m_WaitCredits (esperando que seja 00352 * desbloqueada pela funcao UpdateCretids). Se o objeto possuir creditos 00353 * e se a fila estiver vazia , a thread que chamou a funcao sera 00354 * bloqueada na variavel de condicao m_WaitObject, ate que um elemento 00355 * seja inserido na fila pela funcao Insert. 00356 * @return ponteiro para o elemento do inicio da fila que foi removido. 00357 * Note, pelo que foi descrito anteriormente, que a funcao somente 00358 * retornara se o objeto possuir creditos e existir pelo menos um 00359 * elemento na fila. 00360 */ 00361 FragmentInfo *Remove(); 00362 00363 /** 00364 * UpdateCredits atualiza o numero de creditos de um objeto da classe. 00365 * Se o numero de creditos da classe for igual ao maximo, a thread que 00366 * chamou a funcao sera bloqueada na variavel de condicao 00367 * m_WaitUseCredits ate que o credto da classe seja decrementado e a 00368 * funcao possa incrementar os creditos da classe. Se ja podemos 00369 * incrementar o credito do objeto e se o tempo entre as atualizacoes 00370 * nao passou, o credito nao sera atualizado, e se mais tempo passou, o 00371 * numero de creditos sera aumentado de acordo (por exemplo, se decorreu 00372 * um tempo tres vezes maior do que o da atualizacao, o credito sera 00373 * aumentado em 3 unidades). 00374 */ 00375 void UpdateCredits(); 00376 }; 00377 00378 // Classe que implementa uma fila FIFO de espera. Ela sera usada para colocar 00379 // os objetos FragmentInfo enviados pela classe RioNeti para serem 00380 // posteriormente processados pela thread da classe que trata dos clientes. 00381 00382 class CFPool : CFragmentQueue 00383 { 00384 private: 00385 /** Variavel de condicao usada pela thread que processa os clientes 00386 * para esperar pelo evento indicando que a fila FIFO da classe, 00387 * com objetos FragmentInfo, deixou de ficar vazia. 00388 */ 00389 pthread_cond_t m_WaitObject; 00390 /** Mutex para garantir o acesso exclusivo a fila FIFO. */ 00391 pthread_mutex_t m_AccessFragmentQueue; 00392 public: 00393 /** 00394 * CFPool construtor da classe, chamado quando um objeto e criado usando 00395 * o comando new. 00396 */ 00397 CFPool(); 00398 00399 /** 00400 * ~CFPool destrutor da classe, chamado quando um objeto e removido com 00401 * o comando delete. 00402 */ 00403 ~CFPool(); 00404 00405 /** 00406 * Insert Insere um objeto FragmentInfo no final da fila. Se a fila 00407 * estava vazia antes da insercao do elemento, um sinal sera enviado a 00408 * thread que foi bloqueada na variavel de condicao m_WaitObject ao 00409 * executar a funcao Remove dada a seguir, pois agora existem elementos 00410 * a serem removidos da fila. 00411 * @param fip ponteiro para o objeto a ser inserido no final da fila. 00412 * @return S_OK se o objeto foi corretamente inserido na fila, e valor 00413 * diferente de S_OK se algum erro ocorreu ao inserir o objeto. 00414 */ 00415 int Insert( FragmentInfo *fip ); 00416 00417 /** 00418 * WaitObject funcao usada para esperar que existam objetos na fila FIFO 00419 * de um objeto da classe. Se a fila nao estiver vazia, a funcao 00420 * retornara imediatamente o controle a thread que a executou. Porem, 00421 * caso a fila esteja vazia, a thread que chamou a funcao sera bloqueada 00422 * na variavel de condicao m_WaitObject, ate que um elemento seja 00423 * inserido na fila pela funcao Insert. 00424 */ 00425 void WaitObject(); 00426 00427 /** 00428 * Remove remove um dos elementos do inicio da fila FIFO de um objeto da 00429 * classe, se a fila nao estiver vazia e se este objeto possuir 00430 * creditos. Depois da remocao do elemento do inicio da fila, o numero 00431 * de creditos da classe sera decrementado em 1 unidade. 00432 * @return ponteiro para o elemento do inicio da fila que foi removido, 00433 * se o objeto possuir creditos e a fila nao estiver vazia, ou NULL em 00434 * caso contrario (isto e, se a fila estiver vazia ou se o objeto nao 00435 * possuir creditos). 00436 */ 00437 FragmentInfo *Remove(); 00438 }; 00439 00440 /** A classe que representa um cliente e que tambem e cada elemento do heap. 00441 * Para cada um dos clientes sera criado um objeto da classe CClientInfo. 00442 */ 00443 class CClientInfo : public CLeakBucket 00444 { 00445 private: 00446 /** Endereco IP do cliente (na ordem da rede). */ 00447 int IP; 00448 /** Porta IP do cliente (na ordem da rede). */ 00449 int Port; 00450 /** Contador usado para detectar a inatividade do cliente. Quando o 00451 * contador for nulo, isso significa que o cliente devera ser removido 00452 * do heap e do mapa. 00453 */ 00454 unsigned int IdleCount; 00455 /** Mutex para garantir o acesso exclusivo a fila do LeakBucket. */ 00456 pthread_mutex_t m_AccessFragmentQueue; 00457 public: 00458 /** 00459 * CClientInfo construtor da classe, chamado quando um objeto e criado 00460 * usando o comando new. Esta classe e derivada da classe CLeakBucket, 00461 * descrita anteriormente. Cada objeto desta classe sera associado a um 00462 * cliente com trafego de tempo real conectado ao servidor. 00463 * @param MaxCredits valor inteiro (nao sinalizado), definindo o numero 00464 * maximo de creditos a serem contabilizados pelo objeto criado. 00465 * @param TimeBetweenCredits tempo em microsegundos entre duas 00466 * atualizacoes do credito do objeto. 00467 * @param ip endereco IP do cliente associado ao objeto da classe que 00468 * esta sendo criado. 00469 * @param port porta do cliente associado ao objeto da classe que esta 00470 * sendo criado. 00471 */ 00472 CClientInfo( unsigned int MaxCredits, 00473 unsigned long long int TimeBetweenCredits, int ip, int port ); 00474 00475 /** 00476 * ~CClientInfo destrutor da classe, chamado quando um objeto e removido 00477 * com o comando delete. 00478 */ 00479 ~CClientInfo(); 00480 00481 /** 00482 * Insert Insere um objeto FragmentInfo no final da fila do objeto 00483 * associado ao cliente. Alem disso, como o cliente passou a ter 00484 * interacao com o servidor, pois temos fragmentos a serem enviados para 00485 * ele, resetaremos o contador de usado para detectar que um cliente 00486 * esta inativo. 00487 * @param fip ponteiro para o objeto a ser inserido no final da fila. 00488 * @return S_OK se o objeto foi corretamente inserido na fila, e valor 00489 * diferente de S_OK se algum erro ocorreu ao inserir o objeto. 00490 */ 00491 int Insert( FragmentInfo *fip ); 00492 00493 /** 00494 * Remove remove um dos elementos do inicio da fila do um objeto 00495 * associado ao cliente, se a fila nao estiver vazia e se este objeto 00496 * possuir creditos. Depois da remocao do elemento do inicio da fila, o 00497 * numero de creditos do objeto sera decrementado em 1 unidade. 00498 * @return ponteiro para o elemento do inicio da fila que foi removido, 00499 * se o objeto possuir creditos e a fila nao estiver vazia, ou NULL em 00500 * caso contrario (isto e, se a fila estiver vazia ou se o objeto nao 00501 * possuir creditos). 00502 */ 00503 FragmentInfo *Remove(); 00504 00505 /** 00506 * UpdateCredits atualiza, se necessario, o numero de creditos de um 00507 * objeto associado ao cliente. Se o tempo entre as atualizacoes nao 00508 * passou, o credito nao sera atualizado e um contador, usado para 00509 * detectar se o cliente esta inativo, sera decrementado caso a fila do 00510 * cliente esteja vazia. Em caso contrario, o credito sera incrementado, 00511 * e se mais tempo passou, o numero de creditos sera aumentado de 00512 * acordo (por exemplo, se decorreu um tempo tres vezes maior do que o 00513 * da atualizacao, o credito sera aumentado em 3 unidades). 00514 */ 00515 void UpdateCredits(); 00516 00517 /** 00518 * MustRemoveClient verifica se o cliente associado ao objeto deve ser 00519 * removido porque esta inativo por muito tempo. Isso ocorrera se o 00520 * contador de inatividade for igual a 0. 00521 * @return true se o cliente deve ser removido, ou false em caso 00522 * contrario. 00523 */ 00524 bool MustRemoveClient(); 00525 00526 /** 00527 * GetIPAddress retorna o endereco IP do cliente associado ao objeto. 00528 * @return endereco IP do cliente. 00529 */ 00530 int GetIPAddress(); 00531 00532 /** 00533 * GetPort retorna a porta do cliente associado ao objeto. 00534 * @return porta do cliente. 00535 */ 00536 int GetPort(); 00537 }; 00538 00539 /** Classe usada para comparar dois elementos do heap e ordenados, em ordem 00540 * crescente, segundo o tempo de atualizacao dos creditos. */ 00541 struct CompareHeapElement 00542 { 00543 bool operator()( CClientInfo* x, CClientInfo* y ) 00544 { 00545 return y->NextTimeToUpdateCredits() < x->NextTimeToUpdateCredits(); 00546 } 00547 }; 00548 00549 /** Define um novo tipo para o mapa do cliente. */ 00550 typedef map< unsigned long long int, CClientInfo* > TClientsMap; 00551 00552 /** Define um novo tipo para o heap do cliente. */ 00553 typedef priority_queue< CClientInfo*, vector< CClientInfo* >, 00554 CompareHeapElement > TClientsHeap; 00555 00556 /** Define um novo tipo para um vetor com os fragmentos. */ 00557 typedef vector< FragmentInfo * > TFragments; 00558 00559 /** Classe que implementa uma lista duplamente encadeada com os clientes para os 00560 * quais desejamos enviar dados. Existira uma entrada para cada cliente ativo 00561 * na lista. O objetivo da lista de um cliente e o de controlar o fluxo de 00562 * saida para este cliente. Somente se o cliente possuir credito e que um dos 00563 * objetos serao repassados a lista de controle de fluxo do servidor. Usada 00564 * pela thread que gerencia os objetos FragmentInfo que devem ser enviados aos 00565 * clientes. 00566 */ 00567 class CClientHeap 00568 { 00569 private: 00570 /** Variavel que armazena o numero de creditos dos clientes ao enviar 00571 * fragmentos. 00572 */ 00573 unsigned int m_MaxClientsCredits; 00574 /** Heap usado para armazenar os clientes ativos no servidor. Ele e 00575 * usado como uma lista de eventos, e e ordenado, em ordem crescente, 00576 * pelo tempo de atualizacao dos creditos dos clientes. 00577 */ 00578 TClientsHeap m_ClientsHeap; 00579 /** Mapa usado para acelerar a busca por um cliente no heap (usado ao 00580 * copiarmos os fragmentos do pool para a lista dos clientes). Cada 00581 * entrada do mapa (com um identificador dado por um inteiro de 00582 * bits cujos 32 bits superiores sao a porta do cliente e os 32 bits 00583 * inferiores sao o IP do cliente) aponta para a entrada no heap de 00584 * um cliente diferente. 00585 */ 00586 TClientsMap m_ClientsMap; 00587 /** Ponteiro para o ultimo cliente achado pela funcao FindClient. 00588 * Usado pela funcao Insert para evitar a busca por clientes no mapa 00589 * ClientsMap a cada vez que um fragmento e inserido via a funcao 00590 * Insert dada a seguir. 00591 */ 00592 CClientInfo *m_LastClient; 00593 /** Mutex para garantir o acesso exclusivo ao mapa descrito 00594 *anteriormente, e a variavel m_LastClient. 00595 */ 00596 pthread_mutex_t m_AccessClients; 00597 /** Mutex para garantir o acesso exclusivo ao heap descrito 00598 * anteriormente. 00599 */ 00600 pthread_mutex_t m_AccessClientsHeap; 00601 /** Variavel de condicao usada pela thread que processa os clientes 00602 * para esperar pelo evento indicando que o heap m_AccessClientsHeap 00603 * da classe deixou de ficar vazio, isto e, um cliente possui 00604 * fragmentos para serem enviados. 00605 */ 00606 pthread_cond_t m_WaitClients; 00607 00608 /** 00609 * FindClient verifica se existe, no heap, o cliente identificado pela 00610 * sua conexao com o servidor, composta por seu endereco IP e por sua 00611 * porta. 00612 * @param ip endereco IP do cliente a ser procurado no heap. 00613 * @param port porta do cliente a ser procurado no heap. 00614 * @return ponteiro para o objeto da classe CClientInfo associado ao 00615 * cliente caso este esteja no heap, ou NULL em caso contrario. 00616 */ 00617 CClientInfo *FindClient( int ip, int port ); 00618 00619 /** 00620 * CreateClient insere no heap o cliente identificado pela sua conexao 00621 * com o servidor, composta por seu endereco IP e por sua porta. Um 00622 * sinal para a variavel de condicao m_WaitClients sera gerado para 00623 * desbloquear, se necessario, uma thread que pode ter sido bloqueada 00624 * nesta variavel de condicao, ao executar a funcao GetFragments, caso o 00625 * heap estivesse vazio quando a thread executou a funcao. 00626 * @param ip endereco IP do cliente a ser inserido no heap. 00627 * @param port porta do cliente a ser inserido no heap. 00628 * @param TimeBetweenCredits tempo em microsegundos entre duas 00629 * atualizacoes do credito do cliente inserido no heap. 00630 * @return ponteiro para o objeto da classe CClientInfo associado ao 00631 * cliente que acabou de ser inserido no heap. 00632 */ 00633 CClientInfo *CreateClient( int ip, int port, 00634 unsigned long long int TimeBetweenCredits ); 00635 /** 00636 * CreateClient Funcao para remover do heap o cliente cujo ponteiro e 00637 * passado como parametro. A funcao retorna true se a remocao do cliente 00638 * foi feita com sucesso, e false se ela nao foi feita com sucesso (isto 00639 * e, se a thread que insere fragmentos nos clientes estiver inserindo 00640 * um fragmento neste cliente). 00641 * @param Client Ponteiro para a estrutura do cliente a ser removido do 00642 * heap. 00643 * @return true se a remocao foi feita com sucesso e false, caso a 00644 * remocao nao possa ser feita. 00645 */ 00646 bool RemoveClient( CClientInfo *Client ); 00647 public: 00648 /** 00649 * CClientHeap construtor da classe, chamado quando um objeto e criado 00650 * usando o comando new. 00651 * @param MaxClientsCredits valor inteiro (nao sinalizado), definindo o 00652 * numero maximo de creditos dos clientes associados ao heap. 00653 */ 00654 CClientHeap( unsigned int MaxClientsCredits ); 00655 00656 /** 00657 * ~CClientHeap destrutor da classe, chamado quando um objeto e removido 00658 * com o comando delete. 00659 */ 00660 ~CClientHeap(); 00661 00662 /** 00663 * Insert Insere um objeto FragmentInfo no final da fila do cliente 00664 * associado a este fragmento. Para descobrirmos o cliente, usanmos o 00665 * endereco IP e a porta dado no objeto para descobrirmos no heap o 00666 * cliente associado ao fragmento. Se este cliente estiver no heap, o 00667 * objeto sera inserido no filal da fila associada ao cliente. Se o 00668 * cliente nao estiver no heap, um novo objeto da classe CClientInfo 00669 * sera criado para o cliente, o fragmento sera depois inserido no 00670 * inicio da fila do cliente e, finalmente, o cliente sera inserido no 00671 * heap. 00672 * @param fip ponteiro para o objeto a ser inserido no final da fila. 00673 * @return S_OK se o objeto foi corretamente inserido na fila, e valor 00674 * diferente de S_OK se algum erro ocorreu ao inserir o objeto. 00675 */ 00676 int Insert( FragmentInfo *fip ); 00677 00678 /** 00679 * GetFragments Retorna os fragmentos do cliente associado ao topo do 00680 * heap, se o heap nao estiver vazio. Este cliente sera aquele com o 00681 * tempo de atualizacao dos creditos mais proximo do tempo atual. Apos 00682 * remover o cliente do heap, os creditos do cliente serao atualizados 00683 * apos esperarmos pelo tempo desta atualizacao (usando a funcao 00684 * usleep), e apos isso, um numero de fragmentos nao maior do que o 00685 * numero de creditos deste cliente (que pode ser menor do que este 00686 * numero caso a fila do cliente possua menos fragmentos do que o numero 00687 * de creditos) sera retornado pela funcao. Se nao existirem fragmentos 00688 * a serem enviados para este cliente (o cliente pode estar inativo), o 00689 * cliente sera novamente inserido no heap, na ordem do proximo tempo da 00690 * sua atualizacao de credito, se o contador de inatividade nao for 00691 * nulo. Se ele for nulo, o cliente nao sera inserido no heap, e seu 00692 * objeto da classe CClientInfo sera removido. Agora, se o heap estiver 00693 * vazio, a thread que executou a funcao sera bloqueada na variavel de 00694 * condicao m_WaitClients ate que um cliente seja inserido no heap (por 00695 * outra thread) a partir da funcao Insert. 00696 * @return TFragments vetor de objetos do tipo FragmentInfo 00697 */ 00698 void GetFragments( TFragments &Fragments ); 00699 }; 00700 00701 /** Classe para implementar o controle de fluxo ao enviar blocos de video (ela 00702 * nao sera usada nas copias de dados). 00703 */ 00704 class CStreamControl 00705 { 00706 private: 00707 /** Ponteiro para a classe com a fila FIFO que com os objetos 00708 * FragmentInfo que podem ser enviados. Esta classe e usada para o 00709 * controle de fluxo dos dados que estao sendo enviados pelo servidor. 00710 */ 00711 CSendData *m_SendData; 00712 /** Ponteiro para a classe com a fila FIFO com os objetos FragmentInfo 00713 * que ainda vao ser processados pela thread que gerencia os clientes. 00714 */ 00715 CFPool *m_FPool; 00716 /** Ponteiro para a classe que gerencia o heap com os clientes. Cada 00717 * elemento do heap estara associado a um cliente, e contera os 00718 * objetos FragmentInfo que devem ser enviados a este cliente. 00719 */ 00720 CClientHeap *m_ClientHeap; 00721 /** Identificador da thread que envia os objetos FragmentInfo quando 00722 * existirem creditos. 00723 */ 00724 pthread_t m_SendThread; 00725 /** Identificador da thread que processa os objetos FragmentInfo dos 00726 * recebidos da RioNeti pela funcao Put e os coloca nas listas dos 00727 * clientes. 00728 */ 00729 pthread_t m_PoolThread; 00730 /** Identificador da thread que processa os objetos FragmentInfo nas 00731 * listas dos clientes e os coloca na lista de envio (processada pela 00732 * thread identificada por m_SendThread). 00733 */ 00734 pthread_t m_ClientsThread; 00735 /** Identificador da thread que atualiza os creditos do objeto 00736 * m_SendData, para desbloquear a thread SendDataThread que envia 00737 * objetos FragmentInfo para a rede, usando a chamada scSend da 00738 * RioNeti. 00739 */ 00740 pthread_t m_UpdateThread; 00741 /** Ponteiro para a classe RioNeti que esta usando a classe 00742 * StreamControl para controlar o fluxo de dados. 00743 */ 00744 RioNeti *m_RioNeti; 00745 /** Variavel booleana que indica se a classe esta inicializada. */ 00746 bool m_Started; 00747 #ifdef RIO_DEBUG2 00748 /** Contador usado para contar o numero de pacotes enviados pela thread 00749 * SendData (usado pela funcao SendDataThread). Ele pode ser removido 00750 * depois dos testes. 00751 */ 00752 unsigned int TotalSendFragments; 00753 #endif 00754 /** 00755 * PoolThread funcao usada pela thread que controla o pool de fragmentos 00756 * passados pelo objeto da classe RioNeti (pela funcao nbSend) ao objeto 00757 * responsavel pelo controle de fluxo. A thread copia cada um dos 00758 * fragmentos deste pool para a lista do cliente correspondente a este 00759 * fragmento. Quando o pool estiver vazio, a thread e bloqueada na 00760 * variavel de condicao do Pool (o objeto m_FPool da classe CFPool) ate 00761 * que a funcao nbSend do objeto da classe RioNeti insira fragmentos no 00762 * Pool. 00763 * @param Param ponteiro para o objeto da CStreamControl associado a 00764 * thread que esta sendo executada. 00765 */ 00766 static void *PoolThread( void *Param ); 00767 00768 /** 00769 * ClientsThread funcao usada pela thread que controla a passagem dos 00770 * fragmentos das listas dos clientes para a fila de saida do controle 00771 * de fluxo (do objeto m_SendData da classe CSendData com os fragmentos 00772 * a serem enviados. Os fragmentos da fila de cada cliente sao passados 00773 * para a fila de saida do controle de fluxo apos ocorrer o evento que 00774 * dispara a atualizacao dos creditos deste clientes. O numero de 00775 * fragmentos copiados sera igual ao numero de creditos depois desta 00776 * atualizacao. Se nao existirem clientes (de tempo real) atualmente 00777 * conectados ao servidor, a thread ficara bloqueada na variavel de 00778 * condicao do objeto m_ClientHeap da classe CClientHeap ate que 00779 * fragmentos de um cliente chegem para serem processados pelo controle 00780 * de fluxo. 00781 * @param Param ponteiro para o objeto da CStreamControl associado a 00782 * thread que esta sendo executada. 00783 */ 00784 static void *ClientsThread( void *Param ); 00785 00786 /** 00787 * SendDataThread funcao usada pela thread que controla o envio dos 00788 * fragmentos controlados pelo controle de fluxo pela rede. Os 00789 * fragmentos serao enviados enquando o objeto m_SendData da classe 00790 * CSendData possuir fragmentos para serem enviados e creditos para 00791 * enviar estes faragmentos. A thread ficara bloqueada em uma das 00792 * variaveis de condicao (m_WaitObject) do objeto m_SendData se nao 00793 * existirem fragmentos a serem enviados (colocados na fila de saida 00794 * pela thread que executa a funcao ClientsThread), ou em uma outra 00795 * variavel de condicao do objeto (m_WaitCredits) se o objeto m_SendData 00796 * nao possuir creditos para enviar fragmentos pela rede (os creditos do 00797 * objeto sao atualizados por uma outra thread que executa a funcao 00798 * UpdateThread descrita a seguir). 00799 * @param Param ponteiro para o objeto da CStreamControl associado a 00800 * thread que esta sendo executada. 00801 */ 00802 static void *SendDataThread( void *Param ); 00803 00804 /** 00805 * UpdateThread funcao usada pela thread que atualiza os creditos do 00806 * objeto m_SendData da classe CSendData. Quando nao existirem creditos 00807 * a serem atualizados (o objeto m_SendData ja possui o numero maximo de 00808 * creditos), a thread que executa a funcao seja bloqueada na variavel 00809 * de condicao m_WaitUseCredits do objeto ate que um dos creditos deste 00810 * objeto sejam usados (eles serao usados ao enviarmos fragmentos pela 00811 * thread que executa a funcao SendDataThread). 00812 * @param Param ponteiro para o objeto da CStreamControl associado a 00813 * thread que esta sendo executada. 00814 */ 00815 static void *UpdateThread( void *Param ); 00816 public: 00817 /** 00818 * CStreamControl construtor da classe, chamado quando um objeto e 00819 * criado usando o comando new. 00820 */ 00821 CStreamControl(); 00822 00823 /** 00824 * ~CStreamControl destrutor da classe, chamado quando um objeto e 00825 * removido com o comando delete. 00826 */ 00827 ~CStreamControl(); 00828 /** 00829 * Start Inicializa um objeto da classe CStreamControl. 00830 * @param rn ponteiro para o objeto da classe RioNeti que esta usando o 00831 * objeto para fazer o controle de fluxo. 00832 * @param MaxClientsCredits Numero maximo de creditos para cada um dos 00833 * clientes conectados ao servidor. 00834 * @param MaxNetworkCredits Numero maximo de creditos ao enviarmos os 00835 * fragmentos pela rede. 00836 * @param TimeBetweenCredits tempo entre as atualizacoes de credito 00837 * usados ao enviarmos os fragmentos pela rede (obs: o tempo de 00838 * atualizacao dos creditos de cada cliente dependera da taxa de 00839 * transmissao de video e, devido a isso, sera passado junto com o 00840 * fragmento a ser enviado para aquele cliente). 00841 * @result S_OK se o objeto foi corretamente inicializado, e valor 00842 * diferente de S_OK se algum erro ocorrer ao inicializar o objeto da 00843 * classe. 00844 */ 00845 int Start( RioNeti *rn, unsigned int MaxClientsCredits, 00846 unsigned int MaxNetworkCredits, 00847 unsigned long long int TimeBetweenCredits ); 00848 /** 00849 * Stop Para o processamento do objeto da classe CStreamControl 00850 */ 00851 void Stop(); 00852 /** 00853 * Put coloca um fragmento, dado pelo objeto nbp da classe NetBuf, para 00854 * ser processado pelo controle de fluxo gerenciado pelo objeto da 00855 * classe CStreamControl. Este fragmento sera colocado pela funcao iSend 00856 * do objeto (apontado pelo parametro interno m_RioNeti da classe) da 00857 * classe RioNeti. 00858 * @param nbp ponteiro para o objeto da classe NetBuf com o fragmento. 00859 * @result S_OK se o fragmento foi colocado com sucesso na fila de 00860 * processamento inicial da classe de controle de fluxo (o Pool apontado 00861 * pelo objeto m_FPool), e valor diferente de S_OK se algum erro ocorrer 00862 * ao inicializar o objeto da classe. 00863 */ 00864 int Put( NetBuf *nbp ); 00865 }; 00866 00867 #endif /*STREAMCONTROL_H_*/