update source code from FastDFS V5.02
commit
0dd3d17c92
|
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
Version 1.06 2014-05-28
|
||||||
|
* update source code from FastDFS V5.02
|
||||||
|
|
||||||
|
Version 1.05 2012-07-08
|
||||||
|
* update source code from FastDFS V3.09
|
||||||
|
|
||||||
|
Version 1.04 2011-01-31
|
||||||
|
* update source code from FastDFS V2.08
|
||||||
|
|
||||||
|
Version 1.03 2010-11-16
|
||||||
|
* add local ip functions local_ip_func.c
|
||||||
|
|
||||||
|
Version 1.02 2010-07-02
|
||||||
|
* sockopt.c: tcprecvfile and tcpdiscard add parameter total_recv_bytes
|
||||||
|
* sockopt.h add non-block connect function connectserverbyip_nb
|
||||||
|
* log_init set log to cache to false (no cache)
|
||||||
|
|
||||||
|
Version 1.01 2010-05-15
|
||||||
|
* source file move to directory src
|
||||||
|
* header files add comments
|
||||||
|
* logger.h: correct function name from log_destory_ex to log_destroy_ex
|
||||||
|
* shared_func.h: getExeAbsolutePath change to getAbsolutePath
|
||||||
|
|
||||||
|
Version 1.00 2010-05-08
|
||||||
|
* first version
|
||||||
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
Copy right 2010 Happy Fish / YuQing
|
||||||
|
|
||||||
|
libfastcommon may be copied only under the terms of the Less GNU General
|
||||||
|
Public License(LGPL).
|
||||||
|
Please visit the libfastcommon Home Page for more detail.
|
||||||
|
English language: http://code.google.com/p/libfastcommon/
|
||||||
|
Chinese language: http://linux.chinaunix.net/bbs/forum-75-1.html
|
||||||
|
|
||||||
|
|
||||||
|
#step 1. download libfastcommon source package and unpack it,
|
||||||
|
tar xzf libfastcommon_v1.x.tar.gz
|
||||||
|
#for example:
|
||||||
|
tar xzf libfastcommon_v1.3.tar.gz
|
||||||
|
|
||||||
|
#step 2. enter the libfastcommon dir
|
||||||
|
cd libfastcommon
|
||||||
|
|
||||||
|
#step 3. make
|
||||||
|
./make.sh
|
||||||
|
|
||||||
|
#step 4. make install
|
||||||
|
./make.sh install
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
Copyright (C) 2010 Happy Fish / YuQing
|
||||||
|
|
||||||
|
libfastcommon may be copied only under the terms of the Less GNU General
|
||||||
|
Public License(LGPL).
|
||||||
|
Please visit the libfastcommon Home Page for more detail.
|
||||||
|
English language: http://code.google.com/p/libfastcommon/
|
||||||
|
Chinese language: http://linux.chinaunix.net/bbs/forum-75-1.html
|
||||||
|
|
||||||
|
|
||||||
|
c common functions library extracted from my open source projects FastDFS and
|
||||||
|
FastDHT. this library is very simple and stable.
|
||||||
|
|
||||||
|
functions including: string, logger, chain, hash, socket, ini file reader,
|
||||||
|
base64 encode / decode, url encode / decode etc.
|
||||||
|
|
||||||
|
detail info please see the c header files.
|
||||||
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
tmp_src_filename=fast_check_bits.c
|
||||||
|
cat <<EOF > $tmp_src_filename
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
printf("%d\n", sizeof(long));
|
||||||
|
printf("%d\n", sizeof(off_t));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
gcc -D_FILE_OFFSET_BITS=64 -o a.out $tmp_src_filename
|
||||||
|
output=`./a.out`
|
||||||
|
|
||||||
|
if [ -f /bin/expr ]; then
|
||||||
|
EXPR=/bin/expr
|
||||||
|
else
|
||||||
|
EXPR=/usr/bin/expr
|
||||||
|
fi
|
||||||
|
|
||||||
|
count=0
|
||||||
|
int_bytes=4
|
||||||
|
off_bytes=8
|
||||||
|
for col in $output; do
|
||||||
|
if [ $count -eq 0 ]; then
|
||||||
|
int_bytes=$col
|
||||||
|
else
|
||||||
|
off_bytes=$col
|
||||||
|
fi
|
||||||
|
|
||||||
|
count=`$EXPR $count + 1`
|
||||||
|
done
|
||||||
|
|
||||||
|
/bin/rm -f a.out $tmp_src_filename
|
||||||
|
if [ "$int_bytes" -eq 8 ]; then
|
||||||
|
OS_BITS=64
|
||||||
|
else
|
||||||
|
OS_BITS=32
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$off_bytes" -eq 8 ]; then
|
||||||
|
OFF_BITS=64
|
||||||
|
else
|
||||||
|
OFF_BITS=32
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOF > src/_os_bits.h
|
||||||
|
#ifndef _OS_BITS_H
|
||||||
|
#define _OS_BITS_H
|
||||||
|
|
||||||
|
#define OS_BITS $OS_BITS
|
||||||
|
#define OFF_BITS $OFF_BITS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
EOF
|
||||||
|
|
||||||
|
DEBUG_FLAG=1
|
||||||
|
|
||||||
|
CFLAGS='-Wall -D_FILE_OFFSET_BITS=64'
|
||||||
|
if [ "$DEBUG_FLAG" = "1" ]; then
|
||||||
|
CFLAGS="$CFLAGS -g -DDEBUG_FLAG"
|
||||||
|
else
|
||||||
|
CFLAGS="$CFLAGS -O3"
|
||||||
|
fi
|
||||||
|
|
||||||
|
LIBS=''
|
||||||
|
uname=`uname`
|
||||||
|
if [ "$uname" = "Linux" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DOS_LINUX -DIOEVENT_USE_EPOLL"
|
||||||
|
elif [ "$uname" = "FreeBSD" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DOS_FREEBSD -DIOEVENT_USE_KQUEUE"
|
||||||
|
elif [ "$uname" = "SunOS" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DOS_SUNOS -D_THREAD_SAFE -DIOEVENT_USE_PORT"
|
||||||
|
LIBS="$LIBS -lsocket -lnsl -lresolv"
|
||||||
|
export CC=gcc
|
||||||
|
elif [ "$uname" = "AIX" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DOS_AIX -D_THREAD_SAFE"
|
||||||
|
export CC=gcc
|
||||||
|
elif [ "$uname" = "HP-UX" ]; then
|
||||||
|
CFLAGS="$CFLAGS -DOS_HPUX"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f /usr/lib/libpthread.so ] || [ -f /usr/local/lib/libpthread.so ] || [ -f /usr/lib64/libpthread.so ] || [ -f /usr/lib/libpthread.a ] || [ -f /usr/local/lib/libpthread.a ] || [ -f /usr/lib64/libpthread.a ]; then
|
||||||
|
LIBS="$LIBS -lpthread"
|
||||||
|
else
|
||||||
|
line=`nm -D /usr/lib/libc_r.so | grep pthread_create | grep -w T`
|
||||||
|
if [ -n "$line" ]; then
|
||||||
|
LIBS="$LIBS -lc_r"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd src
|
||||||
|
cp Makefile.in Makefile
|
||||||
|
perl -pi -e "s#\\\$\(CFLAGS\)#$CFLAGS#g" Makefile
|
||||||
|
perl -pi -e "s#\\\$\(LIBS\)#$LIBS#g" Makefile
|
||||||
|
make $1 $2
|
||||||
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
.SUFFIXES: .c .o .lo
|
||||||
|
|
||||||
|
COMPILE = $(CC) $(CFLAGS)
|
||||||
|
INC_PATH =
|
||||||
|
LIB_PATH = -L/usr/local/lib $(LIBS)
|
||||||
|
|
||||||
|
FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
|
||||||
|
logger.lo sockopt.lo base64.lo sched_thread.lo \
|
||||||
|
http_func.lo md5.lo pthread_func.lo local_ip_func.lo \
|
||||||
|
avl_tree.lo ioevent.lo ioevent_loop.lo fast_task_queue.lo \
|
||||||
|
fast_timer.lo process_ctrl.lo
|
||||||
|
|
||||||
|
HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
|
||||||
|
shared_func.h pthread_func.h ini_file_reader.h _os_bits.h \
|
||||||
|
sockopt.h sched_thread.h http_func.h md5.h local_ip_func.h \
|
||||||
|
avl_tree.h ioevent.h ioevent_loop.h fast_task_queue.h \
|
||||||
|
fast_timer.h process_ctrl.h
|
||||||
|
|
||||||
|
ALL_OBJS = $(STATIC_OBJS) $(FAST_SHARED_OBJS)
|
||||||
|
|
||||||
|
ALL_PRGS =
|
||||||
|
ALL_LIBS = libfastcommon.so.1
|
||||||
|
|
||||||
|
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
||||||
|
libfastcommon.so.1:
|
||||||
|
$(COMPILE) -o $@ $< -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
|
||||||
|
.o:
|
||||||
|
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
|
||||||
|
.c:
|
||||||
|
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
|
||||||
|
.c.o:
|
||||||
|
$(COMPILE) -c -o $@ $< $(INC_PATH)
|
||||||
|
.c.lo:
|
||||||
|
$(COMPILE) -c -fPIC -o $@ $< $(INC_PATH)
|
||||||
|
install:
|
||||||
|
cp -f $(ALL_LIBS) /usr/local/lib/
|
||||||
|
mkdir -p /usr/local/include/fastcommon
|
||||||
|
cp -f $(HEADER_FILES) /usr/local/include/fastcommon
|
||||||
|
ln -fs /usr/local/lib/libfastcommon.so.1 /usr/local/lib/libfastcommon.so
|
||||||
|
sh ./fast_link_library.sh
|
||||||
|
clean:
|
||||||
|
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef _OS_BITS_H
|
||||||
|
#define _OS_BITS_H
|
||||||
|
|
||||||
|
#define OS_BITS 64
|
||||||
|
#define OFF_BITS 64
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,789 @@
|
||||||
|
#include "avl_tree.h"
|
||||||
|
|
||||||
|
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
|
||||||
|
CompareFunc compare_func)
|
||||||
|
{
|
||||||
|
tree->root = NULL;
|
||||||
|
tree->free_data_func = free_data_func;
|
||||||
|
tree->compare_func = compare_func;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avl_tree_destroy_loop(FreeDataFunc free_data_func, \
|
||||||
|
AVLTreeNode *pCurrentNode)
|
||||||
|
{
|
||||||
|
if (pCurrentNode->left != NULL)
|
||||||
|
{
|
||||||
|
avl_tree_destroy_loop(free_data_func, pCurrentNode->left);
|
||||||
|
}
|
||||||
|
if (pCurrentNode->right != NULL)
|
||||||
|
{
|
||||||
|
avl_tree_destroy_loop(free_data_func, pCurrentNode->right);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (free_data_func != NULL)
|
||||||
|
{
|
||||||
|
free_data_func(pCurrentNode->data);
|
||||||
|
}
|
||||||
|
free(pCurrentNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_tree_destroy(AVLTreeInfo *tree)
|
||||||
|
{
|
||||||
|
if (tree == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree->root != NULL)
|
||||||
|
{
|
||||||
|
avl_tree_destroy_loop(tree->free_data_func, tree->root);
|
||||||
|
tree->root = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AVLTreeNode *createTreeNode(AVLTreeNode *pParentNode, void *target_data)
|
||||||
|
{
|
||||||
|
AVLTreeNode *pNewNode;
|
||||||
|
pNewNode = (AVLTreeNode *)malloc(sizeof(AVLTreeNode));
|
||||||
|
if (pNewNode == NULL)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail!\n", __LINE__, \
|
||||||
|
(int)sizeof(AVLTreeNode));
|
||||||
|
*/
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNewNode->left = pNewNode->right = NULL;
|
||||||
|
pNewNode->data = target_data;
|
||||||
|
pNewNode->balance = 0;
|
||||||
|
|
||||||
|
return pNewNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avlRotateLeft(AVLTreeNode *pRotateNode, AVLTreeNode **ppRaiseNode)
|
||||||
|
{
|
||||||
|
*ppRaiseNode = pRotateNode->right;
|
||||||
|
pRotateNode->right = (*ppRaiseNode)->left;
|
||||||
|
(*ppRaiseNode)->left = pRotateNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avlRotateRight(AVLTreeNode *pRotateNode, AVLTreeNode **ppRaiseNode)
|
||||||
|
{
|
||||||
|
*ppRaiseNode = pRotateNode->left;
|
||||||
|
pRotateNode->left = (*ppRaiseNode)->right;
|
||||||
|
(*ppRaiseNode)->right = pRotateNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avlLeftBalanceWhenInsert(AVLTreeNode **pTreeNode, int *taller)
|
||||||
|
{
|
||||||
|
AVLTreeNode *leftsub;
|
||||||
|
AVLTreeNode *rightsub;
|
||||||
|
|
||||||
|
leftsub = (*pTreeNode)->left;
|
||||||
|
switch (leftsub->balance)
|
||||||
|
{
|
||||||
|
case -1 :
|
||||||
|
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||||
|
avlRotateRight (*pTreeNode, pTreeNode);
|
||||||
|
*taller = 0;
|
||||||
|
break;
|
||||||
|
case 0 :
|
||||||
|
break;
|
||||||
|
case 1 :
|
||||||
|
rightsub = leftsub->right;
|
||||||
|
switch ( rightsub->balance )
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
(*pTreeNode)->balance = 1;
|
||||||
|
leftsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case 0 :
|
||||||
|
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case 1 :
|
||||||
|
(*pTreeNode)->balance = 0;
|
||||||
|
leftsub->balance = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rightsub->balance = 0;
|
||||||
|
avlRotateLeft( leftsub, &((*pTreeNode)->left));
|
||||||
|
avlRotateRight(*pTreeNode, pTreeNode);
|
||||||
|
*taller = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avlRightBalanceWhenInsert(AVLTreeNode **pTreeNode, int *taller)
|
||||||
|
{
|
||||||
|
AVLTreeNode *rightsub;
|
||||||
|
AVLTreeNode *leftsub;
|
||||||
|
|
||||||
|
rightsub = (*pTreeNode)->right;
|
||||||
|
switch (rightsub->balance)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||||
|
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||||
|
*taller = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
leftsub = rightsub->left;
|
||||||
|
switch (leftsub->balance)
|
||||||
|
{
|
||||||
|
case 1 :
|
||||||
|
(*pTreeNode)->balance = -1;
|
||||||
|
rightsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case 0 :
|
||||||
|
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case -1 :
|
||||||
|
(*pTreeNode)->balance = 0;
|
||||||
|
rightsub->balance = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftsub->balance = 0;
|
||||||
|
avlRotateRight(rightsub, &((*pTreeNode)->right));
|
||||||
|
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||||
|
*taller = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avl_tree_insert_loop(CompareFunc compare_func, AVLTreeNode **pCurrentNode, \
|
||||||
|
void *target_data, int *taller)
|
||||||
|
{
|
||||||
|
int nCompRes;
|
||||||
|
int success;
|
||||||
|
|
||||||
|
if (*pCurrentNode == NULL)
|
||||||
|
{
|
||||||
|
*pCurrentNode = createTreeNode(*pCurrentNode, target_data);
|
||||||
|
if (*pCurrentNode != NULL)
|
||||||
|
{
|
||||||
|
*taller = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nCompRes = compare_func((*pCurrentNode)->data, target_data);
|
||||||
|
if (nCompRes > 0)
|
||||||
|
{
|
||||||
|
success = avl_tree_insert_loop(compare_func, \
|
||||||
|
&((*pCurrentNode)->left), target_data, taller);
|
||||||
|
if (*taller != 0)
|
||||||
|
{
|
||||||
|
switch ((*pCurrentNode)->balance)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
avlLeftBalanceWhenInsert(pCurrentNode, taller);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
(*pCurrentNode)->balance = -1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
(*pCurrentNode)->balance = 0;
|
||||||
|
*taller = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (nCompRes < 0)
|
||||||
|
{
|
||||||
|
success = avl_tree_insert_loop(compare_func, \
|
||||||
|
&((*pCurrentNode)->right), target_data, taller);
|
||||||
|
if (*taller != 0)
|
||||||
|
{
|
||||||
|
switch ((*pCurrentNode)->balance)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
(*pCurrentNode)->balance = 0;
|
||||||
|
*taller = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
(*pCurrentNode)->balance = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
avlRightBalanceWhenInsert(pCurrentNode, taller);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avl_tree_insert(AVLTreeInfo *tree, void *data)
|
||||||
|
{
|
||||||
|
int taller;
|
||||||
|
|
||||||
|
taller = 0;
|
||||||
|
return avl_tree_insert_loop(tree->compare_func, &(tree->root), \
|
||||||
|
data, &taller);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avl_tree_replace_loop(CompareFunc compare_func, \
|
||||||
|
FreeDataFunc free_data_func, AVLTreeNode **pCurrentNode, \
|
||||||
|
void *target_data, int *taller)
|
||||||
|
{
|
||||||
|
int nCompRes;
|
||||||
|
int success;
|
||||||
|
|
||||||
|
if (*pCurrentNode == NULL )
|
||||||
|
{
|
||||||
|
*pCurrentNode = createTreeNode(*pCurrentNode, target_data);
|
||||||
|
if (*pCurrentNode != NULL)
|
||||||
|
{
|
||||||
|
*taller = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nCompRes = compare_func((*pCurrentNode)->data, target_data);
|
||||||
|
if (nCompRes > 0)
|
||||||
|
{
|
||||||
|
success = avl_tree_replace_loop(compare_func, free_data_func,
|
||||||
|
&((*pCurrentNode)->left), target_data, taller);
|
||||||
|
if (*taller != 0)
|
||||||
|
{
|
||||||
|
switch ((*pCurrentNode)->balance)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
avlLeftBalanceWhenInsert(pCurrentNode, taller);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
(*pCurrentNode)->balance = -1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
(*pCurrentNode)->balance = 0;
|
||||||
|
*taller = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (nCompRes < 0)
|
||||||
|
{
|
||||||
|
success = avl_tree_replace_loop(compare_func, free_data_func,
|
||||||
|
&((*pCurrentNode)->right), target_data, taller);
|
||||||
|
if (*taller != 0)
|
||||||
|
{
|
||||||
|
switch ((*pCurrentNode)->balance)
|
||||||
|
{
|
||||||
|
case -1 :
|
||||||
|
(*pCurrentNode)->balance = 0;
|
||||||
|
*taller = 0;
|
||||||
|
break;
|
||||||
|
case 0 :
|
||||||
|
(*pCurrentNode)->balance = 1;
|
||||||
|
break;
|
||||||
|
case 1 :
|
||||||
|
avlRightBalanceWhenInsert(pCurrentNode, taller);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (free_data_func != NULL)
|
||||||
|
{
|
||||||
|
free_data_func((*pCurrentNode)->data);
|
||||||
|
}
|
||||||
|
(*pCurrentNode)->data = target_data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avl_tree_replace(AVLTreeInfo *tree, void *data)
|
||||||
|
{
|
||||||
|
int taller;
|
||||||
|
|
||||||
|
taller = 0;
|
||||||
|
return avl_tree_replace_loop(tree->compare_func, \
|
||||||
|
tree->free_data_func, &(tree->root), data, &taller);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AVLTreeNode *avl_tree_find_loop(CompareFunc compare_func, \
|
||||||
|
AVLTreeNode *pCurrentNode, void *target_data)
|
||||||
|
{
|
||||||
|
int nCompRes;
|
||||||
|
nCompRes = compare_func(pCurrentNode->data, target_data);
|
||||||
|
if (nCompRes > 0)
|
||||||
|
{
|
||||||
|
if (pCurrentNode->left == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return avl_tree_find_loop(compare_func, \
|
||||||
|
pCurrentNode->left, target_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (nCompRes < 0)
|
||||||
|
{
|
||||||
|
if (pCurrentNode->right == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return avl_tree_find_loop(compare_func, \
|
||||||
|
pCurrentNode->right, target_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return pCurrentNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *avl_tree_find_ge_loop(CompareFunc compare_func, \
|
||||||
|
AVLTreeNode *pCurrentNode, void *target_data)
|
||||||
|
{
|
||||||
|
int nCompRes;
|
||||||
|
void *found;
|
||||||
|
|
||||||
|
nCompRes = compare_func(pCurrentNode->data, target_data);
|
||||||
|
if (nCompRes > 0)
|
||||||
|
{
|
||||||
|
if (pCurrentNode->left == NULL)
|
||||||
|
{
|
||||||
|
return pCurrentNode->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = avl_tree_find_ge_loop(compare_func, \
|
||||||
|
pCurrentNode->left, target_data);
|
||||||
|
return found != NULL ? found : pCurrentNode->data;
|
||||||
|
}
|
||||||
|
else if (nCompRes < 0)
|
||||||
|
{
|
||||||
|
if (pCurrentNode->right == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return avl_tree_find_ge_loop(compare_func, \
|
||||||
|
pCurrentNode->right, target_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return pCurrentNode->data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *avl_tree_find(AVLTreeInfo *tree, void *target_data)
|
||||||
|
{
|
||||||
|
AVLTreeNode *found;
|
||||||
|
|
||||||
|
if (tree->root == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = avl_tree_find_loop(tree->compare_func, \
|
||||||
|
tree->root, target_data);
|
||||||
|
|
||||||
|
return found != NULL ? found->data : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *avl_tree_find_ge(AVLTreeInfo *tree, void *target_data)
|
||||||
|
{
|
||||||
|
void *found;
|
||||||
|
|
||||||
|
if (tree->root == NULL)
|
||||||
|
{
|
||||||
|
found = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found = avl_tree_find_ge_loop(tree->compare_func, \
|
||||||
|
tree->root, target_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avlLeftBalanceWhenDelete(AVLTreeNode **pTreeNode, int *shorter)
|
||||||
|
{
|
||||||
|
AVLTreeNode *leftsub;
|
||||||
|
AVLTreeNode *rightsub;
|
||||||
|
|
||||||
|
leftsub = (*pTreeNode)->left;
|
||||||
|
switch (leftsub->balance)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||||
|
avlRotateRight (*pTreeNode, pTreeNode);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
leftsub->balance = 1;
|
||||||
|
avlRotateRight(*pTreeNode, pTreeNode);
|
||||||
|
*shorter = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rightsub = leftsub->right;
|
||||||
|
switch ( rightsub->balance )
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
(*pTreeNode)->balance = 1;
|
||||||
|
leftsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case 0 :
|
||||||
|
(*pTreeNode)->balance = leftsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case 1 :
|
||||||
|
(*pTreeNode)->balance = 0;
|
||||||
|
leftsub->balance = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rightsub->balance = 0;
|
||||||
|
avlRotateLeft( leftsub, &((*pTreeNode)->left));
|
||||||
|
avlRotateRight(*pTreeNode, pTreeNode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avlRightBalanceWhenDelete(AVLTreeNode **pTreeNode, int *shorter)
|
||||||
|
{
|
||||||
|
AVLTreeNode *rightsub;
|
||||||
|
AVLTreeNode *leftsub;
|
||||||
|
|
||||||
|
rightsub = (*pTreeNode)->right;
|
||||||
|
switch (rightsub->balance)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||||
|
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
rightsub->balance = -1;
|
||||||
|
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||||
|
*shorter = 0;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
leftsub = rightsub->left;
|
||||||
|
switch (leftsub->balance)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
(*pTreeNode)->balance = -1;
|
||||||
|
rightsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
(*pTreeNode)->balance = rightsub->balance = 0;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
(*pTreeNode)->balance = 0;
|
||||||
|
rightsub->balance = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftsub->balance = 0;
|
||||||
|
avlRotateRight(rightsub, &((*pTreeNode)->right));
|
||||||
|
avlRotateLeft(*pTreeNode, pTreeNode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avl_tree_delete_loop(AVLTreeInfo *tree, AVLTreeNode **pCurrentNode,\
|
||||||
|
void *target_data, int *shorter, AVLTreeNode *pDeletedDataNode)
|
||||||
|
{
|
||||||
|
int nCompRes;
|
||||||
|
bool result;
|
||||||
|
AVLTreeNode *leftsub;
|
||||||
|
AVLTreeNode *rightsub;
|
||||||
|
|
||||||
|
if (pDeletedDataNode != NULL)
|
||||||
|
{
|
||||||
|
if ((*pCurrentNode)->right == NULL)
|
||||||
|
{
|
||||||
|
pDeletedDataNode->data = (*pCurrentNode)->data;
|
||||||
|
leftsub = (*pCurrentNode)->left;
|
||||||
|
|
||||||
|
free(*pCurrentNode);
|
||||||
|
*pCurrentNode = leftsub;
|
||||||
|
*shorter = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nCompRes = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nCompRes = tree->compare_func((*pCurrentNode)->data, target_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nCompRes > 0)
|
||||||
|
{
|
||||||
|
if ((*pCurrentNode)->left == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = avl_tree_delete_loop(tree, &((*pCurrentNode)->left), \
|
||||||
|
target_data, shorter, pDeletedDataNode);
|
||||||
|
if (*shorter != 0)
|
||||||
|
{
|
||||||
|
switch ((*pCurrentNode)->balance)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
(*pCurrentNode)->balance = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
(*pCurrentNode)->balance = 1;
|
||||||
|
*shorter = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
avlRightBalanceWhenDelete(pCurrentNode, shorter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (nCompRes < 0)
|
||||||
|
{
|
||||||
|
if ((*pCurrentNode)->right == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = avl_tree_delete_loop(tree, &((*pCurrentNode)->right), \
|
||||||
|
target_data, shorter, pDeletedDataNode);
|
||||||
|
if (*shorter != 0)
|
||||||
|
{
|
||||||
|
switch ((*pCurrentNode)->balance)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
avlLeftBalanceWhenDelete(pCurrentNode, shorter);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
(*pCurrentNode)->balance = -1;
|
||||||
|
*shorter = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
(*pCurrentNode)->balance = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tree->free_data_func != NULL)
|
||||||
|
{
|
||||||
|
tree->free_data_func((*pCurrentNode)->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
leftsub = (*pCurrentNode)->left;
|
||||||
|
rightsub = (*pCurrentNode)->right;
|
||||||
|
if (leftsub == NULL)
|
||||||
|
{
|
||||||
|
free(*pCurrentNode);
|
||||||
|
*pCurrentNode = rightsub;
|
||||||
|
}
|
||||||
|
else if (rightsub == NULL)
|
||||||
|
{
|
||||||
|
free(*pCurrentNode);
|
||||||
|
*pCurrentNode = leftsub;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
avl_tree_delete_loop(tree, &((*pCurrentNode)->left), \
|
||||||
|
target_data, shorter, *pCurrentNode);
|
||||||
|
|
||||||
|
if (*shorter != 0)
|
||||||
|
{
|
||||||
|
switch ((*pCurrentNode)->balance)
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
(*pCurrentNode)->balance = 0;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
(*pCurrentNode)->balance = 1;
|
||||||
|
*shorter = 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
avlRightBalanceWhenDelete(pCurrentNode, shorter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*shorter = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int avl_tree_delete(AVLTreeInfo *tree, void *data)
|
||||||
|
{
|
||||||
|
int shorter;
|
||||||
|
|
||||||
|
if (tree->root == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
shorter = 0;
|
||||||
|
return avl_tree_delete_loop(tree, &(tree->root), data, &shorter, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int avl_tree_walk_loop(DataOpFunc data_op_func, \
|
||||||
|
AVLTreeNode *pCurrentNode, void *args)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (pCurrentNode->left != NULL)
|
||||||
|
{
|
||||||
|
result = avl_tree_walk_loop(data_op_func, \
|
||||||
|
pCurrentNode->left, args);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=data_op_func(pCurrentNode->data, args)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (pCurrentNode->balance >= -1 && pCurrentNode->balance <= 1)
|
||||||
|
{
|
||||||
|
//printf("==%d\n", pCurrentNode->balance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("==bad %d!!!!!!!!!!!!\n", pCurrentNode->balance);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (pCurrentNode->right != NULL)
|
||||||
|
{
|
||||||
|
result = avl_tree_walk_loop(data_op_func, \
|
||||||
|
pCurrentNode->right, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avl_tree_walk(AVLTreeInfo *tree, DataOpFunc data_op_func, void *args)
|
||||||
|
{
|
||||||
|
if (tree->root == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return avl_tree_walk_loop(data_op_func, tree->root, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avl_tree_count_loop(AVLTreeNode *pCurrentNode, int *count)
|
||||||
|
{
|
||||||
|
if (pCurrentNode->left != NULL)
|
||||||
|
{
|
||||||
|
avl_tree_count_loop(pCurrentNode->left, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
|
||||||
|
if (pCurrentNode->right != NULL)
|
||||||
|
{
|
||||||
|
avl_tree_count_loop(pCurrentNode->right, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int avl_tree_count(AVLTreeInfo *tree)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
if (tree->root == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
avl_tree_count_loop(tree->root, &count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int avl_tree_depth(AVLTreeInfo *tree)
|
||||||
|
{
|
||||||
|
int depth;
|
||||||
|
AVLTreeNode *pNode;
|
||||||
|
|
||||||
|
if (tree->root == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
depth = 0;
|
||||||
|
pNode = tree->root;
|
||||||
|
while (pNode != NULL)
|
||||||
|
{
|
||||||
|
if (pNode->balance == -1)
|
||||||
|
{
|
||||||
|
pNode = pNode->left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pNode = pNode->right;
|
||||||
|
}
|
||||||
|
depth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static void avl_tree_print_loop(AVLTreeNode *pCurrentNode)
|
||||||
|
{
|
||||||
|
printf("%ld left: %ld, right: %ld, balance: %d\n", pCurrentNode->data,
|
||||||
|
pCurrentNode->left != NULL ? pCurrentNode->left->data : 0,
|
||||||
|
pCurrentNode->right != NULL ? pCurrentNode->right->data : 0,
|
||||||
|
pCurrentNode->balance);
|
||||||
|
|
||||||
|
if (pCurrentNode->left != NULL)
|
||||||
|
{
|
||||||
|
avl_tree_print_loop(pCurrentNode->left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pCurrentNode->right != NULL)
|
||||||
|
{
|
||||||
|
avl_tree_print_loop(pCurrentNode->right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void avl_tree_print(AVLTreeInfo *tree)
|
||||||
|
{
|
||||||
|
if (tree->root == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
avl_tree_print_loop(tree->root);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
#ifndef AVL_TREE_H
|
||||||
|
#define AVL_TREE_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
typedef struct tagAVLTreeNode {
|
||||||
|
void *data;
|
||||||
|
struct tagAVLTreeNode *left;
|
||||||
|
struct tagAVLTreeNode *right;
|
||||||
|
byte balance;
|
||||||
|
} AVLTreeNode;
|
||||||
|
|
||||||
|
typedef int (*DataOpFunc) (void *data, void *args);
|
||||||
|
|
||||||
|
typedef struct tagAVLTreeInfo {
|
||||||
|
AVLTreeNode *root;
|
||||||
|
FreeDataFunc free_data_func;
|
||||||
|
CompareFunc compare_func;
|
||||||
|
} AVLTreeInfo;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
|
||||||
|
CompareFunc compare_func);
|
||||||
|
void avl_tree_destroy(AVLTreeInfo *tree);
|
||||||
|
|
||||||
|
int avl_tree_insert(AVLTreeInfo *tree, void *data);
|
||||||
|
int avl_tree_replace(AVLTreeInfo *tree, void *data);
|
||||||
|
int avl_tree_delete(AVLTreeInfo *tree, void *data);
|
||||||
|
void *avl_tree_find(AVLTreeInfo *tree, void *target_data);
|
||||||
|
void *avl_tree_find_ge(AVLTreeInfo *tree, void *target_data);
|
||||||
|
int avl_tree_walk(AVLTreeInfo *tree, DataOpFunc data_op_func, void *args);
|
||||||
|
int avl_tree_count(AVLTreeInfo *tree);
|
||||||
|
int avl_tree_depth(AVLTreeInfo *tree);
|
||||||
|
//void avl_tree_print(AVLTreeInfo *tree);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,393 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "base64.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker value for chars we just ignore, e.g. \n \r high ascii
|
||||||
|
*/
|
||||||
|
#define BASE64_IGNORE -1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker for = trailing pad
|
||||||
|
*/
|
||||||
|
#define BASE64_PAD -2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determines how long the lines are that are generated by encode.
|
||||||
|
* Ignored by decode.
|
||||||
|
* @param length 0 means no newlines inserted. Must be a multiple of 4.
|
||||||
|
*/
|
||||||
|
void base64_set_line_length(struct base64_context *context, const int length)
|
||||||
|
{
|
||||||
|
context->line_length = (length / 4) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How lines are separated.
|
||||||
|
* Ignored by decode.
|
||||||
|
* @param context->line_separator may be "" but not null.
|
||||||
|
* Usually contains only a combination of chars \n and \r.
|
||||||
|
* Could be any chars not in set A-Z a-z 0-9 + /.
|
||||||
|
*/
|
||||||
|
void base64_set_line_separator(struct base64_context *context, \
|
||||||
|
const char *pLineSeparator)
|
||||||
|
{
|
||||||
|
context->line_sep_len = snprintf(context->line_separator, \
|
||||||
|
sizeof(context->line_separator), "%s", pLineSeparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void base64_init_ex(struct base64_context *context, const int nLineLength, \
|
||||||
|
const unsigned char chPlus, const unsigned char chSplash, \
|
||||||
|
const unsigned char chPad)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(context, 0, sizeof(struct base64_context));
|
||||||
|
|
||||||
|
context->line_length = nLineLength;
|
||||||
|
context->line_separator[0] = '\n';
|
||||||
|
context->line_separator[1] = '\0';
|
||||||
|
context->line_sep_len = 1;
|
||||||
|
|
||||||
|
// build translate valueToChar table only once.
|
||||||
|
// 0..25 -> 'A'..'Z'
|
||||||
|
for (i=0; i<=25; i++)
|
||||||
|
{
|
||||||
|
context->valueToChar[i] = (char)('A'+i);
|
||||||
|
}
|
||||||
|
// 26..51 -> 'a'..'z'
|
||||||
|
for (i=0; i<=25; i++ )
|
||||||
|
{
|
||||||
|
context->valueToChar[i+26] = (char)('a'+i);
|
||||||
|
}
|
||||||
|
// 52..61 -> '0'..'9'
|
||||||
|
for (i=0; i<=9; i++ )
|
||||||
|
{
|
||||||
|
context->valueToChar[i+52] = (char)('0'+i);
|
||||||
|
}
|
||||||
|
context->valueToChar[62] = chPlus;
|
||||||
|
context->valueToChar[63] = chSplash;
|
||||||
|
|
||||||
|
memset(context->charToValue, BASE64_IGNORE, sizeof(context->charToValue));
|
||||||
|
for (i=0; i<64; i++ )
|
||||||
|
{
|
||||||
|
context->charToValue[context->valueToChar[i]] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->pad_ch = chPad;
|
||||||
|
context->charToValue[chPad] = BASE64_PAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
int base64_get_encode_length(struct base64_context *context, const int nSrcLen)
|
||||||
|
{
|
||||||
|
// Each group or partial group of 3 bytes becomes four chars
|
||||||
|
// covered quotient
|
||||||
|
int outputLength;
|
||||||
|
|
||||||
|
outputLength = ((nSrcLen + 2) / 3) * 4;
|
||||||
|
|
||||||
|
// account for trailing newlines, on all but the very last line
|
||||||
|
if (context->line_length != 0)
|
||||||
|
{
|
||||||
|
int lines = (outputLength + context->line_length - 1) /
|
||||||
|
context->line_length - 1;
|
||||||
|
if ( lines > 0 )
|
||||||
|
{
|
||||||
|
outputLength += lines * context->line_sep_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode an arbitrary array of bytes as base64 printable ASCII.
|
||||||
|
* It will be broken into lines of 72 chars each. The last line is not
|
||||||
|
* terminated with a line separator.
|
||||||
|
* The output will always have an even multiple of data characters,
|
||||||
|
* exclusive of \n. It is padded out with =.
|
||||||
|
*/
|
||||||
|
char *base64_encode_ex(struct base64_context *context, const char *src, \
|
||||||
|
const int nSrcLen, char *dest, int *dest_len, const bool bPad)
|
||||||
|
{
|
||||||
|
int linePos;
|
||||||
|
int leftover;
|
||||||
|
int combined;
|
||||||
|
char *pDest;
|
||||||
|
int c0, c1, c2, c3;
|
||||||
|
unsigned char *pRaw;
|
||||||
|
unsigned char *pEnd;
|
||||||
|
const char *ppSrcs[2];
|
||||||
|
int lens[2];
|
||||||
|
char szPad[3];
|
||||||
|
int k;
|
||||||
|
int loop;
|
||||||
|
|
||||||
|
if (nSrcLen <= 0)
|
||||||
|
{
|
||||||
|
*dest = '\0';
|
||||||
|
*dest_len = 0;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
linePos = 0;
|
||||||
|
lens[0] = (nSrcLen / 3) * 3;
|
||||||
|
lens[1] = 3;
|
||||||
|
leftover = nSrcLen - lens[0];
|
||||||
|
ppSrcs[0] = src;
|
||||||
|
ppSrcs[1] = szPad;
|
||||||
|
|
||||||
|
szPad[0] = szPad[1] = szPad[2] = '\0';
|
||||||
|
switch (leftover)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
loop = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
loop = 2;
|
||||||
|
szPad[0] = src[nSrcLen-1];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
loop = 2;
|
||||||
|
szPad[0] = src[nSrcLen-2];
|
||||||
|
szPad[1] = src[nSrcLen-1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDest = dest;
|
||||||
|
for (k=0; k<loop; k++)
|
||||||
|
{
|
||||||
|
pEnd = (unsigned char *)ppSrcs[k] + lens[k];
|
||||||
|
for (pRaw=(unsigned char *)ppSrcs[k]; pRaw<pEnd; pRaw+=3)
|
||||||
|
{
|
||||||
|
// Start a new line if next 4 chars won't fit on the current line
|
||||||
|
// We can't encapsulete the following code since the variable need to
|
||||||
|
// be local to this incarnation of encode.
|
||||||
|
linePos += 4;
|
||||||
|
if (linePos > context->line_length)
|
||||||
|
{
|
||||||
|
if (context->line_length != 0)
|
||||||
|
{
|
||||||
|
memcpy(pDest, context->line_separator, context->line_sep_len);
|
||||||
|
pDest += context->line_sep_len;
|
||||||
|
}
|
||||||
|
linePos = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get next three bytes in unsigned form lined up,
|
||||||
|
// in big-endian order
|
||||||
|
combined = ((*pRaw) << 16) | ((*(pRaw+1)) << 8) | (*(pRaw+2));
|
||||||
|
|
||||||
|
// break those 24 bits into a 4 groups of 6 bits,
|
||||||
|
// working LSB to MSB.
|
||||||
|
c3 = combined & 0x3f;
|
||||||
|
combined >>= 6;
|
||||||
|
c2 = combined & 0x3f;
|
||||||
|
combined >>= 6;
|
||||||
|
c1 = combined & 0x3f;
|
||||||
|
combined >>= 6;
|
||||||
|
c0 = combined & 0x3f;
|
||||||
|
|
||||||
|
// Translate into the equivalent alpha character
|
||||||
|
// emitting them in big-endian order.
|
||||||
|
*pDest++ = context->valueToChar[c0];
|
||||||
|
*pDest++ = context->valueToChar[c1];
|
||||||
|
*pDest++ = context->valueToChar[c2];
|
||||||
|
*pDest++ = context->valueToChar[c3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pDest = '\0';
|
||||||
|
*dest_len = pDest - dest;
|
||||||
|
|
||||||
|
// deal with leftover bytes
|
||||||
|
switch (leftover)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
// nothing to do
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// One leftover byte generates xx==
|
||||||
|
if (bPad)
|
||||||
|
{
|
||||||
|
*(pDest-1) = context->pad_ch;
|
||||||
|
*(pDest-2) = context->pad_ch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(pDest-2) = '\0';
|
||||||
|
*dest_len -= 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Two leftover bytes generates xxx=
|
||||||
|
if (bPad)
|
||||||
|
{
|
||||||
|
*(pDest-1) = context->pad_ch;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(pDest-1) = '\0';
|
||||||
|
*dest_len -= 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} // end switch;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *base64_decode_auto(struct base64_context *context, const char *src, \
|
||||||
|
const int nSrcLen, char *dest, int *dest_len)
|
||||||
|
{
|
||||||
|
int nRemain;
|
||||||
|
int nPadLen;
|
||||||
|
int nNewLen;
|
||||||
|
char tmpBuff[256];
|
||||||
|
char *pBuff;
|
||||||
|
|
||||||
|
nRemain = nSrcLen % 4;
|
||||||
|
if (nRemain == 0)
|
||||||
|
{
|
||||||
|
return base64_decode(context, src, nSrcLen, dest, dest_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
nPadLen = 4 - nRemain;
|
||||||
|
nNewLen = nSrcLen + nPadLen;
|
||||||
|
if (nNewLen <= sizeof(tmpBuff))
|
||||||
|
{
|
||||||
|
pBuff = tmpBuff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pBuff = (char *)malloc(nNewLen);
|
||||||
|
if (pBuff == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Can't malloc %d bytes\n", \
|
||||||
|
nSrcLen + nPadLen + 1);
|
||||||
|
*dest_len = 0;
|
||||||
|
*dest = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pBuff, src, nSrcLen);
|
||||||
|
memset(pBuff + nSrcLen, context->pad_ch, nPadLen);
|
||||||
|
|
||||||
|
base64_decode(context, pBuff, nNewLen, dest, dest_len);
|
||||||
|
|
||||||
|
if (pBuff != tmpBuff)
|
||||||
|
{
|
||||||
|
free(pBuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* decode a well-formed complete base64 string back into an array of bytes.
|
||||||
|
* It must have an even multiple of 4 data characters (not counting \n),
|
||||||
|
* padded out with = as needed.
|
||||||
|
*/
|
||||||
|
char *base64_decode(struct base64_context *context, const char *src, \
|
||||||
|
const int nSrcLen, char *dest, int *dest_len)
|
||||||
|
{
|
||||||
|
// tracks where we are in a cycle of 4 input chars.
|
||||||
|
int cycle;
|
||||||
|
|
||||||
|
// where we combine 4 groups of 6 bits and take apart as 3 groups of 8.
|
||||||
|
int combined;
|
||||||
|
|
||||||
|
// will be an even multiple of 4 chars, plus some embedded \n
|
||||||
|
int dummies;
|
||||||
|
int value;
|
||||||
|
unsigned char *pSrc;
|
||||||
|
unsigned char *pSrcEnd;
|
||||||
|
char *pDest;
|
||||||
|
|
||||||
|
cycle = 0;
|
||||||
|
combined = 0;
|
||||||
|
dummies = 0;
|
||||||
|
pDest = dest;
|
||||||
|
pSrcEnd = (unsigned char *)src + nSrcLen;
|
||||||
|
for (pSrc=(unsigned char *)src; pSrc<pSrcEnd; pSrc++)
|
||||||
|
{
|
||||||
|
value = context->charToValue[*pSrc];
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case BASE64_IGNORE:
|
||||||
|
// e.g. \n, just ignore it.
|
||||||
|
break;
|
||||||
|
case BASE64_PAD:
|
||||||
|
value = 0;
|
||||||
|
dummies++;
|
||||||
|
// fallthrough
|
||||||
|
default:
|
||||||
|
/* regular value character */
|
||||||
|
switch (cycle)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
combined = value;
|
||||||
|
cycle = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
combined <<= 6;
|
||||||
|
combined |= value;
|
||||||
|
cycle = 2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
combined <<= 6;
|
||||||
|
combined |= value;
|
||||||
|
cycle = 3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
combined <<= 6;
|
||||||
|
combined |= value;
|
||||||
|
// we have just completed a cycle of 4 chars.
|
||||||
|
// the four 6-bit values are in combined in big-endian order
|
||||||
|
// peel them off 8 bits at a time working lsb to msb
|
||||||
|
// to get our original 3 8-bit bytes back
|
||||||
|
|
||||||
|
*pDest++ = (char)(combined >> 16);
|
||||||
|
*pDest++ = (char)((combined & 0x0000FF00) >> 8);
|
||||||
|
*pDest++ = (char)(combined & 0x000000FF);
|
||||||
|
|
||||||
|
cycle = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // end for
|
||||||
|
|
||||||
|
if (cycle != 0)
|
||||||
|
{
|
||||||
|
*dest = '\0';
|
||||||
|
*dest_len = 0;
|
||||||
|
fprintf(stderr, "Input to decode not an even multiple of " \
|
||||||
|
"4 characters; pad with %c\n", context->pad_ch);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest_len = (pDest - dest) - dummies;
|
||||||
|
*(dest + (*dest_len)) = '\0';
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//base64.h
|
||||||
|
|
||||||
|
#ifndef _BASE64_H
|
||||||
|
#define _BASE64_H
|
||||||
|
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
struct base64_context
|
||||||
|
{
|
||||||
|
char line_separator[16];
|
||||||
|
int line_sep_len;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max chars per line, excluding line_separator. A multiple of 4.
|
||||||
|
*/
|
||||||
|
int line_length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* letter of the alphabet used to encode binary values 0..63
|
||||||
|
*/
|
||||||
|
unsigned char valueToChar[64];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* binary value encoded by a given letter of the alphabet 0..63
|
||||||
|
*/
|
||||||
|
int charToValue[256];
|
||||||
|
int pad_ch;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** use stardand base64 charset
|
||||||
|
*/
|
||||||
|
#define base64_init(context, nLineLength) \
|
||||||
|
base64_init_ex(context, nLineLength, '+', '/', '=')
|
||||||
|
|
||||||
|
|
||||||
|
/** stardand base64 encode
|
||||||
|
*/
|
||||||
|
#define base64_encode(context, src, nSrcLen, dest, dest_len) \
|
||||||
|
base64_encode_ex(context, src, nSrcLen, dest, dest_len, true)
|
||||||
|
|
||||||
|
/** base64 init function, before use base64 function, you should call
|
||||||
|
* this function
|
||||||
|
* parameters:
|
||||||
|
* context: the base64 context
|
||||||
|
* nLineLength: length of a line, 0 for never add line seperator
|
||||||
|
* chPlus: specify a char for base64 char plus (+)
|
||||||
|
* chSplash: specify a char for base64 char splash (/)
|
||||||
|
* chPad: specify a char for base64 padding char =
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void base64_init_ex(struct base64_context *context, const int nLineLength, \
|
||||||
|
const unsigned char chPlus, const unsigned char chSplash, \
|
||||||
|
const unsigned char chPad);
|
||||||
|
|
||||||
|
/** calculate the encoded length of the source buffer
|
||||||
|
* parameters:
|
||||||
|
* context: the base64 context
|
||||||
|
* nSrcLen: the source buffer length
|
||||||
|
* return: the encoded length of the source buffer
|
||||||
|
*/
|
||||||
|
int base64_get_encode_length(struct base64_context *context, const int nSrcLen);
|
||||||
|
|
||||||
|
/** base64 encode buffer
|
||||||
|
* parameters:
|
||||||
|
* context: the base64 context
|
||||||
|
* src: the source buffer
|
||||||
|
* nSrcLen: the source buffer length
|
||||||
|
* dest: the dest buffer
|
||||||
|
* dest_len: return dest buffer length
|
||||||
|
* bPad: if padding
|
||||||
|
* return: the encoded buffer
|
||||||
|
*/
|
||||||
|
char *base64_encode_ex(struct base64_context *context, const char *src, \
|
||||||
|
const int nSrcLen, char *dest, int *dest_len, const bool bPad);
|
||||||
|
|
||||||
|
/** base64 decode buffer, work only with padding source string
|
||||||
|
* parameters:
|
||||||
|
* context: the base64 context
|
||||||
|
* src: the source buffer with padding
|
||||||
|
* nSrcLen: the source buffer length
|
||||||
|
* dest: the dest buffer
|
||||||
|
* dest_len: return dest buffer length
|
||||||
|
* return: the decoded buffer
|
||||||
|
*/
|
||||||
|
char *base64_decode(struct base64_context *context, const char *src, \
|
||||||
|
const int nSrcLen, char *dest, int *dest_len);
|
||||||
|
|
||||||
|
/** base64 decode buffer, can work with no padding source string
|
||||||
|
* parameters:
|
||||||
|
* context: the base64 context
|
||||||
|
* src: the source buffer with padding or no padding
|
||||||
|
* nSrcLen: the source buffer length
|
||||||
|
* dest: the dest buffer
|
||||||
|
* dest_len: return dest buffer length
|
||||||
|
* return: the decoded buffer
|
||||||
|
*/
|
||||||
|
char *base64_decode_auto(struct base64_context *context, const char *src, \
|
||||||
|
const int nSrcLen, char *dest, int *dest_len);
|
||||||
|
|
||||||
|
/** set line separator string, such as \n or \r\n
|
||||||
|
* parameters:
|
||||||
|
* context: the base64 context
|
||||||
|
* pLineSeparator: the line separator string
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void base64_set_line_separator(struct base64_context *context, \
|
||||||
|
const char *pLineSeparator);
|
||||||
|
|
||||||
|
/** set line length, 0 for never add line separators
|
||||||
|
* parameters:
|
||||||
|
* context: the base64 context
|
||||||
|
* length: the line length
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void base64_set_line_length(struct base64_context *context, const int length);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,325 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "chain.h"
|
||||||
|
//#include "use_mmalloc.h"
|
||||||
|
|
||||||
|
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
|
||||||
|
CompareFunc compareFunc)
|
||||||
|
{
|
||||||
|
if (pList == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pList->head = NULL;
|
||||||
|
pList->tail = NULL;
|
||||||
|
pList->type = type;
|
||||||
|
pList->freeDataFunc = freeDataFunc;
|
||||||
|
pList->compareFunc = compareFunc;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void chain_destroy(ChainList *pList)
|
||||||
|
{
|
||||||
|
ChainNode *pNode;
|
||||||
|
ChainNode *pDeleted;
|
||||||
|
if (pList == NULL || pList->head == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode = pList->head;
|
||||||
|
while (pNode != NULL)
|
||||||
|
{
|
||||||
|
pDeleted = pNode;
|
||||||
|
pNode = pNode->next;
|
||||||
|
|
||||||
|
freeChainNode(pList, pDeleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
pList->head = pList->tail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeChainNode(ChainList *pList, ChainNode *pChainNode)
|
||||||
|
{
|
||||||
|
if (pList->freeDataFunc != NULL)
|
||||||
|
{
|
||||||
|
pList->freeDataFunc(pChainNode->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pChainNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int insertNodePrior(ChainList *pList, void *data)
|
||||||
|
{
|
||||||
|
ChainNode *pNode;
|
||||||
|
if (pList == NULL)
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode = (ChainNode *)malloc(sizeof(ChainNode));
|
||||||
|
if (pNode == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode->data = data;
|
||||||
|
pNode->next = pList->head;
|
||||||
|
|
||||||
|
pList->head = pNode;
|
||||||
|
if (pList->tail == NULL)
|
||||||
|
{
|
||||||
|
pList->tail = pNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int appendNode(ChainList *pList, void *data)
|
||||||
|
{
|
||||||
|
ChainNode *pNode;
|
||||||
|
if (pList == NULL)
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode = (ChainNode *)malloc(sizeof(ChainNode));
|
||||||
|
if (pNode == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode->data = data;
|
||||||
|
pNode->next = NULL;
|
||||||
|
|
||||||
|
if (pList->tail != NULL)
|
||||||
|
{
|
||||||
|
pList->tail->next = pNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
pList->tail = pNode;
|
||||||
|
if (pList->head == NULL)
|
||||||
|
{
|
||||||
|
pList->head = pNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int insertNodeAsc(ChainList *pList, void *data)
|
||||||
|
{
|
||||||
|
ChainNode *pNew;
|
||||||
|
ChainNode *pNode;
|
||||||
|
ChainNode *pPrevious;
|
||||||
|
if (pList == NULL || pList->compareFunc == NULL)
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNew = (ChainNode *)malloc(sizeof(ChainNode));
|
||||||
|
if (pNew == NULL)
|
||||||
|
{
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNew->data = data;
|
||||||
|
|
||||||
|
pPrevious = NULL;
|
||||||
|
pNode = pList->head;
|
||||||
|
while (pNode != NULL && pList->compareFunc(pNode->data, data) < 0)
|
||||||
|
{
|
||||||
|
pPrevious = pNode;
|
||||||
|
pNode = pNode->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNew->next = pNode;
|
||||||
|
if (pPrevious == NULL)
|
||||||
|
{
|
||||||
|
pList->head = pNew;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pPrevious->next = pNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pNode == NULL)
|
||||||
|
{
|
||||||
|
pList->tail = pNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int addNode(ChainList *pList, void *data)
|
||||||
|
{
|
||||||
|
if (pList->type == CHAIN_TYPE_INSERT)
|
||||||
|
{
|
||||||
|
return insertNodePrior(pList, data);
|
||||||
|
}
|
||||||
|
else if (pList->type == CHAIN_TYPE_APPEND)
|
||||||
|
{
|
||||||
|
return appendNode(pList, data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return insertNodeAsc(pList, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteNodeEx(ChainList *pList, ChainNode *pPreviousNode, \
|
||||||
|
ChainNode *pDeletedNode)
|
||||||
|
{
|
||||||
|
if (pDeletedNode == pList->head)
|
||||||
|
{
|
||||||
|
pList->head = pDeletedNode->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pPreviousNode->next = pDeletedNode->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDeletedNode == pList->tail)
|
||||||
|
{
|
||||||
|
pList->tail = pPreviousNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeChainNode(pList, pDeletedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteToNodePrevious(ChainList *pList, ChainNode *pPreviousNode, \
|
||||||
|
ChainNode *pDeletedNext)
|
||||||
|
{
|
||||||
|
ChainNode *pNode;
|
||||||
|
ChainNode *pDeletedNode;
|
||||||
|
|
||||||
|
if (pPreviousNode == NULL)
|
||||||
|
{
|
||||||
|
pNode = pList->head;
|
||||||
|
pList->head = pDeletedNext;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pNode = pPreviousNode->next;
|
||||||
|
pPreviousNode->next = pDeletedNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pNode != NULL && pNode != pDeletedNext)
|
||||||
|
{
|
||||||
|
pDeletedNode = pNode;
|
||||||
|
pNode = pNode->next;
|
||||||
|
freeChainNode(pList, pDeletedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDeletedNext == NULL)
|
||||||
|
{
|
||||||
|
pList->tail = pPreviousNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *chain_pop_head(ChainList *pList)
|
||||||
|
{
|
||||||
|
ChainNode *pDeletedNode;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
pDeletedNode = pList->head;
|
||||||
|
if (pDeletedNode == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pList->head = pDeletedNode->next;
|
||||||
|
if (pList->head == NULL)
|
||||||
|
{
|
||||||
|
pList->tail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = pDeletedNode->data;
|
||||||
|
free(pDeletedNode);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chain_count(ChainList *pList)
|
||||||
|
{
|
||||||
|
ChainNode *pNode;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
pNode = pList->head;
|
||||||
|
while (pNode != NULL)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
pNode = pNode->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteNode(ChainList *pList, void *data, bool bDeleteAll)
|
||||||
|
{
|
||||||
|
ChainNode *pNode;
|
||||||
|
ChainNode *pPrevious;
|
||||||
|
ChainNode *pDeleted;
|
||||||
|
int nCount;
|
||||||
|
int nCompareRes;
|
||||||
|
|
||||||
|
if (pList == NULL || pList->compareFunc == NULL)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nCount = 0;
|
||||||
|
pPrevious = NULL;
|
||||||
|
pNode = pList->head;
|
||||||
|
while (pNode != NULL)
|
||||||
|
{
|
||||||
|
nCompareRes = pList->compareFunc(pNode->data, data);
|
||||||
|
if (nCompareRes == 0)
|
||||||
|
{
|
||||||
|
pDeleted = pNode;
|
||||||
|
pNode = pNode->next;
|
||||||
|
|
||||||
|
deleteNodeEx(pList, pPrevious, pDeleted);
|
||||||
|
nCount++;
|
||||||
|
|
||||||
|
if (!bDeleteAll)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(nCompareRes > 0 && pList->type == CHAIN_TYPE_SORTED)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPrevious = pNode;
|
||||||
|
pNode = pNode->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteOne(ChainList *pList, void *data)
|
||||||
|
{
|
||||||
|
return deleteNode(pList, data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteAll(ChainList *pList, void *data)
|
||||||
|
{
|
||||||
|
return deleteNode(pList, data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,148 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef CHAIN_H
|
||||||
|
#define CHAIN_H
|
||||||
|
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
#define CHAIN_TYPE_INSERT 0 //insert new node before head
|
||||||
|
#define CHAIN_TYPE_APPEND 1 //insert new node after tail
|
||||||
|
#define CHAIN_TYPE_SORTED 2 //sorted chain
|
||||||
|
|
||||||
|
typedef struct tagChainNode
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
struct tagChainNode *next;
|
||||||
|
} ChainNode;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
ChainNode *head;
|
||||||
|
ChainNode *tail;
|
||||||
|
FreeDataFunc freeDataFunc;
|
||||||
|
CompareFunc compareFunc;
|
||||||
|
} ChainList;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** chain init function
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* type: chain type, value is one of following:
|
||||||
|
* CHAIN_TYPE_INSERT: insert new node before head
|
||||||
|
* CHAIN_TYPE_APPEND: insert new node after tail
|
||||||
|
* CHAIN_TYPE_SORTED: sorted chain
|
||||||
|
* freeDataFunc: free data function pointer, can be NULL
|
||||||
|
* compareFunc: compare data function pointer, can be NULL,
|
||||||
|
* must set when type is CHAIN_TYPE_SORTED
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
|
||||||
|
CompareFunc compareFunc);
|
||||||
|
|
||||||
|
/** destroy chain
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void chain_destroy(ChainList *pList);
|
||||||
|
|
||||||
|
|
||||||
|
/** get the chain node count
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* return: chain node count
|
||||||
|
*/
|
||||||
|
int chain_count(ChainList *pList);
|
||||||
|
|
||||||
|
/** add a new node to the chain
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* data: the data to add
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int addNode(ChainList *pList, void *data);
|
||||||
|
|
||||||
|
/** free the chain node
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* pChainNode: the chain node to free
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void freeChainNode(ChainList *pList, ChainNode *pChainNode);
|
||||||
|
|
||||||
|
/** delete the chain node
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* pPreviousNode: the previous chain node
|
||||||
|
* pDeletedNode: the chain node to delete
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void deleteNodeEx(ChainList *pList, ChainNode *pPreviousNode, \
|
||||||
|
ChainNode *pDeletedNode);
|
||||||
|
|
||||||
|
/** delete the chain nodes from pPreviousNode->next to pDeletedNext
|
||||||
|
* (not including pDeletedNext)
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* pPreviousNode: the previous chain node, delete from pPreviousNode->next
|
||||||
|
* pDeletedNext: the chain node after the deleted node
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void deleteToNodePrevious(ChainList *pList, ChainNode *pPreviousNode, \
|
||||||
|
ChainNode *pDeletedNext);
|
||||||
|
|
||||||
|
/** delete the chain node using data compare function
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* data: the first node whose data equals this will be deleted
|
||||||
|
* return: delete chain node count, < 0 fail
|
||||||
|
*/
|
||||||
|
int deleteOne(ChainList *pList, void *data);
|
||||||
|
|
||||||
|
/** delete all chain nodes using data compare function
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* data: the node whose data equals this will be deleted
|
||||||
|
* return: delete chain node count, < 0 fail
|
||||||
|
*/
|
||||||
|
int deleteAll(ChainList *pList, void *data);
|
||||||
|
|
||||||
|
/** pop up a chain nodes from chain head
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* return: the head node, return NULL when the chain is empty
|
||||||
|
*/
|
||||||
|
void *chain_pop_head(ChainList *pList);
|
||||||
|
|
||||||
|
/** add a chain nodes before the chain head
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* data: the node to insert
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int insertNodePrior(ChainList *pList, void *data);
|
||||||
|
|
||||||
|
/** add a chain nodes after the chain tail
|
||||||
|
* parameters:
|
||||||
|
* pList: the chain list
|
||||||
|
* data: the node to insert
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int appendNode(ChainList *pList, void *data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//common_define.h
|
||||||
|
|
||||||
|
#ifndef _COMMON_DEFINE_H_
|
||||||
|
#define _COMMON_DEFINE_H_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock.h>
|
||||||
|
typedef UINT in_addr_t;
|
||||||
|
#define FILE_SEPERATOR "\\"
|
||||||
|
#define THREAD_ENTRANCE_FUNC_DECLARE DWORD WINAPI
|
||||||
|
#define THREAD_RETURN_VALUE 0
|
||||||
|
typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#define FILE_SEPERATOR "/"
|
||||||
|
typedef int SOCKET;
|
||||||
|
#define closesocket close
|
||||||
|
#define INVALID_SOCKET -1
|
||||||
|
#define THREAD_ENTRANCE_FUNC_DECLARE void *
|
||||||
|
typedef void *LPVOID;
|
||||||
|
#define THREAD_RETURN_VALUE NULL
|
||||||
|
typedef void * (*ThreadEntranceFunc)(LPVOID lpThreadParameter);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OS_LINUX
|
||||||
|
#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "_os_bits.h"
|
||||||
|
|
||||||
|
#ifdef OS_BITS
|
||||||
|
#if OS_BITS == 64
|
||||||
|
#define INT64_PRINTF_FORMAT "%ld"
|
||||||
|
#else
|
||||||
|
#define INT64_PRINTF_FORMAT "%lld"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define INT64_PRINTF_FORMAT "%lld"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OFF_BITS
|
||||||
|
#if OFF_BITS == 64
|
||||||
|
#define OFF_PRINTF_FORMAT INT64_PRINTF_FORMAT
|
||||||
|
#else
|
||||||
|
#define OFF_PRINTF_FORMAT "%d"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define OFF_PRINTF_FORMAT INT64_PRINTF_FORMAT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#define USE_SENDFILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_PATH_SIZE 256
|
||||||
|
#define LOG_FILE_DIR "logs"
|
||||||
|
#define CONF_FILE_DIR "conf"
|
||||||
|
#define DEFAULT_CONNECT_TIMEOUT 30
|
||||||
|
#define DEFAULT_NETWORK_TIMEOUT 30
|
||||||
|
#define DEFAULT_MAX_CONNECTONS 256
|
||||||
|
#define DEFAULT_WORK_THREADS 4
|
||||||
|
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
|
||||||
|
#define TIME_NONE -1
|
||||||
|
|
||||||
|
#define IP_ADDRESS_SIZE 16
|
||||||
|
#define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL)
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#ifndef true
|
||||||
|
typedef char bool;
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef byte
|
||||||
|
#define byte signed char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ubyte
|
||||||
|
#define ubyte unsigned char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#ifndef INADDR_NONE
|
||||||
|
#define INADDR_NONE ((in_addr_t) 0xffffffff)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ECANCELED
|
||||||
|
#define ECANCELED 125
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ENONET
|
||||||
|
#define ENONET 64 /* Machine is not on the network */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IS_UPPER_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
|
||||||
|
#define STRERROR(no) (strerror(no) != NULL ? strerror(no) : "Unkown error")
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
byte hour;
|
||||||
|
byte minute;
|
||||||
|
} TimeInfo;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char major;
|
||||||
|
char minor;
|
||||||
|
} Version;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *key;
|
||||||
|
char *value;
|
||||||
|
} KeyValuePair;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *buff;
|
||||||
|
int alloc_size;
|
||||||
|
int length;
|
||||||
|
} BufferInfo;
|
||||||
|
|
||||||
|
typedef void (*FreeDataFunc)(void *ptr);
|
||||||
|
typedef int (*CompareFunc)(void *p1, void *p2);
|
||||||
|
typedef void* (*MallocFunc)(size_t size);
|
||||||
|
|
||||||
|
#define TO_UPPERCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 32 : c)
|
||||||
|
#define MEM_ALIGN(x) (((x) + 7) & (~7))
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
tmp_src_filename=_fast_check_bits_.c
|
||||||
|
cat <<EOF > $tmp_src_filename
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
printf("%d\n", (int)sizeof(long));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
gcc -D_FILE_OFFSET_BITS=64 -o a.out $tmp_src_filename
|
||||||
|
OS_BITS=`./a.out`
|
||||||
|
|
||||||
|
rm $tmp_src_filename a.out
|
||||||
|
|
||||||
|
TARGET_LIB="/usr/local/lib"
|
||||||
|
if [ "`id -u`" = "0" ]; then
|
||||||
|
ln -fs $TARGET_LIB/libfastcommon.so.1 /usr/lib/libfastcommon.so
|
||||||
|
|
||||||
|
if [ "$OS_BITS" = "8" ]; then
|
||||||
|
ln -fs $TARGET_LIB/libfastcommon.so.1 /usr/lib64/libfastcommon.so
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
@ -0,0 +1,503 @@
|
||||||
|
//fast_task_queue.c
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "fast_task_queue.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "shared_func.h"
|
||||||
|
#include "pthread_func.h"
|
||||||
|
|
||||||
|
static struct fast_task_queue g_free_queue;
|
||||||
|
|
||||||
|
struct mpool_chain {
|
||||||
|
struct fast_task_info *blocks;
|
||||||
|
struct fast_task_info *last_block; //last block
|
||||||
|
struct mpool_chain *next;
|
||||||
|
} *g_mpool = NULL;
|
||||||
|
|
||||||
|
#define ALIGNED_TASK_INFO_SIZE MEM_ALIGN(sizeof(struct fast_task_info))
|
||||||
|
|
||||||
|
int task_queue_init(struct fast_task_queue *pQueue)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=init_pthread_lock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"init_pthread_lock fail, errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pQueue->head = NULL;
|
||||||
|
pQueue->tail = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct mpool_chain *malloc_mpool(const int block_size, \
|
||||||
|
const int total_alloc_size)
|
||||||
|
{
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
char *p;
|
||||||
|
char *pCharEnd;
|
||||||
|
struct mpool_chain *mpool;
|
||||||
|
|
||||||
|
mpool = (struct mpool_chain *)malloc(sizeof(struct mpool_chain));
|
||||||
|
if (mpool == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, (int)sizeof(struct mpool_chain), \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpool->next = NULL;
|
||||||
|
mpool->blocks = (struct fast_task_info *)malloc(total_alloc_size);
|
||||||
|
if (mpool->blocks == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, total_alloc_size, \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
free(mpool);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(mpool->blocks, 0, total_alloc_size);
|
||||||
|
|
||||||
|
pCharEnd = ((char *)mpool->blocks) + total_alloc_size;
|
||||||
|
for (p=(char *)mpool->blocks; p<pCharEnd; p += block_size)
|
||||||
|
{
|
||||||
|
pTask = (struct fast_task_info *)p;
|
||||||
|
pTask->size = g_free_queue.min_buff_size;
|
||||||
|
|
||||||
|
pTask->arg = p + ALIGNED_TASK_INFO_SIZE;
|
||||||
|
if (g_free_queue.malloc_whole_block)
|
||||||
|
{
|
||||||
|
pTask->data = (char *)pTask->arg + \
|
||||||
|
g_free_queue.arg_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pTask->data = (char *)malloc(pTask->size);
|
||||||
|
if (pTask->data == NULL)
|
||||||
|
{
|
||||||
|
char *pt;
|
||||||
|
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, pTask->size, \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
|
||||||
|
for (pt=(char *)mpool->blocks; pt < p; \
|
||||||
|
pt += block_size)
|
||||||
|
{
|
||||||
|
free(((struct fast_task_info *)pt)->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(mpool->blocks);
|
||||||
|
free(mpool);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpool->last_block = (struct fast_task_info *)(pCharEnd - block_size);
|
||||||
|
for (p=(char *)mpool->blocks; p<(char *)mpool->last_block; p += block_size)
|
||||||
|
{
|
||||||
|
pTask = (struct fast_task_info *)p;
|
||||||
|
pTask->next = (struct fast_task_info *)(p + block_size);
|
||||||
|
}
|
||||||
|
mpool->last_block->next = NULL;
|
||||||
|
|
||||||
|
return mpool;
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_init(const int max_connections, const int min_buff_size, \
|
||||||
|
const int max_buff_size, const int arg_size)
|
||||||
|
{
|
||||||
|
int64_t total_size;
|
||||||
|
struct mpool_chain *mpool;
|
||||||
|
int block_size;
|
||||||
|
int alloc_size;
|
||||||
|
int result;
|
||||||
|
int loop_count;
|
||||||
|
int aligned_min_size;
|
||||||
|
int aligned_max_size;
|
||||||
|
int aligned_arg_size;
|
||||||
|
rlim_t max_data_size;
|
||||||
|
|
||||||
|
if ((result=init_pthread_lock(&(g_free_queue.lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"init_pthread_lock fail, errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
aligned_min_size = MEM_ALIGN(min_buff_size);
|
||||||
|
aligned_max_size = MEM_ALIGN(max_buff_size);
|
||||||
|
aligned_arg_size = MEM_ALIGN(arg_size);
|
||||||
|
block_size = ALIGNED_TASK_INFO_SIZE + aligned_arg_size;
|
||||||
|
alloc_size = block_size * max_connections;
|
||||||
|
if (aligned_max_size > aligned_min_size)
|
||||||
|
{
|
||||||
|
total_size = alloc_size;
|
||||||
|
g_free_queue.malloc_whole_block = false;
|
||||||
|
max_data_size = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct rlimit rlimit_data;
|
||||||
|
|
||||||
|
if (getrlimit(RLIMIT_DATA, &rlimit_data) < 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call getrlimit fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : EPERM;
|
||||||
|
}
|
||||||
|
if (rlimit_data.rlim_cur == RLIM_INFINITY)
|
||||||
|
{
|
||||||
|
max_data_size = 256 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
max_data_size = rlimit_data.rlim_cur;
|
||||||
|
if (max_data_size > 256 * 1024 * 1024)
|
||||||
|
{
|
||||||
|
max_data_size = 256 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_data_size >= (int64_t)(block_size + aligned_min_size) *
|
||||||
|
(int64_t)max_connections)
|
||||||
|
{
|
||||||
|
total_size = alloc_size + (int64_t)aligned_min_size *
|
||||||
|
max_connections;
|
||||||
|
g_free_queue.malloc_whole_block = true;
|
||||||
|
block_size += aligned_min_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
total_size = alloc_size;
|
||||||
|
g_free_queue.malloc_whole_block = false;
|
||||||
|
max_data_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"max_connections: %d, min_buff_size: %d, max_buff_size: %d, " \
|
||||||
|
"block_size: %d, arg_size: %d, max_data_size: %d, " \
|
||||||
|
"total_size: "INT64_PRINTF_FORMAT, __LINE__, \
|
||||||
|
max_connections, aligned_min_size, aligned_max_size, \
|
||||||
|
block_size, aligned_arg_size, (int)max_data_size, total_size);
|
||||||
|
|
||||||
|
g_free_queue.max_connections = max_connections;
|
||||||
|
g_free_queue.min_buff_size = aligned_min_size;
|
||||||
|
g_free_queue.max_buff_size = aligned_max_size;
|
||||||
|
g_free_queue.arg_size = aligned_arg_size;
|
||||||
|
|
||||||
|
if ((!g_free_queue.malloc_whole_block) || \
|
||||||
|
(total_size <= max_data_size))
|
||||||
|
{
|
||||||
|
loop_count = 1;
|
||||||
|
mpool = malloc_mpool(block_size, total_size);
|
||||||
|
if (mpool == NULL)
|
||||||
|
{
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
g_mpool = mpool;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct mpool_chain *previous_mpool;
|
||||||
|
int remain_count;
|
||||||
|
int alloc_once;
|
||||||
|
int current_count;
|
||||||
|
int current_alloc_size;
|
||||||
|
|
||||||
|
mpool = NULL;
|
||||||
|
previous_mpool = NULL;
|
||||||
|
loop_count = 0;
|
||||||
|
remain_count = max_connections;
|
||||||
|
alloc_once = max_data_size / block_size;
|
||||||
|
while (remain_count > 0)
|
||||||
|
{
|
||||||
|
current_count = (remain_count > alloc_once) ? \
|
||||||
|
alloc_once : remain_count;
|
||||||
|
current_alloc_size = block_size * current_count;
|
||||||
|
mpool = malloc_mpool(block_size, current_alloc_size);
|
||||||
|
if (mpool == NULL)
|
||||||
|
{
|
||||||
|
free_queue_destroy();
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previous_mpool == NULL)
|
||||||
|
{
|
||||||
|
g_mpool = mpool;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previous_mpool->next = mpool;
|
||||||
|
previous_mpool->last_block->next = mpool->blocks;
|
||||||
|
}
|
||||||
|
previous_mpool = mpool;
|
||||||
|
|
||||||
|
remain_count -= current_count;
|
||||||
|
loop_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"alloc_once: %d", __LINE__, alloc_once);
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc task info as whole: %d, malloc loop count: %d", \
|
||||||
|
__LINE__, g_free_queue.malloc_whole_block, loop_count);
|
||||||
|
|
||||||
|
if (g_mpool != NULL)
|
||||||
|
{
|
||||||
|
g_free_queue.head = g_mpool->blocks;
|
||||||
|
g_free_queue.tail = mpool->last_block;
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
int task_count = 0;
|
||||||
|
|
||||||
|
pTask = g_free_queue.head;
|
||||||
|
while (pTask != NULL)
|
||||||
|
{
|
||||||
|
task_count++;
|
||||||
|
pTask = pTask->next;
|
||||||
|
}
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"task count: %d", __LINE__, task_count);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_queue_destroy()
|
||||||
|
{
|
||||||
|
struct mpool_chain *mpool;
|
||||||
|
struct mpool_chain *mp;
|
||||||
|
|
||||||
|
if (g_mpool == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_free_queue.malloc_whole_block)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *pCharEnd;
|
||||||
|
int block_size;
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
|
||||||
|
block_size = ALIGNED_TASK_INFO_SIZE + g_free_queue.arg_size;
|
||||||
|
pCharEnd = ((char *)g_mpool->blocks) + block_size * \
|
||||||
|
g_free_queue.max_connections;
|
||||||
|
for (p=(char *)g_mpool->blocks; p<pCharEnd; p += block_size)
|
||||||
|
{
|
||||||
|
pTask = (struct fast_task_info *)p;
|
||||||
|
if (pTask->data != NULL)
|
||||||
|
{
|
||||||
|
free(pTask->data);
|
||||||
|
pTask->data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpool = g_mpool;
|
||||||
|
while (mpool != NULL)
|
||||||
|
{
|
||||||
|
mp = mpool;
|
||||||
|
mpool = mpool->next;
|
||||||
|
|
||||||
|
free(mp->blocks);
|
||||||
|
free(mp);
|
||||||
|
}
|
||||||
|
g_mpool = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&(g_free_queue.lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fast_task_info *free_queue_pop()
|
||||||
|
{
|
||||||
|
return task_queue_pop(&g_free_queue);;
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_push(struct fast_task_info *pTask)
|
||||||
|
{
|
||||||
|
char *new_buff;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
*(pTask->client_ip) = '\0';
|
||||||
|
pTask->length = 0;
|
||||||
|
pTask->offset = 0;
|
||||||
|
pTask->req_count = 0;
|
||||||
|
|
||||||
|
if (pTask->size > g_free_queue.min_buff_size) //need thrink
|
||||||
|
{
|
||||||
|
new_buff = (char *)malloc(g_free_queue.min_buff_size);
|
||||||
|
if (new_buff == NULL)
|
||||||
|
{
|
||||||
|
logWarning("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, g_free_queue.min_buff_size, \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(pTask->data);
|
||||||
|
pTask->size = g_free_queue.min_buff_size;
|
||||||
|
pTask->data = new_buff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&g_free_queue.lock)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask->next = g_free_queue.head;
|
||||||
|
g_free_queue.head = pTask;
|
||||||
|
if (g_free_queue.tail == NULL)
|
||||||
|
{
|
||||||
|
g_free_queue.tail = pTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&g_free_queue.lock)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int free_queue_count()
|
||||||
|
{
|
||||||
|
return task_queue_count(&g_free_queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
int task_queue_push(struct fast_task_queue *pQueue, \
|
||||||
|
struct fast_task_info *pTask)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask->next = NULL;
|
||||||
|
if (pQueue->tail == NULL)
|
||||||
|
{
|
||||||
|
pQueue->head = pTask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pQueue->tail->next = pTask;
|
||||||
|
}
|
||||||
|
pQueue->tail = pTask;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue)
|
||||||
|
{
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask = pQueue->head;
|
||||||
|
if (pTask != NULL)
|
||||||
|
{
|
||||||
|
pQueue->head = pTask->next;
|
||||||
|
if (pQueue->head == NULL)
|
||||||
|
{
|
||||||
|
pQueue->tail = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int task_queue_count(struct fast_task_queue *pQueue)
|
||||||
|
{
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
int count;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
pTask = pQueue->head;
|
||||||
|
while (pTask != NULL)
|
||||||
|
{
|
||||||
|
pTask = pTask->next;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//fast_task_queue.h
|
||||||
|
|
||||||
|
#ifndef _FAST_TASK_QUEUE_H
|
||||||
|
#define _FAST_TASK_QUEUE_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
#include "ioevent.h"
|
||||||
|
#include "fast_timer.h"
|
||||||
|
|
||||||
|
struct fast_task_info;
|
||||||
|
|
||||||
|
typedef int (*TaskFinishCallBack) (struct fast_task_info *pTask);
|
||||||
|
typedef void (*TaskCleanUpCallBack) (struct fast_task_info *pTask);
|
||||||
|
|
||||||
|
typedef void (*IOEventCallback) (int sock, short event, void *arg);
|
||||||
|
|
||||||
|
typedef struct ioevent_entry
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
FastTimerEntry timer;
|
||||||
|
IOEventCallback callback;
|
||||||
|
} IOEventEntry;
|
||||||
|
|
||||||
|
struct nio_thread_data
|
||||||
|
{
|
||||||
|
struct ioevent_puller ev_puller;
|
||||||
|
struct fast_timer timer;
|
||||||
|
int pipe_fds[2];
|
||||||
|
struct fast_task_info *deleted_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fast_task_info
|
||||||
|
{
|
||||||
|
IOEventEntry event;
|
||||||
|
char client_ip[IP_ADDRESS_SIZE];
|
||||||
|
void *arg; //extra argument pointer
|
||||||
|
char *data; //buffer for write or recv
|
||||||
|
int size; //alloc size
|
||||||
|
int length; //data length
|
||||||
|
int offset; //current offset
|
||||||
|
int req_count; //request count
|
||||||
|
TaskFinishCallBack finish_callback;
|
||||||
|
struct nio_thread_data *thread_data;
|
||||||
|
struct fast_task_info *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fast_task_queue
|
||||||
|
{
|
||||||
|
struct fast_task_info *head;
|
||||||
|
struct fast_task_info *tail;
|
||||||
|
pthread_mutex_t lock;
|
||||||
|
int max_connections;
|
||||||
|
int min_buff_size;
|
||||||
|
int max_buff_size;
|
||||||
|
int arg_size;
|
||||||
|
bool malloc_whole_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int free_queue_init(const int max_connections, const int min_buff_size, \
|
||||||
|
const int max_buff_size, const int arg_size);
|
||||||
|
|
||||||
|
void free_queue_destroy();
|
||||||
|
|
||||||
|
int free_queue_push(struct fast_task_info *pTask);
|
||||||
|
struct fast_task_info *free_queue_pop();
|
||||||
|
int free_queue_count();
|
||||||
|
|
||||||
|
|
||||||
|
int task_queue_init(struct fast_task_queue *pQueue);
|
||||||
|
int task_queue_push(struct fast_task_queue *pQueue, \
|
||||||
|
struct fast_task_info *pTask);
|
||||||
|
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue);
|
||||||
|
int task_queue_count(struct fast_task_queue *pQueue);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,175 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "logger.h"
|
||||||
|
#include "fast_timer.h"
|
||||||
|
|
||||||
|
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||||
|
const int64_t current_time)
|
||||||
|
{
|
||||||
|
int bytes;
|
||||||
|
if (slot_count <= 0 || current_time <= 0) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer->slot_count = slot_count;
|
||||||
|
timer->base_time = current_time; //base time for slot 0
|
||||||
|
timer->current_time = current_time;
|
||||||
|
bytes = sizeof(FastTimerSlot) * slot_count;
|
||||||
|
timer->slots = (FastTimerSlot *)malloc(bytes);
|
||||||
|
if (timer->slots == NULL) {
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
memset(timer->slots, 0, bytes);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fast_timer_destroy(FastTimer *timer)
|
||||||
|
{
|
||||||
|
if (timer->slots != NULL) {
|
||||||
|
free(timer->slots);
|
||||||
|
timer->slots = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TIMER_GET_SLOT_INDEX(timer, expires) \
|
||||||
|
(((expires) - timer->base_time) % timer->slot_count)
|
||||||
|
|
||||||
|
#define TIMER_GET_SLOT_POINTER(timer, expires) \
|
||||||
|
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
|
||||||
|
|
||||||
|
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
|
||||||
|
{
|
||||||
|
FastTimerSlot *slot;
|
||||||
|
|
||||||
|
slot = TIMER_GET_SLOT_POINTER(timer, entry->expires >
|
||||||
|
timer->current_time ? entry->expires : timer->current_time);
|
||||||
|
entry->next = slot->head.next;
|
||||||
|
if (slot->head.next != NULL) {
|
||||||
|
slot->head.next->prev = entry;
|
||||||
|
}
|
||||||
|
entry->prev = &slot->head;
|
||||||
|
slot->head.next = entry;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||||
|
const int64_t new_expires)
|
||||||
|
{
|
||||||
|
if (new_expires == entry->expires) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_expires < entry->expires) {
|
||||||
|
fast_timer_remove(timer, entry);
|
||||||
|
entry->expires = new_expires;
|
||||||
|
return fast_timer_add(timer, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
|
||||||
|
TIMER_GET_SLOT_INDEX(timer, entry->expires);
|
||||||
|
entry->expires = new_expires; //lazy move
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
|
||||||
|
{
|
||||||
|
if (entry->prev == NULL) {
|
||||||
|
return ENOENT; //already removed
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry->next != NULL) {
|
||||||
|
entry->next->prev = entry->prev;
|
||||||
|
entry->prev->next = entry->next;
|
||||||
|
entry->next = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entry->prev->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry->prev = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
|
||||||
|
{
|
||||||
|
if (timer->current_time >= current_time) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
||||||
|
FastTimerEntry *head)
|
||||||
|
{
|
||||||
|
FastTimerSlot *slot;
|
||||||
|
FastTimerEntry *entry;
|
||||||
|
FastTimerEntry *first;
|
||||||
|
FastTimerEntry *last;
|
||||||
|
FastTimerEntry *tail;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
head->prev = NULL;
|
||||||
|
head->next = NULL;
|
||||||
|
if (timer->current_time >= current_time) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
first = NULL;
|
||||||
|
last = NULL;
|
||||||
|
tail = head;
|
||||||
|
count = 0;
|
||||||
|
while (timer->current_time < current_time) {
|
||||||
|
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
|
||||||
|
entry = slot->head.next;
|
||||||
|
while (entry != NULL) {
|
||||||
|
if (entry->expires >= current_time) { //not expired
|
||||||
|
if (first != NULL) {
|
||||||
|
first->prev->next = entry;
|
||||||
|
entry->prev = first->prev;
|
||||||
|
|
||||||
|
tail->next = first;
|
||||||
|
first->prev = tail;
|
||||||
|
tail = last;
|
||||||
|
first = NULL;
|
||||||
|
}
|
||||||
|
if (entry->rehash) {
|
||||||
|
last = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
|
||||||
|
last->rehash = false;
|
||||||
|
fast_timer_remove(timer, last);
|
||||||
|
fast_timer_add(timer, last);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
count++;
|
||||||
|
if (first == NULL) {
|
||||||
|
first = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first != NULL) {
|
||||||
|
first->prev->next = NULL;
|
||||||
|
|
||||||
|
tail->next = first;
|
||||||
|
first->prev = tail;
|
||||||
|
tail = last;
|
||||||
|
first = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
tail->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef __FAST_TIMER_H__
|
||||||
|
#define __FAST_TIMER_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
typedef struct fast_timer_entry {
|
||||||
|
int64_t expires;
|
||||||
|
void *data;
|
||||||
|
struct fast_timer_entry *prev;
|
||||||
|
struct fast_timer_entry *next;
|
||||||
|
bool rehash;
|
||||||
|
} FastTimerEntry;
|
||||||
|
|
||||||
|
typedef struct fast_timer_slot {
|
||||||
|
struct fast_timer_entry head;
|
||||||
|
} FastTimerSlot;
|
||||||
|
|
||||||
|
typedef struct fast_timer {
|
||||||
|
int slot_count; //time wheel slot count
|
||||||
|
int64_t base_time; //base time for slot 0
|
||||||
|
int64_t current_time;
|
||||||
|
FastTimerSlot *slots;
|
||||||
|
} FastTimer;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int fast_timer_init(FastTimer *timer, const int slot_count,
|
||||||
|
const int64_t current_time);
|
||||||
|
void fast_timer_destroy(FastTimer *timer);
|
||||||
|
|
||||||
|
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry);
|
||||||
|
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry);
|
||||||
|
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
|
||||||
|
const int64_t new_expires);
|
||||||
|
|
||||||
|
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time);
|
||||||
|
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
|
||||||
|
FastTimerEntry *head);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,381 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef _HASH_H_
|
||||||
|
#define _HASH_H_
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CRC32_XINIT 0xFFFFFFFF /* initial value */
|
||||||
|
#define CRC32_XOROT 0xFFFFFFFF /* final xor value */
|
||||||
|
|
||||||
|
typedef int (*HashFunc) (const void *key, const int key_len);
|
||||||
|
|
||||||
|
#ifdef HASH_STORE_HASH_CODE
|
||||||
|
#define HASH_CODE(pHash, hash_data) hash_data->hash_code
|
||||||
|
#else
|
||||||
|
#define HASH_CODE(pHash, hash_data) ((unsigned int)pHash->hash_func( \
|
||||||
|
hash_data->key, hash_data->key_len))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CALC_NODE_MALLOC_BYTES(key_len, value_size) \
|
||||||
|
sizeof(HashData) + key_len + value_size
|
||||||
|
|
||||||
|
#define FREE_HASH_DATA(pHash, hash_data) \
|
||||||
|
pHash->item_count--; \
|
||||||
|
pHash->bytes_used -= CALC_NODE_MALLOC_BYTES(hash_data->key_len, \
|
||||||
|
hash_data->malloc_value_size); \
|
||||||
|
free(hash_data);
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct tagHashData
|
||||||
|
{
|
||||||
|
int key_len;
|
||||||
|
int value_len;
|
||||||
|
int malloc_value_size;
|
||||||
|
|
||||||
|
#ifdef HASH_STORE_HASH_CODE
|
||||||
|
unsigned int hash_code;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char *value;
|
||||||
|
struct tagHashData *next;
|
||||||
|
char key[0];
|
||||||
|
} HashData;
|
||||||
|
|
||||||
|
typedef int64_t (*ConvertValueFunc)(const HashData *old_data, const int inc,
|
||||||
|
char *new_value, int *new_value_len, void *arg);
|
||||||
|
|
||||||
|
typedef struct tagHashArray
|
||||||
|
{
|
||||||
|
HashData **buckets;
|
||||||
|
HashFunc hash_func;
|
||||||
|
int item_count;
|
||||||
|
unsigned int *capacity;
|
||||||
|
double load_factor;
|
||||||
|
int64_t max_bytes;
|
||||||
|
int64_t bytes_used;
|
||||||
|
bool is_malloc_capacity;
|
||||||
|
bool is_malloc_value;
|
||||||
|
unsigned int lock_count;
|
||||||
|
pthread_mutex_t *locks;
|
||||||
|
} HashArray;
|
||||||
|
|
||||||
|
typedef struct tagHashStat
|
||||||
|
{
|
||||||
|
unsigned int capacity;
|
||||||
|
int item_count;
|
||||||
|
int bucket_used;
|
||||||
|
double bucket_avg_length;
|
||||||
|
int bucket_max_length;
|
||||||
|
} HashStat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash walk function
|
||||||
|
* parameters:
|
||||||
|
* index: item index based 0
|
||||||
|
* data: hash data, including key and value
|
||||||
|
* args: passed by hash_walk function
|
||||||
|
* return 0 for success, != 0 for error
|
||||||
|
*/
|
||||||
|
typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
|
||||||
|
|
||||||
|
#define hash_init(pHash, hash_func, capacity, load_factor) \
|
||||||
|
hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
|
||||||
|
|
||||||
|
#define hash_insert(pHash, key, key_len, value) \
|
||||||
|
hash_insert_ex(pHash, key, key_len, value, 0, true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash init function
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* hash_func: hash function
|
||||||
|
* capacity: init capacity
|
||||||
|
* load_factor: hash load factor, such as 0.75
|
||||||
|
* max_bytes: max memory can be used (bytes)
|
||||||
|
* bMallocValue: if need malloc value buffer
|
||||||
|
* return 0 for success, != 0 for error
|
||||||
|
*/
|
||||||
|
int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
|
||||||
|
const unsigned int capacity, const double load_factor, \
|
||||||
|
const int64_t max_bytes, const bool bMallocValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set hash locks function
|
||||||
|
* parameters:
|
||||||
|
* lock_count: the lock count
|
||||||
|
* return 0 for success, != 0 for error
|
||||||
|
*/
|
||||||
|
int hash_set_locks(HashArray *pHash, const int lock_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert the value
|
||||||
|
* parameters:
|
||||||
|
* HashData: the old hash data
|
||||||
|
* inc: the increasement value
|
||||||
|
* new_value: return the new value
|
||||||
|
* new_value_len: return the length of the new value
|
||||||
|
* arg: the user data
|
||||||
|
* return the number after increasement
|
||||||
|
*/
|
||||||
|
int64_t hash_inc_value(const HashData *old_data, const int inc,
|
||||||
|
char *new_value, int *new_value_len, void *arg);
|
||||||
|
|
||||||
|
#define hash_inc(pHash, key, key_len, inc, value, value_len) \
|
||||||
|
hash_inc_ex(pHash, key, key_len, inc, value, value_len, \
|
||||||
|
hash_inc_value, NULL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* atomic increase value
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* key: the key to insert
|
||||||
|
* key_len: length of th key
|
||||||
|
* inc: the increasement value
|
||||||
|
* value: return the new value
|
||||||
|
* value_len: return the length of the new value
|
||||||
|
* convert_func: the convert function
|
||||||
|
* arg: the arg to convert function
|
||||||
|
* return 0 for success, != 0 for error (errno)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
|
||||||
|
const int inc, char *value, int *value_len,
|
||||||
|
ConvertValueFunc convert_func, void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash destroy function
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* return none
|
||||||
|
*/
|
||||||
|
void hash_destroy(HashArray *pHash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash insert key
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* key: the key to insert
|
||||||
|
* key_len: length of th key
|
||||||
|
* value: the value
|
||||||
|
* value_len: length of the value
|
||||||
|
* needLock: if need lock
|
||||||
|
* return >= 0 for success, 0 for key already exist (update),
|
||||||
|
* 1 for new key (insert), < 0 for error
|
||||||
|
*/
|
||||||
|
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
|
||||||
|
void *value, const int value_len, const bool needLock);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash find key
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* key: the key to find
|
||||||
|
* key_len: length of th key
|
||||||
|
* return user data, return NULL when the key not exist
|
||||||
|
*/
|
||||||
|
void *hash_find(HashArray *pHash, const void *key, const int key_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash find key
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* key: the key to find
|
||||||
|
* key_len: length of th key
|
||||||
|
* return hash data, return NULL when the key not exist
|
||||||
|
*/
|
||||||
|
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash get the value of the key
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* key: the key to find
|
||||||
|
* key_len: length of th key
|
||||||
|
* value: store the value
|
||||||
|
* value_len: input for the max size of the value
|
||||||
|
* output for the length fo the value
|
||||||
|
* return 0 for success, != 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_get(HashArray *pHash, const void *key, const int key_len,
|
||||||
|
void *value, int *value_len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash partial set
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* key: the key to insert
|
||||||
|
* key_len: length of th key
|
||||||
|
* value: the value
|
||||||
|
* offset: the offset of existed value
|
||||||
|
* value_len: length of the value
|
||||||
|
* return 0 for success, != 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
|
||||||
|
const char *value, const int offset, const int value_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash delete key
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* key: the key to delete
|
||||||
|
* key_len: length of th key
|
||||||
|
* return 0 for success, != 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_delete(HashArray *pHash, const void *key, const int key_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash walk (iterator)
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* walkFunc: walk (interator) function
|
||||||
|
* args: extra args which will be passed to walkFunc
|
||||||
|
* return 0 for success, != 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get hash item count
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* return item count
|
||||||
|
*/
|
||||||
|
int hash_count(HashArray *pHash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash best optimize
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* suggest_capacity: suggest init capacity for speed
|
||||||
|
* return >0 for success, < 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_best_op(HashArray *pHash, const int suggest_capacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash stat
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* pStat: return stat info
|
||||||
|
* stat_by_lens: return stats array by bucket length
|
||||||
|
* stat_by_lens[0] empty buckets count
|
||||||
|
* stat_by_lens[1] contain 1 key buckets count
|
||||||
|
* stat_by_lens[2] contain 2 key buckets count, etc
|
||||||
|
* stat_size: stats array size (contain max elments)
|
||||||
|
* return 0 for success, != 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_stat(HashArray *pHash, HashStat *pStat, \
|
||||||
|
int *stat_by_lens, const int stat_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print hash stat info
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* return none
|
||||||
|
*/
|
||||||
|
void hash_stat_print(HashArray *pHash);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lock the bucket of hash table
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* bucket_index: the index of bucket
|
||||||
|
* return 0 for success, != 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unlock the bucket of hash table
|
||||||
|
* parameters:
|
||||||
|
* pHash: the hash table
|
||||||
|
* bucket_index: the index of bucket
|
||||||
|
* return 0 for success, != 0 fail (errno)
|
||||||
|
*/
|
||||||
|
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
|
||||||
|
|
||||||
|
int RSHash(const void *key, const int key_len);
|
||||||
|
|
||||||
|
int JSHash(const void *key, const int key_len);
|
||||||
|
int JSHash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int PJWHash(const void *key, const int key_len);
|
||||||
|
int PJWHash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int ELFHash(const void *key, const int key_len);
|
||||||
|
int ELFHash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int BKDRHash(const void *key, const int key_len);
|
||||||
|
int BKDRHash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int SDBMHash(const void *key, const int key_len);
|
||||||
|
int SDBMHash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int Time33Hash(const void *key, const int key_len);
|
||||||
|
int Time33Hash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int DJBHash(const void *key, const int key_len);
|
||||||
|
int DJBHash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int APHash(const void *key, const int key_len);
|
||||||
|
int APHash_ex(const void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int calc_hashnr (const void* key, const int key_len);
|
||||||
|
|
||||||
|
int calc_hashnr1(const void* key, const int key_len);
|
||||||
|
int calc_hashnr1_ex(const void* key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int simple_hash(const void* key, const int key_len);
|
||||||
|
int simple_hash_ex(const void* key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
int CRC32(void *key, const int key_len);
|
||||||
|
int CRC32_ex(void *key, const int key_len, \
|
||||||
|
const int init_value);
|
||||||
|
|
||||||
|
#define CRC32_FINAL(crc) (crc ^ CRC32_XOROT)
|
||||||
|
|
||||||
|
#define INIT_HASH_CODES4(hash_codes) \
|
||||||
|
hash_codes[0] = CRC32_XINIT; \
|
||||||
|
hash_codes[1] = 0; \
|
||||||
|
hash_codes[2] = 0; \
|
||||||
|
hash_codes[3] = 0; \
|
||||||
|
|
||||||
|
#define CALC_HASH_CODES4(buff, buff_len, hash_codes) \
|
||||||
|
hash_codes[0] = CRC32_ex(buff, buff_len, hash_codes[0]); \
|
||||||
|
hash_codes[1] = ELFHash_ex(buff, buff_len, hash_codes[1]); \
|
||||||
|
hash_codes[2] = simple_hash_ex(buff, buff_len, hash_codes[2]); \
|
||||||
|
hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \
|
||||||
|
|
||||||
|
|
||||||
|
#define FINISH_HASH_CODES4(hash_codes) \
|
||||||
|
hash_codes[0] = CRC32_FINAL(hash_codes[0]); \
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,302 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "sockopt.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "shared_func.h"
|
||||||
|
|
||||||
|
int get_url_content(const char *url, const int connect_timeout, \
|
||||||
|
const int network_timeout, int *http_status, \
|
||||||
|
char **content, int *content_len, char *error_info)
|
||||||
|
{
|
||||||
|
char domain_name[256];
|
||||||
|
char ip_addr[IP_ADDRESS_SIZE];
|
||||||
|
char out_buff[4096];
|
||||||
|
int domain_len;
|
||||||
|
int url_len;
|
||||||
|
int out_len;
|
||||||
|
int alloc_size;
|
||||||
|
int recv_bytes;
|
||||||
|
int result;
|
||||||
|
int sock;
|
||||||
|
int port;
|
||||||
|
const char *pDomain;
|
||||||
|
const char *pContent;
|
||||||
|
const char *pURI;
|
||||||
|
char *pPort;
|
||||||
|
char *pSpace;
|
||||||
|
|
||||||
|
*http_status = 0;
|
||||||
|
*content_len = 0;
|
||||||
|
*content = NULL;
|
||||||
|
|
||||||
|
url_len = strlen(url);
|
||||||
|
if (url_len <= 7 || strncasecmp(url, "http://", 7) != 0)
|
||||||
|
{
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"invalid url.", __LINE__);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pDomain = url + 7;
|
||||||
|
pURI = strchr(pDomain, '/');
|
||||||
|
if (pURI == NULL)
|
||||||
|
{
|
||||||
|
domain_len = url_len - 7;
|
||||||
|
pURI = "/";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
domain_len = pURI - pDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain_len >= sizeof(domain_name))
|
||||||
|
{
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"domain is too large, exceed %d.", \
|
||||||
|
__LINE__, (int)sizeof(domain_name));
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(domain_name, pDomain, domain_len);
|
||||||
|
*(domain_name + domain_len) = '\0';
|
||||||
|
pPort = strchr(domain_name, ':');
|
||||||
|
if (pPort == NULL)
|
||||||
|
{
|
||||||
|
port = 80;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*pPort = '\0';
|
||||||
|
port = atoi(pPort + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getIpaddrByName(domain_name, ip_addr, \
|
||||||
|
sizeof(ip_addr)) == INADDR_NONE)
|
||||||
|
{
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"resolve domain \"%s\" fail.", \
|
||||||
|
__LINE__, domain_name);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if(sock < 0)
|
||||||
|
{
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"socket create failed, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=connectserverbyip_nb_auto(sock, ip_addr, port, \
|
||||||
|
connect_timeout)) != 0)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"connect to %s:%d fail, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, domain_name, \
|
||||||
|
port, result, STRERROR(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_len = snprintf(out_buff, sizeof(out_buff), \
|
||||||
|
"GET %s HTTP/1.0\r\n" \
|
||||||
|
"Host: %s:%d\r\n" \
|
||||||
|
"Connection: close\r\n" \
|
||||||
|
"\r\n", pURI, domain_name, port);
|
||||||
|
if ((result=tcpsenddata(sock, out_buff, out_len, network_timeout)) != 0)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"send data to %s:%d fail, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, domain_name, \
|
||||||
|
port, result, STRERROR(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc_size = 64 * 1024;
|
||||||
|
*content = (char *)malloc(alloc_size + 1);
|
||||||
|
if (*content == NULL)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes fail, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, alloc_size + 1, \
|
||||||
|
result, STRERROR(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
recv_bytes = alloc_size - *content_len;
|
||||||
|
if (recv_bytes <= 0)
|
||||||
|
{
|
||||||
|
alloc_size *= 2;
|
||||||
|
*content = (char *)realloc(*content, alloc_size + 1);
|
||||||
|
if (*content == NULL)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"realloc %d bytes fail, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, \
|
||||||
|
alloc_size + 1, \
|
||||||
|
result, STRERROR(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv_bytes = alloc_size - *content_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = tcprecvdata_ex(sock, *content + *content_len, \
|
||||||
|
recv_bytes, network_timeout, &recv_bytes);
|
||||||
|
|
||||||
|
*content_len += recv_bytes;
|
||||||
|
} while (result == 0);
|
||||||
|
|
||||||
|
if (result != ENOTCONN)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
free(*content);
|
||||||
|
*content = NULL;
|
||||||
|
*content_len = 0;
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"recv data from %s:%d fail, errno: %d, " \
|
||||||
|
"error info: %s", __LINE__, domain_name, \
|
||||||
|
port, result, STRERROR(result));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(*content + *content_len) = '\0';
|
||||||
|
pContent = strstr(*content, "\r\n\r\n");
|
||||||
|
if (pContent == NULL)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
free(*content);
|
||||||
|
*content = NULL;
|
||||||
|
*content_len = 0;
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"response data from %s:%d is invalid", \
|
||||||
|
__LINE__, domain_name, port);
|
||||||
|
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pContent += 4;
|
||||||
|
pSpace = strchr(*content, ' ');
|
||||||
|
if (pSpace == NULL || pSpace >= pContent)
|
||||||
|
{
|
||||||
|
close(sock);
|
||||||
|
free(*content);
|
||||||
|
*content = NULL;
|
||||||
|
*content_len = 0;
|
||||||
|
|
||||||
|
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
||||||
|
"response data from %s:%d is invalid", \
|
||||||
|
__LINE__, domain_name, port);
|
||||||
|
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*http_status = atoi(pSpace + 1);
|
||||||
|
*content_len -= pContent - *content;
|
||||||
|
memcpy(*content, pContent, *content_len);
|
||||||
|
*(*content + *content_len) = '\0';
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
*error_info = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int http_parse_query(char *url, KeyValuePair *params, const int max_count)
|
||||||
|
{
|
||||||
|
KeyValuePair *pCurrent;
|
||||||
|
KeyValuePair *pEnd;
|
||||||
|
char *pParamStart;
|
||||||
|
char *p;
|
||||||
|
char *pStrEnd;
|
||||||
|
int value_len;
|
||||||
|
|
||||||
|
pParamStart = strchr(url, '?');
|
||||||
|
if (pParamStart == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pParamStart = '\0';
|
||||||
|
|
||||||
|
pEnd = params + max_count;
|
||||||
|
pCurrent = params;
|
||||||
|
p = pParamStart + 1;
|
||||||
|
while (p != NULL && *p != '\0')
|
||||||
|
{
|
||||||
|
if (pCurrent >= pEnd)
|
||||||
|
{
|
||||||
|
return pCurrent - params;
|
||||||
|
}
|
||||||
|
|
||||||
|
pCurrent->key = p;
|
||||||
|
pStrEnd = strchr(p, '&');
|
||||||
|
if (pStrEnd == NULL)
|
||||||
|
{
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*pStrEnd = '\0';
|
||||||
|
p = pStrEnd + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pStrEnd = strchr(pCurrent->key, '=');
|
||||||
|
if (pStrEnd == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pStrEnd = '\0';
|
||||||
|
pCurrent->value = pStrEnd + 1;
|
||||||
|
if (*pCurrent->key == '\0')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
urldecode(pCurrent->value, strlen(pCurrent->value), \
|
||||||
|
pCurrent->value, &value_len);
|
||||||
|
pCurrent++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pCurrent - params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef _HTTP_FUNC_H
|
||||||
|
#define _HTTP_FUNC_H
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
get content from url
|
||||||
|
params:
|
||||||
|
url: the url to fetch, must start as: "http://"
|
||||||
|
connect_timeout: connect timeout (seconds)
|
||||||
|
network_timeout: network timeout (seconds)
|
||||||
|
http_status: return http status code, 200 for Ok
|
||||||
|
content: return the content (HTTP body only, not including HTTP header),
|
||||||
|
*content should be freed by caller
|
||||||
|
content_len: return content length (bytes)
|
||||||
|
return: 0 for success, != 0 for error
|
||||||
|
**/
|
||||||
|
int get_url_content(const char *url, const int connect_timeout, \
|
||||||
|
const int network_timeout, int *http_status, \
|
||||||
|
char **content, int *content_len, char *error_info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
parse url
|
||||||
|
params:
|
||||||
|
url: the url to parse
|
||||||
|
params: params array to store param and it's value
|
||||||
|
max_count: max param count
|
||||||
|
return: param count
|
||||||
|
**/
|
||||||
|
int http_parse_query(char *url, KeyValuePair *params, const int max_count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,784 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//ini_file_reader.c
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include "shared_func.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "http_func.h"
|
||||||
|
#include "ini_file_reader.h"
|
||||||
|
|
||||||
|
#define _LINE_BUFFER_SIZE 512
|
||||||
|
#define _ALLOC_ITEMS_ONCE 8
|
||||||
|
|
||||||
|
static int iniDoLoadFromFile(const char *szFilename, \
|
||||||
|
IniContext *pContext);
|
||||||
|
static int iniDoLoadItemsFromBuffer(char *content, \
|
||||||
|
IniContext *pContext);
|
||||||
|
|
||||||
|
static int iniCompareByItemName(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
return strcmp(((IniItem *)p1)->name, ((IniItem *)p2)->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iniInitContext(IniContext *pContext)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
memset(pContext, 0, sizeof(IniContext));
|
||||||
|
pContext->current_section = &pContext->global;
|
||||||
|
if ((result=hash_init(&pContext->sections, PJWHash, 10, 0.75)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"hash_init fail, errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iniSortHashData(const int index, const HashData *data, void *args)
|
||||||
|
{
|
||||||
|
IniSection *pSection;
|
||||||
|
|
||||||
|
pSection = (IniSection *)data->value;
|
||||||
|
if (pSection->count > 1)
|
||||||
|
{
|
||||||
|
qsort(pSection->items, pSection->count, \
|
||||||
|
sizeof(IniItem), iniCompareByItemName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iniSortItems(IniContext *pContext)
|
||||||
|
{
|
||||||
|
if (pContext->global.count > 1)
|
||||||
|
{
|
||||||
|
qsort(pContext->global.items, pContext->global.count, \
|
||||||
|
sizeof(IniItem), iniCompareByItemName);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_walk(&pContext->sections, iniSortHashData, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int iniLoadFromFile(const char *szFilename, IniContext *pContext)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
int len;
|
||||||
|
char *pLast;
|
||||||
|
char full_filename[MAX_PATH_SIZE];
|
||||||
|
|
||||||
|
if ((result=iniInitContext(pContext)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strncasecmp(szFilename, "http://", 7) == 0)
|
||||||
|
{
|
||||||
|
*pContext->config_path = '\0';
|
||||||
|
snprintf(full_filename, sizeof(full_filename),"%s",szFilename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*szFilename == '/')
|
||||||
|
{
|
||||||
|
pLast = strrchr(szFilename, '/');
|
||||||
|
len = pLast - szFilename;
|
||||||
|
if (len >= sizeof(pContext->config_path))
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, "\
|
||||||
|
"the path of the config file: %s is " \
|
||||||
|
"too long!", __LINE__, szFilename);
|
||||||
|
return ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pContext->config_path, szFilename, len);
|
||||||
|
*(pContext->config_path + len) = '\0';
|
||||||
|
snprintf(full_filename, sizeof(full_filename), \
|
||||||
|
"%s", szFilename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memset(pContext->config_path, 0, \
|
||||||
|
sizeof(pContext->config_path));
|
||||||
|
if (getcwd(pContext->config_path, sizeof( \
|
||||||
|
pContext->config_path)) == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"getcwd fail, errno: %d, " \
|
||||||
|
"error info: %s", \
|
||||||
|
__LINE__, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(pContext->config_path);
|
||||||
|
if (len > 0 && pContext->config_path[len - 1] == '/')
|
||||||
|
{
|
||||||
|
len--;
|
||||||
|
*(pContext->config_path + len) = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(full_filename, sizeof(full_filename), \
|
||||||
|
"%s/%s", pContext->config_path, szFilename);
|
||||||
|
|
||||||
|
pLast = strrchr(szFilename, '/');
|
||||||
|
if (pLast != NULL)
|
||||||
|
{
|
||||||
|
int tail_len;
|
||||||
|
|
||||||
|
tail_len = pLast - szFilename;
|
||||||
|
if (len + tail_len >= sizeof( \
|
||||||
|
pContext->config_path))
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, "\
|
||||||
|
"the path of the config " \
|
||||||
|
"file: %s is too long!", \
|
||||||
|
__LINE__, szFilename);
|
||||||
|
return ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pContext->config_path + len, \
|
||||||
|
szFilename, tail_len);
|
||||||
|
len += tail_len;
|
||||||
|
*(pContext->config_path + len) = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iniDoLoadFromFile(full_filename, pContext);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
iniSortItems(pContext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iniFreeContext(pContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iniDoLoadFromFile(const char *szFilename, \
|
||||||
|
IniContext *pContext)
|
||||||
|
{
|
||||||
|
char *content;
|
||||||
|
int result;
|
||||||
|
int http_status;
|
||||||
|
int content_len;
|
||||||
|
int64_t file_size;
|
||||||
|
char error_info[512];
|
||||||
|
|
||||||
|
if (strncasecmp(szFilename, "http://", 7) == 0)
|
||||||
|
{
|
||||||
|
if ((result=get_url_content(szFilename, 10, 60, &http_status, \
|
||||||
|
&content, &content_len, error_info)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"get_url_content fail, " \
|
||||||
|
"url: %s, error info: %s", \
|
||||||
|
__LINE__, szFilename, error_info);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (http_status != 200)
|
||||||
|
{
|
||||||
|
free(content);
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"HTTP status code: %d != 200, url: %s", \
|
||||||
|
__LINE__, http_status, szFilename);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((result=getFileContent(szFilename, &content, \
|
||||||
|
&file_size)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iniDoLoadItemsFromBuffer(content, pContext);
|
||||||
|
free(content);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int iniLoadFromBuffer(char *content, IniContext *pContext)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=iniInitContext(pContext)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iniDoLoadItemsFromBuffer(content, pContext);
|
||||||
|
if (result == 0)
|
||||||
|
{
|
||||||
|
iniSortItems(pContext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iniFreeContext(pContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
|
||||||
|
{
|
||||||
|
IniSection *pSection;
|
||||||
|
IniItem *pItem;
|
||||||
|
char *pLine;
|
||||||
|
char *pLastEnd;
|
||||||
|
char *pEqualChar;
|
||||||
|
char *pIncludeFilename;
|
||||||
|
char full_filename[MAX_PATH_SIZE];
|
||||||
|
int nLineLen;
|
||||||
|
int nNameLen;
|
||||||
|
int nValueLen;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
pLastEnd = content - 1;
|
||||||
|
pSection = pContext->current_section;
|
||||||
|
if (pSection->count > 0)
|
||||||
|
{
|
||||||
|
pItem = pSection->items + pSection->count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pItem = pSection->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pLastEnd != NULL)
|
||||||
|
{
|
||||||
|
pLine = pLastEnd + 1;
|
||||||
|
pLastEnd = strchr(pLine, '\n');
|
||||||
|
if (pLastEnd != NULL)
|
||||||
|
{
|
||||||
|
*pLastEnd = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*pLine == '#' && \
|
||||||
|
strncasecmp(pLine+1, "include", 7) == 0 && \
|
||||||
|
(*(pLine+8) == ' ' || *(pLine+8) == '\t'))
|
||||||
|
{
|
||||||
|
pIncludeFilename = strdup(pLine + 9);
|
||||||
|
if (pIncludeFilename == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"strdup %d bytes fail", __LINE__, \
|
||||||
|
(int)strlen(pLine + 9) + 1);
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
trim(pIncludeFilename);
|
||||||
|
if (strncasecmp(pIncludeFilename, "http://", 7) == 0)
|
||||||
|
{
|
||||||
|
snprintf(full_filename, sizeof(full_filename),\
|
||||||
|
"%s", pIncludeFilename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*pIncludeFilename == '/')
|
||||||
|
{
|
||||||
|
snprintf(full_filename, sizeof(full_filename), \
|
||||||
|
"%s", pIncludeFilename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf(full_filename, sizeof(full_filename), \
|
||||||
|
"%s/%s", pContext->config_path, \
|
||||||
|
pIncludeFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fileExists(full_filename))
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"include file \"%s\" not exists, " \
|
||||||
|
"line: \"%s\"", __LINE__, \
|
||||||
|
pIncludeFilename, pLine);
|
||||||
|
free(pIncludeFilename);
|
||||||
|
result = ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = iniDoLoadFromFile(full_filename, pContext);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
free(pIncludeFilename);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pSection = pContext->current_section;
|
||||||
|
if (pSection->count > 0)
|
||||||
|
{
|
||||||
|
pItem = pSection->items + pSection->count; //must re-asign
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pItem = pSection->items;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pIncludeFilename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
trim(pLine);
|
||||||
|
if (*pLine == '#' || *pLine == '\0')
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nLineLen = strlen(pLine);
|
||||||
|
if (*pLine == '[' && *(pLine + (nLineLen - 1)) == ']') //section
|
||||||
|
{
|
||||||
|
char *section_name;
|
||||||
|
int section_len;
|
||||||
|
|
||||||
|
*(pLine + (nLineLen - 1)) = '\0';
|
||||||
|
section_name = pLine + 1; //skip [
|
||||||
|
|
||||||
|
trim(section_name);
|
||||||
|
if (*section_name == '\0') //global section
|
||||||
|
{
|
||||||
|
pContext->current_section = &pContext->global;
|
||||||
|
pSection = pContext->current_section;
|
||||||
|
if (pSection->count > 0)
|
||||||
|
{
|
||||||
|
pItem = pSection->items + pSection->count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pItem = pSection->items;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
section_len = strlen(section_name);
|
||||||
|
pSection = (IniSection *)hash_find(&pContext->sections,\
|
||||||
|
section_name, section_len);
|
||||||
|
if (pSection == NULL)
|
||||||
|
{
|
||||||
|
pSection = (IniSection *)malloc(sizeof(IniSection));
|
||||||
|
if (pSection == NULL)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, "\
|
||||||
|
"malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, \
|
||||||
|
(int)sizeof(IniSection), \
|
||||||
|
result, STRERROR(result));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(pSection, 0, sizeof(IniSection));
|
||||||
|
result = hash_insert(&pContext->sections, \
|
||||||
|
section_name, section_len, pSection);
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
|
result *= -1;
|
||||||
|
logError("file: "__FILE__", line: %d, "\
|
||||||
|
"insert into hash table fail, "\
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, \
|
||||||
|
STRERROR(result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pContext->current_section = pSection;
|
||||||
|
if (pSection->count > 0)
|
||||||
|
{
|
||||||
|
pItem = pSection->items + pSection->count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pItem = pSection->items;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pEqualChar = strchr(pLine, '=');
|
||||||
|
if (pEqualChar == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nNameLen = pEqualChar - pLine;
|
||||||
|
nValueLen = strlen(pLine) - (nNameLen + 1);
|
||||||
|
if (nNameLen > FAST_INI_ITEM_NAME_LEN)
|
||||||
|
{
|
||||||
|
nNameLen = FAST_INI_ITEM_NAME_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nValueLen > FAST_INI_ITEM_VALUE_LEN)
|
||||||
|
{
|
||||||
|
nValueLen = FAST_INI_ITEM_VALUE_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSection->count >= pSection->alloc_count)
|
||||||
|
{
|
||||||
|
pSection->alloc_count += _ALLOC_ITEMS_ONCE;
|
||||||
|
pSection->items=(IniItem *)realloc(pSection->items,
|
||||||
|
sizeof(IniItem) * pSection->alloc_count);
|
||||||
|
if (pSection->items == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"realloc %d bytes fail", __LINE__, \
|
||||||
|
(int)sizeof(IniItem) * \
|
||||||
|
pSection->alloc_count);
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pItem = pSection->items + pSection->count;
|
||||||
|
memset(pItem, 0, sizeof(IniItem) * \
|
||||||
|
(pSection->alloc_count - pSection->count));
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pItem->name, pLine, nNameLen);
|
||||||
|
memcpy(pItem->value, pEqualChar + 1, nValueLen);
|
||||||
|
|
||||||
|
trim(pItem->name);
|
||||||
|
trim(pItem->value);
|
||||||
|
|
||||||
|
pSection->count++;
|
||||||
|
pItem++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iniFreeHashData(const int index, const HashData *data, void *args)
|
||||||
|
{
|
||||||
|
IniSection *pSection;
|
||||||
|
|
||||||
|
pSection = (IniSection *)data->value;
|
||||||
|
if (pSection == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSection->items != NULL)
|
||||||
|
{
|
||||||
|
free(pSection->items);
|
||||||
|
memset(pSection, 0, sizeof(IniSection));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pSection);
|
||||||
|
((HashData *)data)->value = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iniFreeContext(IniContext *pContext)
|
||||||
|
{
|
||||||
|
if (pContext == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext->global.items != NULL)
|
||||||
|
{
|
||||||
|
free(pContext->global.items);
|
||||||
|
memset(&pContext->global, 0, sizeof(IniSection));
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_walk(&pContext->sections, iniFreeHashData, NULL);
|
||||||
|
hash_destroy(&pContext->sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||||
|
targetItem, pItem, return_val) \
|
||||||
|
if (szSectionName == NULL || *szSectionName == '\0') \
|
||||||
|
{ \
|
||||||
|
pSection = &pContext->global; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
pSection = (IniSection *)hash_find(&pContext->sections, \
|
||||||
|
szSectionName, strlen(szSectionName)); \
|
||||||
|
if (pSection == NULL) \
|
||||||
|
{ \
|
||||||
|
return return_val; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (pSection->count <= 0) \
|
||||||
|
{ \
|
||||||
|
return return_val; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
snprintf(targetItem.name, sizeof(targetItem.name), "%s", szItemName); \
|
||||||
|
pItem = (IniItem *)bsearch(&targetItem, pSection->items, \
|
||||||
|
pSection->count, sizeof(IniItem), iniCompareByItemName);
|
||||||
|
|
||||||
|
|
||||||
|
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext)
|
||||||
|
{
|
||||||
|
IniItem targetItem;
|
||||||
|
IniSection *pSection;
|
||||||
|
IniItem *pItem;
|
||||||
|
|
||||||
|
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||||
|
targetItem, pItem, NULL)
|
||||||
|
|
||||||
|
if (pItem == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return pItem->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const int64_t nDefaultValue)
|
||||||
|
{
|
||||||
|
char *pValue;
|
||||||
|
|
||||||
|
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||||
|
if (pValue == NULL)
|
||||||
|
{
|
||||||
|
return nDefaultValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return strtoll(pValue, NULL, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const int nDefaultValue)
|
||||||
|
{
|
||||||
|
char *pValue;
|
||||||
|
|
||||||
|
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||||
|
if (pValue == NULL)
|
||||||
|
{
|
||||||
|
return nDefaultValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return atoi(pValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const double dbDefaultValue)
|
||||||
|
{
|
||||||
|
char *pValue;
|
||||||
|
|
||||||
|
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||||
|
if (pValue == NULL)
|
||||||
|
{
|
||||||
|
return dbDefaultValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return strtod(pValue, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const bool bDefaultValue)
|
||||||
|
{
|
||||||
|
char *pValue;
|
||||||
|
|
||||||
|
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
|
||||||
|
if (pValue == NULL)
|
||||||
|
{
|
||||||
|
return bDefaultValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return strcasecmp(pValue, "true") == 0 ||
|
||||||
|
strcasecmp(pValue, "yes") == 0 ||
|
||||||
|
strcasecmp(pValue, "on") == 0 ||
|
||||||
|
strcmp(pValue, "1") == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int iniGetValues(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, char **szValues, const int max_values)
|
||||||
|
{
|
||||||
|
IniItem targetItem;
|
||||||
|
IniSection *pSection;
|
||||||
|
IniItem *pFound;
|
||||||
|
IniItem *pItem;
|
||||||
|
IniItem *pItemEnd;
|
||||||
|
char **ppValues;
|
||||||
|
|
||||||
|
if (max_values <= 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||||
|
targetItem, pFound, 0)
|
||||||
|
if (pFound == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ppValues = szValues;
|
||||||
|
*ppValues++ = pFound->value;
|
||||||
|
for (pItem=pFound-1; pItem>=pSection->items; pItem--)
|
||||||
|
{
|
||||||
|
if (strcmp(pItem->name, szItemName) != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ppValues - szValues < max_values)
|
||||||
|
{
|
||||||
|
*ppValues++ = pItem->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pItemEnd = pSection->items + pSection->count;
|
||||||
|
for (pItem=pFound+1; pItem<pItemEnd; pItem++)
|
||||||
|
{
|
||||||
|
if (strcmp(pItem->name, szItemName) != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ppValues - szValues < max_values)
|
||||||
|
{
|
||||||
|
*ppValues++ = pItem->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ppValues - szValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, int *nTargetCount)
|
||||||
|
{
|
||||||
|
IniItem targetItem;
|
||||||
|
IniSection *pSection;
|
||||||
|
IniItem *pFound;
|
||||||
|
IniItem *pItem;
|
||||||
|
IniItem *pItemEnd;
|
||||||
|
IniItem *pItemStart;
|
||||||
|
|
||||||
|
*nTargetCount = 0;
|
||||||
|
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
|
||||||
|
targetItem, pFound, NULL)
|
||||||
|
if (pFound == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*nTargetCount = 1;
|
||||||
|
for (pItem=pFound-1; pItem>=pSection->items; pItem--)
|
||||||
|
{
|
||||||
|
if (strcmp(pItem->name, szItemName) != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*nTargetCount)++;
|
||||||
|
}
|
||||||
|
pItemStart = pFound - (*nTargetCount) + 1;
|
||||||
|
|
||||||
|
pItemEnd = pSection->items + pSection->count;
|
||||||
|
for (pItem=pFound+1; pItem<pItemEnd; pItem++)
|
||||||
|
{
|
||||||
|
if (strcmp(pItem->name, szItemName) != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*nTargetCount)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pItemStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iniPrintHashData(const int index, const HashData *data, void *args)
|
||||||
|
{
|
||||||
|
IniSection *pSection;
|
||||||
|
IniItem *pItem;
|
||||||
|
IniItem *pItemEnd;
|
||||||
|
char section_name[256];
|
||||||
|
int section_len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
pSection = (IniSection *)data->value;
|
||||||
|
if (pSection == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
section_len = data->key_len;
|
||||||
|
if (section_len >= sizeof(section_name))
|
||||||
|
{
|
||||||
|
section_len = sizeof(section_name) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(section_name, data->key, section_len);
|
||||||
|
*(section_name + section_len) = '\0';
|
||||||
|
|
||||||
|
printf("section: %s, item count: %d\n", section_name, pSection->count);
|
||||||
|
if (pSection->count > 0)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
pItemEnd = pSection->items + pSection->count;
|
||||||
|
for (pItem=pSection->items; pItem<pItemEnd; pItem++)
|
||||||
|
{
|
||||||
|
printf("%d. %s=%s\n", ++i, pItem->name, pItem->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iniPrintItems(IniContext *pContext)
|
||||||
|
{
|
||||||
|
IniItem *pItem;
|
||||||
|
IniItem *pItemEnd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
printf("global section, item count: %d\n", pContext->global.count);
|
||||||
|
if (pContext->global.count > 0)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
pItemEnd = pContext->global.items + pContext->global.count;
|
||||||
|
for (pItem=pContext->global.items; pItem<pItemEnd; pItem++)
|
||||||
|
{
|
||||||
|
printf("%d. %s=%s\n", ++i, pItem->name, pItem->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
hash_walk(&pContext->sections, iniPrintHashData, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,166 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//ini_file_reader.h
|
||||||
|
#ifndef INI_FILE_READER_H
|
||||||
|
#define INI_FILE_READER_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
#define FAST_INI_ITEM_NAME_LEN 64
|
||||||
|
#define FAST_INI_ITEM_VALUE_LEN 256
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char name[FAST_INI_ITEM_NAME_LEN + 1];
|
||||||
|
char value[FAST_INI_ITEM_VALUE_LEN + 1];
|
||||||
|
} IniItem;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
IniItem *items;
|
||||||
|
int count; //item count
|
||||||
|
int alloc_count;
|
||||||
|
} IniSection;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
IniSection global;
|
||||||
|
HashArray sections; //key is session name, and value is IniSection
|
||||||
|
IniSection *current_section; //for load from ini file
|
||||||
|
char config_path[MAX_PATH_SIZE]; //save the config filepath
|
||||||
|
} IniContext;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** load ini items from file
|
||||||
|
* parameters:
|
||||||
|
* szFilename: the filename, can be an URL
|
||||||
|
* pContext: the ini context
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int iniLoadFromFile(const char *szFilename, IniContext *pContext);
|
||||||
|
|
||||||
|
/** load ini items from string buffer
|
||||||
|
* parameters:
|
||||||
|
* content: the string buffer to parse
|
||||||
|
* pContext: the ini context
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int iniLoadFromBuffer(char *content, IniContext *pContext);
|
||||||
|
|
||||||
|
/** free ini context
|
||||||
|
* parameters:
|
||||||
|
* pContext: the ini context
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void iniFreeContext(IniContext *pContext);
|
||||||
|
|
||||||
|
/** get item string value
|
||||||
|
* parameters:
|
||||||
|
* szSectionName: the section name, NULL or empty string for
|
||||||
|
* global section
|
||||||
|
* szItemName: the item name
|
||||||
|
* pContext: the ini context
|
||||||
|
* return: item value, return NULL when the item not exist
|
||||||
|
*/
|
||||||
|
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext);
|
||||||
|
|
||||||
|
/** get item string value
|
||||||
|
* parameters:
|
||||||
|
* szSectionName: the section name, NULL or empty string for
|
||||||
|
* global section
|
||||||
|
* szItemName: the item name
|
||||||
|
* pContext: the ini context
|
||||||
|
* szValues: string array to store the values
|
||||||
|
* max_values: max string array elements
|
||||||
|
* return: item value count
|
||||||
|
*/
|
||||||
|
int iniGetValues(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, char **szValues, const int max_values);
|
||||||
|
|
||||||
|
/** get item int value (32 bits)
|
||||||
|
* parameters:
|
||||||
|
* szSectionName: the section name, NULL or empty string for
|
||||||
|
* global section
|
||||||
|
* szItemName: the item name
|
||||||
|
* pContext: the ini context
|
||||||
|
* nDefaultValue: the default value
|
||||||
|
* return: item value, return nDefaultValue when the item not exist
|
||||||
|
*/
|
||||||
|
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const int nDefaultValue);
|
||||||
|
|
||||||
|
/** get item string value array
|
||||||
|
* parameters:
|
||||||
|
* szSectionName: the section name, NULL or empty string for
|
||||||
|
* global section
|
||||||
|
* szItemName: the item name
|
||||||
|
* pContext: the ini context
|
||||||
|
* nTargetCount: store the item value count
|
||||||
|
* return: item value array, return NULL when the item not exist
|
||||||
|
*/
|
||||||
|
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, int *nTargetCount);
|
||||||
|
|
||||||
|
/** get item int64 value (64 bits)
|
||||||
|
* parameters:
|
||||||
|
* szSectionName: the section name, NULL or empty string for
|
||||||
|
* global section
|
||||||
|
* szItemName: the item name
|
||||||
|
* pContext: the ini context
|
||||||
|
* nDefaultValue: the default value
|
||||||
|
* return: int64 value, return nDefaultValue when the item not exist
|
||||||
|
*/
|
||||||
|
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const int64_t nDefaultValue);
|
||||||
|
|
||||||
|
/** get item boolean value
|
||||||
|
* parameters:
|
||||||
|
* szSectionName: the section name, NULL or empty string for
|
||||||
|
* global section
|
||||||
|
* szItemName: the item name
|
||||||
|
* pContext: the ini context
|
||||||
|
* bDefaultValue: the default value
|
||||||
|
* return: item boolean value, return bDefaultValue when the item not exist
|
||||||
|
*/
|
||||||
|
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const bool bDefaultValue);
|
||||||
|
|
||||||
|
/** get item double value
|
||||||
|
* parameters:
|
||||||
|
* szSectionName: the section name, NULL or empty string for
|
||||||
|
* global section
|
||||||
|
* szItemName: the item name
|
||||||
|
* pContext: the ini context
|
||||||
|
* dbDefaultValue: the default value
|
||||||
|
* return: item value, return dbDefaultValue when the item not exist
|
||||||
|
*/
|
||||||
|
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
|
||||||
|
IniContext *pContext, const double dbDefaultValue);
|
||||||
|
|
||||||
|
/** print all items
|
||||||
|
* parameters:
|
||||||
|
* pContext: the ini context
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void iniPrintItems(IniContext *pContext);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "io_opt.h"
|
||||||
|
|
||||||
|
int mkdir_by_cascading(const char *path,mode_t mode)
|
||||||
|
{
|
||||||
|
int length,pointer_postion = 0;
|
||||||
|
char *postion;
|
||||||
|
char *path_temp = path;
|
||||||
|
char cwd[MAX_PATH_SIZE];
|
||||||
|
char *subfolder;
|
||||||
|
int is_error = 0;
|
||||||
|
int result = 0;
|
||||||
|
if(NULL == getcwd(cwd,sizeof(cwd)))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*path_temp == '/')
|
||||||
|
{
|
||||||
|
if(-1 == chdir("/"))
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
pointer_postion ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(pointer_postion != strlen(path_temp))
|
||||||
|
{
|
||||||
|
postion = strchr(path_temp+pointer_postion,'/');
|
||||||
|
if(0 == postion)
|
||||||
|
{
|
||||||
|
length = strlen(path_temp) - pointer_postion;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
length = postion - path_temp - pointer_postion;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
subfolder = (char *)calloc(length,sizeof(char));
|
||||||
|
if(NULL == subfolder)
|
||||||
|
{
|
||||||
|
result = -3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(subfolder,path_temp+pointer_postion,length);
|
||||||
|
if(is_dir(subfolder))
|
||||||
|
{
|
||||||
|
if(-1 == chdir(subfolder))
|
||||||
|
{
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(-1 == mkdir(subfolder,mode))
|
||||||
|
{
|
||||||
|
result = -4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(-1 == chdir(subfolder))
|
||||||
|
{
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}while(0);
|
||||||
|
|
||||||
|
if(NULL != subfolder)
|
||||||
|
{
|
||||||
|
free(subfolder);
|
||||||
|
subfolder = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer_postion += 0 == postion ? length : length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_dir(const char *dir_path) {
|
||||||
|
struct stat buf;
|
||||||
|
if (0 != stat(dir_path, &buf)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_ISDIR(buf.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef IO_OPT_H_
|
||||||
|
#define IO_OPT_H_
|
||||||
|
|
||||||
|
#ifndef MAX_PATH_SIZE
|
||||||
|
#define MAX_PATH_SIZE 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* create the dir by full dir_path
|
||||||
|
* parameters:
|
||||||
|
* path : the dir full path
|
||||||
|
* mode : the mode for mkdir
|
||||||
|
* return:
|
||||||
|
* 0:create dir is success
|
||||||
|
* -1 : get current path is error;
|
||||||
|
* -2 : change dir is error;
|
||||||
|
* -3 : malloc memory to subfolder is error
|
||||||
|
* -4 : create dir is error;
|
||||||
|
*/
|
||||||
|
int mkdir_by_cascading(const char *path,mode_t mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* check the first parameter is the dir
|
||||||
|
* parameters:
|
||||||
|
* path : the dir full path
|
||||||
|
* return:
|
||||||
|
* 0:the path is dir
|
||||||
|
* not 0: the path is not dir
|
||||||
|
*/
|
||||||
|
int is_dir(const char *path);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* IO_OPT_H_ */
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "ioevent.h"
|
||||||
|
|
||||||
|
#if IOEVENT_USE_KQUEUE
|
||||||
|
/* we define these here as numbers, because for kqueue mapping them to a combination of
|
||||||
|
* filters / flags is hard to do. */
|
||||||
|
int kqueue_ev_convert(int16_t event, uint16_t flags)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (event == EVFILT_READ) {
|
||||||
|
r = KPOLLIN;
|
||||||
|
}
|
||||||
|
else if (event == EVFILT_WRITE) {
|
||||||
|
r = KPOLLOUT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & EV_EOF) {
|
||||||
|
r |= KPOLLHUP;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ioevent_init(IOEventPoller *ioevent, const int size,
|
||||||
|
const int timeout, const int extra_events)
|
||||||
|
{
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
ioevent->size = size;
|
||||||
|
ioevent->extra_events = extra_events;
|
||||||
|
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
ioevent->timeout = timeout;
|
||||||
|
ioevent->poll_fd = epoll_create(ioevent->size);
|
||||||
|
bytes = sizeof(struct epoll_event) * size;
|
||||||
|
ioevent->events = (struct epoll_event *)malloc(bytes);
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
ioevent->timeout.tv_sec = timeout / 1000;
|
||||||
|
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
|
||||||
|
ioevent->poll_fd = kqueue();
|
||||||
|
bytes = sizeof(struct kevent) * size;
|
||||||
|
ioevent->events = (struct kevent *)malloc(bytes);
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
ioevent->timeout.tv_sec = timeout / 1000;
|
||||||
|
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
|
||||||
|
ioevent->poll_fd = port_create();
|
||||||
|
bytes = sizeof(port_event_t) * size;
|
||||||
|
ioevent->events = (port_event_t *)malloc(bytes);
|
||||||
|
#endif
|
||||||
|
if (ioevent->events == NULL) {
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ioevent_destroy(IOEventPoller *ioevent)
|
||||||
|
{
|
||||||
|
if (ioevent->events != NULL) {
|
||||||
|
free(ioevent->events);
|
||||||
|
ioevent->events = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioevent->poll_fd >=0) {
|
||||||
|
close(ioevent->poll_fd);
|
||||||
|
ioevent->poll_fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
struct epoll_event ev;
|
||||||
|
memset(&ev, 0, sizeof(ev));
|
||||||
|
ev.events = e | ioevent->extra_events;
|
||||||
|
ev.data.ptr = data;
|
||||||
|
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev);
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
struct kevent ev[2];
|
||||||
|
int n = 0;
|
||||||
|
if (e & IOEVENT_READ) {
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||||
|
}
|
||||||
|
if (e & IOEVENT_WRITE) {
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||||
|
}
|
||||||
|
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
struct epoll_event ev;
|
||||||
|
memset(&ev, 0, sizeof(ev));
|
||||||
|
ev.events = e | ioevent->extra_events;
|
||||||
|
ev.data.ptr = data;
|
||||||
|
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev);
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
struct kevent ev[2];
|
||||||
|
int n = 0;
|
||||||
|
if (e & IOEVENT_READ) {
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e & IOEVENT_WRITE) {
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, data);
|
||||||
|
}
|
||||||
|
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioevent_detach(IOEventPoller *ioevent, const int fd)
|
||||||
|
{
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
return port_dissociate(ioevent->poll_fd, PORT_SOURCE_FD, fd);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioevent_poll(IOEventPoller *ioevent)
|
||||||
|
{
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout);
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
return kevent(ioevent->poll_fd, NULL, 0, ioevent->events, ioevent->size, &ioevent->timeout);
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
int result;
|
||||||
|
int retval;
|
||||||
|
unsigned int nget = 1;
|
||||||
|
if((retval = port_getn(ioevent->poll_fd, ioevent->events,
|
||||||
|
ioevent->size, &nget, &ioevent->timeout)) == 0)
|
||||||
|
{
|
||||||
|
result = (int)nget;
|
||||||
|
} else {
|
||||||
|
switch(errno) {
|
||||||
|
case EINTR:
|
||||||
|
case EAGAIN:
|
||||||
|
case ETIME:
|
||||||
|
if (nget > 0) {
|
||||||
|
result = (int)nget;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
#error port me
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
#ifndef __IOEVENT_H__
|
||||||
|
#define __IOEVENT_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#define IOEVENT_TIMEOUT 0x8000
|
||||||
|
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#define IOEVENT_EDGE_TRIGGER EPOLLET
|
||||||
|
|
||||||
|
#define IOEVENT_READ EPOLLIN
|
||||||
|
#define IOEVENT_WRITE EPOLLOUT
|
||||||
|
#define IOEVENT_ERROR (EPOLLERR | EPOLLPRI | EPOLLHUP)
|
||||||
|
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
#include <sys/event.h>
|
||||||
|
#define IOEVENT_EDGE_TRIGGER EV_CLEAR
|
||||||
|
|
||||||
|
#define KPOLLIN 0x001
|
||||||
|
#define KPOLLPRI 0x002
|
||||||
|
#define KPOLLOUT 0x004
|
||||||
|
#define KPOLLERR 0x010
|
||||||
|
#define KPOLLHUP 0x020
|
||||||
|
#define IOEVENT_READ KPOLLIN
|
||||||
|
#define IOEVENT_WRITE KPOLLOUT
|
||||||
|
#define IOEVENT_ERROR (KPOLLHUP | KPOLLPRI | KPOLLHUP)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int kqueue_ev_convert(int16_t event, uint16_t flags);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
#include <port.h>
|
||||||
|
#define IOEVENT_EDGE_TRIGGER 0
|
||||||
|
|
||||||
|
#define IOEVENT_READ POLLIN
|
||||||
|
#define IOEVENT_WRITE POLLOUT
|
||||||
|
#define IOEVENT_ERROR (POLLERR | POLLPRI | POLLHUP)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct ioevent_puller {
|
||||||
|
int size; //max events (fd)
|
||||||
|
int extra_events;
|
||||||
|
int poll_fd;
|
||||||
|
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
struct epoll_event *events;
|
||||||
|
int timeout;
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
struct kevent *events;
|
||||||
|
struct timespec timeout;
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
port_event_t *events;
|
||||||
|
timespec_t timeout;
|
||||||
|
#endif
|
||||||
|
} IOEventPoller;
|
||||||
|
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
#define IOEVENT_GET_EVENTS(ioevent, index) \
|
||||||
|
ioevent->events[index].events
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
#define IOEVENT_GET_EVENTS(ioevent, index) kqueue_ev_convert( \
|
||||||
|
ioevent->events[index].filter, ioevent->events[index].flags)
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
#define IOEVENT_GET_EVENTS(ioevent, index) \
|
||||||
|
ioevent->events[index].portev_events
|
||||||
|
#else
|
||||||
|
#error port me
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if IOEVENT_USE_EPOLL
|
||||||
|
#define IOEVENT_GET_DATA(ioevent, index) \
|
||||||
|
ioevent->events[index].data.ptr
|
||||||
|
#elif IOEVENT_USE_KQUEUE
|
||||||
|
#define IOEVENT_GET_DATA(ioevent, index) \
|
||||||
|
ioevent->events[index].udata
|
||||||
|
#elif IOEVENT_USE_PORT
|
||||||
|
#define IOEVENT_GET_DATA(ioevent, index) \
|
||||||
|
ioevent->events[index].portev_user
|
||||||
|
#else
|
||||||
|
#error port me
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ioevent_init(IOEventPoller *ioevent, const int size,
|
||||||
|
const int timeout, const int extra_events);
|
||||||
|
void ioevent_destroy(IOEventPoller *ioevent);
|
||||||
|
|
||||||
|
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
|
void *data);
|
||||||
|
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
|
||||||
|
void *data);
|
||||||
|
int ioevent_detach(IOEventPoller *ioevent, const int fd);
|
||||||
|
int ioevent_poll(IOEventPoller *ioevent);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,150 @@
|
||||||
|
#include "sched_thread.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "ioevent_loop.h"
|
||||||
|
|
||||||
|
static void deal_ioevents(IOEventPoller *ioevent, const int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int event;
|
||||||
|
IOEventEntry *pEntry;
|
||||||
|
for (i=0; i<count; i++)
|
||||||
|
{
|
||||||
|
event = IOEVENT_GET_EVENTS(ioevent, i);
|
||||||
|
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent, i);
|
||||||
|
|
||||||
|
pEntry->callback(pEntry->fd, event, pEntry->timer.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deal_timeouts(FastTimerEntry *head)
|
||||||
|
{
|
||||||
|
FastTimerEntry *entry;
|
||||||
|
FastTimerEntry *curent;
|
||||||
|
IOEventEntry *pEventEntry;
|
||||||
|
|
||||||
|
entry = head->next;
|
||||||
|
while (entry != NULL)
|
||||||
|
{
|
||||||
|
curent = entry;
|
||||||
|
entry = entry->next;
|
||||||
|
|
||||||
|
pEventEntry = (IOEventEntry *)curent->data;
|
||||||
|
if (pEventEntry != NULL)
|
||||||
|
{
|
||||||
|
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT,
|
||||||
|
curent->data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioevent_loop(struct nio_thread_data *pThreadData,
|
||||||
|
IOEventCallback recv_notify_callback, TaskCleanUpCallBack
|
||||||
|
clean_up_callback, volatile bool *continue_flag)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
IOEventEntry ev_notify;
|
||||||
|
FastTimerEntry head;
|
||||||
|
struct fast_task_info *pTask;
|
||||||
|
time_t last_check_time;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
memset(&ev_notify, 0, sizeof(ev_notify));
|
||||||
|
ev_notify.fd = pThreadData->pipe_fds[0];
|
||||||
|
ev_notify.callback = recv_notify_callback;
|
||||||
|
if (ioevent_attach(&pThreadData->ev_puller,
|
||||||
|
pThreadData->pipe_fds[0], IOEVENT_READ,
|
||||||
|
&ev_notify) != 0)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logCrit("file: "__FILE__", line: %d, " \
|
||||||
|
"ioevent_attach fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_check_time = g_current_time;
|
||||||
|
while (*continue_flag)
|
||||||
|
{
|
||||||
|
pThreadData->deleted_list = NULL;
|
||||||
|
count = ioevent_poll(&pThreadData->ev_puller);
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
deal_ioevents(&pThreadData->ev_puller, count);
|
||||||
|
}
|
||||||
|
else if (count < 0)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : EINVAL;
|
||||||
|
if (result != EINTR)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"ioevent_poll fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pThreadData->deleted_list != NULL)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
while (pThreadData->deleted_list != NULL)
|
||||||
|
{
|
||||||
|
pTask = pThreadData->deleted_list;
|
||||||
|
pThreadData->deleted_list = pTask->next;
|
||||||
|
|
||||||
|
clean_up_callback(pTask);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
logInfo("cleanup task count: %d", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_current_time - last_check_time > 0)
|
||||||
|
{
|
||||||
|
last_check_time = g_current_time;
|
||||||
|
count = fast_timer_timeouts_get(
|
||||||
|
&pThreadData->timer, g_current_time, &head);
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
deal_timeouts(&head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
|
||||||
|
int sock, short event, IOEventCallback callback, const int timeout)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
pTask->thread_data = pThread;
|
||||||
|
pTask->event.fd = sock;
|
||||||
|
pTask->event.callback = callback;
|
||||||
|
if (ioevent_attach(&pThread->ev_puller,
|
||||||
|
sock, event, pTask) < 0)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : ENOENT;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"ioevent_attach fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pTask->event.timer.data = pTask;
|
||||||
|
pTask->event.timer.expires = g_current_time + timeout;
|
||||||
|
result = fast_timer_add(&pThread->timer, &pTask->event.timer);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"fast_timer_add fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef _IOEVENT_LOOP_H
|
||||||
|
#define _IOEVENT_LOOP_H
|
||||||
|
|
||||||
|
#include "fast_task_queue.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int ioevent_loop(struct nio_thread_data *pThreadData,
|
||||||
|
IOEventCallback recv_notify_callback, TaskCleanUpCallBack
|
||||||
|
clean_up_callback, volatile bool *continue_flag);
|
||||||
|
|
||||||
|
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
|
||||||
|
int sock, short event, IOEventCallback callback, const int timeout);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,134 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "logger.h"
|
||||||
|
#include "sockopt.h"
|
||||||
|
#include "shared_func.h"
|
||||||
|
#include "local_ip_func.h"
|
||||||
|
|
||||||
|
int g_local_host_ip_count = 0;
|
||||||
|
char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \
|
||||||
|
IP_ADDRESS_SIZE];
|
||||||
|
char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE] = {0};
|
||||||
|
|
||||||
|
bool is_local_host_ip(const char *client_ip)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *pEnd;
|
||||||
|
|
||||||
|
pEnd = g_local_host_ip_addrs + \
|
||||||
|
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||||
|
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||||
|
{
|
||||||
|
if (strcmp(client_ip, p) == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int insert_into_local_host_ip(const char *client_ip)
|
||||||
|
{
|
||||||
|
if (is_local_host_ip(client_ip))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_local_host_ip_count >= FAST_MAX_LOCAL_IP_ADDRS)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(g_local_host_ip_addrs + \
|
||||||
|
IP_ADDRESS_SIZE * g_local_host_ip_count, \
|
||||||
|
client_ip);
|
||||||
|
g_local_host_ip_count++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_local_host_ip_addrs()
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *pEnd;
|
||||||
|
char buff[512];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = sprintf(buff, "local_host_ip_count: %d,", g_local_host_ip_count);
|
||||||
|
pEnd = g_local_host_ip_addrs + \
|
||||||
|
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||||
|
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||||
|
{
|
||||||
|
len += sprintf(buff + len, " %s", p);
|
||||||
|
}
|
||||||
|
|
||||||
|
logInfo("%s", buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_local_host_ip_addrs()
|
||||||
|
{
|
||||||
|
#define STORAGE_MAX_ALIAS_PREFIX_COUNT 4
|
||||||
|
char ip_addresses[FAST_MAX_LOCAL_IP_ADDRS][IP_ADDRESS_SIZE];
|
||||||
|
int count;
|
||||||
|
int k;
|
||||||
|
char *if_alias_prefixes[STORAGE_MAX_ALIAS_PREFIX_COUNT];
|
||||||
|
int alias_count;
|
||||||
|
|
||||||
|
insert_into_local_host_ip("127.0.0.1");
|
||||||
|
|
||||||
|
memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes));
|
||||||
|
if (*g_if_alias_prefix == '\0')
|
||||||
|
{
|
||||||
|
alias_count = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alias_count = splitEx(g_if_alias_prefix, ',', \
|
||||||
|
if_alias_prefixes, STORAGE_MAX_ALIAS_PREFIX_COUNT);
|
||||||
|
for (k=0; k<alias_count; k++)
|
||||||
|
{
|
||||||
|
trim(if_alias_prefixes[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gethostaddrs(if_alias_prefixes, alias_count, ip_addresses, \
|
||||||
|
FAST_MAX_LOCAL_IP_ADDRS, &count) != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (k=0; k<count; k++)
|
||||||
|
{
|
||||||
|
insert_into_local_host_ip(ip_addresses[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_local_host_ip_addrs();
|
||||||
|
//print_local_host_ip_addrs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_local_host_ip_addrs()
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *pEnd;
|
||||||
|
|
||||||
|
printf("local_host_ip_count=%d\n", g_local_host_ip_count);
|
||||||
|
pEnd = g_local_host_ip_addrs + \
|
||||||
|
IP_ADDRESS_SIZE * g_local_host_ip_count;
|
||||||
|
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
|
||||||
|
{
|
||||||
|
printf("%d. %s\n", (int)((p-g_local_host_ip_addrs)/ \
|
||||||
|
IP_ADDRESS_SIZE)+1, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//local_ip_func.h
|
||||||
|
|
||||||
|
#ifndef _LOCAL_IP_FUNC_H
|
||||||
|
#define _LOCAL_IP_FUNC_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
#define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32
|
||||||
|
#define FAST_MAX_LOCAL_IP_ADDRS 16
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int g_local_host_ip_count;
|
||||||
|
extern char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \
|
||||||
|
IP_ADDRESS_SIZE];
|
||||||
|
extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE];
|
||||||
|
|
||||||
|
void load_local_host_ip_addrs();
|
||||||
|
bool is_local_host_ip(const char *client_ip);
|
||||||
|
int insert_into_local_host_ip(const char *client_ip);
|
||||||
|
void print_local_host_ip_addrs();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,668 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "shared_func.h"
|
||||||
|
#include "pthread_func.h"
|
||||||
|
#include "sched_thread.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#ifndef LINE_MAX
|
||||||
|
#define LINE_MAX 2048
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LOG_BUFF_SIZE 64 * 1024
|
||||||
|
|
||||||
|
LogContext g_log_context = {LOG_INFO, STDERR_FILENO, NULL};
|
||||||
|
|
||||||
|
static int log_fsync(LogContext *pContext, const bool bNeedLock);
|
||||||
|
|
||||||
|
static int check_and_mk_log_dir(const char *base_path)
|
||||||
|
{
|
||||||
|
char data_path[MAX_PATH_SIZE];
|
||||||
|
|
||||||
|
snprintf(data_path, sizeof(data_path), "%s/logs", base_path);
|
||||||
|
if (!fileExists(data_path))
|
||||||
|
{
|
||||||
|
if (mkdir(data_path, 0755) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "mkdir \"%s\" fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
data_path, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_init()
|
||||||
|
{
|
||||||
|
if (g_log_context.log_buff != NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_init_ex(&g_log_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_init_ex(LogContext *pContext)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
memset(pContext, 0, sizeof(LogContext));
|
||||||
|
pContext->log_level = LOG_INFO;
|
||||||
|
pContext->log_fd = STDERR_FILENO;
|
||||||
|
pContext->log_to_cache = false;
|
||||||
|
pContext->rotate_immediately = false;
|
||||||
|
pContext->time_precision = LOG_TIME_PRECISION_SECOND;
|
||||||
|
|
||||||
|
pContext->log_buff = (char *)malloc(LOG_BUFF_SIZE);
|
||||||
|
if (pContext->log_buff == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "malloc %d bytes fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
LOG_BUFF_SIZE, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : ENOMEM;
|
||||||
|
}
|
||||||
|
pContext->pcurrent_buff = pContext->log_buff;
|
||||||
|
|
||||||
|
if ((result=init_pthread_lock(&(pContext->log_thread_lock))) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int log_open(LogContext *pContext)
|
||||||
|
{
|
||||||
|
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | \
|
||||||
|
O_CREAT | O_APPEND, 0644)) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "open log file \"%s\" to write fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
pContext->log_filename, errno, STRERROR(errno));
|
||||||
|
pContext->log_fd = STDERR_FILENO;
|
||||||
|
return errno != 0 ? errno : EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
pContext->current_size = lseek(pContext->log_fd, 0, SEEK_END);
|
||||||
|
if (pContext->current_size < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "lseek file \"%s\" fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
pContext->log_filename, errno, STRERROR(errno));
|
||||||
|
return errno != 0 ? errno : EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
|
||||||
|
const char *filename_prefix)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=check_and_mk_log_dir(base_path)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s/logs/%s.log", \
|
||||||
|
base_path, filename_prefix);
|
||||||
|
|
||||||
|
return log_open(pContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_set_filename_ex(LogContext *pContext, const char *log_filename)
|
||||||
|
{
|
||||||
|
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename);
|
||||||
|
return log_open(pContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_set_cache_ex(LogContext *pContext, const bool bLogCache)
|
||||||
|
{
|
||||||
|
pContext->log_to_cache = bLogCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_set_time_precision(LogContext *pContext, const int time_precision)
|
||||||
|
{
|
||||||
|
pContext->time_precision = time_precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_destroy_ex(LogContext *pContext)
|
||||||
|
{
|
||||||
|
if (pContext->log_fd >= 0 && pContext->log_fd != STDERR_FILENO)
|
||||||
|
{
|
||||||
|
log_fsync(pContext, true);
|
||||||
|
|
||||||
|
close(pContext->log_fd);
|
||||||
|
pContext->log_fd = STDERR_FILENO;
|
||||||
|
|
||||||
|
pthread_mutex_destroy(&pContext->log_thread_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext->log_buff != NULL)
|
||||||
|
{
|
||||||
|
free(pContext->log_buff);
|
||||||
|
pContext->log_buff = NULL;
|
||||||
|
pContext->pcurrent_buff = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_sync_func(void *args)
|
||||||
|
{
|
||||||
|
if (args == NULL)
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_fsync((LogContext *)args, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int log_notify_rotate(void *args)
|
||||||
|
{
|
||||||
|
if (args == NULL)
|
||||||
|
{
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
((LogContext *)args)->rotate_immediately = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int log_rotate(LogContext *pContext)
|
||||||
|
{
|
||||||
|
struct tm tm;
|
||||||
|
time_t current_time;
|
||||||
|
char new_filename[MAX_PATH_SIZE + 32];
|
||||||
|
|
||||||
|
if (*(pContext->log_filename) == '\0')
|
||||||
|
{
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(pContext->log_fd);
|
||||||
|
|
||||||
|
current_time = get_current_time();
|
||||||
|
localtime_r(¤t_time, &tm);
|
||||||
|
sprintf(new_filename, "%s.%04d%02d%02d_%02d%02d%02d", \
|
||||||
|
pContext->log_filename, \
|
||||||
|
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
|
||||||
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||||
|
if (rename(pContext->log_filename, new_filename) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"rename %s to %s fail, errno: %d, error info: %s", \
|
||||||
|
__LINE__, pContext->log_filename, new_filename, \
|
||||||
|
errno, STRERROR(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_open(pContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int log_check_rotate(LogContext *pContext, const bool bNeedLock)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (pContext->log_fd == STDERR_FILENO)
|
||||||
|
{
|
||||||
|
if (pContext->current_size > 0)
|
||||||
|
{
|
||||||
|
pContext->current_size = 0;
|
||||||
|
}
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bNeedLock)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&(pContext->log_thread_lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext->rotate_immediately)
|
||||||
|
{
|
||||||
|
result = log_rotate(pContext);
|
||||||
|
pContext->rotate_immediately = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bNeedLock)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int log_fsync(LogContext *pContext, const bool bNeedLock)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
int lock_res;
|
||||||
|
int write_bytes;
|
||||||
|
|
||||||
|
write_bytes = pContext->pcurrent_buff - pContext->log_buff;
|
||||||
|
if (write_bytes == 0)
|
||||||
|
{
|
||||||
|
if (!pContext->rotate_immediately)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return log_check_rotate(pContext, bNeedLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bNeedLock && ((lock_res=pthread_mutex_lock( \
|
||||||
|
&(pContext->log_thread_lock))) != 0))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, lock_res, STRERROR(lock_res));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext->rotate_size > 0)
|
||||||
|
{
|
||||||
|
pContext->current_size += write_bytes;
|
||||||
|
if (pContext->current_size > pContext->rotate_size)
|
||||||
|
{
|
||||||
|
pContext->rotate_immediately = true;
|
||||||
|
log_check_rotate(pContext, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
write_bytes = pContext->pcurrent_buff - pContext->log_buff;
|
||||||
|
if (write(pContext->log_fd, pContext->log_buff, write_bytes) != \
|
||||||
|
write_bytes)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : EIO;
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"call write fail, errno: %d, error info: %s\n",\
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext->log_fd != STDERR_FILENO)
|
||||||
|
{
|
||||||
|
if (fsync(pContext->log_fd) != 0)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : EIO;
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"call fsync fail, errno: %d, error info: %s\n",\
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext->rotate_immediately)
|
||||||
|
{
|
||||||
|
result = log_check_rotate(pContext, false);
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
pContext->pcurrent_buff = pContext->log_buff;
|
||||||
|
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
|
||||||
|
&(pContext->log_thread_lock))) != 0))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, lock_res, STRERROR(lock_res));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doLogEx(LogContext *pContext, struct timeval *tv, \
|
||||||
|
const char *caption, const char *text, const int text_len, \
|
||||||
|
const bool bNeedSync)
|
||||||
|
{
|
||||||
|
struct tm tm;
|
||||||
|
int time_fragment;
|
||||||
|
int buff_len;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
|
||||||
|
{
|
||||||
|
time_fragment = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pContext->time_precision == LOG_TIME_PRECISION_MSECOND)
|
||||||
|
{
|
||||||
|
time_fragment = tv->tv_usec / 1000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time_fragment = tv->tv_usec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localtime_r(&tv->tv_sec, &tm);
|
||||||
|
if ((result=pthread_mutex_lock(&pContext->log_thread_lock)) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_lock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text_len + 64 > LOG_BUFF_SIZE)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"log buff size: %d < log text length: %d ", \
|
||||||
|
__LINE__, LOG_BUFF_SIZE, text_len + 64);
|
||||||
|
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64 \
|
||||||
|
> LOG_BUFF_SIZE)
|
||||||
|
{
|
||||||
|
log_fsync(pContext, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
|
||||||
|
{
|
||||||
|
buff_len = sprintf(pContext->pcurrent_buff, \
|
||||||
|
"[%04d-%02d-%02d %02d:%02d:%02d] ", \
|
||||||
|
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
|
||||||
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buff_len = sprintf(pContext->pcurrent_buff, \
|
||||||
|
"[%04d-%02d-%02d %02d:%02d:%02d.%03d] ", \
|
||||||
|
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
|
||||||
|
tm.tm_hour, tm.tm_min, tm.tm_sec, time_fragment);
|
||||||
|
}
|
||||||
|
pContext->pcurrent_buff += buff_len;
|
||||||
|
|
||||||
|
if (caption != NULL)
|
||||||
|
{
|
||||||
|
buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption);
|
||||||
|
pContext->pcurrent_buff += buff_len;
|
||||||
|
}
|
||||||
|
memcpy(pContext->pcurrent_buff, text, text_len);
|
||||||
|
pContext->pcurrent_buff += text_len;
|
||||||
|
*pContext->pcurrent_buff++ = '\n';
|
||||||
|
|
||||||
|
if (!pContext->log_to_cache || bNeedSync)
|
||||||
|
{
|
||||||
|
log_fsync(pContext, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_mutex_unlock(&(pContext->log_thread_lock))) != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_unlock fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doLog(LogContext *pContext, const char *caption, \
|
||||||
|
const char *text, const int text_len, const bool bNeedSync)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
|
||||||
|
{
|
||||||
|
tv.tv_sec = get_current_time();
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
doLogEx(pContext, &tv, caption, text, text_len, bNeedSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_it_ex1(LogContext *pContext, const int priority, \
|
||||||
|
const char *text, const int text_len)
|
||||||
|
{
|
||||||
|
bool bNeedSync;
|
||||||
|
char *caption;
|
||||||
|
|
||||||
|
switch(priority)
|
||||||
|
{
|
||||||
|
case LOG_DEBUG:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "DEBUG";
|
||||||
|
break;
|
||||||
|
case LOG_INFO:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "INFO";
|
||||||
|
break;
|
||||||
|
case LOG_NOTICE:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "NOTICE";
|
||||||
|
break;
|
||||||
|
case LOG_WARNING:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "WARNING";
|
||||||
|
break;
|
||||||
|
case LOG_ERR:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "ERROR";
|
||||||
|
break;
|
||||||
|
case LOG_CRIT:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "CRIT";
|
||||||
|
break;
|
||||||
|
case LOG_ALERT:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "ALERT";
|
||||||
|
break;
|
||||||
|
case LOG_EMERG:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "EMERG";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "UNKOWN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
doLog(pContext, caption, text, text_len, bNeedSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_it_ex(LogContext *pContext, const int priority, const char *format, ...)
|
||||||
|
{
|
||||||
|
bool bNeedSync;
|
||||||
|
char text[LINE_MAX];
|
||||||
|
char *caption;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
len = vsnprintf(text, sizeof(text), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
switch(priority)
|
||||||
|
{
|
||||||
|
case LOG_DEBUG:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "DEBUG";
|
||||||
|
break;
|
||||||
|
case LOG_INFO:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "INFO";
|
||||||
|
break;
|
||||||
|
case LOG_NOTICE:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "NOTICE";
|
||||||
|
break;
|
||||||
|
case LOG_WARNING:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "WARNING";
|
||||||
|
break;
|
||||||
|
case LOG_ERR:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "ERROR";
|
||||||
|
break;
|
||||||
|
case LOG_CRIT:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "CRIT";
|
||||||
|
break;
|
||||||
|
case LOG_ALERT:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "ALERT";
|
||||||
|
break;
|
||||||
|
case LOG_EMERG:
|
||||||
|
bNeedSync = true;
|
||||||
|
caption = "EMERG";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bNeedSync = false;
|
||||||
|
caption = "UNKOWN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
doLog(pContext, caption, text, len, bNeedSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define _DO_LOG(pContext, priority, caption, bNeedSync) \
|
||||||
|
char text[LINE_MAX]; \
|
||||||
|
int len; \
|
||||||
|
\
|
||||||
|
if (pContext->log_level < priority) \
|
||||||
|
{ \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
{ \
|
||||||
|
va_list ap; \
|
||||||
|
va_start(ap, format); \
|
||||||
|
len = vsnprintf(text, sizeof(text), format, ap); \
|
||||||
|
va_end(ap); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
doLog(pContext, caption, text, len, bNeedSync); \
|
||||||
|
|
||||||
|
|
||||||
|
void logEmergEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_EMERG, "EMERG", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logAlertEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_ALERT, "ALERT", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logCritEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_CRIT, "CRIT", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logErrorEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_ERR, "ERROR", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logWarningEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_WARNING, "WARNING", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logNoticeEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_NOTICE, "NOTICE", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logInfoEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_INFO, "INFO", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logDebugEx(LogContext *pContext, const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG(pContext, LOG_DEBUG, "DEBUG", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logAccess(LogContext *pContext, struct timeval *tvStart, \
|
||||||
|
const char *format, ...)
|
||||||
|
{
|
||||||
|
char text[LINE_MAX];
|
||||||
|
int len;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
len = vsnprintf(text, sizeof(text), format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
doLogEx(pContext, tvStart, NULL, text, len, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef LOG_FORMAT_CHECK
|
||||||
|
|
||||||
|
void logEmerg(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_EMERG, "EMERG", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logAlert(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_ALERT, "ALERT", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logCrit(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_CRIT, "CRIT", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logError(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_ERR, "ERROR", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logWarning(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_WARNING, "WARNING", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logNotice(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_NOTICE, "NOTICE", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logInfo(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_INFO, "INFO", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
void logDebug(const char *format, ...)
|
||||||
|
{
|
||||||
|
_DO_LOG((&g_log_context), LOG_DEBUG, "DEBUG", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//logger.h
|
||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LOG_TIME_PRECISION_SECOND 's' //second
|
||||||
|
#define LOG_TIME_PRECISION_MSECOND 'm' //millisecond
|
||||||
|
#define LOG_TIME_PRECISION_USSECOND 'u' //microsecond
|
||||||
|
|
||||||
|
typedef struct log_context
|
||||||
|
{
|
||||||
|
/* log level value please see: sys/syslog.h
|
||||||
|
default value is LOG_INFO */
|
||||||
|
int log_level;
|
||||||
|
|
||||||
|
/* default value is STDERR_FILENO */
|
||||||
|
int log_fd;
|
||||||
|
|
||||||
|
/* cache buffer */
|
||||||
|
char *log_buff;
|
||||||
|
|
||||||
|
/* string end in the cache buffer for next sprintf */
|
||||||
|
char *pcurrent_buff;
|
||||||
|
|
||||||
|
/* mutext lock */
|
||||||
|
pthread_mutex_t log_thread_lock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
rotate the log when the log file exceeds this parameter
|
||||||
|
rotate_size > 0 means need rotate log by log file size
|
||||||
|
*/
|
||||||
|
int64_t rotate_size;
|
||||||
|
|
||||||
|
/* log file current size */
|
||||||
|
int64_t current_size;
|
||||||
|
|
||||||
|
/* if write to buffer firstly, then sync to disk.
|
||||||
|
default value is false (no cache) */
|
||||||
|
bool log_to_cache;
|
||||||
|
|
||||||
|
/* if rotate the access log */
|
||||||
|
bool rotate_immediately;
|
||||||
|
|
||||||
|
/* time precision */
|
||||||
|
char time_precision;
|
||||||
|
|
||||||
|
/* save the log filename */
|
||||||
|
char log_filename[MAX_PATH_SIZE];
|
||||||
|
} LogContext;
|
||||||
|
|
||||||
|
extern LogContext g_log_context;
|
||||||
|
|
||||||
|
/** init function using global log context
|
||||||
|
* return: 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int log_init();
|
||||||
|
|
||||||
|
#define log_set_prefix(base_path, filename_prefix) \
|
||||||
|
log_set_prefix_ex(&g_log_context, base_path, filename_prefix)
|
||||||
|
|
||||||
|
#define log_set_filename(log_filename) \
|
||||||
|
log_set_filename_ex(&g_log_context, log_filename)
|
||||||
|
|
||||||
|
#define log_set_cache(bLogCache) log_set_cache_ex(&g_log_context, bLogCache)
|
||||||
|
|
||||||
|
#define log_destroy() log_destroy_ex(&g_log_context)
|
||||||
|
|
||||||
|
/** init function, use stderr for output by default
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* return: 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int log_init_ex(LogContext *pContext);
|
||||||
|
|
||||||
|
/** set log filename prefix, such as "tracker", the log filename will be
|
||||||
|
* ${base_path}/logs/tracker.log
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* base_path: base path
|
||||||
|
* filename_prefix: log filename prefix
|
||||||
|
* return: 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
|
||||||
|
const char *filename_prefix);
|
||||||
|
|
||||||
|
/** set log filename
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* log_filename: log filename
|
||||||
|
* return: 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int log_set_filename_ex(LogContext *pContext, const char *log_filename);
|
||||||
|
|
||||||
|
/** set if use log cache
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* bLogCache: true for cache in buffer, false directly write to disk
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void log_set_cache_ex(LogContext *pContext, const bool bLogCache);
|
||||||
|
|
||||||
|
/** set time precision
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* time_precision: the time precision
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void log_set_time_precision(LogContext *pContext, const int time_precision);
|
||||||
|
|
||||||
|
/** destroy function
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* bLogCache: true for cache in buffer, false directly write to disk
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void log_destroy_ex(LogContext *pContext);
|
||||||
|
|
||||||
|
/** log to file
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* priority: unix priority
|
||||||
|
* format: printf format
|
||||||
|
* ...: arguments for printf format
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void log_it_ex(LogContext *pContext, const int priority, \
|
||||||
|
const char *format, ...);
|
||||||
|
|
||||||
|
/** log to file
|
||||||
|
* parameters:
|
||||||
|
* pContext: the log context
|
||||||
|
* priority: unix priority
|
||||||
|
* text: text string to log
|
||||||
|
* text_len: text string length (bytes)
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void log_it_ex1(LogContext *pContext, const int priority, \
|
||||||
|
const char *text, const int text_len);
|
||||||
|
|
||||||
|
/** sync log buffer to log file
|
||||||
|
* parameters:
|
||||||
|
* args: should be (LogContext *)
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int log_sync_func(void *args);
|
||||||
|
|
||||||
|
/** set rotate flag to true
|
||||||
|
* parameters:
|
||||||
|
* args: should be (LogContext *)
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int log_notify_rotate(void *args);
|
||||||
|
|
||||||
|
void logEmergEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logCritEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logAlertEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logErrorEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logWarningEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logNoticeEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logInfoEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logDebugEx(LogContext *pContext, const char *format, ...);
|
||||||
|
void logAccess(LogContext *pContext, struct timeval *tvStart, \
|
||||||
|
const char *format, ...);
|
||||||
|
|
||||||
|
//#define LOG_FORMAT_CHECK
|
||||||
|
|
||||||
|
#ifdef LOG_FORMAT_CHECK /*only for format check*/
|
||||||
|
|
||||||
|
#define logEmerg printf
|
||||||
|
#define logCrit printf
|
||||||
|
#define logAlert printf
|
||||||
|
#define logError printf
|
||||||
|
#define logWarning printf
|
||||||
|
#define logNotice printf
|
||||||
|
#define logInfo printf
|
||||||
|
#define logDebug printf
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* following functions use global log context: g_log_context */
|
||||||
|
void logEmerg(const char *format, ...);
|
||||||
|
void logCrit(const char *format, ...);
|
||||||
|
void logAlert(const char *format, ...);
|
||||||
|
void logError(const char *format, ...);
|
||||||
|
void logWarning(const char *format, ...);
|
||||||
|
void logNotice(const char *format, ...);
|
||||||
|
void logInfo(const char *format, ...);
|
||||||
|
void logDebug(const char *format, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,356 @@
|
||||||
|
#include "md5.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define S11 7
|
||||||
|
#define S12 12
|
||||||
|
#define S13 17
|
||||||
|
#define S14 22
|
||||||
|
#define S21 5
|
||||||
|
#define S22 9
|
||||||
|
#define S23 14
|
||||||
|
#define S24 20
|
||||||
|
#define S31 4
|
||||||
|
#define S32 11
|
||||||
|
#define S33 16
|
||||||
|
#define S34 23
|
||||||
|
#define S41 6
|
||||||
|
#define S42 10
|
||||||
|
#define S43 15
|
||||||
|
#define S44 21
|
||||||
|
|
||||||
|
static void MD5Transform (UINT4[4], unsigned char[64]);
|
||||||
|
static void Encode (unsigned char *, UINT4 *, unsigned int);
|
||||||
|
static void Decode (UINT4 *, unsigned char *, unsigned int);
|
||||||
|
static void MD5_memcpy (POINTER, POINTER, unsigned int);
|
||||||
|
static void MD5_memset (POINTER, int, unsigned int);
|
||||||
|
|
||||||
|
static unsigned char PADDING[64] = {
|
||||||
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* F, G, H and I are basic MD5 functions.
|
||||||
|
*/
|
||||||
|
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||||
|
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||||
|
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||||
|
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ROTATE_LEFT rotates x left n bits.
|
||||||
|
*/
|
||||||
|
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is
|
||||||
|
* separate from addition to prevent recomputation.
|
||||||
|
*/
|
||||||
|
#define FF(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
#define GG(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
#define HH(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
#define II(a, b, c, d, x, s, ac) { \
|
||||||
|
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||||
|
(a) = ROTATE_LEFT ((a), (s)); \
|
||||||
|
(a) += (b); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
my_md5_init(MD5_CTX *context)
|
||||||
|
{
|
||||||
|
context->count[0] = context->count[1] = 0;
|
||||||
|
/*
|
||||||
|
* Load magic initialization constants.
|
||||||
|
*/
|
||||||
|
context->state[0] = 0x67452301;
|
||||||
|
context->state[1] = 0xefcdab89;
|
||||||
|
context->state[2] = 0x98badcfe;
|
||||||
|
context->state[3] = 0x10325476;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MD5 block update operation. Continues an MD5 message-digest operation,
|
||||||
|
* processing another message block, and updating the context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
my_md5_update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
|
||||||
|
{
|
||||||
|
unsigned int i, index, partLen;
|
||||||
|
|
||||||
|
/* Compute number of bytes mod 64 */
|
||||||
|
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
|
||||||
|
|
||||||
|
/* Update number of bits */
|
||||||
|
if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen << 3))
|
||||||
|
context->count[1]++;
|
||||||
|
context->count[1] += ((UINT4) inputLen >> 29);
|
||||||
|
|
||||||
|
partLen = 64 - index;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transform as many times as possible.
|
||||||
|
*/
|
||||||
|
if (inputLen >= partLen) {
|
||||||
|
MD5_memcpy
|
||||||
|
((POINTER) & context->buffer[index], (POINTER) input, partLen);
|
||||||
|
MD5Transform(context->state, context->buffer);
|
||||||
|
|
||||||
|
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||||
|
MD5Transform(context->state, &input[i]);
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
} else
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Buffer remaining input */
|
||||||
|
MD5_memcpy
|
||||||
|
((POINTER) & context->buffer[index], (POINTER) & input[i],
|
||||||
|
inputLen - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MD5 finalization. Ends an MD5 message-digest operation, writing the the
|
||||||
|
* message digest and zeroizing the context.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
my_md5_final(unsigned char digest[16], MD5_CTX *context)
|
||||||
|
{
|
||||||
|
unsigned char bits[8];
|
||||||
|
unsigned int index, padLen;
|
||||||
|
|
||||||
|
/* Save number of bits */
|
||||||
|
Encode(bits, context->count, 8);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pad out to 56 mod 64.
|
||||||
|
*/
|
||||||
|
index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
|
||||||
|
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||||
|
my_md5_update(context, PADDING, padLen);
|
||||||
|
|
||||||
|
/* Append length (before padding) */
|
||||||
|
my_md5_update(context, bits, 8);
|
||||||
|
/* Store state in digest */
|
||||||
|
Encode(digest, context->state, 16);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Zeroize sensitive information.
|
||||||
|
*/
|
||||||
|
MD5_memset((POINTER) context, 0, sizeof(*context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MD5 basic transformation. Transforms state based on block.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
MD5Transform(UINT4 state[4], unsigned char block[64])
|
||||||
|
{
|
||||||
|
UINT4 a = state[0], b = state[1], c = state[2], d = state[3],
|
||||||
|
x[16];
|
||||||
|
|
||||||
|
Decode(x, block, 64);
|
||||||
|
|
||||||
|
/* Round 1 */
|
||||||
|
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
|
||||||
|
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
|
||||||
|
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
|
||||||
|
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
|
||||||
|
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
|
||||||
|
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
|
||||||
|
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
|
||||||
|
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
|
||||||
|
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
|
||||||
|
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
|
||||||
|
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||||
|
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||||
|
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||||
|
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||||
|
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||||
|
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||||
|
|
||||||
|
/* Round 2 */
|
||||||
|
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
|
||||||
|
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
|
||||||
|
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||||
|
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
|
||||||
|
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
|
||||||
|
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||||
|
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||||
|
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
|
||||||
|
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
|
||||||
|
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||||
|
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
|
||||||
|
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
|
||||||
|
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||||
|
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
|
||||||
|
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
|
||||||
|
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||||
|
|
||||||
|
/* Round 3 */
|
||||||
|
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
|
||||||
|
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
|
||||||
|
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||||
|
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||||
|
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
|
||||||
|
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
|
||||||
|
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
|
||||||
|
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||||
|
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||||
|
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
|
||||||
|
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
|
||||||
|
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
|
||||||
|
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
|
||||||
|
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||||
|
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||||
|
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
|
||||||
|
|
||||||
|
/* Round 4 */
|
||||||
|
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
|
||||||
|
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
|
||||||
|
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||||
|
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
|
||||||
|
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||||
|
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
|
||||||
|
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||||
|
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
|
||||||
|
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
|
||||||
|
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||||
|
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
|
||||||
|
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||||
|
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
|
||||||
|
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||||
|
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
|
||||||
|
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
|
||||||
|
|
||||||
|
state[0] += a;
|
||||||
|
state[1] += b;
|
||||||
|
state[2] += c;
|
||||||
|
state[3] += d;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Zeroize sensitive information.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
MD5_memset((POINTER) x, 0, sizeof(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encodes input (UINT4) into output (unsigned char). Assumes len is a
|
||||||
|
* multiple of 4.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
Encode(unsigned char *output, UINT4 *input, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||||
|
output[j] = (unsigned char) (input[i] & 0xff);
|
||||||
|
output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
|
||||||
|
output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
|
||||||
|
output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decodes input (unsigned char) into output (UINT4). Assumes len is a
|
||||||
|
* multiple of 4.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
Decode(UINT4 *output, unsigned char *input, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||||
|
output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
|
||||||
|
(((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Replace "for loop" with standard memcpy if possible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void
|
||||||
|
MD5_memcpy(POINTER output, POINTER input, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
output[i] = input[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Replace "for loop" with standard memset if possible.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
MD5_memset(POINTER output, int value, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
((char *) output)[i] = (char) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Digests a string
|
||||||
|
*/
|
||||||
|
int my_md5_string(char *string,unsigned char digest[16])
|
||||||
|
{
|
||||||
|
MD5_CTX context;
|
||||||
|
unsigned int len = strlen(string);
|
||||||
|
|
||||||
|
my_md5_init(&context);
|
||||||
|
my_md5_update(&context, (unsigned char *)string, len);
|
||||||
|
my_md5_final(digest, &context);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16])
|
||||||
|
{
|
||||||
|
MD5_CTX context;
|
||||||
|
|
||||||
|
my_md5_init(&context);
|
||||||
|
my_md5_update(&context, (unsigned char *)buffer, len);
|
||||||
|
my_md5_final(digest, &context);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int my_md5_file(char *filename,unsigned char digest[16])
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
MD5_CTX context;
|
||||||
|
int len;
|
||||||
|
unsigned char buffer[1024];
|
||||||
|
|
||||||
|
if ((file = fopen(filename, "rb")) == NULL)
|
||||||
|
return -1;
|
||||||
|
else {
|
||||||
|
my_md5_init(&context);
|
||||||
|
while ((len = fread(buffer, 1, 1024, file)) > 0)
|
||||||
|
{
|
||||||
|
my_md5_update(&context, buffer, len);
|
||||||
|
}
|
||||||
|
my_md5_final(digest, &context);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef MCL_MD5_H
|
||||||
|
#define MCL_MD5_H
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef unsigned char *POINTER;
|
||||||
|
typedef unsigned short int UINT2;
|
||||||
|
typedef unsigned int UINT4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT4 state[4]; /* state (ABCD) */
|
||||||
|
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||||
|
unsigned char buffer[64]; /* input buffer */
|
||||||
|
} MD5_CTX;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** md5 for string
|
||||||
|
* parameters:
|
||||||
|
* string: the string to md5
|
||||||
|
* digest: store the md5 digest
|
||||||
|
* return: 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int my_md5_string(char *string, unsigned char digest[16]);
|
||||||
|
|
||||||
|
/** md5 for file
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename whose content to md5
|
||||||
|
* digest: store the md5 digest
|
||||||
|
* return: 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int my_md5_file(char *filename, unsigned char digest[16]);
|
||||||
|
|
||||||
|
/** md5 for buffer
|
||||||
|
* parameters:
|
||||||
|
* buffer: the buffer to md5
|
||||||
|
* len: the buffer length
|
||||||
|
* digest: store the md5 digest
|
||||||
|
* return: 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16]);
|
||||||
|
|
||||||
|
void my_md5_init (MD5_CTX *);
|
||||||
|
|
||||||
|
void my_md5_update (MD5_CTX *, unsigned char *, unsigned int);
|
||||||
|
|
||||||
|
void my_md5_final (unsigned char [16], MD5_CTX *);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,234 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include "shared_func.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "process_ctrl.h"
|
||||||
|
|
||||||
|
int get_pid_from_file(const char *pidFilename, pid_t *pid)
|
||||||
|
{
|
||||||
|
char buff[32];
|
||||||
|
int64_t file_size;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (access(pidFilename, F_OK) != 0) {
|
||||||
|
return errno != 0 ? errno : EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_size = sizeof(buff) - 1;
|
||||||
|
if ((result=getFileContentEx(pidFilename, buff, 0, &file_size)) != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(buff + file_size) = '\0';
|
||||||
|
*pid = strtol(buff, NULL, 10);
|
||||||
|
if (*pid == 0) {
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_to_pid_file(const char *pidFilename)
|
||||||
|
{
|
||||||
|
char buff[32];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = sprintf(buff, "%d", (int)getpid());
|
||||||
|
return writeToFile(pidFilename, buff, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int delete_pid_file(const char *pidFilename)
|
||||||
|
{
|
||||||
|
if (unlink(pidFilename) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return errno != 0 ? errno : ENOENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_stop(const char *pidFilename, const bool bShowError, pid_t *pid)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=get_pid_from_file(pidFilename, pid)) != 0) {
|
||||||
|
if (bShowError) {
|
||||||
|
if (result == ENOENT) {
|
||||||
|
fprintf(stderr, "pid file: %s not exist!\n", pidFilename);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "get pid from file: %s fail, " \
|
||||||
|
"errno: %d, error info: %s\n",
|
||||||
|
pidFilename, result, strerror(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kill(*pid, SIGTERM) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = errno != 0 ? errno : EPERM;
|
||||||
|
if (bShowError || result != ESRCH) {
|
||||||
|
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
|
||||||
|
(int)*pid, result, strerror(result));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_stop(const char *pidFilename)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
result = do_stop(pidFilename, true, &pid);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
|
||||||
|
do {
|
||||||
|
sleep(1);
|
||||||
|
} while (kill(pid, SIGTERM) == 0);
|
||||||
|
fprintf(stderr, "pid [%d] exit.\n", (int)pid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_restart(const char *pidFilename)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
result = do_stop(pidFilename, false, &pid);
|
||||||
|
if (result == 0) {
|
||||||
|
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
|
||||||
|
do {
|
||||||
|
sleep(1);
|
||||||
|
} while (kill(pid, SIGTERM) == 0);
|
||||||
|
fprintf(stderr, "starting ...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == ENOENT || result == ESRCH) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_exist(const char *pidFilename)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
|
||||||
|
if (result == ENOENT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "get pid from file: %s fail, " \
|
||||||
|
"errno: %d, error info: %s\n",
|
||||||
|
pidFilename, result, strerror(result));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kill(pid, 0) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (errno == ENOENT || errno == ESRCH) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
|
||||||
|
(int)pid, errno, strerror(errno));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_base_path_from_conf_file(const char *filename, char *base_path,
|
||||||
|
const int path_size)
|
||||||
|
{
|
||||||
|
char *pBasePath;
|
||||||
|
IniContext iniContext;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
memset(&iniContext, 0, sizeof(IniContext));
|
||||||
|
if ((result=iniLoadFromFile(filename, &iniContext)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"load conf file \"%s\" fail, ret code: %d", \
|
||||||
|
__LINE__, filename, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
|
||||||
|
if (pBasePath == NULL)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"conf file \"%s\" must have item " \
|
||||||
|
"\"base_path\"!", __LINE__, filename);
|
||||||
|
result = ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(base_path, path_size, "%s", pBasePath);
|
||||||
|
chopPath(base_path);
|
||||||
|
if (!fileExists(base_path))
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"\"%s\" can't be accessed, error info: %s", \
|
||||||
|
__LINE__, base_path, STRERROR(errno));
|
||||||
|
result = errno != 0 ? errno : ENOENT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isDir(base_path))
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"\"%s\" is not a directory!", \
|
||||||
|
__LINE__, base_path);
|
||||||
|
result = ENOTDIR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
iniFreeContext(&iniContext);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int process_action(const char *pidFilename, const char *action, bool *stop)
|
||||||
|
{
|
||||||
|
*stop = false;
|
||||||
|
if (action == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(action, "stop") == 0)
|
||||||
|
{
|
||||||
|
*stop = true;
|
||||||
|
return process_stop(pidFilename);
|
||||||
|
}
|
||||||
|
else if (strcmp(action, "restart") == 0)
|
||||||
|
{
|
||||||
|
return process_restart(pidFilename);
|
||||||
|
}
|
||||||
|
else if (strcmp(action, "start") == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "invalid action: %s\n", action);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
#ifndef PROCESS_CTRL_H
|
||||||
|
#define PROCESS_CTRL_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int get_base_path_from_conf_file(const char *filename, char *base_path,
|
||||||
|
const int path_size);
|
||||||
|
|
||||||
|
int get_pid_from_file(const char *pidFilename, pid_t *pid);
|
||||||
|
|
||||||
|
int write_to_pid_file(const char *pidFilename);
|
||||||
|
|
||||||
|
int delete_pid_file(const char *pidFilename);
|
||||||
|
|
||||||
|
int process_stop(const char *pidFilename);
|
||||||
|
|
||||||
|
int process_restart(const char *pidFilename);
|
||||||
|
|
||||||
|
int process_exist(const char *pidFilename);
|
||||||
|
|
||||||
|
int process_action(const char *pidFilename, const char *action, bool *stop);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,193 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include "pthread_func.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
int init_pthread_lock(pthread_mutex_t *pthread_lock)
|
||||||
|
{
|
||||||
|
pthread_mutexattr_t mat;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_mutexattr_init(&mat)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutexattr_init fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if ((result=pthread_mutexattr_settype(&mat, \
|
||||||
|
PTHREAD_MUTEX_ERRORCHECK)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutexattr_settype fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if ((result=pthread_mutex_init(pthread_lock, &mat)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_mutex_init fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if ((result=pthread_mutexattr_destroy(&mat)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call thread_mutexattr_destroy fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
|
||||||
|
{
|
||||||
|
size_t old_stack_size;
|
||||||
|
size_t new_stack_size;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if ((result=pthread_attr_init(pattr)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_attr_init fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_attr_getstacksize(pattr, &old_stack_size)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_attr_getstacksize fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack_size > 0)
|
||||||
|
{
|
||||||
|
if (old_stack_size != stack_size)
|
||||||
|
{
|
||||||
|
new_stack_size = stack_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_stack_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (old_stack_size < 1 * 1024 * 1024)
|
||||||
|
{
|
||||||
|
new_stack_size = 1 * 1024 * 1024;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_stack_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_stack_size > 0)
|
||||||
|
{
|
||||||
|
if ((result=pthread_attr_setstacksize(pattr, \
|
||||||
|
new_stack_size)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_attr_setstacksize fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=pthread_attr_setdetachstate(pattr, \
|
||||||
|
PTHREAD_CREATE_DETACHED)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"call pthread_attr_setdetachstate fail, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_work_threads(int *count, void *(*start_func)(void *), \
|
||||||
|
void *arg, pthread_t *tids, const int stack_size)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
pthread_attr_t thread_attr;
|
||||||
|
pthread_t *ptid;
|
||||||
|
pthread_t *ptid_end;
|
||||||
|
|
||||||
|
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
ptid_end = tids + (*count);
|
||||||
|
for (ptid=tids; ptid<ptid_end; ptid++)
|
||||||
|
{
|
||||||
|
if ((result=pthread_create(ptid, &thread_attr, \
|
||||||
|
start_func, arg)) != 0)
|
||||||
|
{
|
||||||
|
*count = ptid - tids;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"create thread failed, startup threads: %d, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, *count, \
|
||||||
|
result, STRERROR(result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_attr_destroy(&thread_attr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int kill_work_threads(pthread_t *tids, const int count)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
pthread_t *ptid;
|
||||||
|
pthread_t *ptid_end;
|
||||||
|
|
||||||
|
ptid_end = tids + count;
|
||||||
|
for (ptid=tids; ptid<ptid_end; ptid++)
|
||||||
|
{
|
||||||
|
if ((result=pthread_kill(*ptid, SIGINT)) != 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"kill thread failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef PTHREAD_FUNC_H
|
||||||
|
#define PTHREAD_FUNC_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int init_pthread_lock(pthread_mutex_t *pthread_lock);
|
||||||
|
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size);
|
||||||
|
|
||||||
|
int create_work_threads(int *count, void *(*start_func)(void *), \
|
||||||
|
void *arg, pthread_t *tids, const int stack_size);
|
||||||
|
int kill_work_threads(pthread_t *tids, const int count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,256 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "pthread_pool.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
*the thread pool
|
||||||
|
*/
|
||||||
|
static threadpool_info_t *pool;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the thread callback function proxy
|
||||||
|
* parameters:
|
||||||
|
* arg:the thread callback function parameter
|
||||||
|
*/
|
||||||
|
static void *callback_proxy(void *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* push the thread into the pool
|
||||||
|
* parameters:
|
||||||
|
* thread:the thread will push into the poolbool
|
||||||
|
* return:
|
||||||
|
* 0:success
|
||||||
|
* >0 : fail
|
||||||
|
*/
|
||||||
|
static int push2pool(thread_info_t *thread);
|
||||||
|
|
||||||
|
static void *callback_proxy(void *arg)
|
||||||
|
{
|
||||||
|
thread_info_t* thread = (thread_info_t *) arg;
|
||||||
|
while(initialized == pool->state)
|
||||||
|
{
|
||||||
|
thread->func(thread->arg);
|
||||||
|
|
||||||
|
if(pool == NULL || initialized != pool->state) break;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&thread->mutex_locker);
|
||||||
|
|
||||||
|
if(0 == push2pool(thread))
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&thread->run_locker,&thread->mutex_locker);
|
||||||
|
pthread_mutex_unlock(&thread->mutex_locker);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock( &thread->mutex_locker );
|
||||||
|
pthread_cond_destroy( &thread->run_locker );
|
||||||
|
pthread_mutex_destroy( &thread->mutex_locker );
|
||||||
|
|
||||||
|
free( thread );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&pool->mutex_locker);
|
||||||
|
pool->current_size --;
|
||||||
|
if(0 >= pool->current_size) pthread_cond_signal(&pool->empty_locker);
|
||||||
|
pthread_mutex_unlock(&pool->mutex_locker);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int push2pool(thread_info_t *thread)
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&pool->mutex_locker);
|
||||||
|
if( pool->current_index < pool->total_size )
|
||||||
|
{
|
||||||
|
pool->list[ pool->current_index ] = thread;
|
||||||
|
pool->current_index++;
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
pthread_cond_signal( &pool->run_locker);
|
||||||
|
|
||||||
|
if( pool->current_index >= pool->current_size )
|
||||||
|
{
|
||||||
|
pthread_cond_signal( &pool->full_locker );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}while(0);
|
||||||
|
pthread_mutex_unlock(&pool->mutex_locker);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int threadpool_init(int size)
|
||||||
|
{
|
||||||
|
if(0 >= size)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = (threadpool_info_t *) malloc(sizeof(threadpool_info_t));
|
||||||
|
if(NULL == pool)
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
memset(pool,0,sizeof(threadpool_info_t));
|
||||||
|
pool->state = initializing;
|
||||||
|
pool->total_size = size;
|
||||||
|
pool->current_size = 0;
|
||||||
|
pool->current_index = 0;
|
||||||
|
pthread_mutex_init(&pool->mutex_locker,NULL);
|
||||||
|
pthread_cond_init(&pool->run_locker,NULL);
|
||||||
|
pthread_cond_init(&pool->empty_locker,NULL);
|
||||||
|
pthread_cond_init(&pool->full_locker,NULL);
|
||||||
|
|
||||||
|
pool->list = (thread_info_t **) malloc(sizeof(thread_info_t*) * size);
|
||||||
|
if(NULL == pool->list)
|
||||||
|
{
|
||||||
|
pthread_cond_destroy(&pool->run_locker);
|
||||||
|
pthread_cond_destroy(&pool->empty_locker);
|
||||||
|
pthread_cond_destroy(&pool->full_locker);
|
||||||
|
pthread_mutex_destroy(&pool->mutex_locker);
|
||||||
|
free(pool);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->state = initialized;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int threadpool_run(callback func,void *arg)
|
||||||
|
{
|
||||||
|
if(NULL == pool)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&pool->mutex_locker);
|
||||||
|
if(NULL == pool || initialized != pool->state) //the pool cannot use
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//current size is >= the max pool size and all thread are busy now
|
||||||
|
while(pool->current_index <= 0 && pool->current_size >= pool->total_size)
|
||||||
|
{
|
||||||
|
pthread_cond_wait(&pool->run_locker,&pool->mutex_locker);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0 >= pool->current_index)
|
||||||
|
{
|
||||||
|
thread_info_t * thread = (thread_info_t *) malloc(sizeof(thread_info_t));
|
||||||
|
if(NULL == thread)
|
||||||
|
{
|
||||||
|
result = -2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memset(thread,0,sizeof(thread_info_t));
|
||||||
|
|
||||||
|
pthread_mutex_init(&thread->mutex_locker,NULL);
|
||||||
|
pthread_cond_init(&thread->run_locker,NULL);
|
||||||
|
pthread_attr_t attr;
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
|
||||||
|
|
||||||
|
thread->arg = arg;
|
||||||
|
thread->func = func;
|
||||||
|
|
||||||
|
if(0 == pthread_create(&thread->id,&attr,callback_proxy,thread))
|
||||||
|
{
|
||||||
|
pool->current_size ++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = -3;
|
||||||
|
pthread_mutex_destroy(&thread->mutex_locker);
|
||||||
|
pthread_cond_destroy(&thread->run_locker);
|
||||||
|
free(thread);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pool->current_index --;//because the array begin with 0
|
||||||
|
thread_info_t *thread = pool->list[ pool->current_index ];
|
||||||
|
pool->list[ pool->current_index ] = NULL;
|
||||||
|
|
||||||
|
thread->func = func;
|
||||||
|
thread->arg = arg;
|
||||||
|
|
||||||
|
pthread_mutex_lock( &thread->mutex_locker );
|
||||||
|
pthread_cond_signal( &thread->run_locker ) ;
|
||||||
|
pthread_mutex_unlock ( &thread->mutex_locker );
|
||||||
|
}
|
||||||
|
}while(0);
|
||||||
|
pthread_mutex_unlock(&pool->mutex_locker);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int threadpool_free()
|
||||||
|
{
|
||||||
|
if(NULL == pool) return 0;
|
||||||
|
|
||||||
|
pthread_mutex_lock( &pool->mutex_locker);
|
||||||
|
|
||||||
|
if( pool->current_index < pool->current_size )
|
||||||
|
{
|
||||||
|
pthread_cond_wait( &pool->full_locker, &pool->mutex_locker );
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->state = uninstalling;
|
||||||
|
int i = 0;
|
||||||
|
for( i = 0; i < pool->current_index; i++ )
|
||||||
|
{
|
||||||
|
thread_info_t *thread = pool->list[i];
|
||||||
|
|
||||||
|
pthread_mutex_lock( &thread->mutex_locker );
|
||||||
|
pthread_cond_signal( &thread->run_locker ) ;
|
||||||
|
pthread_mutex_unlock ( &thread->mutex_locker );
|
||||||
|
}
|
||||||
|
|
||||||
|
if(0 < pool->current_size)
|
||||||
|
{
|
||||||
|
pthread_cond_wait( &pool->empty_locker, &pool->mutex_locker);
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < pool->current_index; i++ )
|
||||||
|
{
|
||||||
|
free( pool->list[ i ] );
|
||||||
|
pool->list[ i ] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock( &pool->mutex_locker );
|
||||||
|
|
||||||
|
pool->current_index = 0;
|
||||||
|
|
||||||
|
pthread_mutex_destroy( &pool->mutex_locker );
|
||||||
|
pthread_cond_destroy( &pool->run_locker );
|
||||||
|
pthread_cond_destroy( &pool->full_locker );
|
||||||
|
pthread_cond_destroy( &pool->empty_locker );
|
||||||
|
|
||||||
|
free( pool->list );
|
||||||
|
pool->list = NULL;
|
||||||
|
free( pool);
|
||||||
|
pool = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
|
||||||
|
*
|
||||||
|
* FastLib may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastLib source kit.
|
||||||
|
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef PTHREAD_POOL_H_
|
||||||
|
#define PTHREAD_POOL_H_
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* define the callback function type of thread
|
||||||
|
*/
|
||||||
|
typedef void (*callback)(void *);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the thread pool state
|
||||||
|
* member:
|
||||||
|
* uninit : not initialize the thread pool.
|
||||||
|
* initing : initializing the thread pool.
|
||||||
|
* using : the pool can use.
|
||||||
|
* uninstalling : uninstalling the thread pool.
|
||||||
|
* uninstalled : uninstall the thread pool is over.
|
||||||
|
*/
|
||||||
|
typedef enum threadpool_state
|
||||||
|
{
|
||||||
|
uninitialized,
|
||||||
|
initializing,
|
||||||
|
initialized,
|
||||||
|
uninstalling,
|
||||||
|
uninstalled,
|
||||||
|
}thread_state_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* define the thread type which in the pool
|
||||||
|
* members:
|
||||||
|
* id : the thread id
|
||||||
|
* mutex_locker : the mutext locker
|
||||||
|
* run_locker : the locker for noticing the thread do running or waitting
|
||||||
|
* func : the callback function for thread
|
||||||
|
* arg : the callback parameter
|
||||||
|
*/
|
||||||
|
typedef struct thread_info
|
||||||
|
{
|
||||||
|
pthread_t id;
|
||||||
|
pthread_mutex_t mutex_locker;
|
||||||
|
pthread_cond_t run_locker;
|
||||||
|
callback func;
|
||||||
|
void *arg;
|
||||||
|
}thread_info_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* the structure for the thread pool
|
||||||
|
* member:
|
||||||
|
* list : the initialazed thread list
|
||||||
|
* mutex_locker : the mutex locker for the thread operation.
|
||||||
|
* run_locker : the locker for noticing the thread do running or waitting.
|
||||||
|
* full_locker : the locker notice the thread is stoping when free the thread pool and the pool is not full .
|
||||||
|
* empry_Locker : the locker notice the thread waitting for the busy thread work over,then do with the thread.
|
||||||
|
* state : the pool's current state.
|
||||||
|
* total_size : the pool max size;
|
||||||
|
* current_size : the thread count for the current pool ;
|
||||||
|
* current_index : the busy thread in the pool index.
|
||||||
|
*/
|
||||||
|
typedef struct threadpool_info
|
||||||
|
{
|
||||||
|
thread_info_t **list;
|
||||||
|
pthread_mutex_t mutex_locker;
|
||||||
|
pthread_cond_t run_locker;
|
||||||
|
pthread_cond_t full_locker;
|
||||||
|
pthread_cond_t empty_locker;
|
||||||
|
thread_state_t state;
|
||||||
|
int total_size;
|
||||||
|
int current_size;
|
||||||
|
int current_index;
|
||||||
|
}threadpool_info_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* initialize the thread pool
|
||||||
|
* parameters:
|
||||||
|
* size : thread pool max size
|
||||||
|
* return:
|
||||||
|
* 0:initialize pool success;
|
||||||
|
* -1:the size parameter is less 0;
|
||||||
|
* -2:initialize pool is fail,malloc memory for pool or pool->list is error;
|
||||||
|
*/
|
||||||
|
int threadpool_init(int size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* run the function with the thread from pool
|
||||||
|
* parameter:
|
||||||
|
* func:the thread callback function
|
||||||
|
* arg:the parameter of callback function
|
||||||
|
* return:
|
||||||
|
* 0 : success
|
||||||
|
* -1: the pool is NULL;
|
||||||
|
* -2 : malloc memory for thread is error;
|
||||||
|
* -3 : create thread is error;
|
||||||
|
*/
|
||||||
|
int threadpool_run(callback func,void *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* free and destroy the thread pool memory
|
||||||
|
* return:
|
||||||
|
* 0 : success
|
||||||
|
* less 0 : fail
|
||||||
|
*/
|
||||||
|
int threadpool_destroy();
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PTHREAD_POOL_H_ */
|
||||||
|
|
@ -0,0 +1,508 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "sched_thread.h"
|
||||||
|
#include "shared_func.h"
|
||||||
|
#include "pthread_func.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
volatile bool g_schedule_flag = false;
|
||||||
|
volatile time_t g_current_time = 0;
|
||||||
|
|
||||||
|
static ScheduleArray waiting_schedule_array = {NULL, 0};
|
||||||
|
static int waiting_del_id = -1;
|
||||||
|
|
||||||
|
static int sched_cmp_by_next_call_time(const void *p1, const void *p2)
|
||||||
|
{
|
||||||
|
return ((ScheduleEntry *)p1)->next_call_time - \
|
||||||
|
((ScheduleEntry *)p2)->next_call_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sched_init_entries(ScheduleArray *pScheduleArray)
|
||||||
|
{
|
||||||
|
ScheduleEntry *pEntry;
|
||||||
|
ScheduleEntry *pEnd;
|
||||||
|
time_t time_base;
|
||||||
|
struct tm tm_current;
|
||||||
|
struct tm tm_base;
|
||||||
|
|
||||||
|
if (pScheduleArray->count < 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"schedule count %d < 0", \
|
||||||
|
__LINE__, pScheduleArray->count);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if (pScheduleArray->count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_current_time = time(NULL);
|
||||||
|
localtime_r((time_t *)&g_current_time, &tm_current);
|
||||||
|
pEnd = pScheduleArray->entries + pScheduleArray->count;
|
||||||
|
for (pEntry=pScheduleArray->entries; pEntry<pEnd; pEntry++)
|
||||||
|
{
|
||||||
|
if (pEntry->interval <= 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"shedule interval %d <= 0", \
|
||||||
|
__LINE__, pEntry->interval);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pEntry->time_base.hour == TIME_NONE)
|
||||||
|
{
|
||||||
|
pEntry->next_call_time = g_current_time + \
|
||||||
|
pEntry->interval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tm_current.tm_hour > pEntry->time_base.hour || \
|
||||||
|
(tm_current.tm_hour == pEntry->time_base.hour \
|
||||||
|
&& tm_current.tm_min >= pEntry->time_base.minute))
|
||||||
|
{
|
||||||
|
memcpy(&tm_base, &tm_current, sizeof(struct tm));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
time_base = g_current_time - 24 * 3600;
|
||||||
|
localtime_r(&time_base, &tm_base);
|
||||||
|
}
|
||||||
|
|
||||||
|
tm_base.tm_hour = pEntry->time_base.hour;
|
||||||
|
tm_base.tm_min = pEntry->time_base.minute;
|
||||||
|
tm_base.tm_sec = 0;
|
||||||
|
time_base = mktime(&tm_base);
|
||||||
|
|
||||||
|
pEntry->next_call_time = g_current_time + \
|
||||||
|
pEntry->interval - (g_current_time - \
|
||||||
|
time_base) % pEntry->interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
char buff1[32];
|
||||||
|
char buff2[32];
|
||||||
|
logInfo("id=%d, current time=%s, first call time=%s\n", \
|
||||||
|
pEntry->id, formatDatetime(g_current_time, \
|
||||||
|
"%Y-%m-%d %H:%M:%S", buff1, sizeof(buff1)), \
|
||||||
|
formatDatetime(pEntry->next_call_time, \
|
||||||
|
"%Y-%m-%d %H:%M:%S", buff2, sizeof(buff2)));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sched_make_chain(ScheduleContext *pContext)
|
||||||
|
{
|
||||||
|
ScheduleArray *pScheduleArray;
|
||||||
|
ScheduleEntry *pEntry;
|
||||||
|
|
||||||
|
pScheduleArray = &(pContext->scheduleArray);
|
||||||
|
if (pScheduleArray->count == 0)
|
||||||
|
{
|
||||||
|
pContext->head = NULL;
|
||||||
|
pContext->tail = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(pScheduleArray->entries, pScheduleArray->count, \
|
||||||
|
sizeof(ScheduleEntry), sched_cmp_by_next_call_time);
|
||||||
|
|
||||||
|
pContext->head = pScheduleArray->entries;
|
||||||
|
pContext->tail = pScheduleArray->entries + (pScheduleArray->count - 1);
|
||||||
|
for (pEntry=pScheduleArray->entries; pEntry<pContext->tail; pEntry++)
|
||||||
|
{
|
||||||
|
pEntry->next = pEntry + 1;
|
||||||
|
}
|
||||||
|
pContext->tail->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sched_check_waiting(ScheduleContext *pContext)
|
||||||
|
{
|
||||||
|
ScheduleArray *pScheduleArray;
|
||||||
|
ScheduleEntry *newEntries;
|
||||||
|
ScheduleEntry *pWaitingEntry;
|
||||||
|
ScheduleEntry *pWaitingEnd;
|
||||||
|
ScheduleEntry *pSchedEntry;
|
||||||
|
ScheduleEntry *pSchedEnd;
|
||||||
|
int allocCount;
|
||||||
|
int newCount;
|
||||||
|
int result;
|
||||||
|
int deleteCount;
|
||||||
|
|
||||||
|
pScheduleArray = &(pContext->scheduleArray);
|
||||||
|
deleteCount = 0;
|
||||||
|
if (waiting_del_id >= 0)
|
||||||
|
{
|
||||||
|
pSchedEnd = pScheduleArray->entries + pScheduleArray->count;
|
||||||
|
for (pSchedEntry=pScheduleArray->entries; \
|
||||||
|
pSchedEntry<pSchedEnd; pSchedEntry++)
|
||||||
|
{
|
||||||
|
if (pSchedEntry->id == waiting_del_id)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSchedEntry < pSchedEnd)
|
||||||
|
{
|
||||||
|
pSchedEntry++;
|
||||||
|
while (pSchedEntry < pSchedEnd)
|
||||||
|
{
|
||||||
|
memcpy(pSchedEntry - 1, pSchedEntry, \
|
||||||
|
sizeof(ScheduleEntry));
|
||||||
|
pSchedEntry++;
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteCount++;
|
||||||
|
pScheduleArray->count--;
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"delete task id: %d, " \
|
||||||
|
"current schedule count: %d", __LINE__, \
|
||||||
|
waiting_del_id, pScheduleArray->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
waiting_del_id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (waiting_schedule_array.count == 0)
|
||||||
|
{
|
||||||
|
if (deleteCount > 0)
|
||||||
|
{
|
||||||
|
sched_make_chain(pContext);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocCount = pScheduleArray->count + waiting_schedule_array.count;
|
||||||
|
newEntries = (ScheduleEntry *)malloc(sizeof(ScheduleEntry) * allocCount);
|
||||||
|
if (newEntries == NULL)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, (int)sizeof(ScheduleEntry) * allocCount, \
|
||||||
|
result, STRERROR(result));
|
||||||
|
|
||||||
|
if (deleteCount > 0)
|
||||||
|
{
|
||||||
|
sched_make_chain(pContext);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pScheduleArray->count > 0)
|
||||||
|
{
|
||||||
|
memcpy(newEntries, pScheduleArray->entries, \
|
||||||
|
sizeof(ScheduleEntry) * pScheduleArray->count);
|
||||||
|
}
|
||||||
|
newCount = pScheduleArray->count;
|
||||||
|
pWaitingEnd = waiting_schedule_array.entries + waiting_schedule_array.count;
|
||||||
|
for (pWaitingEntry=waiting_schedule_array.entries; \
|
||||||
|
pWaitingEntry<pWaitingEnd; pWaitingEntry++)
|
||||||
|
{
|
||||||
|
pSchedEnd = newEntries + newCount;
|
||||||
|
for (pSchedEntry=newEntries; pSchedEntry<pSchedEnd; \
|
||||||
|
pSchedEntry++)
|
||||||
|
{
|
||||||
|
if (pWaitingEntry->id == pSchedEntry->id)
|
||||||
|
{
|
||||||
|
memcpy(pSchedEntry, pWaitingEntry, \
|
||||||
|
sizeof(ScheduleEntry));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSchedEntry == pSchedEnd)
|
||||||
|
{
|
||||||
|
memcpy(pSchedEntry, pWaitingEntry, \
|
||||||
|
sizeof(ScheduleEntry));
|
||||||
|
newCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"schedule add entries: %d, replace entries: %d",
|
||||||
|
__LINE__, newCount - pScheduleArray->count, \
|
||||||
|
waiting_schedule_array.count - (newCount - pScheduleArray->count));
|
||||||
|
|
||||||
|
if (pScheduleArray->entries != NULL)
|
||||||
|
{
|
||||||
|
free(pScheduleArray->entries);
|
||||||
|
}
|
||||||
|
pScheduleArray->entries = newEntries;
|
||||||
|
pScheduleArray->count = newCount;
|
||||||
|
|
||||||
|
free(waiting_schedule_array.entries);
|
||||||
|
waiting_schedule_array.count = 0;
|
||||||
|
waiting_schedule_array.entries = NULL;
|
||||||
|
|
||||||
|
sched_make_chain(pContext);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *sched_thread_entrance(void *args)
|
||||||
|
{
|
||||||
|
ScheduleContext *pContext;
|
||||||
|
ScheduleEntry *pPrevious;
|
||||||
|
ScheduleEntry *pCurrent;
|
||||||
|
ScheduleEntry *pSaveNext;
|
||||||
|
ScheduleEntry *pNode;
|
||||||
|
ScheduleEntry *pUntil;
|
||||||
|
int exec_count;
|
||||||
|
int i;
|
||||||
|
int sleep_time;
|
||||||
|
|
||||||
|
pContext = (ScheduleContext *)args;
|
||||||
|
if (sched_init_entries(&(pContext->scheduleArray)) != 0)
|
||||||
|
{
|
||||||
|
free(pContext);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sched_make_chain(pContext);
|
||||||
|
|
||||||
|
g_schedule_flag = true;
|
||||||
|
while (*(pContext->pcontinue_flag))
|
||||||
|
{
|
||||||
|
sched_check_waiting(pContext);
|
||||||
|
if (pContext->scheduleArray.count == 0) //no schedule entry
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
g_current_time = time(NULL);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_current_time = time(NULL);
|
||||||
|
sleep_time = pContext->head->next_call_time - g_current_time;
|
||||||
|
|
||||||
|
/*
|
||||||
|
//fprintf(stderr, "count=%d, sleep_time=%d\n", \
|
||||||
|
pContext->scheduleArray.count, sleep_time);
|
||||||
|
*/
|
||||||
|
while (sleep_time > 0 && *(pContext->pcontinue_flag))
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
g_current_time = time(NULL);
|
||||||
|
if (sched_check_waiting(pContext) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep_time--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(*(pContext->pcontinue_flag)))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
exec_count = 0;
|
||||||
|
pCurrent = pContext->head;
|
||||||
|
while (*(pContext->pcontinue_flag) && (pCurrent != NULL \
|
||||||
|
&& pCurrent->next_call_time <= g_current_time))
|
||||||
|
{
|
||||||
|
//fprintf(stderr, "exec task id=%d\n", pCurrent->id);
|
||||||
|
pCurrent->task_func(pCurrent->func_args);
|
||||||
|
pCurrent->next_call_time = g_current_time + \
|
||||||
|
pCurrent->interval;
|
||||||
|
pCurrent = pCurrent->next;
|
||||||
|
exec_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exec_count == 0 || pContext->scheduleArray.count == 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exec_count > pContext->scheduleArray.count / 2)
|
||||||
|
{
|
||||||
|
sched_make_chain(pContext);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pNode = pContext->head;
|
||||||
|
pContext->head = pCurrent; //new chain head
|
||||||
|
for (i=0; i<exec_count; i++)
|
||||||
|
{
|
||||||
|
if (pNode->next_call_time >= pContext->tail->next_call_time)
|
||||||
|
{
|
||||||
|
pContext->tail->next = pNode;
|
||||||
|
pContext->tail = pNode;
|
||||||
|
pNode = pNode->next;
|
||||||
|
pContext->tail->next = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pPrevious = NULL;
|
||||||
|
pUntil = pContext->head;
|
||||||
|
while (pUntil != NULL && \
|
||||||
|
pNode->next_call_time > pUntil->next_call_time)
|
||||||
|
{
|
||||||
|
pPrevious = pUntil;
|
||||||
|
pUntil = pUntil->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pSaveNext = pNode->next;
|
||||||
|
if (pPrevious == NULL)
|
||||||
|
{
|
||||||
|
pContext->head = pNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pPrevious->next = pNode;
|
||||||
|
}
|
||||||
|
pNode->next = pUntil;
|
||||||
|
|
||||||
|
pNode = pSaveNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_schedule_flag = false;
|
||||||
|
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"schedule thread exit", __LINE__);
|
||||||
|
|
||||||
|
free(pContext);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sched_dup_array(const ScheduleArray *pSrcArray, \
|
||||||
|
ScheduleArray *pDestArray)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
if (pSrcArray->count == 0)
|
||||||
|
{
|
||||||
|
pDestArray->entries = NULL;
|
||||||
|
pDestArray->count = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = sizeof(ScheduleEntry) * pSrcArray->count;
|
||||||
|
pDestArray->entries = (ScheduleEntry *)malloc(bytes);
|
||||||
|
if (pDestArray->entries == NULL)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, bytes, result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pDestArray->entries, pSrcArray->entries, bytes);
|
||||||
|
pDestArray->count = pSrcArray->count;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_add_entries(const ScheduleArray *pScheduleArray)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (pScheduleArray->count == 0)
|
||||||
|
{
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"no schedule entry", __LINE__);
|
||||||
|
return ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (waiting_schedule_array.entries != NULL)
|
||||||
|
{
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"waiting for schedule array ready ...", __LINE__);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=sched_dup_array(pScheduleArray, &waiting_schedule_array))!=0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sched_init_entries(&waiting_schedule_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_del_entry(const int id)
|
||||||
|
{
|
||||||
|
if (id < 0)
|
||||||
|
{
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"id: %d is invalid!", __LINE__, id);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (waiting_del_id >= 0)
|
||||||
|
{
|
||||||
|
logDebug("file: "__FILE__", line: %d, " \
|
||||||
|
"waiting for delete ready ...", __LINE__);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
waiting_del_id = id;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid, \
|
||||||
|
const int stack_size, bool * volatile pcontinue_flag)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
pthread_attr_t thread_attr;
|
||||||
|
ScheduleContext *pContext;
|
||||||
|
|
||||||
|
pContext = (ScheduleContext *)malloc(sizeof(ScheduleContext));
|
||||||
|
if (pContext == NULL)
|
||||||
|
{
|
||||||
|
result = errno != 0 ? errno : ENOMEM;
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"malloc %d bytes failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, (int)sizeof(ScheduleContext), \
|
||||||
|
result, STRERROR(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
|
||||||
|
{
|
||||||
|
free(pContext);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result=sched_dup_array(pScheduleArray, \
|
||||||
|
&(pContext->scheduleArray))) != 0)
|
||||||
|
{
|
||||||
|
free(pContext);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pContext->pcontinue_flag = pcontinue_flag;
|
||||||
|
if ((result=pthread_create(ptid, &thread_attr, \
|
||||||
|
sched_thread_entrance, pContext)) != 0)
|
||||||
|
{
|
||||||
|
free(pContext);
|
||||||
|
logError("file: "__FILE__", line: %d, " \
|
||||||
|
"create thread failed, " \
|
||||||
|
"errno: %d, error info: %s", \
|
||||||
|
__LINE__, result, STRERROR(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_attr_destroy(&thread_attr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef _SCHED_THREAD_H_
|
||||||
|
#define _SCHED_THREAD_H_
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
typedef int (*TaskFunc) (void *args);
|
||||||
|
|
||||||
|
typedef struct tagScheduleEntry
|
||||||
|
{
|
||||||
|
int id; //the task id
|
||||||
|
|
||||||
|
/* the time base to execute task, such as 00:00, interval is 3600,
|
||||||
|
means execute the task every hour as 1:00, 2:00, 3:00 etc. */
|
||||||
|
TimeInfo time_base;
|
||||||
|
|
||||||
|
int interval; //the interval for execute task, unit is second
|
||||||
|
|
||||||
|
TaskFunc task_func; //callback function
|
||||||
|
void *func_args; //arguments pass to callback function
|
||||||
|
|
||||||
|
/* following are internal fields, do not set manually! */
|
||||||
|
time_t next_call_time;
|
||||||
|
struct tagScheduleEntry *next;
|
||||||
|
} ScheduleEntry;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ScheduleEntry *entries;
|
||||||
|
int count;
|
||||||
|
} ScheduleArray;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
ScheduleArray scheduleArray;
|
||||||
|
ScheduleEntry *head; //schedule chain head
|
||||||
|
ScheduleEntry *tail; //schedule chain tail
|
||||||
|
bool *pcontinue_flag;
|
||||||
|
} ScheduleContext;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern volatile bool g_schedule_flag; //schedule continue running flag
|
||||||
|
extern volatile time_t g_current_time; //the current time
|
||||||
|
|
||||||
|
|
||||||
|
#define get_current_time() (g_schedule_flag ? g_current_time: time(NULL))
|
||||||
|
|
||||||
|
int sched_add_entries(const ScheduleArray *pScheduleArray);
|
||||||
|
int sched_del_entry(const int id);
|
||||||
|
|
||||||
|
/** execute the schedule thread
|
||||||
|
* parameters:
|
||||||
|
* pScheduleArray: schedule task
|
||||||
|
* ptid: store the schedule thread id
|
||||||
|
* stack_size: set thread stack size (byes)
|
||||||
|
* pcontinue_flag: main process continue running flag
|
||||||
|
* return: error no, 0 for success, != 0 fail
|
||||||
|
*/
|
||||||
|
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid, \
|
||||||
|
const int stack_size, bool * volatile pcontinue_flag);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,495 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef SHARED_FUNC_H
|
||||||
|
#define SHARED_FUNC_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#include "common_define.h"
|
||||||
|
#include "ini_file_reader.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** lowercase the string
|
||||||
|
* parameters:
|
||||||
|
* src: input string, will be changed
|
||||||
|
* return: lowercased string
|
||||||
|
*/
|
||||||
|
char *toLowercase(char *src);
|
||||||
|
|
||||||
|
/** uppercase the string
|
||||||
|
* parameters:
|
||||||
|
* src: input string, will be changed
|
||||||
|
* return: uppercased string
|
||||||
|
*/
|
||||||
|
char *toUppercase(char *src);
|
||||||
|
|
||||||
|
|
||||||
|
/** date format to string
|
||||||
|
* parameters:
|
||||||
|
* nTime: unix timestamp
|
||||||
|
* szDateFormat: date format, more detail man strftime
|
||||||
|
* buff: store the formated result, can be NULL
|
||||||
|
* buff_size: buffer size, max bytes can contain
|
||||||
|
* return: formated date string
|
||||||
|
*/
|
||||||
|
char *formatDatetime(const time_t nTime, \
|
||||||
|
const char *szDateFormat, \
|
||||||
|
char *buff, const int buff_size);
|
||||||
|
|
||||||
|
/** get character count, only support GB charset
|
||||||
|
* parameters:
|
||||||
|
* s: the string
|
||||||
|
* return: character count
|
||||||
|
*/
|
||||||
|
int getCharLen(const char *s);
|
||||||
|
|
||||||
|
/** replace \r and \n to space
|
||||||
|
* parameters:
|
||||||
|
* s: the string
|
||||||
|
* return: replaced string
|
||||||
|
*/
|
||||||
|
char *replaceCRLF2Space(char *s);
|
||||||
|
|
||||||
|
/** get the filename absolute path
|
||||||
|
* parameters:
|
||||||
|
* fileame: the filename
|
||||||
|
* szAbsPath: store the absolute path
|
||||||
|
* pathSize: max bytes to contain
|
||||||
|
* return: absolute path, NULL for fail
|
||||||
|
*/
|
||||||
|
char *getAbsolutePath(const char *fileame, char *szAbsPath, \
|
||||||
|
const int pathSize);
|
||||||
|
|
||||||
|
/** get the executable file absolute filename
|
||||||
|
* parameters:
|
||||||
|
* exeFilename: the executable filename
|
||||||
|
* szAbsFilename: store the absolute filename
|
||||||
|
* maxSize: max bytes to contain
|
||||||
|
* return: absolute filename, NULL for fail
|
||||||
|
*/
|
||||||
|
char *getExeAbsoluteFilename(const char *exeFilename, char *szAbsFilename, \
|
||||||
|
const int maxSize);
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
|
||||||
|
/** get running process count by program name such as fdfs_trackerd
|
||||||
|
* parameters:
|
||||||
|
* progName: the program name
|
||||||
|
* bAllOwners: false for only get my proccess count
|
||||||
|
* return: proccess count, >= 0 success, < 0 fail
|
||||||
|
*/
|
||||||
|
int getProccessCount(const char *progName, const bool bAllOwners);
|
||||||
|
|
||||||
|
/** get running process ids by program name such as fdfs_trackerd
|
||||||
|
* parameters:
|
||||||
|
* progName: the program name
|
||||||
|
* bAllOwners: false for only get my proccess count
|
||||||
|
* pids: store the pids
|
||||||
|
* arrSize: max pids
|
||||||
|
* return: proccess count, >= 0 success, < 0 fail
|
||||||
|
*/
|
||||||
|
int getUserProcIds(const char *progName, const bool bAllOwners, \
|
||||||
|
int pids[], const int arrSize);
|
||||||
|
|
||||||
|
/** execute program, get it's output
|
||||||
|
* parameters:
|
||||||
|
* command: the program
|
||||||
|
* output: store ouput result
|
||||||
|
* buff_size: output max size (bytes)
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int getExecResult(const char *command, char *output, const int buff_size);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** daemon init
|
||||||
|
* parameters:
|
||||||
|
* bCloseFiles: if close the stdin, stdout and stderr
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void daemon_init(bool bCloseFiles);
|
||||||
|
|
||||||
|
/** convert buffer content to hex string such as 0B82A1
|
||||||
|
* parameters:
|
||||||
|
* s: the buffer
|
||||||
|
* len: the buffer length
|
||||||
|
* szHexBuff: store the hex string (must have enough space)
|
||||||
|
* return: hex string (szHexBuff)
|
||||||
|
*/
|
||||||
|
char *bin2hex(const char *s, const int len, char *szHexBuff);
|
||||||
|
|
||||||
|
/** parse hex string to binary content
|
||||||
|
* parameters:
|
||||||
|
* s: the hex string such as 8B04CD
|
||||||
|
* szBinBuff: store the converted binary content(must have enough space)
|
||||||
|
* nDestLen: store the converted content length
|
||||||
|
* return: converted binary content (szBinBuff)
|
||||||
|
*/
|
||||||
|
char *hex2bin(const char *s, char *szBinBuff, int *nDestLen);
|
||||||
|
|
||||||
|
/** print binary buffer as hex string
|
||||||
|
* parameters:
|
||||||
|
* s: the buffer
|
||||||
|
* len: the buffer length
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void printBuffHex(const char *s, const int len);
|
||||||
|
|
||||||
|
/** 32 bits int convert to buffer (big-endian)
|
||||||
|
* parameters:
|
||||||
|
* n: 32 bits int value
|
||||||
|
* buff: the buffer, at least 4 bytes space, no tail \0
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void int2buff(const int n, char *buff);
|
||||||
|
|
||||||
|
/** buffer convert to 32 bits int
|
||||||
|
* parameters:
|
||||||
|
* buff: big-endian 4 bytes buffer
|
||||||
|
* return: 32 bits int value
|
||||||
|
*/
|
||||||
|
int buff2int(const char *buff);
|
||||||
|
|
||||||
|
/** long (64 bits) convert to buffer (big-endian)
|
||||||
|
* parameters:
|
||||||
|
* n: 64 bits int value
|
||||||
|
* buff: the buffer, at least 8 bytes space, no tail \0
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void long2buff(int64_t n, char *buff);
|
||||||
|
|
||||||
|
/** buffer convert to 64 bits int
|
||||||
|
* parameters:
|
||||||
|
* buff: big-endian 8 bytes buffer
|
||||||
|
* return: 64 bits int value
|
||||||
|
*/
|
||||||
|
int64_t buff2long(const char *buff);
|
||||||
|
|
||||||
|
/** trim leading spaces ( \t\r\n)
|
||||||
|
* parameters:
|
||||||
|
* pStr: the string to trim
|
||||||
|
* return: trimed string porinter as pStr
|
||||||
|
*/
|
||||||
|
char *trim_left(char *pStr);
|
||||||
|
|
||||||
|
/** trim tail spaces ( \t\r\n)
|
||||||
|
* parameters:
|
||||||
|
* pStr: the string to trim
|
||||||
|
* return: trimed string porinter as pStr
|
||||||
|
*/
|
||||||
|
char *trim_right(char *pStr);
|
||||||
|
|
||||||
|
/** trim leading and tail spaces ( \t\r\n)
|
||||||
|
* parameters:
|
||||||
|
* pStr: the string to trim
|
||||||
|
* return: trimed string porinter as pStr
|
||||||
|
*/
|
||||||
|
char *trim(char *pStr);
|
||||||
|
|
||||||
|
/** copy string to BufferInfo
|
||||||
|
* parameters:
|
||||||
|
* pBuff: the dest buffer
|
||||||
|
* str: source string
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int buffer_strcpy(BufferInfo *pBuff, const char *str);
|
||||||
|
|
||||||
|
/** copy binary buffer to BufferInfo
|
||||||
|
* parameters:
|
||||||
|
* pBuff: the dest buffer
|
||||||
|
* buff: source buffer
|
||||||
|
* len: source buffer length
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int buffer_memcpy(BufferInfo *pBuff, const char *buff, const int len);
|
||||||
|
|
||||||
|
/** url encode
|
||||||
|
* parameters:
|
||||||
|
* src: the source string to encode
|
||||||
|
* src_len: source string length
|
||||||
|
* dest: store dest string
|
||||||
|
* dest_len: store the dest string length
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
char *urlencode(const char *src, const int src_len, char *dest, int *dest_len);
|
||||||
|
|
||||||
|
/** url decode
|
||||||
|
* parameters:
|
||||||
|
* src: the source string to decode
|
||||||
|
* src_len: source string length
|
||||||
|
* dest: store dest string
|
||||||
|
* dest_len: store the dest string length
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
char *urldecode(const char *src, const int src_len, char *dest, int *dest_len);
|
||||||
|
|
||||||
|
/** get char occurs count
|
||||||
|
* parameters:
|
||||||
|
* src: the source string
|
||||||
|
* seperator: find this char occurs times
|
||||||
|
* return: char occurs count
|
||||||
|
*/
|
||||||
|
int getOccurCount(const char *src, const char seperator);
|
||||||
|
|
||||||
|
/** split string
|
||||||
|
* parameters:
|
||||||
|
* src: the source string, will be modified by this function
|
||||||
|
* seperator: seperator char
|
||||||
|
* nMaxCols: max columns (max split count)
|
||||||
|
* nColCount: store the columns (array elements) count
|
||||||
|
* return: string array, should call freeSplit to free, return NULL when fail
|
||||||
|
*/
|
||||||
|
char **split(char *src, const char seperator, const int nMaxCols, \
|
||||||
|
int *nColCount);
|
||||||
|
|
||||||
|
/** free split results
|
||||||
|
* parameters:
|
||||||
|
* p: return by function split
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void freeSplit(char **p);
|
||||||
|
|
||||||
|
|
||||||
|
/** split string
|
||||||
|
* parameters:
|
||||||
|
* src: the source string, will be modified by this function
|
||||||
|
* seperator: seperator char
|
||||||
|
* pCols: store split strings
|
||||||
|
* nMaxCols: max columns (max split count)
|
||||||
|
* return: string array / column count
|
||||||
|
*/
|
||||||
|
int splitEx(char *src, const char seperator, char **pCols, const int nMaxCols);
|
||||||
|
|
||||||
|
/** split string
|
||||||
|
* parameters:
|
||||||
|
* src: the source string, will be modified by this function
|
||||||
|
* seperator: seperator char
|
||||||
|
* pCols: store split strings
|
||||||
|
* nMaxCols: max columns (max split count)
|
||||||
|
* return: string array / column count
|
||||||
|
*/
|
||||||
|
int my_strtok(char *src, const char *delim, char **pCols, const int nMaxCols);
|
||||||
|
|
||||||
|
/** check file exist
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename
|
||||||
|
* return: true if file exists, otherwise false
|
||||||
|
*/
|
||||||
|
bool fileExists(const char *filename);
|
||||||
|
|
||||||
|
/** check if a directory
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename
|
||||||
|
* return: true for directory
|
||||||
|
*/
|
||||||
|
bool isDir(const char *filename);
|
||||||
|
|
||||||
|
/** check if a regular file
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename
|
||||||
|
* return: true for regular file
|
||||||
|
*/
|
||||||
|
bool isFile(const char *filename);
|
||||||
|
|
||||||
|
/** check if filename securty, /../ ocur in filename not allowed
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename
|
||||||
|
* len: filename length
|
||||||
|
* return: true for regular file
|
||||||
|
*/
|
||||||
|
bool is_filename_secure(const char *filename, const int len);
|
||||||
|
|
||||||
|
/** load log_level from config context
|
||||||
|
* parameters:
|
||||||
|
* pIniContext: the config context
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void load_log_level(IniContext *pIniContext);
|
||||||
|
|
||||||
|
/** load log_level from config file
|
||||||
|
* parameters:
|
||||||
|
* conf_filename: the config filename
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
int load_log_level_ex(const char *conf_filename);
|
||||||
|
|
||||||
|
/** set global log level
|
||||||
|
* parameters:
|
||||||
|
* pLogLevel: log level string value
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void set_log_level(char *pLogLevel);
|
||||||
|
|
||||||
|
/** load allow hosts from config context
|
||||||
|
* parameters:
|
||||||
|
* pIniContext: the config context
|
||||||
|
* allow_ip_addrs: store allow ip addresses
|
||||||
|
* allow_ip_count: store allow ip address count
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int load_allow_hosts(IniContext *pIniContext, \
|
||||||
|
in_addr_t **allow_ip_addrs, int *allow_ip_count);
|
||||||
|
|
||||||
|
/** get time item from config context
|
||||||
|
* parameters:
|
||||||
|
* pIniContext: the config context
|
||||||
|
* item_name: item name in config file, time format: hour:minute, such as 15:25
|
||||||
|
* pTimeInfo: store time info
|
||||||
|
* default_hour: default hour value
|
||||||
|
* default_minute: default minute value
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int get_time_item_from_conf(IniContext *pIniContext, \
|
||||||
|
const char *item_name, TimeInfo *pTimeInfo, \
|
||||||
|
const byte default_hour, const byte default_minute);
|
||||||
|
|
||||||
|
/** trim path tail char /
|
||||||
|
* parameters:
|
||||||
|
* filePath: the file path to chop
|
||||||
|
* return: none
|
||||||
|
*/
|
||||||
|
void chopPath(char *filePath);
|
||||||
|
|
||||||
|
/** get file content
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename
|
||||||
|
* buff: return the buff, must be freed
|
||||||
|
* file_size: store the file size
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int getFileContent(const char *filename, char **buff, int64_t *file_size);
|
||||||
|
|
||||||
|
/** get file content
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename
|
||||||
|
* buff: the buff to store file content
|
||||||
|
* offset: the start offset
|
||||||
|
* size: specify the size to fetch and return the fetched size
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int getFileContentEx(const char *filename, char *buff, \
|
||||||
|
int64_t offset, int64_t *size);
|
||||||
|
|
||||||
|
/** write to file
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename to write
|
||||||
|
* buff: the buffer to write
|
||||||
|
* file_size: the file size
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int writeToFile(const char *filename, const char *buff, const int file_size);
|
||||||
|
|
||||||
|
/** safe write to file, first write to tmp file, then rename to true filename
|
||||||
|
* parameters:
|
||||||
|
* filename: the filename to write
|
||||||
|
* buff: the buffer to write
|
||||||
|
* file_size: the file size
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int safeWriteToFile(const char *filename, const char *buff, \
|
||||||
|
const int file_size);
|
||||||
|
|
||||||
|
/** get a line from file
|
||||||
|
* parameters:
|
||||||
|
* fd: the fd to read
|
||||||
|
* buff: the buffer to store the line
|
||||||
|
* size: the buffer max size
|
||||||
|
* once_bytes: the bytes per read
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int fd_gets(int fd, char *buff, const int size, int once_bytes);
|
||||||
|
|
||||||
|
/** set unix rlimit
|
||||||
|
* parameters:
|
||||||
|
* resource: resource id, please see sys/resource.h
|
||||||
|
* value: the value to set
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int set_rlimit(int resource, const rlim_t value);
|
||||||
|
|
||||||
|
/** set non block mode
|
||||||
|
* parameters:
|
||||||
|
* fd: the fd to set
|
||||||
|
* adding_flags: the flags to add
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int fd_add_flags(int fd, int adding_flags);
|
||||||
|
|
||||||
|
/** set non block mode
|
||||||
|
* parameters:
|
||||||
|
* fd: the fd to set
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
#define set_nonblock(fd) fd_add_flags(fd, O_NONBLOCK)
|
||||||
|
|
||||||
|
/** set run by group and user
|
||||||
|
* parameters:
|
||||||
|
* group_name: the group name, can be NULL or empty
|
||||||
|
* username: the username, can be NULL or empty
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int set_run_by(const char *group_name, const char *username);
|
||||||
|
|
||||||
|
/** compare ip address, type is (in_addr_t *)
|
||||||
|
* parameters:
|
||||||
|
* p1: the first ip address
|
||||||
|
* p2: the second ip address
|
||||||
|
* return: > 0 when p1 > p2, 0 when p1 == p2, < 0 when p1 < p2
|
||||||
|
*/
|
||||||
|
int cmp_by_ip_addr_t(const void *p1, const void *p2);
|
||||||
|
|
||||||
|
/** parse bytes
|
||||||
|
* parameters:
|
||||||
|
* pStr: the string to parse
|
||||||
|
* default_unit_bytes: default unit if not specified the unit like MB etc.
|
||||||
|
* bytes: store the parsed bytes
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int parse_bytes(char *pStr, const int default_unit_bytes, int64_t *bytes);
|
||||||
|
|
||||||
|
/** set rand seed
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int set_rand_seed();
|
||||||
|
|
||||||
|
/** set timer wrapper
|
||||||
|
* parameters:
|
||||||
|
* first_remain_seconds: remain time for first time, in seconds
|
||||||
|
* interval: the interval
|
||||||
|
* sighandler: handler function
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int set_timer(const int first_remain_seconds, const int interval, \
|
||||||
|
void (*sighandler)(int));
|
||||||
|
|
||||||
|
/** set file access and modified times
|
||||||
|
* parameters:
|
||||||
|
* filename: the file to modify times
|
||||||
|
* new_time: the time to set
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int set_file_utimes(const char *filename, const time_t new_time);
|
||||||
|
|
||||||
|
/** ignore singal pipe (SIGPIPE)
|
||||||
|
* return: error no , 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int ignore_signal_pipe();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,335 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2008 Happy Fish / YuQing
|
||||||
|
*
|
||||||
|
* FastDFS may be copied only under the terms of the GNU General
|
||||||
|
* Public License V3, which may be found in the FastDFS source kit.
|
||||||
|
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
|
||||||
|
**/
|
||||||
|
|
||||||
|
//socketopt.h
|
||||||
|
|
||||||
|
#ifndef _SOCKETOPT_H_
|
||||||
|
#define _SOCKETOPT_H_
|
||||||
|
|
||||||
|
#include "common_define.h"
|
||||||
|
|
||||||
|
#define FDFS_WRITE_BUFF_SIZE 256 * 1024
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int (*getnamefunc)(int socket, struct sockaddr *address, \
|
||||||
|
socklen_t *address_len);
|
||||||
|
|
||||||
|
typedef int (*tcpsenddatafunc)(int sock, void* data, const int size, \
|
||||||
|
const int timeout);
|
||||||
|
|
||||||
|
typedef int (*tcprecvdata_exfunc)(int sock, void *data, const int size, \
|
||||||
|
const int timeout, int *count);
|
||||||
|
|
||||||
|
#define getSockIpaddr(sock, buff, bufferSize) \
|
||||||
|
getIpaddr(getsockname, sock, buff, bufferSize)
|
||||||
|
|
||||||
|
#define getPeerIpaddr(sock, buff, bufferSize) \
|
||||||
|
getIpaddr(getpeername, sock, buff, bufferSize)
|
||||||
|
|
||||||
|
/** get a line from socket
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* s: the buffer
|
||||||
|
* size: buffer size (max bytes can receive)
|
||||||
|
* timeout: read timeout
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpgets(int sock, char *s, const int size, const int timeout);
|
||||||
|
|
||||||
|
/** recv data (block mode)
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* data: the buffer
|
||||||
|
* size: buffer size (max bytes can receive)
|
||||||
|
* timeout: read timeout
|
||||||
|
* count: store the bytes recveived
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcprecvdata_ex(int sock, void *data, const int size, \
|
||||||
|
const int timeout, int *count);
|
||||||
|
|
||||||
|
/** recv data (non-block mode)
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* data: the buffer
|
||||||
|
* size: buffer size (max bytes can receive)
|
||||||
|
* timeout: read timeout
|
||||||
|
* count: store the bytes recveived
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcprecvdata_nb_ex(int sock, void *data, const int size, \
|
||||||
|
const int timeout, int *count);
|
||||||
|
|
||||||
|
/** send data (block mode)
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* data: the buffer to send
|
||||||
|
* size: buffer size
|
||||||
|
* timeout: write timeout
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpsenddata(int sock, void* data, const int size, const int timeout);
|
||||||
|
|
||||||
|
/** send data (non-block mode)
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* data: the buffer to send
|
||||||
|
* size: buffer size
|
||||||
|
* timeout: write timeout
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpsenddata_nb(int sock, void* data, const int size, const int timeout);
|
||||||
|
|
||||||
|
/** connect to server by block mode
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* server_ip: ip address of the server
|
||||||
|
* server_port: port of the server
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int connectserverbyip(int sock, const char *server_ip, const short server_port);
|
||||||
|
|
||||||
|
/** connect to server by non-block mode
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* server_ip: ip address of the server
|
||||||
|
* server_port: port of the server
|
||||||
|
* timeout: connect timeout in seconds
|
||||||
|
* auto_detect: if detect and adjust the block mode of the socket
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int connectserverbyip_nb_ex(int sock, const char *server_ip, \
|
||||||
|
const short server_port, const int timeout, \
|
||||||
|
const bool auto_detect);
|
||||||
|
|
||||||
|
/** connect to server by non-block mode, the socket must be set to non-block
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket, must be set to non-block
|
||||||
|
* server_ip: ip address of the server
|
||||||
|
* server_port: port of the server
|
||||||
|
* timeout: connect timeout in seconds
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
#define connectserverbyip_nb(sock, server_ip, server_port, timeout) \
|
||||||
|
connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, false)
|
||||||
|
|
||||||
|
/** connect to server by non-block mode, auto detect socket block mode
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket, can be block mode
|
||||||
|
* server_ip: ip address of the server
|
||||||
|
* server_port: port of the server
|
||||||
|
* timeout: connect timeout in seconds
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
#define connectserverbyip_nb_auto(sock, server_ip, server_port, timeout) \
|
||||||
|
connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, true)
|
||||||
|
|
||||||
|
/** accept client connect request
|
||||||
|
* parameters:
|
||||||
|
* sock: the server socket
|
||||||
|
* timeout: read timeout
|
||||||
|
* err_no: store the error no, 0 for success
|
||||||
|
* return: client socket, < 0 for error
|
||||||
|
*/
|
||||||
|
int nbaccept(int sock, const int timeout, int *err_no);
|
||||||
|
|
||||||
|
/** set socket options
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* timeout: read & write timeout
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpsetserveropt(int fd, const int timeout);
|
||||||
|
|
||||||
|
/** set socket non-block options
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpsetnonblockopt(int fd);
|
||||||
|
|
||||||
|
/** set socket no delay on send data
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* timeout: read & write timeout
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpsetnodelay(int fd, const int timeout);
|
||||||
|
|
||||||
|
/** set socket keep-alive
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* idleSeconds: max idle time (seconds)
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpsetkeepalive(int fd, const int idleSeconds);
|
||||||
|
|
||||||
|
/** print keep-alive related parameters
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpprintkeepalive(int fd);
|
||||||
|
|
||||||
|
/** get ip address
|
||||||
|
* parameters:
|
||||||
|
* getname: the function name, should be getpeername or getsockname
|
||||||
|
* sock: the socket
|
||||||
|
* buff: buffer to store the ip address
|
||||||
|
* bufferSize: the buffer size (max bytes)
|
||||||
|
* return: in_addr_t, INADDR_NONE for fail
|
||||||
|
*/
|
||||||
|
in_addr_t getIpaddr(getnamefunc getname, int sock, \
|
||||||
|
char *buff, const int bufferSize);
|
||||||
|
|
||||||
|
/** get hostname by it's ip address
|
||||||
|
* parameters:
|
||||||
|
* szIpAddr: the ip address
|
||||||
|
* buff: buffer to store the hostname
|
||||||
|
* bufferSize: the buffer size (max bytes)
|
||||||
|
* return: hostname, empty buffer for error
|
||||||
|
*/
|
||||||
|
char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize);
|
||||||
|
|
||||||
|
/** get by ip address by it's hostname
|
||||||
|
* parameters:
|
||||||
|
* name: the hostname
|
||||||
|
* buff: buffer to store the ip address
|
||||||
|
* bufferSize: the buffer size (max bytes)
|
||||||
|
* return: in_addr_t, INADDR_NONE for fail
|
||||||
|
*/
|
||||||
|
in_addr_t getIpaddrByName(const char *name, char *buff, const int bufferSize);
|
||||||
|
|
||||||
|
/** bind wrapper
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* bind_ipaddr: the ip address to bind
|
||||||
|
* port: the port to bind
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int socketBind(int sock, const char *bind_ipaddr, const int port);
|
||||||
|
|
||||||
|
/** start a socket server (socket, bind and listen)
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* bind_ipaddr: the ip address to bind
|
||||||
|
* port: the port to bind
|
||||||
|
* err_no: store the error no
|
||||||
|
* return: >= 0 server socket, < 0 fail
|
||||||
|
*/
|
||||||
|
int socketServer(const char *bind_ipaddr, const int port, int *err_no);
|
||||||
|
|
||||||
|
#define tcprecvdata(sock, data, size, timeout) \
|
||||||
|
tcprecvdata_ex(sock, data, size, timeout, NULL)
|
||||||
|
|
||||||
|
#define tcpsendfile(sock, filename, file_bytes, timeout, total_send_bytes) \
|
||||||
|
tcpsendfile_ex(sock, filename, 0, file_bytes, timeout, total_send_bytes)
|
||||||
|
|
||||||
|
#define tcprecvdata_nb(sock, data, size, timeout) \
|
||||||
|
tcprecvdata_nb_ex(sock, data, size, timeout, NULL)
|
||||||
|
|
||||||
|
/** send a file
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* filename: the file to send
|
||||||
|
* file_offset: file offset, start position
|
||||||
|
* file_bytes: send file length
|
||||||
|
* timeout: write timeout
|
||||||
|
* total_send_bytes: store the send bytes
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpsendfile_ex(int sock, const char *filename, const int64_t file_offset, \
|
||||||
|
const int64_t file_bytes, const int timeout, int64_t *total_send_bytes);
|
||||||
|
|
||||||
|
/** receive data to a file
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* filename: the file to write
|
||||||
|
* file_bytes: file size (bytes)
|
||||||
|
* fsync_after_written_bytes: call fsync every x bytes
|
||||||
|
* timeout: read/recv timeout
|
||||||
|
* true_file_bytes: store the true file bytes
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcprecvfile(int sock, const char *filename, const int64_t file_bytes, \
|
||||||
|
const int fsync_after_written_bytes, const int timeout, \
|
||||||
|
int64_t *true_file_bytes);
|
||||||
|
|
||||||
|
|
||||||
|
#define tcprecvinfinitefile(sock, filename, fsync_after_written_bytes, \
|
||||||
|
timeout, file_bytes) \
|
||||||
|
tcprecvfile(sock, filename, INFINITE_FILE_SIZE, \
|
||||||
|
fsync_after_written_bytes, timeout, file_bytes)
|
||||||
|
|
||||||
|
|
||||||
|
/** receive data to a file
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* filename: the file to write
|
||||||
|
* file_bytes: file size (bytes)
|
||||||
|
* fsync_after_written_bytes: call fsync every x bytes
|
||||||
|
* hash_codes: return hash code of file content
|
||||||
|
* timeout: read/recv timeout
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcprecvfile_ex(int sock, const char *filename, const int64_t file_bytes, \
|
||||||
|
const int fsync_after_written_bytes, \
|
||||||
|
unsigned int *hash_codes, const int timeout);
|
||||||
|
|
||||||
|
/** receive specified data and discard
|
||||||
|
* parameters:
|
||||||
|
* sock: the socket
|
||||||
|
* bytes: data bytes to discard
|
||||||
|
* timeout: read timeout
|
||||||
|
* total_recv_bytes: store the total recv bytes
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int tcpdiscard(int sock, const int bytes, const int timeout, \
|
||||||
|
int64_t *total_recv_bytes);
|
||||||
|
|
||||||
|
/** get local host ip addresses
|
||||||
|
* parameters:
|
||||||
|
* ip_addrs: store the ip addresses
|
||||||
|
* max_count: max ip address (max ip_addrs elements)
|
||||||
|
* count: store the ip address count
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
|
||||||
|
const int max_count, int *count);
|
||||||
|
|
||||||
|
/** get local host ip addresses
|
||||||
|
* parameters:
|
||||||
|
* ip_addrs: store the ip addresses
|
||||||
|
* max_count: max ip address (max ip_addrs elements)
|
||||||
|
* count: store the ip address count
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int getlocaladdrs1(char ip_addrs[][IP_ADDRESS_SIZE], \
|
||||||
|
const int max_count, int *count);
|
||||||
|
|
||||||
|
/** get local host ip addresses by if alias prefix
|
||||||
|
* parameters:
|
||||||
|
* if_alias_prefixes: if alias prefixes, such as eth, bond etc.
|
||||||
|
* prefix_count: if alias prefix count
|
||||||
|
* ip_addrs: store the ip addresses
|
||||||
|
* max_count: max ip address (max ip_addrs elements)
|
||||||
|
* count: store the ip address count
|
||||||
|
* return: error no, 0 success, != 0 fail
|
||||||
|
*/
|
||||||
|
int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
|
||||||
|
char ip_addrs[][IP_ADDRESS_SIZE], const int max_count, int *count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
Loading…
Reference in New Issue