Commit 16ea5aa7 authored by Dean Camera's avatar Dean Camera
Browse files

Add a TELNET server to the webserver project, which currently can list active TCP connections.

parent 77e86e7d
This diff is collapsed.
......@@ -17,6 +17,7 @@
* -# Add ability to get number of bytes not written with pipe/endpoint write routines after an error
* -# Add standardized descriptor names to class driver structures
* -# Correct mishandling of error cases in Mass Storage demos
* -# Add BOARD=NONE Option
* - Documentation/Support
* -# Remake AVRStudio project files
* -# Add detailed overviews of how each demo works
......
......@@ -34,27 +34,27 @@
* DHCP server on the network.
*/
#include "DHCPApp.h"
#include "DHCPClientApp.h"
#if defined(ENABLE_DHCP) || defined(__DOXYGEN__)
/** Timer for managing the timeout period for a DHCP server to respond */
struct timer DHCPTimer;
/** Initialization function for the DHCP client. */
void DHCPApp_Init(void)
void DHCPClientApp_Init(void)
{
uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate;
/* Create a new UDP connection to the DHCP server port for the DHCP solicitation */
uip_ipaddr_t DHCPServerIPAddress;
uip_ipaddr(&DHCPServerIPAddress, 255, 255, 255, 255);
AppState->Connection = uip_udp_new(&DHCPServerIPAddress, HTONS(DHCPC_SERVER_PORT));
AppState->DHCPClient.Connection = uip_udp_new(&DHCPServerIPAddress, HTONS(DHCPC_SERVER_PORT));
/* If the connection was sucessfully created, bind it to the local DHCP client port */
if(AppState->Connection != NULL)
if(AppState->DHCPClient.Connection != NULL)
{
uip_udp_bind(AppState->Connection, HTONS(DHCPC_CLIENT_PORT));
AppState->CurrentState = DHCP_STATE_SendDiscover;
uip_udp_bind(AppState->DHCPClient.Connection, HTONS(DHCPC_CLIENT_PORT));
AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;
}
/* Set timeout period to half a second for a DHCP server to respond */
......@@ -64,33 +64,33 @@ void DHCPApp_Init(void)
/** uIP stack application callback for the DHCP client. This function must be called each time the TCP/IP stack
* needs a UDP packet to be processed.
*/
void DHCPApp_Callback(void)
void DHCPClientApp_Callback(void)
{
uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate;
DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata;
uint16_t AppDataSize = 0;
switch (AppState->CurrentState)
switch (AppState->DHCPClient.CurrentState)
{
case DHCP_STATE_SendDiscover:
/* Clear all DHCP settings, reset client IP address */
memset(&AppState->DHCPOffer_Data, 0x00, sizeof(AppState->DHCPOffer_Data));
uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPOffer_Data.AllocatedIP);
memset(&AppState->DHCPClient.DHCPOffer_Data, 0x00, sizeof(AppState->DHCPClient.DHCPOffer_Data));
uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP);
/* Fill out the DHCP response header */
AppDataSize += DHCPApp_FillDHCPHeader(AppData, DHCP_DISCOVER, AppState);
AppDataSize += DHCPClientApp_FillDHCPHeader(AppData, DHCP_DISCOVER, AppState);
/* Add the required DHCP options list to the packet */
uint8_t RequiredOptionList[] = {DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, DHCP_OPTION_DNS_SERVER};
AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_REQ_LIST, sizeof(RequiredOptionList),
RequiredOptionList);
AppDataSize += DHCPClientApp_SetOption(AppData->Options, DHCP_OPTION_REQ_LIST, sizeof(RequiredOptionList),
RequiredOptionList);
/* Send the DHCP DISCOVER packet */
uip_udp_send(AppDataSize);
/* Reset the timeout timer, progress to next state */
timer_reset(&DHCPTimer);
AppState->CurrentState = DHCP_STATE_WaitForOffer;
AppState->DHCPClient.CurrentState = DHCP_STATE_WaitForOffer;
break;
case DHCP_STATE_WaitForOffer:
......@@ -98,45 +98,45 @@ void DHCPApp_Callback(void)
{
/* Check if the DHCP timeout period has expired while waiting for a response */
if (timer_expired(&DHCPTimer))
AppState->CurrentState = DHCP_STATE_SendDiscover;
AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;
break;
}
uint8_t OfferResponse_MessageType;
if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &OfferResponse_MessageType) &&
DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &OfferResponse_MessageType) &&
(OfferResponse_MessageType == DHCP_OFFER))
{
/* Received a DHCP offer for an IP address, copy over values for later request */
memcpy(&AppState->DHCPOffer_Data.AllocatedIP, &AppData->YourIP, sizeof(uip_ipaddr_t));
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK, &AppState->DHCPOffer_Data.Netmask);
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_ROUTER, &AppState->DHCPOffer_Data.GatewayIP);
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_SERVER_ID, &AppState->DHCPOffer_Data.ServerIP);
memcpy(&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP, &AppData->YourIP, sizeof(uip_ipaddr_t));
DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK, &AppState->DHCPClient.DHCPOffer_Data.Netmask);
DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_ROUTER, &AppState->DHCPClient.DHCPOffer_Data.GatewayIP);
DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_SERVER_ID, &AppState->DHCPClient.DHCPOffer_Data.ServerIP);
timer_reset(&DHCPTimer);
AppState->CurrentState = DHCP_STATE_SendRequest;
AppState->DHCPClient.CurrentState = DHCP_STATE_SendRequest;
}
break;
case DHCP_STATE_SendRequest:
/* Fill out the DHCP response header */
AppDataSize += DHCPApp_FillDHCPHeader(AppData, DHCP_REQUEST, AppState);
AppDataSize += DHCPClientApp_FillDHCPHeader(AppData, DHCP_REQUEST, AppState);
/* Add the DHCP REQUESTED IP ADDRESS option to the packet */
AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, sizeof(uip_ipaddr_t),
&AppState->DHCPOffer_Data.AllocatedIP);
AppDataSize += DHCPClientApp_SetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, sizeof(uip_ipaddr_t),
&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP);
/* Add the DHCP SERVER IP ADDRESS option to the packet */
AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_SERVER_ID, sizeof(uip_ipaddr_t),
&AppState->DHCPOffer_Data.ServerIP);
AppDataSize += DHCPClientApp_SetOption(AppData->Options, DHCP_OPTION_SERVER_ID, sizeof(uip_ipaddr_t),
&AppState->DHCPClient.DHCPOffer_Data.ServerIP);
/* Send the DHCP REQUEST packet */
uip_udp_send(AppDataSize);
/* Reset the timeout timer, progress to next state */
timer_reset(&DHCPTimer);
AppState->CurrentState = DHCP_STATE_WaitForACK;
AppState->DHCPClient.CurrentState = DHCP_STATE_WaitForACK;
break;
case DHCP_STATE_WaitForACK:
......@@ -144,22 +144,22 @@ void DHCPApp_Callback(void)
{
/* Check if the DHCP timeout period has expired while waiting for a response */
if (timer_expired(&DHCPTimer))
AppState->CurrentState = DHCP_STATE_SendDiscover;
AppState->DHCPClient.CurrentState = DHCP_STATE_SendDiscover;
break;
}
uint8_t RequestResponse_MessageType;
if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &RequestResponse_MessageType) &&
DHCPClientApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &RequestResponse_MessageType) &&
(RequestResponse_MessageType == DHCP_ACK))
{
/* Set the new network parameters from the DHCP server */
uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPOffer_Data.AllocatedIP);
uip_setnetmask((uip_ipaddr_t*)&AppState->DHCPOffer_Data.Netmask);
uip_setdraddr((uip_ipaddr_t*)&AppState->DHCPOffer_Data.GatewayIP);
uip_sethostaddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.AllocatedIP);
uip_setnetmask((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.Netmask);
uip_setdraddr((uip_ipaddr_t*)&AppState->DHCPClient.DHCPOffer_Data.GatewayIP);
AppState->CurrentState = DHCP_STATE_AddressLeased;
AppState->DHCPClient.CurrentState = DHCP_STATE_AddressLeased;
}
break;
......@@ -175,7 +175,7 @@ void DHCPApp_Callback(void)
*
* \return Size in bytes of the created DHCP packet
*/
uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState)
uint16_t DHCPClientApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState)
{
/* Erase existing packet data so that we start will all 0x00 DHCP header data */
memset(DHCPHeader, 0, sizeof(DHCP_Header_t));
......@@ -189,8 +189,8 @@ uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageTy
DHCPHeader->ElapsedSeconds = 0;
DHCPHeader->Flags = HTONS(BOOTP_BROADCAST);
memcpy(&DHCPHeader->ClientIP, &uip_hostaddr, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->YourIP, &AppState->DHCPOffer_Data.AllocatedIP, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->NextServerIP, &AppState->DHCPOffer_Data.ServerIP, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->YourIP, &AppState->DHCPClient.DHCPOffer_Data.AllocatedIP, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->NextServerIP, &AppState->DHCPClient.DHCPOffer_Data.ServerIP, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->ClientHardwareAddress, &MACAddress, sizeof(struct uip_eth_addr));
DHCPHeader->Cookie = DHCP_MAGIC_COOKIE;
......@@ -214,7 +214,7 @@ uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageTy
*
* \return Number of bytes added to the DHCP packet
*/
uint8_t DHCPApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData)
uint8_t DHCPClientApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData)
{
/* Skip through the DHCP options list until the terminator option is found */
while (*DHCPOptionList != DHCP_OPTION_END)
......@@ -238,7 +238,7 @@ uint8_t DHCPApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataL
*
* \return Boolean true if the option was found in the DHCP packet's options list, false otherwise
*/
bool DHCPApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination)
bool DHCPClientApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination)
{
/* Look through the incomming DHCP packet's options list for the requested option */
while (*DHCPOptionList != DHCP_OPTION_END)
......
......@@ -30,11 +30,11 @@
/** \file
*
* Header file for DHCPApp.c.
* Header file for DHCPClientApp.c.
*/
#ifndef _DHCP_APP_H_
#define _DHCP_APP_H_
#ifndef _DHCPCLIENT_APP_H_
#define _DHCPCLIENT_APP_H_
/* Includes: */
#include <stdio.h>
......@@ -156,11 +156,11 @@
};
/* Function Prototypes: */
void DHCPApp_Init(void);
void DHCPApp_Callback(void);
void DHCPClientApp_Init(void);
void DHCPClientApp_Callback(void);
uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState);
uint8_t DHCPApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData);
bool DHCPApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination);
uint16_t DHCPClientApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState);
uint8_t DHCPClientApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* OptionData);
bool DHCPClientApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination);
#endif
......@@ -98,36 +98,36 @@ void HTTPServerApp_Callback(void)
if (uip_aborted() || uip_timedout() || uip_closed())
{
/* Connection is being terminated for some reason - close file handle */
f_close(&AppState->FileHandle);
AppState->FileOpen = false;
f_close(&AppState->HTTPServer.FileHandle);
AppState->HTTPServer.FileOpen = false;
/* Lock to the closed state so that no further processing will occur on the connection */
AppState->CurrentState = WEBSERVER_STATE_Closed;
AppState->NextState = WEBSERVER_STATE_Closed;
AppState->HTTPServer.CurrentState = WEBSERVER_STATE_Closed;
AppState->HTTPServer.NextState = WEBSERVER_STATE_Closed;
}
if (uip_connected())
{
/* New connection - initialize connection state values */
AppState->CurrentState = WEBSERVER_STATE_OpenRequestedFile;
AppState->NextState = WEBSERVER_STATE_OpenRequestedFile;
AppState->FileOpen = false;
AppState->ACKedFilePos = 0;
AppState->SentChunkSize = 0;
AppState->HTTPServer.CurrentState = WEBSERVER_STATE_OpenRequestedFile;
AppState->HTTPServer.NextState = WEBSERVER_STATE_OpenRequestedFile;
AppState->HTTPServer.FileOpen = false;
AppState->HTTPServer.ACKedFilePos = 0;
AppState->HTTPServer.SentChunkSize = 0;
}
if (uip_acked())
{
/* Add the amount of ACKed file data to the total sent file bytes counter */
AppState->ACKedFilePos += AppState->SentChunkSize;
AppState->HTTPServer.ACKedFilePos += AppState->HTTPServer.SentChunkSize;
/* Progress to the next state once the current state's data has been ACKed */
AppState->CurrentState = AppState->NextState;
AppState->HTTPServer.CurrentState = AppState->HTTPServer.NextState;
}
if (uip_rexmit() || uip_acked() || uip_newdata() || uip_connected() || uip_poll())
{
switch (AppState->CurrentState)
switch (AppState->HTTPServer.CurrentState)
{
case WEBSERVER_STATE_OpenRequestedFile:
HTTPServerApp_OpenRequestedFile();
......@@ -144,7 +144,7 @@ void HTTPServerApp_Callback(void)
case WEBSERVER_STATE_Closing:
uip_close();
AppState->NextState = WEBSERVER_STATE_Closed;
AppState->HTTPServer.NextState = WEBSERVER_STATE_Closed;
break;
}
}
......@@ -175,19 +175,19 @@ static void HTTPServerApp_OpenRequestedFile(void)
/* If the requested filename has more that just the leading '/' path in it, copy it over */
if (strlen(RequestedFileName) > 1)
strncpy(AppState->FileName, &RequestedFileName[1], (sizeof(AppState->FileName) - 1));
strncpy(AppState->HTTPServer.FileName, &RequestedFileName[1], (sizeof(AppState->HTTPServer.FileName) - 1));
else
strcpy(AppState->FileName, "index.htm");
strcpy(AppState->HTTPServer.FileName, "index.htm");
/* Ensure filename is null-terminated */
AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00;
AppState->HTTPServer.FileName[(sizeof(AppState->HTTPServer.FileName) - 1)] = 0x00;
/* Try to open the file from the Dataflash disk */
AppState->FileOpen = (f_open(&AppState->FileHandle, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);
AppState->HTTPServer.FileOpen = (f_open(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);
/* Lock to the SendResponseHeader state until connection terminated */
AppState->CurrentState = WEBSERVER_STATE_SendResponseHeader;
AppState->NextState = WEBSERVER_STATE_SendResponseHeader;
AppState->HTTPServer.CurrentState = WEBSERVER_STATE_SendResponseHeader;
AppState->HTTPServer.NextState = WEBSERVER_STATE_SendResponseHeader;
}
/** HTTP Server State handler for the HTTP Response Header Send state. This state manages the transmission of
......@@ -202,15 +202,15 @@ static void HTTPServerApp_SendResponseHeader(void)
uint16_t HeaderLength;
/* Determine which HTTP header should be sent to the client */
if (AppState->FileOpen)
if (AppState->HTTPServer.FileOpen)
{
HeaderToSend = HTTP200Header;
AppState->NextState = WEBSERVER_STATE_SendMIMETypeHeader;
AppState->HTTPServer.NextState = WEBSERVER_STATE_SendMIMETypeHeader;
}
else
{
HeaderToSend = HTTP404Header;
AppState->NextState = WEBSERVER_STATE_Closing;
AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing;
}
/* Copy over the HTTP response header and send it to the receiving client */
......@@ -227,7 +227,7 @@ static void HTTPServerApp_SendMIMETypeHeader(void)
uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
char* const AppData = (char*)uip_appdata;
char* Extension = strpbrk(AppState->FileName, ".");
char* Extension = strpbrk(AppState->HTTPServer.FileName, ".");
uint16_t MIMEHeaderLength = 0;
/* Check to see if a file extension was found for the requested filename */
......@@ -261,7 +261,7 @@ static void HTTPServerApp_SendMIMETypeHeader(void)
uip_send(AppData, MIMEHeaderLength);
/* When the MIME header is ACKed, progress to the data send stage */
AppState->NextState = WEBSERVER_STATE_SendData;
AppState->HTTPServer.NextState = WEBSERVER_STATE_SendData;
}
/** HTTP Server State handler for the Data Send state. This state manages the transmission of file chunks
......@@ -276,14 +276,14 @@ static void HTTPServerApp_SendData(void)
uint16_t MaxSegmentSize = uip_mss();
/* Return file pointer to the last ACKed position */
f_lseek(&AppState->FileHandle, AppState->ACKedFilePos);
f_lseek(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.ACKedFilePos);
/* Read the next chunk of data from the open file */
f_read(&AppState->FileHandle, AppData, MaxSegmentSize, &AppState->SentChunkSize);
f_read(&AppState->HTTPServer.FileHandle, AppData, MaxSegmentSize, &AppState->HTTPServer.SentChunkSize);
/* Send the next file chunk to the receiving client */
uip_send(AppData, AppState->SentChunkSize);
uip_send(AppData, AppState->HTTPServer.SentChunkSize);
/* Check if we are at the last chunk of the file, if so next ACK should close the connection */
AppState->NextState = (MaxSegmentSize != AppState->SentChunkSize) ? WEBSERVER_STATE_Closing : WEBSERVER_STATE_SendData;
AppState->HTTPServer.NextState = (MaxSegmentSize != AppState->HTTPServer.SentChunkSize) ? WEBSERVER_STATE_Closing : WEBSERVER_STATE_SendData;
}
......@@ -47,7 +47,7 @@
/** States for each HTTP connection to the webserver. */
enum Webserver_States_t
{
WEBSERVER_STATE_OpenRequestedFile, /** Currently opening requested file */
WEBSERVER_STATE_OpenRequestedFile, /**< Currently opening requested file */
WEBSERVER_STATE_SendResponseHeader, /**< Currently sending HTTP response headers to the client */
WEBSERVER_STATE_SendMIMETypeHeader, /**< Currently sending HTTP MIME type header to the client */
WEBSERVER_STATE_SendData, /**< Currently sending HTTP page data to the client */
......
/*
LUFA Library
Copyright (C) Dean Camera, 2010.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* TELNET Webserver Application. When connected to the uIP stack,
* this will serve out connection information to the client.
*/
#define INCLUDE_FROM_TELNETSERVERAPP_C
#include "TELNETServerApp.h"
/** Welcome message to send to a TELNET client when a connection is first made. */
char PROGMEM WelcomeHeader[] = "********************************************\r\n"
"* LUFA uIP Webserver (TELNET) *\r\n"
"********************************************\r\n";
/** Main TELNET menu, giving the user the list of available commands they may issue */
char PROGMEM TELNETMenu[] = "\r\n"
" Available Commands:\r\n"
" c) List Active TCP Connections\r\n"
"\r\nCommand>";
/** Initialization function for the simple HTTP webserver. */
void TELNETServerApp_Init(void)
{
/* Listen on port 23 for TELNET connections from hosts */
uip_listen(HTONS(TELNET_SERVER_PORT));
}
/** uIP stack application callback for the TELNET server. This function must be called each time the
* TCP/IP stack needs a TCP packet to be processed.
*/
void TELNETServerApp_Callback(void)
{
uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
char* const AppData = (char*)uip_appdata;
if (uip_connected())
{
AppState->TELNETServer.CurrentState = TELNET_STATE_SendHeader;
}
if (uip_acked())
{
AppState->TELNETServer.CurrentState = AppState->TELNETServer.NextState;
}
if (uip_rexmit() || uip_acked() || uip_newdata() || uip_connected() || uip_poll())
{
switch (AppState->TELNETServer.CurrentState)
{
case TELNET_STATE_SendHeader:
/* Copy over and send the TELNET welcome message upon first connection */
strncpy_P(AppData, WelcomeHeader, strlen_P(WelcomeHeader));
uip_send(AppData, strlen_P(WelcomeHeader));
AppState->TELNETServer.NextState = TELNET_STATE_SendMenu;
break;
case TELNET_STATE_SendMenu:
/* Copy over and send the TELNET menu to the client */
strncpy_P(AppData, TELNETMenu, strlen_P(TELNETMenu));
uip_send(AppData, strlen_P(TELNETMenu));
AppState->TELNETServer.NextState = TELNET_STATE_GetCommand;
break;
case TELNET_STATE_GetCommand:
if (!(uip_datalen()))
break;
/* Save the issued command for later processing */
AppState->TELNETServer.IssuedCommand = AppData[0];
AppState->TELNETServer.CurrentState = TELNET_STATE_SendResponse;
break;
case TELNET_STATE_SendResponse:
/* Determine which command was issued, perform command processing */
switch (AppState->TELNETServer.IssuedCommand)
{
case 'c':
TELNETServerApp_DisplayTCPConnections();
break;
}
AppState->TELNETServer.NextState = TELNET_STATE_SendMenu;
break;
}
}
}
/** Sends a list of active TCP connections to the TELNET client. */
static void TELNETServerApp_DisplayTCPConnections(void)
{
char* const AppData = (char*)uip_appdata;
strcpy(AppData, "\r\n* Current TCP Connections: *\r\n");
uint16_t ResponseLen = strlen(AppData);
uint8_t ActiveConnCount = 0;
/* Loop through the complete uIP TCP connections list, looking for active connections */
for (uint8_t i = 0; i < UIP_CONNS; i++)
{
struct uip_conn* CurrConnection = &uip_conns[i];
/* If the connection is not closed, it is active and must be added to the out buffer */
if (CurrConnection->tcpstateflags != UIP_CLOSED)
{
/* Add the current connection's details to the out buffer */
ResponseLen += sprintf(&AppData[ResponseLen], "%u) %02d.%02d.%02d.%02d (Local %u, Remote %u)\r\n",
++ActiveConnCount, CurrConnection->ripaddr.u8[0],
CurrConnection->ripaddr.u8[1],
CurrConnection->ripaddr.u8[2],
CurrConnection->ripaddr.u8[3],
HTONS(CurrConnection->lport), HTONS(CurrConnection->rport));
}
}
uip_send(AppData, ResponseLen);
}
\ No newline at end of file
/*
LUFA Library
Copyright (C) Dean Camera, 2010.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for TELNETServerApp.c.
*/
#ifndef _TELNETSERVER_APP_H_
#define _TELNETSERVER_APP_H_
/* Includes: */
#include <avr/pgmspace.h>
#include <string.h>
#include <stdio.h>
#include <uip.h>
/* Macros: */
/** TCP listen port for incomming TELNET traffic */
#define TELNET_SERVER_PORT 23
/* Enums: */
/** States for each TELNET connection to the server. */
enum TELNET_States_t
{
TELNET_STATE_SendHeader, /**< Currently sending welcome header to the client */
TELNET_STATE_SendMenu, /**< Currently sending the command list menu to the client */
TELNET_STATE_GetCommand, /**< Currently waiting for a command from the client */
TELNET_STATE_SendResponse, /**< Processing the issued command and sending a response */
};
/* Function Prototypes: */
void TELNETServerApp_Init(void);
void TELNETServerApp_Callback(void);
#if defined(INCLUDE_FROM_TELNETSERVERAPP_C)
static void TELNETServerApp_DisplayTCPConnections(void);
#endif