summaryrefslogblamecommitdiffstats
path: root/src/server/server.c
blob: e38a0e3f50466762102e1882246e91a6565d56cf (plain) (tree)












































































































































































                                                                                                              
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <netinet/in.h>
#include <sys/sendfile.h>

#include <pthread.h>

#include "../include/types.h"
#include "../version.h"
#include "file.h"

int file;

void print_help(char* argv_0)
{

	printf("Usage: %s [OPTIONS]...\n", argv_0);
	printf("Start the DNBD3 server.\n");
	printf("-f or --file \t\t File to export.\n");
	printf("-h or --help \t\t Show this help text and quit.\n");
	printf("-v or --version \t Show version and quit.\n");
	exit(0);
}

void print_version()
{
	printf("Version: %s\n", VERSION_STRING);
	exit(0);
}

void handle_sigpipe(int signum)
{
	printf("Program received signal SIGPIPE, Broken pipe (errno: %i)\n", errno);
	return;
}

void *echo(void *client_socket)
{
	int sock = (int) client_socket;
	struct dnbd3_request request;
	struct dnbd3_reply reply;
	uint16_t cmd;
	off_t filesize;

	while (recv(sock, &request, sizeof(struct dnbd3_request), MSG_WAITALL) > 0)
	{
		cmd = request.cmd;
//		char buf[request.size];
		switch (cmd)
		{
		case CMD_GET_SIZE:
			reply.cmd = request.cmd;
			file_getsize(file, &filesize);
			reply.filesize = filesize;
			send(sock, (char *) &reply, sizeof(struct dnbd3_reply), 0);
			break;

		case CMD_GET_BLOCK:
//			printf("CMD: %i, Byte: %llu, Size: %llu\n",request.cmd, request.offset, request.size);
//			file_read(file, buf, request.size, request.offset);
//			send(sock, (char *) buf, request.size, 0);
			sendfile(sock, file, (off_t *) &request.offset, request.size);
			break;

		default:
			;
		}

	}
	close(sock);
	printf("Client exit.\n");
	pthread_exit((void *)0);
}

int main(int argc, char* argv[])
{
	int opt = 0;
	int longIndex = 0;
	static const char *optString = "f:hv?";
	static const struct option longOpts[] =
	{
	{ "file", required_argument, NULL, 'f' },
	{ "help", no_argument, NULL, 'h' },
	{ "version", no_argument, NULL, 'v' } };

	opt = getopt_long(argc, argv, optString, longOpts, &longIndex);
	if (opt == -1)
		print_help(argv[0]);

	while (opt != -1)
	{
		switch (opt)
		{
		case 'f':
			file = file_open(optarg);
			break;
		case 'h':
			print_help(argv[0]);
			break;
		case 'v':
			print_version();
			break;
		case '?':
			exit(1);
		}
		opt = getopt_long(argc, argv, optString, longOpts, &longIndex);
	}

	signal(SIGPIPE, handle_sigpipe);

	struct sockaddr_in server;
	struct sockaddr_in client[50];
	int sock, fd;
	unsigned int len;
	pthread_t thread[50];
	int i=1;

	// Create socket
	sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock < 0)
	{
		printf("ERROR: Socket failure\n");
		exit(EXIT_FAILURE);
	}

	memset(&server, 0, sizeof(server));
	server.sin_family = AF_INET; // IPv4
	server.sin_addr.s_addr = htonl(INADDR_ANY); // Take all IPs
	server.sin_port = htons(PORT); // set port number

	// Bind to socket
	if (bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0)
	{
		printf("ERROR: Bind failure\n");
		exit(EXIT_FAILURE);
	}

	// Listen on socket
	if (listen(sock, 50) == -1)
	{
		printf("ERROR: Listen failure\n");
		exit(EXIT_FAILURE);
	}

	printf("INFO: Server is ready...\n");

	// TODO: dyn threads
	while (1)
	{
		len = sizeof(client);
		fd = accept(sock, (struct sockaddr*) &client[i], &len);
		if (fd < 0)
		{
			printf("ERROR: Accept failure\n");
			exit(EXIT_FAILURE);
		}

		printf("INFO: Client: %s connected\n", inet_ntoa(client[i].sin_addr));
		pthread_create(&(thread[i]), NULL, echo, (void *) fd);
		pthread_detach(thread[i++]);
	}
	return EXIT_SUCCESS;
}