PdCom  5.3
Process data communication client
gnutls_example.cpp

Process implementation for TLS encrypted traffic.Please note that gnutls has some internal buffering, so please do not do some buffering on your own and also do not rely on flush(). Just write directly to the socket, as in PosixProcess::posixWriteDirect().

/*****************************************************************************
* vim:tw=78
*
* Copyright (C) 2021 Bjarne von Horn (vh at igh dot de).
*
* This file is part of the PdCom library.
*
* The PdCom library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* The PdCom library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the PdCom library. If not, see <http://www.gnu.org/licenses/>.
*
*****************************************************************************/
/* PdCom example with TLS encryption.
*
* This example shows how to set up a PdCom::Process instance with the help
* of SecureProcess and PosixProcess.
* A running tls-enabled pdserv instance is needed, it should listen to port
* 4523.
* After the client application connects, it will list all available variables
* (signals and parameters) on the server and exit.
*
*/
#include <fstream>
#include <iostream>
#include <poll.h>
class MyProcess : public PdCom::SecureProcess, private PdCom::PosixProcess
{
// pass data between SecureProcess and PosixProcess
int read(char *buf, int count) override { return posixRead(buf, count); }
void write(const char *buf, size_t count) override
{
posixWriteDirect(buf, count);
}
void listReply(
std::vector<PdCom::Variable> vars /* variables */,
std::vector<std::string> /* directories */) override
{
// we want to enumerate all found variables
for (const auto &v : vars)
std::cout << "Found var " << v.getPath() << "\n";
running_ = false;
}
void connected() override
{
// connection is established, we're now allowed to start interacting
// with the server.
std::cout << "Connected!" << std::endl;
list("");
}
public:
void waitForSocket()
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd_, &fds);
select(fd_ + 1, &fds, NULL, NULL, NULL);
}
MyProcess(const std::string &ca_pem, const char *host = "localhost") :
PdCom::SecureProcess({EncryptionDetails::Default, ca_pem, host}),
PdCom::PosixProcess(host, 4523)
{
// start TLS session
do {
std::cerr << "Handshaking\n";
} while (!handshake());
}
bool running_ = true;
};
int main(int argc, char *argv[])
{
if (argc < 3) {
std::cerr << "Usage: " << argv[0] << " <hostname> <Path to CA.pem>\n";
return -1;
}
// initializing GnuTls
// read CA file
std::ifstream ca_file(argv[2]);
std::string ca;
getline(ca_file, ca, '\0');
// creating Process instance
MyProcess p(ca, argv[1]);
// process incoming data until work is done
while (p.running_) {
// wait until socket is readable
p.waitForSocket();
// ask PdCom to process incoming data
p.asyncData();
}
// close TLS session
p.bye();
return 0;
}