C++: Calling sendmail from pthread results in Broken Pipe - c++

I'm trying to send an e-mail with sendmail in a separate pthread. This code works 99.9% of the time.
void* emailClientThreadFct(void* emailClientPtr)
{
EmailClient* emailClient = static_cast<EmailClient*>(emailClientPtr);
try
{
emailClient->Send();
}
catch (const exception& excep)
{
SYSLOG_ERROR("E-mail client exception: %s", excep.what());
}
delete emailClient;
return NULL;
}
// Send email for current output in a separate thread
pthread_t emailThread;
pthread_attr_t attr;
/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&emailThread, &attr, emailClientThreadFct, emailClientObj);
0.1% of the time, I get the error fwrite error Broken Pipe when I do the following call. From what I read, Broken Pipe (EPIPE 32) is usually a receiver problem, but sendmail is a local process... Could it be that I'm sending too much data to fwrite? Or that I'm doing something bad in my pthread instanciation? Or has sendmail crashed?
void EmailClient::Send() const
{
// Flush all open output streams, as recommended by popen man page
fflush(NULL);
string popen_command = "sendmail -t -oi >/dev/null 2>&1");
// Open pipe to Mail Transport Agent (MTA)
errno = 0;
FILE* stream = popen(popen_command.c_str(), "w");
if (stream == NULL)
{
throw exception("Cannot send email popen");
}
errno = 0;
if (fwrite(message.data(), message.size(), 1, stream) < 1)
{
pclose(stream);
throw exception("fwrite error ", strerror(errno));
}
// Close MTA
errno = 0;
if (pclose(stream) == -1)
printf("\"Error closing the MTA pipe (%s)\"", strerror(errno))
}

EPIPE means that the other end (the process you are writing to) has died. This could happen if there is a fork failure (popen invokes the shell, so there is another subprocess involved) because there are temporarily too many processes in the system. A more direct cause would be sendmail failing and exiting prematurely, before reading all of standard input, say due to malformed email headers.
popen is unfortunately not a very reliable interface. You might be better off using fork/execve or posix_spawn, either with a temporary file for the input or I/O multiplexing using poll, just to be able to capture any error that sendmail might generate. Alternatively, you could try to call sendmail with -oee, which is supposed to report any errors by email, but it won't help if the creation of the sendmail itself fails.

Related

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.

Creating non blocking pipes to child that does not block and can be reused

