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);
+ }
+}