///////////////////////////////////////////////////////////////////////////////////////
//  file   : tcp_client.c
//  author : Alain Greiner
//  date   : march 2020
///////////////////////////////////////////////////////////////////////////////////////
//  This file describes a single thread TCP client chat application.
//  The client send the first message.
///////////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <almosmkh.h>
#include <unistd.h>
#include <sys/socket.h>

#define   BUF_SIZE       256

#define   LOCAL_PORT     13
#define   LOCAL_ADDR     0xAAAAAAAA  // client

#define   REMOTE_PORT    13
#define   REMOTE_ADDR    0xBBBBBBBB  // server

////////////////////////////
void client_chat( int fdid )
{
    char   buffer[BUF_SIZE];   // string buffer (for send and receive)
    int    size;               // string length (including NUL)
    int    nbytes;             // number of characters actually sent or received

    // chat loop
    while( 1 )
    {
        // display client prompt
        printf("\n[from client] ");

        // build client message
        size = get_string( buffer , BUF_SIZE );

        // exit chat function when local message is the "exit" string
        if( strncmp( "exit" , buffer , 4 ) == 0 )
        {
            printf("\n[tcp_client stop] local message is <exit> => return to main\n" );
            return;
        }

        // send client message
        nbytes = send( fdid , buffer , size , 0 );

        if( nbytes != size )
        {
            printf("\n[tcp_client error] cannot send => return to main\n");
            return;
        }

        // display server prompt
        printf("\n[from server] ");

        // receive server message
        nbytes = recv( fdid , buffer , BUF_SIZE , 0 );

        if( nbytes < 0 )
        {
            printf("\n\n[tcp_client error] cannot receive => return to main\n" );
            return;
        }
        else if( nbytes == 0 )
        {
            printf("\n\n[tcp_client stop] receive EOF => return to main\n" );
            return;
        }
        
        // display server message
        printf("%s\n", buffer );

    } // end chat loop

}  // end client_chat()


////////////////
int main( void )
{
    int                  pid;          // process identifier
    int                  fdid;         // file index of local socket
    int                  error;

    struct sockaddr_in   client_sin;   // local client socket
    struct sockaddr_in   server_sin;   // remote server socket

    unsigned long long   start_cycle;

    // get  start cycle
    get_cycle( &start_cycle );
    printf("\n[tcp_client] starts at cycle %d\n", (unsigned int)start_cycle );

    pid = getpid();

    // 1. create TCP socket
    fdid = socket( AF_INET,
                   SOCK_STREAM,
                   0 );

    if( fdid < 0 )
    {
        printf("\n[tcp_client error] cannot create socket\n");
        exit( 0 );
    }
    else
    {
        printf("\n[tcp_client] created socket[%x,%d]\n", pid, fdid );
    }

    // 2. bind local socket
    client_sin.sin_domain = HTONS( AF_INET );
    client_sin.sin_addr   = HTONL( LOCAL_ADDR );
    client_sin.sin_port   = HTONS( LOCAL_PORT );

    error = bind( fdid,
                  (sockaddr_t *)(&client_sin),
                  sizeof(sockaddr_t) );
    if( error )
    {
        printf("\n[tcp_client error] bind failure on socketi[%x,%d]\n", pid, fdid );
        exit( 0 );
    }

    printf("\n[tcp_client] socket[%x,%d] bound : [%x,%x]\n",
    pid, fdid, client_sin.sin_addr, (unsigned int)client_sin.sin_port );

    // 3. connect to remote socket 
    server_sin.sin_domain = HTONS( AF_INET );
    server_sin.sin_addr   = HTONL( REMOTE_ADDR );
    server_sin.sin_port   = HTONS( REMOTE_PORT );

    error = connect( fdid,
                     (sockaddr_t *)(&server_sin),
                     sizeof(sockaddr_t) );
    if( error )
    {
        printf("\n[tcp_client error] connect failure on socket[%x,%d]\n", pid, fdid );
        exit( 0 );
    }

    printf("\n[tcp_client] socket[%x,%d] connected to server [%x,%x]\n",
    pid, fdid, server_sin.sin_addr, server_sin.sin_port );

    // 4. call chat function
    client_chat( fdid );

    // 5. close local socket
    close( fdid );

    printf("\n[tcp_client] closed socket[%x,%d]\n", pid, fdid );

    exit(0);

    return 0;
}
