Repo-Init
 
Loading...
Searching...
No Matches
TelnetServer Class Reference

#include <TelnetServer.hpp>

Inheritance diagram for TelnetServer:
Collaboration diagram for TelnetServer:

Public Member Functions

 TelnetServer ()=default
 Constructor for server.
 
 TelnetServer (const TelnetServer &)=delete
 Copy constructor.
 
 TelnetServer (TelnetServer &&)=delete
 Move constructor.
 
TelnetServeroperator= (TelnetServer)=delete
 Copy assignment operator.
 
TelnetServeroperator= (TelnetServer &&)=delete
 Move assignment operator.
 
 ~TelnetServer ()
 Destructor for server.
 
bool initialise (unsigned long listenPort, const std::shared_ptr< std::atomic_flag > &checkFlag, std::string promptString="", const std::shared_ptr< prometheus::Registry > &reg=nullptr, const std::string &prependName="")
 
void shutdown ()
 Closes the Telnet Server.
 
void connectedCallback (FPTR_ConnectedCallback func)
 
FPTR_ConnectedCallback connectedCallback () const
 
void newLineCallback (FPTR_NewLineCallback func)
 
FPTR_NewLineCallback newLineCallBack () const
 
void tabCallback (FPTR_TabCallback func)
 
FPTR_TabCallback tabCallback () const
 
const VEC_SP_TelnetSessionsessions () const
 
bool interactivePrompt () const
 
void promptString (const std::string_view &prompt)
 
const std::string & promptString () const
 

Private Member Functions

bool acceptConnection ()
 
void threadFunc () noexcept
 
void update ()
 Process new connections and messages.
 

Private Attributes

FPTR_ConnectedCallback m_connectedCallback
 
FPTR_NewLineCallback m_newlineCallback
 
FPTR_TabCallback m_tabCallback
 
unsigned long m_listenPort {}
 
Socket m_listenSocket {-1}
 
VEC_SP_TelnetSession m_sessions
 
bool m_initialised {false}
 
std::string m_promptString
 
std::unique_ptr< TelnetStatsm_stats
 
std::atomic_flag m_shouldStop {false}
 
std::unique_ptr< std::thread > m_serverThread
 
std::shared_ptr< std::atomic_flag > m_checkFlag
 

Detailed Description

Definition at line 130 of file TelnetServer.hpp.

Constructor & Destructor Documentation

◆ TelnetServer() [1/3]

TelnetServer::TelnetServer ( )
default

Constructor for server.

◆ TelnetServer() [2/3]

TelnetServer::TelnetServer ( const TelnetServer & )
delete

Copy constructor.

◆ TelnetServer() [3/3]

TelnetServer::TelnetServer ( TelnetServer && )
delete

Move constructor.

◆ ~TelnetServer()

TelnetServer::~TelnetServer ( )

Destructor for server.

Definition at line 531 of file TelnetServer.cpp.

532{
533 try
534 {
535 shutdown();
536 }
537 catch (const std::exception &e)
538 {
539 try
540 {
541 spdlog::error("Telnet server destructor thrown an exception: {}", e.what());
542 }
543 catch (const std::exception &e2)
544 {
545 std::cerr << "Telnet server destructor and also logger thrown an exception: " << e.what() << '\n'
546 << e2.what() << '\n';
547 }
548 }
549}
void shutdown()
Closes the Telnet Server.
Here is the call graph for this function:

Member Function Documentation

◆ acceptConnection()

bool TelnetServer::acceptConnection ( )
private

Definition at line 622 of file TelnetServer.cpp.

623{
624 const Socket ClientSocket = accept(m_listenSocket, nullptr, nullptr);
625 if (ClientSocket == INVALID_SOCKET)
626 {
627 return false;
628 }
629 if (m_sessions.size() >= MAX_AVAILABLE_SESSION)
630 {
631 // Create for only sending error
632 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
633 session->initialise();
634
635 session->sendLine("Too many active connections. Please try again later. \r\nClosing...");
636 session->closeClient();
637 return false;
638 }
639
640 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
641 m_sessions.push_back(session);
642 session->initialise();
643 return true;
644}
constexpr int MAX_AVAILABLE_SESSION
constexpr int INVALID_SOCKET
int Socket
VEC_SP_TelnetSession m_sessions
Socket m_listenSocket
Here is the caller graph for this function:

◆ connectedCallback() [1/2]

FPTR_ConnectedCallback TelnetServer::connectedCallback ( ) const
inline

Definition at line 167 of file TelnetServer.hpp.

167{ return m_connectedCallback; }
FPTR_ConnectedCallback m_connectedCallback

◆ connectedCallback() [2/2]

void TelnetServer::connectedCallback ( FPTR_ConnectedCallback func)
inline

Definition at line 166 of file TelnetServer.hpp.

166{ m_connectedCallback = std::move(func); }

◆ initialise()

bool TelnetServer::initialise ( unsigned long listenPort,
const std::shared_ptr< std::atomic_flag > & checkFlag,
std::string promptString = "",
const std::shared_ptr< prometheus::Registry > & reg = nullptr,
const std::string & prependName = "" )

Initializes a new Telnet server

Parameters
[in]listenPortPort to listen
[in]promptStringPrompt string for connected users
[in]regPrometheus registry for stats
[in]prependNamePrefix for Prometheus stats
Returns
true If initialized
false otherwise

Definition at line 551 of file TelnetServer.cpp.

554{
555 if (m_initialised)
556 {
557 return false;
558 }
559
560 m_checkFlag = checkFlag;
561 m_listenPort = listenPort;
562 m_promptString = std::move(promptString);
563
564 addrinfo hints{};
565 memset(&hints, 0, sizeof(hints));
566
567 hints.ai_family = AF_INET;
568 hints.ai_socktype = SOCK_STREAM;
569 hints.ai_protocol = IPPROTO_TCP;
570 hints.ai_flags = AI_PASSIVE;
571
572 // Resolve the server address and port
573 addrinfo *result = nullptr;
574 if (getaddrinfo(nullptr, std::to_string(m_listenPort).c_str(), &hints, &result) != 0)
575 {
576 return false;
577 }
578
579 // Create a SOCKET for connecting to server
580 m_listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
582 {
583 freeaddrinfo(result);
584 return false;
585 }
586
587 if (int optionVal = 1; setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &optionVal, sizeof(optionVal)) < 0)
588 {
589 freeaddrinfo(result);
590 close(m_listenSocket);
591 return false;
592 }
593
594 // Setup the TCP listening socket
595 if (bind(m_listenSocket, result->ai_addr, result->ai_addrlen) < 0)
596 {
597 freeaddrinfo(result);
598 close(m_listenSocket);
599 return false;
600 }
601 freeaddrinfo(result);
602
603 if (listen(m_listenSocket, SOMAXCONN) < 0)
604 {
605 close(m_listenSocket);
606 return false;
607 }
608
609 // If prometheus registry is provided prepare statistics
610 if (reg)
611 {
612 m_stats = std::make_unique<TelnetStats>(reg, listenPort, prependName);
613 }
614
615 m_shouldStop.clear();
616 m_serverThread = std::make_unique<std::thread>(&TelnetServer::threadFunc, this);
617
618 m_initialised = true;
619 return true;
620}
std::unique_ptr< TelnetStats > m_stats
unsigned long m_listenPort
std::atomic_flag m_shouldStop
std::string m_promptString
std::unique_ptr< std::thread > m_serverThread
void threadFunc() noexcept
std::shared_ptr< std::atomic_flag > m_checkFlag
const std::string & promptString() const
Here is the call graph for this function:

◆ interactivePrompt()

bool TelnetServer::interactivePrompt ( ) const
inline

Definition at line 177 of file TelnetServer.hpp.

