qrexec: when forgetting about a client/process, flush buffered data
We need to spawn a child to take care of buffered data flushing, if there is any. Expensive, but should be needed rarely.
This commit is contained in:
		
							parent
							
								
									53b517f6a5
								
							
						
					
					
						commit
						1d24ef9d1a
					
				@ -6,8 +6,8 @@ COMMONIOALL=../common/ioall.o
 | 
			
		||||
all: qrexec_daemon qrexec_agent qrexec_client
 | 
			
		||||
qrexec_daemon: qrexec_daemon.o unix_server.o $(COMMONIOALL) txrx-vchan.o buffer.o write_stdin.o
 | 
			
		||||
	$(CC) -g -o qrexec_daemon qrexec_daemon.o unix_server.o $(COMMONIOALL) txrx-vchan.o write_stdin.o buffer.o $(XENLIBS)
 | 
			
		||||
qrexec_agent: qrexec_agent.o exec.o txrx-vchan.o write_stdin.o buffer.o
 | 
			
		||||
	$(CC) -g -o qrexec_agent qrexec_agent.o exec.o txrx-vchan.o write_stdin.o buffer.o $(XENLIBS)
 | 
			
		||||
qrexec_agent: qrexec_agent.o exec.o txrx-vchan.o write_stdin.o buffer.o $(COMMONIOALL)
 | 
			
		||||
	$(CC) -g -o qrexec_agent qrexec_agent.o exec.o txrx-vchan.o write_stdin.o buffer.o $(COMMONIOALL) $(XENLIBS)
 | 
			
		||||
qrexec_client: qrexec_client.o $(COMMONIOALL) exec.o
 | 
			
		||||
	$(CC) -g -o qrexec_client qrexec_client.o $(COMMONIOALL) exec.o
 | 
			
		||||
clean:
 | 
			
		||||
 | 
			
		||||
@ -45,3 +45,4 @@ int flush_client_data(int fd, int clid, struct buffer *buffer);
 | 
			
		||||
int write_stdin(int fd, int clid, char *data, int len,
 | 
			
		||||
		struct buffer *buffer);
 | 
			
		||||
void set_nonblock(int fd);
 | 
			
		||||
int fork_and_flush_stdin(int fd, struct buffer *buffer);
 | 
			
		||||
 | 
			
		||||
@ -206,8 +206,11 @@ void remove_process(int clid, int status)
 | 
			
		||||
	int i;
 | 
			
		||||
	if (!client_info[clid].pid)
 | 
			
		||||
		return;
 | 
			
		||||
        fork_and_flush_stdin(client_info[clid].stdin_fd, &client_info[clid].buffer); 
 | 
			
		||||
#if 0 
 | 
			
		||||
//      let's let it die by itself, possibly after it has received buffered stdin
 | 
			
		||||
	kill(client_info[clid].pid, SIGKILL);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
	if (status != -1)
 | 
			
		||||
		send_exit_code(clid, status);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -118,10 +118,15 @@ void handle_new_client()
 | 
			
		||||
		max_client_fd = fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int children_count;
 | 
			
		||||
 | 
			
		||||
void flush_client(int fd)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct server_header s_hdr;
 | 
			
		||||
	
 | 
			
		||||
	if (fork_and_flush_stdin(fd, &clients[fd].buffer))
 | 
			
		||||
	        children_count++;
 | 
			
		||||
	close(fd);
 | 
			
		||||
	clients[fd].state = CLIENT_INVALID;
 | 
			
		||||
	buffer_free(&clients[fd].buffer);
 | 
			
		||||
@ -249,7 +254,6 @@ void pass_to_client(int clid, struct client_header *hdr)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int children_count;
 | 
			
		||||
int child_exited;
 | 
			
		||||
 | 
			
		||||
void sigchld_handler(int x)
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,8 @@
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <ioall.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "qrexec.h"
 | 
			
		||||
#include "buffer.h"
 | 
			
		||||
#include "glue.h"
 | 
			
		||||
@ -66,7 +68,7 @@ int write_stdin(int fd, int clid, char *data, int len,
 | 
			
		||||
		buffer_append(buffer, data, len);
 | 
			
		||||
		return WRITE_STDIN_BUFFERED;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	ret = write(fd, data, len);
 | 
			
		||||
	if (ret == len)
 | 
			
		||||
		return WRITE_STDIN_OK;
 | 
			
		||||
@ -96,3 +98,31 @@ void set_nonblock(int fd)
 | 
			
		||||
	int fl = fcntl(fd, F_GETFL, 0);
 | 
			
		||||
	fcntl(fd, F_SETFL, fl | O_NONBLOCK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_block(int fd)
 | 
			
		||||
{
 | 
			
		||||
	int fl = fcntl(fd, F_GETFL, 0);
 | 
			
		||||
	fcntl(fd, F_SETFL, fl & ~O_NONBLOCK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fork_and_flush_stdin(int fd, struct buffer *buffer)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	if (!buffer_len(buffer))
 | 
			
		||||
		return 0;
 | 
			
		||||
	switch (fork()) {
 | 
			
		||||
	case -1:
 | 
			
		||||
		perror("fork");
 | 
			
		||||
		exit(1);
 | 
			
		||||
	case 0:
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < MAX_FDS; i++)
 | 
			
		||||
		if (i != fd && i != 2)
 | 
			
		||||
			close(i);
 | 
			
		||||
	set_block(fd);
 | 
			
		||||
	write_all(fd, buffer_data(buffer), buffer_len(buffer));
 | 
			
		||||
	exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user