/** 
 *   @file  echosrv.c
 *
 *   @brief   
 *      This program implements a TCP and UDP echo server, which echos back any
 *      input it receives.
 *
 *  \par
 *  NOTE:
 *      (C) Copyright 2008, Texas Instruments, Inc.
 *
 *  \par
 */
#include <netmain.h>
#include <cslr_emac.h>

#define EMAC_REGS                 ((CSL_EmacRegs *)0x02C80000u)
/** 
 *  @b Description
 *  @n  
 *      This is the TCP/UDP v4 Echo Server.
 *
 *  @retval
 *      Not Applicable
 */
void echosrv()
{
    SOCKET   stcp = INVALID_SOCKET;
    SOCKET   sudp = INVALID_SOCKET;
    SOCKET   stcpactive = INVALID_SOCKET;
    SOCKET   stcpbusy;
    struct   sockaddr_in sin1,Info;
    struct   timeval timeout;           // Timeout struct for select
    int      size,tmp,InfoLength;
    HANDLE   hBuffer;
    char     *pBuf;
    IPN     yourIP;
    char    pszyourIP[32];

    // Allocate the file environment for this task
    fdOpenSession( TaskSelf() );

    // Create the main TCP listen socket
    stcp = socket(AF_INET, SOCK_STREAMNC, IPPROTO_TCP);
    if( stcp == INVALID_SOCKET )
        goto leave;

    // Set Port = 7, leaving IP address = Any
    bzero( &sin1, sizeof(struct sockaddr_in) );
    sin1.sin_family = AF_INET;
    sin1.sin_len    = sizeof( sin1 );
    sin1.sin_port   = htons(7);

    // Bind socket
    if ( bind( stcp, (PSA) &sin1, sizeof(sin1) ) < 0 )
        goto leave;

    // Start listening
    if ( listen( stcp, 1) < 0 )
        goto leave;

    // Create our UDP echo socket
    sudp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if( sudp == INVALID_SOCKET )
        goto leave;

    // Bind the same as TCP ... Port = 7, IPAddr = Any
    if ( bind( sudp, (PSA) &sin1, sizeof(sin1) ) < 0 )
        goto leave;

    // Configure our timeout to be 15 seconds
    timeout.tv_sec  = 15;
    timeout.tv_usec = 0;

    printf("EchoSrv Initialized\n");

    // Run until task is destroyed by the system
    for(;;)
    {
        fd_set ibits, obits, xbits;
        int    cnt;


        // Clear the select flags
        FD_ZERO(&ibits);
        FD_ZERO(&obits);
        FD_ZERO(&xbits);

        // We examine the main TCP, UDP, and active TCP (if any)
        FD_SET(stcp, &ibits);
        FD_SET(sudp, &ibits);

        // Wait for socket activity
        if( stcpactive == INVALID_SOCKET )
        {
            // Wait without timeout
            tmp = fdSelect( 4, &ibits, &obits, &xbits, 0 );
        }
        else
        {
            // Wait for set timeout - abort active connection on no activity
            FD_SET(stcpactive, &ibits);
            tmp = fdSelect( 4, &ibits, &obits, &xbits, &timeout );
            if( tmp <= 0 )
            {
                fdClose( stcpactive );
                stcpactive = INVALID_SOCKET;
            }
        }

        if( tmp < 0 )
            goto leave;

        // Check for a new TCP connection
        if( FD_ISSET(stcp, &ibits) )
        {
            // We have a new connection. Assign it so sbusy at
            // first...
            size = sizeof( sin1 );
            stcpbusy = accept( stcp, (PSA)&sin1, &size );

            // If the active socket is free use it, else print out
            // a busy message
            if( stcpactive == INVALID_SOCKET )
                stcpactive = stcpbusy;
            else
                fdClose( stcpbusy );
        }

        // Check for new data on active TCP connection
        if( stcpactive != INVALID_SOCKET && FD_ISSET(stcpactive, &ibits) )
        {
            // There is data available on the active connection
            cnt = (int)recvnc( stcpactive, (void **)&pBuf, 0, &hBuffer );

            if( cnt > 0 )
            {
            	getpeername(stcpactive,(PSA)&Info, &InfoLength);
                yourIP = Info.sin_addr.s_addr;
                NtIPN2Str( yourIP, pszyourIP );
                if( send( stcpactive, pBuf, cnt, 0 ) < 0 )
                {
                    fdClose( stcpactive );
                    stcpactive = INVALID_SOCKET;
                }
                recvncfree( hBuffer );
            }
            // If the connection got an error or disconnect, close
            else
            {
                fdClose( stcpactive );
                stcpactive = INVALID_SOCKET;
            }
        }

        // Check for new data on UDP socket
        if( FD_ISSET(sudp, &ibits) )
        {
            tmp = sizeof( sin1 );
            cnt = (int)recvncfrom( sudp, (void **)&pBuf, 0,(struct sockaddr *)&sin1, &tmp, &hBuffer );

            // Spit any data back out
            if( cnt >= 0 )
            {
                sendto( sudp, pBuf, cnt, 0,(struct sockaddr *)&sin1, sizeof(sin1) );
                recvncfree( hBuffer );
            }
        }
    }

leave:
    // We only get here on an error - close the sockets
    if( stcp != INVALID_SOCKET )
        fdClose( stcp );
    if( sudp != INVALID_SOCKET )
        fdClose( sudp );

    printf("EchoSrv Fatal Error\n");

    // This task is killed by the system - here, we block
    TaskBlock( TaskSelf() );
}

#ifdef _INCLUDE_IPv6_CODE

/** 
 *  @b Description
 *  @n  
 *      This is the TCP/UDP v6 Echo Server.
 *
 *  @retval
 *      Not Applicable
 */
void v6echosrv()
{
    SOCKET   stcp = INVALID_SOCKET;
    SOCKET   sudp = INVALID_SOCKET;
    SOCKET   stcpactive = INVALID_SOCKET;
    SOCKET   stcpbusy;
    struct   sockaddr_in6 sin1;
    struct   timeval timeout;           // Timeout struct for select
    int      size,tmp;
    char     Buffer[1500];

    // Allocate the file environment for this task
    fdOpenSession( TaskSelf() );

    /* Create the main TCPv6 Listening Socket. */ 
    stcp = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
    if( stcp == INVALID_SOCKET )
        goto leave;

    /* Set Port = 7, leaving IP address = Any and bind the socket. */
    bzero( &sin1, sizeof(struct sockaddr_in6) );
    sin1.sin6_family = AF_INET6;
    sin1.sin6_port   = htons(7);
    if ( bind( stcp, (PSA) &sin1, sizeof(sin1) ) < 0 )
        goto leave;

    /* Listen for connections. */ 
    if ( listen( stcp, 1) < 0 )
        goto leave;

    /* Create our UDP echo socket */
    sudp = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
    if( sudp == INVALID_SOCKET )
        goto leave;

    /* Bind the same as TCP ... Port = 7, IPAddr = Any */
    if ( bind( sudp, (PSA) &sin1, sizeof(sin1) ) < 0 )
        goto leave;

    /* Configure our timeout to be 15 seconds */
    timeout.tv_sec  = 15;
    timeout.tv_usec = 0;

    printf("V6EchoSrv Initialized\n");

    /* Run until task is destroyed by the system */
    for(;;)
    {
        fd_set ibits, obits, xbits;
        int    cnt;

        // Clear the select flags
        FD_ZERO(&ibits);
        FD_ZERO(&obits);
        FD_ZERO(&xbits);

        // We examine the main TCP, UDP, and active TCP (if any)
        FD_SET(stcp, &ibits);
        FD_SET(sudp, &ibits);

        // Wait for socket activity
        if( stcpactive == INVALID_SOCKET )
        {
            // Wait without timeout
            tmp = fdSelect( 4, &ibits, &obits, &xbits, 0 );
        }
        else
        {
            // Wait for set timeout - abort active connection on no activity
            FD_SET(stcpactive, &ibits);
            tmp = fdSelect( 4, &ibits, &obits, &xbits, &timeout );
            if( tmp <= 0 )
            {
                fdClose( stcpactive );
                stcpactive = INVALID_SOCKET;
            }
        }

        if( tmp < 0 )
            goto leave;

        // Check for a new TCP connection
        if( FD_ISSET(stcp, &ibits) )
        {
            // We have a new connection. Assign it so sbusy at
            // first...
            size = sizeof( sin1 );
            stcpbusy = accept( stcp, (PSA)&sin1, &size );

            // If the active socket is free use it, else print out
            // a busy message
            if( stcpactive == INVALID_SOCKET )
                stcpactive = stcpbusy;
            else
                fdClose( stcpbusy );
        }

        // Check for new data on active TCP connection
        if( stcpactive != INVALID_SOCKET && FD_ISSET(stcpactive, &ibits) )
        {
            // There is data available on the active connection
            cnt = recv( stcpactive, (void *)&Buffer[0], sizeof(Buffer), 0 );
            if( cnt > 0 )
            {
                if( send( stcpactive, (void *)&Buffer[0], cnt, 0 ) < 0 )
                {
                    fdClose( stcpactive );
                    stcpactive = INVALID_SOCKET;
                }
            }
            // If the connection got an error or disconnect, close
            else
            {
                fdClose( stcpactive );
                stcpactive = INVALID_SOCKET;
            }
        }

        // Check for new data on UDP socket
        if( FD_ISSET(sudp, &ibits) )
        {
            tmp = sizeof( sin1 );
            cnt = recvfrom (sudp, (void *)&Buffer[0], sizeof(Buffer), 0, (struct sockaddr *)&sin1, &tmp);

            // Spit any data back out
            if( cnt >= 0 )
            {
                sendto( sudp, (void *)&Buffer[0], cnt, 0,(struct sockaddr *)&sin1, sizeof(sin1) );
            }
        }
    }

leave:
    // We only get here on an error - close the sockets
    if( stcp != INVALID_SOCKET )
        fdClose( stcp );
    if( sudp != INVALID_SOCKET )
        fdClose( sudp );

    printf("V6EchoSrv Fatal Error\n");

    // This task is killed by the system - here, we block
    TaskBlock( TaskSelf() );
}

#endif /* _INCLUDE_IPv6_CODE */

