Archives for Tutoriais category

PL/PGSQL Funções Aninhadas

Posted on out 29, 2008 under Tutoriais | No Comment

Utilizando a versão 8.2.7 do Postgresql verifiquei a possibilidade de criar funções aninhadas.
Veja o exemplo:

CREATE OR REPLACE FUNCTION testNestedFunction() RETURNS  REAL as
$$
<>
DECLARE
v_test REAL;
r REAL;
BEGIN
   CREATE OR REPLACE FUNCTION addTest(a REAL,b REAL) RETURNS REAL AS
   $BODY_ADDTEST$
	DECLARE
		r REAL;
	BEGIN
		r := a + b;
	RETURN r;
   END;
   $BODY_ADDTEST$language plpgsql;

   r := addTest(1,1);
   RAISE NOTICE 'addTest = %',r;

   r := addTest(2,2);
   RAISE NOTICE 'addTest = %',r;

   RETURN r;
END global;
$$ LANGUAGE 'plpgsql';

Na função acima criei uma função aninhada chamada addTest(REAL,REAL) recebendo como parâmetro dois valores do tipo real, com os quais é efetuado uma soma e retornado o resultado. Executando a função temos o seguinte resultado:

SELECT testNestedFunction();

NOTA:  addTest = 2
NOTA:  addTest = 4

Tempo total de execução da consulta: 18 ms.
1 registros recuperados.

Como pode ser visto foi realizado duas chamadas a função aninhada addTest() passando diferentes parâmetros.

O interessante é que o Postgresql cria duas funções: testNestedFunction() e addTest(REAL,REAL). E não somente uma função aninhada, isso favorece aos bugs, vamos simular um então.

Vamos deletar a função addTest(REAL,REAL) e executar novamente.

DROP FUNCTION addtest(real, real);
SELECT testNestedFunction();

ERRO:  cache lookup failed for function 1906343
CONTEXT:  PL/pgSQL function "testnestedfunction" line 16 at assignment

********** Erro **********

ERRO: cache lookup failed for function 1906343
SQL state: XX000
Contexto: PL/pgSQL function "testnestedfunction" line 16 at assignment

O comando DROP FUNCTION addTest(REAL,REAL) não verificou que a função testnestedfunction() é depende daquela para sua execução, procurei na documentação uma maneira de declarar a dependência mas não encontrei. Outro detalhe interessante é que a função addTest() não existe até a primeira execução, ou seja, quando o comando é executado SELECT testnestedfunction() pela primeira vez a função addTest() é criada. Então quando deletamos a função addTest() e executamos novamente o comando SELECT testnestedfunction(), a função addTest() não é criada novamente.

Funções aninhadas são interessantes para melhorar a leitura do código e prover reutilização de código. O problema é se por acidente algum DBA deletar a função aninhada como mostrado acima. Irá causar um bug difícil de resolver. Pois, a resposta do erro é pouco intuitiva não informando claramente a função que não foi encontrada.

Criar funções separadas é uma outra solução invés de criar uma função aninhada. Mas, o problema que dificulta a leitura e entendimento do código.

Carpe Diem!

PL/PGSQL blocos de código

Posted on out 29, 2008 under Tutoriais | No Comment

A linguagem PL/PGSQL permite a criação de blocos de código. Com essa característica é possível definir o escopo das variáveis. Sendo um recurso interessante para deixar o código mais legível, auxiliando também na depuração do código.
As variáveis existem no momento da declaração do bloco até o final do bloco onde a variável é declarada.
Rótulos podem ser adicionados aos blocos para melhorar a leitura e também para qualificar as variáveis que existem dentro do bloco. Os blocos de código são definidos da seguinte forma:

<

Como exemplo vamos criar uma função onde teremos dois blocos global e local, com uma variável declarada no bloco global com o nome v_test do tipo real e outra variável também declarada com o nome v_test dentro do bloco local. Veja o exemplo:

CREATE OR REPLACE FUNCTION test() RETURNS VOID as
$$
<>
DECLARE
v_test REAL;
BEGIN
        v_test := 1;
        <>
        DECLARE
             v_test REAL;
        BEGIN
	      v_test :=2;
	      RAISE NOTICE 'global.v_test = %, v_test = %',global.v_test,v_test;
        END local;

 RAISE NOTICE 'Global v_test = %',v_test;

END global;
$$ LANGUAGE 'plpgsql';

Resultado da execução:

select test();
NOTA:  global.v_test = 1, v_test = 2
NOTA:  Global v_test = 1
Tempo total de execução da consulta: 6 ms.
1 registros recuperados.

Essa função demonstra claramente o escopo da variáveis e também demonstra que podemos ter sub blocos de código dentro de uma função.
É importante notar que BEGIN/END é utilizado para agrupar as declarações da linguagem PL/PGSQL e também como comandos de controle de transações. Mas, um detalhe interessante é que funções e triggers não podem iniciar ou encerrar transações e o Postgresql não suporta transações aninhadas.

Carpe Diem.

Java Comunicando com equipamentos Modbus

Posted on ago 15, 2008 under Tutoriais | No Comment

Participei de vários projetos de automação industrial onde era necessário ler ou escrever instrumentos como medidores de temperatura, medidores de energia elétrica e outros equipamentos que implementam o protocolo Modbus RTU.

A linguagem Java possui uma API muito boa para comunicar com instrumentos que utilizam o protocolo Modbus RTU a API Jamod. Além de propiciar a comunicação com equipamentos e instrumentos função do Master da rede, também é possível fazer com a aplicação ser torne um Slave Modbus, respondendo as solicitações do Master.

A documentação da Api Jamod é boa, possui vários códigos de exemplo para implementar ModBus Escravo e Modbus Mestre.

Entendo o protocolo ModBus http://jamod.sourceforge.net/kbase/protocol.html

How-To’s de como utilizar o Jamod http://jamod.sourceforge.net/kbase/modbus_udp.html

Thats all Folks :-) .

PL/PGSQL Programando no Postgresql

Posted on jul 13, 2008 under Tutoriais | 2 Comentários

Postgresql suporta uma variedade de linguagens procedurais, podemos programar uma store procedure na linguagens de nossa preferência como exemplos: Pl/Perl, Pl/Python, Pl/Java, Pl/PHP, Pl/Ruby e muitas outras. Para utilizar estas linguagens primeiro é necessário habilitar na base de dados.

O comando para habilitar a linguagem na base de dados não é complicado. Nesse post iremos utilizar a linguagem nativa do PostgreSQL que PL/PGSQL.

Habilitando a linguagem em uma bases de dados.

create lang plpgsql nomedabasededados

Por exemplo na base de dados book

create lang plpgsql book

Este comando deve ser executado no shell.

O exemplo tem a finalidade de mostrar o poder de um procedimento armazenado (store procedure) da linguagem PL/PGSQL está linguagem somente irá atuar dentro da base de dados, então não será possível executar comandos externos. Caso seja necessário é possível desenvolver uma função externa em C ou usar uma linguagem procedural não confiável a qual pode inserir algum risco de segurança a base de dados.

Voltando ao exemplo vamos desenvolver o algoritmo da torre de hanoi em PL/PGSQL.

CREATE FUNCTION towerHanoi(ndisk INTEGER,src INTEGER,dst INTEGER, tmp INTEGER) RETURNS void AS '
Declare

BEGIN
	IF ndisk = 1 THEN
		RAISE NOTICE '' DISK % Move da haste % para haste % '', ndisk,src,dst;
	ELSE
		perform towerHanoi(ndisk - 1,src,dst,tmp);
		RAISE NOTICE '' DISK % Move da haste % para haste % '', ndisk,src,tmp;
		perform towerHanoi(ndisk - 1,src,tmp,src);
	END IF;

END;
' LANGUAGE 'plpgsql';

Executando a função
select towerHanoi(3,1,2,3);

Veja o resultado da função

NOTA: DISK 1 Move da haste 1 para haste 2
CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
NOTA: DISK 2 Move da haste 1 para haste 3
CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
NOTA: DISK 1 Move da haste 1 para haste 3
CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
NOTA: DISK 3 Move da haste 1 para haste 3
NOTA: DISK 1 Move da haste 1 para haste 3
CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $4 )”
PL/pgSQL function “towerhanoi” line 7 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
NOTA: DISK 2 Move da haste 1 para haste 1
CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
NOTA: DISK 1 Move da haste 1 para haste 1
CONTEXT: comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform
comando SQL “SELECT towerHanoi( $1 – 1, $2 , $3 , $2 )”
PL/pgSQL function “towerhanoi” line 9 at perform

Total query runtime: 2 ms.
Data retrieval runtime: 7 ms.
1 rows retrieved.

Esta simples função demonstra como usar recursividade, passagem de parâmetros e como chamar uma função em PL/PGSQL.

Estou pesquisando pra ver se consigo fazer uma árvore binária em PL/PGSQL. Quando eu conseguir coloco o algoritmo.

Abraços

Hei pessoal não se esqueçam a assinatura dos feeds é gratuita então não percam tempo.

Explorando o PostgreSQL – Como descobrir o tamanho de uma tabela no disco

Posted on jul 12, 2008 under Tutoriais | 3 Comentários

imagem postgresqlA algum tempo atrás, surgiu a necessidade de saber o tamanho de cada tabela em bytes, numa base de dados (database) Postgresql. Era necessário para estimar o crescimento destas tabelas e saber quanto tempo levaria que esgotar a capacidade do HD.
Nesta pesquisa encontrei muitos dados interessantes que irei compartilhar com vocês. Claro que para alguns não terá novidade nenhuma nesta matéria, mas com certeza será valioso para alguém como foi para mim.

Antes de começar temos que entender como o postgresql gerencia os arquivos da base de dados, então vamos explora-lo.

Como PostgreSQL gerencia os arquivos da base de dados ?

O conceito fundamental do Postgresql e de outros SGBDS é que os dados são armazenados em tabelas e as tabelas agrupadas em base de dados (databases). Em um nível mais alto desta organização as base de dados são agrupadas em clusters – e um cluster de base de dados é gerenciado pelo postmaster.

E como fica essa hierarquia no disco ?

Para descobrir como funciona essa hierarquia na prática vamos fazer umas consultas (queries) , executar um comandos no shell.
Vamos começar conectando a base de dados e descobrindo o OID (Obect ID) através de uma consulta.

~$ psql book -U postgres

book=# SELECT datname, oid from pg_database;

datname oid
postgres 10819
book 16384
template1 1
template0 10818

(4 registros)

Na resposta da nossa query podemos ver que temos 4 base de dados (databases) no cluster. Agora podemos encontrar as base de dados no disco dentro do diretório $PG_DATA.

~$ cd $PG_DATA
~$ ls
base pg_clog pg_ident.conf pg_subtrans pg_twophase pg_xlog postmaster.opts
global pg_hba.conf pg_multixact pg_tblspc PG_VERSION postgresql.conf postmaster.pid

Dentro do subdiretório base encontra-se as base de dados no SELECT que executamos antes tem um oid 1 para a base de dados (datname) template1. Vamos entrar dentro do diretório base e ver o que tem por lá.
~$ cd base
~$ ls -la
drwx—— 2 postgres postgres 2648 Jul 11 11:17 1
drwx—— 2 postgres postgres 2648 Jul 11 11:17 10818
drwx—— 2 postgres postgres 2680 Jul 11 11:18 10819
drwx—— 2 postgres postgres 2680 Jul 11 11:39 16384

Neste exemplo temos 4 diretórios o mesmo números de registros quando executamos o SELECT então isso demonstra que o OID(object ID) corresponde ao nome do diretorio dentro da base de dados. Como exemplo o diretórios 1 corresponde a base de dados template1.
Entrando no diretório 1 podemos ver que existem vários arquivos vamos descobrir o que significa cada um deles.

~$ cd 1
~$ ls
10737 10747 10757 10767 1250 2603 2609 2615 2650 2656 2662 2668 2678 2684 690 2700 2831 2837 10739 10749 10759 10769 1255 2604 2610 2616 2651 2657 2663 2669
….
….

Para saber o que significa cada um desses arquivos temos que descobrir os OIDS dentro da base de dados template1. Vamos voltar ao psql

~$ psql -q -d template1
template1=# select oid, relname from pg_class;

oid relname
10762 sql_sizing
10769 pg_toast_10767
10771 pg_toast_10767_index
10767 sql_sizing_profiles
10772 table_constraints
10776 table_privileges
10780 tables
10784 triggered_update_columns
10787 triggers

Na tabela pg_class existe mais informação que pode nos ajudar a explorar a estrutura de armazenamento do PostgreSQL.

psql book -Upostgres
book=# select relname,oid,relpages, reltuples FROM pg_class ORDER BY OID;

relname oid relpages reltuples
pg_type 1247 5 242
pg_autovacuum 1248 0 0
pg_attribute 1249 28 1628
pg_autovacuum_vacrelid_index 1250 1 0
pg_proc 1255 45 1929
pg_class 1259 5 204

A coluna reltuples informa quantas tuplas tem em cada tabela. Já a coluna relpages mostra quantas páginas (pages) são requiridas para armazenar o conteúdo da tabela.

Qual a correspondência entre relpages e reltuples com o tamanho do arquivo no disco ?

Vamos listar o conteúdo do diretório e pegar dois exemplos

$ ls -l 1247 1249
-rw------- 1 postgres postgres  40960 Jul  11 11:17 1247
-rw------- 1 postgres postgres 229376 Jul 11 11:17 1249

O arquivo chamado 1247 tabela pg_type ocupa um espaço em disco e 40960 bytes. Se dividirmos 40960/5 relpages = 8192 bytes, realizando o mesmo cálculo para a tabela pg_attribute que corresponde ao arquivo 1249 que possui um tamanho em disco de 229376 bytes / 28 relpages = 8192 bytes.
O tamanho 8192 refere-se ao tamanho da página este valor é fixo como podemos verificar.

Com esta matéria acho que consegui mostrar como o PostgreSQL estrutura os dados no disco.
E como descobrir o tamanho da tabela no Hd, com certeza existe outras maneiras mas escolhi está para demonstrar também como o postgresql organiza as tabelas no HD.

Referência:
Livro PostgreSQL – Korry Douglas e Susan Douglas

Transferindo dados com segurança

Posted on jul 09, 2008 under Dicas Linux, Segurança, Tutoriais | 1 Comentário

Segurança na troca de mensagens e arquivos está se tornando cada vez mais necessário para manter nossa privacidade ou algum projeto confidencial. Encontrei um tutorial em vídeo no linux journal o tutorial é em inglês mas é possível seguir os passos e aprender a usar o GnuPG e PGP.

Muito bom vale a pena assistir.
Parte 1

Parte 2

Pessoal assinem os feed do blog é de graça.

Gerenciando pacotes no Gentoo

Posted on jul 03, 2008 under Dicas Linux, Tutoriais | 7 Comentários

O gentoo possui um ótimo gerenciador de pacotes, diga-se de passagem foi um dos 5 motivos que me fez usa-lo. A idéia deste post é mostrar como gerenciar os pacotes instalados de forma simples.

Para gerenciar os pacotes os desenvolvedores do gentoo fizeram uma excelente ferramenta a Gentoolkit, com esta ferramenta conseguimos descobrir muita informação sobre os pacotes como por exemplo: tamanho do pacote instalado, integridade do pacote, descobrir a qual pacote um arquivo pertence, mostrar as dependências de um pacote, mostrar quais pacotes usam uma flag USE específica, calcular a dependência reversa, etc …
Existe um outro pacote que se chama portage-utils que também possui muitas ferramentas úteis para gerenciar pacotes o qual falarei em um próximo post.

Read the rest of this entry »

C chat with sockets and thread

Posted on jun 28, 2008 under C, Sem categoria, Tutoriais | 2 Comentários

I developed a chat server in the C language and Python language The chat written in Python is posted here. Now I developed the chat using the C sockets and threads. The code developed in C follows the same principles of the code in Python. In C had to develop a double linked list to store the file descriptor of the socket, user name and nickname. This code was developed to the discipline of Distributed Systems.

#include

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "listaDDE.h"
#define MYPORT 5800    // the port users will be connecting to

#define BACKLOG 10     // how many pending connections queue will hold
#define MAXLINE 1024
#define NUM_THREADS     50
fd_set rmask;
pthread_mutex_t mutexsum;
pthread_mutex_t mutexLogin;
int fd_max;
int maxfds;

int sockfd;
fd_set read_fds;
fd_set master;
nodo *root = NULL;
static int	read_cnt;
static char	*read_ptr;
static char	read_buf[MAXLINE];

static void *sendMensagem(void *arg);
void sigchld_handler(int s);
static void *sendALL(char msg[],int soks);
static void *sendMensagem(void *arg);
static void *newClientConnect(int arg);

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

void *sendALL(char msg[],int soks)
{
	nodo *aux = getFirst();
	while(aux != NULL)
	{
		int soc =aux->socket;

		if(soc != soks)
			{
	      	       		if(write(soc, msg, strlen(msg)) == -1)
		    			perror("send");
				printf("send %s %s\n",msg,aux->nick);

			}
		aux = aux->prox;
	}
}

void *sendMensagem(void *arg)
{
  char *buff;
  int fd = (*(int *) arg);
  int nbytes;
  char tmp[5000];

  printf("\nthread call %d",fd);
  newClientConnect(fd);
  printf("\n entry LOOP\n");
  nodo *cliente = busca(fd);

while(1)
{

     buff = (char *) calloc( MAXLINE,sizeof(char));
     if(FD_ISSET(fd,&master))
     {
         nbytes = recv(fd,buff, MAXLINE -1 , 0);
	 if(nbytes > 1)
	 {

	   if(!tmp)
	   {
		perror("alocation:");
		exit(-1);
	   }
           strcat(tmp, cliente->nick);
	   strcat(tmp, " >> ");
	   strcat(tmp, buff);
           sendALL(tmp,fd);
	 }
	 else
	 {
	       if (nbytes == 0) {
                       printf ("servidor: socket %d desligado\n",  fd);
               } else {
                       perror ("recv");
               }
              close (fd); // BYE!!
              FD_CLR( fd , &master);
	      removi(getFirst(),fd);
	      pthread_exit(NULL);
	  }

     }
     free(buff);

}

}

static void *newClientConnect(int arg)
{
	int fd = arg;
	pthread_t tid;
	struct sockaddr_in their_addr;
	char welcome[] = "Welcome Chat SistDistribuidos 0.1 \n";
	char msg1[] = "Login: ";
	char msg2[] = "NickName: ";
	char nome[100];
	char nick[100];
	int nbytes;
	socklen_t sin_size;

	pthread_mutex_lock (&mutexLogin);

		printf("\naccept \n");
		if (write(fd, welcome, sizeof welcome - 1) != sizeof welcome - 1) {
	   		perror("write:");
			exit(1);
		}		

		printf("write %s \n",welcome);
		usleep(1000);

		if (write(fd, msg1, strlen(msg1)) != strlen(msg1)) {

	   		perror("write:");
			exit(1);
		}

		printf("write %s \n",msg1);
		usleep(1000);
		if ((nbytes = recv(fd, nome, 100,0)) < 0) {
		perror("read:");
	        exit(1);
	   	return;
		}
		nome[nbytes -1] = '\0';
		printf("Read %d %s\n",strlen(nome),nome);
		usleep(1000);
		if (write(fd, msg2, sizeof msg2 - 1) != sizeof msg2 - 1) {
	        	perror("write:");
	   	exit(1);
		}

		if ((nbytes =recv(fd, nick, 100,0)) < 0) {
	  	perror("read:");
		 exit(1);
		}
		nick[nbytes-1]='\0';
		printf("Read %d %s\n",strlen(nick),nick);		

		inseri(&root,fd,nome,nick, inet_ntoa(their_addr.sin_addr));
		FD_SET(fd, &master);		/* listen to this socket too */

	printf("end welcome \n");

	pthread_mutex_unlock (&mutexLogin);

}

int main(void)
{
      // listen on sock_fd, new connection on new_fd
    int j,new_fd;
    struct timeval waitd;
    int nbytes;
    char buf[256];
    int fd_max; //numero maximo de descritores

    struct sockaddr_in my_addr;    // my address information
    struct sockaddr_in their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;

    FD_ZERO(&master);
    FD_ZERO(&read_fds);

    pthread_mutex_init(&mutexsum, NULL);
    pthread_mutex_init(&mutexLogin,NULL);

    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    if ( setsockopt ( sockfd , SOL_SOCKET , SO_REUSEADDR , &yes , sizeof ( int ) ) == -1 )
    {
		perror ( " setsockopt " );
		exit ( 1 );
    }

    my_addr.sin_family = AF_INET;         // host byte order
    my_addr.sin_port = htons(MYPORT);     // short, network byte order
    my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
    memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) == -1) {
        perror("bind");
        exit(1);
    }

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    FD_SET(sockfd, &master);

    fd_max = sockfd;	

    int rc =0;	 

    int i = 0;
    int ret;

    int fd;
      waitd.tv_sec = 1;
      waitd.tv_usec = 0;

     while(1)
     {  

        read_fds = master;
        if (select (fd_max+1,  &read_fds, NULL, NULL, NULL)== -1) {
                perror ("select");
                exit(1);
        }

        int addrlen = sizeof (their_addr);
        if (( new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&addrlen)) == -1)  {
            perror ("accept");
        } else {

            FD_SET ( new_fd , &master);

            printf ("server : new connection %s socket %d\n",
                              inet_ntoa (their_addr.sin_addr),new_fd);

	    pthread_t tred;
	    rc = pthread_create( &tred, NULL,sendMensagem, (void *) &new_fd);
       	    if (rc){
        	printf("ERROR; return code from pthread_create() is %d\n", rc);
       		exit(-1);
            }

        }
      } 