177{ return !m_promptString.empty(); }

◆ newLineCallBack()

FPTR_NewLineCallback TelnetServer::newLineCallBack ( ) const
inline

Definition at line 170 of file TelnetServer.hpp.

170{ return m_newlineCallback; }
FPTR_NewLineCallback m_newlineCallback

◆ newLineCallback()

void TelnetServer::newLineCallback ( FPTR_NewLineCallback func)
inline

Definition at line 169 of file TelnetServer.hpp.

169{ m_newlineCallback = std::move(func); }

◆ operator=() [1/2]

TelnetServer & TelnetServer::operator= ( TelnetServer && )
delete

Move assignment operator.

◆ operator=() [2/2]

TelnetServer & TelnetServer::operator= ( TelnetServer )
delete

Copy assignment operator.

◆ promptString() [1/2]

const std::string & TelnetServer::promptString ( ) const
inline

Definition at line 179 of file TelnetServer.hpp.

179{ return m_promptString; }
Here is the caller graph for this function:

◆ promptString() [2/2]

void TelnetServer::promptString ( const std::string_view & prompt)
inline

Definition at line 178 of file TelnetServer.hpp.

178{ m_promptString = prompt; }

◆ sessions()

const VEC_SP_TelnetSession & TelnetServer::sessions ( ) const
inline

Definition at line 175 of file TelnetServer.hpp.

175{ return m_sessions; }

◆ shutdown()

void TelnetServer::shutdown ( )

Closes the Telnet Server.

Definition at line 733 of file TelnetServer.cpp.

734{
735 // Attempt to cleanly close every telnet session in flight.
736 for (const SP_TelnetSession &tSession : m_sessions)
737 {
738 tSession->closeClient();
739 }
740 m_sessions.clear();
741
742 // No longer need server socket so close it.
743 close(m_listenSocket);
745 m_initialised = false;
746
747 m_shouldStop.test_and_set();
748 if (m_serverThread && m_serverThread->joinable())
749 {
750 m_serverThread->join();
751 m_serverThread.reset();
752 }
753}
std::shared_ptr< TelnetSession > SP_TelnetSession
Here is the caller graph for this function:

◆ tabCallback() [1/2]

FPTR_TabCallback TelnetServer::tabCallback ( ) const
inline

Definition at line 173 of file TelnetServer.hpp.

173{ return m_tabCallback; }
FPTR_TabCallback m_tabCallback

◆ tabCallback() [2/2]

void TelnetServer::tabCallback ( FPTR_TabCallback func)
inline

Definition at line 172 of file TelnetServer.hpp.

172{ m_tabCallback = std::move(func); }

◆ threadFunc()

void TelnetServer::threadFunc ( )
privatenoexcept

Definition at line 646 of file TelnetServer.cpp.

647{
648 spdlog::info("Telnet server started");
649 while (!m_shouldStop._M_i)
650 {
651 try
652 {
653 update();
654 if (m_checkFlag)
655 {
656 m_checkFlag->test_and_set();
657 }
658 }
659 catch (const std::exception &e)
660 {
661 spdlog::error("Telnet server failed: {}", e.what());
662 }
663 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_INTERVAL_MS));
664 }
665 spdlog::info("Telnet server stopped");
666}
constexpr int SLEEP_INTERVAL_MS
void update()
Process new connections and messages.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ update()

void TelnetServer::update ( )
private

Process new connections and messages.

Definition at line 668 of file TelnetServer.cpp.

669{
670 // See if connection pending on the listening socket
671 fd_set readSet;
672 FD_ZERO(&readSet);
673 FD_SET(m_listenSocket, &readSet);
674 timeval timeout{};
675 timeout.tv_sec = 0; // Zero timeout (poll)
676 timeout.tv_usec = 0;
677
678 bool newConnectionAccept = false;
679 bool newConnectionRefused = false;
680
681 TelnetServerStats serverStats;
682 serverStats.processingTimeStart = std::chrono::high_resolution_clock::now();
683
684 // If there is a connection pending, accept it.
685 if (select(m_listenSocket + 1, &readSet, nullptr, nullptr, &timeout) > 0)
686 {
687 if (acceptConnection())
688 {
689 newConnectionAccept = true;
690 }
691 else
692 {
693 newConnectionRefused = true;
694 }
695 }
696
697 // Update all the telnet Sessions that are currently in flight.
698 for (size_t idx = 0; idx < m_sessions.size(); ++idx)
699 {
700 // Update session
701 m_sessions[idx]->update();
702
703 // Close session if needed
704 if (m_sessions[idx]->checkTimeout())
705 {
706 m_sessions[idx]->closeClient();
707 if (m_stats)
708 {
709 m_stats->consumeStats(m_sessions[idx]->stats, true);
710 }
711 m_sessions.erase(m_sessions.begin() + static_cast<int>(idx));
712 --idx;
713 }
714 else
715 {
716 if (m_stats)
717 {
718 m_stats->consumeStats(m_sessions[idx]->stats, false);
719 }
720 }
721 }
722
723 serverStats.activeConnectionCtr = m_sessions.size();
724 serverStats.acceptedConnectionCtr = static_cast<uint64_t>(newConnectionAccept);
725 serverStats.refusedConnectionCtr = static_cast<uint64_t>(newConnectionRefused);
726 serverStats.processingTimeEnd = std::chrono::high_resolution_clock::now();
727 if (m_stats)
728 {
729 m_stats->consumeStats(serverStats);
730 }
731}
bool acceptConnection()
std::chrono::high_resolution_clock::time_point processingTimeStart
Processing time start.
uint64_t activeConnectionCtr
Number of active connections.
std::chrono::high_resolution_clock::time_point processingTimeEnd
Processing time end.
uint64_t refusedConnectionCtr
Number of refused connections.
uint64_t acceptedConnectionCtr
Number of accepted connections.
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_checkFlag

std::shared_ptr<std::atomic_flag> TelnetServer::m_checkFlag
private

Runtime check flag

Definition at line 207 of file TelnetServer.hpp.

◆ m_connectedCallback

FPTR_ConnectedCallback TelnetServer::m_connectedCallback
private

Definition at line 183 of file TelnetServer.hpp.

◆ m_initialised

bool TelnetServer::m_initialised {false}
private

Definition at line 198 of file TelnetServer.hpp.

198{false};

◆ m_listenPort

unsigned long TelnetServer::m_listenPort {}
private

Definition at line 195 of file TelnetServer.hpp.

195{};

◆ m_listenSocket

Socket TelnetServer::m_listenSocket {-1}
private

Definition at line 196 of file TelnetServer.hpp.

196{-1};

◆ m_newlineCallback

FPTR_NewLineCallback TelnetServer::m_newlineCallback
private

Definition at line 185 of file TelnetServer.hpp.

◆ m_promptString

std::string TelnetServer::m_promptString
private

Definition at line 200 of file TelnetServer.hpp.

◆ m_serverThread

std::unique_ptr<std::thread> TelnetServer::m_serverThread
private

Thread handler

Definition at line 206 of file TelnetServer.hpp.

◆ m_sessions

VEC_SP_TelnetSession TelnetServer::m_sessions
private

Definition at line 197 of file TelnetServer.hpp.

◆ m_shouldStop

std::atomic_flag TelnetServer::m_shouldStop {false}
private

Flag to stop monitoring.

Definition at line 205 of file TelnetServer.hpp.

205{false};

◆ m_stats

std::unique_ptr<TelnetStats> TelnetServer::m_stats
private

Definition at line 203 of file TelnetServer.hpp.

◆ m_tabCallback

FPTR_TabCallback TelnetServer::m_tabCallback
private

Definition at line 187 of file TelnetServer.hpp.


The documentation for this class was generated from the following files: