From b0053f87034ff358b7ccadc7f2d9643e9a7767e7 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Thu, 30 Apr 2020 16:15:09 +0800
Subject: [PATCH] update tlv project for server

---
 prj1_tlv/lylib/proc.c   |    2 
 prj1_tlv/lylib/socket.h |   32 +
 prj1_tlv/tlv_client.c   |    4 
 prj1_tlv/lylib/socket.c |   92 ++++
 prj1_tlv/lylib/list.h   |  723 ++++++++++++++++++++++++++++++++++++++++++
 prj1_tlv/lylib/logger.c |    2 
 prj1_tlv/tlv_server.c   |  115 ++++++
 7 files changed, 951 insertions(+), 19 deletions(-)

diff --git a/prj1_tlv/lylib/list.h b/prj1_tlv/lylib/list.h
new file mode 100644
index 0000000..a8c3636
--- /dev/null
+++ b/prj1_tlv/lylib/list.h
@@ -0,0 +1,723 @@
+/*********************************************************************************
+ *      Copyright:  (C) 2012 Guo Wenxue <guowenxue@gmail.com>
+ *                  All rights reserved.
+ *
+ *       Filename:  list.h
+ *    Description:  This file is copied from Linux kernel, which provide link list API.
+ *                 
+ *        Version:  1.0.0(08/09/2012~)
+ *         Author:  Guo Wenxue <guowenxue@gmail.com>
+ *      ChangeLog:  1, Release initial version on "08/09/2012 02:24:34 AM"
+ *                 
+ ********************************************************************************/
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <linux/stddef.h>
+
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:    the pointer to the member.
+ * @type:   the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#define container_of(ptr, type, member) ({          \
+    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+    (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+/*
+ * Architectures might want to move the poison pointer offset
+ * into some well-recognized area such as 0xdead000000000000,
+ * that is also not mappable by user-space exploits:
+ */
+#ifdef CONFIG_ILLEGAL_POINTER_VALUE
+# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
+#else
+# define POISON_POINTER_DELTA 0
+#endif
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)
+#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)
+
+#ifndef ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCH
+static inline void prefetch(const void *x) {;}
+#endif
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+				struct list_head *new)
+{
+	new->next = old->next;
+	new->next->prev = new;
+	new->prev = old->prev;
+	new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+					struct list_head *new)
+{
+	list_replace(old, new);
+	INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+				const struct list_head *head)
+{
+	return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+	struct list_head *next = head->next;
+	return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+	return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	struct list_head *new_first = entry->next;
+	list->next = head->next;
+	list->next->prev = list;
+	list->prev = entry;
+	entry->next = list;
+	head->next = new_first;
+	new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ *	and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ *
+ */
+static inline void list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	if (list_empty(head))
+		return;
+	if (list_is_singular(head) &&
+		(head->next != entry && head != entry))
+		return;
+	if (entry == head)
+		INIT_LIST_HEAD(list);
+	else
+		__list_cut_position(list, head, entry);
+}
+
+static inline void __list_splice(const struct list_head *list,
+				 struct list_head *prev,
+				 struct list_head *next)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+/**
+ * list_splice - join two lists, this is designed for stacks
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+				struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+				struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head, head->next);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+					 struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head->prev, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+		pos = pos->next)
+
+/**
+ * __list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+		pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+	for (pos = (head)->prev, n = pos->prev; \
+	     prefetch(pos->prev), pos != (head); \
+	     pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     prefetch(pos->member.next), &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     prefetch(pos->member.prev), &pos->member != (head);	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:	the type * to use as a start point
+ * @head:	the head of the list
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+	((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
+	     prefetch(pos->member.next), &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)		\
+	for (pos = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     prefetch(pos->member.prev), &pos->member != (head);	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member)			\
+	for (; prefetch(pos->member.next), &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member),		\
+		n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member)			\
+	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
+	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
+		n = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+	h->next = NULL;
+	h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+	return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+	return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+	struct hlist_node *next = n->next;
+	struct hlist_node **pprev = n->pprev;
+	*pprev = next;
+	if (next)
+		next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+	__hlist_del(n);
+	n->next = LIST_POISON1;
+	n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+	if (!hlist_unhashed(n)) {
+		__hlist_del(n);
+		INIT_HLIST_NODE(n);
+	}
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *first = h->first;
+	n->next = first;
+	if (first)
+		first->pprev = &n->next;
+	h->first = n;
+	n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+					struct hlist_node *next)
+{
+	n->pprev = next->pprev;
+	n->next = next;
+	next->pprev = &n->next;
+	*(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+					struct hlist_node *next)
+{
+	next->next = n->next;
+	n->next = next;
+	next->pprev = &n->next;
+
+	if(next->next)
+		next->next->pprev  = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+	for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+	     pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+	     pos = n)
+
+/**
+ * hlist_for_each_entry	- iterate over list of given type
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member)			 \
+	for (pos = (head)->first;					 \
+	     pos && ({ prefetch(pos->next); 1;}) &&			 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member)		 \
+	for (pos = (pos)->next;						 \
+	     pos && ({ prefetch(pos->next); 1;}) &&			 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member)			 \
+	for (; pos && ({ prefetch(pos->next); 1;}) &&			 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @n:		another &struct hlist_node to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member)		 \
+	for (pos = (head)->first;					 \
+	     pos && ({ n = pos->next; 1; }) &&				 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = n)
+
+
+#endif
+
+
diff --git a/prj1_tlv/lylib/logger.c b/prj1_tlv/lylib/logger.c
index 9763d7b..a28c2aa 100644
--- a/prj1_tlv/lylib/logger.c
+++ b/prj1_tlv/lylib/logger.c
@@ -137,7 +137,7 @@
     logger->fp = fopen(logger->file, filemode);
     if (NULL == logger->fp)
     {
-        fprintf(stderr, "Open log file \"%s\" in %s failure\n", logger->file, filemode);
+        fprintf(stderr, "Open log file \"%s\" in %s failure: %s\n", logger->file, filemode, strerror(errno));
         return -2;
     }
 
diff --git a/prj1_tlv/lylib/proc.c b/prj1_tlv/lylib/proc.c
index 015609f..154864c 100644
--- a/prj1_tlv/lylib/proc.c
+++ b/prj1_tlv/lylib/proc.c
@@ -304,7 +304,7 @@
  * *****************************************************************************/
 int set_daemon_running(const char *pid_file)
 { 
-    daemonize(0, 1); 
+    daemonize(1, 1); 
     log_nrml("Program running as daemon [PID:%d].\n", getpid()); 
     
     if (record_daemon_pid(pid_file) < 0) 
diff --git a/prj1_tlv/lylib/socket.c b/prj1_tlv/lylib/socket.c
index 1d7b0be..1a0053e 100644
--- a/prj1_tlv/lylib/socket.c
+++ b/prj1_tlv/lylib/socket.c
@@ -22,7 +22,7 @@
  *               $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 socket_init(socket_t *sock, uint8_t type, int create)
 {
     int        fd = -1;
 
@@ -116,7 +116,6 @@
 int socket_listen(socket_t *sock, char *ipaddr, int port)
 {
     int                 rv = 0; 
-    int                 fd = -1; 
     struct sockaddr_in  addr;
     int                 backlog = 13;
 
@@ -126,7 +125,7 @@
         return -1;
     }
 
-    if( sock->status != SOCK_STAT_INIT )
+    if( sock->status != SOCK_STAT_UNINIT )
     {
         socket_close(sock);
     }
@@ -149,7 +148,7 @@
     }
 
     /* initial socket context and create socket fd  */
-    if( socket_ctx_init(sock, SOCK_TYPE_LISTEN, SOCK_CREATE) < 0)
+    if( socket_init(sock, SOCK_TYPE_LISTEN, SOCK_CREATE) < 0)
     {
         log_err("socket context initial failure\n");
         return -2;
@@ -179,8 +178,6 @@
         goto cleanup;
     }
 
-    log_nrml("create socket and listen on [%s:%d] already\n", sock->laddr, sock->lport);
-
 cleanup: 
     if( rv ) 
     { 
@@ -190,7 +187,7 @@
     else 
     { 
         sock->status = SOCK_STAT_LISTENED; 
-        log_nrml("Create socket[%p:%d] listen [%s:%d] ok\n", sock, sock->fd, sock->laddr, sock->lport); 
+        log_nrml("Create socket[%d] listen [%s:%d] ok\n", sock->fd, sock->laddr, sock->lport); 
     }
 
     return rv; 
@@ -236,7 +233,7 @@
     /* socket not initial before */
     if( SOCK_STAT_UNINIT== sock->status ) 
     {
-        if( socket_ctx_init(sock, SOCK_TYPE_LISTEN, SOCK_NOT_CREATE) < 0)
+        if( socket_init(sock, SOCK_TYPE_LISTEN, SOCK_NOT_CREATE) < 0)
         {
             log_err("ERROR: initial socket context failure\n");
             return -2;
@@ -559,6 +556,72 @@
 }
 
 
+/*  description: create epoll for socket server and add listenfd into it
+ *   input args: $max_evts:  max events for epoll_create()
+ *               $listenfd:  listen socket fd
+ * return value: <0: failure  >=0: epollfd
+ */ 
+int epoll_init(int max_evts, int listenfd)
+{
+    int                       epollfd;
+    struct epoll_event        event;
+
+    if( max_evts<=0 || listenfd<0 )
+    {
+        log_err("Invalid input arguments\n");
+        return -1;  
+    }
+
+    if( (epollfd=epoll_create(max_evts)) < 0 )
+    {
+        log_err("epoll_create() failure: %s\n", strerror(errno));
+        return -2;
+    }
+
+    if( epoll_add(epollfd, listenfd) < 0 )
+    {
+        log_err("epoll add listen socket[%d] failure: %s\n", listenfd, strerror(errno));
+        close(epollfd);
+        return -2;
+    }
+
+    log_nrml("epoll add listen socket[%d] ok\n", listenfd);
+    return epollfd;
+}
+
+/*  description: add new fd into epoll to monitor
+ *   input args: $epollfd:  epoll fd
+ *               $fd:       socket fd need added into epoll
+ * return value: <0: failure  0: successfully
+ */ 
+inline int epoll_add(int epollfd, int fd)
+{
+    struct epoll_event        event;
+
+    if( epollfd<0 || fd<0 )
+    {
+        log_err("Invalid input arguments\n");
+        return -1;  
+    }
+
+    //event.events = EPOLLIN | EPOLLET;  /* Edge Triggered  */
+    event.events = EPOLLIN; /* default Level Triggered */
+    event.data.fd = fd;
+
+    if( epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) < 0)
+    {
+        log_err("epoll add fd[%d] failure: %s\n", fd, strerror(errno));
+        return -2;
+    }
+
+    return 0;
+}
+
+
+
+/*+-------------------------------------------------------------------+
+ *|                socket utils function                              |
+ *+-------------------------------------------------------------------+*/
 
 /*  description: parser hostname and port from $host and set it into $sock 
  *   input args: $sock: socket context
@@ -787,3 +850,16 @@
 }
 
 
+/*  Set open file description count to max */
+void set_socket_rlimit(void)
+{
+    struct rlimit limit = {0};
+
+    getrlimit(RLIMIT_NOFILE, &limit );
+    limit.rlim_cur  = limit.rlim_max;
+    setrlimit(RLIMIT_NOFILE, &limit );
+
+    log_nrml("set socket open fd max count to %d\n", limit.rlim_max);
+}
+
+
diff --git a/prj1_tlv/lylib/socket.h b/prj1_tlv/lylib/socket.h
index 1b5a043..b472ae6 100644
--- a/prj1_tlv/lylib/socket.h
+++ b/prj1_tlv/lylib/socket.h
@@ -32,6 +32,11 @@
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
 
+#include <sys/epoll.h>
+#include <sys/resource.h>
+
+#include "list.h"
+
 #define HOSTNAME_LEN         128
 
 enum
@@ -69,7 +74,9 @@
     int            keepintvl;   /* keepalive detect interval */ 
     int            keepcnt;     /* keepalive count */ 
 
-    struct sockaddr  saddr;              /*  sockaddr for connect */ 
+    struct sockaddr  saddr;     /* sockaddr for connect */ 
+
+    struct list_head list;      /* socket server manage client link list */
 } socket_t;
 
 
@@ -88,7 +95,7 @@
     SOCK_NOT_CREATE,
     SOCK_CREATE,
 };
-int socket_ctx_init(socket_t *sock, uint8_t type, int create);
+int socket_init(socket_t *sock, uint8_t type, int create);
 
 
 /*  description: close socket and set socket status as SOCK_STAT_INIT 
@@ -148,6 +155,25 @@
 int socket_recv(socket_t *sock, char *buf, int size, int timeout);
 
 
+/*  description: create epoll for socket server and add listenfd into it
+ *   input args: $max_evts:  max events for epoll_create()
+ *               $listenfd:  listen socket fd
+ * return value: <0: failure  >=0: epollfd
+ */ 
+int epoll_init(int max_evts, int listenfd);
+
+/*  description: add new fd into epoll to monitor
+ *   input args: $epollfd:  epoll fd
+ *               $fd:       socket fd need added into epoll
+ * return value: <0: failure  0: successfully
+ */ 
+inline int epoll_add(int epollfd, int fd);
+
+static inline int epoll_del(int epollfd, int fd)
+{
+    return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
+}
+
 /*+-------------------------------------------------------------------+
  *|                socket utils function                              |
  *+-------------------------------------------------------------------+*/
@@ -171,6 +197,8 @@
 /* set heartbeat keepalive  */
 int socket_set_keepalive(int sockfd, int keepintvl, int keepcnt);
 
+/*  Set open file description count to max */
+void set_socket_rlimit(void);
 
 #endif   /* ----- #ifndef _SOCKET_H_  ----- */
 
diff --git a/prj1_tlv/tlv_client.c b/prj1_tlv/tlv_client.c
index 98c392d..03305be 100644
--- a/prj1_tlv/tlv_client.c
+++ b/prj1_tlv/tlv_client.c
@@ -69,7 +69,7 @@
     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 = "127.0.0.1:10086";
     //char                 *host = "baidu.com:10086";
     int                   log_level = LOG_LEVEL_NRML;
     char                 *log_file = DEF_LOG_FILE;
@@ -321,7 +321,7 @@
 
         if( (rv=socket_recv(sock, buf, sizeof(buf), timeout)) < 0 )
         {
-            log_err("read ACK from server failure, rv=%d\n");
+            log_err("read ACK from server failure, rv=%d\n", rv);
             return -2;
         }
     }
diff --git a/prj1_tlv/tlv_server.c b/prj1_tlv/tlv_server.c
index f0e2d56..64782a4 100644
--- a/prj1_tlv/tlv_server.c
+++ b/prj1_tlv/tlv_server.c
@@ -19,10 +19,15 @@
 
 #include "logger.h"
 #include "proc.h"
+#include "socket.h"
 
 #define PROG_VERSION     "1.0.0"
 
 #define DEF_LOG_FILE     "tlv_server.log"
+#define DEF_LISTEN_IP    "0.0.0.0"
+#define DEF_LISTEN_PORT  10086
+
+#define MAX_EVENTS       512
 
 static void banner(void)
 {
@@ -52,8 +57,9 @@
 { 
     int                   opt; 
     int                   i = 0; 
-    //int                   rv = 0; 
+    int                   rv = 0; 
     int                   debug = 0;
+    int                   port = DEF_LISTEN_PORT;
 
     char                  pid_file[64] = { 0 }; /* The file used to record the PID */
     const char           *progname=NULL;
@@ -62,7 +68,15 @@
     char                 *log_file = DEF_LOG_FILE;
     logger_t              logger;
 
+    socket_t              sock;
+    int                   epollfd;
+    int                   connfd;
+    struct epoll_event    event_array[MAX_EVENTS];
+
+    char                  buf[1024];
+
     struct option long_options[] = { 
+        {"port", required_argument, NULL, 'p'}, 
         {"debug", no_argument, NULL, 'd'}, 
         {"level", required_argument, NULL, 'l'}, 
         {"version", no_argument, NULL, 'v'}, 
@@ -71,14 +85,18 @@
     };
 
     memset(&logger, 0, sizeof(logger));
+    memset(&sock, 0, sizeof(sock));
 
     progname = basename(argv[0]); /* get program name */
 
     /* parser the command line parameters */ 
-    while ((opt = getopt_long(argc, argv, "c:dl:vh", long_options, NULL)) != -1) 
+    while ((opt = getopt_long(argc, argv, "p:dl:vh", long_options, NULL)) != -1) 
     { 
         switch (opt) 
         {
+            case 'p': /* listen port  */
+                port = atoi(optarg); 
+                break;
 
             case 'd': /* set debug running */
                 debug = 1;
@@ -105,6 +123,12 @@
         } 
     }
 
+    if( port <= 0 )
+    {
+        printf("ERROR: no listen port specified, refer to program usage\n\n");
+        program_usage(progname);
+    }
+
     /* check program already running or not, if already running then exit, or set running as daemon */
     snprintf(pid_file, sizeof(pid_file), "/var/run/%s.pid", progname);
     if( !debug )
@@ -114,6 +138,8 @@
             printf("Programe already running, exit now.\n");
             return -1;
         }
+
+        set_daemon_running(pid_file);
     }
 
     /* initial and open logger system */
@@ -126,13 +152,92 @@
     /* install signal proc handler */
     install_proc_signal();
 
-    log_nrml("Program start running\n");
+    log_nrml("TLV server program start running\n");
+
+    set_socket_rlimit();
+
+    if( socket_listen(&sock, DEF_LISTEN_IP, port) < 0 )
+    {
+        log_err("create listen socket failure\n");
+        return -2;
+    }
+
+    if( (epollfd=epoll_init(MAX_EVENTS, sock.fd)) < 0 )
+    {
+        log_err("initial epoll for listen socket failure\n");
+        return -2;
+    }
 
     /* g_signal.stop defined in proc.c, and will be set when catch stop signal */
     while( !g_signal.stop )
     {
-        log_dbg("Program still running\n");
-        sleep(3);
+        /* program will blocked here */ 
+        rv = epoll_wait(epollfd, event_array, MAX_EVENTS, -1/* never timeout */);
+        if( rv < 0 )
+        {
+            log_err("epoll failure: %s\n", strerror(errno));
+            continue;
+        }
+        else if( rv == 0)
+        {
+            log_err("epoll get timeout\n");
+            continue;
+        }
+
+        /* rv>0 is the active events count */ 
+        for(i=0; i<rv; i++)
+        {
+            if ( (event_array[i].events&EPOLLERR) || (event_array[i].events&EPOLLHUP) )
+            {
+                log_err("epoll_wait get error on fd[%d]: %s\n", event_array[i].data.fd, strerror(errno));
+                epoll_del(epollfd, event_array[i].data.fd);
+                close(event_array[i].data.fd);
+            }
+
+            /* listen socket get event means new client start connect now */ 
+            if( event_array[i].data.fd == sock.fd )
+            {
+                struct epoll_event       event;
+                if( (connfd=accept(sock.fd, (struct sockaddr *)NULL, NULL)) < 0)
+                {
+                    log_nrml("accept new client failure: %s\n", strerror(errno));
+                    continue;
+                }
+                log_info("accept new client socket[%d]\n", connfd);
+
+                event.data.fd = connfd;
+                event.events =  EPOLLIN;
+                epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &event);
+
+#if 0
+                if( epoll_add(epollfd, connfd) < 0 )
+                {
+                    close(connfd);
+                    log_err("epoll add client socket failure, rv=%d\n", rv);
+                }
+                log_dbg("epoll add new client socket[%d] ok.\n", connfd);
+#endif
+            }
+            else 
+            {
+                rv=read(event_array[i].data.fd, buf, sizeof(buf));
+                if( rv <= 0 )
+                {
+                    printf("socket[%d] read failure [%s] or disconncet, close and remove now.\n", 
+                            event_array[i].data.fd, strerror(errno));
+
+                    epoll_del(epollfd, event_array[i].data.fd);
+                    close( event_array[i].data.fd );
+                    continue;
+                }
+                else
+                {
+                    log_dbg("socket[%d] receive %d bytes data\n", event_array[i].data.fd, rv);
+                    logger_dump(LOG_LEVEL_INFO, buf, rv);
+                }
+
+            }
+        }
     }
 
     logger_term();

--
Gitblit v1.9.1