I have to write a program which monitors two named pipes and prints the information sent through either.
When the write end of one of the pipes is closed, the program will detect this and close and open the pipe again.
This is what I have written so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 200
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
ssize_t n_read;
char buf[BUF_SIZE];
/* Open pipes */
int tuberia1_fd = open("tuberia1",O_RDONLY);
int tuberia2_fd = open("tuberia2",O_RDONLY);
while(1){
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait for an indefinite amount of time. */
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(2, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
exit(EXIT_FAILURE);
if(FD_ISSET(tuberia1_fd, &rfds)){
n_read = read(tuberia1_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia1_fd);
tuberia1_fd = open("tuberia1", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia1: %s", buf);
}
} else if (FD_ISSET(tuberia2_fd, &rfds)){
n_read = read(tuberia2_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia2_fd);
tuberia2_fd = open("tuberia2", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia2: %s", buf);
}
}
}
}
When I run it, the program locks, which is the expected behavior. But when I echo hello_world > tuberia1 there is no response from the program.
What is going on?
EDIT: As observed by GM below, I was incorrectly passing arguments to select. After fixing that my program looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#define BUF_SIZE 200
int
main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
ssize_t n_read;
char buf[BUF_SIZE];
/* Open pipes */
printf("Opening tuberia1");
int tuberia1_fd = open("tuberia1",O_RDONLY);
printf("Opening tuberia2");
int tuberia2_fd = open("tuberia2",O_RDONLY);
while(1){
printf("Enter the loop");
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(tuberia1_fd, &rfds);
FD_SET(tuberia2_fd, &rfds);
/* Wait for an indefinite amount of time. */
tv.tv_sec = 5;
tv.tv_usec = 0;
int fd_max = (tuberia1_fd > tuberia2_fd) ? tuberia1_fd : tuberia2_fd;
retval = select(fd_max, &rfds, NULL, NULL, &tv);
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
exit(EXIT_FAILURE);
if(FD_ISSET(tuberia1_fd, &rfds)){
n_read = read(tuberia1_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia1_fd);
tuberia1_fd = open("tuberia1", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia1: %s", buf);
}
} else if (FD_ISSET(tuberia2_fd, &rfds)){
n_read = read(tuberia2_fd, &buf, BUF_SIZE);
if (n_read == 0){
close(tuberia2_fd);
tuberia2_fd = open("tuberia2", O_RDONLY);
}else{
buf[n_read] = '\0';
printf("tuberia2: %s", buf);
}
}
}
}
It still does not work. Running it under GDB shows that the program never progresses past the first open.
You need to use FD_SET on the file descriptors you're actually interested in -- namely tuberia1_fd and tuberia2_fd.
So something like...
while (1) {
FD_ZERO(&rfds);
FD_SET(tuberia1_fd, &rfds);
FD_SET(tuberia2_fd, &rfds);
int max;
if (tuberia1_fd > tuberia2_fd) {
max = tuberia1_fd;
} else {
max = tuberia2_fd;
}
tv.tv_sec = 0;
tv.tv_usec = 0;
retval = select(max + 1, &rfds, NULL, NULL, &tv);
Related
I am trying to modify an example I found.
The example:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
struct timeval tv;
fd_set readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
FD_ZERO(&readfds);
FD_SET(STDIN, &readfds);
// don't care about writefds and exceptfds:
select(STDIN+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET(STDIN, &readfds))
printf("A key was pressed!\n");
else
printf("Timed out.\n");
return 0;
}
Which print time out if 2.5 seconds has passed without sending a message, otherwise printing a key was pressed.
I tried to put it inside a while loop:
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
if (select(STDIN+1, &temp, NULL, NULL, &tv) == -1)
printf("err");
if (FD_ISSET(STDIN, &temp))
{
printf("A key was pressed!\n");
}
else
printf("Timed out.\n");
}
return 0;
}
In this code when I enter a key it keeps printing a key was pressed forever.
I read online the I have to set tv variable every time but still no help.
Do i need a temp fd_set
? what am I wrong ?
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
// Note: STDIN_FILENO, or fileno(stdin)
#define STDIN 0 // file descriptor for standard input
int main(void)
{
fd_set readfds, temp;
struct timeval tv;
int ret,ch;
FD_ZERO(&readfds);
FD_ZERO(&temp);
FD_SET(STDIN, &readfds);
while(1){
temp = readfds;
tv.tv_sec = 2;
tv.tv_usec = 500000;
// don't care about writefds and exceptfds:
ret = select(STDIN+1, &temp, NULL, NULL, &tv) ;
if (ret == -1) {
if (errno == EAGAIN) continue; // These are NOT Errors, but natural occuring events
if (errno == EINTR) continue; // The are reported to avoid your select() to block for too long
perror("erreur");
break;
}
else if (ret ==0) {
printf("Timed out.\n");
continue;
}
// Ok: select has returned > 0; there must be something to read
if (FD_ISSET(STDIN, &temp)) {
ch = getc(stdin); // Lookout: stdin is line-buffered
printf("A key was pressed: %d!\n", ch);
}
}
return 0;
}
I'm using the OpenSSL library to secure network messages, but for some reason it doesn't always seems to work. Actually most of the time it doesn't work. When I run the compiled code and connect to the socket, most of the time it just runs the code of the main process in the child as well, but sometimes it runs the child instructions. Obiously, this isn't the way it should work, the child should exit instead, after it handled the client (handle_client(newfd)) all the time. One interesting part is, if I remove the handle_client(newfd) line from the child instructions and put something small there, like printf("test"), then the child works every time as it should, it prints test and exits right after that. Is this some kind of limitation in fork(), or I just shouldn't run this much code in a child? Or something else? Any help would be really appriciated!
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/wait.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include "json.h"
#include "create_socket.h"
#include "get_addr.h"
#include "handle_income.h"
#include "handle_client.h"
int main(void) {
int newfd;
struct sockaddr_storage their_addr;
char s[INET6_ADDRSTRLEN];
pid_t pid;
unsigned int cpc = 0;
int listenfd = create_socket("8069");
if (listenfd < 0)
exit(1);
while(1) {
socklen_t sin_size = sizeof their_addr;
if ((newfd = accept(listenfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)
continue;
inet_ntop(their_addr.ss_family,
get_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("conn %s siz %d\n", s, (int) sin_size); //REMOVE
if ((pid = fork()) < 0) {
exit(1);
} else if (pid == 0) {
close(listenfd);
handle_client(newfd);
exit(0);
}
printf("child %d\n", (int) pid); //REMOVE
cpc++;
while(cpc) {
pid = waitpid((pid_t) -1, NULL, WNOHANG);
if (pid < 0)
exit(1);
else if (pid == 0)
break;
else
cpc--;
}
}
EVP_cleanup();
exit(0);
}
handle_client.h:
#define READ_SIZE 32
void handle_client(int newfd) {
char *buffer = NULL;
char *tmp_buffer = malloc(READ_SIZE);
unsigned long buffer_size = 0;
unsigned long received = 0;
int status = 0;
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *sslctx = SSL_CTX_new(SSLv23_server_method());
if (sslctx) {
SSL_CTX_set_ecdh_auto(sslctx, 1);
if ((SSL_CTX_use_certificate_file(sslctx, "/ssl-cert.pem", SSL_FILETYPE_PEM)) > 0) {
if ((SSL_CTX_use_PrivateKey_file(sslctx, "/ssl-key.pem", SSL_FILETYPE_PEM)) > 0) {
SSL *ssl = SSL_new(sslctx);
SSL_set_fd(ssl, newfd);
if (SSL_accept(ssl) > 0) {
fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK);
do {
if (received >= buffer_size) {
char *tmp;
buffer_size += READ_SIZE;
if ((tmp = realloc(buffer, buffer_size)) == NULL) {
break;
} else {
buffer = tmp;
}
}
status = SSL_read(ssl, tmp_buffer, READ_SIZE);
if (status > 0) {
received += status;
strncat(buffer, tmp_buffer, status);
} else {
ERR_print_errors_fp(stderr);
}
} while (status > 0);
free(tmp_buffer);
buffer[received] = 0;
if (received < buffer_size) {
buffer = realloc(buffer, received);
}
printf("%s\n", buffer); //REMOVE
char *response = handle_income(buffer);
SSL_write(ssl, response, strlen(response));
printf("%s\n", response); //REMOVE
}
SSL_free(ssl);
}
}
}
SSL_CTX_free(sslctx);
close(newfd);
}
There might be other problems too, but you should fix the following buffer overflow error, and check if it fix visible problem too:
SSL_read may return less than READ_SIZE. So the next piece of code is broken.
Problem occurs for example, when the 1st SSL_read() returns for example 16, and the next call return 32 (=READ_SIZE). Allocated buffer size during 2nd strncat call is 32, so buffer overflow may occurs during strncat().
if (received >= buffer_size) {
char *tmp;
buffer_size += READ_SIZE;
if ((tmp = realloc(buffer, buffer_size)) == NULL) {
break;
} else {
buffer = tmp;
}
}
status = SSL_read(ssl, tmp_buffer, READ_SIZE);
if (status > 0) {
received += status;
strncat(buffer, tmp_buffer, status);
}
...
There might be other problem with strncat call. It needs one extra byte for null terminator of string. From man page:
the size of dest must be at least strlen(dest)+n+1
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <poll.h>
#include <string.h>
#include <errno.h>
#define BUFSIZE 256
char buffer[BUFSIZE];
int readBytes;
struct termios saved;
struct termios modif;
void onExit(){
if(tcsetattr(STDIN_FILENO, TCSANOW, &saved) == -1)
readBytes = readBytes; //placeholder
}
void nonCanonMode(){
if(tcgetattr(STDIN_FILENO, &saved) == -1)
readBytes = readBytes;
if(tcgetattr(STDIN_FILENO, &modif) == -1)
readBytes = readBytes;
modif.c_iflag = ISTRIP;
modif.c_oflag = 0;
modif.c_lflag = 0;
if(tcsetattr(STDIN_FILENO, TCSANOW, &modif) == -1)
readBytes = readBytes;
atexit(onExit);
}
void readChar(){
int counter = 0;
readBytes = read(STDIN_FILENO, buffer, BUFSIZE);
if(readBytes == -1)
readBytes = readBytes;
while(counter < readBytes){
if(buffer[counter] == '\004'){
exit(0);
}
else{
if(write(STDOUT_FILENO, &buffer[counter], sizeof(char)) == -1)
readBytes = readBytes;
write(STDOUT_FILENO, &buffer[counter], sizeof(char));
}
counter++;
}
}
int main(){
nonCanonMode();
while(1)
readChar();
exit(0);
}
The readChar() function doesn't print out characters as they are typed in. I put my terminal into noncanonical mode and loop this function indefinitely to read a character at a time. However the function only writes to stdout once. If I comment out the second write then there's no output.
I'm implementing a simple ipc system using linux named pipes in C.
I have this server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "external/paths.h"
#include "external/sv.h"
#include "external/tags.h"
int main(int argc, char *argv[])
{
int fd, bytes_read;
char request[200];
// create fifo
mknod(FIFO_SERVER, S_IFIFO | 0666, 0);
puts("Servidor initialized.\nWaiting for client requests.");
// open created fifo
fd = open(FIFO_SERVER, O_RDONLY);
while(1)
{
if( (bytes_read = read(fd, request, LEN_CL_REQUEST)) == -1 )
perror("error read()");
if(bytes_read == 0)
continue;
if(bytes_read > 0)
{
printf("Request read: %s\n", request);
// answer back
}
}
close(fd);
unlink(FIFO_SERVER);
return 0;
}
I'm ommiting the client because my question is only related with the server. The communication is working fine, I can read requests from the client and I can answer them. Now, lets say I want to, at anytime, be able to quit the server when the key 'Q' is pressed.. I can't do this because my code blocks on the read statement waiting for another client request, so I have no way to read the stdin..
Is something like this possible to do? I'm thinking in something like non-blocking the read statement and try to read stdin for a few seconds, then check again for incoming requests.. I've been searching but I haven't found anything similar.
UPDATE:
I followed Jean-Baptiste Yunès approach but it turns out that select is only detecting the fifo events, I don't really know why.
This is the code I'm testing:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int result, fd, maxDescriptor;
char input[20], texto[100];
mknod("fifo", S_IFIFO | 0666, 0);
fd = open("fifo", O_RDWR); // RDWR to avoid EOF return to select
fd_set readset;
FD_ZERO(&readset);
FD_SET(fileno(stdin), &readset);
FD_SET(fd, &readset);
maxDescriptor = fileno(stdin) > fd ? fileno(stdin) : fd;
while(1)
{
result = select(maxDescriptor+1, &readset, NULL, NULL, NULL);
if(result == -1)
perror("select()");
else if(result)
{
puts("data available.");
if( FD_ISSET(fileno(stdin), &readset) )
{
scanf("%s", input);
printf("%s\n", input);
if( strcmp(input, "Q") == 0 )
break;
}
if( FD_ISSET(fd, &readset) )
{
read(fd, texto, 100);
printf("lido:\n%s\n", texto);
}
}
else
puts("no data.");
}
unlink("fifo");
return 0;
}
UPDATE 2:
As Jean-Baptiste Yunès pointed out, there's need to reset fd_set since it doesn't reset automatically.
Here's the final working code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int result, fd, maxDescriptor;
char input[20], texto[100];
mknod("fifo", S_IFIFO | 0666, 0);
fd = open("fifo", O_RDWR); // RDWR to avoid EOF return to select
fd_set readset;
FD_ZERO(&readset);
FD_SET(fileno(stdin), &readset);
FD_SET(fd, &readset);
maxDescriptor = fileno(stdin) > fd ? fileno(stdin) : fd;
while(1)
{
result = select(maxDescriptor+1, &readset, NULL, NULL, NULL);
if(result == -1)
perror("select()");
else if(result)
{
puts("data available.");
if( FD_ISSET(fileno(stdin), &readset) )
{
scanf("%s", input);
printf("%s\n", input);
if( strcmp(input, "Q") == 0 )
break;
}
if( FD_ISSET(fd, &readset) )
{
read(fd, texto, 100);
printf("lido:\n%s\n", texto);
}
FD_SET(fileno(stdin), &readset);
FD_SET(fd, &readset);
}
else
puts("no data.");
}
unlink("fifo");
return 0;
}
You have to use select. You need to wait on both channels: something from the pipe or something from stdin but you never know which one to read. The purpose of select is to make your process wait on any channel for read or write.
fd_set readset;
FD_ZERO(&readset); // empty set of descriptor to select on
FD_SET(fd, &readset); // add the pipe
FD_SET(stdin, &readset); // add stdin
result = select(fd + 1, &readset, NULL, NULL, NULL); // now wait for something to read on at least one channel (pipe or stdin)
if (result>0) {
if (FD_ISSET(fd, &readset)) { // test for pipe availability
// now read the pipe
}
if (FD_ISSET(stdin, &readset)) { // test for stdin availability
// now read stdin
}
}
fifo.3 source code:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pthread.h>
#include <time.h>
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF //4096
#define TEN_MEG (1024 * 1024 * 1)
void* thread_tick(void* arg)
{
int count =0;
while(count < 4){
printf("hello, world!\n");
sleep(1);
count++;
}
}
void* thread_write(void* arg)
{
int pipe_fd;
int res;
int bytes_sent = 0;
char buffer[BUFFER_SIZE ];
int count=0;
if (access(FIFO_NAME, F_OK) == -1) {
res = mkfifo(FIFO_NAME, 0777);
if (res != 0) {
fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
exit(EXIT_FAILURE);
}
}
while(count < 10){
printf("write: Process %d opening FIFO O_WRONLY\n", getpid());
pipe_fd = open(FIFO_NAME, O_WRONLY);
printf("write: Process %d result %d \n", getpid(), pipe_fd);
if (pipe_fd != -1) {
while(bytes_sent < TEN_MEG) {
res = write(pipe_fd, buffer, BUFFER_SIZE);
if (res == -1) {
fprintf(stderr, "Write error on pipe\n");
exit(EXIT_FAILURE);
}
bytes_sent += res;
}
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
printf("write: Process %d finished , count =%d\n", getpid(),count);
count++;
}
}
void CreateThread(void* (*start_routine)(void*), void* arg,int stacksize, int priority)
{
pthread_t app_thread;
pthread_attr_t thread_attr;
int res;
int max_priority;
int min_priority;
struct sched_param scheduling_value;
res = pthread_attr_init(&thread_attr);
if (res != 0) {
perror("Attribute creation failed\n");
exit(EXIT_FAILURE);
}
res = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
if (res != 0) {
perror("Setting detached attribute failed");
exit(EXIT_FAILURE);
}
res = pthread_attr_setstacksize(&thread_attr, stacksize);
if (res != 0) {
perror("Set stack size failed\n");
exit(EXIT_FAILURE);
}
res = pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
max_priority = sched_get_priority_max(SCHED_RR);
min_priority = sched_get_priority_min(SCHED_RR);
scheduling_value.sched_priority = priority;
res = pthread_attr_setschedparam(&thread_attr, &scheduling_value);
if (res != 0) {
perror("Setting schedpolicy failed");
exit(EXIT_FAILURE);
}
res = pthread_create(&app_thread, &thread_attr, (*start_routine), arg);
if(res != 0){
perror("Thread creation failed\n");
exit(EXIT_FAILURE);
}
pthread_attr_destroy(&thread_attr);
//res = pthread_join(app_thread ,0 );
//return app_thread;
}
int main()
{
CreateThread(thread_write, 0, 50000, 99);
CreateThread(thread_tick, 0, 50000, 98);
// pthread_join(w,0 );
// pthread_join(t ,0 );
return 0;
}
fifo.4 source code :
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF //4096
int main()
{
int pipe_fd;
int res;
char buffer[BUFFER_SIZE ];
int bytes_read = 0;
int count = 0;
memset(buffer, '\0', sizeof(buffer));
while(count < 10){
printf("read: Process %d opening FIFO O_RDONLY\n", getpid());
pipe_fd = open(FIFO_NAME, O_RDONLY);
printf("read: Process %d result %d\n", getpid(), pipe_fd);
if (pipe_fd != -1) {
do {
res = read(pipe_fd, buffer, BUFFER_SIZE);
bytes_read += res;
} while (res > 0);
(void)close(pipe_fd);
}
else {
exit(EXIT_FAILURE);
}
printf("read: Process %d finished, %d bytes read , count =%d\n", getpid(), bytes_read,count);
count++;
}
return 0;
}
this is the first time I post code on Stack overflow, so it is in a mess.
Above are two C source code. fifo3.c has two thread and thread_write is to write data to named fifo.
fifo4.c is to read data from named fifo.
my question:
1) how does the read(pipe_fd, buffer, BUFFER_SIZE) behave when write() is writing data to fifo? If read() can not read data, SHOULD not read() return 0 and then exit, why read() would wait write() to finish write data??? of course, how does write() behave when read() is reading?
2) in fifo3.c , I create two threads, when I create them detached , the program can not run !!!
but joinable, they could run correctly !!I do not know why!
In theory, they both could function right.
Answer for Question-1:
If read cannot read data it will 'block' till data arrives, this is called blocking mode read. Incase of a blocking mode read, the read call blocks till a data arrives. If you wish to change it to non-blocking mode, you can use fcntl functionality, if the same is supported.
For other queries, it is best that you read about it through man pages as a concise answer will be difficult.
Answer for Question-2:
When you create a thread detached, it means the created threads are not bound to the parent thread which creates it. So, the parent thread will just exit, if it completes it's work. If the parent happens to be the main thread, then when it exits the process also will exit, which will cause program not to run.