Advertisement
Guest User

chatserv 1.1

a guest
Dec 16th, 2012
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.20 KB | None | 0 0
  1. /* charserv 1.1
  2.  * by Daemonio (Marcos Paulo Ferreira)
  3.  * undefinido gmail com
  4.  *
  5.  * chatserv
  6.  * Handles incoming connections from (MAX_USERS)
  7.  * users and redirect a message from an user
  8.  * to all the others. I create this code
  9.  * to play around on those boring classes on
  10.  * college. Now they are more interesting.
  11.  *
  12.  * My first goal was to create a shell script
  13.  * that would handle all connections using
  14.  * netcat. I made the script but it seems that
  15.  * every system I put my hands in has a
  16.  * different version of nc.
  17.  * So I code this simple server in C that will
  18.  * run in all linux boxes with no problems,
  19.  * and of course, to practice my select skills. :/
  20.  *
  21.  * How to use:
  22.  * $ ./chatserv 2020
  23.  *
  24.  * Now the clients has to do:
  25.  *
  26.  * $ nc <server address> 2020
  27.  *
  28.  * To type in one terminal and see everything
  29.  * you has received in another one:
  30.  *
  31.  * $ nc -lp 2021                                  (in console 1)
  32.  * $ nc <server address> 2020 | nc localhost 2021 (in console 2)
  33.  *
  34.  * Now you will type your messages in console 2
  35.  * and see what you got in console 1.
  36.  *
  37.  * If you a programmer you can easily create
  38.  * a chat client that, for example, colorize
  39.  * a message, transfer files, change nicks, etc ...
  40.  * keep in mind that you have to create a
  41.  * small protocol to facilitate the communication
  42.  * between clients. (hey, isn't that the fun part??)
  43.  *
  44.  * Tue Oct 19 19:52:35 BRST 2010
  45.  * Tue Oct 19 22:18:10 BRST 2010
  46.  * Tue Oct 19 23:48:20 BRST 2010
  47.  * Wed Oct 20 12:18:40 BRST 2010
  48.  *
  49.  * Sun Dec 16 08:43:47 BRST 2012
  50.  *
  51.  */
  52. #include <stdio.h>
  53. #include <string.h>
  54. #include <stdlib.h>
  55. #include <netinet/in.h>
  56. #include <sys/types.h>
  57. #include <sys/socket.h>
  58. #include <sys/times.h>
  59. #include <sys/select.h>
  60. #include <unistd.h>
  61.  
  62. #define SERVER_BUSY "Sorry. The server is busy. bye\n"
  63.  
  64. #define MAX_USERS 20
  65. #define MSG_LEN 4096
  66. #define NICK_LEN 20
  67.  
  68. struct stclient {
  69. char nick[NICK_LEN+1] ;
  70. int sockfd ;
  71. int flag_has_nick ;
  72. int flag_is_connected ;
  73. } ;
  74.  
  75. struct stclient *list_of_clients ;
  76.  
  77. int socket_listening ;
  78. /* for select() */
  79. fd_set select_set ;
  80.  
  81.  
  82. int  max_users = MAX_USERS ;
  83.  
  84. /* grows up everytime an user
  85.  * got a connection.
  86.  * this variable stores the
  87.  * current list size.*/
  88. int  list_len = 0 ;
  89.  
  90. /* the user message */
  91. char msg[MSG_LEN+1] ;
  92.  
  93. void show_help(char *name) {
  94. printf("Chatserv 1.0\n") ;
  95. printf("by Daemonio (undefinido gmail com)\n\n") ;
  96. printf("[uso] %s <port> [<max_users>]\n", name) ;
  97. }
  98.  
  99. /* clean client struct */
  100. void clean_stclient(struct stclient *c) {
  101.     c->nick[0] = 0 ; c->nick[NICK_LEN] = 0 ;
  102.     c->sockfd = -1 ;
  103.     c->flag_has_nick = 0;
  104.     c->flag_is_connected = 0;
  105. }
  106.  
  107. /* if it's possible to insert a socket in
  108.  * the list, this function returns 0 and
  109.  * 1 otherwise.
  110.  */
  111. char insert_socket_into_list(int socket) {
  112.     int i ;
  113.  
  114.     if ( list_len == max_users ) {
  115.         return 1 ;
  116.     }
  117.  
  118.     for ( i = 0; i < max_users; i++ ) {
  119.         if ( list_of_clients[i].sockfd == -1 ) {
  120.             list_of_clients[i].flag_is_connected = 1 ;
  121.             list_of_clients[i].sockfd = socket ;
  122.             list_len++ ;
  123.             break ;
  124.         }
  125.     }
  126.     return 0 ;
  127. }
  128.  
  129. /* searches for a socket in the list
  130.  * and closes it.
  131.  */
  132. void remove_socket_from_list(int _sock) {
  133.     int i ;
  134.  
  135.     for ( i = 0; i < max_users; i++ ) {
  136.         if ( list_of_clients[i].sockfd == _sock ) {
  137.             close(list_of_clients[i].sockfd) ;
  138.             clean_stclient(&list_of_clients[i]) ;
  139.             list_len-- ;
  140.             break ;
  141.         }
  142.     }
  143. }
  144.  
  145. /* gets the message from an user.
  146.  * this message will be in `msg'.
  147.  * Returns 0 if the message was delivered
  148.  * succesfully and 1 if the client
  149.  * has finished the connection.
  150.  */
  151. char get_message_from_socket(int _sock) {
  152.     int t ;
  153.  
  154.     memset(msg,0x0,MSG_LEN+1) ;
  155.     t = recv(_sock, msg, MSG_LEN, 0 ) ;
  156.  
  157.     if ( t == 0 ) {
  158.         remove_socket_from_list(_sock) ;
  159.         return 1 ;
  160.     }
  161.  
  162.     return 0 ;
  163. }
  164.  
  165. /* after we got the message from the user,
  166.  * we'll send it to all the others here.
  167.  * note that an user cant send a message
  168.  * to himself (list_of_clients[i] != _sock).
  169.  */
  170. void send_message_to_all(int _sock, int flag_system_msg) {
  171.     int i ;
  172.     char newmsg[MSG_LEN+1] ;
  173.     struct stclient from ;
  174.  
  175.     /* gets who is sending the message */
  176.     for ( i = 0; i < max_users; i++ ) {
  177.         if ( list_of_clients[i].sockfd == _sock ) {
  178.              from = list_of_clients[i] ;
  179.         }
  180.     }
  181.  
  182.     for ( i = 0; i < max_users; i++ ) {
  183.         if ( (list_of_clients[i].sockfd != -1)    &&
  184.              (list_of_clients[i].sockfd != _sock) &&
  185.              (list_of_clients[i].sockfd != socket_listening) ) {
  186.  
  187.             if(flag_system_msg == 0) {
  188.                  snprintf(newmsg, MSG_LEN, "<%s> said: %s", from.nick, msg) ;
  189.             }
  190.  
  191.             send(list_of_clients[i].sockfd, newmsg, strlen(newmsg), 0) ;
  192.         }
  193.     }
  194. }
  195.  
  196.  
  197. int main(int argc, char **argv) {
  198.     int port ;
  199.     int t    ;
  200.  
  201.     struct sockaddr_in server ;
  202.     struct timeval select_time ;
  203.  
  204.     if ( argc == 1 ) {
  205.         show_help(argv[0]) ;
  206.         return -1 ;
  207.     }
  208.  
  209.     if ( argc > 2 ) {
  210.         max_users = atoi(argv[2]) ;
  211.     }
  212.  
  213.     port = atoi(argv[1]) ;
  214.  
  215.     socket_listening = socket(AF_INET, SOCK_STREAM, 0) ;
  216.  
  217.     if ( socket_listening < 0 ) {
  218.         perror("socket") ;
  219.         return -1 ;
  220.     }
  221.  
  222.     server.sin_family = AF_INET ;
  223.     server.sin_port = htons(port) ;
  224.     server.sin_addr.s_addr = INADDR_ANY ;
  225.  
  226.     t = sizeof(struct sockaddr_in) ;
  227.     if ( bind( socket_listening, (struct sockaddr *) &server, t ) < 0 ) {
  228.         perror("bind") ;
  229.         return -1 ;
  230.     }
  231.  
  232.     if ( listen(socket_listening, 5) < 0 ) {
  233.         perror("listen") ;
  234.         return -1 ;
  235.     }
  236.  
  237.     /* create the list of sockets.
  238.      * for each client, there is a socket in this list.
  239.      */
  240.     list_of_clients = (struct stclient *) malloc( max_users * sizeof(struct stclient) ) ;
  241.     if ( list_of_clients == NULL ) {
  242.         perror("malloc") ;
  243.         return -1 ;
  244.     }
  245.  
  246.     /* "clean up" the list. */
  247.     for ( t = 0; t < max_users; t++ )
  248.         clean_stclient(&list_of_clients[t]) ;
  249.  
  250.     /* you'll need a ctrl+c to break this loop */
  251.     while ( 1 ) {
  252.         /* gets all the sockets and put in a
  253.          * fd_set struct. */
  254.         FD_ZERO(&select_set) ;
  255.         FD_SET(socket_listening, &select_set) ;
  256.         for ( t = 0; list_len > 0 && t < max_users; t++ ) {
  257.             if ( list_of_clients[t].sockfd != -1 ) {
  258.                 FD_SET(list_of_clients[t].sockfd, &select_set) ;
  259.             }
  260.         }
  261.  
  262.         printf("[+] Listening on %d [%d/%d] ...\n", port, list_len, max_users) ;
  263.  
  264.         /* select will wait 2 seconds before
  265.          * returning. */
  266.         select_time.tv_sec = 2 ;
  267.         select_time.tv_usec = 0 ;
  268.  
  269.         /* select returns:
  270.          * < 0 if error.
  271.          * = 0 if nothing happened
  272.          * > 0 number of sockets on the sets
  273.          */
  274.         if ( (t=select(FD_SETSIZE, &select_set, NULL, NULL, &select_time)) < 0 ) {
  275.             perror("select") ;
  276.             return -1 ;
  277.         }
  278.  
  279.         /* wow, we have something ... */
  280.         if ( t > 0 ) {
  281.             /* if it's the listening socket, we have to
  282.              * accept the incoming connection and add
  283.              * the new socket in the list. */
  284.             if ( FD_ISSET(socket_listening, &select_set) ) {
  285.                 int n ;
  286.  
  287.                 if ( (n=accept(socket_listening, NULL, NULL)) < 0 ) {
  288.                     perror("accept") ;
  289.                 } else if ( insert_socket_into_list(n) == 1 ) { /* server is busy */
  290.                     send(n,SERVER_BUSY,strlen(SERVER_BUSY),0) ;
  291.                     close(n) ;
  292.                 }
  293.                 continue ;
  294.             } else {
  295.                 int i ;
  296.  
  297.                 /* handle the incoming data. */
  298.                 for ( i = 0; i < max_users; i++ ) {
  299.                     if ( FD_ISSET(list_of_clients[i].sockfd, &select_set) ) {
  300.                         if ( get_message_from_socket(list_of_clients[i].sockfd) == 0 ) {
  301.                             int flag_system_msg = 0 ;
  302.  
  303.                             if(list_of_clients[i].flag_has_nick == 0) { /* setting the nickname */
  304.                                   list_of_clients[i].flag_has_nick = 1 ;
  305.                                   strncpy(list_of_clients[i].nick, msg, NICK_LEN) ;
  306.  
  307.                                   /* remove trailling '\n' */
  308.                                   if(list_of_clients[i].nick[strlen(list_of_clients[i].nick)-1]=='\n') {
  309.                                         list_of_clients[i].nick[strlen(list_of_clients[i].nick)-1]=0 ;
  310.                                   }
  311.  
  312.                                   snprintf(msg, MSG_LEN, "%s : is now on the chat!\n", list_of_clients[i].nick) ;
  313.                                   /* if it is 1, doenst include the prefix "<nick> said: " on message */
  314.                                   flag_system_msg = 1 ;
  315.                             }
  316.                             send_message_to_all(list_of_clients[i].sockfd, flag_system_msg) ;
  317.                         }
  318.                     }
  319.                 }
  320.             }
  321.         }
  322.     } /* while */
  323.  
  324.     return 0 ;
  325. } /* main */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement