/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 * Description.
 * =======================================================================
 * applicationStart() is the entry point for user applications.  This
 * This function will be called after the kernel has started and the
 * TCP/IP stack has loaded.  applicationTcpDown() is called periodically
 * after the kernel has started while the system is waiting for the
 * TCP/IP stack to start.  
 *                                                                        
 *                                                                        
 * Edit Date/Ver   Edit Description
 * ==============  ===================================================
 * 01/16/04  JZW    Now using NAHSStartServer to start up the AWS. Allows
 *                  total configuration and ability to call secure web server
 *
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tx_api.h>
#include <http_awsapi.h>
#include <sysAccess.h>
#include <bsp_api.h>
#include "ssl.h"
#include "appconf.h"
#include "server.h"     /*  For username/password */
#include "init.h"
#include "fservapi.h"
#include "snmpapi.h"
#include "snmpv1v2capi.h"

#define TRAP_PORT               162
#define TRAP_SINK_ADDR          0x0A342371     /* 10.52.35.113 */
#define TRAP_ENTERPRISE_NUM     901
#define TRAP_ENTERPRISE_LEN     8
#define TRAP_COMMUNITY          "public"

extern NaStatus initializeCustomMibs(void);
extern	int sendGreenLedTrap(void);
extern	int sendYellowLedTrap(void);

/* comment this to test using peer whitelist and revoked peer list*/
#define TEST_USING_CRL

/* function reads the specified file to given buffer. Function returns
   number of bytes read */
static int readKeysFromDB(char *fpath, char *buf, int buflen)
{
    int rlen, first_time = 1;
    FILE *fname = NULL;

    /*
     * Read from the file system the file that contain the CA
     * certificate.  If the file does not exist, wait until it
     * is downloaded to the file system via the FTP server.
     */
    do
    {
        fname = fopen(fpath, "r");
        if (fname)
        {
            rlen = fread(buf, 1, buflen, fname);
            if ((!rlen) || (rlen == EOF))
            {
                printf("C library fread() returned 0, error %d\n", getErrno());
                rlen = 0;
            }
            break;
        }
        else
        {
            if (first_time)
            {
                printf("Please load %s through FTP...\n", fpath);
                first_time = 0;
            }
            tx_thread_sleep(NABspTicksPerSecond);
        }
    } while (fname == NULL);

    if (fclose(fname))
    {
        printf("C library fclose() failed\n");
    }

    return rlen;
}


/*
 *
 *  Function: void applicationTcpDown (void)
 *
 *  Description:
 *
 *      This routine will be called by the NET+OS root thread once every 
 *      clock tick while it is waiting for the TCP/IP stack to come up.  
 *      This function can increment a counter everytime it's called to 
 *      keep track of how long we've been waiting for the stack to start.
 *      If we've been waiting too long, then this function can do something
 *      to handle the error.  
 *
 *      This function will not be called once the stack has started.
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */

void applicationTcpDown (void)

{
    static int ticksPassed = 0;

    ticksPassed++;
/*
 * Code to handle error condition if the stack doesn't come up goes here.
 */
}

static NaStatus setupTraps(void)
{
    NaSnmpTrap_t trap;
    NaStatus ret;

    /* At least one trap sink must be set before the agent is started. It will be used for 
       coldStart and authenticationFailure traps 
    */ 
    trap.destAddr.ss_port = ntohs(TRAP_PORT);
    trap.destAddr.ss_family = AF_INET;
    trap.destAddr.addr.ipv4.sin_addr.s_addr = ntohl(TRAP_SINK_ADDR);

    /* Set ss_family to 0 to use a default source address */
    trap.srcAddr.ss_family = 0; 
 
    trap.enterpriseNum = TRAP_ENTERPRISE_NUM;
    trap.enterpriseLen = TRAP_ENTERPRISE_LEN;

    strcpy((char *)trap.community, TRAP_COMMUNITY);
    trap.communityLen = strlen(TRAP_COMMUNITY);

    /* Both v1 and v2c traps will be sent. 
       Use NA_SNMP_TRAP_NO_V1 to send only v2c traps to this destination address.
       Use NA_SNMP_TRAP_NO_V2c to send only v1 traps to this destination address.
    */
    trap.versionFilter = 0; 

    ret = naSnmpAddTrap (&trap);
    if (ret != NA_SUCCESS)
    {
        printf("naSnmpAddTrap failed [0x%X]\n", (unsigned int)ret);
        return ret;
    }

#ifdef DISABLE_COLD_START_TRAP 
    ret = naSnmpDisableColdStartTrap();
    if (ret != NA_SUCCESS)
    {
        printf("naSnmpDisableColdStartTrap failed [0x%X]\n", ret);
        return ret;
    }
#endif
    return NA_SUCCESS;
}


/*
 *
 *  Function: void applicationStart (void)
 *
 *  Description:
 *
 *      This routine is responsible for starting the user application.  It should 
 *      create any threads or other resources the application needs.
 *
 *      ThreadX, the NET+OS device drivers, and the TCP/IP stack will be running
 *      when this function is called.
 *
 *  Parameters:
 *
 *      none
 *
 *  Return Values:
 *
 *      none
 *
 */

void applicationStart (void)
{
    unsigned int ccode;
    NaStatus startup;

    static unsigned char cipher_list[] = SSL_CIPHER_LIST_HTTPS_DEFAULT;  /* static required for persistent memory   */
    int	cipher_list_len = SSL_CIPHER_LIST_HTTPS_DEFAULT_LEN;
    NaSslCertDbHandle_t cert_db_handle = NULL;
    NaRpHsSecureParams_t LocalHttp_Parameters;
    int errorCode = 0;
    static char svr_cert_buffer[MAX_SSL_CERTIFICATE_LEN];
    static char svr_key_buffer[MAX_SSL_KEY_LEN];
    static char ca_cert_buffer[MAX_SSL_CERTIFICATE_LEN];
    int svr_cert_len, svr_key_len, ca_cert_len; 
#ifdef TEST_USING_CRL
    static char crl_cert_buffer[MAX_SSL_CERTIFICATE_LEN];
    int crl_cert_len;
#else
    static char clnt_cert_buffer[MAX_SSL_CERTIFICATE_LEN];
    static char bclnt_cert_buffer[MAX_SSL_CERTIFICATE_LEN];
    int clnt_cert_len, bclnt_cert_len;
#endif
    if (NABspFilesystemForCLib == 0)
    {
        printf ("BSP does not include file system for C library\n");
        goto exit;
    }
   /*
    * Link the FTP server to a file system volume and start the FTP server
    */
    
    /* Add the FTP server super user username and password */
    errorCode = NAsetSysAccess (NASYSACC_ADD, FTP_SUPERUSER_USERNAME, FTP_SUPERUSER_PASSWORD, NASYSACC_FS_GROUP2_READ | NASYSACC_FS_GROUP2_WRITE | NASYSACC_LEVEL_RW, NULL);
    if (errorCode != 0)
    {
        printf("NASetSysAccess Error: unsuccessfully set \"%s\" username \"%s\" password %d\n", 
               FTP_SUPERUSER_USERNAME , FTP_SUPERUSER_PASSWORD, errorCode);
        goto exit;
    }

    /* Link FTP server to file system volume and start FTP server */
    errorCode = naFtpFSInit(FS_VOLUME1_DIR, NA_FTP_DEF_USERS); 
    if (errorCode != 0)
    {
        printf("naFtpFSInit Error: %d\n", errorCode);
        goto exit;
    }

    /* read the server certificate from data base */
    svr_cert_len = readKeysFromDB(SVR_CERTICATE_FILEPATH, svr_cert_buffer, MAX_SSL_CERTIFICATE_LEN);
    if (!svr_cert_len) goto exit;

    /* read the server key from data base */
    svr_key_len = readKeysFromDB(SVR_KEY_FILEPATH, svr_key_buffer, MAX_SSL_KEY_LEN);
    if (!svr_key_len) goto exit;

    /* read the CA certificate from data base */
    ca_cert_len = readKeysFromDB(CA_CERTICATE_FILEPATH, ca_cert_buffer, MAX_SSL_CERTIFICATE_LEN);
    if (!ca_cert_len) goto exit;

#ifdef TEST_USING_CRL
    /* read the CRL from data base */
    crl_cert_len = readKeysFromDB(CERTICATE_REV_LIST_FILEPATH, crl_cert_buffer, MAX_SSL_CERTIFICATE_LEN);
    if (!crl_cert_len) goto exit;
#else
    /* read the client certificate from data base */
    clnt_cert_len = readKeysFromDB(CLNT_CERTICATE_FILEPATH, clnt_cert_buffer, MAX_SSL_CERTIFICATE_LEN);
    if (!clnt_cert_len) goto exit;

    /* read the another client certificate from data base (revoked) */
    bclnt_cert_len = readKeysFromDB(CLNT_REV_CERTICATE_FILEPATH, bclnt_cert_buffer, MAX_SSL_CERTIFICATE_LEN);
    if (!bclnt_cert_len) goto exit;
#endif

   /*
    * Register the URL search and preprocess functions and start the 
    * HTTP server
    */

    /*  Add Username Digi International password sysadm to the System Access Database   */
    NAsetSysAccess (NASYSACC_ADD, HTTP_USERNAME, HTTP_PASSWORD, NASYSACC_LEVEL_HTTP_R1, 0);
    if (errorCode != 0)
    {
        printf("NASetSysAccess Error: unsuccessfully set \"%s\" username \"%s\" password %d\n", 
               HTTP_USERNAME , HTTP_PASSWORD, errorCode);
        goto exit;
    }

    /* Create the certificate database */
    cert_db_handle = naSslCreateCertDb();
    if (cert_db_handle == NULL)
    {
        printf("Certificate database was not created\n");
        goto exit;
    }

    /* Add server certificate */
    errorCode = naSslAddCert(cert_db_handle,
                             svr_cert_buffer,
                             svr_cert_len,
                             SSL_CERTIFICATE_IDENTITY,
                             SSL_CERTIFICATE_FORMAT_PEM,
                             "Nassl Server");
    if (errorCode)
    {
        printf("naSslAddCert() failed, error %d\n", errorCode);
        goto exit;
    }

    /* Add server's private key */
    errorCode = naSslAddCertKey(cert_db_handle,
                                svr_key_buffer,
                                svr_key_len,
                                SSL_CERTIFICATE_KEY_TYPE_RSA,
                                SSL_CERTIFICATE_FORMAT_PEM,
                                SVR_KEY_PASSWORD);
    if (errorCode)
    {
        printf("naSslAddCertKey() failed, error %d\n", errorCode);
        goto exit;
    }

    /* Add CA certificate */
    errorCode = naSslAddCert(cert_db_handle,
                             ca_cert_buffer,
                             ca_cert_len,
                             SSL_CERTIFICATE_CA,
                             SSL_CERTIFICATE_FORMAT_PEM,
                             "Nassl CA");
    if (errorCode)
    {
        printf("naSslAddCert() failed, error %d\n", errorCode);
        goto exit;
    }

#ifdef TEST_USING_CRL
    /* Add CRL */
    errorCode = naSslAddCert(cert_db_handle,
                             crl_cert_buffer,
                             crl_cert_len,
                             SSL_CERTIFICATE_CRL,
                             SSL_CERTIFICATE_FORMAT_PEM,
                             "Nassl CRL");
    if (errorCode)
    {
        printf("naSslAddCert() failed, error %d\n", errorCode);
        goto exit;
    }
#else
    /* Add client certificate */
    errorCode = naSslAddCert(cert_db_handle,
                             clnt_cert_buffer,
                             clnt_cert_len,
                             SSL_CERTIFICATE_PEER,
                             SSL_CERTIFICATE_FORMAT_PEM,
                             "Nassl Client");
    if (errorCode)
    {
        printf("naSslAddCert() failed, error %d\n", errorCode);
        goto exit;
    }

    /* Add revoked client certificate */
    errorCode = naSslAddCert(cert_db_handle,
                             bclnt_cert_buffer,
                             bclnt_cert_len,
                             SSL_CERTIFICATE_REVOKED_PEER,
                             SSL_CERTIFICATE_FORMAT_PEM,
                             "Nassl bad client");
    if (errorCode)
    {
        printf("naSslAddCert() failed, error %d\n", errorCode);
        goto exit;
    }
#endif

    /* use SSL_CERTIFICATE_VERIFY_NONE if you don't want server 
       to send certificate request to client */
    errorCode = naSslSetCertVerify(cert_db_handle, NULL, SSL_CERTIFICATE_VERIFY_PEER);
    if (errorCode)
    {
        printf("naSslSetCertVerify() failed, error %d\n", errorCode);
        goto exit;
    }
    
    /* set the secure parameters */
    memset (&LocalHttp_Parameters, 0, sizeof(LocalHttp_Parameters));
    LocalHttp_Parameters.SecurityParams.cipher_list = cipher_list;
    LocalHttp_Parameters.SecurityParams.cipher_list_len = cipher_list_len;
    LocalHttp_Parameters.SecurityParams.secure_only = HTTPS_ONLY;
    LocalHttp_Parameters.SecurityParams.cert_db_handle = cert_db_handle;

    /* the Lengthofstructure field defines the version of the protocol */
    LocalHttp_Parameters.WebServerParams.Lengthofstructure  = sizeof (HS_SERVER_PARAMETER);

    errorCode = naRpNgStartServerSecure(&LocalHttp_Parameters);
    if (errorCode)
    {
        printf("naRpNgStartServerSecure() failed, error %d\n", errorCode);
        goto exit;
    }

    printf ("AWS HTTPS Web Server is ready.\n");
    
       ccode = NAsetSysAccess (NASYSACC_ADD, "public", "public", NASYSACC_LEVEL_SNMP_R, NULL);
    if (ccode != 0)
    {
        printf ("NAsetSysAccess failed for the public account: %d.\n", ccode);
        goto exit;
    }

    ccode = NAsetSysAccess (NASYSACC_ADD, "private", "private", NASYSACC_LEVEL_SNMP_RW, NULL);
    if (ccode != 0)
    {
        printf ("NAsetSysAccess failed for the private account: %d.\n", ccode);
        goto exit;
    }

    if (initializeCustomMibs() != NA_SUCCESS)
    {
        printf("initializeCustomMibs() failed, Treck SNMP agent was not started\n");
        goto exit;
    }

    if (setupTraps() != NA_SUCCESS)
    {
        printf("setupTraps() failed, Treck SNMP agent was not started\n");
        goto exit;
    }

    startup = naSnmpStart();
    if (startup != NA_SUCCESS)
    {
        printf("naSnmpStart() failed: %d\n", (int)startup);
        goto exit;
    }
	sendGreenLedTrap();
	sendYellowLedTrap();

    printf("The example MIB has been loaded.\n");
   
    tx_thread_suspend(tx_thread_identify());
    
exit:
    return;
}

