Advertisement
Guest User

non-blocking tcp/ip Chat Server

a guest
Jul 25th, 2014
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.77 KB | None | 0 0
  1. /*
  2.    Basic non-blocking TCP/IP Chat Server Source Code
  3.  
  4.  
  5.  * Copyright (c) 2014 JUAN JOSE FERNANDEZ LOPEZ
  6.  * All rights reserved.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18.  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  19.  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  20.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
  21.  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27.  * POSSIBILITY OF SUCH DAMAGE.
  28.  
  29.  
  30.    Contact: Current Cel & email - 7873973266 - jjfl.88@aol.com
  31.  
  32.  
  33.    Example client: $ nc serverhosturlorip 6660 [enter]
  34.                    INPUT: myname [enter]
  35.                    INPUT: THE MESSAGE [enter]
  36.                    OUTPUT: myname> THE MESSAGE
  37.    
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #include <errno.h>
  44. #include <unistd.h>
  45. #include <sys/socket.h>
  46. #include <sys/types.h>
  47. #include <sys/stat.h>
  48. #include <netinet/in.h>
  49. #include <netinet/tcp.h>
  50. #include <arpa/inet.h>
  51. #include <poll.h>    
  52. #include <signal.h>  
  53. #include <time.h>
  54. #include <fcntl.h>
  55. #include <netdb.h>  
  56. #define PORT 6660  
  57.  
  58. struct pollfd *fds;
  59.  
  60. /* used to record client information */
  61.  
  62. typedef struct {
  63.   int fd;
  64.   char name[260];
  65.   _Bool nameset:1;
  66. } client;
  67.  
  68. client *clnt;
  69.  
  70. /* set-up ipv4 address */
  71.  
  72. void setipv4address(struct sockaddr_in * serv_addr)
  73. {
  74.    serv_addr[0].sin_family = AF_INET;
  75.    serv_addr[0].sin_addr.s_addr = INADDR_ANY;
  76.    serv_addr[0].sin_port = htons((uint16_t)PORT);
  77. }
  78.  
  79. /* signal handling */
  80.  
  81. void terminate(int n) {
  82.    free(fds);
  83.    free(clnt);
  84.    exit(n);
  85. }
  86.  
  87. int main(void)
  88. {
  89.    /* BSD DAEMON */
  90.    void daemonize();
  91.  
  92.    void setipv4address(struct sockaddr_in *);
  93.    void terminate(int);
  94.    int sockfd,i,read_val,msglen,seconds;
  95.    int tcp_protocol_number = (getprotobyname("tcp"))->p_proto;
  96.    char buff[256];
  97.    char msg[500];
  98.    nfds_t nfds,x;
  99.    int on;
  100.    socklen_t cli_addr_len;
  101.    struct sockaddr_in serv_addr, cli_addr;    
  102.    
  103.    daemonize();
  104.    cli_addr_len = sizeof(cli_addr);
  105.    sockfd = socket(AF_INET, SOCK_STREAM, 0);
  106.    seconds=25;
  107.    on=1;
  108.    signal(SIGINT,terminate);
  109.    signal(SIGTERM,terminate);
  110.    signal(SIGPIPE,SIG_IGN);
  111.    setipv4address(&serv_addr);
  112.    if((bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr))) == -1)
  113.    {
  114.       exit(EXIT_FAILURE);
  115.    }
  116.    if((listen(sockfd,5)) == -1) {
  117.       exit(EXIT_FAILURE);
  118.    }
  119.    nfds = 1;
  120.    if(!(clnt = (client *) calloc (1,nfds * sizeof(client))))
  121.    {
  122.      perror("ERROR: ");
  123.      exit(EXIT_FAILURE);
  124.    }
  125.    if(!(fds = (struct pollfd *) calloc(1,nfds * sizeof(struct pollfd))))
  126.    {
  127.      perror("ERROR: ");
  128.      exit(EXIT_FAILURE);
  129.    }
  130.  
  131.    fds[0].fd = sockfd;
  132.    fds[0].events = POLLIN;
  133.    clnt[0].fd = sockfd;
  134.    clnt[0].name[0]='\0';
  135.  
  136.    while(1) {
  137.       poll(fds,nfds,-1);
  138.       for(i=0; (i < (int) nfds); ++i)
  139.       {
  140.  
  141.          if( !i  && (fds[i].revents & POLLIN)  ) {
  142.  
  143.             clnt = (client *)        realloc(clnt,((nfds+1) * sizeof(client)));
  144.             fds =  (struct pollfd *) realloc(fds, ((nfds+1) * sizeof(struct pollfd)));
  145.  
  146.             if((fds[nfds].fd = accept(sockfd,(struct sockaddr *) &cli_addr, &cli_addr_len)) != -1)
  147.             {
  148.  
  149.                 if( (fcntl(fds[nfds].fd,F_SETFL,O_NONBLOCK)) == -1) {
  150.                      perror("fcntl() = -1: ");
  151.                 }
  152.  
  153. #ifdef TCP_KEEPIDLE
  154.                 if((setsockopt(fds[nfds].fd,tcp_protocol_number,TCP_KEEPIDLE,&seconds,sizeof(seconds))) == -1) {
  155.                      perror("setsockopt() == -1 1: ");
  156.                 }
  157. #endif
  158.  
  159.                 if((setsockopt(fds[nfds].fd,SOL_SOCKET,SO_KEEPALIVE,&on,sizeof(on))) == -1) {
  160.                      perror("setsockopt() == -1 2: ");
  161.                 }
  162.  
  163.                 fds[nfds].events = POLLRDNORM;
  164.                 clnt[nfds].nameset = 0;
  165.                 clnt[nfds].fd = fds[nfds].fd;
  166.  
  167.             }
  168.  
  169.             else
  170.             {
  171.                free(fds);
  172.                free(clnt);
  173.                perror("ERROR> -1 on accept(): ");
  174.                exit(EXIT_FAILURE);
  175.             }
  176.  
  177.             ++nfds;
  178.          }
  179.  
  180.  
  181.          else if( fds[i].revents & (POLLNVAL | POLLHUP | POLLERR) ) {
  182.             if(!(fds[i].events & POLLNVAL)) {
  183.                close(fds[i].fd);
  184.             }
  185.             --nfds;
  186.                if((nfds - i) == 0) {
  187.                  x=1;
  188.                }
  189.                else {
  190.                  x=nfds-1;
  191.                }
  192.             memcpy((&(clnt[i])), (&(clnt[i+1])),sizeof(clnt) * (x));
  193.             memcpy( (&(fds[i])), (&(fds[i+1])),sizeof(struct pollfd) * (x));
  194.             fds = (struct pollfd *) realloc( fds, ( nfds * (sizeof(struct pollfd)) ) );
  195.             clnt = (client *) realloc( clnt, ( nfds * (sizeof(client)) ) );
  196.          }
  197.  
  198.          else if( (i != 0) && (fds[i].revents & POLLRDNORM) ) {
  199.             read_val = read(fds[i].fd,buff,255);          
  200.             buff[read_val] = '\0';
  201.  
  202.             if(read_val <= 0) {
  203.                if(!(read_val)) {
  204.                   close(fds[i].fd);
  205.                }
  206.                --nfds;
  207.                if((nfds - i) == 0) {
  208.                  x=1;
  209.                }
  210.                else {
  211.                  x=nfds-1;
  212.                }
  213.                memcpy( (&(clnt[i])), (&(clnt[i+1])),sizeof(client) * (x));
  214.                memcpy( (&(fds[i])), (&(fds[i+1])), sizeof(struct pollfd) * (x));
  215.                fds = (struct pollfd *) realloc( fds, ( nfds * (sizeof(struct pollfd)) ) );
  216.                clnt = (client *) realloc( clnt, ( nfds * (sizeof(client)) ) );
  217.             }
  218.  
  219.             else {
  220.                if((clnt[i].nameset)) {
  221.                  x=1;
  222.                  msg[0]='\0';
  223.                  strcat(msg,clnt[i].name);
  224.                  strcat(msg,"> ");
  225.                  strcat(msg,buff);
  226.                  msglen=strlen(msg);
  227.                  while(x < nfds)
  228.                  {
  229.                     write(clnt[x].fd,msg,msglen);
  230.                     ++x;
  231.                  }
  232.                }
  233.  
  234.                else {
  235.                   clnt[i].nameset = 1;
  236.                   clnt[i].name[0] = '\0';
  237.                   if(buff[(strlen(buff))-1] == '\n') {
  238.                     buff[(strlen(buff))-1] = '\0';
  239.                   }
  240.                   strcat(clnt[i].name,buff);
  241.                }
  242.             }
  243.  
  244.          }
  245.          
  246.       }
  247.    }
  248.  
  249.    /*
  250.       Flow never reach here
  251.    */
  252.    free(fds);
  253.    free(clnt);
  254.    return 0;
  255. }
  256.  
  257. void daemonize()
  258. {
  259.      pid_t pid;                           /* PROCESS ID                                                  */
  260.      pid_t sid;                           /* SESSION ID (SAME AS PID)                                    */
  261.      pid = fork();                        /* NEW CHILD                                                   */
  262.      if (pid < 0)                         /* ERROR HANDLING                                              */
  263.         exit(EXIT_FAILURE);
  264.      if (pid > 0)
  265.         exit(EXIT_SUCCESS);               /* SAY BYEBYE TO FATHER                                        */
  266.      umask(0);                            /* TO BE SURE WE HAVE ACCESS TO ANY GENERATED FILE FROM DAEMON */
  267.      sid = setsid();                      /* WE OWN OUR OWN PLACE                                        */
  268.      if (sid < 0)                         /* ERROR HANDLING                                              */
  269.         exit(EXIT_FAILURE);
  270.      if((chdir("/")) < 0)                /* CHANGE TO A PATH THAT WILL ALWAYS BE THERE                  */
  271.         exit(EXIT_FAILURE);
  272.      close(STDIN_FILENO);                 /* CLOSE STANDARD INPUT                                        */
  273.      close(STDOUT_FILENO);                /* CLOSE STANDARD OUTPUT                                       */
  274.      close(STDERR_FILENO);                /* CLOSE STANDARD ERROR OUTPUT                                 */
  275. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement