From d81310d55b9b7d07904c19f879f50e52fd7be489 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Mon, 06 Nov 2023 16:52:08 +0800
Subject: [PATCH] Add new code
---
prj1_tlv/tlv_server.c | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 286 insertions(+), 5 deletions(-)
diff --git a/prj1_tlv/tlv_server.c b/prj1_tlv/tlv_server.c
index f0e2d56..43251b6 100644
--- a/prj1_tlv/tlv_server.c
+++ b/prj1_tlv/tlv_server.c
@@ -19,10 +19,30 @@
#include "logger.h"
#include "proc.h"
+#include "socket.h"
+#include "tlv_pack.h"
+#include "crc-itu-t.h"
#define PROG_VERSION "1.0.0"
#define DEF_LOG_FILE "tlv_server.log"
+#define DEF_LISTEN_IP "0.0.0.0"
+#define DEF_LISTEN_PORT 10086
+
+#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 int parser_tlvpack(cli_buf_t *cli_buf);
+static void term_socket_client(int epollfd, int fd, struct list_head *buf_list);
static void banner(void)
{
@@ -52,8 +72,9 @@
{
int opt;
int i = 0;
- //int rv = 0;
+ int rv = 0;
int debug = 0;
+ int port = DEF_LISTEN_PORT;
char pid_file[64] = { 0 }; /* The file used to record the PID */
const char *progname=NULL;
@@ -62,7 +83,19 @@
char *log_file = DEF_LOG_FILE;
logger_t logger;
+ socket_t sock;
+ int epollfd;
+ int connfd;
+ int fd;
+ int nfds;
+ struct epoll_event event_array[MAX_EVENTS];
+
+ 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'},
{"debug", no_argument, NULL, 'd'},
{"level", required_argument, NULL, 'l'},
{"version", no_argument, NULL, 'v'},
@@ -71,14 +104,19 @@
};
memset(&logger, 0, sizeof(logger));
+ memset(&sock, 0, sizeof(sock));
+ INIT_LIST_HEAD(&buf_list);
progname = basename(argv[0]); /* get program name */
/* parser the command line parameters */
- while ((opt = getopt_long(argc, argv, "c:dl:vh", long_options, NULL)) != -1)
+ while ((opt = getopt_long(argc, argv, "p:dl:vh", long_options, NULL)) != -1)
{
switch (opt)
{
+ case 'p': /* listen port */
+ port = atoi(optarg);
+ break;
case 'd': /* set debug running */
debug = 1;
@@ -105,6 +143,12 @@
}
}
+ if( port <= 0 )
+ {
+ printf("ERROR: no listen port specified, refer to program usage\n\n");
+ program_usage(progname);
+ }
+
/* check program already running or not, if already running then exit, or set running as daemon */
snprintf(pid_file, sizeof(pid_file), "/var/run/%s.pid", progname);
if( !debug )
@@ -114,6 +158,8 @@
printf("Programe already running, exit now.\n");
return -1;
}
+
+ set_daemon_running(pid_file);
}
/* initial and open logger system */
@@ -126,13 +172,120 @@
/* install signal proc handler */
install_proc_signal();
- log_nrml("Program start running\n");
+ log_nrml("TLV server program start running\n");
+
+ /* set open file description number to max */
+ set_socket_rlimit();
+
+ /* initial listen socket */
+ if( socket_listen(&sock, DEF_LISTEN_IP, port) < 0 )
+ {
+ log_err("create listen socket failure\n");
+ return -2;
+ }
+
+ /* create epoll and put listen socket into it */
+ if( (epollfd=epoll_init(MAX_EVENTS, sock.fd)) < 0 )
+ {
+ log_err("initial epoll for listen socket failure\n");
+ return -2;
+ }
/* g_signal.stop defined in proc.c, and will be set when catch stop signal */
while( !g_signal.stop )
{
- log_dbg("Program still running\n");
- sleep(3);
+ /* epoll wailt and program will blocked here */
+ nfds = epoll_wait(epollfd, event_array, MAX_EVENTS, -1 /* never timeout */);
+ if( nfds <= 0 )
+ {
+ log_err("epoll_wait failure or timeout: %s\n", strerror(errno));
+ continue;
+ }
+
+ /* 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", 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( 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;
+ }
+
+ /* 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);
+ }
+
+ /* 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
+ {
+ 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 )
+ {
+ log_warn("socket[%d] read failure [%s] or disconncet, terminate it now.\n",
+ fd, strerror(errno));
+
+ term_socket_client(epollfd, fd, &buf_list);
+ continue;
+ }
+ else
+ {
+ cli_buf->bytes += rv;
+ log_dbg("socket[%d] receive %d bytes data\n", fd, rv);
+ }
+
+ parser_tlvpack(cli_buf);
+ }
+ }
+
+ sleep(1);
}
logger_term();
@@ -140,3 +293,131 @@
return 0;
}
+static int parser_tlvpack(cli_buf_t *cli_buf)
+{
+ int i;
+ int left_bytes;
+ unsigned short crc16;
+ tlv_pack_t *tlv_pack;
+
+ if( !cli_buf )
+ {
+ log_err("Invalid input arguments\n");
+ return -1;
+ }
+
+ log_info("start to parser client buffer %d bytes data:\n", cli_buf->bytes);
+ logger_dump(LOG_LEVEL_INFO, cli_buf->buf, cli_buf->bytes);
+
+ if( cli_buf->bytes < TLV_MIN_SIZE )
+ {
+ log_warn("TLV packet bytes less than min. size\n");
+ return -2;
+ }
+
+PARSER_AGAIN:
+ for(i=0; i<cli_buf->bytes; i++)
+ {
+ if( PACK_HEADER == (unsigned char )cli_buf->buf[i] )
+ {
+ log_dbg("found TLV packet header on [%d]\n", i);
+ left_bytes = cli_buf->bytes - i;
+
+ if(left_bytes < TLV_MIN_SIZE)
+ {
+ log_warn("TLV packet bytes less than min. size\n");
+ memmove(cli_buf->buf, &cli_buf->buf[i], left_bytes);
+ cli_buf->bytes = left_bytes;
+ break;
+ }
+
+ tlv_pack = (tlv_pack_t *) &cli_buf->buf[i];
+ log_info("header: 0x%02x tag: 0x%02x len: 0x%02x\n", tlv_pack->header, tlv_pack->tag, tlv_pack->len);
+
+ if(tlv_pack->len > left_bytes )
+ {
+ log_err("TLV packet not integrated, continue to receive left data\n");
+ memmove(cli_buf->buf, &cli_buf->buf[i], left_bytes);
+ cli_buf->bytes = left_bytes;
+ break;
+ }
+
+ if( tlv_pack->len > TLV_MAX_SIZE )
+ {
+ log_err("TLV packet length more than max. length, maybe found wrong header?\n");
+
+ /* skip current header */
+ left_bytes -= 1;
+ memmove(cli_buf->buf, &cli_buf->buf[i+1], left_bytes);
+ cli_buf->bytes = left_bytes;
+ goto PARSER_AGAIN;
+ }
+
+ crc16 = crc_itu_t(MAGIC_CRC, (unsigned char *)&cli_buf->buf[i], tlv_pack->len-2);
+ if( crc16 != bytes_to_ushort((unsigned char *)&cli_buf->buf[i+tlv_pack->len-2], 2) )
+ {
+ log_err("TLV packet CRC check error, maybe found wrong header?\n");
+
+ /* skip current header */
+ left_bytes -= 1;
+ memmove(cli_buf->buf, &cli_buf->buf[i+1], left_bytes);
+ cli_buf->bytes = left_bytes;
+
+ goto PARSER_AGAIN;
+ }
+
+ if( tlv_pack->tag == TAG_SN )
+ {
+ log_nrml("Found SN TLV data:\n");
+ dump_buf(tlv_pack->data, tlv_pack->len-TLV_FIXED_SIZE);
+ }
+ else if( tlv_pack->tag == TAG_TEMP )
+ {
+ log_nrml("Found temperature TLV data:\n");
+ dump_buf(tlv_pack->data, tlv_pack->len-TLV_FIXED_SIZE);
+ }
+ else if( tlv_pack->tag == TAG_TIME )
+ {
+ log_nrml("Found date time TLV data:\n");
+ dump_buf(tlv_pack->data, tlv_pack->len-TLV_FIXED_SIZE);
+ }
+
+ left_bytes -= tlv_pack->len;
+ memmove(cli_buf->buf, &cli_buf->buf[i+tlv_pack->len], left_bytes);
+ cli_buf->bytes = left_bytes;
+
+ log_info("left %d bytes data:\n", cli_buf->bytes);
+ logger_dump(LOG_LEVEL_INFO, cli_buf->buf, cli_buf->bytes);
+ goto PARSER_AGAIN;
+ }
+ }
+
+ 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 );
+}
+
--
Gitblit v1.9.1