2020-10-22 19:25:20 +02:00
/*
* © 2020 , Gregor Baues . All rights reserved .
*
* This is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* It is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with CommandStation . If not , see < https : //www.gnu.org/licenses/>.
*/
# include <Arduino.h>
2020-11-09 15:41:17 +01:00
# include "NetworkDiag.h"
2020-10-22 19:25:20 +02:00
# include "NetworkInterface.h"
2020-11-09 15:41:17 +01:00
# include "RingStream.h"
2020-10-22 19:25:20 +02:00
# include "Transport.h"
extern bool diagNetwork ;
extern uint8_t diagNetworkClient ;
template < class S , class C , class U >
2020-10-26 10:29:40 +01:00
bool Transport < S , C , U > : : setup ( NetworkInterface * nw ) {
2020-10-22 19:25:20 +02:00
if ( protocol = = TCP ) {
2020-10-26 10:29:40 +01:00
connectionPool ( server ) ; // server should have started here so create the connection pool only for TCP though
2020-11-09 15:41:17 +01:00
} else {
connectionPool ( udp ) ;
2020-10-22 19:25:20 +02:00
}
t = new TransportProcessor ( ) ;
2020-11-09 15:41:17 +01:00
t - > nwi = nw ; // The TransportProcessor needs to know which Interface he is connected to
2020-10-22 19:25:20 +02:00
connected = true ; // server & clients which will recieve/send data have all e setup and are available
return true ;
}
template < class S , class C , class U >
void Transport < S , C , U > : : loop ( ) {
switch ( protocol )
{
case UDP :
{
2020-11-09 15:41:17 +01:00
udpHandler ( udp ) ;
2020-10-22 19:25:20 +02:00
break ;
} ;
case TCP :
{
2020-11-09 15:41:17 +01:00
DBG ( F ( " Transport: %s \n " ) , this - > transport = = WIFI ? " WIFI " : " ETHERNET " ) ;
2020-10-26 10:29:40 +01:00
tcpSessionHandler ( server ) ;
2020-10-22 19:25:20 +02:00
} ;
case MQTT :
{
// MQTT
break ;
} ;
}
}
template < class S , class C , class U >
void Transport < S , C , U > : : connectionPool ( S * server )
{
for ( int i = 0 ; i < Transport : : maxConnections ; i + + )
{
clients [ i ] = server - > accept ( ) ;
2020-10-27 21:33:16 +01:00
connections [ i ] . client = & clients [ i ] ;
memset ( connections [ i ] . overflow , 0 , MAX_OVERFLOW ) ;
connections [ i ] . id = i ;
2020-11-09 15:41:17 +01:00
TRC ( F ( " \n TCP Connection pool: [%d:%x] " ) , i , connections [ i ] . client ) ;
2020-10-22 19:25:20 +02:00
}
}
2020-11-09 15:41:17 +01:00
template < class S , class C , class U >
void Transport < S , C , U > : : connectionPool ( U * udp )
{
for ( int i = 0 ; i < Transport : : maxConnections ; i + + )
{
// clients[i] = server->accept();
// connections[i].client = &clients[i];
memset ( connections [ i ] . overflow , 0 , MAX_OVERFLOW ) ;
connections [ i ] . id = i ;
TRC ( F ( " \n UDP Connection pool: [%d:%x] " ) , i , connections [ i ] . client ) ;
}
}
/**
* @ todo implement UDP properly
*
* @ tparam S
* @ tparam C
* @ tparam U
*/
2020-10-22 19:25:20 +02:00
template < class S , class C , class U >
2020-11-09 15:41:17 +01:00
void Transport < S , C , U > : : udpHandler ( U * udp )
2020-10-22 19:25:20 +02:00
{
int packetSize = udp - > parsePacket ( ) ;
2020-11-09 15:41:17 +01:00
if ( packetSize > 0 )
2020-10-22 19:25:20 +02:00
{
2020-11-09 15:41:17 +01:00
TRC ( F ( " \n Received packet of size:[%d] " ) , packetSize ) ;
2020-10-22 19:25:20 +02:00
IPAddress remote = udp - > remoteIP ( ) ;
char portBuffer [ 6 ] ;
2020-11-09 15:41:17 +01:00
TRC ( F ( " From: [%d.%d.%d.%d: %s] " ) , remote [ 0 ] , remote [ 1 ] , remote [ 2 ] , remote [ 3 ] , utoa ( udp - > remotePort ( ) , portBuffer , 10 ) ) ; // DIAG has issues with unsigend int's so go through utoa
udp - > read ( t - > buffer , MAX_ETH_BUFFER ) ;
t - > buffer [ packetSize ] = 0 ; // terminate buffer
t - > readStream ( & connections [ 0 ] , false ) ; // there is only one connection for UDP; reading into the buffer has been done
2020-10-22 19:25:20 +02:00
2020-11-09 15:41:17 +01:00
memset ( t - > buffer , 0 , MAX_ETH_BUFFER ) ; // reset PacktBuffer
return ;
2020-10-22 19:25:20 +02:00
// send the reply
// udp.beginPacket(udp.remoteIP(), udp.remotePort());
// parse(&udp, (byte *)buffer, true); //////////// Put into the TransportProcessor
// udp.endPacket();
}
2020-11-09 15:41:17 +01:00
return ;
2020-10-22 19:25:20 +02:00
}
/**
* @ brief As tcpHandler but this time the connections are kept open ( thus creating a statefull session ) as long as the client doesn ' t disconnect . A connection
* pool has been setup beforehand and determines the number of available sessions depending on the network hardware . Commands crossing packet boundaries will be captured
*
*/
template < class S , class C , class U >
void Transport < S , C , U > : : tcpSessionHandler ( S * server )
{
// get client from the server
C client = server - > accept ( ) ;
2020-10-26 10:29:40 +01:00
// check for new client
2020-10-22 19:25:20 +02:00
if ( client )
{
2020-10-26 10:29:40 +01:00
for ( byte i = 0 ; i < maxConnections ; i + + )
2020-10-22 19:25:20 +02:00
{
if ( ! clients [ i ] )
{
// On accept() the EthernetServer doesn't track the client anymore
// so we store it in our client array
clients [ i ] = client ;
2020-11-09 15:41:17 +01:00
INFO ( F ( " New Client: [%d:%x] " ) , i , clients [ i ] ) ;
2020-10-22 19:25:20 +02:00
break ;
}
}
}
2020-10-26 10:29:40 +01:00
2020-10-22 19:25:20 +02:00
// check for incoming data from all possible clients
2020-10-26 10:29:40 +01:00
for ( byte i = 0 ; i < maxConnections ; i + + )
2020-10-22 19:25:20 +02:00
{
if ( clients [ i ] & & clients [ i ] . available ( ) > 0 )
{
2020-11-09 15:41:17 +01:00
t - > readStream ( & connections [ i ] , true ) ;
2020-10-22 19:25:20 +02:00
}
// stop any clients which disconnect
2020-10-26 10:29:40 +01:00
for ( byte i = 0 ; i < maxConnections ; i + + )
2020-10-22 19:25:20 +02:00
{
if ( clients [ i ] & & ! clients [ i ] . connected ( ) )
{
2020-11-09 15:41:17 +01:00
INFO ( F ( " Disconnect client #%d " ) , i ) ;
2020-10-22 19:25:20 +02:00
clients [ i ] . stop ( ) ;
connections [ i ] . isProtocolDefined = false ;
2020-10-26 10:29:40 +01:00
if ( diagNetworkClient = = i & & diagNetwork )
{
2020-10-22 19:25:20 +02:00
diagNetwork = false ;
2020-11-09 15:41:17 +01:00
NetworkDiag : : resetDiagOut ( ) ;
2020-10-22 19:25:20 +02:00
}
}
}
}
}
template < class S , class C , class U >
2020-10-26 10:29:40 +01:00
Transport < S , C , U > : : Transport ( ) { }
2020-10-22 19:25:20 +02:00
template < class S , class C , class U >
2020-10-26 10:29:40 +01:00
Transport < S , C , U > : : ~ Transport ( ) { }
2020-10-22 19:25:20 +02:00
// explicitly instatiate to get the relevant copies for ethernet / wifi build @compile time
template class Transport < EthernetServer , EthernetClient , EthernetUDP > ;
template class Transport < WiFiServer , WiFiClient , WiFiUDP > ;