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 540 of file TelnetServer.cpp.

541{
542 try
543 {
544 shutdown();
545 }
546 catch (const std::exception &e)
547 {
548 try
549 {
550 spdlog::error("Telnet server destructor thrown an exception: {}", e.what());
551 }
552 catch (const std::exception &e2)
553 {
554 std::cerr << "Telnet server destructor and also logger thrown an exception: " << e.what() << '\n'
555 << e2.what() << '\n';
556 }
557 }
558}
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 631 of file TelnetServer.cpp.

632{
633 const Socket ClientSocket = accept(m_listenSocket, nullptr, nullptr);
634 if (ClientSocket == INVALID_SOCKET)
635 {
636 return false;
637 }
638 if (m_sessions.size() >= MAX_AVAILABLE_SESSION)
639 {
640 // Create for only sending error
641 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
642 session->initialise();
643
644 session->sendLine("Too many active connections. Please try again later. \r\nClosing...");
645 session->closeClient();
646 return false;
647 }
648
649 const auto session = std::make_shared<TelnetSession>(ClientSocket, shared_from_this());
650 m_sessions.push_back(session);
651 session->initialise();
652 return true;
653}
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 560 of file TelnetServer.cpp.

563{
564 if (m_initialised)
565 {
566 return false;
567 }
568
569 m_checkFlag = checkFlag;
570 m_listenPort = listenPort;
571 m_promptString = std::move(promptString);
572
573 addrinfo hints{};
574 memset(&hints, 0, sizeof(hints));
575
576 hints.ai_family = AF_INET;
577 hints.ai_socktype = SOCK_STREAM;
578 hints.ai_protocol = IPPROTO_TCP;
579 hints.ai_flags = AI_PASSIVE;
580
581 // Resolve the server address and port
582 addrinfo *result = nullptr;
583 if (getaddrinfo(nullptr, std::to_string(m_listenPort).c_str(), &hints, &result) != 0)
584 {
585 return false;
586 }
587
588 // Create a SOCKET for connecting to server
589 m_listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
591 {
592 freeaddrinfo(result);
593 return false;
594 }
595
596 if (int optionVal = 1; setsockopt(m_listenSocket, SOL_SOCKET, SO_REUSEADDR, &optionVal, sizeof(optionVal)) < 0)
597 {
598 freeaddrinfo(result);
599 close(m_listenSocket);
600 return false;
601 }
602
603 // Setup the TCP listening socket
604 if (bind(m_listenSocket, result->ai_addr, result->ai_addrlen) < 0)
605 {
606 freeaddrinfo(result);
607 close(m_listenSocket);
608 return false;
609 }
610 freeaddrinfo(result);
611
612 if (listen(m_listenSocket, SOMAXCONN) < 0)
613 {
614 close(m_listenSocket);
615 return false;
616 }
617
618 // If prometheus registry is provided prepare statistics
619 if (reg)
620 {
621 m_stats = std::make_unique<TelnetStats>(reg, listenPort, prependName);
622 }
623
624 m_shouldStop.clear();
625 m_serverThread = std::make_unique<std::thread>(&TelnetServer::threadFunc, this);
626
627 m_initialised = true;
628 return true;
629}
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.length() > 0; }

◆ 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 742 of file TelnetServer.cpp.

743{
744 // Attempt to cleanly close every telnet session in flight.
745 for (const SP_TelnetSession &tSession : m_sessions)
746 {
747 tSession->closeClient();
748 }
749 m_sessions.clear();
750
751 // No longer need server socket so close it.
752 close(m_listenSocket);
754 m_initialised = false;
755
756 m_shouldStop.test_and_set();
757 if (m_serverThread && m_serverThread->joinable())
758 {
759 m_serverThread->join();
760 m_serverThread.reset();
761 }
762}
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 655 of file TelnetServer.cpp.

656{
657 spdlog::info("Telnet server started");
658 while (!m_shouldStop._M_i)
659 {
660 try
661 {
662 update();
663 if (m_checkFlag)
664 {
665 m_checkFlag->test_and_set();
666 }
667 }
668 catch (const std::exception &e)
669 {
670 spdlog::error("Telnet server failed: {}", e.what());
671 }
672 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_INTERVAL_MS));
673 }
674 spdlog::info("Telnet server stopped");
675}
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 677 of file TelnetServer.cpp.

678{
679 // See if connection pending on the listening socket
680 fd_set readSet;
681 FD_ZERO(&readSet);
682 FD_SET(m_listenSocket, &readSet);
683 timeval timeout{};
684 timeout.tv_sec = 0; // Zero timeout (poll)
685 timeout.tv_usec = 0;
686
687 bool newConnectionAccept = false;
688 bool newConnectionRefused = false;
689
690 TelnetServerStats serverStats;
691 serverStats.processingTimeStart = std::chrono::high_resolution_clock::now();
692
693 // If there is a connection pending, accept it.
694 if (select(m_listenSocket + 1, &readSet, nullptr, nullptr, &timeout) > 0)
695 {
696 if (acceptConnection())
697 {
698 newConnectionAccept = true;
699 }
700 else
701 {
702 newConnectionRefused = true;
703 }
704 }
705
706 // Update all the telnet Sessions that are currently in flight.
707 for (size_t idx = 0; idx < m_sessions.size(); ++idx)
708 {
709 // Update session
710 m_sessions[idx]->update();
711
712 // Close session if needed
713 if (m_sessions[idx]->checkTimeout())
714 {
715 m_sessions[idx]->closeClient();
716 if (m_stats)
717 {
718 m_stats->consumeStats(m_sessions[idx]->stats, true);
719 }
720 m_sessions.erase(m_sessions.begin() + static_cast<int>(idx));
721 --idx;
722 }
723 else
724 {
725 if (m_stats)
726 {
727 m_stats->consumeStats(m_sessions[idx]->stats, false);
728 }
729 }
730 }
731
732 serverStats.activeConnectionCtr = m_sessions.size();
733 serverStats.acceptedConnectionCtr = static_cast<uint64_t>(newConnectionAccept);
734 serverStats.refusedConnectionCtr = static_cast<uint64_t>(newConnectionRefused);
735 serverStats.processingTimeEnd = std::chrono::high_resolution_clock::now();
736 if (m_stats)
737 {
738 m_stats->consumeStats(serverStats);
739 }
740}
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: