APUE Learning Example Source Code
guowenxue
2020-04-29 90025642ce97002910ace4654c64035bb91ad4a8
update prj1_tlv source code, test socket client connect ok
7 files modified
7 files added
6156 ■■■■ changed files
prj1_tlv/lylib/crc-itu-t.h 2 ●●● patch | view | raw | blame | history
prj1_tlv/lylib/cscope.in.out patch | view | raw | blame | history
prj1_tlv/lylib/cscope.out 4307 ●●●● patch | view | raw | blame | history
prj1_tlv/lylib/cscope.po.out patch | view | raw | blame | history
prj1_tlv/lylib/ds18b20.c 113 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/ds18b20.h 28 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/logger.c 1 ●●●● patch | view | raw | blame | history
prj1_tlv/lylib/socket.c 789 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/socket.h 176 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/tags 98 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/tlv_pack.c 338 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/tlv_pack.h 77 ●●●●● patch | view | raw | blame | history
prj1_tlv/tlv_client.c 202 ●●●●● patch | view | raw | blame | history
prj1_tlv/tlv_client.log 25 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/crc-itu-t.h
@@ -13,7 +13,7 @@
#ifndef CRC_ITU_T_H
#define CRC_ITU_T_H
#define MAGIC_CRC           0x1E50
#define MAGIC_CRC           0x0107
extern const unsigned short  crc_itu_t_table[256];
prj1_tlv/lylib/cscope.in.out
Binary files differ
prj1_tlv/lylib/cscope.out
Diff too large
prj1_tlv/lylib/cscope.po.out
Binary files differ
prj1_tlv/lylib/ds18b20.c
New file
@@ -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_err("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_err("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_err("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_err("open %s error: %s\n", w1_path, strerror(errno));
        return -2;
    }
    if(read(fd, buf, sizeof(buf)) < 0)
    {
        log_err("read %s error: %s\n", w1_path, strerror(errno));
        close(fd);
        return -2;
    }
    ptr = strstr(buf, "t=");
    if( !ptr )
    {
        log_err("ERROR: Can not get temperature\n");
        close(fd);
        return -2;
    }
    ptr+=2;
    /* use two bytes to save temperature value */
    byte = (uint8_t *)temp;
    byte[0] = atoi(ptr)/1000;      /* integer part */
    byte[1] = (atoi(ptr)%1000)/10; /* fractional part, two digits after */
    close(fd);
    return 0;
}
prj1_tlv/lylib/ds18b20.h
New file
@@ -0,0 +1,28 @@
/********************************************************************************
 *      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]: integer part
 *                     byte[1]: fractional part, two digits after
 */
int ds18b20_get_temperature(uint16_t *temp);
#endif   /* ----- #ifndef _DS18B20_H_  ----- */
prj1_tlv/lylib/logger.c
@@ -17,6 +17,7 @@
static unsigned long log_rollback_size = LOG_ROLLBACK_NONE;
/* This library is not thread safe */
static logger_t *logger = NULL;
char *log_str[LOG_LEVEL_MAX + 1] = { "", "F", "E", "W", "N", "D", "I", "T", "M" };
prj1_tlv/lylib/socket.c
New file
@@ -0,0 +1,789 @@
/*********************************************************************************
 *      Copyright:  (C) 2020 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  socket.c
 *    Description:  This file is for socket API
 *
 *        Version:  1.0.0(2020年04月16日)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "2020年04月16日 13时43分28秒"
 *
 ********************************************************************************/
#include "socket.h"
#include "logger.h"
static int proc_sock_connect(socket_t *sock);
/*  description: initialise socket context and create socket fd
 *   input args: $sock: socket context
 *               $type: SOCK_TYPE_LISTEN, SOCK_TYPE_ACCEPT or SOCK_TYPE_CONNEC
 *               $create: call socket() create or not
 * return value: <0: failure  0: successfully
 */
int socket_ctx_init(socket_t *sock, uint8_t type, int create)
{
    int        fd = -1;
    if( !sock )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    memset(sock, 0, sizeof(*sock));
    sock->type = type;
    sock->keepintvl=600;
    sock->keepcnt = 3;
    if( create )
    {
        fd = socket(AF_INET, SOCK_STREAM, 0);
        if( fd < 0 )
        {
            log_err("Create socket failure: %s\n", strerror(errno));
            return -2;
        }
        sock->fd = fd;
    }
    else
    {
        sock->fd = -1;
    }
    sock->status = SOCK_STAT_INIT;
    return 0;
}
/*  description: close socket
 *   input args: $sock: socket context
 * return value: <0: failure  0: successfully
 */
int socket_close(socket_t *sock)
{
    int           force = 0;
    if( !sock )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    if(sock->fd < 0)
    {
        log_nrml("socket already closed\n");
        return 0;
    }
    log_nrml("start close socket[%d] on port[%d] to [%s:%d]\n", sock->fd, sock->lport, sock->raddr, sock->rport);
    if(force)
    {
        /* If l_onoff is nonzero and l_linger is zero, TCP aborts the connection when it is closed.
         * That is, TCP discards any data still remaining in the socket send buffer and sends an RST
         * to the peer, not the normal four-packet connection termination sequence.  */
        struct linger so_linger;
        so_linger.l_onoff = 1;  /*  Turn on linger */
        so_linger.l_linger = 0; /*  Set the timeout to 0 */
        setsockopt (sock->fd, SOL_SOCKET, SO_LINGER, (char *) &so_linger, sizeof (struct linger));
    }
    if( SOCK_TYPE_ACCEPT==sock->type || SOCK_TYPE_CONNECT==sock->type )
    {
        shutdown(sock->fd, SHUT_RDWR);
    }
    close(sock->fd);
    sock->fd = -1;
    sock->status = SOCK_STAT_INIT;
    return 0;
}
/*  description: create socket and listen on port $port
 *   input args: $sock: socket context
 *             $ipaddr: listen IP address, NULL for any address
 *               $port: listen port
 * return value: <0: failure  0: successfully
 */
int socket_listen(socket_t *sock, char *ipaddr, int port)
{
    int                 rv = 0;
    int                 fd = -1;
    struct sockaddr_in  addr;
    int                 backlog = 13;
    if( !sock )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    if( sock->status != SOCK_STAT_INIT )
    {
        socket_close(sock);
    }
    /* initial listen socket bind address  */
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    if( !ipaddr )
    {
        addr.sin_addr.s_addr = htons(INADDR_ANY);
    }
    else
    {
        if( !inet_pton(AF_INET, ipaddr, &addr.sin_addr) )
        {
            log_err("Listen IP address '%s' not valid\n");
            return -2;
        }
    }
    /* initial socket context and create socket fd  */
    if( socket_ctx_init(sock, SOCK_TYPE_LISTEN, SOCK_CREATE) < 0)
    {
        log_err("socket context initial failure\n");
        return -2;
    }
    strncpy(sock->laddr, (!ipaddr?"0.0.0.0":ipaddr), sizeof(sock->laddr));
    sock->lport = port;
    memset(&sock->raddr, 0, sizeof(sock->raddr));
    sock->rport = 0;
    log_dbg("initial listen socket context ok\n");
    /* set listen port reuseable  */
    socket_set_reuseaddr(sock->fd);
    if( bind(sock->fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
    {
        log_err("bind listen socket failure: %s\n", strerror(errno));
        rv = -3;
        goto cleanup;
    }
    if( listen(sock->fd, backlog) < 0 )
    {
        log_err("Listen on socket[%d] failed: %s\n", sock->fd, strerror(errno));
        rv = -4;
        goto cleanup;
    }
    log_nrml("create socket and listen on [%s:%d] already\n", sock->laddr, sock->lport);
cleanup:
    if( rv )
    {
        log_err("Create socket listen on [%s:%d] failed\n", sock->laddr, sock->lport);
        socket_close(sock);
    }
    else
    {
        sock->status = SOCK_STAT_LISTENED;
        log_nrml("Create socket[%p:%d] listen [%s:%d] ok\n", sock, sock->fd, sock->laddr, sock->lport);
    }
    return rv;
}
/*  description: create socket and connect to server
 *   input args: $sock: socket context
 *               $host: IP address and port, format as "host:port", such as "127.0.0.1:8000"
 *               $block: block mode(1) or non-block(0)
 *return value:  <0: error   0: connecing in non-block mode   1:connected
 */
int socket_connect(socket_t *sock, int lport, char *host, int block)
{
    int                 rv = 0;
    char                service[20];
    struct addrinfo     hints, *rp;
    struct addrinfo    *res = NULL;
    struct in_addr      inaddr;
    struct sockaddr_in  addr;
    int                 len = sizeof(addr);
    if( !sock )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    /* socket already connected */
    if( SOCK_STAT_CONNECTED == sock->status )
    {
        return 1;
    }
    /* socket connecting in none-block mode */
    else if( SOCK_STAT_CONNECTING == sock->status )
    {
        log_dbg("socket continue connect to remote server [%s:%d]\n", sock->raddr, sock->rport);
        rv = proc_sock_connect(sock);
        goto out;
    }
    /* socket not initial before */
    if( SOCK_STAT_UNINIT== sock->status )
    {
        if( socket_ctx_init(sock, SOCK_TYPE_LISTEN, SOCK_NOT_CREATE) < 0)
        {
            log_err("ERROR: initial socket context failure\n");
            return -2;
        }
        if( parser_host_port(sock, host)<0 || sock->rport<=0 )
        {
            log_err("parser connect server hostname and port [%s] failure\n", host);
            return -3;
        }
        if( lport>0 )
        {
            sock->lport = lport;
        }
        log_dbg("initial socket context ok\n");
    }
    log_nrml("start create socket connect to server [%s:%d] now\n", sock->raddr, sock->rport);
    /*+--------------------------------------------------+
     *| use getaddrinfo() to do domain name translation  |
     *+--------------------------------------------------+*/
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET; /* Only support IPv4 */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP; /* TCP protocol */
    /* If 'raddr' is a valid IP address, then don't use name resolution */
    if( inet_aton(sock->raddr, &inaddr) )
    {
        log_info("%s is a valid IP address, don't use domain name resolution.\n", sock->raddr);
        hints.ai_flags |= AI_NUMERICHOST;
    }
    /* Obtain address(es) matching host/port */
    snprintf(service, sizeof(service), "%d", sock->rport);
    if( (rv=getaddrinfo(sock->raddr, service, &hints, &res)) )
    {
        log_err("getaddrinfo() parser [%s:%s] failed: %s\n", sock->raddr, service, gai_strerror(rv));
        return -3;
    }
    /* close any opened socket on it */
    socket_close(sock);
    /* getaddrinfo() returns a list of address structures. Try each
       address until we successfully connect or bind */
    for (rp=res; rp!=NULL; rp=rp->ai_next)
    {
        char                  ipaddr[INET_ADDRSTRLEN];
        struct sockaddr_in   *sp = (struct sockaddr_in *) rp->ai_addr;
        /* check and print domain name translation result  */
        memset( ipaddr, 0, sizeof(ipaddr) );
        if( inet_ntop(AF_INET, &sp->sin_addr, ipaddr, sizeof(ipaddr)) )
        {
            log_nrml("domain name resolution [%s->%s]\n", sock->raddr, ipaddr);
        }
        memcpy(&sock->saddr, rp->ai_addr, sizeof(sock->saddr));
        /*  Create the socket */
        sock->fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
        if( sock->fd < 0)
        {
            log_err("socket() create failed: %s\n", strerror(errno));
            rv = -3;
            continue;
        }
        log_info("socket[%d] for connect create ok\n", sock->fd);
        /*  bind local port to socket if needed */
        if(sock->lport > 0)
        {
            memset(&addr, 0, len);
            addr.sin_family = AF_INET;
            addr.sin_port = htons ((u_short) sock->lport);
            if ( bind(sock->fd, (struct sockaddr *)&addr, len) )
            {
                rv = -4;
                close(sock->fd);
                log_err("Bind port[%d] to connect socket [%d] failed: %s\n", sock->lport, sock->fd, strerror(errno));
                continue;
            }
            else
            {
                rv = 0;
                log_dbg("Bind local port[%d] to connect socket [%d] OK\n", lport, sock->fd);
            }
        }
        /* Set socket options */
        if( !block )
        {
            socket_set_nonblock(sock->fd);
        }
        socket_set_keepalive(sock->fd, sock->keepintvl, sock->keepcnt);
        if( (rv=proc_sock_connect(sock)) >= 0 )
        {
            /* connecting or connected already */
            break;
        }
        else
        {
            /* socket connect get error, try another IP address */
            close(sock->fd);
            continue;
        }
    }
    freeaddrinfo(res);
out:
    return rv;
}
/*  description: connect() server and check the connect result
 *   input args: $sock: socket context
 *return value:  <0: Error   0: Connecing in non-block mode   1:Connected
 */
static int proc_sock_connect(socket_t *sock)
{
    int          rv;
    int          len = sizeof(struct sockaddr);
    if( !sock || sock->fd<0 )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    log_nrml("socket[%d] try to connect to server [%s:%d] now...\n", sock->fd, sock->raddr, sock->rport);
    rv = connect(sock->fd, &sock->saddr, len);
    if( 0 == rv )
    {
        sock->status = SOCK_STAT_CONNECTED;
        rv = 1;
        goto out;
    }
    /* rv < 0, connect failure will continue to check */
    switch (errno)
    {
        case EISCONN:
            sock->status = SOCK_STAT_CONNECTED;
            rv = 1;
            break;
        case EALREADY:
        case EINPROGRESS:
            sock->status = SOCK_STAT_CONNECTING;
            rv = 0;
            break;
        default:
            sock->status = SOCK_STAT_UNINIT;
            rv = -7;
            break;
    }
out:
    if( rv > 0 )
    {
        log_nrml("socket[%d] connected to remote server [%s:%d]\n", sock->fd, sock->raddr, sock->rport);
    }
    else if ( rv == 0 )
    {
        log_nrml("socket[%d] connect to remote server [%s:%d] in progressing\n", sock->fd, sock->raddr, sock->rport);
    }
    else
    {
        log_err("socket[%d] connect to remote [%s:%d] failed: %s\n", sock->fd, sock->raddr, sock->rport, strerror(errno));
        socket_close(sock);
    }
    return rv;
}
/*  description: accept a new client socket
 *   input args: $sock: socket context
 *               $listenfd: listen socket fd
 * return value: <0: failure  0: successfully
 */
int socket_accept(socket_t *sock, int listenfd)
{
    if( !sock )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
}
/*  description: send data to the socket, make sure all data send over.
 *   input args: $sock: socket context
 *               $data: send data
 *               $bytes: data size
 * return value: <0: failure  0: successfully
 */
int socket_send(socket_t *sock, char *data, int bytes)
{
    int            rv = 0;
    int            i = 0;
    int            left_bytes = bytes;
    if( !sock || !data || bytes<=0 )
    {
        log_err("Invalid input arguments\n");
        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_close(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 in some time
 *   input args: $sock: socket context
 *               $data: send data
 *               $bytes: data size
 *               $timeout: receive data time, <=0 will don't timeout
 * return value: <0: error  >=0: receive data bytes;
 */
int socket_recv(socket_t *sock, char *buf, int size, int timeout)
{
    int               rv = 0;
    int               i = 0;
    fd_set            fdsr;
    int               maxsock;
    if( !sock || sock->fd<0 || !buf ||size<=0 )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    memset(buf, 0, size);
    maxsock = sock->fd;
    FD_ZERO(&fdsr);
    FD_SET(sock->fd, &fdsr);
    if( timeout <= 0 ) /* no timeout  */
    {
        rv=select(maxsock+1, &fdsr, NULL, NULL, NULL);
    }
    else
    {
        struct timeval    tv;
        tv.tv_sec = timeout;
        tv.tv_usec = 0;
        rv=select(maxsock+1, &fdsr, NULL, NULL, &tv);
    }
    if( rv < 0 )
    {
        log_err("select() read from socket[%d] failure: %s\n", sock->fd, strerror(errno));
        return -2;
    }
    else if( rv == 0 )
    {
        log_err("select() read from socket[%d] get timeout\n", sock->fd);
        return 0;
    }
    else
    {
        rv = read(sock->fd, buf, size);
        if( rv < 0 )
        {
            log_err("socket[%d] read() failure: %s, close socket now\n", sock->fd, strerror(errno));
            socket_close(sock);
            return -2;
        }
        else if( rv == 0 )
        {
            log_err("socket[%d] read() get peer disconnect, close socket now\n", sock->fd);
            socket_close(sock);
            return -2;
        }
        else
        {
            log_dbg("socket[%d] receive %d bytes data\n", sock->fd, rv);
            logger_dump(LOG_LEVEL_INFO, buf, rv);
            return rv;
        }
    }
}
/*  description: parser hostname and port from $host and set it into $sock
 *   input args: $sock: socket context
 *               $host: connect hostname, format as "hostname:port"
 */
int parser_host_port(socket_t *sock, char *host)
{
    char          *ptr = NULL;
    int            len = 0;
    if( !sock || !host )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    ptr = strchr(host, ':');
    if( !ptr )
    {
        log_err("Invalid arguments for host, format should be 'hostname:port'\n");
        return -1;
    }
    len = ptr-host;
    if( len >  sizeof(sock->raddr) )
        len = sizeof(sock->raddr);
    memcpy(sock->raddr, host, ptr-host);
    sock->rport = atoi(ptr+1);
    log_info("paser host[%s] to '%s:%d'\n", host, sock->raddr, sock->rport);
    return 0;
}
int socket_set_reuseaddr(int sockfd)
{
    int opt = 1;
    int len = sizeof (int);
    if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, len))
    {
        log_err("Set socket[%d] option SO_REUSEADDR failed:%s\n", sockfd, strerror(errno));
        return -1;
    }
    log_dbg("Set socket[%d] option SO_REUSEADDR ok\n", sockfd);
    return 0;
}
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_dbg("Set socket[%d] none blocking\n", sockfd);
    return opts;
}
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_err("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_err("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_err("setsockopt() set TCP_KEEPCNT to %d failure: %s\n", opt, strerror(errno));
                return -5;
            }
        }
    }
    log_dbg("Set socket[%d] KEEPINTVL:%d  KEEPCNT:%d\n", sockfd, keepintvl, keepcnt);
    return 0;
}
prj1_tlv/lylib/socket.h
New file
@@ -0,0 +1,176 @@
/********************************************************************************
 *      Copyright:  (C) 2020 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  socket.h
 *    Description:  This head file is for socket API
 *
 *        Version:  1.0.0(2020年04月16日)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "2020年04月16日 13时45分33秒"
 *
 ********************************************************************************/
