Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* charserv 1.2
- * by Daemonio (Marcos Paulo Ferreira)
- * undefinido gmail com
- *
- * chatserv
- * Handles incoming connections from (MAX_USERS)
- * users and redirect a message from an user
- * to all the others. I create this code
- * to play around on those boring classes on
- * college. Now they are more interesting.
- *
- * My first goal was to create a shell script
- * that would handle all connections using
- * netcat. I made the script but it seems that
- * every system I put my hands in has a
- * different version of nc.
- * So I code this simple server in C that will
- * run in all linux boxes with no problems,
- * and of course, to practice my select skills. :/
- *
- * How to use:
- * $ ./chatserv 2020
- *
- * Now the clients has to do:
- *
- * $ nc <server address> 2020
- *
- * To type in one terminal and see everything
- * you has received in another one:
- *
- * $ nc -lp 2021 (in console 1)
- * $ nc <server address> 2020 | nc localhost 2021 (in console 2)
- *
- * Now you will type your messages in console 2
- * and see what you got in console 1.
- *
- * If you a programmer you can easily create
- * a chat client that, for example, colorize
- * a message, transfer files, change nicks, etc ...
- * keep in mind that you have to create a
- * small protocol to facilitate the communication
- * between clients. (hey, isn't that the fun part??)
- *
- * Tue Oct 19 19:52:35 BRST 2010
- * Tue Oct 19 22:18:10 BRST 2010
- * Tue Oct 19 23:48:20 BRST 2010
- * Wed Oct 20 12:18:40 BRST 2010
- *
- * Sun Dec 16 08:43:47 BRST 2012
- * Thu Dec 20 16:54:06 BRST 2012
- *
- * Thu Apr 4 22:54:12 BRT 2013 - wendev, version 1.0
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/times.h>
- #include <sys/select.h>
- #include <unistd.h>
- #define SERVER_BUSY "Sorry. The server is busy. bye\n"
- #define MAX_USERS 20
- #define MSG_LEN 4096
- #define NICK_LEN 20
- struct stclient {
- char nick[NICK_LEN+1] ;
- int sockfd ;
- int flag_has_nick ;
- int flag_is_connected ;
- } ;
- struct stclient *list_of_clients ;
- int socket_listening ;
- /* for select() */
- fd_set select_set ;
- int max_users = MAX_USERS ;
- /* grows up everytime an user
- * got a connection.
- * this variable stores the
- * current list size.*/
- int list_len = 0 ;
- /* the user message */
- char msg[MSG_LEN+1] ;
- void show_help(char *name) {
- printf("Chatserv 1.0\n") ;
- printf("by Daemonio (undefinido gmail com)\n\n") ;
- printf("[uso] %s <port> [<max_users>]\n", name) ;
- }
- /* clean client struct */
- void clean_stclient(struct stclient *c) {
- c->nick[0] = 0 ; c->nick[NICK_LEN] = 0 ;
- c->sockfd = -1 ;
- c->flag_has_nick = 0;
- c->flag_is_connected = 0;
- }
- /* if it's possible to insert a socket in
- * the list, this function returns 0 and
- * 1 otherwise.
- */
- char insert_socket_into_list(int socket) {
- int i ;
- if ( list_len == max_users ) {
- return 1 ;
- }
- for ( i = 0; i < max_users; i++ ) {
- if ( list_of_clients[i].sockfd == -1 ) {
- list_of_clients[i].flag_is_connected = 1 ;
- list_of_clients[i].sockfd = socket ;
- list_len++ ;
- break ;
- }
- }
- return 0 ;
- }
- /* after we got the message from the user,
- * we'll send it to all the others here.
- * note that an user cant send a message
- * to himself (list_of_clients[i] != _sock).
- */
- void send_message_to_all(int _sock, int flag_system_msg) {
- int i ;
- struct stclient from ;
- /* gets who is sending the message */
- for ( i = 0; i < max_users; i++ ) {
- if ( list_of_clients[i].sockfd == _sock ) {
- from = list_of_clients[i] ;
- }
- }
- for ( i = 0; i < max_users; i++ ) {
- if ( (list_of_clients[i].sockfd != -1) &&
- (list_of_clients[i].sockfd != _sock) &&
- (list_of_clients[i].sockfd != socket_listening) ) {
- if(flag_system_msg == 0) {
- char newmsg[MSG_LEN+1] ;
- snprintf(newmsg, MSG_LEN, "<%s> said: %s", from.nick, msg) ;
- send(list_of_clients[i].sockfd, newmsg, strlen(newmsg), 0) ;
- } else if (msg[0] != '\n') { // do not send empty msg
- send(list_of_clients[i].sockfd, msg, strlen(msg), 0) ;
- }
- }
- }
- }
- void send_message_to_user(int _sock) {
- int i ;
- struct stclient from ;
- char tonick[NICK_LEN+1], *p ;
- /* gets who is sending the message */
- for ( i = 0; i < max_users; i++ ) {
- if ( list_of_clients[i].sockfd == _sock ) {
- from = list_of_clients[i] ;
- }
- }
- /* destination nick */
- if((p = strchr(msg, ' '))==NULL) return ; // NULL if invalid synthax
- *p=0; strncpy(tonick, msg+1, NICK_LEN) ;
- /* searches for the given nick */
- for ( i = 0; i < max_users; i++ ) {
- if ( (list_of_clients[i].sockfd != -1) &&
- (list_of_clients[i].sockfd != _sock) &&
- (list_of_clients[i].sockfd != socket_listening) &&
- (strcmp(list_of_clients[i].nick, tonick)== 0) ) {
- char newmsg[MSG_LEN+1] ;
- snprintf(newmsg, MSG_LEN, "<%s> said exclusively to you: %s", from.nick, p+1) ;
- send(list_of_clients[i].sockfd, newmsg, strlen(newmsg), 0) ;
- }
- }
- }
- /* searches for a socket in the list
- * and closes it.
- */
- void remove_socket_from_list(int _sock) {
- int i ;
- for ( i = 0; i < max_users; i++ ) {
- if ( list_of_clients[i].sockfd == _sock ) {
- sprintf(msg, "%s has quit.\n", list_of_clients[i].nick) ;
- send_message_to_all(list_of_clients[i].sockfd, 1) ;
- close(list_of_clients[i].sockfd) ;
- clean_stclient(&list_of_clients[i]) ;
- list_len-- ;
- break ;
- }
- }
- }
- /* gets the message from an user.
- * this message will be in `msg'.
- * Returns 0 if the message was delivered
- * succesfully and 1 if the client
- * has finished the connection.
- */
- char get_message_from_socket(int _sock) {
- int t ;
- memset(msg,0x0,MSG_LEN+1) ;
- t = recv(_sock, msg, MSG_LEN, 0 ) ;
- if ( t == 0 ) {
- remove_socket_from_list(_sock) ;
- return 1 ;
- }
- return 0 ;
- }
- int main(int argc, char **argv) {
- int port ;
- int t ;
- struct sockaddr_in server ;
- struct timeval select_time ;
- if ( argc == 1 ) {
- show_help(argv[0]) ;
- return -1 ;
- }
- if ( argc > 2 ) {
- max_users = atoi(argv[2]) ;
- }
- port = atoi(argv[1]) ;
- socket_listening = socket(AF_INET, SOCK_STREAM, 0) ;
- if ( socket_listening < 0 ) {
- perror("socket") ;
- return -1 ;
- }
- server.sin_family = AF_INET ;
- server.sin_port = htons(port) ;
- server.sin_addr.s_addr = INADDR_ANY ;
- t = sizeof(struct sockaddr_in) ;
- if ( bind( socket_listening, (struct sockaddr *) &server, t ) < 0 ) {
- perror("bind") ;
- return -1 ;
- }
- if ( listen(socket_listening, 5) < 0 ) {
- perror("listen") ;
- return -1 ;
- }
- /* create the list of sockets.
- * for each client, there is a socket in this list.
- */
- list_of_clients = (struct stclient *) malloc( max_users * sizeof(struct stclient) ) ;
- if ( list_of_clients == NULL ) {
- perror("malloc") ;
- return -1 ;
- }
- /* "clean up" the list. */
- for ( t = 0; t < max_users; t++ )
- clean_stclient(&list_of_clients[t]) ;
- /* you'll need a ctrl+c to break this loop */
- while ( 1 ) {
- /* gets all the sockets and put in a
- * fd_set struct. */
- FD_ZERO(&select_set) ;
- FD_SET(socket_listening, &select_set) ;
- for ( t = 0; list_len > 0 && t < max_users; t++ ) {
- if ( list_of_clients[t].sockfd != -1 ) {
- FD_SET(list_of_clients[t].sockfd, &select_set) ;
- }
- }
- printf("[+] Listening on %d [%d/%d] ...\n", port, list_len, max_users) ;
- /* select will wait 2 seconds before
- * returning. */
- select_time.tv_sec = 2 ;
- select_time.tv_usec = 0 ;
- /* select returns:
- * < 0 if error.
- * = 0 if nothing happened
- * > 0 number of sockets on the sets
- */
- if ( (t=select(FD_SETSIZE, &select_set, NULL, NULL, &select_time)) < 0 ) {
- perror("select") ;
- return -1 ;
- }
- /* wow, we have something ... */
- if ( t > 0 ) {
- /* if it's the listening socket, we have to
- * accept the incoming connection and add
- * the new socket in the list. */
- if ( FD_ISSET(socket_listening, &select_set) ) {
- int n ;
- if ( (n=accept(socket_listening, NULL, NULL)) < 0 ) {
- perror("accept") ;
- } else if ( insert_socket_into_list(n) == 1 ) { /* server is busy */
- send(n,SERVER_BUSY,strlen(SERVER_BUSY),0) ;
- close(n) ;
- }
- continue ;
- } else {
- int i ;
- /* handle the incoming data. */
- for ( i = 0; i < max_users; i++ ) {
- if ( FD_ISSET(list_of_clients[i].sockfd, &select_set) ) {
- if ( get_message_from_socket(list_of_clients[i].sockfd) == 0 ) {
- int flag_system_msg = 0 ;
- if(list_of_clients[i].flag_has_nick == 0) { /* setting the nickname */
- list_of_clients[i].flag_has_nick = 1 ;
- strncpy(list_of_clients[i].nick, msg, NICK_LEN) ;
- /* remove trailling '\n' */
- if(list_of_clients[i].nick[strlen(list_of_clients[i].nick)-1]=='\n') {
- list_of_clients[i].nick[strlen(list_of_clients[i].nick)-1]=0 ;
- }
- snprintf(msg, MSG_LEN, "%s : is now on the chat!\n", list_of_clients[i].nick) ;
- /* if it is 1, doenst include the prefix "<nick> said: " on message */
- flag_system_msg = 1 ;
- } else if(msg[0] == '@') { /* if starts with an '@', sends private msg */
- send_message_to_user(list_of_clients[i].sockfd) ;
- } else { /* otherwise, sends msg to everybody */
- send_message_to_all(list_of_clients[i].sockfd, flag_system_msg) ;
- }
- }
- }
- }
- }
- }
- } /* while */
- return 0 ;
- } /* main */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement