{-------------------------------------------------------------}
{               CartaVox - Interface de rede
{-------------------------------------------------------------}

unit CarRede;

interface

uses winTypes, winProcs, winDos, shellApi, strings, winSock,
     dvcrt, dvWin,
     carVars, carMsg;

function abreConexao (nomeComput: string; porta: integer): integer;
procedure netDebug (s: pchar; tam: integer);
function recv (sock: integer; buf: PChar; len: integer;
                       flags: integer): integer;
function temDadoSock (sock: integer): boolean;

implementation

{-------------------------------------------------------------}
{                     abre a conexao
{-------------------------------------------------------------}

function abreConexao (nomeComput: string; porta: integer): integer;
var
    localAddr,                          { descricao dos endereços local e remoto }
    remoteAddr: sockaddr_in;
    enderHost: longint;
    hip: phostent;		        { retorna o endereco IP do soquete }
    ret: integer;
    wsaData: LPWSADATA;
    s: string;
    hostName, localName: array [0..128] of char;
    sock: integer;

begin
    abreConexao := -1;

    ret := WSAStartup ($0101, wsaData);
    if ret <> 0 then
        begin
            mensagem ('CTERRCOM', 1);  {'Não consegui ativar o sistema de comunicações do micro'}
            exit;
        end;

    {************ Cria soquete ***********}

    sock := _socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sock = -1) then
        begin
            mensagem ('CTNAOSOQ', 1);  {'Não consegui criar soquete'}
            exit;
        end;

    {************ Aloca uma porta para o processamento ***********}

    fillchar (localAddr, sizeof (localAddr), 0);
    with localAddr do
        begin
            sin_family := AF_INET ;
            sin_addr.s_addr := htonl (INADDR_ANY);
            sin_port := htons (0);
        end;

    ret := bind (sock, localAddr, sizeof(localAddr));
    if (ret = -1)  then
        begin
            mensagem ('CTERBIND', 1);  {'Não consegui alocar porta (bind)'}
            exit;
        end;

    {************ Descobre endereco IP do computador ***********}

    strPCopy (hostName, nomeComput);
    if (hostName[0] >= '0') and (hostName[0] <= '9')  then
        enderHost := inet_addr (hostName)
    else
        begin
            hip := gethostbyname (hostName);
            if (hip = NIL)  then
                begin
                    while keypressed do readkey;
    	            mensagem ('CTSEMSRV', 1);  {'Não consegui achar um servidor com este nome'}
                    exit;
                end;
            move (hip^.h_addr_list^[0]^, enderHost, 4);
        end;

    {************ Conecta computador ***********}

    fillchar (remoteAddr, sizeof (remoteAddr), 0);
    with remoteAddr do
        begin
            sin_family := AF_INET;
            move (enderHost, sin_addr, 4);
            sin_port := htons (porta);
        end;

    with remoteAddr.sin_addr do
        begin
            s := 'Conectando com ';
            write (s);
            writeln (strPas (inet_ntoa (enderHost)));
        end;

    if (connect (sock, remoteAddr, sizeof (remoteAddr)) = -1) then
        begin
            while keypressed do readkey;
            mensagem ('CTNAOCON', 1);  {'Não consegui realizar a conexao'}
            exit;
        end;

    gethostname (localName, 80);
    computLocal := strPas (localName);

    mensagem ('CTCONOK', 1);  {'Conexão realizada'}

    abreConexao := sock;
end;

{-------------------------------------------------------------}
{                  ve se chegou dado na rede
{-------------------------------------------------------------}

function temDadoSock (sock: integer): boolean;
var
    entradas: fd_set;
    tempoZero: timeVal;
begin
    with tempoZero do
        begin
            tv_sec := 0;
            tv_usec := 0;
        end;

    keypressed;    { força execução do scheduler do Windows }

    FD_ZERO (entradas);	 { monitora soquete }
    _FD_SET (sock, entradas);
    select (sock+1, @entradas, NIL, NIL, tempoZero);

    temDadoSock := FD_ISSET (sock, entradas);
end;

{-------------------------------------------------------------}
{                     recv nao bloqueante
{-------------------------------------------------------------}

function recv (sock: integer; buf: PChar; len: integer;
                       flags: integer): integer;
var
    entradas: fd_set;
    tempoZero: timeVal;
    esperando: boolean;
begin
    with tempoZero do
        begin
            tv_sec := 0;
            tv_usec := 0;
        end;

    esperando := true;
    while esperando do
        begin
            keypressed;    { força execução do scheduler do Windows }

            FD_ZERO (entradas);	 { monitora soquete }
            _FD_SET (sock, entradas);
            select (sock+1, @entradas, NIL, NIL, tempoZero);

            if FD_ISSET (sock, entradas) then
                begin
                    recv := winSock.recv (sock, buf, len, flags);
                    esperando := false;
                end;

            if keypressed and esperando then
                begin
                    if readkey = ESC then
                        begin
                            recv := -2;
                            esperando := false;
                        end;
                end;
        end;
end;

{-------------------------------------------------------------}
{                      escreve texto de debug
{-------------------------------------------------------------}

procedure netDebug (s: pchar; tam: integer);
begin
    if not debug then exit;
    textBackGround (BROWN);
    write ('>>>');
    writebuf (s, tam);
    textBackGround (BLACK);
end;

end.