about summary refs log tree commit diff
path: root/server.cpp
diff options
context:
space:
mode:
authorUbuntu <baitinq@Peces.qluofd4gyjdubpy0ojfn3gxkic.bx.internal.cloudapp.net>2020-06-05 17:12:19 +0000
committerUbuntu <baitinq@Peces.qluofd4gyjdubpy0ojfn3gxkic.bx.internal.cloudapp.net>2020-06-05 17:12:19 +0000
commitc739aa0cf8fc885c8cad79d2d639d0ecd49bd5ae (patch)
tree66fb3ec1af228082fab674e9aa98ba17d6b9cb44 /server.cpp
downloadencrypted-chat-master.tar.gz
encrypted-chat-master.tar.bz2
encrypted-chat-master.zip
Release HEAD master
Diffstat (limited to 'server.cpp')
-rw-r--r--server.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/server.cpp b/server.cpp
new file mode 100644
index 0000000..597e131
--- /dev/null
+++ b/server.cpp
@@ -0,0 +1,206 @@
+#include "utils.hpp"
+
+#define PUBLIC "0.0.0.0"
+#define LOCAL "127.0.0.1"
+#define IP PUBLIC
+#define PORT "4444"
+
+int main(int argc, char** argv);
+int start_server(Options* options);
+void* handle_connections(void* poptions);
+void* handle_client(void* pclient_fd);
+int parse_arguments(int argc, char** argv, Options* options);
+int print_help();
+
+Options options {};
+std::vector<int> clients;
+
+int main(int argc, char** argv)
+{
+	int status;
+
+	options.server = true;	
+	strncpy(options.ip, IP, sizeof(options.ip));
+	strncpy(options.port, PORT, sizeof(options.port));
+	strncpy(options.name, "Server", sizeof(options.name));
+	options.encryption = false;
+	options.pass = false;
+	strncpy(options.password, DEFAULT_PASS, sizeof(options.password));
+	options.interactive = false;
+	options.max_clients = -1;
+
+	status = parse_arguments(argc, argv, &options);
+	if(status)
+	{
+		print_help();
+		goto end;
+	}
+
+	status = start_server(&options);
+	if(status)
+	{
+		ERROR_LOG("Failed to start server.\n");
+		goto end;
+	}
+
+	INFO_LOG("Succesfully started server.\n");
+
+	if(options.interactive)
+		start_client(&clients, &options);
+	
+	pause();
+
+	end:
+	return status;
+}
+
+int start_server(Options* options)
+{
+	options->sockfd = socket(AF_INET, SOCK_STREAM, 0);
+	if(options->sockfd < 0)
+		return 1;
+
+	sockaddr_in sockaddr;
+	memset(&sockaddr, 0, sizeof(sockaddr));
+	sockaddr.sin_family = AF_INET;
+	sockaddr.sin_addr.s_addr = inet_addr(options->ip);
+	sockaddr.sin_port = htons(atoi(options->port));
+
+	if(bind(options->sockfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)))
+		return 2;
+
+	if(listen(options->sockfd, 1))
+		return 3;
+
+	pthread_t connections_thread;
+	if(pthread_create(&connections_thread, NULL, handle_connections, (void*)options))
+		return 4;
+	
+	return 0;
+}
+
+void* handle_connections(void* poptions)
+{
+	Options* options = (Options*)poptions;
+	sockaddr_in sockaddr;
+	socklen_t addrlen = sizeof(sockaddr);
+
+	int connection;
+	while((connection = accept(options->sockfd, (struct sockaddr*)&sockaddr, &addrlen)))
+	{
+		if(connection < 0)
+			return 0;
+
+		if((int)(&clients)->size() == options->max_clients)
+		{
+			ERROR_LOG("Client limit reached. New client has been forbidden to connect.\n");
+			close(connection);
+			continue;
+		}
+
+		pthread_t client_thread;
+		if(pthread_create(&client_thread, NULL, handle_client, (void*)(intptr_t)connection))
+			return 0;
+	}
+
+	return 0;
+}
+
+void* handle_client(void* pclient_fd)
+{
+	int client_fd = (intptr_t)pclient_fd;
+	Packet incoming_packet;
+	bool first = true;
+	char name[20];
+	
+	int read_size;
+	while((read_size = recv(client_fd, &incoming_packet, sizeof(incoming_packet), 0)) > 0)
+	{
+		int result = handle_incoming_packet(&incoming_packet, &client_fd, &clients, &options);
+		if(result == -1)
+		{
+			ERROR_LOG("Invalid packet recieved.\n");
+			break;
+		}
+		else if(result == -3)
+			return 0;
+		else if(result > 0)
+		{
+			ERROR_LOG("Error handling packet recieved.\n");
+			break;
+		}
+
+		if(first && incoming_packet.type == PacketType::packet_ping)
+		{
+			first = false;
+			strncpy(name, incoming_packet.data.packet_ping.name, sizeof(name));
+		}
+	}
+
+	if(strlen(name) > 0)
+	{
+		Packet dc_packet {};
+		dc_packet.type = PacketType::packet_disconnect;
+		strncpy(dc_packet.data.packet_disconnect.name, name, sizeof(dc_packet.data.packet_disconnect.name));	
+		if(options.encryption)
+			encrypt(&options, (char*)&dc_packet, sizeof(dc_packet));
+		handle_incoming_packet(&dc_packet, &client_fd, &clients, &options);
+	}
+
+	close(client_fd);
+
+	return 0;
+}
+
+int parse_arguments(int argc, char** argv, Options* options)
+{
+	extern char* optarg;
+	int status = 0;
+	int option;
+	while((option = getopt(argc, argv, "p:en:ix:h")) != -1)
+		switch(option)
+		{
+			case 'p':
+				strncpy(options->port, optarg, sizeof(options->port));
+				break;
+			case 'e':
+				options->encryption = true;
+				break;
+			case 'n':
+				options->max_clients = atoi(optarg);
+				break;
+			case 'i':
+				options->interactive = true;
+				break;
+			case 'x':
+				options->pass = true;
+				strncpy(options->password, optarg, sizeof(options->password));
+				break;
+			case 'h':
+				print_help();
+				break;	
+			case ':':
+				status = 1;
+				break;
+			case '?':
+				status = 1;
+				break;
+		}
+
+	return status;
+}
+
+int print_help()
+{
+	printf(
+		"Usage:\n"
+			"\t./server\n"
+				"\t\t-p (PORT) [port number]\n"
+				"\t\t-e [encryption]\n"
+				"\t\t-n (NUM_CLIENTS) [max clients]\n"
+				"\t\t-i [interactive]\n"
+				"\t\t-x (PASS) [pasword]\n"
+				"\t\t-h [show help]\n"
+	      );
+	return 0;
+}