APUE Learning Example Source Code
guowenxue
2020-04-30 b0053f87034ff358b7ccadc7f2d9643e9a7767e7
update tlv project for server
6 files modified
1 files added
970 ■■■■■ changed files
prj1_tlv/lylib/list.h 723 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/logger.c 2 ●●● patch | view | raw | blame | history
prj1_tlv/lylib/proc.c 2 ●●● patch | view | raw | blame | history
prj1_tlv/lylib/socket.c 92 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/socket.h 32 ●●●●● patch | view | raw | blame | history
prj1_tlv/tlv_client.c 4 ●●●● patch | view | raw | blame | history
prj1_tlv/tlv_server.c 115 ●●●●● patch | view | raw | blame | history
prj1_tlv/lylib/list.h
New file
@@ -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
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;
    }
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) 
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);
}
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_  ----- */
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;
        }
    }
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();