From 68826376ee5f47783c644c6604f4411ec747cd7e Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Fri, 14 Nov 2025 23:52:16 +0800
Subject: [PATCH] Add UDP DNS client source code

---
 project/2.socketd/socket_server.c |  351 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 351 insertions(+), 0 deletions(-)

diff --git a/project/2.socketd/socket_server.c b/project/2.socketd/socket_server.c
new file mode 100644
index 0000000..100233e
--- /dev/null
+++ b/project/2.socketd/socket_server.c
@@ -0,0 +1,351 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2020 LingYun IoT System Studio
+ *                  All rights reserved.
+ *
+ *       Filename:  socket_server.c
+ *    Description:  This is a socket server program to receive RPi's temperature
+ *
+ *        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 <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <errno.h>
+
+#include "logger.h"
+#include "proc.h"
+#include "list.h"
+#include "socket.h"
+#include "packet.h"
+
+#define PROG_VERSION               "1.0.0"
+#define DAEMON_PIDFILE             "/tmp/.sockets.pid"
+#define MAX_EVENTS                 512
+
+/* Every client need get a stand alone buffer to save TLV packet data */
+typedef struct cli_buf_s
+{
+    int                  fd;         /* client fd  */
+    char                 buf[512];   /* client receive buffer */
+    int                  bytes;      /* left bytes in buffer  */
+    struct list_head     list;       /* all client buffer saved in a list */
+} cli_buf_t;
+
+static int  parser_tlv_data(cli_buf_t *cli_buf);
+static void term_socket_client(int epollfd, int fd, struct list_head *buf_list);
+
+static void print_usage(char *progname)
+{
+    printf("Usage: %s [OPTION]...\n", progname);
+    printf(" %s is LingYun studio temperature socket server program running on RaspberryPi\n", progname);
+
+    printf("\nMandatory arguments to long options are mandatory for short options too:\n");
+    printf("-p(--port)    : sepcify server port.\n");
+    printf("-d(--debug)   : running in debug mode\n");
+    printf("-v(--version) : display the program version\n");
+    printf("-h(--help)    : display this help information\n");
+
+    printf("\n%s version %s build on %s %s\n", progname, PROG_VERSION, __DATE__, __TIME__);
+    return;
+}
+
+int main (int argc, char *argv[])
+{
+    char                 *progname=NULL;
+    int                   daemon = 1;
+    int                   opt;
+    int                   i = 0;
+    int                   rv = 0;
+
+    char                 *logfile="sock_server.log";
+    int                   loglevel=LOG_LEVEL_INFO;
+    int                   logsize=10; /* logfile size max to 10K */
+
+    socket_t              sock;
+    int                   port = 10086;
+    int                   epollfd;
+    int                   connfd;
+    int                   fd;
+    int                   nfds;
+    struct epoll_event    event_array[MAX_EVENTS];
+
+    cli_buf_t            *cli_buf;
+    cli_buf_t            *node;
+    struct list_head      buf_list; /* every client get a stand alone buffer saved in the list */
+
+    struct option long_options[] = {
+        {"port", required_argument, NULL, 'p'},
+        {"debug", no_argument, NULL, 'd'},
+        {"version", no_argument, NULL, 'v'},
+        {"help", no_argument, NULL, 'h'},
+        {NULL, 0, NULL, 0}
+    };
+
+    memset(&sock, 0, sizeof(sock));
+    INIT_LIST_HEAD(&buf_list);
+
+    progname = basename(argv[0]); /* get program name */
+
+    /* parser the command line parameters */
+    while ((opt = getopt_long(argc, argv, "p:dvh", long_options, NULL)) != -1)
+    {
+        switch (opt)
+        {
+            case 'p': /* listen port  */
+                port = atoi(optarg);
+                break;
+
+            case 'd': /* set debug running */
+                daemon = 0;
+                logfile="console";
+                loglevel=LOG_LEVEL_DEBUG;
+                break;
+
+            case 'v':  /* print software version */
+                printf("%s version %s\n", progname, PROG_VERSION);
+                return 0;
+
+            case 'h':  /* print help information */
+                print_usage(progname);
+                return 0;
+
+            default:
+                break;
+        }
+    }
+
+    /* open logger system */
+    if( log_open(logfile, loglevel, logsize, THREAD_LOCK_NONE) < 0 )
+    {
+        fprintf(stderr, "Initial log system failed\n");
+        return 1;
+    }
+
+    /* install signal proc handler */
+    install_default_signal();
+
+    /* check program already running or not, if already running then exit, or set running as daemon */
+    if( check_set_program_running(daemon, DAEMON_PIDFILE) < 0 )
+        goto cleanup;
+
+    log_info("socket server(TLV) running and listen on port[%d].\n", port);
+
+    /* initial listen socket  */
+    if( socket_listen(&sock, port) < 0 )
+    {
+        log_error("create listen socket failure\n");
+        rv = 2;
+        goto cleanup;
+    }
+
+    /* create epoll and put listen socket into it  */
+    if( (epollfd=epoll_init(MAX_EVENTS, sock.fd)) < 0 )
+    {
+        log_error("initial epoll for listen socket failure\n");
+        rv = 3;
+        goto cleanup;
+    }
+
+    /* g_signal.stop defined in proc.c, and will be set when catch stop signal */
+    while( !g_signal.stop )
+    {
+        /* epoll wailt and program will blocked here */
+        nfds = epoll_wait(epollfd, event_array, MAX_EVENTS, -1 /* never timeout */);
+        if( nfds <= 0 )
+        {
+            log_error("epoll_wait failure or timeout: %s\n", strerror(errno));
+            continue;
+        }
+
+        /* nfds>0 is the active events count */
+        for(i=0; i<nfds; i++)
+        {
+            fd = event_array[i].data.fd;
+
+            /* epoll get error  */
+            if ( (event_array[i].events&EPOLLERR) || (event_array[i].events&EPOLLHUP) )
+            {
+                log_error("epoll_wait get error on fd[%d]: %s\n", fd, strerror(errno));
+                if( fd != sock.fd )
+                    term_socket_client(epollfd, event_array[i].data.fd, &buf_list);
+
+                continue;
+            }
+
+            /* listen socket get event means new client start connect now */
+            if( fd == sock.fd )
+            {
+                /* accept new client socket  */
+                if( (connfd=accept(sock.fd, (struct sockaddr *)NULL, NULL)) < 0)
+                {
+                    log_info("accept new client failure: %s\n", strerror(errno));
+                    continue;
+                }
+
+                /* add new client socket into epoll  */
+                if( epoll_add(epollfd, connfd) < 0 )
+                {
+                    close(connfd);
+                    log_error("epoll add client socket failure, rv=%d\n", rv);
+                }
+
+                /* malloc client buffer and add it into list */
+                if( NULL != (cli_buf=(cli_buf_t *)malloc(sizeof(*cli_buf))) )
+                {
+                    memset(cli_buf, 0, sizeof(*cli_buf));
+                    cli_buf->fd = connfd;
+                    list_add_tail(&cli_buf->list, &buf_list);
+                    log_info("alloc and add socket[%d] buffer[%p] into list\n", cli_buf->fd, cli_buf);
+                }
+
+                log_info("accept and add new client socket[%d] ok.\n", connfd);
+            }
+            /* already connected client socket get data arrive  */
+            else
+            {
+                cli_buf = NULL;
+
+                /* Use list_for_each_entry to find the client buf in  buf list */
+                list_for_each_entry(node, &buf_list, list)
+                {
+                    if( node->fd == fd )
+                    {
+                        log_info("found socket[%d] buffer[%p] in list\n", fd, node);
+                        cli_buf = node;
+                    }
+                }
+
+                if( !cli_buf )
+                {
+                    log_error("can not find socket[%d] buffer and close it now\n", fd);
+                    term_socket_client(epollfd, fd, NULL);
+                }
+
+                rv=read(fd, &cli_buf->buf[cli_buf->bytes], sizeof(cli_buf->buf)-cli_buf->bytes);
+                if( rv <= 0 )
+                {
+                    log_warn("socket[%d] read failure [%s] or disconncet, terminate it now.\n",
+                            fd, strerror(errno));
+
+                    term_socket_client(epollfd, fd, &buf_list);
+                    continue;
+                }
+                else
+                {
+                    cli_buf->bytes += rv;
+                    log_debug("socket[%d] receive %d bytes data\n", fd, rv);
+                }
+
+                parser_tlv_data(cli_buf);
+            }
+        }
+
+        sleep(1);
+    }
+
+
+cleanup:
+    socket_term(&sock);
+    log_close();
+    return 0;
+}
+
+static int parser_tlv_data(cli_buf_t *cli_buf)
+{
+    int                     i, rv;
+    int                     left_bytes;
+    pack_info_t             pack_info;
+
+    if( !cli_buf )
+    {
+        log_error("Invalid input arguments\n");
+        return -1;
+    }
+
+    log_info("start to parser client buffer %d bytes data:\n", cli_buf->bytes);
+    log_dump(LOG_LEVEL_INFO, NULL, cli_buf->buf, cli_buf->bytes);
+
+    if( cli_buf->bytes < TLV_FIXSIZE )
+    {
+        log_warn("TLV packet bytes less than min. size\n");
+        return -2;
+    }
+
+    for(i=0; i<cli_buf->bytes; i++)
+    {
+        memset(&pack_info, 0, sizeof(pack_info));
+        rv = parser_tlv_pack(&pack_info, (uint8_t *)&cli_buf->buf[i], cli_buf->bytes);
+        if( rv <= 0 )
+        {
+            /* parser failed, continue to parser next byte */
+            continue;
+        }
+        else if( rv == 0)
+        {
+            log_debug("found TLV packet header on [%d]\n", i);
+
+            /* remove the parsed garbage data  */
+            left_bytes = cli_buf->bytes - i;
+            memmove(cli_buf->buf, &cli_buf->buf[i], left_bytes);
+            cli_buf->bytes = left_bytes;
+
+            log_warn("TLV packet not integrated, need receive left data");
+            break;
+        }
+
+        /* parser and get a correct TLV packet */
+
+        left_bytes = cli_buf->bytes - rv;
+        memmove(cli_buf->buf, &cli_buf->buf[i+rv], left_bytes);
+        cli_buf->bytes = left_bytes;
+
+        if( TAG_TEMPERATURE == pack_info.tag )
+        {
+            log_info("devsn: %s temperature:%.2f \n", pack_info.devid, pack_info.temper);
+        }
+    }
+
+    /* all the data is garbage */
+    if( rv < 0)
+    {
+        log_error("parser TLV data failed, remove the unused garbage data\n");
+
+        /* maybe last byte is the header's first byte */
+        cli_buf->buf[0] = cli_buf->buf[cli_buf->bytes-1];
+        cli_buf->bytes = 1;
+    }
+
+    return 0;
+}
+
+static void term_socket_client(int epollfd, int fd, struct list_head *buf_list)
+{
+    cli_buf_t          *buf, *tmp;
+
+    log_warn("start terminatl client socket[%d]\n", fd);
+
+    /* if get buf_list, then remove buf from list */
+    if( buf_list )
+    {
+        /* Use list_for_each_entry_safe to travel the socket list and destroy the buffer */
+        list_for_each_entry_safe(buf, tmp, buf_list, list)
+        {
+            if( buf->fd == fd )
+            {
+                list_del(&buf->list);
+                free(buf);
+                log_info("free socket[%d] buffer[%p]\n", fd, buf);
+                break;
+            }
+        }
+    }
+
+    epoll_del(epollfd, fd);
+    close( fd );
+}

--
Gitblit v1.9.1