Version 1.10+4

Updated with chrishamm's latest Network, Webserver and PrintMonitor
module changes
This commit is contained in:
David Crocker 2016-03-30 13:29:13 +01:00
parent 1356abd707
commit 818e14f984
7 changed files with 98 additions and 80 deletions

Binary file not shown.

View file

@ -30,7 +30,7 @@ Licence: GPL
#endif #endif
#ifndef VERSION #ifndef VERSION
#define VERSION "1.10+3" #define VERSION "1.10+4"
#endif #endif
#ifndef DATE #ifndef DATE

View file

@ -124,9 +124,11 @@ void UnlockLWIP()
lwipLocked = false; lwipLocked = false;
} }
// Callback functions for the EMAC driver // Callback functions for the EMAC driver and for LwIP
// Callback to report when the link has gone up or down // Callback to report when the network interface has gone up or down.
// Note that this is only a rough indicator and may not be called when
// the IP address is changed on-the-fly!
static void ethernet_status_callback(struct netif *netif) static void ethernet_status_callback(struct netif *netif)
{ {
if (netif_is_up(netif)) if (netif_is_up(netif))
@ -134,10 +136,6 @@ static void ethernet_status_callback(struct netif *netif)
char ip[16]; char ip[16];
ipaddr_ntoa_r(&(netif->ip_addr), ip, sizeof(ip)); ipaddr_ntoa_r(&(netif->ip_addr), ip, sizeof(ip));
reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network up, IP=%s\n", ip); reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network up, IP=%s\n", ip);
// Do mDNS announcement here and not while the network is being initialised,
// because the IP address may not be assigned at that time
mdns_announce();
} }
else else
{ {
@ -178,8 +176,6 @@ static void conn_err(void *arg, err_t err)
} }
} }
/*-----------------------------------------------------------------------------------*/
static err_t conn_poll(void *arg, tcp_pcb *pcb) static err_t conn_poll(void *arg, tcp_pcb *pcb)
{ {
ConnectionState *cs = (ConnectionState*)arg; ConnectionState *cs = (ConnectionState*)arg;
@ -235,8 +231,6 @@ static err_t conn_poll(void *arg, tcp_pcb *pcb)
return ERR_OK; return ERR_OK;
} }
/*-----------------------------------------------------------------------------------*/
static err_t conn_sent(void *arg, tcp_pcb *pcb, u16_t len) static err_t conn_sent(void *arg, tcp_pcb *pcb, u16_t len)
{ {
ConnectionState *cs = (ConnectionState*)arg; ConnectionState *cs = (ConnectionState*)arg;
@ -259,8 +253,6 @@ static err_t conn_sent(void *arg, tcp_pcb *pcb, u16_t len)
return ERR_OK; return ERR_OK;
} }
/*-----------------------------------------------------------------------------------*/
static err_t conn_recv(void *arg, tcp_pcb *pcb, pbuf *p, err_t err) static err_t conn_recv(void *arg, tcp_pcb *pcb, pbuf *p, err_t err)
{ {
ConnectionState *cs = (ConnectionState*)arg; ConnectionState *cs = (ConnectionState*)arg;
@ -302,8 +294,6 @@ static err_t conn_recv(void *arg, tcp_pcb *pcb, pbuf *p, err_t err)
return ERR_OK; return ERR_OK;
} }
/*-----------------------------------------------------------------------------------*/
static err_t conn_accept(void *arg, tcp_pcb *pcb, err_t err) static err_t conn_accept(void *arg, tcp_pcb *pcb, err_t err)
{ {
LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(arg);
@ -413,7 +403,7 @@ void Network::Spin()
return; return;
} }
if (state == NetworkActive) if (state == NetworkObtainingIP || state == NetworkActive)
{ {
// Is the link still up? // Is the link still up?
if (!ethernet_link_established()) if (!ethernet_link_established())
@ -425,7 +415,7 @@ void Network::Spin()
return; return;
} }
// See if we can read any packets // See if we can read any packets. They may include DHCP responses too
ethernet_task(); ethernet_task();
if (resetCallback) if (resetCallback)
{ {
@ -433,6 +423,21 @@ void Network::Spin()
ethernet_set_rx_callback(&ethernet_rx_callback); ethernet_set_rx_callback(&ethernet_rx_callback);
} }
// Have we obtained a valid IP address yet?
if (state == NetworkObtainingIP)
{
const uint8_t *ip = ethernet_get_ipaddress();
if (ip[0] != 0 && ip[1] != 0 && ip[2] != 0 && ip[3] != 0)
{
// Yes - we're good to go now
state = NetworkActive;
// Send mDNS announcement so that some routers can perform hostname mapping
// if ths board is connected via a non-IGMP capable WiFi bridge (like the TP-Link WR701N)
mdns_announce();
}
}
// See if we can send anything // See if we can send anything
NetworkTransaction *transaction = writingTransactions; NetworkTransaction *transaction = writingTransactions;
if (transaction != nullptr && sendingConnection == nullptr) if (transaction != nullptr && sendingConnection == nullptr)
@ -476,7 +481,7 @@ void Network::Spin()
{ {
ethernet_set_configuration(platform->IPAddress(), platform->NetMask(), platform->GateWay()); ethernet_set_configuration(platform->IPAddress(), platform->NetMask(), platform->GateWay());
} }
state = NetworkActive; state = NetworkObtainingIP;
} }
UnlockLWIP(); UnlockLWIP();
@ -615,6 +620,7 @@ void Network::ConnectionClosed(ConnectionState* cs, bool closeConnection)
tcp_poll(pcb, nullptr, TCP_WRITE_TIMEOUT / TCP_SLOW_INTERVAL / TCP_MAX_SEND_RETRIES); tcp_poll(pcb, nullptr, TCP_WRITE_TIMEOUT / TCP_SLOW_INTERVAL / TCP_MAX_SEND_RETRIES);
if (pcb != nullptr && closeConnection) if (pcb != nullptr && closeConnection)
{ {
tcp_err(pcb, nullptr);
tcp_close(pcb); tcp_close(pcb);
} }
cs->pcb = nullptr; cs->pcb = nullptr;
@ -697,6 +703,7 @@ bool Network::ConnectionClosedGracefully(ConnectionState *cs)
tcp_sent(cs->pcb, nullptr); tcp_sent(cs->pcb, nullptr);
tcp_recv(cs->pcb, nullptr); tcp_recv(cs->pcb, nullptr);
tcp_poll(cs->pcb, nullptr, TCP_WRITE_TIMEOUT / TCP_SLOW_INTERVAL / TCP_MAX_SEND_RETRIES); tcp_poll(cs->pcb, nullptr, TCP_WRITE_TIMEOUT / TCP_SLOW_INTERVAL / TCP_MAX_SEND_RETRIES);
tcp_err(cs->pcb, nullptr);
tcp_close(cs->pcb); tcp_close(cs->pcb);
cs->pcb = nullptr; cs->pcb = nullptr;
@ -736,7 +743,7 @@ const uint8_t *Network::IPAddress() const
void Network::SetIPAddress(const uint8_t ipAddress[], const uint8_t netmask[], const uint8_t gateway[]) void Network::SetIPAddress(const uint8_t ipAddress[], const uint8_t netmask[], const uint8_t gateway[])
{ {
if (state == NetworkActive) if (state == NetworkObtainingIP || state == NetworkActive)
{ {
// This performs IP changes on-the-fly // This performs IP changes on-the-fly
ethernet_set_configuration(ipAddress, netmask, gateway); ethernet_set_configuration(ipAddress, netmask, gateway);
@ -878,22 +885,20 @@ uint16_t Network::GetHttpPort() const
void Network::SetHttpPort(uint16_t port) void Network::SetHttpPort(uint16_t port)
{ {
if (state == NetworkActive && port != httpPort) if (port != httpPort)
{ {
// Close old HTTP port // Close the old HTTP PCB and create a new one
tcp_close(http_pcb); tcp_close(http_pcb);
httpPort = port;
httpd_init();
// Create a new one for the new port // Update mDNS service
tcp_pcb* pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, port);
http_pcb = tcp_listen(pcb);
tcp_accept(http_pcb, conn_accept);
// Update mDNS services
mdns_services[MDNS_HTTP_SERVICE_INDEX].port = port; mdns_services[MDNS_HTTP_SERVICE_INDEX].port = port;
if (state == NetworkActive)
{
mdns_announce(); mdns_announce();
} }
httpPort = port; }
} }
// Close FTP data port and purge associated PCB // Close FTP data port and purge associated PCB
@ -1488,7 +1493,7 @@ void NetworkTransaction::Discard()
{ {
if (reprap.Debug(moduleNetwork)) if (reprap.Debug(moduleNetwork))
{ {
reprap.GetPlatform()->MessageF(HOST_MESSAGE, "Network: Discard() is handling a graceful disconnect for cs=%08x\n", (unsigned int)cs); reprap.GetPlatform()->Message(HOST_MESSAGE, "Network: Discard() is handling a graceful disconnect\n");
} }
reprap.GetNetwork()->ConnectionClosed(cs, false); reprap.GetNetwork()->ConnectionClosed(cs, false);
} }

View file

@ -15,6 +15,7 @@ Separated out from Platform.h by dc42 and extended by zpl
#include <climits> #include <climits>
#include "lwipopts.h" #include "lwipopts.h"
#include "OutputMemory.h" #include "OutputMemory.h"
// This class handles the network - typically an Ethernet. // This class handles the network - typically an Ethernet.
@ -41,7 +42,6 @@ const uint16_t DEFAULT_HTTP_PORT = 80;
const uint16_t FTP_PORT = 21; const uint16_t FTP_PORT = 21;
const uint16_t TELNET_PORT = 23; const uint16_t TELNET_PORT = 23;
/****************************************************************************************************/ /****************************************************************************************************/
struct tcp_pcb; struct tcp_pcb;
@ -201,7 +201,7 @@ class Network
NetworkTransaction * volatile readyTransactions; NetworkTransaction * volatile readyTransactions;
NetworkTransaction * volatile writingTransactions; NetworkTransaction * volatile writingTransactions;
enum { NetworkInactive, NetworkEstablishingLink, NetworkActive } state; enum { NetworkInactive, NetworkEstablishingLink, NetworkObtainingIP, NetworkActive } state;
bool isEnabled; bool isEnabled;
volatile bool resetCallback; volatile bool resetCallback;
char hostname[16]; // Limit DHCP hostname to 15 characters + terminating 0 char hostname[16]; // Limit DHCP hostname to 15 characters + terminating 0

View file

@ -593,7 +593,7 @@ bool PrintMonitor::GetFileInfoResponse(const char *filename, OutputBuffer *&resp
if (filename != nullptr && filename[0] != 0) if (filename != nullptr && filename[0] != 0)
{ {
GCodeFileInfo info; GCodeFileInfo info;
if (!GetFileInfo("0:/", filename, info)) if (!GetFileInfo(FS_PREFIX, filename, info))
{ {
// This may take a few runs... // This may take a few runs...
return false; return false;
@ -681,7 +681,7 @@ void PrintMonitor::StopParsing(const char *filename)
{ {
if (parseState != notParsing && StringEquals(filenameBeingParsed, filename)) if (parseState != notParsing && StringEquals(filenameBeingParsed, filename))
{ {
if (!printingFileParsed) if (filenameBeingPrinted[0] != 0 && !printingFileParsed)
{ {
// If this is the file we're parsing for internal purposes, don't bother with this request // If this is the file we're parsing for internal purposes, don't bother with this request
return; return;

View file

@ -89,7 +89,6 @@ const char* badEscapeResponse = "bad escape";
//******************************************************************************************** //********************************************************************************************
// Constructor and initialisation // Constructor and initialisation
Webserver::Webserver(Platform* p, Network *n) : platform(p), network(n), webserverActive(false) Webserver::Webserver(Platform* p, Network *n) : platform(p), network(n), webserverActive(false)
{ {
@ -103,6 +102,7 @@ void Webserver::Init()
// initialise the webserver class // initialise the webserver class
longWait = platform->Time(); longWait = platform->Time();
webserverActive = true; webserverActive = true;
readingConnection = nullptr;
// initialise all protocol handlers // initialise all protocol handlers
httpInterpreter->ResetState(); httpInterpreter->ResetState();
@ -110,7 +110,6 @@ void Webserver::Init()
telnetInterpreter->ResetState(); telnetInterpreter->ResetState();
} }
// Deal with input/output from/to the client (if any) // Deal with input/output from/to the client (if any)
void Webserver::Spin() void Webserver::Spin()
{ {
@ -136,7 +135,7 @@ void Webserver::Spin()
telnetInterpreter->Spin(); telnetInterpreter->Spin();
// See if we have new data to process // See if we have new data to process
currentTransaction = network->GetTransaction(); currentTransaction = network->GetTransaction(readingConnection);
if (currentTransaction != nullptr) if (currentTransaction != nullptr)
{ {
// Take care of different protocol types here // Take care of different protocol types here
@ -209,7 +208,8 @@ void Webserver::Spin()
// Process other messages (if we can) // Process other messages (if we can)
else if (interpreter != httpInterpreter || httpInterpreter->IsReady()) else if (interpreter != httpInterpreter || httpInterpreter->IsReady())
{ {
for(size_t i = 0; i < 500; i++) readingConnection = currentTransaction->GetConnection();
for(size_t i = 0; i < TCP_MSS / 3; i++)
{ {
char c; char c;
if (currentTransaction->Read(c)) if (currentTransaction->Read(c))
@ -218,20 +218,29 @@ void Webserver::Spin()
// calling either Commit(), Discard() or Defer() // calling either Commit(), Discard() or Defer()
if (interpreter->CharFromClient(c)) if (interpreter->CharFromClient(c))
{ {
readingConnection = nullptr;
break; break;
} }
} }
else else
{ {
// We ran out of data before finding a complete request. // We ran out of data before finding a complete request. This happens when the incoming
// This happens when the incoming message length exceeds the TCP MSS. // message length exceeds the TCP MSS. Notify the current ProtocolInterpreter about this,
// Notify the current ProtocolInterpreter about this // which will remove the current transaction too
interpreter->NoMoreDataAvailable(); interpreter->NoMoreDataAvailable();
readingConnection = nullptr;
break; break;
} }
} }
} }
} }
else if (readingConnection != nullptr)
{
// We failed to find a transaction for a reading connection.
// This should never happen, but if it does, terminate this connection instantly
platform->Message(HOST_MESSAGE, "Error: Transaction for reading connection not found\n");
readingConnection->Terminate();
}
network->Unlock(); // unlock LWIP again network->Unlock(); // unlock LWIP again
} }
platform->ClassReport(longWait); platform->ClassReport(longWait);
@ -364,6 +373,12 @@ void Webserver::ConnectionLost(const ConnectionState *cs)
platform->MessageF(HOST_MESSAGE, "ConnectionLost called for local port %d (remote port %d)\n", localPort, cs->GetRemotePort()); platform->MessageF(HOST_MESSAGE, "ConnectionLost called for local port %d (remote port %d)\n", localPort, cs->GetRemotePort());
} }
interpreter->ConnectionLost(cs); interpreter->ConnectionLost(cs);
// Don't process any more data from this connection if has gone down
if (readingConnection == cs)
{
readingConnection = nullptr;
}
} }
@ -405,6 +420,13 @@ void ProtocolInterpreter::ConnectionEstablished()
webserver->currentTransaction->Discard(); webserver->currentTransaction->Discard();
} }
void ProtocolInterpreter::NoMoreDataAvailable()
{
// Request is not complete yet, but don't care. Interpreters that do not explicitly
// overwrite this method don't support more than one connected client anyway
webserver->currentTransaction->Discard();
}
// Start writing to a new file // Start writing to a new file
bool ProtocolInterpreter::StartUpload(FileStore *file, const char *fileName) bool ProtocolInterpreter::StartUpload(FileStore *file, const char *fileName)
{ {
@ -514,7 +536,7 @@ Webserver::HttpInterpreter::HttpInterpreter(Platform *p, Webserver *ws, Network
{ {
gcodeReadIndex = gcodeWriteIndex = 0; gcodeReadIndex = gcodeWriteIndex = 0;
gcodeReply = new OutputStack(); gcodeReply = new OutputStack();
processingDeferredRequest = false; deferredRequestConnection = nullptr;
seq = 0; seq = 0;
} }
@ -877,11 +899,12 @@ bool Webserver::HttpInterpreter::IsReady()
} }
// Are we still processing a deferred request? // Are we still processing a deferred request?
if (processingDeferredRequest && deferredRequestConnection == webserver->currentTransaction->GetConnection()) if (deferredRequestConnection == webserver->currentTransaction->GetConnection())
{ {
if (deferredRequestConnection->IsConnected()) if (deferredRequestConnection->IsConnected())
{ {
// Process more of this request // Process more of this request. If it doesn't finish this time, it will be appended to the list
// of ready transactions again, which will ensure it can be processed later again
ProcessDeferredRequest(); ProcessDeferredRequest();
} }
else else
@ -997,9 +1020,9 @@ bool Webserver::HttpInterpreter::GetJsonResponse(const char* request, OutputBuff
} }
else if (StringEquals(request, "fileinfo")) else if (StringEquals(request, "fileinfo"))
{ {
if (processingDeferredRequest) if (deferredRequestConnection != nullptr)
{ {
// Don't allow multiple requests to be processed at once // Don't allow multiple deferred requests to be processed at once
webserver->currentTransaction->Defer(true); webserver->currentTransaction->Defer(true);
} }
else else
@ -1076,14 +1099,16 @@ void Webserver::HttpInterpreter::NoMoreDataAvailable()
void Webserver::HttpInterpreter::ConnectionLost(const ConnectionState *cs) void Webserver::HttpInterpreter::ConnectionLost(const ConnectionState *cs)
{ {
// Make sure deferred requests are cancelled // Make sure deferred requests are cancelled
if (processingDeferredRequest && deferredRequestConnection == cs) if (deferredRequestConnection == cs)
{ {
if (filenameBeingProcessed[0] != 0)
{
// Only stop the parsing process if the filename is valid
reprap.GetPrintMonitor()->StopParsing(filenameBeingProcessed); reprap.GetPrintMonitor()->StopParsing(filenameBeingProcessed);
deferredRequestConnection = nullptr;
} }
processingDeferredRequest = false;
// If we couldn't read an entire request from a connection, reset our state here again
if (webserver->readingConnection == cs)
{
ResetState();
} }
// Deal with aborted POST uploads. Note that we also check the remote port here, // Deal with aborted POST uploads. Note that we also check the remote port here,
@ -1756,7 +1781,7 @@ void Webserver::HttpInterpreter::HandleGCodeReply(const char *reply)
void Webserver::HttpInterpreter::ProcessDeferredRequest() void Webserver::HttpInterpreter::ProcessDeferredRequest()
{ {
OutputBuffer *jsonResponse = nullptr; OutputBuffer *jsonResponse = nullptr;
bool doingDeferredRequest = processingDeferredRequest; const ConnectionState *lastDeferredConnection = deferredRequestConnection;
// At the moment only file info requests are deferred. // At the moment only file info requests are deferred.
// Parsing the file may take a while, so keep LwIP running while we're waiting // Parsing the file may take a while, so keep LwIP running while we're waiting
@ -1765,13 +1790,14 @@ void Webserver::HttpInterpreter::ProcessDeferredRequest()
while (!network->Lock()); while (!network->Lock());
// Because LwIP was unlocked before, there is a chance that the ConnectionLost() call has already // Because LwIP was unlocked before, there is a chance that the ConnectionLost() call has already
// stopped the file parsing. Check this special case // stopped the file parsing. Check this special case here
NetworkTransaction *transaction = webserver->currentTransaction; if (lastDeferredConnection == deferredRequestConnection)
if (doingDeferredRequest == processingDeferredRequest)
{ {
processingDeferredRequest = !gotFileInfo; NetworkTransaction *transaction = webserver->currentTransaction;
if (gotFileInfo) if (gotFileInfo)
{ {
deferredRequestConnection = nullptr;
// Got it - send the response now // Got it - send the response now
transaction->Write("HTTP/1.1 200 OK\n"); transaction->Write("HTTP/1.1 200 OK\n");
transaction->Write("Cache-Control: no-cache, no-store, must-revalidate\n"); transaction->Write("Cache-Control: no-cache, no-store, must-revalidate\n");
@ -1790,8 +1816,12 @@ void Webserver::HttpInterpreter::ProcessDeferredRequest()
transaction->Defer(false); transaction->Defer(false);
} }
} }
else
{
// Clean up again if we cannot send the response at all
OutputBuffer::ReleaseAll(jsonResponse);
}
} }
//******************************************************************************************** //********************************************************************************************
// //
@ -1954,12 +1984,6 @@ void Webserver::FtpInterpreter::ResetState()
state = idle; state = idle;
} }
void Webserver::FtpInterpreter::NoMoreDataAvailable()
{
clientPointer = 0;
SendReply(422, "Incomplete or too long request", true);
}
bool Webserver::FtpInterpreter::DoingFastUpload() const bool Webserver::FtpInterpreter::DoingFastUpload() const
{ {
return (IsUploading() && webserver->currentTransaction->GetLocalPort() == network->GetDataPort()); return (IsUploading() && webserver->currentTransaction->GetLocalPort() == network->GetDataPort());
@ -2572,15 +2596,6 @@ void Webserver::TelnetInterpreter::ResetState()
clientPointer = 0; clientPointer = 0;
} }
void Webserver::TelnetInterpreter::NoMoreDataAvailable()
{
clientPointer = 0;
NetworkTransaction *transaction = webserver->currentTransaction;
transaction->Write("Invalid or too long request\r\n");
transaction->Commit(true);
}
void Webserver::TelnetInterpreter::ProcessLine() void Webserver::TelnetInterpreter::ProcessLine()
{ {
NetworkTransaction *transaction = network->GetTransaction(); NetworkTransaction *transaction = network->GetTransaction();

View file

@ -85,7 +85,7 @@ class ProtocolInterpreter
virtual void ConnectionEstablished(); virtual void ConnectionEstablished();
virtual void ConnectionLost(const ConnectionState *cs) { } virtual void ConnectionLost(const ConnectionState *cs) { }
virtual bool CharFromClient(const char c) = 0; virtual bool CharFromClient(const char c) = 0;
virtual void NoMoreDataAvailable() = 0; virtual void NoMoreDataAvailable();
virtual bool DoingFastUpload() const; virtual bool DoingFastUpload() const;
virtual void DoFastUpload(); virtual void DoFastUpload();
@ -250,8 +250,7 @@ class Webserver
uint32_t postFileLength, uploadedBytes; // How many POST bytes do we expect and how many have already been written? uint32_t postFileLength, uploadedBytes; // How many POST bytes do we expect and how many have already been written?
// Deferred requests (rr_fileinfo) // Deferred requests (rr_fileinfo)
bool processingDeferredRequest; // Are we processing a transaction multiple times to retrieve information? ConnectionState * volatile deferredRequestConnection; // Which connection expects a response for a deferred request?
ConnectionState *deferredRequestConnection; // Which connection expects a response?
char filenameBeingProcessed[FILENAME_LENGTH]; // The filename being processed (for rr_fileinfo) char filenameBeingProcessed[FILENAME_LENGTH]; // The filename being processed (for rr_fileinfo)
void ProcessDeferredRequest(); void ProcessDeferredRequest();
@ -268,7 +267,6 @@ class Webserver
void ConnectionEstablished() override; void ConnectionEstablished() override;
void ConnectionLost(const ConnectionState *cs) override; void ConnectionLost(const ConnectionState *cs) override;
bool CharFromClient(const char c) override; bool CharFromClient(const char c) override;
void NoMoreDataAvailable() override;
void ResetState(); void ResetState();
bool DoingFastUpload() const override; bool DoingFastUpload() const override;
@ -314,7 +312,6 @@ class Webserver
void ConnectionEstablished() override; void ConnectionEstablished() override;
void ConnectionLost(const ConnectionState *cs) override; void ConnectionLost(const ConnectionState *cs) override;
bool CharFromClient(const char c) override; bool CharFromClient(const char c) override;
void NoMoreDataAvailable() override;
void ResetState(); void ResetState();
bool GCodeAvailable() const; bool GCodeAvailable() const;
@ -364,6 +361,7 @@ class Webserver
Network* network; Network* network;
bool webserverActive; bool webserverActive;
NetworkTransaction *currentTransaction; NetworkTransaction *currentTransaction;
ConnectionState * volatile readingConnection;
float longWait; float longWait;
}; };