#ifndef  _SOCKET_H_
#define  _SOCKET_H_
#include <stdio.h>
#include <stdlib.h>
#include <stdint.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>
#define HOSTNAME_LEN         128
enum
{
    SOCK_TYPE_LISTEN,  /* listen  socket */
    SOCK_TYPE_ACCEPT,  /* accept  socket */
    SOCK_TYPE_CONNECT, /* connect socket */
};
enum
{
    SOCK_STAT_UNINIT     = 0,  /* socket not initial */
    SOCK_STAT_INIT       = 1,  /* socket initialed */
    SOCK_STAT_CONNECTING = 2,  /* socket connecting in non-block mode */
    SOCK_STAT_CONNECTED  = 3,  /* socket connected in client mdoe */
    SOCK_STAT_LISTENED   = 3,  /* socket listened  in server mode */
    SOCK_STAT_ACCEPTED   = 3,  /* socket already accepted */
};
typedef struct socket_s
{
    int            fd;          /* socket fd  */
    uint8_t        type;        /* socket type: listen, accept or accept */
    uint8_t        status;      /* socket status: SOCK_STAT_INIT,SOCK_STAT_CONNECTED... */
    /* socket server/client IP address and port */
    char           raddr[HOSTNAME_LEN];  /* remote IP address or domain name */
    char           laddr[HOSTNAME_LEN];  /* local IP address */
    uint16_t       lport;                /* local listen port */
    uint16_t       rport;                /* remote connected port */
    /* socket heartbeat settings  */
    int            keepintvl;   /* keepalive detect interval */
    int            keepcnt;     /* keepalive count */
    struct sockaddr  saddr;              /*  sockaddr for connect */
} socket_t;
/*+-------------------------------------------------------------------+
 *|           client/server  socket API functions                     |
 *+-------------------------------------------------------------------+*/
/*  description: initialise socket context and create socket fd if sepecified
 *   input args: $sock: socket context
 *               $type: SOCK_TYPE_LISTEN, SOCK_TYPE_ACCEPT or SOCK_TYPE_CONNEC
 *               $create: call socket() create or not
 * return value: <0: failure  0: successfully
 */
enum
{
    SOCK_NOT_CREATE,
    SOCK_CREATE,
};
int socket_ctx_init(socket_t *sock, uint8_t type, int create);
/*  description: close socket and set socket status as SOCK_STAT_INIT
 *   input args: $sock: socket context
 * return value: <0: failure  0: successfully
 */
int socket_close(socket_t *sock);
/*  description: close socket
 *   input args: $sock: socket context
 *               $lport: specify use local port $lport to connect remote server
 *               $host: IP address and port, format as "host:port", such as "127.0.0.1:8000"
 *              $block: block mode(1) or none-block(0)
 *return value:  <0: error   0: connecing in non-block mode   1:connected
 */
enum
{
    MODE_NONBLOCK,
    MODE_BLOCK,
};
int socket_connect(socket_t *sock, int lport, char *host, int block);
/*  description: create socket and listen on port $port
 *   input args: $sock: socket context
 *                 $ip: listen IP address, NULL for any address
 *               $port: listen port
 * return value: <0: failure  0: successfully
 */
int socket_listen(socket_t *sock, char *ipaddr, int port);
/*  description: accept a new client socket
 *   input args: $sock: socket context
 *               $listenfd: listen socket fd
 * return value: <0: failure  0: successfully
 */
int socket_accept(socket_t *sock, int listenfd);
/*  description: send data to the socket, make sure all data send over.
 *   input args: $sock: socket context
 *               $data: send data
 *               $bytes: data size
 * return value: <0: failure  0: successfully
 */
int socket_send(socket_t *sock, char *data, int bytes);
/*  description: receive data from the socket in some time
 *   input args: $sock: socket context
 *               $data: send data
 *               $bytes: data size
 *               $timeout: receive data time, <=0 will don't timeout
 * return value: <0: error  >=0: receive data bytes;
 */
int socket_recv(socket_t *sock, char *buf, int size, int timeout);
/*+-------------------------------------------------------------------+
 *|                socket utils function                              |
 *+-------------------------------------------------------------------+*/
/*  description: parser hostname and port from $host and set it into $sock
 *   input args: $sock: socket context
 *               $host: connect hostname, format as "hostname:port"
 */
int parser_host_port(socket_t *sock, char *host);
/* description: set socket listen port as reusable, fix port already used bug  */
int socket_set_reuseaddr(int sockfd);
/* set socket as non-block mode, common socket default work as block mode */
int socket_set_nonblock(int sockfd);
/* set socket receive and send buffer size in linux kernel space */
int socket_set_buffer(int sockfd, int rsize, int ssize);
/* set heartbeat keepalive  */
int socket_set_keepalive(int sockfd, int keepintvl, int keepcnt);
#endif   /* ----- #ifndef _SOCKET_H_  ----- */
prj1_tlv/lylib/tags
@@ -4,9 +4,8 @@
!_TAG_PROGRAM_NAME    Exuberant Ctags    //
!_TAG_PROGRAM_URL    http://ctags.sourceforge.net    /official site/
!_TAG_PROGRAM_VERSION    5.9~svn20110310    //
BUFSIZE    tlv_sample.c    21;"    d    file:
CHARS_PER_LINE    logger.c    334;"    d    file:
CHARS_PER_LINE    tlv_sample.c    156;"    d    file:
CHARS_PER_LINE    logger.c    335;"    d    file:
CHARS_PER_LINE    tlv_pack.c    102;"    d    file:
CRC_ITU_T_H    crc-itu-t.h    14;"    d
DBG_LOG_FILE    logger.h    35;"    d
DEFAULT_TIME_FORMAT    logger.h    40;"    d
@@ -14,8 +13,8 @@
FLAG_LOGGER_CONSOLE    logger.h    63;"    d
FLAG_LOGGER_FILE    logger.h    64;"    d
FLAG_LOGGER_LEVEL_OPT    logger.h    61;"    d
LINELEN    logger.c    333;"    d    file:
LINELEN    tlv_sample.c    155;"    d    file:
LINELEN    logger.c    334;"    d    file:
LINELEN    tlv_pack.c    101;"    d    file:
LOG_FILE_LINE    logger.h    92;"    d
LOG_LEVEL_DEBUG    logger.h    /^    LOG_LEVEL_DEBUG,                  \/*  Debug Level "Debug" *\/$/;"    e    enum:__anon1
LOG_LEVEL_DISB    logger.h    /^    LOG_LEVEL_DISB = 0,               \/*  Disable "Debug" *\/$/;"    e    enum:__anon1
@@ -28,46 +27,47 @@
LOG_LEVEL_WARN    logger.h    /^    LOG_LEVEL_WARN,                   \/*  Debug Level "warnning" *\/$/;"    e    enum:__anon1
LOG_ROLLBACK_NONE    logger.h    38;"    d
LOG_ROLLBACK_SIZE    logger.h    37;"    d
LOG_TIME_FMT    logger.c    24;"    d    file:
LOG_TIME_FMT    logger.c    25;"    d    file:
LOG_VERSION_STR    logger.h    29;"    d
MAGIC_CRC    crc-itu-t.h    16;"    d
MAX_LOG_MESSAGE_LEN    logger.h    41;"    d
OFF    tlv_sample.c    18;"    d    file:
ON    tlv_sample.c    19;"    d    file:
PACK_HEADER    tlv_sample.c    30;"    d    file:
PACK_HEADER    tlv_pack.h    26;"    d
PID_ASCII_SIZE    proc.h    18;"    d
PRECISE_TIME_FACTOR    logger.c    16;"    d    file:
TAG_CAMERA    tlv_sample.c    /^    TAG_CAMERA,$/;"    e    enum:__anon2    file:
TAG_LED    tlv_sample.c    /^    TAG_LED,$/;"    e    enum:__anon2    file:
TAG_LOGON    tlv_sample.c    /^    TAG_LOGON=1,$/;"    e    enum:__anon2    file:
TLV_FIXED_SIZE    tlv_sample.c    41;"    d    file:
TLV_MIN_SIZE    tlv_sample.c    44;"    d    file:
TAG_ACK    tlv_pack.h    /^    TAG_ACK=1,$/;"    e    enum:__anon2
TAG_SN    tlv_pack.h    /^    TAG_SN,$/;"    e    enum:__anon2
TAG_TEMP    tlv_pack.h    /^    TAG_TEMP,$/;"    e    enum:__anon2
TAG_TIME    tlv_pack.h    /^    TAG_TIME,$/;"    e    enum:__anon2
TLV_BUFSIZE    tlv_pack.h    44;"    d
TLV_FIXED_SIZE    tlv_pack.h    29;"    d
TLV_MIN_SIZE    tlv_pack.h    32;"    d
_DS18B20_H_    ds18b20.h    15;"    d
_LOGGER_H_    logger.h    15;"    d
_PROC_H_    proc.h    15;"    d
_TLV_PACK_H_    tlv_pack.h    14;"    d
_curOffset    logger.c    /^        long _curOffset = ftell(logger->fp);$/;"    l
act    logger.c    /^    struct sigaction act;$/;"    l
argp    logger.c    /^    va_list argp;$/;"    l
args    proc.c    /^    va_list             args;$/;"    l
buf    ds18b20.c    /^    char            buf[128];$/;"    l
buf    logger.c    /^    char buf[MAX_LOG_MESSAGE_LEN];$/;"    l
buf    tlv_sample.c    /^    char          buf[BUFSIZE];$/;"    l
bytes    tlv_sample.c    /^    int           bytes;$/;"    l
buf    tlv_pack.h    /^    char                   buf[TLV_BUFSIZE];$/;"    m    struct:tlv_buf_s    access:public
byte    ds18b20.c    /^    uint8_t        *byte;$/;"    l
bytes_to_ushort    crc-itu-t.c    /^unsigned short bytes_to_ushort(unsigned char *bytes, int len)$/;"    f    signature:(unsigned char *bytes, int len)
bytes_to_ushort    crc-itu-t.h    /^extern unsigned short bytes_to_ushort(unsigned char *bytes, int len);$/;"    p    signature:(unsigned char *bytes, int len)
c    logger.c    /^            unsigned char c = buf[idx];$/;"    l
c    tlv_sample.c    /^            unsigned char c = data[idx];$/;"    l
c    tlv_pack.c    /^            unsigned char c = data[idx];$/;"    l
check_and_rollback    logger.c    /^static void check_and_rollback(void)$/;"    f    file:    signature:(void)
check_daemon_running    proc.c    /^int check_daemon_running(const char *pid_file)$/;"    f    signature:(const char *pid_file)
check_daemon_running    proc.h    /^extern int check_daemon_running(const char *pid_file);$/;"    p    signature:(const char *pid_file)
chip    ds18b20.c    /^    char            chip[20];$/;"    l
chmod    proc.c    /^        (void)chmod(ipc_dir, mode); $/;"    p    file:
cmd    logger.c    /^            char cmd[512];$/;"    l
cmd    proc.c    /^    char                cmd[256];$/;"    l
cp_install_proc_signal    proc.c    /^void cp_install_proc_signal(void)$/;"    f    signature:(void)
cp_install_proc_signal    proc.h    /^extern void cp_install_proc_signal(void);$/;"    p    signature:(void)
cp_printout    logger.c    /^static void cp_printout(char *level, char *fmt, va_list argp)$/;"    f    file:    signature:(char *level, char *fmt, va_list argp)
cp_printout_line    logger.c    /^static void cp_printout_line(char *level, char *fmt, char *file, int line, va_list argp)$/;"    f    file:    signature:(char *level, char *fmt, char *file, int line, va_list argp)
cp_proc_sighandler    proc.c    /^void cp_proc_sighandler(int sig)$/;"    f    signature:(int sig)
crc16    tlv_sample.c    /^    unsigned short      crc16 = 0;$/;"    l
crc16    tlv_sample.c    /^    unsigned short      crc16;$/;"    l
crc16    tlv_pack.c    /^    unsigned short      crc16 = 0;$/;"    l
crc16    tlv_pack.c    /^    unsigned short      crc16;$/;"    l
crc_itu_t    crc-itu-t.c    /^unsigned short crc_itu_t(unsigned short crc, const unsigned char *buffer, unsigned int len)$/;"    f    signature:(unsigned short crc, const unsigned char *buffer, unsigned int len)
crc_itu_t    crc-itu-t.h    /^extern unsigned short crc_itu_t(unsigned short magic_crc, const unsigned char *buffer, unsigned int len);$/;"    p    signature:(unsigned short magic_crc, const unsigned char *buffer, unsigned int len)
crc_itu_t_byte    crc-itu-t.h    /^static inline unsigned short crc_itu_t_byte(unsigned short crc, const unsigned char data)$/;"    f    signature:(unsigned short crc, const unsigned char data)
@@ -75,10 +75,13 @@
crc_itu_t_table    crc-itu-t.h    /^extern const unsigned short  crc_itu_t_table[256];$/;"    x
daemonize    proc.c    /^void daemonize(int nochdir, int noclose)$/;"    f    signature:(int nochdir, int noclose)
daemonize    proc.h    /^extern void daemonize(int nochdir, int noclose);$/;"    p    signature:(int nochdir, int noclose)
data_len    tlv_sample.c    /^    int                 data_len = 0;$/;"    l
direntp    ds18b20.c    /^    struct dirent  *direntp;$/;"    l
dirp    ds18b20.c    /^    DIR            *dirp;$/;"    l
done    proc.c    /^    int                 done; $/;"    l
dump_buf    tlv_sample.c    /^void dump_buf(char *data, int len)$/;"    f    signature:(char *data, int len)
dump_buf    tlv_sample.c    /^void dump_buf(char *data, int len);$/;"    p    file:    signature:(char *data, int len)
ds18b20_get_temperature    ds18b20.c    /^int ds18b20_get_temperature(uint16_t *temp)$/;"    f    signature:(uint16_t *temp)
ds18b20_get_temperature    ds18b20.h    /^int ds18b20_get_temperature(uint16_t *temp);$/;"    p    signature:(uint16_t *temp)
dump_buf    tlv_pack.c    /^void dump_buf(char *data, int len)$/;"    f    signature:(char *data, int len)
dump_buf    tlv_pack.h    /^void dump_buf(char *data, int len);$/;"    p    signature:(char *data, int len)
exec_system_cmd    proc.c    /^void exec_system_cmd(const char *format, ...)$/;"    f    signature:(const char *format, ...)
exec_system_cmd    proc.h    /^extern void exec_system_cmd(const char *format, ...);$/;"    p    signature:(const char *format, ...)
f    proc.c    /^    FILE *f; $/;"    l
@@ -86,31 +89,36 @@
fStatBuf    proc.c    /^    struct stat fStatBuf; $/;"    l
fStatBuf    proc.c    /^    struct stat fStatBuf;$/;"    l
fclose    proc.c    /^        (void)fclose(f); $/;"    p    file:
fd    ds18b20.c    /^    int             fd =-1;$/;"    l
fd    proc.c    /^    int fd = -1; $/;"    l
fd    proc.c    /^    int retval, fd; $/;"    l
fgets    proc.c    /^        (void)fgets(pid_ascii, PID_ASCII_SIZE, f); $/;"    p    file:
file    logger.h    /^    char               file[FILENAME_LEN];$/;"    m    struct:logger_s    access:public
filemode    logger.c    /^    char *filemode;$/;"    l
flag    logger.h    /^    unsigned char      flag;$/;"    m    struct:logger_s    access:public
found    ds18b20.c    /^    int             found = 0;$/;"    l
fp    logger.h    /^    FILE               *fp;$/;"    m    struct:logger_s    access:public
g_signal    proc.c    /^proc_signal_t     g_signal={0};$/;"    v
g_signal    proc.h    /^extern proc_signal_t     g_signal;$/;"    x
get_daemon_pid    proc.c    /^pid_t get_daemon_pid(const char *pid_file)$/;"    f    signature:(const char *pid_file)
get_daemon_pid    proc.h    /^extern pid_t get_daemon_pid(const char *pid_file);$/;"    p    signature:(const char *pid_file)
hc    logger.c    /^    char hc[4];$/;"    l
hc    tlv_sample.c    /^    char hc[4];$/;"    l
hc    tlv_pack.c    /^    char hc[4];$/;"    l
i    crc-itu-t.c    /^    int              i = 0;$/;"    l
i    crc-itu-t.c    /^    int            i = 0;$/;"    l
i    proc.c    /^    int i; $/;"    l
idx    logger.c    /^    int idx;$/;"    l
idx    tlv_sample.c    /^    int idx;$/;"    l
idx    tlv_pack.c    /^    int idx;$/;"    l
install_proc_signal    proc.c    /^void install_proc_signal(void)$/;"    f    signature:(void)
install_proc_signal    proc.h    /^extern void install_proc_signal(void);$/;"    p    signature:(void)
ipc_dir    proc.c    /^    char ipc_dir[64] = { 0 }; $/;"    l
ldx    logger.c    /^        int ldx = idx % CHARS_PER_LINE;$/;"    l
len    tlv_pack.h    /^    int                    len;$/;"    m    struct:tlv_buf_s    access:public
level    logger.h    /^    int                level;$/;"    m    struct:logger_s    access:public
line_done    logger.c    /^    short line_done = 1;$/;"    l
line_done    tlv_sample.c    /^    short line_done = 1;$/;"    l
line_done    tlv_pack.c    /^    short line_done = 1;$/;"    l
lit    logger.c    /^    char lit[CHARS_PER_LINE + 2];$/;"    l
lit    tlv_sample.c    /^    char lit[CHARS_PER_LINE + 1];$/;"    l
lit    tlv_pack.c    /^    char lit[CHARS_PER_LINE + 1];$/;"    l
local    logger.c    /^    struct tm *local;$/;"    l
log_dbg    logger.h    105;"    d
log_dbg    logger.h    97;"    d
@@ -160,33 +168,37 @@
logger_t    logger.h    /^} logger_t;$/;"    t    typeref:struct:logger_s
logger_term    logger.c    /^void logger_term(void)$/;"    f    signature:(void)
logger_term    logger.h    /^extern void logger_term(void);$/;"    p    signature:(void)
main    tlv_sample.c    /^int main(int argc, char **argv)$/;"    f    signature:(int argc, char **argv)
mode    proc.c    /^    int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;$/;"    l
now    logger.c    /^    struct timeval now;$/;"    l
ofset    tlv_sample.c    /^    int                 ofset = 0; \/* index position for the buf *\/$/;"    l
pack_len    tlv_sample.c    /^    int                 pack_len = 0;$/;"    l
pack_len    tlv_sample.c    /^    int                 pack_len = TLV_FIXED_SIZE+1; \/* Only 1 byte data *\/$/;"    l
packtlv_led    tlv_sample.c    /^int packtlv_led(char *buf, int size, int cmd)$/;"    f    signature:(char *buf, int size, int cmd)
packtlv_led    tlv_sample.c    /^int packtlv_led(char *buf, int size, int cmd);$/;"    p    file:    signature:(char *buf, int size, int cmd)
packtlv_logon    tlv_sample.c    /^int packtlv_logon(char *buf, int size, char *pwd)$/;"    f    signature:(char *buf, int size, char *pwd)
packtlv_logon    tlv_sample.c    /^int packtlv_logon(char *buf, int size, char *pwd);$/;"    p    file:    signature:(char *buf, int size, char *pwd)
ofset    tlv_pack.c    /^    int                 ofset = 0; \/* index position for the buf *\/$/;"    l
pack_len    tlv_pack.c    /^    int                 pack_len = 0;$/;"    l
pack_len    tlv_pack.c    /^    int                 pack_len = TLV_FIXED_SIZE+1; \/* Only 1 byte data *\/$/;"    l
packtlv_ack    tlv_pack.c    /^int packtlv_ack(char *buf, int size, int ack)$/;"    f    signature:(char *buf, int size, int ack)
packtlv_ack    tlv_pack.h    /^int packtlv_ack (char *buf, int size, int ack);$/;"    p    signature:(char *buf, int size, int ack)
packtlv_led    tlv_pack.c    /^int packtlv_led(char *buf, int size, int cmd)$/;"    f    signature:(char *buf, int size, int cmd)
packtlv_msg    tlv_pack.h    /^int packtlv_msg(tlv_buf_t *tlv, char *sn, uint16_t temp, struct tm *tm);$/;"    p    signature:(tlv_buf_t *tlv, char *sn, uint16_t temp, struct tm *tm)
packtlv_sn    tlv_pack.h    /^int packtlv_sn  (char *buf, int size, char *sn);$/;"    p    signature:(char *buf, int size, char *sn)
packtlv_temp    tlv_pack.h    /^int packtlv_temp(char *buf, int size, uint16_t temp);$/;"    p    signature:(char *buf, int size, uint16_t temp)
packtlv_time    tlv_pack.h    /^int packtlv_time(char *buf, int size, struct tm *tm);$/;"    p    signature:(char *buf, int size, struct tm *tm)
pid    proc.c    /^        char pid[PID_ASCII_SIZE]; $/;"    l
pid    proc.c    /^        pid_t pid = -1; $/;"    l
pid    proc.c    /^    pid_t            pid = -1; $/;"    l
pid    proc.c    /^    pid_t pid; $/;"    l
pid_ascii    proc.c    /^        char pid_ascii[PID_ASCII_SIZE]; $/;"    l
print_char    logger.c    /^static char *print_char =$/;"    v    file:
print_char    tlv_sample.c    /^static char *print_char =$/;"    v    file:
print_char    tlv_pack.c    /^static char *print_char =$/;"    v    file:
prn    logger.c    /^    char prn[LINELEN];$/;"    l
prn    tlv_sample.c    /^    char prn[LINELEN];$/;"    l
prn    tlv_pack.c    /^    char prn[LINELEN];$/;"    l
proc_sighandler    proc.c    /^void proc_sighandler(int sig)$/;"    f    signature:(int sig)
proc_signal_s    proc.h    /^typedef struct proc_signal_s$/;"    s
proc_signal_s::signal    proc.h    /^    int       signal;$/;"    m    struct:proc_signal_s    access:public
proc_signal_s::stop    proc.h    /^    unsigned  stop;     \/* 0: Not term  1: Stop  *\/$/;"    m    struct:proc_signal_s    access:public
proc_signal_s::threads    proc.h    /^    int       threads;  \/* threads counter *\/$/;"    m    struct:proc_signal_s    access:public
proc_signal_t    proc.h    /^}  proc_signal_t;$/;"    t    typeref:struct:proc_signal_s
ptr    ds18b20.c    /^    char           *ptr;$/;"    l
rc    logger.c    /^    int rc = 0;$/;"    l
rc    logger.c    /^    int rc;$/;"    l
rc    tlv_sample.c    /^    int rc;$/;"    l
rc    tlv_pack.c    /^    int rc;$/;"    l
record_daemon_pid    proc.c    /^int record_daemon_pid(const char *pid_file)$/;"    f    signature:(const char *pid_file)
record_daemon_pid    proc.h    /^extern int record_daemon_pid(const char *pid_file);$/;"    p    signature:(const char *pid_file)
retVal    proc.c    /^    int retVal = -1; $/;"    l
@@ -210,6 +222,12 @@
thread_stop    proc.h    /^extern void thread_stop(char *prompt);$/;"    p    signature:(char *prompt)
threads    proc.h    /^    int       threads;  \/* threads counter *\/$/;"    m    struct:proc_signal_s    access:public
timestr    logger.c    /^    char timestr[256];$/;"    l
tlv_buf_s    tlv_pack.h    /^typedef struct tlv_buf_s $/;"    s
tlv_buf_s::buf    tlv_pack.h    /^    char                   buf[TLV_BUFSIZE];$/;"    m    struct:tlv_buf_s    access:public
tlv_buf_s::len    tlv_pack.h    /^    int                    len;$/;"    m    struct:tlv_buf_s    access:public
tlv_buf_t    tlv_pack.h    /^} tlv_buf_t;  $/;"    t    typeref:struct:tlv_buf_s
ushort_to_bytes    crc-itu-t.c    /^int ushort_to_bytes(unsigned char *bytes, unsigned short val)$/;"    f    signature:(unsigned char *bytes, unsigned short val)
ushort_to_bytes    crc-itu-t.h    /^extern int ushort_to_bytes(unsigned char *bytes, unsigned short val);$/;"    p    signature:(unsigned char *bytes, unsigned short val)
val    crc-itu-t.c    /^    unsigned short val = 0;$/;"    l
value    ds18b20.c    /^    float           value;$/;"    l
w1_path    ds18b20.c    /^    char            w1_path[50] = "\/sys\/bus\/w1\/devices\/";$/;"    l
prj1_tlv/lylib/tlv_pack.c
New file
@@ -0,0 +1,338 @@
/*********************************************************************************
 *      Copyright:  (C) 2020 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  tlv_pack.h
 *    Description:  This head file is for TLV packet
 *
 *        Version:  1.0.0(2020年04月14日)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "2020年04月14日 00时52分56秒"
 *
 ********************************************************************************/
#include <stdio.h>
#include <string.h>
#include "tlv_pack.h"
#include "crc-itu-t.h"
int packtlv_ack(char *buf, int size, int ack)
{
    unsigned short      crc16 = 0;
    int                 pack_len = 0;
    int                 ofset = 0; /* index position for the buf */
    if(!buf || size<TLV_MIN_SIZE )
    {
        printf("Invalid input arguments\n");
        return 0;
    }
    /*+-------------------------+
     *|   1.fill packet Header  |
     *+-------------------------+*/
    buf[ofset] = PACK_HEADER;
    ofset += 1;
    /*+-------------------------+
     *|   2.fill packet Tag     |
     *+-------------------------+*/
    buf[ofset] = TAG_ACK;
    ofset += 1;
    /*+-------------------------+
     *|   3.fill packet Length  |
     *+-------------------------+*/
    /* ACK message only get 1B payload data */
    pack_len = TLV_FIXED_SIZE + 1;
    buf[ofset] = pack_len;
    ofset += 1;
    /*+-------------------------+
     *|   4.fill packet Value   |
     *+-------------------------+*/
    if( ack )
        buf[ofset++] = 1; /* 1 for ACK */
    else
        buf[ofset++] = 0; /* 0 for NAK */
    /*+-------------------------+
     *|   5.fill packet CRC     |
     *+-------------------------+*/
    /* Calc CRC16 checksum value from Packet Head(buf[0]) ~ Value(buf[ofset]) */
    crc16 = crc_itu_t(MAGIC_CRC, buf, ofset);
    /* Append the 2 Bytes CRC16 checksum value into the last two bytes in packet buffer */
    ushort_to_bytes(&buf[ofset], crc16);
    ofset += 2;
    /* ofset value is the TLV packet length  */
    return ofset;
}
int packtlv_sn(char *buf, int size, char *sn)
{
    unsigned short      crc16 = 0;
    int                 payload_len = 0;
    int                 pack_len = 0;
    int                 ofset = 0; /* index position for the buf */
    if(!buf || size<TLV_MIN_SIZE )
    {
        printf("Invalid input arguments\n");
        return 0;
    }
    /*+-------------------------+
     *|   1.fill packet Header  |
     *+-------------------------+*/
    buf[ofset] = PACK_HEADER;
    ofset += 1;
    /*+-------------------------+
     *|   2.fill packet Tag     |
     *+-------------------------+*/
    buf[ofset] = TAG_SN;
    ofset += 1;
    /*+-------------------------+
     *|   3.fill packet Length  |
     *+-------------------------+*/
    /* $sn too long maybe result buffer overflow, so we need check the buffer
     * is large enuf or not. If not enuf we will truncate $sn string
     */
    if( strlen(sn) <= size-TLV_FIXED_SIZE )
        payload_len = strlen(sn);
    else
        payload_len = size-TLV_FIXED_SIZE;
    /*  TLV packet length is SN length+5Byte () */
    pack_len = payload_len + TLV_FIXED_SIZE;
    buf[ofset] = pack_len;
    ofset += 1;
    /*+-------------------------+
     *|   4.fill packet Value   |
     *+-------------------------+*/
    memcpy(&buf[ofset], sn, payload_len);
    ofset += payload_len;
    /*+-------------------------+
     *|   5.fill packet CRC     |
     *+-------------------------+*/
    /* Calc CRC16 checksum value from Packet Head(buf[0]) ~ Value(buf[ofset]) */
    crc16 = crc_itu_t(MAGIC_CRC, buf, ofset);
    /* Append the 2 Bytes CRC16 checksum value into the last two bytes in packet buffer */
    ushort_to_bytes(&buf[ofset], crc16);
    ofset += 2;
    /* ofset value is the TLV packet length  */
    return ofset;
}
int packtlv_temp(char *buf, int size, uint16_t temp)
{
    unsigned short      crc16 = 0;
    int                 pack_len = 0;
    int                 ofset = 0; /* index position for the buf */
    if(!buf || size<TLV_FIXED_SIZE+2 )
    {
        printf("Invalid input arguments\n");
        return 0;
    }
    /*+-------------------------+
     *|   1.fill packet Header  |
     *+-------------------------+*/
    buf[ofset] = PACK_HEADER;
    ofset += 1;
    /*+-------------------------+
     *|   2.fill packet Tag     |
     *+-------------------------+*/
    buf[ofset] = TAG_TEMP;
    ofset += 1;
    /*+-------------------------+
     *|   3.fill packet Length  |
     *+-------------------------+*/
    /* termperature message get 2B payload data */
    pack_len = TLV_FIXED_SIZE + 2;
    buf[ofset] = pack_len;
    ofset += 1;
    /*+-------------------------+
     *|   4.fill packet Value   |
     *+-------------------------+*/
    /* temperature get 2 bytes, byte[0]:integer part, byte[1]:fractional part  */
    memcpy(&buf[ofset], &temp, 2);
    ofset += 2;
    /*+-------------------------+
     *|   5.fill packet CRC     |
     *+-------------------------+*/
    /* Calc CRC16 checksum value from Packet Head(buf[0]) ~ Value(buf[ofset]) */
    crc16 = crc_itu_t(MAGIC_CRC, buf, ofset);
    /* Append the 2 Bytes CRC16 checksum value into the last two bytes in packet buffer */
    ushort_to_bytes(&buf[ofset], crc16);
    ofset += 2;
    /* ofset value is the TLV packet length  */
    return ofset;
}
int packtlv_time(char *buf, int size, struct tm *tm)
{
    unsigned short      crc16 = 0;
    int                 pack_len = 0;
    int                 ofset = 0; /* index position for the buf */
    if(!buf || size<TLV_FIXED_SIZE+6 )
    {
        printf("Invalid input arguments\n");
        return 0;
    }
    /*+-------------------------+
     *|   1.fill packet Header  |
     *+-------------------------+*/
    buf[ofset] = PACK_HEADER;
    ofset += 1;
    /*+-------------------------+
     *|   2.fill packet Tag     |
     *+-------------------------+*/
    buf[ofset] = TAG_TIME;
    ofset += 1;
    /*+-------------------------+
     *|   3.fill packet Length  |
     *+-------------------------+*/
    /* date time message get 6B payload data */
    pack_len = TLV_FIXED_SIZE + 6;
    buf[ofset] = pack_len;
    ofset += 1;
    /*+-------------------------+
     *|   4.fill packet Value   |
     *+-------------------------+*/
    buf[ofset++] = tm->tm_year-100; /* tm_year is since 1900, we change it it to 2000 */
    buf[ofset++] = tm->tm_mon+1;    /* tm_mon is from 0~11  */
    buf[ofset++] = tm->tm_mday;
    buf[ofset++] = tm->tm_hour;
    buf[ofset++] = tm->tm_min;
    buf[ofset++] = tm->tm_sec;
    /*+-------------------------+
     *|   5.fill packet CRC     |
     *+-------------------------+*/
    /* Calc CRC16 checksum value from Packet Head(buf[0]) ~ Value(buf[ofset]) */
    crc16 = crc_itu_t(MAGIC_CRC, buf, ofset);
    /* Append the 2 Bytes CRC16 checksum value into the last two bytes in packet buffer */
    ushort_to_bytes(&buf[ofset], crc16);
    ofset += 2;
    /* ofset value is the TLV packet length  */
    return ofset;
}
/*+------------------------------+
 *|  dump_buf() implement code   |
 *+------------------------------+*/
#define LINELEN 81
#define CHARS_PER_LINE 16
static char *print_char =
    "                "
    "                "
    " !\"#$%&'()*+,-./"
    "0123456789:;<=>?"
    "@ABCDEFGHIJKLMNO"
    "PQRSTUVWXYZ[\\]^_"
    "`abcdefghijklmno"
    "pqrstuvwxyz{|}~ "
    "                "
    "                "
    " ???????????????"
    "????????????????"
    "????????????????"
    "????????????????"
    "????????????????"
    "????????????????";
/* print every byte in the buffer as HEX and corresponding charactor, which is not printable charactor will be instead as '?' */
void dump_buf(char *data, int len)
{
    int rc;
    int idx;
    char prn[LINELEN];
    char lit[CHARS_PER_LINE + 1];
    char hc[4];
    short line_done = 1;
    rc = len;
    idx = 0;
    lit[CHARS_PER_LINE] = '\0';
    while (rc > 0)
    {
        if (line_done)
            snprintf(prn, LINELEN, "%08X: ", idx);
        do
        {
            unsigned char c = data[idx];
            snprintf(hc, 4, "%02X ", c);
            strncat(prn, hc, 4);
            lit[idx % CHARS_PER_LINE] = print_char[c];
            ++idx;
        } while (--rc > 0 && (idx % CHARS_PER_LINE != 0));
        line_done = (idx % CHARS_PER_LINE) == 0;
        if (line_done)
            printf("%s  %s\n", prn, lit);
        else if (rc == 0)
            strncat(prn, "   ", LINELEN);
    }
    if (!line_done)
    {
        lit[(idx % CHARS_PER_LINE)] = '\0';
        while ((++idx % CHARS_PER_LINE) != 0)
            strncat(prn, "   ", LINELEN);
        printf("%s  %s\n", prn, lit);
    }
}
prj1_tlv/lylib/tlv_pack.h
New file
@@ -0,0 +1,77 @@
/********************************************************************************
 *      Copyright:  (C) 2020 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  tlv_pack.h
 *    Description:  This head file is for TLV packet
 *
 *        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秒"
 *
 ********************************************************************************/
