Ejemplo n.º 1
0
/* 
 * Send a welcome message to the chat client after he has connected.
 */
void send_welcome_msg(int sockfd)
{
	int socklen = 0;
	struct list_entry *cur = NULL;
	va_list args;
	char buffer[1024];
		
	cur = llist_find_by_sockfd(&list_start, sockfd);
	socklen = sizeof(cur->client_info->address);

	/* Lock entry */
	pthread_mutex_lock(cur->mutex);

	/* Send welcome message to client */
	memset(buffer, 0, 1024);
	sprintf(buffer, "%s/---------------------------------------------\\%s\r\n", color_white, color_normal);
	sendto(cur->client_info->sockfd, buffer, strlen(buffer), 0,
		(struct sockaddr *)&(cur->client_info->address), (socklen_t)socklen);
	memset(buffer, 0, 1024);
	sprintf(buffer, "%s|             W E L C O M E   T O             |%s\r\n", color_white, color_normal);
	sendto(cur->client_info->sockfd, buffer, strlen(buffer), 0,
		(struct sockaddr *)&(cur->client_info->address), (socklen_t)socklen);
	memset(buffer, 0, 1024);
	sprintf(buffer, "%s|                  %s %s                |%s\r\n", color_white, APP_NAME, APP_VERSION, color_normal);
	sendto(cur->client_info->sockfd, buffer, strlen(buffer), 0,
		(struct sockaddr *)&(cur->client_info->address), (socklen_t)socklen);
	memset(buffer, 0, 1024);
	sprintf(buffer, "%s|          Written by Andre Gasser 2012       |%s\r\n", color_white, color_normal);
	sendto(cur->client_info->sockfd, buffer, strlen(buffer), 0,
		(struct sockaddr *)&(cur->client_info->address), (socklen_t)socklen);
	memset(buffer, 0, 1024);
	sprintf(buffer, "%s\\---------------------------------------------/%s\r\n", color_white, color_normal);
	sendto(cur->client_info->sockfd, buffer, strlen(buffer), 0,
		(struct sockaddr *)&(cur->client_info->address), (socklen_t)socklen);
		
	/* Unlock entry */
	pthread_mutex_unlock(cur->mutex);
}
Ejemplo n.º 2
0
/*
 * Process a chat message coming from a chat client.
 */
void process_msg(char *message, int self_sockfd)
{
	char buffer[1024];
	regex_t regex_quit;
	regex_t regex_nick;
	regex_t regex_msg;
	regex_t regex_me;
	regex_t regex_who;
	int ret;
	char newnick[20];
	char oldnick[20];
	char priv_nick[20];
	struct list_entry *list_entry = NULL;
	struct list_entry *nick_list_entry = NULL;
	struct list_entry *priv_list_entry = NULL;
	int processed = FALSE;
	size_t ngroups = 0;
	size_t len = 0;
	regmatch_t groups[3];
	
	memset(buffer, 0, 1024);
	memset(newnick, 0, 20);
	memset(oldnick, 0, 20);
	memset(priv_nick, 0, 20);
	
	/* Load client info object */
	list_entry = llist_find_by_sockfd(&list_start, self_sockfd);
	
	/* Remove \r\n from message */
	chomp(message);
	
	/* Compile regex patterns */
	regcomp(&regex_quit, "^/quit$", REG_EXTENDED);
	regcomp(&regex_nick, "^/nick ([a-zA-Z0-9_]{1,19})$", REG_EXTENDED);
	regcomp(&regex_msg, "^/msg ([a-zA-Z0-9_]{1,19}) (.*)$", REG_EXTENDED);
	regcomp(&regex_me, "^/me (.*)$", REG_EXTENDED);
	regcomp(&regex_who, "^/who$", REG_EXTENDED);

	/* Check if user wants to quit */
	ret = regexec(&regex_quit, message, 0, NULL, 0);
	if (ret == 0)
	{
		/* Notify */
		send_broadcast_msg("%sUser %s has left the chat server.%s\r\n", 
			color_magenta, list_entry->client_info->nickname, color_normal);
		logline(LOG_INFO, "User %s has left the chat server.", list_entry->client_info->nickname);
		pthread_mutex_lock(&curr_thread_count_mutex);
		curr_thread_count--;
		logline(LOG_DEBUG, "process_msg(): Connections used: %d of %d", curr_thread_count, MAX_THREADS);
		pthread_mutex_unlock(&curr_thread_count_mutex);

		/* Remove entry from linked list */
		logline(LOG_DEBUG, "process_msg(): Removing element with sockfd = %d", self_sockfd);
		llist_remove_by_sockfd(&list_start, self_sockfd);

		/* Disconnect client from server */
		close(self_sockfd);

		/* Free memory */
		regfree(&regex_quit);
		regfree(&regex_nick);
		regfree(&regex_msg);
		regfree(&regex_me);

		/* Terminate this thread */		
		pthread_exit(0);
	}

	/* Check if user wants to change nick */		
	ngroups = 2;
	ret = regexec(&regex_nick, message, ngroups, groups, 0);
	if (ret == 0)
	{
		processed = TRUE;
		
		/* Extract nickname */
		len = groups[1].rm_eo - groups[1].rm_so;
		strncpy(newnick, message + groups[1].rm_so, len);
		strcpy(oldnick, list_entry->client_info->nickname);
		
		strcpy(buffer, "User ");
		strcat(buffer, oldnick);
		strcat(buffer, " is now known as ");
		strcat(buffer, newnick);
							
		/* Change nickname. Check if nickname already exists first. */
		nick_list_entry = llist_find_by_nickname(&list_start, newnick);
		if (nick_list_entry == NULL)
		{
			change_nickname(oldnick, newnick);
			send_broadcast_msg("%s%s%s\r\n", color_yellow, buffer, color_normal);
			logline(LOG_INFO, buffer);
		}
		else
		{
			send_private_msg(oldnick, "%sCHATSRV: Cannot change nickname. Nickname already in use.%s\r\n", 
				color_yellow, color_normal);
			logline(LOG_INFO, "Private message from CHATSRV to %s: Cannot change nickname. Nickname already in use", 
				oldnick);
		}
	}
	
	/* Check if user wants to transmit a private message to another user */
	ngroups = 3;
	ret = regexec(&regex_msg, message, ngroups, groups, 0);
	if (ret == 0)
	{
		processed = TRUE;
		
		/* Extract nickname and private message */
		len = groups[1].rm_eo - groups[1].rm_so;
		memcpy(priv_nick, message + groups[1].rm_so, len);
		len = groups[2].rm_eo - groups[2].rm_so;
		memcpy(buffer, message + groups[2].rm_so, len);
		
		/* Check if nickname exists. If yes, send private message to user. 
		 * If not, ignore message.
		 */
		priv_list_entry = llist_find_by_nickname(&list_start, priv_nick);
		if (priv_list_entry != NULL)
		{
			send_private_msg(priv_nick, "%s%s:%s %s%s%s\r\n", color_green, list_entry->client_info->nickname, 
				color_normal, color_red, buffer, color_normal);
			logline(LOG_INFO, "Private message from %s to %s: %s", 
				list_entry->client_info->nickname, priv_nick, buffer);
		}
	}
	
	/* Check if user wants to say something about himself */
	ngroups = 2;
	ret = regexec(&regex_me, message, ngroups, groups, 0);
	if (ret == 0)
	{
		processed = TRUE;
		
		strcpy(buffer, list_entry->client_info->nickname);
		
		/* Prepare message */
		len = groups[1].rm_eo - groups[1].rm_so;
		strcat(buffer, " ");
		strncat(buffer, message + groups[1].rm_so, len);
			
		/* Broadcast message */
		send_broadcast_msg("%s%s%s\r\n", color_cyan, buffer, color_normal);
		logline(LOG_INFO, buffer);
	}

	/* Check if user wants a listing of currently connected clients */
	ret = regexec(&regex_who, message, 0, NULL, 0);
	if (ret == 0)
	{
		processed = TRUE;

		int socklen = sizeof(list_entry->client_info->address);

		logline(LOG_INFO, "%s requested the client list", list_entry->client_info->nickname);

		char **nicks = malloc(sizeof(*nicks) * 1000);
		int i;
		for (i = 0; i < 1000; i++)
			nicks[i] = malloc(sizeof(**nicks) * 30);
		int count = llist_get_nicknames(&list_start, nicks);

		memset(buffer, 0, 1024);
		for (i = 0; i < count; i++) {
			sprintf(buffer, "%s%s%s%s", buffer, color_magenta, nicks[i], color_normal);
			if(i != (count - 1)) sprintf(buffer, "%s, ", buffer);
			if(i == (count - 1)) sprintf(buffer, "%s\r\n", buffer);
			free(nicks[i]);
		}
		sendto(list_entry->client_info->sockfd, buffer, strlen(buffer), 0,
				(struct sockaddr *)&(list_entry->client_info->address), (socklen_t)socklen);
		free(nicks);
	}
	
	/* Broadcast message */
	if (processed == FALSE)
	{
		send_broadcast_msg("%s%s:%s %s\r\n", color_green, list_entry->client_info->nickname, color_normal, message);
		logline(LOG_INFO, "%s: %s", list_entry->client_info->nickname, message);
	}

	/* Dump current user list */
	llist_show(&list_start);
	
	/* Free memory */
	regfree(&regex_quit);
	regfree(&regex_nick);
	regfree(&regex_msg);
	regfree(&regex_me);
	regfree(&regex_who);
}
Ejemplo n.º 3
0
/*
 * Process a chat message coming from a chat client.
 */
void process_msg(char *message, int self_sockfd)
{
        char buffer[BUF_SIZE_1K];
        char statsBuf[BUF_SIZE_1K];
        regex_t regex_quit;
        regex_t regex_nick;
        regex_t regex_msg;
        //regex_t regex_me;
        regex_t regex_stats;
        int ret;
        char newnick[20];
        char oldnick[20];
        char priv_nick[20];
        struct list_entry *list_entry = NULL;
        struct list_entry *nick_list_entry = NULL;
        struct list_entry *priv_list_entry = NULL;
        int processed = FALSE;
        size_t ngroups = 0;
        size_t len = 0;
        regmatch_t groups[3];

        memset(buffer, 0, BUF_SIZE_1K);
        memset(newnick, 0, 20);
        memset(oldnick, 0, 20);
        memset(priv_nick, 0, 20);

        /* Load client info object */
        list_entry = llist_find_by_sockfd(&list_start, self_sockfd);
       /* Remove \r\n from message */
        chomp(message);

        /* Compile regex patterns */
        regcomp(&regex_quit, "^/logout$", REG_EXTENDED);
        regcomp(&regex_nick, "^/chatName ([a-zA-Z0-9_]{1,19})$", REG_EXTENDED);
        regcomp(&regex_msg, "^/privateMessage ([a-zA-Z0-9_]{1,19}) (.*)$", REG_EXTENDED);
        regcomp(&regex_stats, "^/showStats$", REG_EXTENDED);

        /* Check if user wants to quit */
        ret = regexec(&regex_quit, message, 0, NULL, 0);
        if (ret == 0)
        {
                /* Notify */
                send_broadcast_msg("\n%sUser: %s has left the chat server.%s\n\r\n",
                        color_magenta, list_entry->client_info->nickname, color_normal);
                printf("\nUser: %s has left the chat server.\n", list_entry->client_info->nickname);
                pthread_mutex_lock(&curr_thread_count_mutex);
                curr_thread_count--;
                pthread_mutex_unlock(&curr_thread_count_mutex);

                /* Remove entry from linked list */
                llist_remove_by_sockfd(&list_start, self_sockfd);
		serverStats.num_of_active_connections--;

                /* Disconnect client from server */
                close(self_sockfd);

                /* Free memory */
                regfree(&regex_quit);
                regfree(&regex_nick);
                regfree(&regex_msg);
                regfree(&regex_stats);
               /* Terminate this thread */
                pthread_exit(0);
        }

        /* Check if user wants to change nick */
        ngroups = 2;
        ret = regexec(&regex_nick, message, ngroups, groups, 0);
        if (ret == 0)
        {
                processed = TRUE;

                /* Extract nickname */
                len = groups[1].rm_eo - groups[1].rm_so;
                strncpy(newnick, message + groups[1].rm_so, len);
                strcpy(oldnick, list_entry->client_info->nickname);

                strcpy(buffer, "User: "******" is now known as - ");
                strcat(buffer, newnick);

                /* Change nickname. Check if nickname already exists first. */
                nick_list_entry = llist_find_by_nickname(&list_start, newnick);
                if (nick_list_entry == NULL)
                {
                        change_nickname(oldnick, newnick);
                        send_broadcast_msg("\n\n%s\n%s\n%s\n\r\n", color_yellow, buffer, color_normal);
                        printf("Broadcast Message is sent for username change\n"); 
                }
                else
                {
                        send_private_msg(oldnick, "%sCHATSRV: Cannot change nickname. Nickname already in use.%s\r\n",
                                color_yellow, color_normal);
                        printf("Private message from CHATSRV to %s: Cannot change nickname. Nickname already in use\n",
                                oldnick);
                }
        }

        /* Check if user wants to transmit a private message to another user */
        ngroups = 3;
        ret = regexec(&regex_msg, message, ngroups, groups, 0);
        if (ret == 0)
        {
                processed = TRUE;

                /* Extract nickname and private message */
                len = groups[1].rm_eo - groups[1].rm_so;
                memcpy(priv_nick, message + groups[1].rm_so, len);
                len = groups[2].rm_eo - groups[2].rm_so;
                memcpy(buffer, message + groups[2].rm_so, len);

                /* Check if nickname exists. If yes, send private message to user. 
                 * If not, ignore message.
                 */
                priv_list_entry = llist_find_by_nickname(&list_start, priv_nick);
                if (priv_list_entry != NULL)
                {
                        send_private_msg(priv_nick, "%s %s:\n%s %s %s %s\r\n", color_green, list_entry->client_info->nickname,
                                color_normal, color_red, buffer, color_normal);
                        printf("Private message from %s to %s: %s\n",
                                list_entry->client_info->nickname, priv_nick, buffer);
                }
        }

        /* Check if user wants to say something about himself */
        ngroups = 2; //TODO:
        ret = regexec(&regex_stats, message, ngroups, groups, 0);
        if (ret == 0)
        {
               processed = TRUE;
              int socklen = sizeof(list_entry->client_info->address);

                printf("%s requested the client list\n", list_entry->client_info->nickname);

                char **nicks = malloc(sizeof(*nicks) * 1000);
                int i;
                for (i = 0; i < 1000; i++)
                        nicks[i] = malloc(sizeof(**nicks) * 30);
                int count = llist_get_nicknames(&list_start, nicks);

                memset(buffer, 0, BUF_SIZE_1K);
                for (i = 0; i < count; i++) {
                        sprintf(buffer, "%s%s%s%s", buffer, color_magenta, nicks[i], color_normal);
                        if(i != (count - 1)) sprintf(buffer, "%s, ", buffer);
                        if(i == (count - 1)) sprintf(buffer, "%s\r\n", buffer);
                        free(nicks[i]);
                }


		memset(statsBuf, 0, BUF_SIZE_1K);	
		sprintf(statsBuf, "Max threads: %d\nNumber of active connections: %d\nNumber of clients serviced: %d\nNumber of clients dropped:%d\n",serverStats.max_threads, serverStats.num_of_active_connections,serverStats.num_of_clients_serviced, serverStats.num_of_conn_dropped);	
		printf("Server Stats : \n%s\n", statsBuf);		
                sendto(list_entry->client_info->sockfd, buffer, strlen(buffer), 0,
                                (struct sockaddr *)&(list_entry->client_info->address), (socklen_t)socklen);
                sendto(list_entry->client_info->sockfd, statsBuf, strlen(statsBuf), 0,
                                (struct sockaddr *)&(list_entry->client_info->address), (socklen_t)socklen);
                free(nicks);
        }

        /* Broadcast message */
        if (processed == FALSE)
        {
                send_broadcast_msg("%s%s:%s %s\r\n", color_green, list_entry->client_info->nickname, color_normal, message);
                printf("%s: %s", list_entry->client_info->nickname, message);
        }

        /* Dump current user list */
        llist_show(&list_start);

        /* Free memory */
        regfree(&regex_quit);
        regfree(&regex_nick);
        regfree(&regex_msg);
	regfree(&regex_stats);
}
Ejemplo n.º 4
0
/*
 * This method is run on a per-connection basis in a separate thred.
 */
void proc_client(int *arg)
{
	char buffer[1024];
	char message[1024];
	int ret = 0;
	int len = 0;
	int socklen = 0;
	struct list_entry *list_entry;
	fd_set readfds;
	int sockfd = 0;
	
	/* Load associated client info */
	sockfd = *arg;
	list_entry = llist_find_by_sockfd(&list_start, sockfd);
	
	memset(message, 0, 1024);
	FD_ZERO(&readfds);
	FD_SET(sockfd, &readfds);

	/* Send welcome message */
	send_welcome_msg(sockfd);

	/* Announce to others using broadcast */
	send_broadcast_msg("%sUser %s joined the chat.%s\r\n", color_magenta, list_entry->client_info->nickname, color_normal);

	/* Process requests */
	while (1)
	{
		ret = select(FD_SETSIZE, &readfds, (fd_set *)0, 
			(fd_set *)0, (struct timeval *) 0);
		if (ret == -1)
		{
			logline(LOG_ERROR, "Error calling select() on thread.");
			perror(strerror(errno));
		}
		else
		{
			/* Read data from stream */
			memset(buffer, 0, 1024);
			socklen = sizeof(list_entry->client_info->address);
			len = recvfrom(sockfd, buffer, sizeof(buffer), 0, 
				(struct sockaddr *)&list_entry->client_info->address, (socklen_t *)&socklen);

			logline(LOG_DEBUG, "proc_client(): Receive buffer contents = %s", buffer);

			/* Copy receive buffer to message buffer */
			if (sizeof(message) - strlen(message) > strlen(buffer))
			{
				strcat(message, buffer);
			}
			
			/* Check if message buffer contains a full message. A full message
			 * is recognized by its terminating \n character. If a message
			 * is found, process it and clear message buffer afterwards.
			 */
			char *pos = strstr(message, "\n");
			if (pos != NULL)
			{		  		
				chomp(message);
				logline(LOG_DEBUG, "proc_client(): Message buffer contents = %s", message);
				logline(LOG_DEBUG, "proc_client(): Complete message received.");

		  		/* Process message */
		  		process_msg(message, sockfd);
		  		memset(message, 0, 1024);	
			}
			else
			{
				logline(LOG_DEBUG, "proc_client(): Message buffer contents = %s", message);
				logline(LOG_DEBUG, "proc_client(): Message still incomplete.");
			}
		}
	}
}
Ejemplo n.º 5
0
void server_read_client(void *arg)
/// This function runs in a thread for every client, and reads incoming data.
/// It also writes the incoming data to all other clients.
{
        char buffer[BUF_SIZE_1K];
        char message[BUF_SIZE_1K];
        int ret = 0;
        int len = 0;
        int socklen = 0;
        struct list_entry *list_entry;
        fd_set readfds;
        int sockfd = 0;

        /* Load associated client info */
        sockfd = *(int *)arg;
        list_entry = llist_find_by_sockfd(&list_start, sockfd);

        memset(message, 0, BUF_SIZE_1K);
        FD_ZERO(&readfds);
        FD_SET(sockfd, &readfds);
        /* Send welcome message */
	server_write_welcome_client(sockfd);
        /* Announce to others using broadcast */
        send_broadcast_msg("\n%sUser: %s joined the chat.%s\n\r\n", color_magenta, list_entry->client_info->nickname, color_normal);

        /* Process requests */
        while (1)
        {
                ret = select(FD_SETSIZE, &readfds, (fd_set *)0,
                        (fd_set *)0, (struct timeval *) 0);
                if (ret == -1)
                {
                        printf("Error calling select() on thread.\n");
		  }
                else
                {
                        /* Read data from stream */
                        memset(buffer, 0, BUF_SIZE_1K);
                        socklen = sizeof(list_entry->client_info->address);
                        len = recvfrom(sockfd, buffer, sizeof(buffer), 0,
                                (struct sockaddr *)&list_entry->client_info->address, (socklen_t *)&socklen);

                        /* Copy receive buffer to message buffer */
                        if (sizeof(message) - strlen(message) > strlen(buffer))
                        {
                                strcat(message, buffer);
                        }

                        /* Check if message buffer contains a full message. A full message
                         * is recognized by its terminating \n character. If a message
                         * is found, process it and clear message buffer afterwards.
                         */
                        char *pos = strstr(message, "\n");
                        if (pos != NULL)
                        {
                                chomp(message);
                                /*Code will be useful for Our Project */
                                /* Process message */
                                process_msg(message, sockfd);
                                memset(message, 0, BUF_SIZE_1K);
                        }
                        else
                        {
                                printf("Message still incomplete....\n");
                        }
                }
        }
}