Mostrando postagens com marcador rede. Mostrar todas as postagens
Mostrando postagens com marcador rede. Mostrar todas as postagens

Adicionando uma página de cadastro de usuários (Hotspot) em ASP.NET no Mikrotik

Cada projeto que pego, é uma aventura nova a ser encarada! Dessa vez me adentrei no universo de Linux, rede, SSH, infra e tudo o que é direito. Quem não conhece, a Mikrotik é uma empresa de grande referência no que tange em equipamentos para redes de computadores. Seu principal destaque é o RouterOS que é sistema operacional que torna o roteador um poderoso gerente de rede. Dentro do Mikrotik (irei me referenciar sempre dessa forma generalizando como um produto), há o HotSpot. Com ele pode-se gerenciar quem irá autenticar na rede para usar a internet (ou apenas a intranet), banda usada, taxa de transferência e outras funcionalidades por usuário ou de forma geral. Um exemplo de uso desse sistema é de quando você vai a uma rede corporativa onde precisa autenticar-se para usar a internet... é isso!


Qual é o objetivo desse artigo então? A princípio é apenas obter as páginas originais de hotspot do Mikrotik, colocar um redirecionador para uma página externa, criar uma página externa de cadastro de usuário (para que possa acessar a rede) e fazer funcionar. Não ensinarei como configurar ou criar o hotspot. Pela net há vários tutoriais muito bons sobre o assunto e também não é de minha área. Recomendo fortemente o fórum da Under-Linux que lá o pessoal manja muito no assunto.

Nesse artigo usei o Mikrotik MKBR100 que é bem fácil de usar: basta plugar o cabo de rede da internet, do servidor e da energia. Pronto!

Para acessar seu SO, deve-se utilizar o Winbox como se fosse um daqueles players de máquina virtual ou OpenSSH. Vamos lá colocar a mão na massa!

Conecte o cabo de rede de seu PC (ou servidor) na porta (interface) ether2 do Mikrotik. Agora conecte outro cabo na ether1 para os outros computadores da rede (ou roteador simples). Porquê na ether1? Estou considerando que o hotspot está configurado para monitorar essa interface enquanto a ether2 será utilizado para que o servidor de comunique com o aparelho. Seria algo do tipo:



Vá em IP > Address no Mikrotik para que sejam configuradas as interfaces e sejam endereçados conforme os exemplos abaixo:

  • ether1: 192.168.88.1
  • ether2: 192.168.88.2

Somente através de IP que será possível enviar os arquivos do hotspot. Se ficar conectando, via MAC, pelo Winbox, você terá a mensagem de erro: "router has been disconnected" (logo, conecte-se usando a ether2 - 192.168.88.2). E outra coisa é: se não seguir o esquema acima, outros erros você terá, como:

could not connect to ... no response
could not connect to ... connection refused

could not connect to ... network is unreachable
could not fetch index from ... not found


Tudo isso por causa de configuração apenas! É bom deixar o IP do servidor fixo para que possa dar permissão de porta, firewall, etc. No caso deixei como 192.168.88.30 (que no caso era minha própria máquina). Uma dica: às vezes dê um reboot no aparelho!

O próximo passo é ativar a porta da API que o Mikrotik dispõe para integração com linguagens de programação. É através dela que iremos conectar e fazer a comunicação. Só que precisamos ativá-la. Vá em IP > Services e ative a API na porta 8728.


Também libere, no Firewall, as portas para conexão tanto do sistema quanto do Winbox (pelo IP), senão quando estiver acessando pela página de cadastro, irá surgir o erro: "nenhuma conexão pôde ser feita porque a máquina de destino as recusou ativamente ..:8728.".


Para permitir a navegação e envio de informações, adicione as permissões no Walled Garden.


Vejam que até o momento tudo é configuração e nada de programação. Continuemos...

Agora vamos em Files e selecione todos os arquivos da pasta hotspot, arraste para sua área de trabalho que será copiado. Para enviar faça o processo inverso... Se estiver acessando pelo IP vai dar certo, senão cairá a conexão (lembra que disse acima?).

Abra o HTML da página login.html e acione um link para a página de cadastro que ficará hospedada no servidor. Adicionei o link <a href="http://192.168.88.30/mikrotik/cadastro.aspx">cadastre-se</a> . Customize as demais páginas como desejar e as envie de volta. Praticamente terminamos de trabalhar no Mikrotik.

Agora vem o mais simples: criar a página ASP.NET. Você pode utilizar qualquer linguagem de programação que possa usar TCP na comunicação e que a API suporte: PHP, Delphi, C, C++, C#, Flash, Ruby on Rails, Java, Python, VB.NET, etc.

Faça o download da classe MK, em C# (eles já dispõe de classes prontas para outras linguagens também), nesse link aqui e adicione no seu projeto. Agora crie um Web Form adicionando os campos que queira trabalhar. No meu exemplo, só quis login (username) e senha. Adicione um Button e um método para executar o cadastro do usuário conforme exemplo abaixo:


             // Autenticação
            MK mikrotik = new MK("192.168.88.2");
            if (!mikrotik.Login("admin", ""))
            {
                ScriptManager.RegisterStartupScript(Page, typeof(Page), "alert", "alert('Houve um problema de comunicação com o Hotspot! Por favor, tente mais tarde.');", true);
                mikrotik.Close();
                return;
            }

            // Requisição
            mikrotik.Send("/ip/hotspot/user/add");
            mikrotik.Send("=name=" + nome.Text);
            mikrotik.Send("=password=" + senha.Text, true);

            //Retorno
            string retorno = string.Empty;
            foreach (string h in mikrotik.Read())
            {
                if (retorno != string.Empty)
                    retorno += ", ";
                retorno += h;
            }

            // Fecha objeto
            mikrotik.Close();

            // Validação
            if (retorno.ToLower().Contains("!done=ret="))
                ScriptManager.RegisterStartupScript(Page, typeof(Page), "alert", "alert('Cadastro realizado com sucesso!'); location.href='http://192.168.88.1/login.html';", true);
            else if (retorno.ToLower().Contains("message=failure: already have user with this name for this server"))
                ScriptManager.RegisterStartupScript(Page, typeof(Page), "alert", "alert('Já existe um usuário com esse nome!');", true);
            else
                ScriptManager.RegisterStartupScript(Page, typeof(Page), "alert", "alert('Falha no cadastro: " + retorno + "!');", true);


Você poderia não só fazer o cadastro de usuário no hotspot como também executar qualquer comando (SSH) no Mikrotik. Lembrando que eu atropelei muita coisa aí no que diz respeito a configuração do dispositivo na qual disse logo no início que não era minha finalidade. Vocês observaram que a parte de programação é bem simples do que configuração... e com certeza é! Agora nunca irá sair de minha cabeça a palavra Mikrotik Mikrotik Mikrotik Mikrotik Mikrotik ... Por favor, qualquer erro ou informação adicional me avise!

[]'s

UPDATE: disponibilizei uma implementação no post http://thiagomarcal.blogspot.com.br/2016/09/implementacao-do-aspnet-c-com-o.html

Comunicando com microterminal em ASP.NET

Quem já foi em supermercado e nunca viu aquelas maquininhas que o operador fica digitando? Pois é... estamos falando dela mesma. Parece ser fácil seu uso, mas quem começa a trabalhar com elas é de perder os cabelos.


Nesse artigo veremos como comunicar com um microterminal via TCP/IP e trocar informações (ida e volta). Para isso vamos utilizar o modelo da Gertec MT 720. Uma breve descrição do aparelho e seu uso (retirado daqui):

"O MT 720 é um excelente microterminal que opera em rede Ethernet com protocolos TCP-IP. Seu teclado com 20 teclas programáveis pode ser utilizado com funções específicas de atalhos para agilizar a operação.
As teclas re-legendáveis permitem a identificação da função de cada tecla. O display com back light (iluminado), com 20 caracteres por 2 linhas, permite facilmente a visualização da informação, principalmente em ambientes que possuem pouca iluminação, como bares noturnos, por exemplo.
Através de uma porta de teclado (AT/PS2) e mais 3 portas Seriais (RS-232) é possível a conexão de periféricos como: Leitor de Código de Barras, Display de Cliente, Balança, Impressora, etc.
O MT 720 é ideal para aplicações de Cartão de Consumo, soluções para Bares, Lanchonetes, Restaurantes Self-Service, Livrarias, Papelarias, apontamento de produção em Indústrias."
Na própria página do dispositivo (citada acima) tem alguns downloads de arquivos, dentre eles alguns códigos-fontes com exemplos de como fazer a comunicação bem como realizar as operações pelas quais foi criado. Um porém: só tem disponíveis nas linguagens C++, Delphi e VB (não é VB.NET).

Daí pensamos: "sem problemas! é só converter pra VB.NET a partir do VB"... Também pensei nisso e não consegui! Dando uma olhada de perto no código-fonte dá para saber que as proezas encontradas são só possíveis por artifícios que a linguagem oferece: por exemplo, ponteiros. Quem já programou em VB via a grande flexibilidade da linguagem de fazer tudo o que quer e do jeito que era mais conveniente. Maravilha! Pena que tenhamos que seguir certos padrões. Fica a dica: se não quiser perder tempo, pegue logo o código prontinho lá na página do fabricante (vem também no CD quando compra o aparelho) e utilize. De preferência use o Delphi e em seguida em VB. Se quiser aventurar vamos com C#...

Se escolheu C# siga lendo pois, em diante, veremos como fazer... Teremos os seguintes objetivos na implementação:

  1. Criar uma única aplicação que irá receber e enviar os dados;
  2. Exibir o que foi digitado tanto no microterminal quanto no monitor.


Instalação

Leia o manual do usuário aqui. Em resumo: ligue o microterminal na rede elétrica e conecte na porta traseira um cabo RJ-45 no dispositivo e a rede. Em seguida configure, no microterminal, o IP do Servidor (no meu caso, considerei minha máquina local com o IP 192.168.1.100, por exemplo). Demais configurações a seu gosto...



Implementação

Criemos um Windows Form. Coloquei alguns controles para embelezar a aplicação...



O mais importante é adicionar um objeto Timer. Os demais coloquei para gerar a aplicação final (que ficará no tray - perto do relógio - e outras coisas fru-frus). Configure seu Timer com Interval de 50. Pegue a DLL pmtg.dll e copie para sua aplicação. Eu disse copie! Você não conseguirá aplicar Reference sobre ela. Clique com o botão direito sobre a DLL e escolha Properties. Em Copy to Output Directory coloque Copy Always.



Agora vamos ao código! Clique sobre o WinForm e escolha View Code. Cole os códigos abaixo para que possamos usá-las no form:


        // VARIÁVEIS
        IntPtr v_Hwnd;
        int statusCard;
        int statusSerial;
        int MsgReceiveData = 1;
        string[] dados = new string[255];


        // INICIALIZAÇÃO DE FUNÇÕES EXTERNAS
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_startserver(IntPtr mywhnd, int conecmsg, int commumsg);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern void mt_finishserver();
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_getkey(int id, StringBuilder str);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_backspace(int id);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_dispstr(int id, string str);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_dispch(int id, char ch);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_dispclrln(int id, int lin);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]]
        public static extern int mt_gotoxy(int id, int lin, int col);



Em seguida adicionamos as duas funções primordiais: início (quando carregar o formulário) e término (quando fechar o formulário):


        private void MicroTerminal_Load(object sender, EventArgs e)
        {
            v_Hwnd = this.Handle;
            statusCard = 0;
            statusSerial = 0;
            if (mt_startserver(v_Hwnd, 0, MsgReceiveData) == 1)
            {
                temporizadorLista.Enabled = true;
            }
            else
                MessageBox.Show("Não foi possível carregar os módulos de conexão à leitora!");
        }



        private void MicroTerminal_FormClosed(object sender, FormClosedEventArgs e)
        {
            temporizadorLista.Enabled = false;
            mt_finishserver();
        }



Lembrando que esses eventos devem estar configurados (não é apenas copiar e colar o código, lembra? deve-se indicar lá em Events do Form). Com isso, ao fazer o primeiro teste, sua aplicação já estará recebendo dados do microterminal. Em seguida devemos adicionar um evento Tick ao Timer. Ou seja, a cada 50 milisegundos (lembra que colocamos com esse valor) irá ser executado um determinado método.

