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