pthread_mutex_destroy(&mutexsum);
pthread_mutex_destroy(&mutexLogin);

    return 0;
}

Header Double Linked List name ListaDDE.h

#include 
#include 
#include 

#define MAXBUFFER 2048

typedef struct cel
{
	int socket;
	char nome[50];
	char nick[50];
	char host[50];
	char buff[MAXBUFFER];
	struct cel *ante;
       	struct cel *prox;
}nodo;

nodo *getFirst();
nodo *getLast();
nodo *busca(int key);

void inseri(nodo **root, int socket,char nome[],char nick[],char host[]);

void removi(nodo *root, int socket);
void print (nodo *ini);

Implementation Double Linked List without use global variable

#include 
#include 
#include "listaDDE.h"

nodo *first = NULL, *last = NULL;

nodo *getFirst()
{
	printf("call getFirst()\n");
	return first;
}

nodo *getLast()
{
	return last;
}
void inseri(nodo **root, int socket, char nome[],char nick[],char host[])
{
	nodo *aux;
	//primeira inserção
	if(*root == NULL)
	{
		*root = (nodo *) malloc(sizeof (nodo));
		if(*root == NULL)
		{
			perror("erro de alocação\n");

		}
		(*root)->socket = socket;
		strcpy((*root)->nome , nome);
		strcpy((*root)->nick , nick);
	        strcpy((*root)->host , host);
		(*root)->prox = NULL;
		(*root)->ante = NULL;
		 first = (*root);
		last = first;

	}
	else
	{
		aux = (nodo *) malloc(sizeof (nodo));
		if(aux == NULL)
		{
			perror("erro de alocação\n");

		}
		aux->socket = socket;
		strcpy(aux->nome , nome);
		strcpy(aux->nick , nick);
	        strcpy(aux->host , host);

		aux->ante =last;
            	aux->prox = NULL;

                last->prox = aux;
            	last = aux;
		*root = last;
	}
}

void removi(nodo *primeiro,int dado)
{
   nodo *aux = primeiro;
   while(aux != NULL)
   {
       if(dado == aux->socket && aux == first) //Remove first element
      {

	 if(aux->prox != NULL)
	 {
		printf("!= null\n");
		aux->prox->ante = NULL;
	        first = aux->prox;
	 }
	 else
	 {
		printf("null\n");
		free(first);

		break;
	 }

      }
      else if(dado == aux->socket && aux->prox == NULL) //remove last
      {
      	 aux->ante->prox = NULL;
         last = aux->ante;
         free(aux);
         break;
      }
      else if(dado == aux->socket &&  aux->prox != NULL && aux->ante !=NULL) //remove middle
      {
      	aux->ante->prox = aux->prox;
         aux->prox->ante = aux->ante;
         free(aux);
         break;
      }

      aux = aux->prox;
   }
}

void print (nodo *ini)
{
   nodo *p = first;
   while(p != NULL)
   {   printf ("socket %d cliente %s\n", p->socket,p->nome);
	p = p->prox;    

   }
}

nodo *busca (int key)
{
   nodo *p = getFirst();
   int flag = 0;
   while(p != NULL)
   {
   	if(p->socket == key)
	{
		return p;
	}
	p = p->prox;    

   }
   return NULL;
}

In order to compile this code together use the follow command gcc -o chatserver server.c listaDDE.c -lpthread
Using On the server
./chatserver

On the client telnet ipServer 5800

Digg if you like it: Development of a chat with the C sockets and Threads

UPDATE: This code is avaible in http://github.com/petryx/

Balanceando 2 links no Linux

Posted on jun 22, 2008 under Dicas Linux, Sem categoria, Tutoriais | 5 Comentários

Nesta matéria pretendo mostrar como fazer balanceamento entre links, utilizando uma máquina com o Linux instalado.

A imagem abaixo mostra a topologia de rede, nesta configuração temos uma Linux Box com três
placas de redes eth1 para os clientes, eth0 para o link1 e eth2 para o link2. O link1 é 2 vezes mais rápido que o link2.
balaceamento de links na internet

Existem várias técnicas que podem realizar balanceamento entre links como por exemplo: bonding, roteamento avançado. Irei utilizar roteamento avançado porque com port bonding não descobri como configurar o peso de cada link.

Bonding

Este método permite criar uma uma interface lógica de rede que agrega dois ou mais links físicos conectados a switchs separados. Mais detalhes sobre bonding

Roteamento avançado Linux

Linux possui recursos avançados para roteamento esses recursos estão implementados no kernel, então eles devem estar habilitados. Para saber mais sobre roteamento avançado acesso http://lartc.org/lartc.html

Então vamos colocar a mão na massa.

Pré-requisitos

Kernel

As seguintes opções devem estar habilitadas:

  • CONFIG_IP_ADVANCED_ROUTER (Networking/IP: Advanced Router)
  • CONFIG_IP_MULTIPLE_TABLES (Networking/IP: policy routing)

Estas opções habilitam o roteamento avançado e também possibilitam ter múltiplas tabelas de roteamento.

Para verificar se o seu kernel está compilado com estes recursos rode o seguinte comando:

grep -e CONFIG_IP_ADVANCED_ROUTER -e CONFIG_IP_MULTIPLE_TABLES /usr/src/linux/.config
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_MULTIPLE_TABLES=y

Se estes recursos não estiverem habilitados será necessário recompilar o kernel habilitando estes recursos. Rode os seguintes comandos para recompilar o kernel com estas opções.

cd /usr/src/linux
make menuconfig

Navegue para Network–>
Network Options –> e modifique as opções
IP: Advanced router para [*] e
IP: policy routing para [*]

Salve e rode make && make modules_install

IPROUTE2

Verifique se o iproute2 está instalado com o comando ip. Caso não esteja instalado neste site possui uma ótima documentação sobre o iproute2.

Definindo a tabela de Rotas

Vamos criar duas tabelas de rotas dentro do arquivo /etc/iproute/rt_tables

echo "1 Link1" >> /etc/iproute/rt_tables
echo "2 Link2" >> /etc/iproute/rt_tables

A partir de agora temos três tabelas de rotas Link1 e Link2.

A próxima etapa é preencher a tabela de rotas.

Rota Link1

/sbin/ip route add 200.xx.yy.0/24 dev eth0 src 200.xx.yy.2 table link1
/sbin/ip route add default via 200.xx.yy.1 table link1
/sbin/ip rule add from  200.xx.yy.2 table link1

Rota Link2

/sbin/ip route add 190.xx.yy.0/24 dev eth0 src 190.xx.yy.2 table link2
/sbin/ip route add default via 190.xx.yy.1 table link2
/sbin/ip rule add from  190.xx.yy.2 table link1

Balanceando

Para balancear o uso dos links devemos atribuir o peso de cada link. O peso é atribuído através do parâmetro weight no nosso exemplo vamos utilizar o peso 2 para o link1 e 1 para o link 2.

/sbin/ip route add default scope global\
         nexthop via 200.xx.yy.1 dev eth0 weight 2\
         nexthop via 190.xx.yy.1 dev eth1 weight 1

Script completo

#!/bin/bash
#
#Script para balanceamento de 2 links de acesso a internet
#Licença=GPL
#Author=Marlon Petry

NETMASK1=200.xx.yy.0/24
DEVICE1=eth0
IPADDRESS1=200.xx.yy.2
GATEWAY1=200.xx.yy.1
TABLE1=Link1

NETMASK2=190.xx.yy.0/24
DEVICE2=eth2
IPADDRESS2=190.xx.yy.2
GATEWAY2=190.xx.yy.1
TABLE2=Link2

#PESO DOS LINKS
W1=2
W2=1

#interface 1
/sbin/ifconfig eth0 down
/sbin/ifconfig eth0 $IPADDRESS1/29  up
/sbin/ip route add $NETMASK1 dev $DEVICE1 src $IPADDRESS1 table $TABLE1
/sbin/ip route add default via $GATEWAY1 table $TABLE1
/sbin/ip rule add from $IPADDRESS1 table $TABLE1

#Interface 2
/sbin/ifconfig eth2 down
/sbin/ifconfig eth2 $IPADDRESS2/29 up
/sbin/ip route add $NETMASK2 dev $DEVICE2 src $IPADDRESS2 table $TABLE2
/sbin/ip route add default via $GATEWAY2 table $TABLE2
/sbin/ip rule add from $IPADDRESS2 table $TABLE2

#Adicionando as rotas e o balanceamento de carga
/sbin/ip route add default scope global\
         nexthop via $GATEWAY1 dev $DEVICE1 weight $W1\
         nexthop via $GATEWAY2 dev $DEVICE2 weight $W2

echo "Balanceamento 2 link petryx.blogrs.com.br"

O balanceamento de links através de roteamento funciona bem, mas segundo o how-to http://lartc.org/lartc.html não é perfeito, pois as rotas são cacheadas. Isto significa que quando um site for acessado através do link1, sempre será acessado através da mesma rota. Este problema pode ser resolvido com a aplicação de um patch disponível no site http://www.ssi.bg/~ja/#routes.

Precisando de Consultoria em Linux entre em contato aqui.

Saiba mais

http://www.linuxhorizon.ro/iproute2.html
http://lartc.org/lartc.html
http://linux-ip.net/html/routing-intro.html
http://www.rnp.br/newsgen/0201/roteamento_linux.html
http://www.linuxjournal.com/article/5826

Tutorial Postfix Iniciante

Posted on mai 17, 2008 under Tutoriais | No Comment

Este é um tutorial sobre postfix bem básico não implementamos verificação de spam, antivírus.

Não é aconselhável colocar um servidor no ar com estas configurações.

Postfix é um MTA(Mail Transfer Agent), sendo uma
alternativa ou sendmail, qmail e outros. Tem como vantagens
estabilidade, seguranca e fácil configuraçao

Neste tutorial mostraremos como compilar e configurar o servidor
de email Postfix, nas suas configurações básicas:

1) Passo realizar o download da ultima release estavel

wget ftp://ftp.pucpr.br/postfix/official/postfix-2.4.5.tar.gz

2) Após concluído o download devemos realizar um backup dos
arquivos de configuraçãoo do sendmail, se estiver instalado

mv /usr/sbin/sendmail /usr/sbin/sendmail.OFF

mv /usr/bin/newaliases /usr/bin/newaliases.OFF

mv /usr/bin/mailq /usr/bin/mailq.OFF

chmod 755 /usr/sbin/sendmail.OFF /usr/bin/newaliases.OFF /usr/bin/mailq.OFF

3)Mover e descompactar os fontes


mv postfix-2.4.5.tar.gz /usr/src
cd /usr/src
tar -xzvf postfix-2.4.5.tar.gz

4)Como padrão no Linux sempre acompanha os fontes o arquivo
INSTALL que mostra detalhes da compilação do pacote

less INSTALL
make -f Makefile.init makefiles
make

Antes de executar o make install devemos criar o usuário postfix

Acrescentar a seguinte linha no passwd

vim /etc/passwd
postfix:*:12345:12345:postfix:/no/where:/no/shell

Acrescentar o grupo

#vim /etc/group
postfix:*:12345:
postdrop:*:54321:

6) Ao executar o make install será solicitado os caminhos do servidor de email neste caso usaremos os padrões do postfix

make install

install_root: [/]tempdir: o diretório de origem da instalação
config_directory: [/etc/postfix]
daemon_directory: [/usr/libexec/postfix]
command_directory: [/usr/sbin]
queue_directory: [/var/spool/postfix]
sendmail_path: [/usr/sbin/sendmail]
newalises_path: [/usr/bin/newaliases]
mailq_path: [/usr/bin/mailq]
mail_owner: [postfix]
setgid_group: [postdrop]
html_directory: [/var/www/htdocs/postfix/]
manpage_directory: [/usr/local/man]

readme_directory: [/etc/postfix]

A partir daqui o postfix já esta compilado e instalado só falta configurar

vim  /etc/postfix/main.cf

myhostname = localhost
mydomain = localdomain.com.br
mydestination = $myhostname, localhost.$mydomain, $mydomain,
mail.$mydomain

#Parametro para configurar as redes que serao aceitas no servido de email
mynetworks = 127.0.0.0/8

#Configuração para restricao de envio de email

smtpd_recipient_restrictions = permit_mynetworks,check_client_access,hash:/etc/postfix/client_access
check_relay_domains
#Local de entrega dos emails
mail_spool_directory = /var/spool/mail

Após realizada as configurações podemos verificar se existe algum erro de configuração com o comando

postfix check

Não havendo erros podemos iniciar o servidor de email

postfix start

Para verificar o funcionamento podemos executar o comando

netstat -vantu

Este comando mostra todos as conexoes tcp e udp na maquina devemos procurar pela porta 25

Testando o servidor

telnet 127.0.0.1 25

helo  a resposta deve ser a seguinte 250 OK

mail from:
aresposta deve ser a seguinte 250 OK - mail from

rcpt to:
a resposta deve ser a seguinte 250 OK - Recipient

data
a resposta deve ser a seguinte 354 Send data. Finalizar com
.

quit

OK servidor testado, verifique se recebeu a mensagem

Outra forma de verificar o funcionamento é através do logs

tail -f /var/logs/mail/info