Antes disso vamos criar um método que irá limpar a tela do microterminal e reiniciar os dados de entrada:


                 private void ReiniciaEntrada(int i)
        {
            // Limpa as duas linhas e o que foi armazenado
            dados[i] = "";
            mt_dispclrln(i, 1);
            mt_dispclrln(i, 2);
            // Coloca o cursor na primeira linha e prepara o display
            mt_gotoxy(i, 1, 0);
            mt_dispstr(i, "Numero: ");
            mt_gotoxy(i, 2, 0);
        }


Enfim adicionamos o código que irá ler temporariamente cada leitora conectada à rede e coletar/processar os dados de acordo com o que desejar. No meu caso deixei o seguinte:


        private void temporizadorLista_Tick(object sender, EventArgs e)
        {
            StringBuilder rntStr = new StringBuilder();
            int i = 0;
            // Loop em toda faixa de Ips úteis: cada leitora conectada na rede
            while (i < 255)
            {
                // Captura algo do teclado
                if (mt_getkey(i, rntStr) == 1)
                {
                    string chrAsHex = ((int)rntStr[0]).ToString("x");
                    // Entrada do display caso seja um número
                    if ((chrAsHex == "3030") || (chrAsHex == "30") || (chrAsHex == "31") || (chrAsHex == "32") || (chrAsHex == "33") || (chrAsHex == "34") || (chrAsHex == "35") || (chrAsHex == "36") || (chrAsHex == "37") || (chrAsHex == "38") || (chrAsHex == "39"))
                    {
                        if (dados[i].Length >= 20)
                            dados[i] = dados[i].Substring(0, 19) + rntStr[0];
                        else
                            dados[i] += rntStr[0];
                        mt_dispch(i, rntStr[0]);
                    }
                    // Se for um ENTER, dá a entrada na tela para mostrar
                    else if (chrAsHex == "d")
                    {
                        // Captura e trata a entrada
                        if (dados[i] != "")
                        {
                            // Faz o processamento do que desejar em dados[i]
                        }
                        // Limpa tela
                        ReiniciaEntrada(i);
                    }
                    // Se for um ESC, apaga tudo
                    else if (chrAsHex == "1b")
                    {
                        // Limpa tela
                        ReiniciaEntrada(i);
                    }
                    // Se for backspace apaga último caractere do display
                    else if (chrAsHex == "8")
                    {
                        if (dados[i].Length > 0)
                            dados[i] = dados[i].Substring(0, dados[i].Length - 1);
                        mt_backspace(i);
                    }
                    // Se apertar * toca o som
                    else if (chrAsHex == "2a")
                    {
                        // Toca um sonzinho... depois publico o código de tocar som!
                    }
                }
                i++;
            }
        }


Feito! Rode sua aplicação e digite algo no teclado do microterminal e verá que o que está sendo digitado está indo tanto para a aplicação quanto para o display (no microterminal). A saída seria algo do tipo:


Se precisar de saída na tela crie um outro WinForm que ocupe toda tela (sua) e captura o que está no display do microterminal. Assim é mais fácil! Ou faça do jeito que sua imaginação mandar! O mais difícil já passou...

Para quem quiser capturar os IPs de cada microterminal, utilize os métodos:


[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern TTABSOCK mt_connectlist();

ou


[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern StringBuilder mt_ipfromid(int id);



Nessas funções tem algumas particularidades muito chatinhas de se trabalhar (veja no manual das funções) por isso deixei de lado. Principalmente a classe:


    [StructLayout(LayoutKind.Sequential)]
    public struct TTABSOCK
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
        public UInt32[] TSOCK;
    }


Quem quiser se aventurar nela, fica aí a dica. Esse artigo merecia até uma vídeo-aula, mas a preguiça às vezes é muito forte! É até legalzinho ter esses desafios, mas às vezes se torna muito chato quando não consegue. Enfim, quanto menos se estressar, melhor! Então tente usar as implementações que já a Gertec já disponibilizou, caso não queira aventurar, a menos que precise de algo mais específico.
Falar que nem Marcoratti: "eu sei, é apenas ASP.NET, mas eu gosto!"