ref: 968ac77631ed370269bfd11dec3ba15679585491
dir: /khar.c/
#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
typedef struct {
int sockfd;
struct sockaddr_storage claddr;
socklen_t claddr_len;
} client_t;
client_t clients[MAX_CLIENT];
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 < MAX_CLIENT; 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);
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;
for (int i = 0; i <= MAX_CLIENT; i++) {
if (clients[i].sockfd == -1) {
free_index = i;
break;
}
}
if (free_index > 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;
}
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);
}
}