Many smaller networking code fixes

A number of smaller networking code fixes have been applied to both the
Async code and the Echolib code.
This commit is contained in:
Tobias Blomberg 2022-04-12 12:57:52 +02:00
parent 1114ac3cec
commit 6345dad203
16 changed files with 137 additions and 119 deletions

View File

@ -52,13 +52,16 @@
VARNAME=88.5:-1,136.5:1. It is also possible to use other key/value
separators.
* New class Async::StateMachine used to build Hierarchial Finate State
* New class Async::StateMachine used to build Hierarchical Finite State
Machines.
* New class Async::TcpPrioClient for handling pools of servers to connect to.
The pool members can be specified using DNS SRV records or locally using the
HOSTS configuration variable.
* Slightly changed semantics of the TcpClient::connect functions. It's now
not allowed to call the connect function if already connected.
1.6.0 -- 01 Sep 2019

View File

@ -127,6 +127,8 @@ FramedTcpConnection::FramedTcpConnection(
: TcpConnection(sock, remote_addr, remote_port, recv_buf_len),
m_max_frame_size(DEFAULT_MAX_FRAME_SIZE), m_size_received(false)
{
TcpConnection::sendBufferFull.connect(
sigc::mem_fun(*this, &FramedTcpConnection::onSendBufferFull));
} /* FramedTcpConnection::FramedTcpConnection */
@ -221,7 +223,6 @@ int FramedTcpConnection::write(const void *buf, int count)
void FramedTcpConnection::closeConnection(void)
{
//cout << "### FramedTcpConnection::closeConnection\n";
disconnectCleanup();
TcpConnection::closeConnection();
} /* FramedTcpConnection::closeConnection */
@ -229,11 +230,8 @@ void FramedTcpConnection::closeConnection(void)
void FramedTcpConnection::onDisconnected(DisconnectReason reason)
{
//cout << "### FramedTcpConnection::onDisconnected: "
// << TcpConnection::disconnectReasonStr(reason) << "\n";
disconnectCleanup();
TcpConnection::onDisconnected(reason);
disconnected(this, reason);
} /* FramedTcpConnection::onDisconnected */
@ -257,7 +255,7 @@ int FramedTcpConnection::onDataReceived(void *buf, int count)
if (m_frame_size > m_max_frame_size)
{
closeConnection();
disconnected(this, DR_PROTOCOL_ERROR);
onDisconnected(DR_PROTOCOL_ERROR);
return orig_count - count;
}
m_frame.clear();

View File

@ -206,7 +206,7 @@ class FramedTcpConnection : public TcpConnection
std::vector<uint8_t>&> frameReceived;
protected:
sigc::signal<int, FramedTcpConnection *, void *, int> dataReceived;
sigc::signal<int, TcpConnection*, void*, int> dataReceived;
sigc::signal<void, bool> sendBufferFull;
/**
@ -242,10 +242,14 @@ class FramedTcpConnection : public TcpConnection
*/
virtual int onDataReceived(void *buf, int count) override;
/**
* @brief Emit the disconnected signal
* @param reason The reason for the disconnection
*/
virtual void emitDisconnected(DisconnectReason reason) override
{
TcpConnection::emitDisconnected(reason);
disconnected(this, reason);
TcpConnection::emitDisconnected(reason);
}
private:

View File

@ -127,6 +127,8 @@ HttpServerConnection::HttpServerConnection(
: TcpConnection(sock, remote_addr, remote_port, recv_buf_len),
m_state(STATE_EXPECT_START_LINE), m_chunked(false)
{
TcpConnection::sendBufferFull.connect(
sigc::mem_fun(*this, &HttpServerConnection::onSendBufferFull));
} /* HttpServerConnection::HttpServerConnection */
@ -203,10 +205,9 @@ bool HttpServerConnection::write(const Response& res)
{
std::ostringstream os;
os << "HTTP/1.1 " << res.code() << " " << codeToString(res.code()) << "\r\n";
for (std::map<std::string, std::string>::const_iterator it=res.headers().begin();
it!=res.headers().end(); ++it)
for (const auto& header : res.headers())
{
os << (*it).first << ": " << (*it).second << "\r\n";
os << header.first << ": " << header.second << "\r\n";
}
if (m_chunked)
{
@ -256,7 +257,6 @@ bool HttpServerConnection::write(const char* buf, int len)
void HttpServerConnection::closeConnection(void)
{
//std::cout << "### HttpServerConnection::closeConnection" << std::endl;
disconnectCleanup();
TcpConnection::closeConnection();
} /* HttpServerConnection::closeConnection */
@ -264,10 +264,8 @@ void HttpServerConnection::closeConnection(void)
void HttpServerConnection::onDisconnected(DisconnectReason reason)
{
//cout << "### HttpServerConnection::onDisconnected: "
// << TcpConnection::disconnectReasonStr(reason) << "\n";
disconnectCleanup();
disconnected(this, reason);
TcpConnection::onDisconnected(reason);
} /* HttpServerConnection::onDisconnected */

View File

@ -323,10 +323,14 @@ class HttpServerConnection : public TcpConnection
*/
virtual int onDataReceived(void *buf, int count) override;
/**
* @brief Emit the disconnected signal
* @param reason The reason for the disconnection
*/
virtual void emitDisconnected(DisconnectReason reason) override
{
TcpConnection::emitDisconnected(reason);
disconnected(this, reason);
TcpConnection::emitDisconnected(reason);
}
private:

View File

@ -190,7 +190,7 @@ class TcpClient : public ConT, public TcpClientBase
* disconnected, nothing will be done. The disconnected signal is not
* emitted when this function is called
*/
virtual void disconnect(void) { closeConnection(); }
virtual void disconnect(void) override { closeConnection(); }
/**
* @brief Check if the connection is idle
@ -210,7 +210,7 @@ class TcpClient : public ConT, public TcpClientBase
* This function is used internally to close the connection to the remote
* peer.
*/
virtual void closeConnection(void)
virtual void closeConnection(void) override
{
ConT::closeConnection();
TcpClientBase::closeConnection();

View File

@ -135,13 +135,16 @@ TcpClientBase::TcpClientBase(TcpConnection *con)
TcpClientBase::TcpClientBase(TcpConnection *con, const string& remote_host,
uint16_t remote_port)
: con(con), remote_host(remote_host), sock(-1)
: con(con), sock(-1)
{
IpAddress ip_addr(remote_host);
if (!ip_addr.isEmpty())
{
con->setRemoteAddr(ip_addr);
this->remote_host = ip_addr.toString();
}
else
{
dns.setLookupParams(remote_host);
}
con->setRemotePort(remote_port);
wr_watch.activity.connect(mem_fun(*this, &TcpClientBase::connectHandler));
@ -151,7 +154,7 @@ TcpClientBase::TcpClientBase(TcpConnection *con, const string& remote_host,
TcpClientBase::TcpClientBase(TcpConnection *con, const IpAddress& remote_ip,
uint16_t remote_port)
: con(con), remote_host(remote_ip.toString()), sock(-1)
: con(con), sock(-1)
{
con->setRemoteAddr(remote_ip);
con->setRemotePort(remote_port);
@ -173,9 +176,6 @@ TcpClientBase& TcpClientBase::operator=(TcpClientBase&& other)
dns = std::move(other.dns);
remote_host = other.remote_host;
other.remote_host.clear();
sock = other.sock;
other.sock = -1;
@ -196,12 +196,17 @@ void TcpClientBase::setBindIp(const IpAddress& bind_ip)
void TcpClientBase::connect(const string &remote_host, uint16_t remote_port)
{
this->remote_host = remote_host;
assert(isIdle() && con->isIdle());
IpAddress ip_addr(remote_host);
if (!ip_addr.isEmpty())
{
con->setRemoteAddr(ip_addr);
this->remote_host = ip_addr.toString();
dns.setLookupParams("");
}
else
{
dns.setLookupParams(remote_host);
}
con->setRemotePort(remote_port);
connect();
@ -210,33 +215,22 @@ void TcpClientBase::connect(const string &remote_host, uint16_t remote_port)
void TcpClientBase::connect(const IpAddress& remote_ip, uint16_t remote_port)
{
assert(isIdle() && con->isIdle());
con->setRemoteAddr(remote_ip);
remote_host = remote_ip.toString();
con->setRemotePort(remote_port);
dns.setLookupParams("");
connect();
} /* TcpClientBase::connect */
void TcpClientBase::connect(void)
{
//std::cout << "### TcpClientBase::connect:"
// << " dns.isPending()=" << dns.isPending()
// << " sock=" << sock
// << " con->socket()=" << con->socket()
// << std::endl;
assert(isIdle() && con->isIdle());
// Do nothing if DNS lookup is pending, connection is pending or if the
// connection is already established
if (dns.isPending() || (sock != -1) || (con->socket() != -1))
if (!dns.label().empty())
{
return;
}
if (con->remoteHost().isEmpty() ||
(remote_host != con->remoteHost().toString()))
{
assert(!remote_host.empty());
dns.lookup(remote_host);
dns.lookup();
}
else
{
@ -245,6 +239,13 @@ void TcpClientBase::connect(void)
} /* TcpClientBase::connect */
/****************************************************************************
*
* Protected member functions
*
****************************************************************************/
void TcpClientBase::closeConnection(void)
{
wr_watch.setEnabled(false);
@ -260,14 +261,6 @@ void TcpClientBase::closeConnection(void)
/****************************************************************************
*
* Protected member functions
*
****************************************************************************/
/****************************************************************************
*
* Private member functions
@ -276,26 +269,27 @@ void TcpClientBase::closeConnection(void)
void TcpClientBase::dnsResultsReady(DnsLookup& dns_lookup)
{
//std::cout << "### TcpClientBase::dnsResultsReady" << std::endl;
vector<IpAddress> result = dns.addresses();
if (result.empty() || result[0].isEmpty())
for (const auto& addr : dns.addresses())
{
closeConnection();
con->onDisconnected(TcpConnection::DR_HOST_NOT_FOUND);
return;
if (!addr.isEmpty())
{
con->setRemoteAddr(addr);
connectToRemote();
return;
}
}
con->setRemoteAddr(result[0]);
connectToRemote();
closeConnection();
con->onDisconnected(TcpConnection::DR_HOST_NOT_FOUND);
} /* TcpClientBase::dnsResultsReady */
void TcpClientBase::connectToRemote(void)
{
assert(sock == -1);
assert(!con->remoteHost().isEmpty());
assert(con->remotePort() > 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;

View File

@ -176,9 +176,17 @@ class TcpClientBase : virtual public sigc::trackable
* @return Returns the name of the remote host
*
* This function return the name of the remote host as it was given to the
* connect call.
* connect call. If an IP address was used the text representation of that
* will be returned.
*/
const std::string& remoteHostName(void) const { return remote_host; }
std::string remoteHostName(void) const
{
if (!dns.label().empty())
{
return dns.label();
}
return con->remoteHost().toString();
}
/**
* @brief Bind to the interface having the specified IP address
@ -200,7 +208,7 @@ class TcpClientBase : virtual public sigc::trackable
* This function will initiate a connection to the remote host. The
* connection must not be written to before the connected signal
* (see @ref TcpClient::connected) has been emitted. If the connection is
* already established or pending, nothing will be done.
* already established or pending, an assertion will be raised.
*/
void connect(const std::string &remote_host, uint16_t remote_port);
@ -212,7 +220,7 @@ class TcpClientBase : virtual public sigc::trackable
* This function will initiate a connection to the remote host. The
* connection must not be written to before the connected signal
* (see @ref TcpClient::connected) has been emitted. If the connection is
* already established or pending, nothing will be done.
* already established or pending, an assertion will be raised.
*/
void connect(const Async::IpAddress& remote_ip, uint16_t remote_port);
@ -222,7 +230,7 @@ class TcpClientBase : virtual public sigc::trackable
* This function will initiate a connection to the remote host. The
* connection must not be written to before the connected signal
* (see @ref TcpClient::connected) has been emitted. If the connection is
* already established or pending, nothing will be done.
* already established or pending, an assertion will be raised.
*/
void connect(void);
@ -241,8 +249,12 @@ class TcpClientBase : virtual public sigc::trackable
*
* A connection being idle means that it is not connected nor connecting.
*/
bool isIdle(void) const { return (sock == -1); }
bool isIdle(void) const { return !dns.isPending() && (sock == -1); }
/**
* @brief Return the connection object for this client connection
* @return Returns the connection object
*/
TcpConnection* conObj(void) { return con; }
/**
@ -279,7 +291,6 @@ class TcpClientBase : virtual public sigc::trackable
private:
TcpConnection * con;
DnsLookup dns;
std::string remote_host;
int sock;
FdWatch wr_watch;
Async::IpAddress bind_ip;

View File

@ -235,7 +235,6 @@ class TcpConnection : virtual public sigc::trackable
* @return Returns \em true if the connection is idle
*
* A connection being idle means that it is not connected
* NOTE: This function is overridden in Async::TcpClient.
*/
bool isIdle(void) const { return sock == -1; }
@ -321,8 +320,7 @@ class TcpConnection : virtual public sigc::trackable
*/
virtual void onDisconnected(DisconnectReason reason)
{
//std::cout << "### TcpConnection::onDisconnected" << std::endl;
disconnected(this, reason);
emitDisconnected(reason);
}
/**
@ -344,6 +342,10 @@ class TcpConnection : virtual public sigc::trackable
return dataReceived(this, buf, count);
}
/**
* @brief Emit the disconnected signal
* @param reason The reason for the disconnection
*/
virtual void emitDisconnected(DisconnectReason reason)
{
disconnected(this, reason);

View File

@ -269,7 +269,8 @@ class TcpPrioClientBase::Machine
void emitConnected(void)
{
client->emitConnected();
//client->emitConnected();
client->TcpClientBase::connectionEstablished();
}
bool isIdle(void) const
@ -277,7 +278,7 @@ class TcpPrioClientBase::Machine
return client->isIdle();
}
const std::string& remoteHostName(void) const
std::string remoteHostName(void) const
{
return client->remoteHostName();
}

View File

@ -312,7 +312,7 @@ class TcpPrioClientBase : public TcpClientBase
* when a connection has been established. The overriding function should
* normally call this function.
*/
virtual void connectionEstablished(void);
virtual void connectionEstablished(void) override;
/**
* @brief Called when a connection has been terminated

View File

@ -6,7 +6,7 @@
\verbatim
Async - A library for programming event driven applications
Copyright (C) 2003-2014 Tobias Blomberg / SM0SVX
Copyright (C) 2003-2022 Tobias Blomberg / SM0SVX
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -36,8 +36,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <iostream>
#include <arpa/inet.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cassert>
@ -50,7 +52,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include <AsyncFdWatch.h>
#include <AsyncApplication.h>
#include <AsyncFramedTcpConnection.h>
/****************************************************************************
@ -95,9 +96,6 @@ using namespace Async;
*
****************************************************************************/
namespace {
void delete_connection(TcpConnection *con);
};
/****************************************************************************
@ -108,7 +106,6 @@ void delete_connection(TcpConnection *con);
/****************************************************************************
*
* Local Global Variables
@ -305,7 +302,7 @@ void TcpServerBase::removeConnection(TcpConnection *con)
it = find(tcpConnectionList.begin(), tcpConnectionList.end(), con);
assert(it != tcpConnectionList.end());
tcpConnectionList.erase(it);
Application::app().runTask(sigc::bind(sigc::ptr_fun(&delete_connection), con));
Application::app().runTask([=]{ delete con; });
} /* TcpServerBase::onDisconnected */
@ -381,11 +378,6 @@ void TcpServerBase::onConnection(FdWatch *watch)
} /* TcpServerBase::onConnection */
namespace {
void delete_connection(TcpConnection *con) { delete con; }
};
/*
* This file has not been truncated
*/

View File

@ -2,7 +2,6 @@
#include <AsyncCppApplication.h>
#include <AsyncTcpClient.h>
using namespace std;
using namespace Async;
class MyClass : public sigc::trackable
@ -10,38 +9,41 @@ class MyClass : public sigc::trackable
public:
MyClass(void)
{
con = new TcpClient<>("www.linux.org", 80);
con->connected.connect(mem_fun(*this, &MyClass::onConnected));
con->disconnected.connect(mem_fun(*this, &MyClass::onDisconnected));
con->dataReceived.connect(mem_fun(*this, &MyClass::onDataReceived));
con->connect();
}
~MyClass(void)
{
delete con;
con.connected.connect(mem_fun(*this, &MyClass::onConnected));
con.disconnected.connect(mem_fun(*this, &MyClass::onDisconnected));
con.dataReceived.connect(mem_fun(*this, &MyClass::onDataReceived));
con.connect("www.svxlink.org", 80);
}
private:
TcpClient<>* con;
TcpClient<> con;
void onConnected(void)
{
cout << "Connection established to " << con->remoteHost() << "...\n";
con->write("GET /\n", 6);
std::cout << "--- Connection established to " << con.remoteHost()
<< std::endl;
std::string req(
"GET / HTTP/1.0\r\n"
"Host: " + con.remoteHostName() + "\r\n"
"\r\n");
std::cout << "--- Sending request:\n" << req << std::endl;
con.write(req.data(), req.size());
}
void onDisconnected(TcpConnection *con, TcpClient<>::DisconnectReason reason)
void onDisconnected(TcpConnection *, TcpClient<>::DisconnectReason reason)
{
cout << "Disconnected from " << con->remoteHost() << "...\n";
std::cout << "--- Disconnected from " << con.remoteHost() << ": "
<< TcpConnection::disconnectReasonStr(reason)
<< std::endl;
Application::app().quit();
}
int onDataReceived(TcpConnection *con, void *buf, int count)
int onDataReceived(TcpConnection *, void *buf, int count)
{
char *str = static_cast<char *>(buf);
string html(str, str+count);
cout << html;
std::cout << "--- Data received:" << std::endl;
const char *str = static_cast<char *>(buf);
std::string html(str, str+count);
std::cout << html;
return count;
}
};

View File

@ -1,3 +1,12 @@
1.3.4 -- ?? ??? ????
----------------------
* Replace potentially dangerous function call 'localtime' with 'localtime_r'.
* Smaller adaptions to new networking code in Async.
1.3.3 -- 30 Dec 2017
----------------------

View File

@ -218,7 +218,7 @@ bool DirectoryCon::isIdle(void) const
Proxy *proxy = Proxy::instance();
if (proxy == 0)
{
return is_ready && !client->isConnected();
return is_ready && client->isIdle();
}
else
{

View File

@ -5,16 +5,16 @@ PROJECT=master
QTEL=1.2.4.99.5
# Version for the EchoLib library
LIBECHOLIB=1.3.3.99.1
LIBECHOLIB=1.3.3.99.2
# Version for the Async library
LIBASYNC=1.6.99.19
LIBASYNC=1.6.99.20
# SvxLink versions
SVXLINK=1.7.99.64
SVXLINK=1.7.99.65
MODULE_HELP=1.0.0
MODULE_PARROT=1.1.1
MODULE_ECHO_LINK=1.5.99.2
MODULE_ECHO_LINK=1.5.99.3
MODULE_TCL=1.0.1
MODULE_PROPAGATION_MONITOR=1.0.1
MODULE_TCL_VOICE_MAIL=1.0.2
@ -25,7 +25,7 @@ MODULE_FRN=1.1.0
MODULE_TRX=1.0.0
# Version for the RemoteTrx application
REMOTE_TRX=1.3.99.8
REMOTE_TRX=1.3.99.9
# Version for the signal level calibration utility
SIGLEV_DET_CAL=1.0.7.99.5
@ -37,4 +37,4 @@ DEVCAL=1.0.2.99.6
SVXSERVER=0.0.6
# Version for SvxReflector
SVXREFLECTOR=1.99.14
SVXREFLECTOR=1.99.15