#ifndef  _TLV_PACK_H_
#define  _TLV_PACK_H_
#include <stdint.h>
#include <time.h>
/* TLV Packet format:
 *
 *+------------+---------+------------+-----------+-----------+
 *| Header(1B) | Tag(1B) | Length(1B) | Value(1B) | CRC16(2B) |
 *+------------+---------+------------+-----------+-----------+
 */
#define PACK_HEADER        0xFD
/* TLV packet fixed segement size, 1B Head, 1B Tag, 1B length, 2B CRC16, total 5B. */
#define TLV_FIXED_SIZE     5
/* TLV packet Minimum size is fixed bytes + 1 byte data */
#define TLV_MIN_SIZE       (TLV_FIXED_SIZE+1)
/* Tag definition */
enum
{
    TAG_ACK=1,
    TAG_SN,
    TAG_TEMP,
    TAG_TIME,
};
#define TLV_BUFSIZE        256
#define TLV_FLAG_TX        1<<0 /* This TLV message need to be sent by socket    */
#define TLV_FLAG_DB        1<<1 /* This TLV message need to be saved in database */
typedef struct tlv_buf_s
{
    uint8_t                flag; /* TLV message flags */
    char                   buf[TLV_BUFSIZE];
    int                    len;  /* data length */
    int                    size; /* buffer size */
} tlv_buf_t;
/* Packet TLV message for server reply ACK message: ACK(ack=1)/NAK(ack=0) */
#define ACK         1
#define NAK         0
int packtlv_ack (char *buf, int size, int ack);
/* Packet TLV message for SN */
int packtlv_sn  (char *buf, int size, char *sn);
/* Packet TLV message for temperature */
int packtlv_temp(char *buf, int size, uint16_t temp);
/* Packet TLV message for date time */
int packtlv_time(char *buf, int size, struct tm *tm);
/* Packet 3 TLV message together: with SN, temperature, date&time */
int packtlv_msg(tlv_buf_t *tlv, char *sn, uint16_t temp, struct tm *tm);
/* print buf data in hex and string mode  */
void dump_buf(char *data, int len);
#endif   /* ----- #ifndef _TLV_PACK_H_  ----- */
prj1_tlv/tlv_client.c
@@ -19,10 +19,20 @@
#include "logger.h"
#include "proc.h"
#include "ds18b20.h"
#include "socket.h"
#include "tlv_pack.h"
#define PROG_VERSION     "1.0.0"
#define RPI_SN           "RPI00001"
#define DEF_LOG_FILE     "tlv_client.log"
#define DEF_ACK_TIMEOUT  2  /* wait for ACK timeout value */
#define DEF_RETRYTIMES   3  /* receive ACK timeout or get NAK, retry to send times */
int socket_send_tlv_pack(socket_t *sock, tlv_buf_t *tlv, int timeout, int retry_times);
int packtlv_msg(tlv_buf_t *tlv, char *sn, uint16_t temp, struct tm *tm);
static void banner(void)
{
@@ -38,6 +48,7 @@
    printf("This program used to connect to server and send RPi's temperature by TLV protocal.\n");
    printf("\nMandatory arguments to long options are mandatory for short options too:\n");
    printf(" -H[Host    ]  Specify host server address and port, foramt as \"127.0.0.1:9000\"\n");
    printf(" -d[debug   ]  Running in debug mode\n");
    printf(" -l[level   ]  Set the log level as [0..%d]\n", LOG_LEVEL_MAX-1); 
    printf(" -h[help    ]  Display this help information\n"); 
@@ -52,17 +63,27 @@
    int                   opt; 
    int                   i = 0; 
    //int                   rv = 0;
    int                   rv = 0;
    int                   debug = 0;
    char                  pid_file[64] = { 0 }; /* The file used to record the PID */
    const char           *progname=NULL;
    char                 *host = "192.168.2.110:10086";
    //char                 *host = "baidu.com:10086";
    int                   log_level = LOG_LEVEL_NRML;
    char                 *log_file = DEF_LOG_FILE;
    logger_t              logger;
    socket_t              sock;
    tlv_buf_t             tlv;
    uint16_t              temp;
    struct                tm *tm;
    time_t                cur_time, last_time = 0;
    struct option long_options[] = { 
        {"Host", required_argument, NULL, 'H'},
        {"debug", no_argument, NULL, 'd'}, 
        {"level", required_argument, NULL, 'l'}, 
        {"version", no_argument, NULL, 'v'}, 
@@ -70,15 +91,19 @@
        {NULL, 0, NULL, 0}
    };
    memset(&sock, 0, sizeof(sock));
    memset(&logger, 0, sizeof(logger));
    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, "H:dl:vh", long_options, NULL)) != -1)
    { 
        switch (opt) 
        {
            case 'H':
                host=optarg;
                break;
            case 'd': /* set debug running */
                debug = 1;
@@ -105,8 +130,18 @@
        } 
    }
#if 1
    if( !host )
    {
        printf("ERROR: No argument specify host server address and port, please refer to usage\n");
    //    return 1;
    }
#endif
    /* 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);
    snprintf(pid_file, sizeof(pid_file), "/tmp/%s.pid", progname);
    if( !debug )
    {
        if( check_daemon_running(pid_file) )
@@ -114,13 +149,17 @@
            printf("Programe already running, exit now.\n");
            return -1;
        }
        daemon(1, 1);
    }
    record_daemon_pid(pid_file);
    /* initial and open logger system */
    if( logger_init(&logger, log_file, log_level, 512)<0 || logger_open()<0 )
    {
        printf("ERROR: Initialise logger system failure\n");
        return -1;
        return 2;
    }
    /* install signal proc handler */
@@ -128,15 +167,166 @@
    log_nrml("Program start running\n");
#if 0
    if( initial_db(&sqldb, db_file) < 0)
    {
        log_err("initialise sqlite database failure\n");
        return 3;
    }
#endif
    last_time = 0;
    /* 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);
        time(&cur_time);
        if( cur_time-last_time > 3)
        {
            log_nrml("start sample temperature now.\n");
            rv = 0;
            temp = 0x1122;
            //rv = ds18b20_get_temperature(&temp);
            if( 0 == rv )
            {
                /* convert time_t to tm format  */
                tm=localtime(&cur_time);
                last_time = cur_time;
                packtlv_msg(&tlv, RPI_SN, temp, tm);
                logger_dump(LOG_LEVEL_DEBUG, tlv.buf, tlv.len);
                /* this message need to be transmit and saved in database if send failure */
                tlv.flag = TLV_FLAG_TX | TLV_FLAG_DB;
            }
            else
            {
                log_err("DS18B20 get temperature failure\n");
            }
        }
        if( SOCK_STAT_CONNECTED != sock.status )
        {
            if( socket_connect(&sock, -1, host, MODE_NONBLOCK) < 0)
            {
                log_err("connect to server [%s:%d] failure\n", sock.raddr, sock.rport);
            }
        }
        if( (tlv.flag&TLV_FLAG_TX) && SOCK_STAT_CONNECTED==sock.status )
        {
            if(0 == socket_send_tlv_pack(&sock, &tlv, DEF_ACK_TIMEOUT, DEF_RETRYTIMES) )
            {
                tlv.flag = 0;
            }
        }
#if 0
        /* need to send TLV packet in database now  */
        for(i=0; i<5; i++)
        {
            /* get a TLV record from DB and send it by socket  */
            /* rv<0: Erorr  rv=0: No record  >0: record count  */
            rv = get_db_tlv_pack(sqldb, tlv, size) ;
            if( rv <= 0)
                break;
            if( 0 == socket_send_tlv_pack() )
            {
                /* delete the record from DB */
                del_db_tlv_pack();
            }
        }
SAVE_DB:
        if( tlv_buf.flag & TLV_FLAG_DB)
        {
            record_db_tlv(sqldb, tlv_buf, tlv_len);
        }
#endif
        sleep(1);
    }
    logger_term();
    //db_term();
    return 0;
/*  Packet 3 TLV message together: with SN, temperature, date&time */
int packtlv_msg(tlv_buf_t *tlv, char *sn, uint16_t temp, struct tm *tm)
{
    int               rv;
    if( !tlv )
    {
        log_err("Invalid input arguments\n");
        return -1;
    }
    memset(tlv->buf, 0, sizeof(tlv->buf)); /* clear data in buffer */
    tlv->size = sizeof(tlv->buf); /* buffer free space size */
    tlv->len = 0; /* buffer data length */
    if( sn )
    {
        rv = packtlv_sn(&tlv->buf[tlv->len], tlv->size, sn);
        if( rv > 0 )
        {
            tlv->len += rv;
            tlv->size -= rv;
        }
    }
    if( temp )
    {
        rv = packtlv_temp(&tlv->buf[tlv->len], tlv->size, temp);
        if( rv > 0 )
        {
            tlv->len += rv;
            tlv->size -= rv;
        }
    }
    if( tm )
    {
        rv = packtlv_time(&tlv->buf[tlv->len], tlv->size, tm);
        if( rv > 0 )
        {
            tlv->len += rv;
            tlv->size -= rv;
        }
    }
    return 0;
}
int socket_send_tlv_pack(socket_t *sock, tlv_buf_t *tlv, int timeout, int retry_times)
{
    int            i;
    int            rv = 0;
    char           buf[128];
    log_info("start to send tlv packet from socket now\n");
    for(i=0; i<retry_times; i++)
    {
        if( (rv=socket_send(sock, tlv->buf, tlv->len)) < 0 )
        {
            log_err("send tlv packet failure, rv=%d\n", rv);
            return -1;
        }
        if( (rv=socket_recv(sock, buf, sizeof(buf), timeout)) < 0 )
        {
            log_err("read ACK from server failure, rv=%d\n");
            return -2;
        }
    }
    return 0;
}
prj1_tlv/tlv_client.log
New file
@@ -0,0 +1,25 @@
Initialize log "tlv_client.log" on level [N] size [512] KiB, log system version 1.0.0
 [ Date ]    [ Time ]   [ Level ]  [ File/Line ]  [ Message ]
-------------------------------------------------------------
[2020-04-28 20:52:49.352] <N> <proc.c:0059> : Install default signal handler.
[2020-04-28 20:52:49.352] <N> <tlv_client.c:0164> : Program start running
[2020-04-28 20:52:49.352] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:52:53.353] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:52:57.353] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:01.353] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:05.354] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:09.354] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:13.354] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:17.355] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:21.355] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:25.356] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:29.356] <N> <tlv_client.c:0182> : start sample temperature now.
[2020-04-28 20:53:30.815] <W> <proc.c:0038> : SIGTERM - stopping
Terminate log "tlv_client.log" on level [N] size [512] KiB, log system version 1.0.0
 [ Date ]    [ Time ]   [ Level ]  [ File/Line ]  [ Message ]
-------------------------------------------------------------