wm: khar

Download patch

ref: c2ea79dba50215eaeefba1c4cffba868fea8c624
author: Bxxh7 <StormBorower@gmail.com>
date: Fri Nov 5 14:43:19 EDT 2021

new file:   config.h
	new file:   khar.c

--- /dev/null
+++ b/config.h
@@ -1,0 +1,12 @@
+#ifndef __HARKI_HARF_BEZANE_KHARE_H
+#define __HARKI_HARF_BEZANE_KHARE_H
+
+
+const char *joined_message_private = "Hi, as long as you don't say anything, you're welcome and not khar.\n";
+const char *joined_message_public = "%s joined and is not khar yet.\n";
+const char *khar_message_private = "you are khar, and not welcome here.\n";
+const char *khar_message_public = "%s is khar and is kicked out of the server.\n";
+const char *max_clients_private = "There isn't any more room for you here, it's obvious that you are khar.\n";
+const char *message_template = "%s said: %s";
+const char *list_message = "list of people who are not khar yet:\n";
+#endif
--- /dev/null
+++ b/khar.c
@@ -1,0 +1,260 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <signal.h>
+#include "config.h"
+
+#define PORTNO "32723"
+#define BACKLOG 20
+#define MAX_CLIENT 50
+#define BUF_SIZE 1024
+
+
+
+void atomic_decr(pthread_mutex_t *mutex, int *resource) { 
+	pthread_mutex_lock(mutex);  
+	*resource = *resource - 1;  
+	pthread_mutex_unlock(mutex);
+}
+
+void atomic_incr(pthread_mutex_t *mutex, int *resource) {
+	pthread_mutex_lock(mutex);  
+	*resource = *resource + 1; 
+	pthread_mutex_unlock(mutex);
+}
+	
+
+
+typedef struct {
+	int sockfd;
+	struct sockaddr_storage claddr;
+	socklen_t claddr_len;
+} client_t;
+
+client_t clients[MAX_CLIENT];
+int clients_count = 0;
+
+pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+char *
+printable_addr(struct sockaddr * saddr, socklen_t saddr_len) {
+        char host[NI_MAXHOST], serv[NI_MAXSERV], res[NI_MAXHOST+NI_MAXSERV + 2];
+        int s;
+        
+	s = getnameinfo(saddr, saddr_len, host, NI_MAXHOST, serv, NI_MAXSERV, NI_NUMERICHOST|NI_NUMERICSERV);
+        if (s != 0) {
+                sprintf(res, "UNKNKOWN:UNKNOWN");
+        } else {
+                sprintf(res, "%s:%s", host, serv);
+        }
+
+        return strdup(res);
+}
+
+
+
+
+int init_socket(int socktype) {
+	struct addrinfo hints, *results, *rp;
+	int sfd, status, opt = 1;
+	
+	memset(&hints, 0, sizeof(hints));
+	
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = socktype;
+	hints.ai_flags = AI_PASSIVE;
+	hints.ai_protocol = 0;
+	hints.ai_canonname = NULL;
+	hints.ai_addr = NULL;
+	hints.ai_next = NULL;
+	
+	status = getaddrinfo(NULL, PORTNO, &hints, &results);
+	if (status != 0) {
+		fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
+		exit(EXIT_FAILURE);
+	}
+	
+	for (rp = results; rp != NULL; rp = rp->ai_next) {
+		sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+		
+		if (sfd == -1)
+			continue;
+		
+		setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+		
+		if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0 && listen(sfd, BACKLOG) == 0)
+			break;
+		
+		close(sfd);
+	}
+	
+	freeaddrinfo(results);
+	
+	if (rp == NULL) {
+		fprintf(stderr, "Could't bind\n");
+		exit(EXIT_FAILURE);
+	}
+	
+	return sfd;
+	
+	
+}
+
+void write_all(char *msg, int length) {
+	for (int i = 0; i < clients_count; i++) {
+		if (clients[i].sockfd != -1)
+			write(clients[i].sockfd, msg, length);
+	}
+}
+
+void* handle_client(void *arg) {
+	int index = *(int *)arg, s;
+	char buffer[BUF_SIZE] = {0}, *a, *all_khar_msg;
+	
+	a = printable_addr((struct sockaddr*)&clients[index].claddr, clients[index].claddr_len);
+	
+	
+	/* Print joined_message_public */
+	s = NI_MAXHOST + 5 + strlen(joined_message_public) + 2;
+	all_khar_msg = (char *)malloc(s);
+	
+	if (all_khar_msg == NULL) {
+		all_khar_msg = strdup(joined_message_public);
+	} else {
+		snprintf(all_khar_msg, s, joined_message_public, a);
+	}
+	write_all(all_khar_msg, strlen(all_khar_msg));
+	free(all_khar_msg);
+	
+	/* print join_message_private */
+	write(clients[index].sockfd, joined_message_private, strlen(joined_message_private));
+	
+	
+	while (read(clients[index].sockfd, buffer, BUF_SIZE)) {
+		if (buffer[0] == '\n')
+			continue;
+		else if (strncmp(buffer, "/list", 5) == 0) {
+			write(clients[index].sockfd, list_message, strlen(list_message));
+			for (int i = 0; i < MAX_CLIENT; i++) {
+				if (clients[i].sockfd != -1) {
+					char *addr = printable_addr((struct sockaddr*)&clients[i].claddr, clients[i].claddr_len);
+					addr[strlen(addr) + 1] = '\n';
+
+					write(clients[index].sockfd, addr, strlen(addr) + 2);
+					free(addr);
+				}
+			}
+			memset(buffer, 0, BUF_SIZE);
+			continue;
+		}
+		break;
+	}
+	
+	s = NI_MAXHOST + 5 + strlen(message_template) + BUF_SIZE;
+	
+	all_khar_msg = (char *)malloc(s);
+	
+	if (all_khar_msg == NULL) {
+		all_khar_msg = strdup(message_template);
+	} else {
+		snprintf(all_khar_msg, s, message_template, a, buffer);
+	}
+	write_all(all_khar_msg, strlen(all_khar_msg));
+	free(all_khar_msg);
+
+
+	write(clients[index].sockfd, khar_message_private, strlen(khar_message_private));	
+	close(clients[index].sockfd); // this need to be closed in server too
+	clients[index].sockfd = -1;
+	
+	
+	
+	s = NI_MAXHOST + 5 + strlen(khar_message_public) + 2;
+	all_khar_msg = (char *)malloc(s);
+	
+	if (all_khar_msg == NULL) {
+		all_khar_msg = strdup(khar_message_public);
+	} else {
+		snprintf(all_khar_msg, s, khar_message_public, a);
+	}
+	
+	write_all(all_khar_msg, strlen(all_khar_msg));
+	
+	
+	free(all_khar_msg);
+	
+	
+	atomic_decr(&count_mutex, &clients_count);
+	
+	free(arg);
+	pthread_detach(pthread_self());
+}
+
+int main(int argc, char *argv[]) {
+	int serverfd, cfd, *copy, free_index;
+	struct addrinfo hints;
+	struct sockaddr_storage claddr;
+	pthread_t tid;
+	socklen_t claddr_len;
+	
+	
+	serverfd = init_socket(SOCK_STREAM); /* Returns a scoket or otherwise terminates the program */
+	signal(SIGPIPE, SIG_IGN);
+
+			
+	for (int i = 0; i < MAX_CLIENT; i++) 
+		clients[i].sockfd = -1;
+	
+	for (;;) {
+			
+		cfd = accept(serverfd, (struct sockaddr*)&claddr, &claddr_len);
+		if (cfd == -1)
+			continue;
+			
+		if (clients_count + 1 >= MAX_CLIENT) {
+			char *a;
+			a = printable_addr((struct sockaddr *)&claddr, claddr_len);
+			
+			fprintf(stderr, "giving up on client %s.\n", a);
+			write(cfd, max_clients_private, strlen(max_clients_private));
+			close(cfd);
+			free(a);
+			continue;
+		}
+
+
+		for (int i = 0; i <= MAX_CLIENT; i++) {
+			if (clients[i].sockfd == -1) {
+				free_index = i;
+				break;
+			}
+		}
+		
+				
+		clients[free_index].claddr = claddr;
+		clients[free_index].sockfd = cfd;
+		clients[free_index].claddr_len = claddr_len;
+		
+		
+		
+		copy = (int *)malloc(sizeof(int));
+		if (copy == NULL) {			
+			write(cfd, khar_message_private, strlen(khar_message_private));
+			close(cfd);
+			clients[free_index].sockfd = -1;
+			continue;
+		}
+		*copy = free_index;
+		
+		printf("%s connected.\n", printable_addr((struct sockaddr *)&clients[free_index].claddr, clients[free_index].claddr_len));
+		pthread_create(&tid, NULL, handle_client, (void*) copy);
+		
+		
+		atomic_incr(&count_mutex, &clients_count);
+	}
+}