Skip to content

mini_server #16

@Adrian-REH

Description

@Adrian-REH
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>

int extract_message(char **buf, char **msg)
{
	char	*newbuf;
	int	i;

	*msg = 0;
	if (*buf == 0)
		return (0);
	i = 0;
	while ((*buf)[i])
	{
		if ((*buf)[i] == '\n')
		{
			newbuf = calloc(1, sizeof(*newbuf) * (strlen(*buf + i + 1) + 1));
			if (newbuf == 0)
				return (-1);
			strcpy(newbuf, *buf + i + 1);
			*msg = *buf;
			(*msg)[i + 1] = 0;
			*buf = newbuf;
			return (1);
		}
		i++;
	}
	return (0);
}

char *str_join(char *buf, char *add)
{
	char	*newbuf;
	int		len;

	if (buf == 0)
		len = 0;
	else
		len = strlen(buf);
	newbuf = malloc(sizeof(*newbuf) * (len + strlen(add) + 1));
	if (newbuf == 0)
		return (0);
	newbuf[0] = 0;
	if (buf != 0)
		strcat(newbuf, buf);
	free(buf);
	strcat(newbuf, add);
	return (newbuf);
}


int main() {
	int sockfd, connfd, len;
	struct sockaddr_in servaddr, cli; 

	// socket create and verification 
	sockfd = socket(AF_INET, SOCK_STREAM, 0); 
	if (sockfd == -1) { 
		printf("socket creation failed...\n"); 
		exit(0); 
	} 
	else
		printf("Socket successfully created..\n"); 
	bzero(&servaddr, sizeof(servaddr)); 

	// assign IP, PORT 
	servaddr.sin_family = AF_INET; 
	servaddr.sin_addr.s_addr = htonl(2130706433); //127.0.0.1
	servaddr.sin_port = htons(8081); 

	// Binding newly created socket to given IP and verification 
	if ((bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr))) != 0) { 
		printf("socket bind failed...\n"); 
		exit(0); 
	} 
	else
		printf("Socket successfully binded..\n");
	if (listen(sockfd, 10) != 0) {
		printf("cannot listen\n"); 
		exit(0); 
	}
	len = sizeof(cli);
	connfd = accept(sockfd, (struct sockaddr *)&cli, &len);
	if (connfd < 0) { 
        printf("server acccept failed...\n"); 
        exit(0); 
    } 
    else
        printf("server acccept the client...\n");
}
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>


typedef struct s_client {
    int id;
    char *buffer;
}t_client;

typedef struct s_server {
    int sockfd;
    int count;
    int maxfd;
    char write[42];
    char read[1001];
    t_client clients[65536];
    fd_set read_fds;
    fd_set write_fds;
    fd_set current_fds;

} t_server;

void fatal() {
    write(2, "Fatal error\n", 13);
    exit(1);
}

int extract_message(char **buf, char **msg)
{
	char	*newbuf;
	int	i;

	*msg = 0;
	if (*buf == 0)
		return (0);
	i = 0;
	while ((*buf)[i])
	{
		if ((*buf)[i] == '\n')
		{
			newbuf = calloc(1, sizeof(*newbuf) * (strlen(*buf + i + 1) + 1));
			if (newbuf == 0)
				return (-1);
			strcpy(newbuf, *buf + i + 1);
			*msg = *buf;
			(*msg)[i + 1] = 0;
			*buf = newbuf;
			return (1);
		}
		i++;
	}
	return (0);
}

char *str_join(char *buf, char *add)
{
	char	*newbuf;
	int		len;

	if (buf == 0)
		len = 0;
	else
		len = strlen(buf);
	newbuf = malloc(sizeof(*newbuf) * (len + strlen(add) + 1));
	if (newbuf == 0)
		return (0);
	newbuf[0] = 0;
	if (buf != 0)
		strcat(newbuf, buf);
	free(buf);
	strcat(newbuf, add);
	return (newbuf);
}

void ft_broadcast(int sender, t_server *server, char*msg) {
    for (int fd = 0; fd <= server->maxfd; fd++) {
        if (FD_ISSET(fd, &server->write_fds) && fd != sender) {
            send(fd, msg, strlen(msg), 0);
        }
    }
}

void ft_send_msg (int sender, t_server *server) {
    char *msg;
    while (extract_message(&server->clients[sender].buffer, &msg)) {
        sprintf(server->write, "client %d: ", server->clients[sender].id);
        ft_broadcast(sender, server, server->write);
        ft_broadcast(sender, server, msg);
        free(msg);
    }
}

void ft_remove_cli(int sender, t_server * server) {

    FD_CLR(sender, &server->current_fds);
    close(sender);
    if (server->clients[sender].buffer) {
        free(server->clients[sender].buffer);
    }
    server->clients[sender].buffer = (NULL);
    sprintf(server->write, "server: client %d just left\n", server->clients[sender].id);
    ft_broadcast(sender, server, server->write);
}


int ft_read_msg (int sender, t_server * server) {
    int bytes = recv(sender, server->read, 1000, 0);
    if (bytes <= 0) {
        ft_remove_cli(sender, server);
        return - 1;
    }
    server->read[bytes] = 0;
    server->clients[sender].buffer = str_join(server->clients[sender].buffer, server->read);
    ft_send_msg(sender, server);
    return 0;
}


void ft_config_srv (t_server *server, uint16_t port) {
    struct sockaddr_in addrsrv; 
    bzero(&addrsrv, sizeof(addrsrv));

    server->sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (server->sockfd < 0 ) {
        fatal();
    }

    FD_ZERO(&server->current_fds);
    FD_SET(server->sockfd, &server->current_fds);


    addrsrv.sin_family = AF_INET;
    addrsrv.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    addrsrv.sin_port = htons(port);

    server->maxfd = server->sockfd;

    if (bind(server->sockfd, (const struct sockaddr *)&addrsrv, sizeof(addrsrv)) < 0)
        fatal();
    if (listen(server->sockfd, 65536) < 0)
        fatal();
}


void ft_accept_cli(t_server *server) {
    struct sockaddr_in addrcli;
    socklen_t len;
    bzero(&addrcli, sizeof(addrcli));

    len = sizeof(addrcli);
    int clifd = accept(server->sockfd, (struct sockaddr *)&addrcli, &len);
    if (clifd < 0 ) {
        fatal();
    }

    FD_SET(clifd, &server->current_fds);

    //Save
    server->maxfd  =clifd > server->maxfd ? clifd: server->maxfd;
    server->clients[clifd].id = server->count++;
    server->clients[clifd].buffer = NULL;
    //Notify

    sprintf(server->write, "server: client %d just arrived\n", server->clients[clifd].id);
    ft_broadcast(clifd, server, server->write);
}

int main (int argc, char **arg) {
    t_server server;
    if (argc != 2) {
        write(2, "Wrong number of arguments\n", 27);
        exit(1);
    }

    bzero(&server, sizeof(server));
    ft_config_srv(&server, atoi(arg[1]));

    while (1) {
        server.read_fds= server.current_fds;
        server.write_fds= server.current_fds;
        if (select(server.maxfd + 1, &server.read_fds, &server.write_fds, NULL, NULL) < 0) {
            fatal();
        }
        for (int fd = 0; fd <= server.maxfd; fd++) {
            if (FD_ISSET(fd, &server.read_fds)) {
                if (fd == server.sockfd) {
                    ft_accept_cli(&server);
                } else {
                    if (ft_read_msg(fd, &server) < 0)
                        break;
                }
            }
        }
    }

    return 0;
}

Execute

Terminal A

cc mini_srv.c -o mini_srv
./mini_srv 8080

Terminal B

nc 127.0.0.1 8080

Terminal C

nc 127.0.0.1 8080

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions