Exemplo n.º 1
0
/*****************************************************************************
  Function:
	int gethostname(char* name, int namelen )

  Summary:
	Returns the standard host name for the system.

  Description:
	This function returns the standard host name of the system which is
	calling this function.	The returned name is null-terminated.

  Precondition:
	None.

  Parameters:
	name - Pointer to a buffer that receives the local host name.
	namelen - size of the name array.

  Returns:
	Success will return a value of 0.
	If name is too short to hold the host name or any other error occurs,
	SOCKET_ERROR (-1) will be returned (and errno set accordingly).
    On error, *name will be unmodified
	and no null terminator will be generated.

  Remarks:
	The function returns the host name as set on the default network interface.

  ***************************************************************************/
int gethostname(char* name, int namelen)
{
    uint16_t wSourceLen;
    uint16_t w;
    uint8_t v;
    TCPIP_NET_IF* pNetIf;

    pNetIf = (TCPIP_NET_IF*)TCPIP_STACK_GetDefaultNet();

    wSourceLen = sizeof(pNetIf->NetBIOSName);
    for(w = 0; w < wSourceLen; w++)
    {
        v = pNetIf->NetBIOSName[w];
        if((v == ' ') || (v == 0u))
            break;
    }
    wSourceLen = w;
    if(namelen < (int)wSourceLen + 1)
    {
        errno = EINVAL;
        return SOCKET_ERROR;
    }

    memcpy((void*)name, (void*)pNetIf->NetBIOSName, wSourceLen);
    name[wSourceLen] = 0;

    return 0;
}
Exemplo n.º 2
0
/*********************************************************************
  Function:
 	 uint8_t SNMPValidateCommunity(uint8_t* community)
 
  Summary:			
 	 Validates community name for access control. 
 
  Description:		
     This function validates the community name for the mib access to NMS.
 	 The snmp community name received in the request pdu is validated for
 	 read and write community names. The agent gives an access to the mib
 	 variables only if the community matches with the predefined values.
  	 This routine also sets a gloabal flag to send trap if authentication
 	 failure occurs.
  
  PreCondition:
 	 SNMPInit is already called.
 
  parameters:
     community - Pointer to community string as sent by NMS.
 
  Returns:          
 	 This routine returns the community validation result as 
  	 READ_COMMUNITY or WRITE_COMMUNITY or INVALID_COMMUNITY	
 
  Remarks:
     This is a callback function called by module. User application must 
  	 implement this function and verify that community matches with 
 	 predefined value. This validation occurs for each NMS request.
 ********************************************************************/
