Commit 63bf56d0 authored by Mikhail Karpenko's avatar Mikhail Karpenko
Browse files

Process commands in a thread

parent 73ecbfc7
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -231,6 +231,7 @@ void camogm_init(camogm_state *state, char *pipe_name)
	state->rawdev.curr_pos_w = state->rawdev.start_pos;
	state->rawdev.curr_pos_r = state->rawdev.start_pos;
	state->active_chn = ALL_CHN_ACTIVE;
	state->rawdev.mmap_size = MMAP_CHUNK_SIZE;
}

/**
@@ -802,7 +803,7 @@ void camogm_set_prefix(camogm_state *state, const char * p, path_type type)
			D0(fprintf(debug_file, "WARNING: raw device write initiated\n"));
			state->rawdev_op = 1;
			/* debug code follows */
//			state->rawdev.end_pos = 10485760; // 10 Mib
			state->rawdev.end_pos = 10485760; // 10 Mib
			/* end of debug code */
		}
	}
@@ -954,6 +955,8 @@ void camogm_status(camogm_state *state, char * fn, int xml)
	case STATE_READING:
		_state = "reading";
		break;
	default:
		_state = "stopped";
	}
	_output_format = state->format ? ((state->format == CAMOGM_FORMAT_OGM) ? "ogm" :
					  ((state->format == CAMOGM_FORMAT_JPEG) ? "jpeg" :
@@ -1006,7 +1009,7 @@ void camogm_status(camogm_state *state, char * fn, int xml)
			"  <raw_device_path>\"%s\"</raw_device_path>\n" \
			"  <raw_device_overruns>%d</raw_device_overruns>\n" \
			"  <raw_device_pos_write>0x%llx</raw_dev_pos_write>\n" \
			"  <raw_device_pos_read>0x%llx (%d\% done)</raw_device_pos_read>\n",
			"  <raw_device_pos_read>0x%llx (%d%% done)</raw_device_pos_read>\n",
			_state,  state->path, state->frameno, state->start_after_timestamp, _dur, _udur, _len, \
			_frames_skip, _sec_skip, \
			state->width, state->height, _output_format, _using_exif, \
@@ -1067,7 +1070,7 @@ void camogm_status(camogm_state *state, char * fn, int xml)
		fprintf(f, "raw device overruns\t%d\n",        state->rawdev.overrun);
		fprintf(f, "raw write position \t0x%llx\n",    state->rawdev.curr_pos_w);
		fprintf(f, "raw read position  \t0x%llx\n",    state->rawdev.curr_pos_r);
		fprintf(f, "   percent done    \t%d\%\n",      _percent_done);
		fprintf(f, "   percent done    \t%d%%\n",      _percent_done);
		fprintf(f, "max file duration  \t%d sec\n",    state->segment_duration);
		fprintf(f, "max file length    \t%d B\n",      state->segment_length);
		fprintf(f, "max frames         \t%d\n",        state->max_frames);
@@ -1498,7 +1501,7 @@ int listener_loop(camogm_state *state)
					state->rawdev.thread_finished = false;
					state->prog_state = STATE_STOPPED;
					pthread_join(state->rawdev.tid, &tret);
					if ((int)tret != 0 && (int)tret != PTHREAD_CANCELED) {
					if ((int)tret != 0 && (int)tret != (int)PTHREAD_CANCELED) {
						D0(fprintf(debug_file, "Reading thread returned error %d\n", (int)tret));
					} else {
						D3(fprintf(debug_file, "Reading thread stopped\n"));
@@ -1509,7 +1512,8 @@ int listener_loop(camogm_state *state)
			} else if (state->rawdev.thread_state == STATE_STOPPED) {
				state->rawdev.thread_state = STATE_RUNNING;
				state->rawdev.thread_finished = false;
				if (pthread_create(&state->rawdev.tid, NULL, build_index, state) != 0) {
//				if (pthread_create(&state->rawdev.tid, NULL, build_index, state) != 0) {
				if (pthread_create(&state->rawdev.tid, NULL, reader, state) != 0) {
					state->prog_state = STATE_STOPPED;
					state->rawdev.thread_state = STATE_STOPPED;
					D0(fprintf(debug_file, "%s:line %d: Can not start new thread, disk index is not built\n", __FILE__, __LINE__));
+3 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@
#define RAWDEV_START_OFFSET       1024
/** @brief Maximum length of file or raw device path */
#define ELPHEL_PATH_MAX           300
#define MMAP_CHUNK_SIZE           134217728

/**
 * @enum state_flags
@@ -99,6 +100,8 @@ typedef struct {
	uint64_t start_pos;
	uint64_t end_pos;
	uint64_t curr_pos_w;
	uint64_t *disk_mmap;
	uint64_t mmap_size;
	volatile uint64_t curr_pos_r;
	uint64_t file_start;
	pthread_t tid;
+279 −77
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@
#include <ctype.h>
#include <asm/byteorder.h>
#include <sys/statvfs.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include "camogm_read.h"

@@ -41,6 +44,9 @@
/** @brief Separator character between seconds and microseconds in JPEG file name */
#define SUBSEC_SEPARATOR          '.'
#define EXIF_DATE_TIME_FORMAT     "%Y:%m:%d %H:%M:%S"
#define CMD_DELIMITER             "/?"
#define CMD_BUFF_LEN              1024
#define COMMAND_LOOP_DELAY        500000
/** @brief The size of read buffer in bytes. The data will be read from disk in blocks of this size */
#define PHY_BLK_SZ                4096
/** @brief Include or exclude file start and stop markers from resulting file. This must be set to 1 for JPEG files */
@@ -60,6 +66,26 @@ static const struct iovec elphel_en = {
		.iov_len = sizeof(elphelen)
};

#define COMMAND_TABLE \
	X(CMD_BUILD_INDEX, "build_index") \
	X(CMD_GET_INDEX, "get_index") \
	X(CMD_READ_DISK, "read_disk") \
	X(CMD_READ_FILE, "read_file") \
	X(CMD_READ_ALL_FILES, "read_all_files") \
	X(CMD_STATUS, "status")

#define X(a, b) a,
enum socket_commands {
	COMMAND_TABLE
};
#undef X

#define X(a, b) b,
static const char *cmd_list[] = {
	COMMAND_TABLE
};
#undef X

/**
 * @enum file_result
 * @brief Return codes for file operations
@@ -122,6 +148,16 @@ enum search_state {
	SEARCH_FILE_START,
	SEARCH_FILE_DATA
};

//enum sock_commands {
//	CMD_BUILD_INDEX,
//	CMD_GET_INDEX,
//	CMD_READ_DISK,
//	CMD_READ_FILE,
//	CMD_READ_ALL_FILES,
//	CMD_STATUS
//};

/**
 * @brief Exif data format table.
 *
@@ -219,6 +255,8 @@ struct exit_state {
	int ret_val;
};

static inline void exit_thread(void *arg);

void dump_index_dir(const struct disk_idir *idir)
{
	struct disk_index *ind = idir->head;
@@ -540,39 +578,39 @@ int stop_index(struct disk_idir *idir, uint64_t pos_stop)
 * @param[in]   f_op   pointer to a structure holding information about currently opened file
 * @return      \e FILE_OK if file was successfully opened and negative error code otherwise
 */
static int start_new_file(struct file_opts *f_op)
{
	int ret;
	int err;
	struct statvfs vfs;
	uint64_t free_size = 0;
	char file_name[ELPHEL_PATH_MAX] = {0};

	memset(&vfs, 0, sizeof(struct statvfs));
	ret = statvfs(f_op->state->path_prefix, &vfs);
	if (ret != 0) {
		D0(fprintf(debug_file, "Unable to get free size on disk, statvfs() returned %d\n", ret));
		return -CAMOGM_FRAME_FILE_ERR;
	}
	free_size = (uint64_t)vfs.f_bsize * (uint64_t)vfs.f_bfree;
	// statvfs can return irrelevant values in some fields for unsupported file systems,
	// thus free_size is checked to be equal to non-zero value
	if (free_size > 0 && free_size < FREE_SIZE_LIMIT) {
		return -CAMOGM_NO_SPACE;
	}

//	make_fname(f_op->state, file_name);
	sprintf(f_op->state->path, "%s%s", f_op->state->path_prefix, file_name);

	if ((f_op->fh = fopen(f_op->state->path, "w")) == NULL) {
		err = errno;
		D0(fprintf(debug_file, "Error opening %s for writing\n", file_name));
		D0(fprintf(debug_file, "%s\n", strerror(err)));
		return -CAMOGM_FRAME_FILE_ERR;
	}

	return FILE_OK;
}
//static int start_new_file(struct file_opts *f_op)
//{
//	int ret;
//	int err;
//	struct statvfs vfs;
//	uint64_t free_size = 0;
//	char file_name[ELPHEL_PATH_MAX] = {0};
//
//	memset(&vfs, 0, sizeof(struct statvfs));
//	ret = statvfs(f_op->state->path_prefix, &vfs);
//	if (ret != 0) {
//		D0(fprintf(debug_file, "Unable to get free size on disk, statvfs() returned %d\n", ret));
//		return -CAMOGM_FRAME_FILE_ERR;
//	}
//	free_size = (uint64_t)vfs.f_bsize * (uint64_t)vfs.f_bfree;
//	// statvfs can return irrelevant values in some fields for unsupported file systems,
//	// thus free_size is checked to be equal to non-zero value
//	if (free_size > 0 && free_size < FREE_SIZE_LIMIT) {
//		return -CAMOGM_NO_SPACE;
//	}
//
////	make_fname(f_op->state, file_name);
//	sprintf(f_op->state->path, "%s%s", f_op->state->path_prefix, file_name);
//
//	if ((f_op->fh = fopen(f_op->state->path, "w")) == NULL) {
//		err = errno;
//		D0(fprintf(debug_file, "Error opening %s for writing\n", file_name));
//		D0(fprintf(debug_file, "%s\n", strerror(err)));
//		return -CAMOGM_FRAME_FILE_ERR;
//	}
//
//	return FILE_OK;
//}

/**
 * @brief Detect cases when file marker crosses read buffer boundary
@@ -636,56 +674,221 @@ static int check_edge_case(const struct iovec *from, const struct iovec *to, con
 * @param[in]   to     end pointer to data buffer
 * @return      a constant of #file_result type
 */
static int write_buffer(struct file_opts *f_op, unsigned char *from, unsigned char *to)
//static int write_buffer(struct file_opts *f_op, unsigned char *from, unsigned char *to)
//{
//	int ret = FILE_OK;
//	int len;
//	unsigned int sz;
//
//	sz = to - from;
//	switch (f_op->file_state) {
//	case WRITE_RUNNING:
//		len = fwrite(from, sz, 1, f_op->fh);
//		if (len != 1) {
//			perror(__func__);
//			ret = FILE_WR_ERR;
//		}
//		break;
//	case WRITE_START:
//		if ((ret = start_new_file(f_op)) == FILE_OK) {
//			len = fwrite(from, sz, 1, f_op->fh);
//			if (len != 1) {
//				perror(__func__);
//				ret = FILE_WR_ERR;
//			}
//		} else {
//			if (ret == -CAMOGM_NO_SPACE)
//				D0(fprintf(debug_file, "No free space left on the disk\n"));
//			f_op->fh = NULL;
//			ret = FILE_OPEN_ERR;
//		}
//		break;
//	case WRITE_STOP:
//		len = fwrite(from, sz, 1, f_op->fh);
//		if (len != 1) {
//			perror(__func__);
//			ret = FILE_WR_ERR;
//		}
//		if (fclose(f_op->fh) != 0) {
//			perror(__func__);
//			ret = FILE_CLOSE_ERR;
//		} else {
//			f_op->fh = NULL;
//			f_op->file_cntr++;
//		}
//		break;
//	default:
//		ret = FILE_OPT_ERR;
//	}
//	return ret;
//}

void send_buffer(int sockfd, unsigned char *buff, size_t sz)
{
	int ret = FILE_OK;
	int len;
	unsigned int sz;

	sz = to - from;
	switch (f_op->file_state) {
	case WRITE_RUNNING:
		len = fwrite(from, sz, 1, f_op->fh);
		if (len != 1) {
			perror(__func__);
			ret = FILE_WR_ERR;
	size_t bytes_left = sz;
	size_t bytes_written = 0;
	size_t offset = 0;

	while (bytes_left > 0) {
		bytes_written = write(sockfd, &buff[offset], bytes_left);
		bytes_left -= bytes_written;
		offset += bytes_written;
	}
		break;
	case WRITE_START:
		if ((ret = start_new_file(f_op)) == FILE_OK) {
			len = fwrite(from, sz, 1, f_op->fh);
			if (len != 1) {
				perror(__func__);
				ret = FILE_WR_ERR;
}
		} else {
			if (ret == -CAMOGM_NO_SPACE)
				D0(fprintf(debug_file, "No free space left on the disk\n"));
			f_op->fh = NULL;
			ret = FILE_OPEN_ERR;

int mmap_disk(rawdev_buffer *rawdev)
{
	int ret = 0;

	rawdev->rawdev_fd = open(rawdev->rawdev_path, O_RDONLY);
	if (rawdev->rawdev_fd < 0) {
		return -1;
	}
	rawdev->disk_mmap = mmap(0, rawdev->mmap_size, PROT_READ, MAP_SHARED, rawdev->rawdev_fd, rawdev->start_pos);
	if (rawdev->disk_mmap == MAP_FAILED) {
		close(rawdev->rawdev_fd);
		return -1;
	}

	return ret;
}

int unmmap_disk(rawdev_buffer *rawdev)
{
	int ret = 0;

	if (munmap(rawdev->disk_mmap, rawdev->mmap_size) != 0)
		return -1;
	if (close(rawdev->rawdev_fd) != 0)
		return -1;

	return ret;
}

#define PORT_NUMBER 3456
void prep_socket(int *socket_fd)
{
	int opt = 1;
	struct sockaddr_in sock;

	memset((char *)&sock, 0, sizeof(struct sockaddr_in));
	sock.sin_family = AF_INET;
	sock.sin_port = htons(PORT_NUMBER);
	*socket_fd = socket(AF_INET, SOCK_STREAM, 0);
	setsockopt(*socket_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
	bind(*socket_fd, (struct sockaddr *) &sock, sizeof(struct sockaddr_in));
	listen(*socket_fd, 10);
}

/**
 *
 * @param cmd
 * cmd pointer is updated to point to current command
 * @return -1 command not recognized, -2 end of buffer
 */
int parse_command(char **cmd)
{
	size_t cmd_len;
	int cmd_indx = -1;
	char *char_ptr;

	D6(fprintf(debug_file, "Parsing command line: %s\n", *cmd));
	char_ptr = strpbrk(*cmd, CMD_DELIMITER);
	if (char_ptr != NULL) {
		char_ptr[0] = '\0';
		char_ptr++;
		for (int i = 0; i < sizeof(cmd_list) / sizeof(cmd_list[0]); i++) {
			cmd_len = strlen(cmd_list[i]);
			if (strncmp(char_ptr, cmd_list[i], cmd_len) == 0) {
				cmd_indx = i;
				break;
	case WRITE_STOP:
		len = fwrite(from, sz, 1, f_op->fh);
		if (len != 1) {
			perror(__func__);
			ret = FILE_WR_ERR;
		}
		if (fclose(f_op->fh) != 0) {
			perror(__func__);
			ret = FILE_CLOSE_ERR;
			}
		}
		*cmd = char_ptr;
	} else {
			f_op->fh = NULL;
			f_op->file_cntr++;
		cmd_indx = -2;
	}

	return cmd_indx;
}

/**
 * @brief Break HTTP GET string after the command part as we do not need that part. The function
 * finds the first space character after the command part starts and replaces it with null.
 * @param[in,out]   cmd   pointer to HTTP GET string
 */
void trim_command(char *cmd, ssize_t cmd_len)
{
	char *ptr_start, *ptr_end;

	if (cmd_len >= 0 && cmd_len < CMD_BUFF_LEN)
		cmd[cmd_len] = '\0';
	ptr_start = strpbrk(cmd, CMD_DELIMITER);
	if (ptr_start) {
		ptr_end = strchr(ptr_start, ' ');
		if (ptr_end)
			ptr_end[0] = '\0';
	}
}

/**
 *
 * @param arg
 * @todo print unrecognized command
 */
void *reader(void *arg)
{
	int sockfd, fd;
	int cmd;
	char cmd_buff[CMD_BUFF_LEN] = {0};
	char *cmd_ptr;
	ssize_t cmd_len;
	camogm_state *state = (camogm_state *)arg;
	rawdev_buffer *rawdev = &state->rawdev;
	unsigned char *disk_buff = NULL;
	struct exit_state exit_state = {
			.state = state,
			.ret_val = 0
	};

	prep_socket(&sockfd);
	while (true) {
		fd = accept(sockfd, NULL, 0);
		if (fd == -1)
			continue;
		cmd_len = read(fd, cmd_buff, sizeof(cmd_buff) - 1);
		cmd_ptr = cmd_buff;
		trim_command(cmd_ptr, cmd_len);
		while ((cmd = parse_command(&cmd_ptr)) != -2) {
			if (cmd >= 0)
				D6(fprintf(debug_file, "Got command '%s'\n", cmd_list[cmd]));
			switch (cmd) {
			case CMD_BUILD_INDEX:
				break;
			case CMD_GET_INDEX:
				break;
			case CMD_READ_DISK:
				break;
			case CMD_READ_FILE:

				break;
			case CMD_READ_ALL_FILES:
				break;
			case CMD_STATUS:
				break;
			default:
		ret = FILE_OPT_ERR;
				D0(fprintf(debug_file, "Unrecognized command is skipped\n"));
			}
	return ret;
		}
		fprintf(debug_file, "Closing connection\n");
		close(fd);
		usleep(COMMAND_LOOP_DELAY);
	}

	return (void *) 0;
}

static inline void *exit_thread(void *arg)
static inline void exit_thread(void *arg)
{
	struct exit_state *s = (struct exit_state *)arg;

@@ -694,7 +897,6 @@ static inline void *exit_thread(void *arg)
		s->state->rawdev.rawdev_fd = -1;
	}
	s->state->rawdev.thread_finished = true;
	return (void *) s->ret_val;
}

/**
+2 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ struct disk_index {
	struct disk_index *next;
	struct disk_index *prev;
	time_t rawtime;
	useconds_t usec;
	unsigned int usec;
	uint32_t port;
	size_t f_size;
	uint64_t f_offset;
@@ -36,5 +36,6 @@ struct disk_idir {
};

void *build_index(void *arg);
void *reader(void *arg);

#endif /* _CAMOGM_READ_H */