I am trying to create a inter process communication bus using pipes.
I can send messages to the client, and i can receive messages at the client.
I also tried to create another pipe which goes the other way, child-> parent.
However I need this communication to be non blocking and I want to send messages in both directions with some undefined time gap in between.
It appears i can not send more then one message, I take it it is due to the fclose(); closing the stream, however if i remove the close, the program stops working...
How can I make this code nonblocking two way parent -> child communication through pipes?
Later I want to connect a child-binary using exec(), and connecting this binary's stdin, stdout to my parent, so that I can pass messages to the stdin of the child and retrieve answers through the "childParent" descriptor.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define READ_SIDE 0
#define WRITE_SIDE 1
/* Read characters from the pipe and echo them to stdout. */
void
read_from_pipe (int file)
{
FILE *stream;
int c;
stream = fdopen (file, "r");
while ((c = fgetc (stream)) != EOF)
putchar (c);
fclose (stream);
}
/* Write some random text to the pipe. */
void
write_to_pipe (int file, char * message)
{
FILE *stream;
stream = fdopen (file, "w");
fprintf (stream, message);
//fprintf (stream, "goodbye, world!\n");
//Dont forget to close
fclose (stream);
}
void end(){
//kill process and close pipes
}
int
main (void)
{
pid_t pid;
int parentToChild[2];
int childToParent[2];
/* Create the pipes. */
if (pipe (parentToChild))
{
fprintf (stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
if (pipe (childToParent))
{
fprintf (stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
/* Create the child process. */
pid = fork ();
if (pid == (pid_t) 0)
{
/* This is the child process.
Close other end first. */
close(childToParent[READ_SIDE]);
close (parentToChild[WRITE_SIDE]);
read_from_pipe (parentToChild[READ_SIDE]);
write_to_pipe(childToParent[WRITE_SIDE], "Child sent message to parent");
return EXIT_SUCCESS;
}
else if (pid < (pid_t) 0)
{
/* The fork failed. */
fprintf (stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
else
{
/* This is the parent process.
Close other end first. */
close(childToParent[WRITE_SIDE]);
close (parentToChild[READ_SIDE]);
write_to_pipe (parentToChild[WRITE_SIDE],"Parent sent message to child");
read_from_pipe(childToParent[READ_SIDE]);
//Send more messages...
return EXIT_SUCCESS;
}
}
UPDATE
It appears that sometimes the communication only happens one way, depending on which process gets to read/write first I guess.
There are several issues to be considered. First, pipes have a finite
maximum length (4096 was common in the distant past); any write to a
pipe which has more data in it than that will block, as will any read
from an empty pipe. These are fundamental to the way pipes work, so
when you speak of non-blocking, you have to take them into consideration
(or use asynchronous IO).
Second, if you really need to control things at this level, you might
want to consider using Posix level IO, rather than streams. If you do
use streams (either iostream or FILE*), then you have to take into
account the buffering they use. In particular, when you want to be sure
that the data is output to the pipe, you need to flush (fflush on
the FILE*). With regards to sending more than one message, and the
code not working without the fclose, replacing the fclose with
fflush should be all you need to fix this.
And while I'm at it: your use of fprintf for output is extremely
dangerous. If you're getting a message from an external source, and
(possibly) don't know what it contains, you should use fputs to output
it, or possibly something like fprintf( fd, "%s\n", message ) (if you
want to append a new line). As you've done it, if the message contains
a '%', strange things will happen. More generally, you should prefer
the much safer iostream, but for simple things like this, it doesn't
matter much. And for what you're actually doing, Posix level IO is
probably just as appropriate, or more so. With Posix level IO, you
don't get any formatting or buffering: but since you're not using the
formatting capabilities, and the buffering it part of your problem...

pthread create Error 11 on detached threads

I have a server application, which waits on a queue, fetches incoming messages, and spawns a thread to process the received message and send a reply.
The pthread portion/options I am using are as follows:
pthread_attr_t child_attr;
pthread_attr_setdetachstate(&child_attr, PTHREAD_CREATE);
// other code here
while (true)
{
// code here to wait on valid message (msg)
if (valid_message(msg))
{
pthread_t child_thread;
MessageProcessor * processor = new MessageProcessor();
if (0 == pthread_create(&child_thread, &child_attr, processor->process, (void *) msg))
{
printf("Thread dispatch successful\n");
}
else
{
printf("Error %d: could not create thread\n", errno);
}
}
}
// other code here
pthread_attr_destroy(&child_attr);
Every time I run this, the error code displayed is 11, which apparently would indicate that my process has crossed the max threads threshold, based on stuff I've read on the Internet.
However,
This is happening right from the beginning, not after I have run the application for a while.
The threads are created detached, so I shouldn't have to use pthread_join().
I used top as well as ps -p <PID> -lfT to check how many threads were in use by the application, and only 3 were (one for main server, one for the message receiver, and one for a message sender for the queue system)
PS:
The "process" prototype is as follows:
class MessageProcessor
{
MessageProcessor();
static void * MessageProcessor::process(void * arg);
}
void * MessageProcessor::process(void * arg)
{
// do something here with arg
}
Like all pthreads functions, pthread_create does not set errno to report errors, it returns an error number instead. To see why it failed you need to print the return value, not errno.
const int err = pthread_create(&child_thread, &child_attr, processor->process, (void *) msg);
if (err == 0)
printf("Thread dispatch successful\n");
else
printf("Error %d: could not create thread\n", err);
POSIX specifies errno like so:
The value of errno shall be defined only after a call to a function for which it is explicitly stated to be set [...] The value of errno should only be examined when it is indicated to be valid by a function's return value.
Since pthread_create is not documented to set errno it means the value is not defined after a call to pthread_create and should not be examined.
Your code is using an uninitialized child_attr, you'll have to do:
pthread_attr_init(&child_attr);
pthread_attr_setdetachstate(&child_attr, PTHREAD_CREATE_DETACHED);
errno 11 is usually EAGAIN, in this case it means no more processes (linux treats threads as light weight processes - see the clone manual page)available.
The while(true) loop will run forever making processes.
Note if you have a special version of Linux like ARM the error number 11 is NOT required to be EAGAIN. So take this answer with a grain of salt.

valgrind/helgrind gets killed on stress test

I'm making a web server on linux in C++ with pthreads. I tested it with valgrind for leaks and memory problems - all fixed. I tested it with helgrind for thread problems - all fixed. I'm trying a stress test. I'm getting problem when the probram is run with helgrind
valgrind --tool=helgrind ./chats
It just dies on random places with the text "Killed" as it would do when I kill it with kill -9. The only report I get sometimes from helgrind is that the program exists while still holding some locks, which is normal when gets killed.
When checking for leaks:
valgrind --leak-check=full ./chats
it's more stable, but I managed to make it die once with few hundreds of concurrent connections.
I tried running program alone and couldn't make it crash at all. I tried up to 250 concurrent connections. Each thread delays with 100ms to make it easier to have multiple connections at the same time. No crash.
In all cases threads as well as connections do not get above 10 and I see it crash even with 2 connections, but never with only one connection at the same time (with including main thread and one helper thread is total of 3).
Is it possible that the problem will only happen when run with
helgrind or just helgrind makes it more likely to show?
What be the reason that a program gets killed (by kernel?) Allocating too much memory, too many file descriptors?
I tested a bit more and I found out that it only dies when the client times out and closes the connection. So here is the code which detects that the client closed the socket:
void *TcpClient::run(){
int ret;
struct timeval tv;
char * buff = (char *)malloc(10001);
int br;
colorPrintf(TC_GREEN, "new client starting: %d\n", sockFd);
while(isRunning()){
tv.tv_sec = 0;
tv.tv_usec = 500*1000;
FD_SET(sockFd, &readFds);
ret = select(sockFd+1, &readFds, NULL, NULL, &tv);
if(ret < 0){
//select error
continue;
}else if(ret == 0){
// no data to read
continue;
}
br = read(sockFd, buff, 10000);
buff[br] = 0;
if (br == 0){
// client disconnected;
setRunning(false);
break;
}
if (reader != NULL){
reader->tcpRead(this, std::string(buff, br));
}else{
readBuffer.append(buff, br);
}
//printf("received: %s\n", buff);
}
free(buff);
sendFeedback((void *)1);
colorPrintf(TC_RED, "closing client socket: %d\n", sockFd);
::close(sockFd);
sockFd = -1;
return NULL;
}
// this method writes to socket
bool TcpClient::write(std::string data){
int bw;
int dataLen = data.length();
bw = ::write(sockFd, data.data(), dataLen);
if (bw != dataLen){
return false; // I don't close the socket in this case, maybe I should
}
return true;
}
P.S. Threads are:
main thread. connections are accepted here.
one helper thread which listen for signals and sends signals. It stops signal reception for the app and manually polls the signal queue. The reason is because it's hard to handle signals when using threads. I found this technique here in stackoverflow and it seams to work pretty fine in other projects.
client connection threads
The full code is pretty big, but I can post chunks if someone is interested.
Update:
I managed to trigger the problem with only one connection. It's all happening in client thread. This is what I do:
I read/parse headers. I put delay before writing so the client can timeout (which causes the problem).
Here the client timeouts and leaves (probably closes socket)
I write back headers
I write back the html code.
Here is how I write back
bw = ::write(sockFd, data.data(), dataLen);
// bw is = dataLen = 108 when writing the headers
//then secondary write for HTML kills the program. there is a message before and after write()
bw = ::write(sockFd, data.data(), dataLen); // doesn't go past this point second time
Update 2: Got it :)
gdb sais:
Program received signal SIGPIPE, Broken pipe.
[Switching to Thread 0x41401940 (LWP 10554)]
0x0000003ac2e0d89b in write () from /lib64/libpthread.so.0
Question 1: What should I do to void receiving this signal.
Question 2: How to know that remote side disconnected while writing. On read select returns that there is data but data read is 0. How about write?
Well I just had to handle the SIGPIPE singal and write returned -1 -> I close socket and quit thread gracefully. Works like a charm.
I guess the easiest way is to set signal handler of SIGPIPE to SIG_IGN:
signal(SIGPIPE, SIG_IGN);
Note that first write was successful and didn't kill the program. If you have similar problem check if you are writing once or multiple times. If you are not familiar with gdb this is how to do it:
gdb ./your-program
> run
and gdb will tell you all about signals and sigfaults.

Showing a message in the terminal from which signal was sent

My process in running as daemon.
I want to reload the configuration using signal.
The problem is that if configuration is wrong it should error message in the tty form which signal was sent.
Is there a way to do this?
Is it recommended way?
If it is not recommended way. What will be a more appropriate way to check if it was successful or not?
For getting pid of signal source, you need to use sa_sigaction instead of sa_handler when you set signal handlers:
static pid_t g_killer_pid = 0;
static void signal_handler( int num, siginfo_t *info, void* blabla )
{
g_killer_pid = info->si_pid;
}
int main(void)
{
struct sigaction sa;
memset( &sa, 0, sizeof(sa) );
sa.sa_sigaction = &signal_handler;
sa.sa_flags = SA_SIGINFO;
sigaction( SIGTERM, &sa, NULL );
sigaction( SIGINT, &sa, NULL );
pause();
hello_killer( g_killer_pid );
return 0;
}
Now you have pid of the source process.
For getting terminal id of the source process is not so simple.
One way is read it from proc/<pid>/stat file. One number in the file is tty_nr.
tty_nr is little bit strange for me, so I don't know is this even portable stuff.
But it holds minor number, that can be used for opening correct terminal for writing:
static void hello_killer( pid_t killer )
{
char filename[200];
FILE* fil;
FILE* out;
int tty_nr;
sprintf( filename, "/proc/%ld/stat", (long int)killer );
fil = fopen( filename, "r" );
if( fil )
{
if( fscanf( fil, "%*s %*s %*s %*s %*s %*s %d ", &tty_nr ) == 1 )
{
sprintf( filename, "/dev/pts/%d", (tty_nr & 0xF) | ((tty_nr >> 20) & 0xFFF) );
out = fopen( filename, "a" );
if( out )
{
fprintf( out, "Hello!\n" );
fclose( out );
}
}
fclose( fil );
}
}
I am not sure is that /dev/pts trick correct/best way to do it. But it seems to work in my Linux box:
~ # killall temp_test
Hello!
~ #
I'm guessing you something like catching SIGUSR1 and then reload the configuration?
You should remember that signal handlers should be as small and quick as possible, and not do something that can cause another signal. So basically you should refrain from I/O as much as possible. What is probably the best way to do this is to have a very simple signal handler that only sets a flag, then in your main loop you check for this flag and then reload your configuration in the context of your main thread. There you can output to the console all you want.
You can do this, but there's no trivial way to do it. You need to arrange a mechanism for the daemon to feedback to the process sending the signal.
Some possible ways of doing that include:
Write the (timestamped) result to a file in a predetermined location.
Have the daemon maintain a shared memory segment with the information in a known structure.
Have the daemon listen on a named pipe/socket of some sort and give out feedback that way. (You could also send the reload command via that channel).
Have the thing that sends the signal and the daemon link against a shared library so that both are capable of validating the configuration file. Validate the file before raising the signal.
Of those a named pipe would be my first choice I think - you can restrict access to it with normal permissions and it's the easiest to make robust and correct.
I doubt, that you can determine the source of the signal and even, if you could so, it don't have to be a terminal. What about using a simple tcp/ip protocol? Accept tcp/ip connections on a special port. Read a command until a first new line. If that command is "reconfigure", do the reconfiguration and send a message over the established TCP/IP connection.