Using pipes in Boost unit tests - c++

I'm trying to write Boost unit tests for my server.
I want to launch my server - start() launches the server in a thread - open a client, connect it and try to download a file.
I'm doing this this way:
tftp_server* my_test_server;
BOOST_AUTO_TEST_SUITE (tftptest) // name of the test suite is tftptest
BOOST_AUTO_TEST_CASE (test1)
{
my_test_server = new tftp_server(69);
my_test_server->start();
FILE *in;
char buff[512];
if(!(in = popen("tftp", "w"))){
exit(1);
}
fputs ( "connect xx.xx.xx.xx\n", in );
fputs ( "mode binary\n", in );
fputs ( "mode\n", in );
fputs ( "get truc.txt\n", in );
while(fgets(buff, sizeof(buff), in)!=NULL)
printf("%s", buff);
sleep(10);
BOOST_CHECK(true);
}
1) Creating and launching the server,
2) using the system TFTP client (I'm on OSX),
3) waiting 10 seconds.
It doesn't work : It only executes the client after the test is done.
Running 1 test case...
Server started on port 69
Server running.
*** No errors detected
$ Using octet mode to transfer files.
Transfer timed out.
Any idea how I could solve my problem ?
Thanks !
EDIT
void tftp_server::start()
{
LOG_INFO("Server running.", 0);
boost::thread bt(boost::bind(&boost::asio::io_service::run, &_io_service));
}

I've added close, and it works.
Thanks to Arne Mertz.
if(!(in = popen("tftp", "w"))){
exit(1);
}
//...
while(fgets(buff, sizeof(buff), in)!=NULL)
printf("%s", buff);
pclose(in);

Related

QSerialPort is in use before application starts

I am developing an application for Apalis iMX6 with Qt C++ in Linux and I've added this application into the startup by means of profile.d
this code must set ttymxc1 into RS485 mode like below:
int enableRS485(){
struct serial_rs485 rs485conf;
int fd = open ("/dev/ttymxc1", O_RDWR);
if (fd < 0) {
printf("Error: Can't open: /dev/ttymxc1 %d\n",fd);
return fd;
}
rs485conf.flags |= SER_RS485_ENABLED;
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
rs485conf.flags |= SER_RS485_RX_DURING_TX;
err = ioctl (fd, TIOCSRS485, &rs485conf);
if (err < 0) {
printf("Error: TIOCSRS485 ioctl not supported.\n");
return err;
}
err = close (fd);
if (err < 0) {
printf("Error: Can't close: /dev/ttyLP1 %d\n",err);
return err;
}
return 0;
}
this function is working as well and has no problem. but when I try to open the serial port sometimes during startup application couldn't get this serial port and QSerialPortInfo shows me ttymxc1 is in use. my initiation of the serial port is like below:
void SerialClass::initSerial()
{
m_serialPort = new QSerialPort();
enableRS485();
sleep(1);
m_serialPort->setPortName("/dev/ttymxc1");
m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
m_serialPort->setBaudRate(9600);
m_serialPort->setRequestToSend(false);
bool res = m_serialPort->open(QIODevice::ReadWrite);
}
"QSerialPort::errorOccured" signal will emit with value "PermissionError"
but mysteriously "ls -l /proc/[0-9]/fd/ |grep /dev/ttymxc1" shows me ttymxc1 is in used by my application.
there is no application that works with serial port and my application is just for one time run.
Is there any idea?
Thanks
You need to call close() on m_serialPort when you close your application. Otherwise your serial port will keep in-use state.
I've found a new remedy, so I want to share it here.
in SerialClass constructor I've added initSerial(), in this way application at the beginning of starting, will open the ttymxc1.
There is no more problem with such a solution.
I don't have such an issue with Raspberry Pi (Raspberry Pi3 + Qt 5.6 + Raspbian). But Toradex Apalis is in another way.
Would you please tell me why?

Simplest IPC from one Linux app to another in C++ on raspberry pi

I need the simplest most reliable IPC method from one C++ app running on the RPi to another app.
All I'm trying to do is send a string message of 40 characters from one app to another
The first app is running as a service on boot, the other app is started at a later time and is frequently exited and restarted for debugging
The frequent debugging for the second app is whats causing problems with the IPCs I've tried so far
I've tried about 3 different methods and here is where they failed:
File FIFO, the problem is one program hangs while the other program is writing to the file
Shared memory: cannot initialize on one thread and read from another thread. Also frequent exiting while debugging causing GDB crashes with the following GDB command is taking too long to complete -stack-list-frames --thread 1
UDP socket with localhost - same issue as above, plus improper exits block the socket, forcing me to reboot device
Non blocking pipe - not getting any messages on the receiving process
What else can I try? I dont want to get the DBus library, seems too complex for this application.
Any simple server and client code or a link to it would be helpful
Here is my non-blockign pipe code, that doesnt work for me,
I assume its because I dont have a reference to the pipe from one app to the other
Code sourced from here: https://www.geeksforgeeks.org/non-blocking-io-with-pipes-in-c/
char* msg1 = "hello";
char* msg2 = "bye !!";
int p[2], i;
bool InitClient()
{
// error checking for pipe
if(pipe(p) < 0)
exit(1);
// error checking for fcntl
if(fcntl(p[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
//Read
int nread;
char buf[MSGSIZE];
// write link
close(p[1]);
while (1) {
// read call if return -1 then pipe is
// empty because of fcntl
nread = read(p[0], buf, MSGSIZE);
switch (nread) {
case -1:
// case -1 means pipe is empty and errono
// set EAGAIN
if(errno == EAGAIN) {
printf("(pipe empty)\n");
sleep(1);
break;
}
default:
// text read
// by default return no. of bytes
// which read call read at that time
printf("MSG = % s\n", buf);
}
}
return true;
}
bool InitServer()
{
// error checking for pipe
if(pipe(p) < 0)
exit(1);
// error checking for fcntl
if(fcntl(p[0], F_SETFL, O_NONBLOCK) < 0)
exit(2);
//Write
// read link
close(p[0]);
// write 3 times "hello" in 3 second interval
for(i = 0 ; i < 3000000000 ; i++) {
write(p[0], msg1, MSGSIZE);
sleep(3);
}
// write "bye" one times
write(p[0], msg2, MSGSIZE);
return true;
}
Please consider ZeroMQ
https://zeromq.org/
It is lightweight and has wrapper for all major programming languages.

Server Fails on Openssl Initialization

I am working on a win32 file server that was coded using Visual Studio 6.0. It had SSL configured and working back in 2000, but hasn't been used since.
Now, we want to use SSL (Opensll), so I've updated the libraries, etc and have the server working with SSLv3 and TLS when the server is run as a console app.
As soon as I run the server as a windows service, the ssl initialization routine crashes without any error messages. Here is the code that is causing all of the grief.
int SwiftSSL::Initialize()
{
SSLeay_add_ssl_algorithms();
SSL_load_error_strings();
ctx_ = SSL_CTX_new( SSLv23_server_method() );
if(!ctx_) {
LogEvent( "SSL_CTX is bad.");
return false;
}
LogEvent( "Before using cert and private key file.");
if ( SSL_CTX_use_certificate_file( ctx_, CERT_FILE, SSL_FILETYPE_PEM ) == 1 ) {
LogEvent( "SUCCESS SSL_CTX_use_certificate_file." );
}
else {
LogEvent( "FAILED SSL_CTX_use_certificate_file." );
return false;
}
if ( SSL_CTX_use_PrivateKey_file( ctx_, KEY_FILE, SSL_FILETYPE_PEM ) == 0 ) {
LogEvent( "Failed SSL_CTX_use_PrivateKey_file." );
return false;
}
else {
LogEvent( "SUCCESSFUL SSL_CTX_use_PrivateKey_file." );
}
if ( SSL_CTX_check_private_key( ctx_ ) == 0 ) {
ERR_print_errors_fp( stderr );
LogEvent( "Failed SSL_CTX_check_private_key" );
return false;
}
LogEvent( "Successfully used cert and private key file.");
return true;
}
When run as a Windows Service, the only message logged is:
"Before using cert and private key file."
Nothing else is logged. That, to me, means that the command
SSL_CTX_use_certificate_file( ctx_, CERT_FILE, SSL_FILETYPE_PEM ) is crashing.
But why would it work with no issues when the same program is run as a console?
This is the information that I found in event viewer:
The description for Event ID ( 0 ) in Source ( OPENSSL ) cannot be found. The
local computer may not have the necessary registry information or message DLL
files to display messages from a remote computer. The following information is
part of the event: OPENSSL_Uplink(00341000,08): no OPENSSL_Applink
Any help will be appreciated.
Ok. I woke up this morning with the solution to this situation. As it turns out, the Windows Service did not know where to find the CERT_FILE or the KEY_FILE. Apps running as a Windows Service will look for files in the %WinDir%\System32 directory. I have the files in the app directory, so I simply had to add the actual path to the files when calling SSL_CTX_use_certificate_file and SSL_CTX_use_PrivateKey_file.
It now works fine.

exec functions not working from linux daemon

I have been writing a linux daemon which listens on TCP/IP for a request and launches an application on receiving that request. My problem is when I run this daemon from command prompt or IDE (eclipse 3.7) everything works fine and my executable launches. But when i use
sudo service <myservicename> start
It will receive request on socket but its not launching that executable.
here is the standard code I am using for daemonizing the process
/// Linux Daemon related stuff
/// Create the lock file as the current user
int lfp = open( "/var/lock/subsys/LauncherService", O_RDWR|O_CREAT, 0640);
if ( lfp < 0 )
{
LOG_ERROR ("Unable to open lockfile");
LOG_ERROR ( strerror(errno) );
}
/// All
/// Our process ID and Session ID
pid_t pid, sid;
/// Fork off the parent process
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/// If we got a good PID, then
/// we can exit the parent process.
if (pid > 0)
{
exit(EXIT_SUCCESS);
}
/// Change the file mode mask
umask(0);
/// Create a new SID for the child process
sid = setsid();
if (sid < 0)
{
LOG_ERROR ("Error Setting sid");
exit(EXIT_FAILURE);
}
LOG_INFO ("sid set");
/// Change the current working directory
if ( (chdir("/usr/local/<mylocaldir>/bin")) < 0 )
{
LOG_ERROR ("Error changing Directory");
exit(EXIT_FAILURE);
}
LOG_INFO ("chdir successful");
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
here is function in which i am launching my binary which needs to be launched. This function is called in forked child process.
std::string configFile = "/usr/local/<mydir>/config/Settings.config";
std::string binary = "<binaryname>";
std::string path ="/usr/local/<mydir>/bin/<binaryname>";
//char *argv[] = { "<binaryname>", "/usr/local/<mydir>/config/Settings.config", (char *)0 };
LOG_INFO("Calling Process" );
if ( execlp( path.c_str(), binary.c_str(), configFile.c_str(), (char *)0 ) == -1 )
//if ( execv("/usr/local/<mydir>/bin/<binaryname>", argv) == -1 )
//if ( execvp("/usr/local/<mydir>/bin/<binaryname>", argv) == -1 )
{
LOG_ERROR("System call failed !!")
std::string errString = strerror(errno);
LOG_ERROR (errString );
}
else
{
LOG_INFO("System call successful");
}
So after discussion with Casey I investigated more into my called program and I found that my program indeed is getting called. Also I found out that environment variables are not the issue child process is taking environment from parent itself. I am creating QApplication (qt gui application) in my main program. Its some issue with that and linux system daemon. I will try to figure that out and will ask separate question if needed.
Edit: Final Solution
It was a qt GUI application which was not able to connect to XServer. I had to changes suggested by Casey and given in this post
Cannot connect to X server :0.0 with a Qt application
after that it started launching.

Redirect bash stdin and stdout in c++

I need help to get the following to work. I need to start a bash process from c++, this bash process needs to accept input from stdin and output as per normal it's output to stdout.
From a different process I need to write commands to stdin which will then actually execute in bash as per above, then I'm interested in the result from stdout.
This is what I've tried so far, but the output does not make sense to me at all...
if (pipe(pipeBashShell)) {
fprintf(stderr, "Pipe error!\n");
exit(1);
}
if ((pipePId = fork()) == -1) {
fprintf(stderr, "Fork error. Exiting.\n"); /* something went wrong */
exit(1);
}
if (pipePId == 0) { //this is the child process
dup2(pipeBashShell[0], STDIN_FILENO);
dup2(pipeBashShell[1], STDOUT_FILENO);
dup2(pipeBashShell[1], STDERR_FILENO);
static char* bash[] = {"/bin/bash", "-i", NULL};
if (execv(*bash, bash) == -1) {
fprintf(stderr, "execv Error!");
exit(1);
}
exit(0);
} else {
char buf[512];
memset(buf, 0x00, sizeof(buf));
sprintf(buf, "ls\n");
int byteswritten = write(pipeBashShell[1], buf, strlen(buf));
int bytesRead = read(pipeBashShell[0], buf, sizeof(buf));
write(STDOUT_FILENO, buf, strlen(buf));
exit(0);
}
.
The output of the result above is as follows:
' (main)
bash:: command not found gerhard#gerhard-work-pc:~/workspaces/si/si$ gerhard
orkspaces/si/si$ gerhard# gerhard-work-pc:~/workspa
....
The command i'm trying to send to bash is "ls", which should give me a directory listing
Am I missing something here?
You have created one pipe (with two ends) and you are trying to use it for bi-directional communication -- from your main process to bash and vice versa. You need two separate pipes for that.
The way you have connected the file descriptors makes bash talk to itself -- it interprets its prompt as a command which it cannot find, and then interprets the error messages as subsequend commands.
Edit:
The correct setup works as follows:
prepare two pipes:
int parent2child[2], child2parent[2];
pipe(parent2child);
pipe(child2parent);
fork()
in the parent process:
close(parent2child[0]);
close(child2parent[1]);
// write to parent2child[1], read from child2parent[0]
in the child process:
close(parent2child[1]);
close(child2parent[0]);
dup2(parent2child[0], STDIN_FILENO);
dup2(child2parent[1], STDOUT_FILENO);