|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | #define MAX_EVENTS       512 | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* Every client need get a stand alone buffer to save TLV packet data */ | 
|---|
|  |  |  | typedef struct cli_buf_s | 
|---|
|  |  |  | { | 
|---|
|  |  |  | int                  fd;         /* client fd  */ | 
|---|
|  |  |  | char                 buf[512];   /* client receive buffer */ | 
|---|
|  |  |  | int                  bytes;      /* left bytes in buffer  */ | 
|---|
|  |  |  | struct list_head     list;       /* all client buffer saved in a list */ | 
|---|
|  |  |  | } cli_buf_t; | 
|---|
|  |  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | static void term_socket_client(int epollfd, int fd, struct list_head *buf_list); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | static void banner(void) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | printf("Version %s build on %s %s\n", PROG_VERSION, __DATE__, __TIME__); | 
|---|
|  |  |  | 
|---|
|  |  |  | socket_t              sock; | 
|---|
|  |  |  | int                   epollfd; | 
|---|
|  |  |  | int                   connfd; | 
|---|
|  |  |  | int                   fd; | 
|---|
|  |  |  | int                   nfds; | 
|---|
|  |  |  | struct epoll_event    event_array[MAX_EVENTS]; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | char                  buf[1024]; | 
|---|
|  |  |  | cli_buf_t            *cli_buf; | 
|---|
|  |  |  | cli_buf_t            *node; | 
|---|
|  |  |  | struct list_head      buf_list; /* every client get a stand alone buffer saved in the list */ | 
|---|
|  |  |  |  | 
|---|
|  |  |  | struct option long_options[] = { | 
|---|
|  |  |  | {"port", required_argument, NULL, 'p'}, | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | memset(&logger, 0, sizeof(logger)); | 
|---|
|  |  |  | memset(&sock, 0, sizeof(sock)); | 
|---|
|  |  |  | INIT_LIST_HEAD(&buf_list); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | progname = basename(argv[0]); /* get program name */ | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | /* nfds>0 is the active events count */ | 
|---|
|  |  |  | for(i=0; i<nfds; i++) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | fd = event_array[i].data.fd; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* epoll get error  */ | 
|---|
|  |  |  | if ( (event_array[i].events&EPOLLERR) || (event_array[i].events&EPOLLHUP) ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | log_err("epoll_wait get error on fd[%d]: %s\n", event_array[i].data.fd, strerror(errno)); | 
|---|
|  |  |  | epoll_del(epollfd, event_array[i].data.fd); | 
|---|
|  |  |  | close(event_array[i].data.fd); | 
|---|
|  |  |  | log_err("epoll_wait get error on fd[%d]: %s\n", fd, strerror(errno)); | 
|---|
|  |  |  | if( fd != sock.fd ) | 
|---|
|  |  |  | term_socket_client(epollfd, event_array[i].data.fd, &buf_list); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* listen socket get event means new client start connect now */ | 
|---|
|  |  |  | if( event_array[i].data.fd == sock.fd ) | 
|---|
|  |  |  | if( fd == sock.fd ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | /* accept new client socket  */ | 
|---|
|  |  |  | if( (connfd=accept(sock.fd, (struct sockaddr *)NULL, NULL)) < 0) | 
|---|
|  |  |  | 
|---|
|  |  |  | log_nrml("accept new client failure: %s\n", strerror(errno)); | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | log_info("accept new client socket[%d]\n", connfd); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* add new client socket into epoll  */ | 
|---|
|  |  |  | if( epoll_add(epollfd, connfd) < 0 ) | 
|---|
|  |  |  | 
|---|
|  |  |  | close(connfd); | 
|---|
|  |  |  | log_err("epoll add client socket failure, rv=%d\n", rv); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | log_dbg("epoll add new client socket[%d] ok.\n", connfd); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* malloc client buffer and add it into list */ | 
|---|
|  |  |  | if( NULL != (cli_buf=(cli_buf_t *)malloc(sizeof(*cli_buf))) ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | memset(cli_buf, 0, sizeof(cli_buf)); | 
|---|
|  |  |  | cli_buf->fd = connfd; | 
|---|
|  |  |  | list_add_tail(&cli_buf->list, &buf_list); | 
|---|
|  |  |  | log_info("alloc and add socket[%d] buffer[%p] into list\n", cli_buf->fd, cli_buf); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | log_nrml("accept and add new client socket[%d] ok.\n", connfd); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | /* already connected client socket get data arrive  */ | 
|---|
|  |  |  | else | 
|---|
|  |  |  | { | 
|---|
|  |  |  | rv=read(event_array[i].data.fd, buf, sizeof(buf)); | 
|---|
|  |  |  | cli_buf = NULL; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* Use list_for_each_entry to find the client buf in  buf list */ | 
|---|
|  |  |  | list_for_each_entry(node, &buf_list, list) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if( node->fd == fd ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | log_info("found socket[%d] buffer[%p] in list\n", fd, node); | 
|---|
|  |  |  | cli_buf = node; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if( !cli_buf ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | log_err("can not find socket[%d] buffer and close it now\n", fd); | 
|---|
|  |  |  | term_socket_client(epollfd, fd, NULL); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | rv=read(fd, &cli_buf->buf[cli_buf->bytes], sizeof(cli_buf->buf)-cli_buf->bytes); | 
|---|
|  |  |  | if( rv <= 0 ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | printf("socket[%d] read failure [%s] or disconncet, close and remove now.\n", | 
|---|
|  |  |  | event_array[i].data.fd, strerror(errno)); | 
|---|
|  |  |  | log_warn("socket[%d] read failure [%s] or disconncet, terminate it now.\n", | 
|---|
|  |  |  | fd, strerror(errno)); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | epoll_del(epollfd, event_array[i].data.fd); | 
|---|
|  |  |  | close( event_array[i].data.fd ); | 
|---|
|  |  |  | term_socket_client(epollfd, fd, &buf_list); | 
|---|
|  |  |  | continue; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | else | 
|---|
|  |  |  | { | 
|---|
|  |  |  | log_dbg("socket[%d] receive %d bytes data\n", event_array[i].data.fd, rv); | 
|---|
|  |  |  | logger_dump(LOG_LEVEL_INFO, buf, rv); | 
|---|
|  |  |  | log_dbg("socket[%d] receive %d bytes data\n", fd, rv); | 
|---|
|  |  |  | logger_dump(LOG_LEVEL_INFO, cli_buf->buf, rv); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | 
|---|
|  |  |  | return 0; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | static void term_socket_client(int epollfd, int fd, struct list_head *buf_list) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | cli_buf_t          *buf, *tmp; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | log_warn("start terminatl client socket[%d]\n", fd); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /* if get buf_list, then remove buf from list */ | 
|---|
|  |  |  | if( buf_list ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | /* Use list_for_each_entry_safe to travel the socket list and destroy the buffer */ | 
|---|
|  |  |  | list_for_each_entry_safe(buf, tmp, buf_list, list) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | if( buf->fd == fd ) | 
|---|
|  |  |  | { | 
|---|
|  |  |  | list_del(&buf->list); | 
|---|
|  |  |  | free(buf); | 
|---|
|  |  |  | log_info("free socket[%d] buffer[%p]\n", fd, buf); | 
|---|
|  |  |  | break; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | epoll_del(epollfd, fd); | 
|---|
|  |  |  | close( fd ); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|