From dc4b04335bd8086487dfcd332082b324e3bbdf3c Mon Sep 17 00:00:00 2001
From: Guo Wenxue <guowenxue@gmail.com>
Date: Mon, 18 Apr 2022 21:11:01 +0800
Subject: [PATCH] Add socket project

---
 apue/project_socket/src/sqlite_blob.c    |  265 +++++
 apue/project_socket/do.sh                |    4 
 apue/project_socket/main/server_main.c   |  278 ++++++
 apue/project_socket/makefile             |   16 
 apue/project_socket/src/ds18b20.c        |  113 ++
 apue/project_socket/src/util_time.h      |  186 ++++
 apue/project_socket/main/makefile        |   20 
 apue/project_socket/src/socket.h         |  100 ++
 apue/project_socket/src/sqlite_blob.h    |   60 +
 apue/project_socket/src/socket.c         |  465 ++++++++++
 apue/project_socket/libs/cjson/build.sh  |   42 
 apue/project_socket/src/packet.h         |   59 +
 apue/project_socket/src/makefile         |   29 
 apue/project_socket/main/client_main.c   |  251 +++++
 apue/project_socket/src/logger.h         |   52 +
 apue/project_socket/src/packet.c         |   67 +
 apue/project_socket/libs/makefile        |   10 
 apue/project_socket/src/util_proc.c      |  433 +++++++++
 apue/project_socket/src/util_proc.h      |   65 +
 apue/project_socket/src/ds18b20.h        |   31 
 apue/project_socket/libs/sqlite/build.sh |   44 
 apue/project_socket/src/logger.c         |  165 +++
 22 files changed, 2,755 insertions(+), 0 deletions(-)

diff --git a/apue/project_socket/do.sh b/apue/project_socket/do.sh
new file mode 100755
index 0000000..b07abc2
--- /dev/null
+++ b/apue/project_socket/do.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+make
+./main/client_main -i 127.0.0.1 -p 8888 -I 30 -d
diff --git a/apue/project_socket/libs/cjson/build.sh b/apue/project_socket/libs/cjson/build.sh
new file mode 100755
index 0000000..2e72a9d
--- /dev/null
+++ b/apue/project_socket/libs/cjson/build.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# libraries install path
+INST_PATH=`pwd`/../install
+
+# LingYun studio FTP server address for all the open source code
+LYFTP_SRC=ftp://master.iot-yun.club/src/
+
+# set shell script exit when any command failure
+set -e
+
+# funciton used to build cjson source code
+function build_cjson()
+{
+   SRC_NAME=cJSON-1.7.15
+
+   if [ -L $INST_PATH/lib/libcjson.so ] ; then
+      echo "$SRC_NAME already compile and installed"
+      return ;
+   fi
+
+   # If source code tarball file not exist, it will download the packet.
+   if [ ! -f ${SRC_NAME}.tar.gz ] ; then
+      wget ${LYFTP_SRC}/${SRC_NAME}.tar.gz
+   fi
+
+
+   # If source code folder not exist, decompress the tarball packet
+   if [ ! -d ${SRC_NAME} ] ; then
+      tar -xzf ${SRC_NAME}.tar.gz
+   fi
+
+   cd ${SRC_NAME}
+
+   make && make DESTDIR=${INST_PATH} PREFIX=/ install
+
+   cd -
+}
+
+# start build cjson
+
+build_cjson
diff --git a/apue/project_socket/libs/makefile b/apue/project_socket/libs/makefile
new file mode 100644
index 0000000..8b2a24d
--- /dev/null
+++ b/apue/project_socket/libs/makefile
@@ -0,0 +1,10 @@
+all:
+	cd sqlite && ./build.sh
+	cd cjson && ./build.sh
+
+clean:
+	cd sqlite && rm -rf sqlite*
+	cd cjson && rm -rf c*
+
+distclean: clean
+	rm -rf install
diff --git a/apue/project_socket/libs/sqlite/build.sh b/apue/project_socket/libs/sqlite/build.sh
new file mode 100755
index 0000000..10e13a0
--- /dev/null
+++ b/apue/project_socket/libs/sqlite/build.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# library install path
+INST_PATH=`pwd`/../install
+
+# LingYun studio FTP server address for all the open source code
+LYFTP_SRC=ftp://master.iot-yun.club/src/
+
+# set shell script exit when any command failure
+set -e
+
+#define a funciton to build sqlite source code
+function build_sqlite()
+{
+   SRC_NAME=sqlite-autoconf-3380200
+
+   if [ -L $INST_PATH/lib/libsqlite3.so ] ; then
+	  echo "$SRC_NAME already compile and installed"
+	  return ;
+   fi
+
+   # If source code tarball file not exist, it will download the packet.
+   if [ ! -f ${SRC_NAME}.tar.gz ] ; then
+      #wget https://sqlite.org/2022/${SRC_NAME}.tar.gz
+      wget ${LYFTP_SRC}/${SRC_NAME}.tar.gz
+   fi
+
+
+   # If source code folder not exist, decompress the tarball packet
+   if [ ! -d ${SRC_NAME} ] ; then
+      tar -xzf ${SRC_NAME}.tar.gz
+   fi
+
+   cd ${SRC_NAME}
+
+   ./configure --prefix=${INST_PATH} --enable-static
+
+   make && make install
+}
+
+
+# call function to start build sqlite
+
+build_sqlite
diff --git a/apue/project_socket/main/client_main.c b/apue/project_socket/main/client_main.c
new file mode 100644
index 0000000..9c8c604
--- /dev/null
+++ b/apue/project_socket/main/client_main.c
@@ -0,0 +1,251 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <time.h>
+
+#include "logger.h"
+#include "ds18b20.h"
+#include "packet.h"
+#include "socket.h"
+#include "sqlite_blob.h"
+#include "util_proc.h"
+
+
+void print_usage(char *progname)
+{
+	printf("%s usage: \n", progname);
+	printf("-i(--ipaddr)  : sepcify server IP address\n");
+	printf("-p(--port)    : sepcify server port.\n");
+	printf("-I(--interval): sepcify report interval time\n");
+	printf("-s(--sn)      : sepcify device serial number\n");
+	printf("-d(--debug)   : run as debug mode\n");
+	printf("-h(--Help)    : print this help information.\n");
+
+	return ;
+}
+
+static int check_sample_time(time_t *last_time, int interval);
+
+int main(int argc, char **argv)
+{
+	int                  rv = -1;
+	int                  pr_times = 0;
+	int                  port;
+	char                *serverip;
+	int                  interval = 30; /* default report termperature every 30 seconds */
+	int                  sn = 1;        /* default serial number for device ID */
+	int                  debug = 0;     /* running in debug mode or not */
+	char                *logfile="client.log";
+
+	socket_ctx_t         sock;
+	time_t               last_time = 0;
+	int                  sample_flag = 0;
+
+	char                 pack_buf[1024];
+	int                  pack_bytes;
+	pack_info_t          pack_info;
+	pack_proc_t          pack_proc = packet_string_pack; /* use string packet */
+
+  	struct option        opts[] = {
+		{"ipaddr", required_argument, NULL, 'i'},
+		{"port", required_argument, NULL, 'p'},
+		{"interval", no_argument, NULL, 'I'},
+		{"debug", no_argument, NULL, 'd'},
+		{"sn", required_argument, NULL, 's'},
+		{"help", no_argument, NULL, 'h'},
+		{NULL, 0, NULL, 0}
+	};
+
+	while( (rv=getopt_long(argc, argv, "i:p:dI:s:h", opts, NULL)) != -1 )
+	{
+		switch(rv)
+		{
+			case 'i':
+				serverip=optarg;
+				break;
+
+			case 'p':
+				port=atoi(optarg);
+				break;
+
+			case 'd':
+				debug=1;
+				break;
+
+			case 'I':
+				interval=atoi(optarg);
+				break;
+
+			case 's':
+				sn=atoi(optarg);
+				break;
+
+			case 'h':
+				print_usage(argv[0]);
+				return 0;
+		}
+
+	}
+
+	if( !serverip || !port )
+	{
+		print_usage(argv[0]);
+		return 0;
+	}
+
+	if( debug )
+	{
+		/* set logger to standard output with level debug */
+		logger_init(NULL, LOG_LEVEL_DEBUG);
+		log_info("set program running on debug now.\n");
+	}
+	else
+	{
+		/* set logger to $logfile with level info */
+		if( logger_init(logfile, LOG_LEVEL_INFO) < 0 )
+		{
+			fprintf(stderr, "Initial logger file '%s' failure: %s\n", strerror(errno));
+			return 1;
+		}
+
+		log_info("set program running on background now.\n");
+		daemon(1, 1); /* don't change work path, don't close opened file descriptor */
+	}
+
+	install_default_signal();
+
+	log_info("program start running.\n");
+
+	if( database_init("client.db") < 0 )
+	{
+		return 2;
+	}
+
+	socket_init(&sock, serverip, port);
+
+	while( !g_signal.stop )
+	{
+		/* +----------------------------------+
+		 * |  check and sample temperature    |
+		 * +----------------------------------+*/
+
+		sample_flag = 0; /* clear sample flag */
+
+		if( check_sample_time(&last_time, interval) )
+		{
+			log_debug("start DS18B20 sample termperature\n");
+
+			if( (rv=ds18b20_get_temperature(&pack_info.temper)) < 0 )
+			{
+				log_error("DS18B20 sample temperature failure, rv=%d\n", rv);
+				continue;
+			}
+			log_info("DS18B20 sample termperature %d.%d oC\n",
+					temper_integer(pack_info.temper), temper_fract(pack_info.temper));
+
+			get_devid(pack_info.devid, DEVID_LEN, sn);
+			get_time(pack_info.strtime, TIME_LEN);
+
+			pack_bytes = pack_proc(&pack_info, pack_buf, sizeof(pack_buf));
+			sample_flag = 1; /* set sample flag */
+		}
+
+		/* +---------------------------------+
+		 * |  check and do socket connect    |
+		 * +---------------------------------+*/
+
+		/* start connect to server if not connected */
+		if( sock.fd < 0 )
+		{
+			if( 0 == (pr_times % 10) )
+			{
+				log_info("socket not connect, start connect it now.\n");
+			}
+			socket_connect(&sock);
+		}
+
+		/* check socket connected or not  */
+		if( sock_check_connect(sock.fd) < 0 )
+		{
+			pr_times ++;
+			if( 0 == (pr_times % 10) )
+			{
+				log_error("socket got disconnected, terminate it and reconnect now.\n");
+				pr_times = 0;
+			}
+			socket_term(&sock); /* close the soket */
+		}
+
+		/* socket disconnected */
+		if( sock.fd < 0 )
+		{
+			if( sample_flag )
+			{
+				blobdb_push_packet(pack_buf, pack_bytes);
+			}
+		}
+		else /* socket connected */
+		{
+			/* +---------------------------------+
+			 * |   socket send sample packet     |
+			 * +---------------------------------+*/
+			if( sample_flag )
+			{
+				log_debug("socket send sample packet bytes[%d]: %s\n", pack_bytes, pack_buf);
+				if( socket_send(&sock, pack_buf, pack_bytes) < 0 )
+				{
+					log_warn("socket send sample packet failure, save it in database now.\n");
+					blobdb_push_packet(pack_buf, pack_bytes);
+					socket_term(&sock); /* close the soket */
+				}
+			}
+
+			/* +---------------------------------+
+			 * | socket send packet in database  |
+			 * +---------------------------------+*/
+			if( !blobdb_pop_packet(pack_buf, sizeof(pack_buf), &pack_bytes) )
+			{
+				log_debug("socket send database packet bytes[%d]: %s\n", pack_bytes, pack_buf);
+				if( socket_send(&sock, pack_buf, pack_bytes) < 0 )
+				{
+					log_error("socket send database packet failure");
+					socket_term(&sock); /* close the soket */
+				}
+				else
+				{
+					log_warn("socket send database packet okay, remove it from database now.\n");
+					blobdb_del_packet();
+				}
+			}
+		}
+
+		sleep(1);
+	}
+
+	socket_term(&sock);
+	database_term();
+
+	return 0;
+}
+
+int check_sample_time(time_t *last_time, int interval)
+{
+	int                  need = 0; /* no need sample now */
+	time_t               now;
+
+	time(&now);
+
+	if( now >= *last_time+interval )
+	{
+		need = 1; /* need sample now  */
+		*last_time = now;
+	}
+
+	return need;
+}
diff --git a/apue/project_socket/main/makefile b/apue/project_socket/main/makefile
new file mode 100644
index 0000000..382b856
--- /dev/null
+++ b/apue/project_socket/main/makefile
@@ -0,0 +1,20 @@
+
+LIBS_PATH=`pwd`/../libs/install/
+
+CFLAGS   += -I ${LIBS_PATH}/include/
+LDFLAGS  += -L ${LIBS_PATH}/lib/ -lbooster
+LDFLAGS  += -lpthread -lsqlite3
+
+SRCFILES = $(wildcard *.c)
+BINARIES=$(SRCFILES:%.c=%)
+
+all: clean ${BINARIES}
+
+%:  %.c
+	$(CC) $(CFLAGS) -o $@ $< ${LDFLAGS}
+
+clean:
+	rm -f ${BINARIES}
+
+distclean: clean
+	rm -f *.log *.db
diff --git a/apue/project_socket/main/server_main.c b/apue/project_socket/main/server_main.c
new file mode 100644
index 0000000..6e69fcd
--- /dev/null
+++ b/apue/project_socket/main/server_main.c
@@ -0,0 +1,278 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <pthread.h>
+#include <getopt.h>
+#include <libgen.h> 
+#include <sys/types.h>   
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h> 
+#include <sys/epoll.h>
+#include <sys/resource.h>
+
+#define MAX_EVENTS          512
+#define ARRAY_SIZE(x)       (sizeof(x)/sizeof(x[0]))
+
+static inline void print_usage(char *progname);
+int socket_server_init(char *listen_ip, int listen_port);
+void set_socket_rlimit(void);
+
+int main(int argc, char **argv)
+{
+    int                       listenfd, connfd;
+    int                       serv_port = 0;
+    int                       daemon_run = 0;
+    char                     *progname = NULL;
+    int                       opt;
+    int                       rv;
+    int                       i, j;
+    int                       found;
+    char                      buf[1024];
+
+    int                       epollfd;
+    struct epoll_event        event;
+    struct epoll_event        event_array[MAX_EVENTS];
+    int                       events;
+     
+    struct option             long_options[] = 
+    {   
+        {"daemon", no_argument, NULL, 'b'},
+        {"port", required_argument, NULL, 'p'},
+        {"help", no_argument, NULL, 'h'},
+        {NULL, 0, NULL, 0}
+    };  
+
+    progname = basename(argv[0]);
+
+    /*  Parser the command line parameters */
+    while ((opt = getopt_long(argc, argv, "bp:h", long_options, NULL)) != -1) 
+    {   
+        switch (opt)
+        {   
+            case 'b':
+                daemon_run=1;
+                break;
+
+            case 'p':
+                serv_port = atoi(optarg);
+                break;
+
+            case 'h':  /*  Get help information */
+                print_usage(progname);
+                return EXIT_SUCCESS;
+
+            default:
+                break;
+        }   
+    }   
+
+    if( !serv_port ) 
+    {   
+        print_usage(progname);
+        return -1; 
+    }
+
+    set_socket_rlimit(); /* set max open socket count */
+
+    if( (listenfd=socket_server_init(NULL, serv_port)) < 0 )
+    {
+        printf("ERROR: %s server listen on port %d failure\n", argv[0],serv_port);
+        return -2;
+    }
+    printf("%s server start to listen on port %d\n", argv[0],serv_port);
+
+
+    /* set program running on background */
+    if( daemon_run ) 
+    {
+        daemon(0, 0);
+    }
+
+    if( (epollfd=epoll_create(MAX_EVENTS)) < 0 )
+    {
+	printf("epoll_create() failure: %s\n", strerror(errno));
+	return -3;
+    }
+
+    //event.events = EPOLLIN|EPOLLET;
+    event.events = EPOLLIN;
+    event.data.fd = listenfd;
+
+    if( epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &event) < 0)
+    {
+	printf("epoll add listen socket failure: %s\n", strerror(errno));
+	return -4;
+    }
+
+
+    for ( ; ; ) 
+    {
+	/* program will blocked here */
+	events = epoll_wait(epollfd, event_array, MAX_EVENTS, -1);
+        if(events < 0)
+        {
+            printf("epoll failure: %s\n", strerror(errno));
+            break;
+        }
+        else if(events == 0)
+        {
+            printf("epoll get timeout\n");
+            continue;
+        }
+
+	/* rv>0 is the active events count */
+	for(i=0; i<events; i++)
+	{
+	    if ( (event_array[i].events&EPOLLERR) || (event_array[i].events&EPOLLHUP) )
+	    {
+		printf("epoll_wait get error on fd[%d]: %s\n", event_array[i].data.fd, strerror(errno));
+		epoll_ctl(epollfd, EPOLL_CTL_DEL, event_array[i].data.fd, NULL);
+		close(event_array[i].data.fd);
+	    }
+
+	    /* listen socket get event means new client start connect now */
+	    if( event_array[i].data.fd == listenfd )
+	    { 
+		if( (connfd=accept(listenfd, (struct sockaddr *)NULL, NULL)) < 0)
+		{
+		    printf("accept new client failure: %s\n", strerror(errno));
+		    continue;
+		}
+
+		event.data.fd = connfd;
+		//event.events =  EPOLLIN|EPOLLET;
+		event.events =  EPOLLIN;
+		if( epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &event) < 0 )
+		{
+		    printf("epoll add client socket failure: %s\n", strerror(errno));
+		    close(event_array[i].data.fd);
+		    continue;
+		}
+	       	printf("epoll add new client socket[%d] ok.\n", connfd);
+	    }
+	    else /* already connected client socket get data incoming */
+	    {
+                if( (rv=read(event_array[i].data.fd, buf, sizeof(buf))) <= 0)
+		{
+                    printf("socket[%d] read failure or get disconncet and will be removed.\n", event_array[i].data.fd);
+		    epoll_ctl(epollfd, EPOLL_CTL_DEL, event_array[i].data.fd, NULL);
+		    close(event_array[i].data.fd);
+		    continue;
+		}
+		else
+		{
+		    printf("socket[%d] read get %d bytes data\n", event_array[i].data.fd, rv);
+
+		    /* convert letter from lowercase to uppercase */
+		    for(j=0; j<rv; j++)
+			buf[j]=toupper(buf[j]);
+
+                    if( write(event_array[i].data.fd, buf, rv) < 0 )
+		    {
+		        printf("socket[%d] write failure: %s\n", event_array[i].data.fd, strerror(errno));
+		       	epoll_ctl(epollfd, EPOLL_CTL_DEL, event_array[i].data.fd, NULL);
+		       	close(event_array[i].data.fd);
+		    } 
+		} 
+	    } 
+	} /* for(i=0; i<rv; i++) */
+    } /* while(1) */
+
+CleanUp:
+    close(listenfd);
+    return 0;
+}
+
+
+static inline void print_usage(char *progname)
+{ 
+    printf("Usage: %s [OPTION]...\n", progname);
+    
+    printf(" %s is a socket server program, which used to verify client and echo back string from it\n", progname); 
+    printf("\nMandatory arguments to long options are mandatory for short options too:\n"); 
+    
+    printf(" -b[daemon ]  set program running on background\n");
+    printf(" -p[port    ]  Socket server port address\n");
+    printf(" -h[help    ]  Display this help information\n");
+    
+
+    printf("\nExample: %s -b -p 8900\n", progname);
+    return ;
+}
+
+
+int socket_server_init(char *listen_ip, int listen_port)
+{
+    struct sockaddr_in        servaddr;
+    int                       rv = 0;
+    int                       on = 1;
+    int                       listenfd;
+
+    if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+    {
+        printf("Use socket() to create a TCP socket failure: %s\n", strerror(errno));
+        return -1;
+    }
+
+    /* Set socket port reuseable, fix 'Address already in use' bug when socket server restart */
+    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+    memset(&servaddr, 0, sizeof(servaddr));
+    servaddr.sin_family = AF_INET;   
+    servaddr.sin_port = htons(listen_port); 
+
+    if( !listen_ip )  /* Listen all the local IP address */
+    {
+        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
+    }
+    else /* listen the specified IP address  */
+    {
+        if (inet_pton(AF_INET, listen_ip, &servaddr.sin_addr) <= 0)
+        {
+            printf("inet_pton() set listen IP address failure.\n");
+	    rv = -2;
+            goto CleanUp;
+        }
+    }
+
+
+    if(bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
+    {
+        printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
+        rv = -3;
+        goto CleanUp;
+    }
+
+    if(listen(listenfd, 13) < 0)
+    {
+        printf("Use bind() to bind the TCP socket failure: %s\n", strerror(errno));
+        rv = -4;
+        goto CleanUp;
+    }
+
+CleanUp:
+    if(rv<0)
+        close(listenfd);
+    else
+        rv = listenfd;
+
+    return rv;
+}
+
+/* Set open file description count to max */
+void set_socket_rlimit(void)
+{
+     struct rlimit limit = {0};
+
+     getrlimit(RLIMIT_NOFILE, &limit );
+     limit.rlim_cur  = limit.rlim_max;
+     setrlimit(RLIMIT_NOFILE, &limit );
+
+     printf("set socket open fd max count to %d\n", limit.rlim_max);
+}
+
diff --git a/apue/project_socket/makefile b/apue/project_socket/makefile
new file mode 100644
index 0000000..52c4271
--- /dev/null
+++ b/apue/project_socket/makefile
@@ -0,0 +1,16 @@
+
+all:
+	make -C libs
+	make -C src  && make install -C src
+	make -C main
+
+clean:
+	make clean -C libs
+	make clean -C src
+	make clean -C main
+
+distclean:
+	make distclean -C libs
+	make distclean -C src
+	make distclean -C main
+	rm -f *.log *.db
diff --git a/apue/project_socket/src/ds18b20.c b/apue/project_socket/src/ds18b20.c
new file mode 100644
index 0000000..d0ea616
--- /dev/null
+++ b/apue/project_socket/src/ds18b20.c
@@ -0,0 +1,113 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  ds18b20.c
+ *    Description:  This file is get temperature by DS18B20 on RaspberryPi
+ *
+ *        Version:  1.0.0(2020年04月15日)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "2020年04月15日 23时14分21秒"
+ *
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "logger.h"
+
+/* File Content:
+   pi@raspberrypi:~/guowenxue $ cat /sys/bus/w1/devices/28-041731f7c0ff/w1_slave
+   3a 01 4b 46 7f ff 0c 10 a5 : crc=a5 YES
+   3a 01 4b 46 7f ff 0c 10 a5 t=19625
+ */
+
+int ds18b20_get_temperature(uint16_t *temp)
+{
+    char            w1_path[50] = "/sys/bus/w1/devices/";
+    char            chip[20];
+    char            buf[128];
+    DIR            *dirp;
+    struct dirent  *direntp;
+    int             fd =-1;
+    char           *ptr;
+    uint8_t        *byte;
+    float           value;
+    int             found = 0;
+
+    if( !temp )
+    {
+        log_error("ERROR: Invalid input arguments\n");
+        return -1;
+    }
+
+    /*+-------------------------------------------------------------------+
+     *|  open dierectory /sys/bus/w1/devices to get chipset Serial Number |
+     *+-------------------------------------------------------------------+*/
+    if((dirp = opendir(w1_path)) == NULL)
+    {
+        log_error("opendir error: %s\n", strerror(errno));
+        return -2;
+    }
+
+    while((direntp = readdir(dirp)) != NULL)
+    {
+        if(strstr(direntp->d_name,"28-"))
+        {
+            /* find and get the chipset SN filename */
+            strcpy(chip,direntp->d_name);
+            found = 1;
+            break;
+        }
+    }
+    closedir(dirp);
+
+    if( !found )
+    {
+        log_error("Can not find ds18b20 in %s\n", w1_path);
+        return -2;
+    }
+
+    /* get DS18B20 sample file full path: /sys/bus/w1/devices/28-xxxx/w1_slave */
+    strncat(w1_path, chip, sizeof(w1_path)-strlen(w1_path));
+    strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path));
+
+    /* open file /sys/bus/w1/devices/28-xxxx/w1_slave to get temperature */
+    if( (fd=open(w1_path, O_RDONLY)) < 0 )
+    {
+        log_error("open %s error: %s\n", w1_path, strerror(errno));
+        return -2;
+    }
+
+    if(read(fd, buf, sizeof(buf)) < 0)
+    {
+        log_error("read %s error: %s\n", w1_path, strerror(errno));
+        close(fd);
+        return -2;
+    }
+
+    ptr = strstr(buf, "t=");
+    if( !ptr )
+    {
+        log_error("ERROR: Can not get temperature\n");
+        close(fd);
+        return -2;
+    }
+
+    ptr+=2;
+
+    /* use two bytes to save temperature value */
+    byte = (uint8_t *)temp;
+    byte[1] = atoi(ptr)/1000;      /* integer part */
+    byte[0] = (atoi(ptr)%1000)/10; /* fractional part, two digits after */
+
+    close(fd);
+    return 0;
+}
diff --git a/apue/project_socket/src/ds18b20.h b/apue/project_socket/src/ds18b20.h
new file mode 100644
index 0000000..b71ae1e
--- /dev/null
+++ b/apue/project_socket/src/ds18b20.h
@@ -0,0 +1,31 @@
+/********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  ds18b20.h
+ *    Description:  This head file is get temperature by DS18B20 on RaspberryPi
+ *
+ *        Version:  1.0.0(2020年04月15日)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "2020年04月15日 23时37分38秒"
+ *
+ ********************************************************************************/
+
+#ifndef  _DS18B20_H_
+#define  _DS18B20_H_
+
+#include <stdint.h>
+
+/*  description: get temperature by DS18B20 on RaspberryPi
+ * return value: 0: Successfully   <0: Failure
+ * output value: $temp: temperature value saved in two bytes:
+ *                     byte[0]: fractional part, two digits after
+ *                     byte[1]: integer part
+ */
+int ds18b20_get_temperature(uint16_t *temp);
+
+#define temper_integer(x)   (((x)>>8) & 0xFF)
+#define temper_fract(x)     ( (x)     & 0xFF)
+
+#endif   /* ----- #ifndef _DS18B20_H_  ----- */
+
diff --git a/apue/project_socket/src/logger.c b/apue/project_socket/src/logger.c
new file mode 100644
index 0000000..66eef8f
--- /dev/null
+++ b/apue/project_socket/src/logger.c
@@ -0,0 +1,165 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2022 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  logger.c
+ *    Description:  This file
+ *
+ *        Version:  1.0.0(15/04/22)
+ *         Author:  LingYun <lingyun@email.com>
+ *      ChangeLog:  1, Release initial version on "15/04/22 10:38:49"
+ *
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <stdarg.h>
+#include <string.h>
+#include "logger.h"
+
+/*
+ * Program name variable is provided by the libc
+ */
+extern const char* __progname;
+#define PROGRAM_NAME __progname
+
+/*
+ * Logger internal sctructure
+ */
+typedef struct logger_s {
+    FILE   *fp;
+    int     loglevel;
+    int     use_stdout;
+} logger_t;
+
+static struct logger_s g_logger;
+
+static const char* LOG_LEVELS[] = {
+    LOG_STRING_ERROR,
+    LOG_STRING_WARN,
+    LOG_STRING_INFO,
+    LOG_STRING_DEBUG
+};
+
+/*
+ * initial logger system
+ */
+int logger_init(char *filename, int loglevel)
+{
+    logger_term();
+
+    g_logger.loglevel = loglevel>LOG_LEVEL_MAX ? LOG_LEVEL_MAX : loglevel;
+
+    /* $filename is NULL or match "stdout"  will use standard output */
+    if( !filename || !strcasecmp(filename, "stdout"))
+    {
+        g_logger.use_stdout = 1;
+        g_logger.fp = stderr;
+    }
+    else
+    {
+        g_logger.use_stdout = 0;
+        g_logger.fp = fopen(filename, "a");
+        if( !g_logger.fp )
+        {
+            fprintf(stderr, "Failed to open file '%s': %s", filename, strerror(errno));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * terminate logger system
+ */
+void logger_term(void)
+{
+    if( !g_logger.fp )
+    {
+        return ;
+    }
+
+    if( !g_logger.use_stdout )
+    {
+        fclose(g_logger.fp);
+    }
+
+    g_logger.use_stdout = 0;
+    g_logger.fp = NULL;
+
+    return ;
+}
+
+
+/*
+ * Logging functions
+ */
+void log_generic(const int level, const char* format, va_list args)
+{
+    char message[256];
+    struct tm* current_tm;
+    time_t time_now;
+
+    vsprintf(message, format, args);
+
+    time(&time_now);
+    current_tm = localtime(&time_now);
+
+    int res = fprintf(g_logger.fp,
+            "<%s> %02i:%02i:%02i [%s] %s"
+                , PROGRAM_NAME
+                , current_tm->tm_hour
+                , current_tm->tm_min
+                , current_tm->tm_sec
+                , LOG_LEVELS[level]
+                , message );
+
+    fflush(g_logger.fp);
+}
+
+void log_error(char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    log_generic(LOG_LEVEL_ERROR, format, args);
+    va_end(args);
+}
+
+void log_warn(char *format, ...)
+{
+    if (g_logger.loglevel < LOG_LEVEL_WARN) {
+        return;
+    }
+
+    va_list args;
+    va_start(args, format);
+    log_generic(LOG_LEVEL_WARN, format, args);
+    va_end(args);
+}
+
+void log_info(char *format, ...)
+{
+    if (g_logger.loglevel < LOG_LEVEL_INFO) {
+        return;
+    }
+
+    va_list args;
+    va_start(args, format);
+    log_generic(LOG_LEVEL_INFO, format, args);
+    va_end(args);
+}
+
+void log_debug(char *format, ...)
+{
+    if (g_logger.loglevel < LOG_LEVEL_DEBUG) {
+        return;
+    }
+
+    va_list args;
+    va_start(args, format);
+    log_generic(LOG_LEVEL_DEBUG, format, args);
+    va_end(args);
+}
+
diff --git a/apue/project_socket/src/logger.h b/apue/project_socket/src/logger.h
new file mode 100644
index 0000000..095c942
--- /dev/null
+++ b/apue/project_socket/src/logger.h
@@ -0,0 +1,52 @@
+/********************************************************************************
+ *      Copyright:  (C) 2022 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  logger.h
+ *    Description:  This head file
+ *
+ *        Version:  1.0.0(15/04/22)
+ *         Author:  LingYun <lingyun@email.com>
+ *      ChangeLog:  1, Release initial version on "15/04/22 10:38:02"
+ *
+ ********************************************************************************/
+
+#ifndef  _LOGGER_H_
+#define  _LOGGER_H_
+
+/*
+ * logger level
+ */
+enum
+{
+	LOG_LEVEL_ERROR,
+	LOG_LEVEL_WARN,
+	LOG_LEVEL_INFO,
+	LOG_LEVEL_DEBUG,
+	LOG_LEVEL_MAX,
+};
+
+/*
+ * logger prefix string for different logging levels
+ */
+#define LOG_STRING_ERROR  "ERROR"
+#define LOG_STRING_WARN   "WARN "
+#define LOG_STRING_INFO   "INFO "
+#define LOG_STRING_DEBUG  "DEBUG"
+
+
+/*
+ * logger initial and terminate functions
+ */
+int logger_init(char *filename, int loglevel);
+void logger_term(void);
+
+/*
+ * logging methods by levels
+ */
+void log_error(char* format, ...);
+void log_warn(char* format, ...);
+void log_info(char* format, ...);
+void log_debug(char* format, ...);
+
+#endif   /* ----- #ifndef _LOGGER_H_  ----- */
diff --git a/apue/project_socket/src/makefile b/apue/project_socket/src/makefile
new file mode 100644
index 0000000..05877f5
--- /dev/null
+++ b/apue/project_socket/src/makefile
@@ -0,0 +1,29 @@
+
+LIBNAME  = booster
+
+PREFIX   ?= `pwd`/../libs/install
+CFLAGS  += -I ${PREFIX}/include
+
+INCFILES = $(wildcard *.h)
+SRCFILES = $(wildcard *.c)
+OBJFILES = $(patsubst %.c,%.o,$(SRCFILES))
+
+all: $(OBJFILES)
+	@${AR} -rcs lib${LIBNAME}.a ${OBJFILES}
+
+%.o : %.c
+	@$(CC) $(CFLAGS) -c $<
+
+clean:
+	@rm -f *.o
+	rm -rf lib${LIBNAME}.*
+
+distclean: clean
+
+install: all
+	install lib${LIBNAME}.* ${PREFIX}/lib
+	install ${INCFILES} ${PREFIX}/include
+
+uninstall:
+	rm -f ${PREFIX}/lib/lib${LIBNAME}.*
+	rm -f ${PREFIX}/include/${INCFILES}
diff --git a/apue/project_socket/src/packet.c b/apue/project_socket/src/packet.c
new file mode 100644
index 0000000..1f1d9f9
--- /dev/null
+++ b/apue/project_socket/src/packet.c
@@ -0,0 +1,67 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2022 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  packet.c
+ *    Description:  This file is packet API functions
+ *                 
+ *        Version:  1.0.0(18/04/22)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "18/04/22 16:30:25"
+ *                 
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include "packet.h"
+#include "logger.h"
+#include "ds18b20.h"
+
+int get_devid(char *devid, int size, int sn)
+{
+	if( !devid || size<DEVID_LEN )
+	{
+		log_error("Invalid input arugments\n");
+		return -1;
+	}
+
+	memset(devid, 0, size);
+	snprintf(devid, size, "rpi#%04d", sn);
+	return 0;
+}
+
+int get_time(char *strtime, int size)
+{
+    time_t now = time(NULL);
+    struct tm *tnow = localtime(&now);
+
+	if( !strtime || size<TIME_LEN )
+	{
+		log_error("Invalid input arugments\n");
+		return -1;
+	}
+
+	snprintf(strtime, size, "%04d-%02d-%2d %02d:%02d:%02d", 
+			tnow->tm_year+1900, tnow->tm_mon+1, tnow->tm_mday,
+			tnow->tm_hour, tnow->tm_min, tnow->tm_sec);
+
+	return 0;
+}
+
+int packet_string_pack(pack_info_t *pack_info, char *pack_buf, int size)
+{
+	if( !pack_info || !pack_buf || size<=0 )
+	{
+		log_error("Invalid input arguments\n");
+		return -1;
+	}
+
+	snprintf(pack_buf, size, "%s|%s|%d.%d", pack_info->devid, pack_info->strtime, 
+			temper_integer(pack_info->temper), temper_fract(pack_info->temper));
+
+	return strlen(pack_buf);
+}
+
+
diff --git a/apue/project_socket/src/packet.h b/apue/project_socket/src/packet.h
new file mode 100644
index 0000000..1c18b84
--- /dev/null
+++ b/apue/project_socket/src/packet.h
@@ -0,0 +1,59 @@
+/********************************************************************************
+ *      Copyright:  (C) 2022 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  packet.h
+ *    Description:  This head file is packet API functions.
+ *
+ *        Version:  1.0.0(18/04/22)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "18/04/22 16:24:40"
+ *                 
+ ********************************************************************************/
+
+
+#ifndef  _PACKET_H_
+#define  _PACKET_H_
+
+#include <stdint.h>
+
+#define DEVID_LEN          16
+#define TIME_LEN           32
+
+typedef struct pack_info_s 
+{
+	char          devid[DEVID_LEN];  /* device ID  */
+	char          strtime[TIME_LEN]; /* sample time  */
+	uint16_t      temper;            /* sample temperature */
+} pack_info_t; 
+
+/* packet function pointer type */
+typedef int (* pack_proc_t)(pack_info_t *pack_info, char *pack_buf, int size);
+
+/*  description: get device ID 
+ *   input args:
+ *               $devid :  device ID string
+ *               $size  :  device ID output buffer size
+ *               $sn    :  serial number
+ * return value: <0: failure   0:ok
+ */
+extern int get_devid(char *devid, int size, int sn);
+
+/*  description: get current system in format "YYYY-MM-DD HH:MM:SS"
+ *   input args:
+ *               $strtime:  time string output buf
+ *               $size   :  time string output buffer size
+ * return value: <0: failure   0:ok
+ */
+extern int get_time(char *strtime, int size);
+
+/*  description: package a string packet in format "devid|time|temper"
+ *   input args:
+ *               $pack_info:  packet data contains devid, time and temperature
+ *               $pack_buf :  packet output buffer
+ *               $size     :  packet output buffer size
+ * return value: <0: failure   >0: packet bytes
+ */
+extern int packet_string_pack(pack_info_t *pack_info, char *pack_buf, int size);
+
+#endif   /* ----- #ifndef _PACKET_H_  ----- */
diff --git a/apue/project_socket/src/socket.c b/apue/project_socket/src/socket.c
new file mode 100644
index 0000000..9de6d1a
--- /dev/null
+++ b/apue/project_socket/src/socket.c
@@ -0,0 +1,465 @@
+/********************************************************************************
+ *      Copyright:  (C) 2022 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  socket.c
+ *    Description:  This file is for socket API functions
+ *
+ *        Version:  1.0.0(18/04/22)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "18/04/22 17:09:59"
+ *                 
+ ********************************************************************************/
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <poll.h>
+#include <errno.h> 
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/sockios.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <sys/resource.h>
+
+#include "socket.h"
+#include "logger.h"
+
+/*  description: initial socket context 
+ *   input args: 
+ *               $sock:  socket context pointer
+ *               $host:  connect server hostname for client mode, unused for server mode
+ *               $port:  connect server port for client mode or listen port for server mode
+ * return value: <0: failure   0:ok
+ */
+int socket_init(socket_ctx_t *sock, char *host, int port)
+{
+	if( !sock || !host || port<=0 )
+		return -1;
+
+	memset( sock, 0, sizeof(*sock) );
+	sock->fd = -1;
+	strncpy(sock->host, host, HOSTNAME_LEN);
+	sock->port = port;
+}
+
+/*  description: close socket
+ *   input args: 
+ *               $sock:  socket context pointer
+ * return value: <0: failure   0:ok
+ */
+int socket_term(socket_ctx_t *sock)
+{
+	if( !sock )
+		return -1;
+
+	if( sock->fd > 0)
+	{
+		close(sock->fd);
+		sock->fd = -1;
+	}
+
+	return 0;
+}
+
+/*  description: socket server start listen
+ *   input args: 
+ *               $sock:  socket context pointer
+ * return value: <0: failure   0:ok
+ */
+int socket_listen(socket_ctx_t *sock)
+{
+    int                 rv = 0;  
+    struct sockaddr_in  addr;
+    int                 backlog = 13; 
+
+	if( !sock )
+		return -1;
+
+}
+
+/*  description: socket check connected or not
+ *   input args: 
+ *               $sock:  socket context pointer
+ * return value: <0: failure   0:ok
+ */
+int socket_connect(socket_ctx_t *sock)
+{
+    int                 rv = 0;  
+    int                 sockfd = 0;  
+	struct sockaddr_in  servaddr;
+
+	if( !sock )
+		return -1;
+
+	socket_term(sock);
+
+    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
+    if(sockfd < 0)
+    {   
+        log_error("create socket failure: %s\n", strerror(errno));
+        return -1; 
+    }   
+
+    memset(&servaddr, 0, sizeof(servaddr));
+    servaddr.sin_family=AF_INET;
+    servaddr.sin_port = htons(sock->port);
+    inet_aton(sock->host, &servaddr.sin_addr);
+
+    rv=connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
+    if(rv < 0)
+    {   
+        //log_error("connect to server[%s:%d] failure: %s\n", sock->host, sock->port, strerror(errno));
+		close(sockfd);
+        return -2; 
+    }   
+
+	log_info("Connect to server[%s:%d] on fd[%d] successfully!\n", sock->host, sock->port, sockfd);
+
+	sock->fd = sockfd;
+
+	return 0;
+}
+
+/*  description: send data from the socket
+ *   input args: 
+ *               $sock :  socket context pointer
+ *               $data :  socket send data
+ *               $bytes:  socket send data bytes
+ * return value: <0: failure   0:ok
+ */
+int socket_send(socket_ctx_t *sock, char *data, int bytes)
+{
+    int            rv = 0;
+    int            i = 0;
+    int            left_bytes = bytes;
+
+	if( !sock || !data || bytes<= 0 )
+		return -1;
+
+    while( left_bytes > 0 ) 
+    {   
+        rv=write(sock->fd, &data[i], left_bytes);
+        if( rv < 0 ) 
+        {
+            log_info("socket[%d] write() failure: %s, close socket now\n", sock->fd, strerror(errno));
+            socket_term(sock);
+            return -2; 
+        }
+        else if( rv == left_bytes )
+        {
+            log_info("socket send %d bytes data over\n", bytes);
+            return 0;
+        }
+        else 
+        {
+            /* not send over this time, continue to send left data  */
+            i += rv; 
+            left_bytes -= rv; 
+            continue;
+        }
+    }   
+}
+
+/*  description: receive data from the socket
+ *   input args: 
+ *               $sock :  socket context pointer
+ *               $buf  :  socket receive data buffer
+ *               $size :  socket receive data buffer size
+ *               $timeout: receive data time, <=0 will don't timeout
+ * return value: <0: failure   0:ok
+ */
+int socket_recv(socket_ctx_t *sock, char *buf, int size, int timeout)
+{
+    int               rv = 0;
+    int               i = 0;
+    fd_set            rdset;
+    int               maxfd;
+
+	if( !sock || !buf || size<= 0 )
+		return -1;
+
+    memset(buf, 0, size);
+
+    maxfd = sock->fd;
+    FD_ZERO(&rdset);
+    FD_SET(sock->fd, &rdset);
+
+    if( timeout <= 0 ) /* no timeout  */
+    {
+        rv=select(maxfd+1, &rdset, NULL, NULL, NULL);
+    }
+    else
+    {
+        struct timeval    tv;
+        tv.tv_sec = timeout;
+        tv.tv_usec = 0;
+        rv=select(maxfd+1, &rdset, NULL, NULL, &tv);
+    }
+
+    if( rv < 0 )
+    {
+        log_error("select() on socket[%d] got error: %s\n", sock->fd, strerror(errno));
+        return -2;
+    }
+    else if( rv == 0 )
+    {
+        log_error("select() on socket[%d] get timeout\n", sock->fd);
+        return 0;
+    }
+    else
+    {
+        rv = read(sock->fd, buf, size);
+        if( rv <= 0 )
+        {
+            log_error("socket[%d] read() failure or got disconnected: %s, close socket now\n", sock->fd, strerror(errno));
+            socket_term(sock);
+            return -2;
+        }
+        else
+        {
+            log_debug("socket[%d] receive %d bytes data\n", sock->fd, rv);
+            return rv;
+        }
+    }
+}
+
+
+
+/*+-------------------------------------------------------------------+
+ *|                socket utils function                              |
+ *+-------------------------------------------------------------------+*/
+
+
+/*  socket connected or not: <0: failure  0:ok */
+int sock_check_connect(int sockfd)
+{
+	struct tcp_info   info;
+	int               len=sizeof(info);
+
+	if( sockfd < 0 )
+		return -1;
+
+	getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
+
+	if( TCP_CLOSE==info.tcpi_state || TCP_CLOSING==info.tcpi_state || TCP_CLOSE_WAIT==info.tcpi_state )
+ 	{
+		return -3;
+	}
+
+	return -0;
+}
+
+/* description: set socket listen port as reusable, fix port already used bug  */
+int socket_set_reuseaddr(int sockfd)
+{
+    int opt = 1;
+    int len = sizeof (int);
+
+    if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, len))
+    {
+        log_error("Set socket[%d] option SO_REUSEADDR failed:%s\n", sockfd, strerror(errno));
+        return -1;
+    }
+    log_debug("Set socket[%d] option SO_REUSEADDR ok\n", sockfd);
+
+    return 0;
+}
+
+/* set socket as non-block mode, common socket default work as block mode */
+int socket_set_nonblock(int sockfd)
+{
+    int opts;
+    /*
+     * fcntl may set: 
+     *
+     * EACCES, EAGAIN: Operation is prohibited by locks held by other 
+     *          processes. Or, operation is prohibited because the file has 
+     *          been memory-mapped by another process. 
+     * EBADF:   fd is not an open file descriptor, or the command was F_SETLK 
+     *          or F_SETLKW and the file descriptor open mode doesn't match 
+     *          with the type of lock requested.
+     * EDEADLK: It was detected that the specified F_SETLKW command would 
+     *          cause a deadlock.
+     * EFAULT:  lock is outside your accessible address space.
+     * EINTR:   For F_SETLKW, the command was interrupted by a signal. For 
+     *          F_GETLK and F_SETLK, the command was interrupted by a signal 
+     *          before the lock was checked or acquired. Most likely when 
+     *          locking a remote file (e.g. locking over NFS), but can 
+     *          sometimes happen locally.
+     * EINVAL:  For F_DUPFD, arg is negative or is greater than the maximum 
+     *          allowable value. For F_SETSIG, arg is not an allowable signal 
+     *          number.
+     * EMFILE:  For F_DUPFD, the process already has the maximum number of 
+     *          file descriptors open. 
+     * ENOLCK:  Too many segment locks open, lock table is full, or a remote 
+     *          locking protocol failed (e.g. locking over NFS).
+     * EPERM:   Attempted to clear the O_APPEND flag on a file that has the 
+     *          append-only attribute set.
+     */
+    opts = fcntl(sockfd, F_GETFL);
+    if (opts < 0)
+    {
+        log_warn("fcntl() get socket options failure: %s\n", strerror(errno));
+        return -1;
+    }
+
+    opts |= O_NONBLOCK;
+
+    if (fcntl(sockfd, F_SETFL, opts) < 0)
+    {
+        log_warn("fcntl() set socket options failure: %s\n", strerror(errno));
+        return -1;
+    }
+
+    log_debug("Set socket[%d] none blocking\n", sockfd);
+    return opts;
+}
+
+
+/* set socket receive and send buffer size in linux kernel space */
+int socket_set_buffer(int sockfd, int rsize, int ssize)
+{
+    int        opt;
+    socklen_t  optlen = sizeof(opt);
+
+    if(sockfd < 0)
+        return -1;
+
+    /* Get system default receive buffer size, Linux X86: 85K */
+    if (getsockopt (sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, &optlen))
+    {
+        log_warn("getsockopt() get receive buffer failure: %s\n", strerror(errno));
+        return -2;
+    }
+
+    /* Only when current receive buffer size larger than the default one will change it  */
+    if(rsize > opt)
+    {
+        opt = (int) rsize;
+        if (setsockopt (sockfd, SOL_SOCKET, SO_RCVBUF, (char *) &opt, optlen))
+        {
+            log_warn("setsockopt() set receive buffer to %d failure: %s\n", opt, strerror(errno));
+            return -2;
+        }
+    }
+
+    /* Get system default send buffer size, Linux X86: 16K */
+    if (getsockopt (sockfd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, &optlen))
+    {
+        log_warn("getsockopt() get send buffer failure: %s\n", strerror(errno));
+        return -3;
+    }
+
+    /* Only when current receive buffer size larger than the default one will change it  */
+    if(ssize > opt)
+    {
+        opt = (int) ssize;
+        if (setsockopt (sockfd, SOL_SOCKET, SO_SNDBUF, (char *) &opt, optlen))
+        {
+            log_warn("setsockopt() set send buffer to %d failure: %s\n", opt, strerror(errno));
+            return -3;
+        }
+    }
+
+    log_info("Set socket[%d] RCVBUF size:%d  SNDBUF size:%d\n", sockfd, rsize, ssize);
+    return 0;
+}
+
+/*
+ * Enable socket SO_KEEPALIVE, if the connection disconnected, any system call on socket
+ * will return immediately and errno will be set to "WSAENOTCONN"
+ *
+ * keepalive is not program related, but socket related, * so if you have multiple sockets, 
+ * you can handle keepalive for each of them separately.
+ *
+ * Reference: http://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
+ */
+int socket_set_keepalive(int sockfd, int keepintvl, int keepcnt)
+{
+    int  opt;
+
+    if(sockfd < 0)
+        return -1;
+
+    /* Enable the KEEPALIVE flag */
+    opt = 1;
+    if (setsockopt (sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt, sizeof (opt)))
+    {
+        log_warn("setsockopt() enable SO_KEEPALIVE failure: %s\n", strerror(errno));
+        return -2;
+    }
+
+    if(keepintvl || keepcnt)
+    {
+        /*
+         *  The tcp_keepidle parameter specifies the interval between the last data packet sent 
+         *  (simple ACKs are not considered data) and the first keepalive probe; after the 
+         *  connection is marked to need keepalive, this counter is not used any further. 
+         *  ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_time 
+         *  7200
+         */
+        opt = 3; /* 3 seconds  */
+        if (setsockopt (sockfd, SOL_TCP, TCP_KEEPIDLE, (char *) &opt, sizeof (opt)))
+        {
+            log_error("setsockopt() set TCP_KEEPIDLE to %d seconds failure: %s\n", opt, strerror(errno));
+            return -3;
+        }
+
+        if((opt=keepintvl) > 0)
+        {
+            /*
+             * The tcp_keepintvl parameter specifies the interval between subsequential keepalive 
+             * probes, regardless of what the connection has exchanged in the meantime.
+             * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_intvl 
+             * 75
+             */
+            if (setsockopt (sockfd, SOL_TCP, TCP_KEEPINTVL, (char *) &opt, sizeof (opt)))
+            {
+                log_error("setsockopt() set TCP_KEEPINTVL to %d failure: %s\n", opt, strerror(errno));
+                return -4;
+            }
+        }
+
+        if((opt=keepcnt) > 0)
+        {
+            /*
+             * The TCP_KEEPCNT option specifies the maximum number of unacknowledged probes to 
+             * send before considering the connection dead and notifying the application layer
+             * probes to be sent. The value of TCP_KEEPCNT is an integer value between 1 and n, 
+             * where n is the value of the systemwide tcp_keepcnt parameter. 
+             * ~ >: cat /proc/sys/net/ipv4/tcp_keepalive_probes 
+             * 9
+             */
+            if (setsockopt (sockfd, SOL_TCP, TCP_KEEPCNT, (char *) &opt, sizeof (opt)))
+            {
+                log_error("setsockopt() set TCP_KEEPCNT to %d failure: %s\n", opt, strerror(errno));
+                return -5;
+            }
+        }
+    }
+
+    log_debug("Set socket[%d] KEEPINTVL:%d  KEEPCNT:%d\n", sockfd, keepintvl, keepcnt);
+    return 0;
+}
+
+
+/* Set open file description count to max */
+void set_socket_rlimit(void)
+{
+    struct rlimit limit = {0};
+
+    getrlimit(RLIMIT_NOFILE, &limit );
+    limit.rlim_cur  = limit.rlim_max;
+    setrlimit(RLIMIT_NOFILE, &limit );
+
+    log_info("set socket open fd max count to %d\n", limit.rlim_max);
+}
+
diff --git a/apue/project_socket/src/socket.h b/apue/project_socket/src/socket.h
new file mode 100644
index 0000000..e23b850
--- /dev/null
+++ b/apue/project_socket/src/socket.h
@@ -0,0 +1,100 @@
+/********************************************************************************
+ *      Copyright:  (C) 2022 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  socket.h
+ *    Description:  This head file is for socket API functions
+ *
+ *        Version:  1.0.0(18/04/22)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "18/04/22 17:09:59"
+ *                 
+ ********************************************************************************/
+
+#ifndef  _SOCKET_H_
+#define  _SOCKET_H_
+
+#define HOSTNAME_LEN          64
+
+typedef struct socket_ctx_s 
+{
+	char        host[HOSTNAME_LEN]; /* CLIENT: Connect server hostname; SERVER: Unused */
+	int         port;               /* CLIENT: Connect server port;     SERVER: listen port */
+	int         fd;                 /* socket descriptor  */
+} socket_ctx_t; 
+
+/*  description: initial socket context 
+ *   input args: 
+ *               $sock:  socket context pointer
+ *               $host:  connect server hostname for client mode, unused for server mode
+ *               $port:  connect server port for client mode or listen port for server mode
+ * return value: <0: failure   0:ok
+ */
+extern int socket_init(socket_ctx_t *sock, char *host, int port);
+
+/*  description: close socket
+ *   input args: 
+ *               $sock:  socket context pointer
+ * return value: <0: failure   0:ok
+ */
+extern int socket_term(socket_ctx_t *sock);
+
+/*  description: socket server start listen
+ *   input args: 
+ *               $sock:  socket context pointer
+ * return value: <0: failure   0:ok
+ */
+extern int socket_listen(socket_ctx_t *sock);
+
+/*  description: socket client connect to server
+ *   input args: 
+ *               $sock:  socket context pointer
+ * return value: <0: failure   0:ok
+ */
+extern int socket_connect(socket_ctx_t *sock);
+
+/*  description: send data from the socket
+ *   input args: 
+ *               $sock :  socket context pointer
+ *               $data :  socket send data
+ *               $bytes:  socket send data bytes
+ * return value: <0: failure   0:ok
+ */
+extern int socket_send(socket_ctx_t *sock, char *data, int bytes);
+
+/*  description: receive data from the socket
+ *   input args: 
+ *               $sock :  socket context pointer
+ *               $buf  :  socket receive data buffer
+ *               $size :  socket receive data buffer size
+ *               $timeout: receive data time, <=0 will don't timeout
+ * return value: <0: failure   0:ok
+ */
+#define TIMEOUT_NONE       0 
+extern int socket_recv(socket_ctx_t *sock, char *buf, int size, int timeout);
+
+/*+-------------------------------------------------------------------+
+ *|                socket utils function                              |
+ *+-------------------------------------------------------------------+*/
+
+
+/*  socket connected or not: <0: failure  0:ok */
+extern int sock_check_connect(int sockfd);
+
+/* description: set socket listen port as reusable, fix port already used bug  */
+extern int socket_set_reuseaddr(int sockfd);
+
+/* set socket as non-block mode, common socket default work as block mode */
+extern int socket_set_nonblock(int sockfd);
+
+/* set socket receive and send buffer size in linux kernel space */
+extern int socket_set_buffer(int sockfd, int rsize, int ssize);
+
+/* set heartbeat keepalive  */
+extern int socket_set_keepalive(int sockfd, int keepintvl, int keepcnt);
+
+/*  Set open file description count to max */
+extern void set_socket_rlimit(void);
+
+#endif   /* ----- #ifndef _SOCKET_H_  ----- */
+
diff --git a/apue/project_socket/src/sqlite_blob.c b/apue/project_socket/src/sqlite_blob.c
new file mode 100644
index 0000000..07a95f1
--- /dev/null
+++ b/apue/project_socket/src/sqlite_blob.c
@@ -0,0 +1,265 @@
+/********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  sqlite_blob.c
+ *    Description:  This library used to operate blob packet in sqlite database.
+ *
+ *        Version:  1.0.0(2020年05月13日)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "2020年05月13日 12时14分23秒"
+ *
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include "sqlite_blob.h"
+#include "logger.h"
+
+/* Blob packet table name */
+#define TABLE_NAME     "PackTable"
+
+/* Use static global handler here in order to simplify the API,
+ * But it will make this library not thread safe
+ */
+static sqlite3         *s_clidb = NULL;
+
+
+/*  description: open or create sqlite database if not exist
+ *   input args:
+ *               $db_file: sqlite database file name
+ * return value: <0: failure   0:ok
+ * */
+int database_init(const char *db_file)
+{
+    char               sql[SQL_COMMAND_LEN]={0};
+    char              *errmsg = NULL;
+
+    if( !db_file )
+    {
+        log_error("%s() Invalid input arguments\n", __func__);
+        return -1;
+    }
+
+    /*+------------------------------------------+
+     *|   database already exist, just open it   |
+     *+------------------------------------------+*/
+    if( 0==access(db_file, F_OK) )
+    {
+        if( SQLITE_OK != sqlite3_open(db_file, &s_clidb) )
+        {
+            log_error("open database file '%s' failure\n", db_file);
+            return -2;
+        }
+        log_info("open database file '%s' ok\n", db_file);
+        return 0;
+    }
+
+    /*+-----------------------------------------+
+     *|  database not exist, create and init it |
+     *+-----------------------------------------+*/
+
+    if( SQLITE_OK != sqlite3_open(db_file, &s_clidb) )
+    {
+        log_error("create database file '%s' failure\n", db_file);
+        return -2;
+    }
+
+    /* SQLite continues without syncing as soon as it has handed data off to the operating system */
+    sqlite3_exec(s_clidb, "pragma synchronous = OFF; ", NULL, NULL, NULL);
+
+    /* enable full auto vacuum, Auto increase/decrease  */
+    sqlite3_exec(s_clidb, "pragma auto_vacuum = 2 ; ", NULL, NULL, NULL);
+
+    /*   Create firehost table in the database */
+    snprintf(sql, sizeof(sql), "CREATE TABLE %s(packet BLOB);", TABLE_NAME);
+    if( SQLITE_OK != sqlite3_exec(s_clidb, sql, NULL, NULL, &errmsg) )
+    {
+        log_error("create data_table in database file '%s' failure: %s\n", db_file, errmsg);
+        sqlite3_free(errmsg); /* free errmsg  */
+        sqlite3_close(s_clidb);   /* close databse */
+        unlink(db_file);      /* remove database file */
+    }
+
+    log_info("create and init database file '%s' ok\n", db_file);
+    return 0;
+}
+
+
+/*  description: close sqlite database handler
+ * return value: none
+ */
+void database_term(void)
+{
+    log_warn("close sqlite database now\n");
+    sqlite3_close(s_clidb);
+
+    return ;
+}
+
+
+/*  description: push a blob packet into database
+ *   input args:
+ *               $pack:  blob packet data address
+ *               $size:  blob packet data bytes
+ * return value: <0: failure   0:ok
+ */
+int blobdb_push_packet(void *pack, int size)
+{
+    char               sql[SQL_COMMAND_LEN]={0};
+    int                rv = 0;
+    char              *errmsg = NULL;
+    sqlite3_stmt      *stat = NULL;
+
+    if( !pack || size<=0 )
+    {
+        log_error("%s() Invalid input arguments\n", __func__);
+        return -1;
+    }
+
+    if( ! s_clidb )
+    {
+        log_error("sqlite database not opened\n");
+        return -2;
+    }
+
+	snprintf(sql, sizeof(sql), "insert into %s(packet) values(?)", TABLE_NAME);
+    rv = sqlite3_prepare_v2(s_clidb, sql, -1, &stat, NULL);
+    if(SQLITE_OK!=rv || !stat)
+    {
+        log_error("blob add sqlite3_prepare_v2 failure\n");
+        rv = -2;
+        goto OUT;
+    }
+
+    if( SQLITE_OK != sqlite3_bind_blob(stat, 1, pack, size, NULL) )
+    {
+        log_error("blob add sqlite3_bind_blob failure\n");
+        rv = -3;
+        goto OUT;
+    }
+
+    rv = sqlite3_step(stat);
+    if( SQLITE_DONE!=rv && SQLITE_ROW!=rv )
+    {
+        log_error("blob add sqlite3_step failure\n");
+        rv = -4;
+        goto OUT;
+    }
+
+OUT:
+    sqlite3_finalize(stat);
+
+    if( rv < 0 )
+        log_error("add new blob packet into database failure, rv=%d\n", rv);
+    else
+        log_info("add new blob packet into database ok\n");
+
+    return rv;
+}
+
+
+/*  description: pop the first blob packet from database
+ *   input args:
+ *               $pack:  blob packet output buffer address
+ *               $size:  blob packet output buffer size
+ *               $byte:  blob packet bytes
+ * return value: <0: failure   0:ok
+ */
+int blobdb_pop_packet(void *pack, int size, int *bytes)
+{
+    char               sql[SQL_COMMAND_LEN]={0};
+    int                rv = 0;
+    sqlite3_stmt      *stat = NULL;
+    const void        *blob_ptr;
+
+    if( !pack || size<=0 )
+    {
+        log_error("%s() Invalid input arguments\n", __func__);
+        return -1;
+    }
+
+    if( ! s_clidb )
+    {
+        log_error("sqlite database not opened\n");
+        return -2;
+    }
+
+    /* Only query the first packet record */
+    snprintf(sql, sizeof(sql), "select packet from %s limit 0,1;", TABLE_NAME);
+    rv = sqlite3_prepare_v2(s_clidb, sql, -1, &stat, NULL);
+    if(SQLITE_OK!=rv || !stat)
+    {
+        log_error("firehost sqlite3_prepare_v2 failure\n");
+        rv = -3;
+        goto out;
+    }
+
+    rv = sqlite3_step(stat);
+    if( SQLITE_DONE!=rv && SQLITE_ROW!=rv )
+    {
+        log_error("firehost sqlite3_step failure\n");
+        rv = -5;
+        goto out;
+    }
+
+    /* 1rd argument<0> means first segement is packet  */
+    blob_ptr = sqlite3_column_blob(stat, 0);
+    if( !blob_ptr )
+    {
+        rv = -6;
+        goto out;
+    }
+
+	*bytes = sqlite3_column_bytes(stat, 0);
+
+	if( *bytes > size )
+	{
+		log_error("blob packet bytes[%d] larger than bufsize[%d]\n", *bytes, size);
+		*bytes = 0;
+		rv = -1;
+	}
+
+    memcpy(pack, blob_ptr, *bytes);
+	rv = 0;
+
+out:
+    sqlite3_finalize(stat);
+    return rv;
+}
+
+
+/*  description: remove the first blob packet from database
+ *   input args: none
+ * return value: <0: failure   0:ok
+ */
+int blobdb_del_packet(void)
+{
+    char               sql[SQL_COMMAND_LEN]={0};
+    char              *errmsg = NULL;
+
+    if( ! s_clidb )
+    {
+        log_error("sqlite database not opened\n");
+        return -2;
+    }
+
+    /*  remove packet from db */
+    memset(sql, 0, sizeof(sql));
+    snprintf(sql, sizeof(sql), "delete from %s limit 0,1;", TABLE_NAME);
+    if( SQLITE_OK != sqlite3_exec(s_clidb, sql, NULL, 0, &errmsg) )
+    {
+        log_error("delete first blob packet from database failure: %s\n", errmsg);
+        sqlite3_free(errmsg);
+        return -2;
+    }
+    log_warn("delete first blob packet from database ok\n");
+
+    /*  Vacuum the database */
+    sqlite3_exec(s_clidb, "VACUUM;", NULL, 0, NULL);
+
+    return 0;
+}
+
diff --git a/apue/project_socket/src/sqlite_blob.h b/apue/project_socket/src/sqlite_blob.h
new file mode 100644
index 0000000..953e50e
--- /dev/null
+++ b/apue/project_socket/src/sqlite_blob.h
@@ -0,0 +1,60 @@
+/********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  sqlite_blob.h
+ *    Description:  This library used to operate blob packet in sqlite database.
+ *
+ *        Version:  1.0.0(2020年05月13日)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "2020年05月13日 12时14分23秒"
+ *
+ ********************************************************************************/
+#ifndef  _SQLITE_BLOB_H_
+#define  _SQLITE_BLOB_H_
+
+#include "sqlite3.h"
+
+#define SQL_COMMAND_LEN        256
+
+/*  description: open or create sqlite database if not exist
+ *   input args:
+ *              $db_file: sqlite database file name
+ * return value: <0: failure   0:ok
+ * */
+extern int database_init(const char *db_file);
+
+
+/*  description: close sqlite database handler
+ * return value: none
+ */
+extern void database_term(void);
+
+
+/*  description: push a blob packet into database
+ *   input args:
+ *               $pack:  blob packet data address
+ *               $size:  blob packet data bytes
+ * return value: <0: failure   0:ok
+ */
+extern int blobdb_push_packet(void *pack, int size);
+
+
+/*  description: pop the first blob packet from database
+ *   input args:
+ *               $pack:  blob packet output buffer address
+ *               $size:  blob packet output buffer size
+ *               $byte:  blob packet bytes
+ * return value: <0: failure   0:ok
+ */
+extern int blobdb_pop_packet(void *pack, int size, int *bytes);
+
+
+/*  description: remove the first blob packet from database
+ *   input args: none
+ * return value: <0: failure   0:ok
+ */
+extern int blobdb_del_packet(void);
+
+
+#endif   /* ----- #ifndef _SQLITE_BLOB_H_  ----- */
diff --git a/apue/project_socket/src/util_proc.c b/apue/project_socket/src/util_proc.c
new file mode 100644
index 0000000..039443d
--- /dev/null
+++ b/apue/project_socket/src/util_proc.c
@@ -0,0 +1,433 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  util_proc.c
+ *    Description:  This file is the process API
+ *
+ *        Version:  1.0.0(7/06/2020)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "7/06/2020 09:19:02 PM"
+ *
+ ********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+
+#include "util_proc.h"
+#include "logger.h"
+
+proc_signal_t     g_signal={0};
+
+void proc_default_sighandler(int sig)
+{
+    switch(sig)
+    {
+        case SIGINT:
+            log_warn("SIGINT - stopping\n");
+            g_signal.stop = 1;
+            break;
+
+        case SIGTERM:
+            log_warn("SIGTERM - stopping\n");
+            g_signal.stop = 1;
+            break;
+
+        case SIGSEGV:
+            log_warn("SIGSEGV - stopping\n");
+#if 0
+            if(g_signal.stop)
+                exit(0);
+
+            g_signal.stop = 1;
+#endif
+            break;
+
+        case SIGPIPE:
+            log_warn("SIGPIPE - warnning\n");
+            break;
+
+        default:
+            break;
+    }
+}
+
+
+/* install default signal process functions  */
+void install_default_signal(void)
+{
+    struct sigaction sigact, sigign;
+
+    log_info("Install default signal handler.\n");
+
+    /*  Initialize the catch signal structure. */
+    sigemptyset(&sigact.sa_mask);
+    sigact.sa_flags = 0;
+    sigact.sa_handler = proc_default_sighandler;
+
+    /*  Setup the ignore signal. */
+    sigemptyset(&sigign.sa_mask);
+    sigign.sa_flags = 0;
+    sigign.sa_handler = SIG_IGN;
+
+    sigaction(SIGTERM, &sigact, 0); /*  catch terminate signal "kill" command */
+    sigaction(SIGINT,  &sigact, 0); /*  catch interrupt signal CTRL+C */
+    //sigaction(SIGSEGV, &sigact, 0); /*  catch segmentation faults  */
+    sigaction(SIGPIPE, &sigact, 0); /*  catch broken pipe */
+#if 0
+    sigaction(SIGCHLD, &sigact, 0); /*  catch child process return */
+    sigaction(SIGUSR2, &sigact, 0); /*  catch USER signal */
+#endif
+}
+
+
+/* ****************************************************************************
+ * FunctionName: daemonize
+ * Description : Set the programe runs as daemon in background
+ * Inputs      : nodir: DON'T change the work directory to / :  1:NoChange 0:Change
+ *               noclose: close the opened file descrtipion or not 1:Noclose 0:Close
+ * Output      : NONE
+ * Return      : NONE
+ * *****************************************************************************/
+void daemonize(int nochdir, int noclose)
+{
+    int rv, fd;
+    int i;
+
+    /*  already a daemon */
+    if (1 == getppid())
+        return;
+
+    /*  fork error */
+    rv = fork();
+    if (rv < 0) exit(1);
+
+    /*  parent process exit */
+    if (rv > 0)
+        exit(0);
+
+    /*  obtain a new process session group */
+    setsid();
+
+    if (!noclose)
+    {
+        /*  close all descriptors */
+        for (i = getdtablesize(); i >= 0; --i)
+        {
+            //if (i != g_logPtr->fd)
+                close(i);
+        }
+
+        /*  Redirect Standard input [0] to /dev/null */
+        fd = open("/dev/null", O_RDWR);
+
+        /* Redirect Standard output [1] to /dev/null */
+        dup(fd);
+
+        /* Redirect Standard error [2] to /dev/null */
+        dup(fd);
+    }
+
+    umask(0);
+
+    if (!nochdir)
+        chdir("/");
+
+    return;
+}
+
+/* ****************************************************************************
+ * FunctionName: check_set_program_running
+ * Description : check program already running or not, if not then run it and
+ *               record pid into $pidfile
+ * Inputs      : daemon:  set program running in daemon or not
+ *               pid_file:The record PID file path
+ * Output      : NONE
+ * Return      : 0: Record successfully  Else: Failure
+ * *****************************************************************************/
+
+int check_set_program_running(int daemon, char *pidfile)
+{
+    if( !pidfile )
+        return 0;
+
+    if( check_daemon_running(pidfile) )
+    {
+        log_error("Program already running, process exit now");
+        return -1;
+    }
+
+    if( daemon )
+    {
+        if( set_daemon_running(pidfile) < 0 )
+        {
+            log_error("set program running as daemon failure\n");
+            return -2;
+        }
+    }
+    else
+    {
+        if( record_daemon_pid(pidfile) < 0 )
+        {
+            log_error("record program running PID failure\n");
+            return -3;
+        }
+    }
+
+    return 0;
+}
+
+
+
+/* ****************************************************************************
+ * FunctionName: record_daemon_pid
+ * Description : Record the running daemon program PID to the file "pid_file"
+ * Inputs      : pid_file:The record PID file path
+ * Output      : NONE
+ * Return      : 0: Record successfully  Else: Failure
+ * *****************************************************************************/
+int record_daemon_pid(const char *pid_file)
+{
+    struct stat fStatBuf;
+    int fd = -1;
+    int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
+    char ipc_dir[64] = { 0 };
+
+    strncpy(ipc_dir, pid_file, 64);
+
+    /* dirname() will modify ipc_dir and save the result */
+    dirname(ipc_dir);
+
+    /* If folder pid_file PATH doesnot exist, then we will create it" */
+    if (stat(ipc_dir, &fStatBuf) < 0)
+    {
+        if (mkdir(ipc_dir, mode) < 0)
+        {
+            log_error("cannot create %s: %s\n", ipc_dir, strerror(errno));
+            return -1;
+        }
+
+        (void)chmod(ipc_dir, mode);
+    }
+
+    /*  Create the process running PID file */
+    mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+    if ((fd = open(pid_file, O_RDWR | O_CREAT | O_TRUNC, mode)) >= 0)
+    {
+        char pid[PID_ASCII_SIZE];
+        snprintf(pid, sizeof(pid), "%u\n", (unsigned)getpid());
+        write(fd, pid, strlen(pid));
+        close(fd);
+
+        log_debug("Record PID<%u> to file %s.\n", getpid(), pid_file);
+    }
+    else
+    {
+        log_error("cannot create %s: %s\n", pid_file, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+/* ****************************************************************************
+ * FunctionName: get_daemon_pid
+ * Description : Get the daemon process PID from the PID record file "pid_file"
+ * Inputs      : pid_file: the PID record file
+ * Output      : NONE
+ * Return      : pid_t: The daemon process PID number
+ * *****************************************************************************/
+pid_t get_daemon_pid(const char *pid_file)
+{
+    FILE *f;
+    pid_t pid;
+
+    if ((f = fopen(pid_file, "rb")) != NULL)
+    {
+        char pid_ascii[PID_ASCII_SIZE];
+        (void)fgets(pid_ascii, PID_ASCII_SIZE, f);
+        (void)fclose(f);
+        pid = atoi(pid_ascii);
+    }
+    else
+    {
+        log_error("Can't open PID record file %s: %s\n", pid_file, strerror(errno));
+        return -1;
+    }
+    return pid;
+}
+
+/* ****************************************************************************
+ * FunctionName: check_daemon_running
+ * Description : Check the daemon program already running or not
+ * Inputs      : pid_file: The record running daemon program PID
+ * Output      : NONE
+ * Return      : 1: The daemon program alread running   0: Not running
+ * *****************************************************************************/
+int check_daemon_running(const char *pid_file)
+{
+    int rv = -1;
+    struct stat fStatBuf;
+
+    rv = stat(pid_file, &fStatBuf);
+    if (0 == rv)
+    {
+        pid_t pid = -1;
+        printf("PID record file \"%s\" exist.\n", pid_file);
+
+        pid = get_daemon_pid(pid_file);
+        if (pid > 0)  /*  Process pid exist */
+        {
+            if ((rv = kill(pid, 0)) == 0)
+            {
+                printf("Program with PID[%d] seems running.\n", pid);
+                return 1;
+            }
+            else   /* Send signal to the old process get no reply. */
+            {
+                printf("Program with PID[%d] seems exit.\n", pid);
+                remove(pid_file);
+                return 0;
+            }
+        }
+        else if (0 == pid)
+        {
+            printf("Can not read program PID form record file.\n");
+            remove(pid_file);
+            return 0;
+        }
+        else  /* Read pid from file "pid_file" failure */
+        {
+            printf("Read record file \"%s\" failure, maybe program still running.\n", pid_file);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+/* ****************************************************************************
+ * FunctionName: stop_daemon_running
+ * Description : Stop the daemon program running
+ * Inputs      : pid_file: The record running daemon program PID
+ * Output      : NONE
+ * Return      : 1: The daemon program alread running   0: Not running
+ * *****************************************************************************/
+int stop_daemon_running(const char *pid_file)
+{
+    pid_t            pid = -1;
+    struct stat      fStatBuf;
+
+    if ( stat(pid_file, &fStatBuf) < 0)
+        return 0;
+
+    printf("PID record file \"%s\" exist.\n", pid_file);
+    pid = get_daemon_pid(pid_file);
+    if (pid > 0)  /*  Process pid exist */
+    {
+        while ( (kill(pid, 0) ) == 0)
+        {
+            kill(pid, SIGTERM);
+            sleep(1);
+        }
+
+        remove(pid_file);
+    }
+
+    return 0;
+}
+
+/* ****************************************************************************
+ * FunctionName: set_daemon_running
+ * Description : Set the programe running as daemon if it's not running and record
+ *               its PID to the pid_file.
+ * Inputs      : pid_file: The record running daemon program PID
+ * Output      : NONE
+ * Return      : 0: Successfully. 1: Failure
+ * *****************************************************************************/
+int set_daemon_running(const char *pid_file)
+{
+    daemonize(0, 1);
+    log_info("Program running as daemon [PID:%d].\n", getpid());
+
+    if (record_daemon_pid(pid_file) < 0)
+    {
+        log_error("Record PID to file \"%s\" failure.\n", pid_file);
+        return -2;
+    }
+
+    return 0;
+}
+
+/* start a new thread to run $thread_workbody point function  */
+int thread_start(pthread_t *thread_id, thread_body_t thread_workbody, void *thread_arg)
+{
+    int                rv = 0;
+    pthread_t          tid;
+
+    pthread_attr_t     thread_attr;
+
+    /* Initialize the thread  attribute */
+    rv = pthread_attr_init(&thread_attr);
+    if(rv)
+        return -1;
+
+#if 0
+    /* Set the stack size of the thread */
+    rv = pthread_attr_setstacksize(&thread_attr, 120 * 1024);
+    if(rv)
+        goto CleanUp;
+#endif
+
+    /* Set thread to detached state:Don`t need pthread_join */
+    rv = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
+    if(rv)
+        goto CleanUp;
+
+    /* Create the thread */
+    rv = pthread_create(&tid, &thread_attr, thread_workbody, thread_arg);
+    if(rv)
+        goto CleanUp;
+
+CleanUp:
+
+
+    if( thread_id )
+    {
+        if( rv )
+            *thread_id = 0;
+        else
+            *thread_id = tid;
+    }
+
+    /* Destroy the  attributes  of  thread */
+    pthread_attr_destroy(&thread_attr);
+    return rv;
+}
+
+
+/* excute a linux command by system() */
+void exec_system_cmd(const char *format, ...)
+{
+    char                cmd[256];
+    va_list             args;
+
+    memset(cmd, 0, sizeof(cmd));
+
+    va_start(args, format);
+    vsnprintf(cmd, sizeof(cmd), format, args);
+    va_end(args);
+
+    system(cmd);
+}
+
+
diff --git a/apue/project_socket/src/util_proc.h b/apue/project_socket/src/util_proc.h
new file mode 100644
index 0000000..b52692f
--- /dev/null
+++ b/apue/project_socket/src/util_proc.h
@@ -0,0 +1,65 @@
+/********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  util_proc.h
+ *    Description:  This head file is for Linux process/thread API
+ *
+ *        Version:  1.0.0(7/06/2012~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "7/06/2012 09:21:33 PM"
+ *
+ ********************************************************************************/
+
+#ifndef __UTIL_PROC_H_
+#define __UTIL_PROC_H_
+
+#include <signal.h>
+
+#define PID_ASCII_SIZE  11
+
+typedef struct proc_signal_s
+{
+    int       signal;
+    unsigned  stop;     /* 0: Not term  1: Stop  */
+}  proc_signal_t;
+
+typedef void *(* thread_body_t) (void *thread_arg);
+
+extern proc_signal_t    g_signal;
+
+/* install default signal process functions  */
+extern void install_default_signal(void);
+
+/* excute a linux command by system() */
+extern void exec_system_cmd(const char *format, ...);
+
+/* check program already running or not, if not then run it and record pid into $pidfile */
+extern int check_set_program_running(int daemon, char *pidfile);
+
+/* stop program running from $pid_file  */
+extern int stop_daemon_running(const char *pid_file);
+
+/* my implementation for set program running in daemon   */
+extern void daemonize(int nochdir, int noclose);
+
+/* start a new thread to run $thread_workbody point function  */
+extern int thread_start(pthread_t *thread_id, thread_body_t thread_workbody, void *thread_arg);
+
+/* +---------------------+
+ * |   Low level API     |
+ * +---------------------+*/
+
+/* record proces ID into $pid_file  */
+extern int record_daemon_pid(const char *pid_file);
+
+/* get daemon process ID from $pid_file   */
+extern pid_t get_daemon_pid(const char *pid_file);
+
+/* check program already running or not from $pid_file  */
+extern int check_daemon_running(const char *pid_file);
+
+/* set program daemon running and record pid in $pid_file  */
+extern int set_daemon_running(const char *pid_file);
+
+#endif
diff --git a/apue/project_socket/src/util_time.h b/apue/project_socket/src/util_time.h
new file mode 100644
index 0000000..0f8dbcc
--- /dev/null
+++ b/apue/project_socket/src/util_time.h
@@ -0,0 +1,186 @@
+/********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  util_time.h
+ *    Description:  This head file is system time, timer API
+ *
+ *        Version:  1.0.0(07/23/2020)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "07/23/2020 07:46:37 AM"
+ *
+ ********************************************************************************/
+#ifndef __UTIL_TIME_H_
+#define __UTIL_TIME_H_
+
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <linux/rtc.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+
+typedef struct date_time_s
+{
+    int year;
+    int month;
+    int day;
+    int hour;
+    int minute;
+    int second;
+    int dayofweek;
+} date_time_t;
+
+/* sleep for micro second */
+static inline void msleep(unsigned long ms)
+{
+    struct timespec  timeout;
+    unsigned long    tmp;
+
+    timeout.tv_sec = ms / 1000;
+    if (timeout.tv_sec == 0)
+    {
+        tmp = ms * 10000;
+        timeout.tv_nsec = tmp * 100;
+    }
+    else
+    {
+        timeout.tv_nsec = 0;
+    }
+
+    nanosleep(&timeout, 0);
+}
+
+/* call gettimeofday() to get current micro second */
+static inline unsigned long time_now()
+{
+    struct timeval            now;
+
+    gettimeofday(&now, 0);
+
+    return (now.tv_sec*1000) + (now.tv_usec/1000);
+}
+
+/* timep has elapsed since $start, unit as micro second*/
+static inline uint32_t time_elapsed(uint32_t start)
+{
+    uint32_t current = time_now();
+
+    if(current >= start)
+        return current-start;
+    else
+        return current+0xFFFFFFFF-start;
+}
+
+/* call gettimeofday() to get current micro second */
+static inline unsigned long time_second()
+{
+    struct timeval            now;
+
+    gettimeofday(&now, 0);
+    return now.tv_sec;
+}
+
+/* timep has elapsed since $start, unit as micro second*/
+static inline uint32_t seconds_elapsed(uint32_t start)
+{
+    uint32_t current = time_second();
+
+    if(current >= start)
+        return current-start;
+    else
+        return current+0xFFFFFFFF-start;
+}
+
+/*
+* These inlines deal with timer wrapping correctly. You are
+* strongly encouraged to use them
+* 1. Because people otherwise forget
+* 2. Because if the timer wrap changes in future you won't have to
+* alter your driver code.
+*
+* time_after(a,b) returns true if the time a is after time b.
+*
+* Do this with "<0" and ">=0" to only test the sign of the result. A
+* good compiler would generate better code (and a really good compiler
+* wouldn't care). Gcc is currently neither.
+*/
+
+#define typecheck(type,x) \
+({      type __dummy; \
+        typeof(x) __dummy2; \
+        (void)(&__dummy == &__dummy2); \
+        1; \
+})
+
+#define time_after(a,b) \
+(typecheck(unsigned long, a) && typecheck(unsigned long, b) && ((long)(b) - (long)(a) < 0))
+#define time_before(a,b) time_after(b,a)
+
+#define time_after_eq(a,b) \
+(typecheck(unsigned long, a) && typecheck(unsigned long, b) && ((long)(a) - (long)(b) >= 0))
+#define time_before_eq(a,b) time_after_eq(b,a)
+
+/* Same as above, but does so with platform independent 64bit types.
+ * These must be used when utilizing jiffies_64 (i.e. return value of
+ * get_jiffies_64() */
+#define time_after64(a,b) \
+    (typecheck(__u64, a) && typecheck(__u64, b) && ((__s64)(b) - (__s64)(a) < 0))
+#define time_before64(a,b)  time_after64(b,a)
+
+#define time_after_eq64(a,b) \
+    (typecheck(__u64, a) && typecheck(__u64, b) && ((__s64)(a) - (__s64)(b) >= 0))
+#define time_before_eq64(a,b)   time_after_eq64(b,a)
+
+
+static inline void get_sys_time(date_time_t *date)
+{
+    time_t now = time(NULL);
+    struct tm *tnow = localtime(&now);
+
+    memset(date, 0, sizeof(*date));
+    date->year = 1900 + tnow->tm_year;
+    date->month = 1 + tnow->tm_mon;
+    date->day = tnow->tm_mday;
+
+    date->hour = tnow->tm_hour;
+    date->minute = tnow->tm_min;
+    date->second = tnow->tm_sec;
+    date->dayofweek = tnow->tm_wday;
+    return;
+}
+
+static inline int get_rtc_time(date_time_t *date)
+{
+    int                 rv, fd = -1;
+    struct rtc_time     rtc_tm;
+
+    memset(date, 0, sizeof(*date));
+
+    if ((fd=open("/dev/rtc0", O_RDONLY)) < 0)
+        return -1;
+
+    if((rv=ioctl(fd, RTC_RD_TIME, &rtc_tm)) < 0)
+        return -2;
+
+    date->year = 1900 + rtc_tm.tm_year;
+    date->month = 1 + rtc_tm.tm_mon;
+    date->day = rtc_tm.tm_mday;
+
+    date->hour = rtc_tm.tm_hour;
+    date->minute = rtc_tm.tm_min;
+    date->second = rtc_tm.tm_sec;
+    date->dayofweek = rtc_tm.tm_wday;
+
+    close(fd);
+
+    return 0;
+}
+
+#endif

--
Gitblit v1.9.1