uint8_t SNMPValidateCommunity(uint8_t * community)
{
	uint8_t i;
	uint8_t *ptr;
    NET_CONFIG* pConfig;
    
	/*
	If the community name is encrypted in the request from the Manager,
	agent required to decrypt it to match with the community it is
	configured for. The response from the agent should contain encrypted community 
	name using the same encryption algorithm which Manager used while
	making the request.
	*/ 		

	// Validate that community string is a legal size
	if(strlen((char*)community) <= SNMP_COMMUNITY_MAX_LEN)
	{
        pConfig = TCPIP_STACK_GetDefaultNet();
		// Search to see if this is a write community.  This is done before 
		// searching read communities so that full read/write access is 
		// granted if a read and write community name happen to be the same.
		for(i = 0; i < SNMP_MAX_COMMUNITY_SUPPORT; i++)
		{
			ptr = pConfig->writeCommunity[i];
			if(ptr == NULL)
				continue;
			if(*ptr == 0x00u)
				continue;
			if(strncmp((char*)community, (char*)ptr, SNMP_COMMUNITY_MAX_LEN) == 0)
				return WRITE_COMMUNITY;
		}
		
		// Did not find in write communities, search read communities
		for(i = 0; i < SNMP_MAX_COMMUNITY_SUPPORT; i++)
		{
			ptr = pConfig->readCommunity[i];
			if(ptr == NULL)
				continue;
			if(*ptr == 0x00u)
				continue;
			if(strncmp((char*)community, (char*)ptr, SNMP_COMMUNITY_MAX_LEN) == 0)
				return READ_COMMUNITY;
		}
	}
	
	// Could not find any matching community, set up to send a trap
	gSpecificTrapNotification=VENDOR_TRAP_DEFAULT;
	gGenericTrapNotification=AUTH_FAILURE;
	gSendTrapFlag=true;
	return INVALID_COMMUNITY;
	
}
Exemplo n.º 3
0
/*****************************************************************************
  Function:
	DNS_RESULT DNSBeginUsage(NET_CONFIG* pConfig)

  Summary:
	Claims access to the DNS module.
	
  Description:
	This function acts as a semaphore to obtain usage of the DNS module.
	Call this function and ensure that it returns DNS_RES_OK before calling any
	other DNS APIs.  Call DNSEndUsage when this application no longer 
	needs the DNS module so that other applications may make use of it.

  Precondition:
	Stack is initialized.

  Parameters:
	pConfig   - interface to use
                If 0, a default interface will be selected

  Return Values:
  	DNS_RES_OK      - the calling application has sucessfully taken ownership of the DNS module
  	DNS_RES_BUSY    - The DNS module is currently in use.
                      Yield to the stack and attempt this call again later.
  	
  Remarks:
	Ensure that DNSEndUsage is always called once your application has
	obtained control of the DNS module.  If this is not done, the stack
	will hang for all future applications requiring DNS access.
  ***************************************************************************/
DNS_RESULT DNSBeginUsage(TCPIP_NET_HANDLE netH)
{
    NET_CONFIG* pNewIf;
    
	if(Flags.bits.DNSInUse)
		return DNS_RES_BUSY;

    pNewIf = _TCPIPStackHandleToNet(netH);
    
    if(pNewIf == 0 || !_TCPIPStackIsNetUp(pNewIf))
    {   // try a default interface
        if(_TCPIPStackIsNetUp(pDNSNet))
        {
            pNewIf = pDNSNet;
        }
        else
        {
            pNewIf = (NET_CONFIG*)TCPIP_STACK_GetDefaultNet();
            if(!_TCPIPStackIsNetUp(pNewIf))
            {
                pNewIf = 0;
            }
        }
    }
    // else pNewIf should do just fine

    if(pNewIf == 0)
    {
        return DNS_RES_NO_INTERFACE;
    }
    
    pDNSNet = pNewIf;
    
	Flags.bits.DNSInUse = true;
    DNSServers[0] = pDNSNet->PrimaryDNSServer;
    DNSServers[1] = pDNSNet->SecondaryDNSServer;
    
    smDNS = DNS_IDLE;

	return DNS_RES_OK;
}
Exemplo n.º 4
0
bool Ping6 (char * target)
{
    if (pingState != STATE_IDLE)
        return false;

    pNetIf = (NET_CONFIG*)TCPIP_STACK_GetDefaultNet();

    pingCount = 0;

    if (TCPIP_HELPER_StringToIPv6Address ((uint8_t *)target, &targetAddressIPv6))
    {
        // The user passed in a valid IPv6 address
        pingState = STATE_SEND_ECHO_REQUEST_IPV6;
    }
    else
    {
        // The user passed in a host name
        targetHostName = target;
        pingState = STATE_DNS_SEND_QUERY_IPV6;
    }

    return true;
}
Exemplo n.º 5
0
/*****************************************************************************
  Function:
	bool Ping4(int8_t * target)

  Summary:
	Sends an ICMP Echo Request to the target.
	
  Description:
	This function begins the state machine for transmitting ICMP Echo 
    Requests and processing the responses from them.
	
	This function can be used as a model for applications requiring Ping6 
	capabilities to check if a host is reachable.

  Precondition:
	None.

  Parameters:
	target   - the target IP_ADDR or host name to ping

  Returns:
  	None
  ***************************************************************************/
bool Ping4 (char * target)
{
    if (pingState != STATE_IDLE)
        return false;

    pNetIf = (NET_CONFIG*)TCPIP_STACK_GetDefaultNet();

    pingCount = 0;

    if (TCPIP_HELPER_StringToIPAddress ((const char *)target, &targetAddressIPv4))
    {
        // The user passed in a valid IPv4 address
        pingState = STATE_RESOLVE_ARP;
    }
    else
    {
        // The user passed in a host name
        targetHostName = target;
        pingState = STATE_DNS_SEND_QUERY_IPV4;
    }

    return true;
}
Exemplo n.º 6
0
/**************************************************************************
  Function:
 	void SNMPSendTrap(void)
 
  Summary:	
  	 Prepare, validate remote node which will receive trap and send trap pdu.
 	 	  
  Description:		
     This function is used to send trap notification to previously 
     configured ip address if trap notification is enabled. There are
     different trap notification code. The current implementation
     sends trap for authentication failure (4).
  
  PreCondition:
 	 If application defined event occurs to send the trap.
 
  parameters:
     None.
 
  Returns:          
 	 None.
 
  Remarks:
     This is a callback function called by the application on certain 
     predefined events. This routine only implemented to send a 
     authentication failure Notification-type macro with PUSH_BUTTON
     oid stored in MPFS. If the ARP is no resolved i.e. if 
     SNMPIsNotifyReady() returns false, this routine times 
     out in 5 seconds. This routine should be modified according to 
     event occured and should update corrsponding OID and notification
     type to the trap pdu.
 *************************************************************************/
void SNMPSendTrap(void)
{
	static uint8_t timeLock=false;
	static uint8_t receiverIndex=0; ///is application specific
	IP_ADDR remHostIPAddress,* remHostIpAddrPtr;
	SNMP_VAL val;
	static SYS_TICK TimerRead;
    
	static enum 
	{
		SM_PREPARE,
		SM_NOTIFY_WAIT 
	} smState = SM_PREPARE;

    gpSnmpIf = TCPIP_STACK_GetDefaultNet();

	if(trapInfo.table[receiverIndex].Flags.bEnabled)
	{
		remHostIPAddress.v[0] = trapInfo.table[receiverIndex].IPAddress.v[3];
		remHostIPAddress.v[1] = trapInfo.table[receiverIndex].IPAddress.v[2];
		remHostIPAddress.v[2] = trapInfo.table[receiverIndex].IPAddress.v[1];
		remHostIPAddress.v[3] = trapInfo.table[receiverIndex].IPAddress.v[0];
		remHostIpAddrPtr = &remHostIPAddress;
		if(timeLock==(uint8_t)false)
		{
			TimerRead=SYS_TICK_Get();
			timeLock=true;
		}
	}	
	else
	{
		receiverIndex++;
		if((receiverIndex == (uint8_t)TRAP_TABLE_SIZE))
		{
			receiverIndex=0;
			timeLock=false;
			gSendTrapFlag=false;	
			UDPDiscard(s, gpSnmpIf);
		}
		return;
		
	}
		
	switch(smState)
	{
	
		case SM_PREPARE:

			SNMPNotifyPrepare(remHostIpAddrPtr,trapInfo.table[receiverIndex].community,
						trapInfo.table[receiverIndex].communityLen,
						MICROCHIP,			  // Agent ID Var
						gSpecificTrapNotification,					  // Notification code.
						SNMPGetTimeStamp());
			smState++;
			break;
			
		case SM_NOTIFY_WAIT:
			if(SNMPIsNotifyReady(remHostIpAddrPtr))
			{
				smState = SM_PREPARE;
		 		val.byte = 0;
				receiverIndex++;

				//application has to decide on which SNMP var OID to send. Ex. PUSH_BUTTON	
				SNMPNotify(gOIDCorrespondingSnmpMibID, val, 0);
            	smState = SM_PREPARE;
				UDPDiscard(s, gpSnmpIf);
				break;
			}
	}	
		
	//Try for max 5 seconds to send TRAP, do not get block in while()
	if((SYS_TICK_Get()-TimerRead)>(5*SYS_TICK_TicksPerSecondGet())|| (receiverIndex == (uint8_t)TRAP_TABLE_SIZE))
	{
		UDPDiscard(s, gpSnmpIf);
		smState = SM_PREPARE;
		receiverIndex=0;
		timeLock=false;
		gSendTrapFlag=false;
		return;
	}

}
Exemplo n.º 7
0
/**************************************************************************
  Function:
 	void SNMPV2TrapDemo(void)
 
  Summary:	
  	Send SNMP V2 notification with multiple varbinds.
 	  	  
  Description:		
	This routine sends a trap v2 pdu with multiple varbind variables
	for the predefined ip addresses with the agent. And as per RFC1905 
	the first two variable bindings in the varbind pdu list of an
   	SNMPv2-Trap-PDU are sysUpTime.0 and snmpTrapOID.0 respectively.
   	To support multiple varbind, user need to call SendNotification()
    for the first varbind variable and SendNotification() will do the 
    arp resolve and adds sysUpTime.0 and snmpTrapOID.0 variable to 
    the pdu. For the second varbind variable onwards user need to 
   	call only SNMPNotify().
	In this demo , snmpv2 trap includes ANALOG_POT0,PUSH_BUTTON and LED_D5
	variable bindains and this trap can be generated by using portmeter value.
	and SNMPv2-Trap-PDU will be generated only when pot meter reading exceeds 501.
	
	gSetTrapSendFlag Should be set to true when user is trying to send first 
	variable binding and gSetTrapSendFlag should be set to false before 
    sending the last variable binding.

	* if user is sending only one variable binding then 
	* gSetTrapSendFlag should be set to False.	
    * user can add more variable bindings.
  PreCondition:
 	Application defined event occurs to send the trap.
 	
  parameters:
     None.
 
  Returns:          
 	 None.
 
  Remarks:
    This routine guides how to build a event generated trap notification.
 *************************************************************************/
void SNMPV2TrapDemo(void)
{
	static SYS_TICK tempTimerRead = 0;
	static uint8_t	trapIndex=0;
	static SNMP_VAL		analogPotVal;
	static uint8_t potReadLock = false;
	static uint8_t timeLock = false;
	static uint8_t maxTryToSendTrap=0;
	
	if(timeLock==(uint8_t)false)
	{
		tempTimerRead=SYS_TICK_Get();
		timeLock=true;
	}

    gpSnmpIf = TCPIP_STACK_GetDefaultNet();

	for(;trapIndex<TRAP_TABLE_SIZE;trapIndex++)
	{	
		if(!trapInfo.table[trapIndex].Flags.bEnabled)
			continue;
		
		//Read POT reading once and send trap to all configured recipient
		if(potReadLock ==(uint8_t)false)
		{
			analogPotVal.word= (uint16_t)ADC1BUF0;
			potReadLock    = true;
		}
	
		if(analogPotVal.word >512u)
		{
			/*
			 * prepare  and send multivarbind pdu using pot meter value. 
			 * for SNMP v2 trap sysUpTime.0 and SNMPv2TrapOID.0 are mandatory
			 * apart from these varbinds, push button and potmeter OID are included
			 * to this pdu.
			*/
			gSpecificTrapNotification = 1; //expecting 1 should be the specific trap.
			gGenericTrapNotification = ENTERPRISE_SPECIFIC;
			gSetTrapSendFlag = true;
			// insert ANALOG_POT0 OID value and OID to the varbind pdu
			//set global flag gSetTrapSendFlag to true , it signifies that there are more than one 
			// variable need to be the part of SNMP v2 TRAP. 
			// if there is  only varbind variable to be the part of SNMP v2 trap, 
			// then user should set gSetTrapSendFlag to false.
			//gSetTrapSendFlag = false;

			if(SendNotification(trapIndex,ANALOG_POT0,analogPotVal) == false)
			{
				if(maxTryToSendTrap >= MAX_TRY_TO_SEND_TRAP)
				{
					trapIndex++;
					maxTryToSendTrap = 0;
					return;
				}
				maxTryToSendTrap++;
				return ;
			}
			//prepare PUSH_BUTTON trap .for the next trap varbind we need to use snmp_notify instead of 
			// SendNotification(), because we have already prepared SNMP v2 trap header 
			//and arp has been resolved already.
			
			analogPotVal.byte = BUTTON0_IO;
			SNMPNotify(PUSH_BUTTON,analogPotVal,0);
		
			// if this is the last trap variable need to be the part of SNMP v2 Trap,
			// then we should disable gSetTrapSendFlag to false
			gSetTrapSendFlag = false;
			analogPotVal.byte = LED0_IO;
			SNMPNotify(LED_D5,analogPotVal,0);			
		}
	}

	//Try for max 5 seconds to send TRAP, do not get block in while()
	if((SYS_TICK_Get()-tempTimerRead)>(5*SYS_TICK_TicksPerSecondGet()))
	{
//		UDPDiscard(s, gpSnmpIf);
		potReadLock = false;
		timeLock = false;
		trapIndex = 0;
		analogPotVal.word = 0;
		return;
	}
}
Exemplo n.º 8
0
/*****************************************************************************
  Function:
    void GenericTCPClient(void)

  Summary:
    Implements a simple HTTP client (over TCP).

  Description:
    This function implements a simple HTTP client, which operates over TCP.
    The function is called periodically by the stack, and waits for BUTTON1
    to be pressed.  When the button is pressed, the application opens a TCP
    connection to an Internet search engine, performs a search for the word
    "Microchip" on "microchip.com", and prints the resulting HTML page to
    the UART.

    This example can be used as a model for many TCP and HTTP client
    applications.

  Precondition:
    TCP is initialized.

  Parameters:
    None

  Returns:
      None
  ***************************************************************************/
void GenericTCPClient(void)
{
    uint8_t                 i;
    uint16_t                w;
    DNS_RESULT          dnsRes;
    uint8_t                vBuffer[9];
    static TCPIP_NET_HANDLE    netH;
    static uint32_t        clientTimer;
    static TCP_SOCKET    MySocket = INVALID_SOCKET;
    static uint32_t nAttempts =0;

    static enum _GenericTCPExampleState
    {
        SM_HOME = 0,
        SM_WAIT_DNS,
        SM_DNS_RESOLVED,
        SM_SOCKET_OBTAINED,
        SM_PROCESS_RESPONSE,
        SM_DISCONNECT,
        SM_DONE
    } GenericTCPExampleState = SM_DONE;

    //DBPRINTF("    Starting TCP client\n");

    switch(GenericTCPExampleState)
    {

        case SM_HOME:

            DBPRINTF("  SM_HOME\n");
            netH = TCPIP_STACK_GetDefaultNet();
            if(DNSBeginUsage(netH) != DNS_RES_OK)
            {
                break;
            }
            DNSResolve(ServerName, DNS_TYPE_A); 
            GenericTCPExampleState++;
            break;

        case SM_WAIT_DNS:

            DBPRINTF("  SM_WAIT_DNS\n");
            dnsRes = DNSIsResolved(ServerName, &serverIP);
            if(dnsRes == DNS_RES_PENDING)
            {   // ongoing operation;
                break;
            }
            else if(dnsRes < 0)
            {   // some DNS error occurred; retry
                DBPRINTF((const char*)"\r\n\r\nGeneric TCP client: DNS name resolving failed...\r\n");
                TCPClose(MySocket);
                MySocket = INVALID_SOCKET;
                GenericTCPExampleState = SM_HOME;
                nAttempts++;
                if(nAttempts>8) // After 8 attempts give-up
                {
                    GenericTCPExampleState = SM_DONE;
                    nAttempts=0;
                }
            }
            else
            {
                clientTimer = SYS_TICK_Get();
                GenericTCPExampleState++;
            }
            DNSEndUsage(netH);
            break;

        case SM_DNS_RESOLVED:
            DBPRINTF("  SM_DNS_RESOLVED\n");
            // Connect the socket to the remote TCP server
            MySocket = TCPOpenClient(IP_ADDRESS_TYPE_IPV4, ServerPort, (IP_MULTI_ADDRESS*)&serverIP);

			// Abort operation if no TCP socket could be opened.
			// If this ever happens, you need to update your tcp_config.h
            if(MySocket == INVALID_SOCKET)
            {   // retry
                break;
            }

            GenericTCPExampleState++;
            clientTimer = SYS_TICK_Get();
            break;

        case SM_SOCKET_OBTAINED:

            DBPRINTF("  SM_SOCKET_OBTAINED\n");
            // Wait for the remote server to accept our connection request
            if(!TCPIsConnected(MySocket))
            {
                // Time out if more than 5 seconds is spent in this state
                if((SYS_TICK_Get()-clientTimer) > 5 * SYS_TICK_TicksPerSecondGet() )
                {
                    // Close the socket so it can be used by other modules
                    TCPClose(MySocket);
                    MySocket = INVALID_SOCKET;
                    GenericTCPExampleState--;
                    DBPRINTF((const char*)"\r\n\r\nGeneric TCP client: Failed connecting to the remote server...\r\n");
                }
                break;
            }

            clientTimer = SYS_TICK_Get();

            // Make certain the socket can be written to
            if(TCPIsPutReady(MySocket) < 125u)
                break;

            // Place the application protocol data into the transmit buffer.  For this example, we are connected to an HTTP server, so we'll send an HTTP GET request.
            TCPPutString(MySocket, (const uint8_t*)"GET ");
            TCPPutString(MySocket, RemoteURL);
            TCPPutString(MySocket, (const uint8_t*)" HTTP/1.0\r\nHost: ");
            TCPPutString(MySocket, (const uint8_t*)ServerName);
            TCPPutString(MySocket, (const uint8_t*)"\r\nConnection: close\r\n\r\n");

            // Send the packet
            TCPFlush(MySocket);
            GenericTCPExampleState++;
            break;

        case SM_PROCESS_RESPONSE:
            //DBPRINTF("  SM_PROCESS_RESPONSE\n");
            // Check to see if the remote node has disconnected from us or sent us any application data
            // If application data is available, write it to the UART
            if(!TCPIsConnected(MySocket))
            {
                GenericTCPExampleState = SM_DISCONNECT;
                // Do not break;  We might still have data in the TCP RX FIFO waiting for us
            }

            // Get count of RX bytes waiting
            w = TCPIsGetReady(MySocket);

            // Obtian and print the server reply
            i = sizeof(vBuffer)-1;
            vBuffer[i] = '\0';
            while(w)
            {
                if(w < i)
                {
                    i = w;
                    vBuffer[i] = '\0';
                }
                w -= TCPGetArray(MySocket, vBuffer, i);
#if defined(GENERIC_TCP_CLIENT_ENABLE_UART_DUMP)
                DBPRINTF((char*)vBuffer);
#endif
                // SYS_CONSOLE_MESSAGE is a blocking call which will slow down the rest of the stack
                // if we shovel the whole TCP RX FIFO into the serial port all at once.
                // Therefore, let's break out after only one chunk most of the time.  The
                // only exception is when the remote node disconncets from us and we need to
                // use up all the data before changing states.
                if(GenericTCPExampleState == SM_PROCESS_RESPONSE)
                    break;
            }

            break;

        case SM_DISCONNECT:
            DBPRINTF("  SM_DISCONNECT\n");
            // Close the socket so it can be used by other modules
            // For this application, we wish to stay connected, but this state will still get entered if the remote server decides to disconnect
            TCPClose(MySocket);
            MySocket = INVALID_SOCKET;
            GenericTCPExampleState = SM_DONE;
            break;

        case SM_DONE:
            //DBPRINTF("  SM_DONE\n");
            // Do nothing unless the user pushes BUTTON1 and wants to restart the whole connection/download process
            // On many boards, SYS_USERIO_BUTTON_0 is assigned to sw1
            // SYS_USERIO_BUTTON_1=sw2 and SYS_USERIO_BUTTON_2=sw3
            if(SYS_USERIO_ButtonGet((SYS_USERIO_BUTTON_1),SYS_USERIO_BUTTON_ASSERTED))
                GenericTCPExampleState = SM_HOME;
            break;
    }
}
Exemplo n.º 9
0
/*****************************************************************************
  Function:
    void GenericSSLClient(void)

  Summary:
    Implements a simple HTTP client (over TCP).

  Description:
    This function implements a simple HTTP client, which operates over TCP.  
    The function is called periodically by the stack, and waits for BUTTON1 
    to be pressed.  When the button is pressed, the application opens a TCP
    connection to an Internet search engine, performs a search for the word
    "Microchip" on "microchip.com", and prints the resulting HTML page to
    the UART.  
    
    To add this to an existing application, make the call to GenericSSLClient 
    from StackTasks.
    
    This example can be used as a model for many TCP and HTTP client
    applications.

  Precondition:
    TCP is initialized.

  Parameters:
    None

  Returns:
    None
  ***************************************************************************/
void GenericSSLClient(void)
{
    uint8_t             i;
    uint16_t            w;
    DNS_RESULT          dnsRes;
    uint8_t             vBuffer[9];
    static TCPIP_NET_HANDLE    netH;
    static uint32_t     clientTimer;
    static TCP_SOCKET   MySocket = INVALID_SOCKET;
    static enum _GenericTCPExampleState
    {
        SM_HOME = 0,
        SM_WAIT_DNS,
        SM_DNS_RESOLVED,
        SM_SOCKET_OBTAINED,
        SM_START_SSL,
        SM_PROCESS_RESPONSE,
        SM_DISCONNECT,
        SM_DONE
    } GenericTCPExampleState = SM_DONE;

    switch(GenericTCPExampleState)
    {

        case SM_HOME:
            
            netH = TCPIP_STACK_GetDefaultNet();
            dnsRes = DNSBeginUsage(netH);
            if(dnsRes != DNS_RES_OK)
                break;
            DNSResolve(SSLServerName, DNS_TYPE_A);
            GenericTCPExampleState++;
            break;

        case SM_WAIT_DNS:
            
            dnsRes = DNSIsResolved(SSLServerName, &serverIP_SSL);
            if(dnsRes == DNS_RES_PENDING)
            {   // ongoing operation;
                break;
            }
            else if(dnsRes < 0)
            {   // some DNS error occurred; retry
                SYS_CONSOLE_MESSAGE((const char*)"\r\n\r\nDNS name resolving failed...\r\n");
                TCPClose(MySocket);
                MySocket = INVALID_SOCKET;
                GenericTCPExampleState = SM_HOME;
            }
            else
            {
                clientTimer = SYS_TICK_Get();
                GenericTCPExampleState++;
            }
            DNSEndUsage(netH);
            break;

        case SM_DNS_RESOLVED:
            // Connect the socket to the remote TCP server
            MySocket = TCPOpenClient(IP_ADDRESS_TYPE_IPV4, SSLServerPort, (IP_MULTI_ADDRESS*)&serverIP_SSL);
            
			// Abort operation if no TCP socket could be opened.
			// If this ever happens, you need to update your tcp_config.h
            if(MySocket == INVALID_SOCKET)
            {   // retry
                break;
            }

            SYS_CONSOLE_MESSAGE((const char*)"\r\n\r\nConnecting using Microchip TCP API...\r\n");

            GenericTCPExampleState++;
            clientTimer = SYS_TICK_Get();
            break;

        case SM_SOCKET_OBTAINED:

            // Wait for the remote server to accept our connection request
            if(!TCPIsConnected(MySocket))
            {
                // Time out if more than 5 seconds is spent in this state
                if((SYS_TICK_Get()-clientTimer) > 5 * SYS_TICK_TicksPerSecondGet() )
                {
                    // Close the socket so it can be used by other modules
                    TCPClose(MySocket);
                    MySocket = INVALID_SOCKET;
                    GenericTCPExampleState--;
                    SYS_CONSOLE_MESSAGE((const char*)"\r\n\r\nFailed connecting to the remote server...\r\n");
                }
                break;
            }

            clientTimer = SYS_TICK_Get();

            if(!TCPStartSSLClient(MySocket,(uint8_t *)"thishost"))
                break;

            GenericTCPExampleState++;
            break;

        case SM_START_SSL:
            if (TCPSSLIsHandshaking(MySocket)) 
            {
                // Handshaking may fail if the SSL_RSA_CLIENT_SIZE is not large enough
                // for the server’s certificate
                if(SYS_TICK_Get()-clientTimer > 10*SYS_TICK_TicksPerSecondGet())
                {
                    // Close the socket so it can be used by other modules
                    TCPClose(MySocket);
                    MySocket = INVALID_SOCKET;
                    GenericTCPExampleState=SM_HOME;
                }
                break;
            }


            // Make certain the socket can be written to
            if(TCPIsPutReady(MySocket) < 125u)
                break;
            
            // Place the application protocol data into the transmit buffer.  For this example, we are connected to an HTTP server, so we'll send an HTTP GET request.
            TCPPutString(MySocket, (const uint8_t*)"GET ");
            TCPPutString(MySocket, SSLRemoteURL);
            TCPPutString(MySocket, (const uint8_t*)" HTTP/1.0\r\nHost: ");
            TCPPutString(MySocket, (const uint8_t*)SSLServerName);
            TCPPutString(MySocket, (const uint8_t*)"\r\nConnection: close\r\n\r\n");

            // Send the packet
            TCPFlush(MySocket);
            GenericTCPExampleState++;
            break;

        case SM_PROCESS_RESPONSE:
            // Check to see if the remote node has disconnected from us or sent us any application data
            // If application data is available, write it to the UART
            if(!TCPIsConnected(MySocket))
            {
                GenericTCPExampleState = SM_DISCONNECT;
                // Do not break;  We might still have data in the TCP RX FIFO waiting for us
            }
    
            // Get count of RX bytes waiting
            w = TCPIsGetReady(MySocket);    
    
            // Obtian and print the server reply
            i = sizeof(vBuffer)-1;
            vBuffer[i] = '\0';
            while(w)
            {
                if(w < i)
                {
                    i = w;
                    vBuffer[i] = '\0';
                }
                w -= TCPGetArray(MySocket, vBuffer, i);
                SYS_CONSOLE_MESSAGE((char*)vBuffer);
                
                // SYS_CONSOLE_MESSAGE is a blocking call which will slow down the rest of the stack 
                // if we shovel the whole TCP RX FIFO into the serial port all at once.  
                // Therefore, let's break out after only one chunk most of the time.  The 
                // only exception is when the remote node disconncets from us and we need to 
                // use up all the data before changing states.
                if(GenericTCPExampleState == SM_PROCESS_RESPONSE)
                    break;
            }
    
            break;
    
        case SM_DISCONNECT:
            // Close the socket so it can be used by other modules
            // For this application, we wish to stay connected, but this state will still get entered if the remote server decides to disconnect
            TCPClose(MySocket);
            MySocket = INVALID_SOCKET;
            GenericTCPExampleState = SM_DONE;
            break;
    
        case SM_DONE:
            // Do nothing unless the user pushes BUTTON1 and wants to restart the whole connection/download process
            if(BUTTON1_IO == 0u)
                GenericTCPExampleState = SM_HOME;
            break;
    }
}