depend on libfastcommon
parent
b832e104b2
commit
8a9ec249fa
4
HISTORY
4
HISTORY
|
|
@ -1,4 +1,8 @@
|
||||||
|
|
||||||
|
Version 5.04 2014-08-19
|
||||||
|
* add fastdfs.spec for build RPM on Linux
|
||||||
|
* depend on libfastcommon
|
||||||
|
|
||||||
Version 5.03 2014-08-10
|
Version 5.03 2014-08-10
|
||||||
* network send and recv retry when error EINTR happen
|
* network send and recv retry when error EINTR happen
|
||||||
* support mac OS Darwin
|
* support mac OS Darwin
|
||||||
|
|
|
||||||
34
INSTALL
34
INSTALL
|
|
@ -6,43 +6,47 @@ Please visit the FastDFS Home Page for more detail.
|
||||||
English language: http://english.csource.org/
|
English language: http://english.csource.org/
|
||||||
Chinese language: http://www.csource.org/
|
Chinese language: http://www.csource.org/
|
||||||
|
|
||||||
#step 1. download FastDFS source package and unpack it,
|
#step 1. download libfastcommon source package from github and install it,
|
||||||
|
the github address:
|
||||||
|
https://github.com/happyfish100/libfastcommon.git
|
||||||
|
|
||||||
|
#step 2. download FastDFS source package and unpack it,
|
||||||
tar xzf FastDFS_v5.x.tar.gz
|
tar xzf FastDFS_v5.x.tar.gz
|
||||||
#for example:
|
#for example:
|
||||||
tar xzf FastDFS_v5.01.tar.gz
|
tar xzf FastDFS_v5.04.tar.gz
|
||||||
|
|
||||||
#step 2. enter the FastDFS dir
|
#step 3. enter the FastDFS dir
|
||||||
cd FastDFS
|
cd FastDFS
|
||||||
|
|
||||||
#step 3. execute:
|
#step 4. execute:
|
||||||
./make.sh
|
./make.sh
|
||||||
|
|
||||||
#step 4. make install
|
#step 5. make install
|
||||||
./make.sh install
|
./make.sh install
|
||||||
|
|
||||||
#step 5. edit/modify the config file of tracker and storage
|
#step 6. edit/modify the config file of tracker and storage
|
||||||
|
|
||||||
#step 6. run server programs
|
#step 7. run server programs
|
||||||
#start the tracker server:
|
#start the tracker server:
|
||||||
/usr/local/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
|
/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
|
||||||
#in Linux, you can start fdfs_trackerd as a service:
|
#in Linux, you can start fdfs_trackerd as a service:
|
||||||
/sbin/service fdfs_trackerd start
|
/sbin/service fdfs_trackerd start
|
||||||
|
|
||||||
#start the storage server:
|
#start the storage server:
|
||||||
/usr/local/bin/fdfs_storaged /etc/fdfs/storage.conf restart
|
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
|
||||||
#in Linux, you can start fdfs_storaged as a service:
|
#in Linux, you can start fdfs_storaged as a service:
|
||||||
/sbin/service fdfs_storaged start
|
/sbin/service fdfs_storaged start
|
||||||
|
|
||||||
#step 7. run test program
|
#step 8. run test program
|
||||||
#run the client test program:
|
#run the client test program:
|
||||||
/usr/local/bin/fdfs_test <client_conf_filename> <operation>
|
/usr/bin/fdfs_test <client_conf_filename> <operation>
|
||||||
/usr/local/bin/fdfs_test1 <client_conf_filename> <operation>
|
/usr/bin/fdfs_test1 <client_conf_filename> <operation>
|
||||||
#for example, upload a file:
|
#for example, upload a file:
|
||||||
/usr/local/bin/fdfs_test conf/client.conf upload /usr/include/stdlib.h
|
/usr/bin/fdfs_test conf/client.conf upload /usr/include/stdlib.h
|
||||||
|
|
||||||
#step 8. run monitor program
|
#step 9. run monitor program
|
||||||
#run the monitor program:
|
#run the monitor program:
|
||||||
/usr/local/bin/fdfs_monitor <client_conf_filename>
|
/usr/bin/fdfs_monitor <client_conf_filename>
|
||||||
|
|
||||||
|
|
||||||
tracker server config file sample please see conf/tracker.conf
|
tracker server config file sample please see conf/tracker.conf
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,13 @@
|
||||||
COMPILE = $(CC) $(CFLAGS)
|
COMPILE = $(CC) $(CFLAGS)
|
||||||
ENABLE_STATIC_LIB = $(ENABLE_STATIC_LIB)
|
ENABLE_STATIC_LIB = $(ENABLE_STATIC_LIB)
|
||||||
ENABLE_SHARED_LIB = $(ENABLE_SHARED_LIB)
|
ENABLE_SHARED_LIB = $(ENABLE_SHARED_LIB)
|
||||||
INC_PATH = -I../common -I../tracker -I/usr/include
|
INC_PATH = -I../common -I../tracker -I/usr/include/fastcommon
|
||||||
LIB_PATH = $(LIBS)
|
LIB_PATH = $(LIBS) -lfastcommon
|
||||||
TARGET_PATH = $(TARGET_PREFIX)/bin
|
TARGET_PATH = $(TARGET_PREFIX)/bin
|
||||||
TARGET_LIB = $(TARGET_PREFIX)/lib64
|
TARGET_LIB = $(TARGET_PREFIX)/lib64
|
||||||
TARGET_INC = $(TARGET_PREFIX)/include
|
TARGET_INC = $(TARGET_PREFIX)/include
|
||||||
CONFIG_PATH = $(TARGET_CONF_PATH)
|
CONFIG_PATH = $(TARGET_CONF_PATH)
|
||||||
|
|
||||||
FAST_STATIC_OBJS = ../common/hash.o ../common/chain.o \
|
|
||||||
../common/shared_func.o ../common/ini_file_reader.o \
|
|
||||||
../common/logger.o ../common/sockopt.o \
|
|
||||||
../common/base64.o ../common/sched_thread.o \
|
|
||||||
../common/http_func.o ../common/md5.o \
|
|
||||||
../common/pthread_func.o ../common/local_ip_func.o \
|
|
||||||
../common/avl_tree.o ../common/connection_pool.o \
|
|
||||||
../common/ioevent.o ../common/ioevent_loop.o \
|
|
||||||
../common/fast_task_queue.o ../common/fast_timer.o \
|
|
||||||
../common/process_ctrl.o ../common/fast_mblock.o
|
|
||||||
|
|
||||||
FDFS_STATIC_OBJS = ../common/fdfs_global.o ../common/fdfs_http_shared.o \
|
FDFS_STATIC_OBJS = ../common/fdfs_global.o ../common/fdfs_http_shared.o \
|
||||||
../common/mime_file_parser.o ../tracker/tracker_proto.o \
|
../common/mime_file_parser.o ../tracker/tracker_proto.o \
|
||||||
../tracker/fdfs_shared_func.o \
|
../tracker/fdfs_shared_func.o \
|
||||||
|
|
@ -28,18 +17,7 @@ FDFS_STATIC_OBJS = ../common/fdfs_global.o ../common/fdfs_http_shared.o \
|
||||||
tracker_client.o client_func.o \
|
tracker_client.o client_func.o \
|
||||||
client_global.o storage_client.o
|
client_global.o storage_client.o
|
||||||
|
|
||||||
STATIC_OBJS = $(FAST_STATIC_OBJS) $(FDFS_STATIC_OBJS)
|
STATIC_OBJS = $(FDFS_STATIC_OBJS)
|
||||||
|
|
||||||
FAST_SHARED_OBJS = ../common/hash.lo ../common/chain.lo \
|
|
||||||
../common/shared_func.lo ../common/ini_file_reader.lo \
|
|
||||||
../common/logger.lo ../common/sockopt.lo \
|
|
||||||
../common/base64.lo ../common/sched_thread.lo \
|
|
||||||
../common/http_func.lo ../common/md5.lo \
|
|
||||||
../common/pthread_func.lo ../common/local_ip_func.lo \
|
|
||||||
../common/avl_tree.lo ../common/connection_pool.lo \
|
|
||||||
../common/ioevent.lo ../common/ioevent_loop.lo \
|
|
||||||
../common/fast_task_queue.lo ../common/fast_timer.lo \
|
|
||||||
../common/process_ctrl.lo ../common/fast_mblock.lo
|
|
||||||
|
|
||||||
FDFS_SHARED_OBJS = ../common/fdfs_global.lo ../common/fdfs_http_shared.lo \
|
FDFS_SHARED_OBJS = ../common/fdfs_global.lo ../common/fdfs_http_shared.lo \
|
||||||
../common/mime_file_parser.lo ../tracker/tracker_proto.lo \
|
../common/mime_file_parser.lo ../tracker/tracker_proto.lo \
|
||||||
|
|
@ -48,18 +26,6 @@ FDFS_SHARED_OBJS = ../common/fdfs_global.lo ../common/fdfs_http_shared.lo \
|
||||||
tracker_client.lo client_func.lo \
|
tracker_client.lo client_func.lo \
|
||||||
client_global.lo storage_client.lo
|
client_global.lo storage_client.lo
|
||||||
|
|
||||||
FAST_HEADER_FILES = ../common/common_define.h ../common/hash.h \
|
|
||||||
../common/chain.h ../common/logger.h \
|
|
||||||
../common/base64.h ../common/shared_func.h \
|
|
||||||
../common/pthread_func.h ../common/ini_file_reader.h \
|
|
||||||
../common/sockopt.h ../common/sched_thread.h \
|
|
||||||
../common/http_func.h ../common/md5.h ../common/_os_bits.h \
|
|
||||||
../common/local_ip_func.h ../common/avl_tree.h \
|
|
||||||
../common/connection_pool.h ../common/ioevent.h \
|
|
||||||
../common/ioevent_loop.h ../common/fast_task_queue.h \
|
|
||||||
../common/fast_timer.h ../common/process_ctrl.h \
|
|
||||||
../common/fast_mblock.h
|
|
||||||
|
|
||||||
FDFS_HEADER_FILES = ../common/fdfs_define.h ../common/fdfs_global.h \
|
FDFS_HEADER_FILES = ../common/fdfs_define.h ../common/fdfs_global.h \
|
||||||
../common/mime_file_parser.h ../common/fdfs_http_shared.h \
|
../common/mime_file_parser.h ../common/fdfs_http_shared.h \
|
||||||
../tracker/tracker_types.h ../tracker/tracker_proto.h \
|
../tracker/tracker_types.h ../tracker/tracker_proto.h \
|
||||||
|
|
@ -68,29 +34,23 @@ FDFS_HEADER_FILES = ../common/fdfs_define.h ../common/fdfs_global.h \
|
||||||
tracker_client.h storage_client.h storage_client1.h \
|
tracker_client.h storage_client.h storage_client1.h \
|
||||||
client_func.h client_global.h fdfs_client.h
|
client_func.h client_global.h fdfs_client.h
|
||||||
|
|
||||||
ALL_OBJS = $(STATIC_OBJS) $(FAST_SHARED_OBJS) $(FDFS_SHARED_OBJS)
|
ALL_OBJS = $(STATIC_OBJS) $(FDFS_SHARED_OBJS)
|
||||||
|
|
||||||
ALL_PRGS = fdfs_monitor fdfs_test fdfs_test1 fdfs_crc32 fdfs_upload_file \
|
ALL_PRGS = fdfs_monitor fdfs_test fdfs_test1 fdfs_crc32 fdfs_upload_file \
|
||||||
fdfs_download_file fdfs_delete_file fdfs_file_info \
|
fdfs_download_file fdfs_delete_file fdfs_file_info \
|
||||||
fdfs_appender_test fdfs_appender_test1 fdfs_append_file \
|
fdfs_appender_test fdfs_appender_test1 fdfs_append_file \
|
||||||
fdfs_upload_appender
|
fdfs_upload_appender
|
||||||
|
|
||||||
STATIC_LIBS = libfastcommon.a libfdfsclient.a
|
STATIC_LIBS = libfdfsclient.a
|
||||||
|
|
||||||
SHARED_LIBS = libfastcommon.so libfdfsclient.so
|
SHARED_LIBS = libfdfsclient.so
|
||||||
CLIENT_SHARED_LIBS = libfdfsclient.so
|
CLIENT_SHARED_LIBS = libfdfsclient.so
|
||||||
|
|
||||||
ALL_LIBS = $(STATIC_LIBS) $(SHARED_LIBS)
|
ALL_LIBS = $(STATIC_LIBS) $(SHARED_LIBS)
|
||||||
|
|
||||||
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
||||||
libfastcommon.so:
|
|
||||||
$(COMPILE) -o $@ $< -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
|
|
||||||
# ln -fs libfastcommon.so.1 libfastcommon.so
|
|
||||||
libfdfsclient.so:
|
libfdfsclient.so:
|
||||||
$(COMPILE) -o $@ $< -shared $(FDFS_SHARED_OBJS) $(LIB_PATH) -lfastcommon
|
$(COMPILE) -o $@ $< -shared $(FDFS_SHARED_OBJS) $(LIB_PATH)
|
||||||
# ln -fs libfdfsclient.so.1 libfdfsclient.so
|
|
||||||
libfastcommon.a:
|
|
||||||
ar cru $@ $< $(FAST_STATIC_OBJS)
|
|
||||||
libfdfsclient.a:
|
libfdfsclient.a:
|
||||||
ar cru $@ $< $(FDFS_STATIC_OBJS)
|
ar cru $@ $< $(FDFS_STATIC_OBJS)
|
||||||
.o:
|
.o:
|
||||||
|
|
@ -111,7 +71,7 @@ install:
|
||||||
|
|
||||||
mkdir -p $(TARGET_INC)/fastdfs
|
mkdir -p $(TARGET_INC)/fastdfs
|
||||||
cp -f $(FDFS_HEADER_FILES) $(TARGET_INC)/fastdfs
|
cp -f $(FDFS_HEADER_FILES) $(TARGET_INC)/fastdfs
|
||||||
if [ ! -f $(CONFIG_PATH)/client.conf ]; then cp -f ../conf/client.conf $(CONFIG_PATH)/client.conf.sample; fi
|
if [ ! -f $(CONFIG_PATH)/client.conf.sample ]; then cp -f ../conf/client.conf $(CONFIG_PATH)/client.conf.sample; fi
|
||||||
clean:
|
clean:
|
||||||
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
COMPILE = $(CC) -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -g -O -DDEBUG_FLAG -DOS_LINUX -DIOEVENT_USE_EPOLL
|
COMPILE = $(CC) -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -g -O -DDEBUG_FLAG -DOS_LINUX -DIOEVENT_USE_EPOLL
|
||||||
INC_PATH = -I/usr/local/include/fastcommon -I/usr/local/include/fastdfs
|
INC_PATH = -I/usr/include/fastcommon -I/usr/include/fastdfs
|
||||||
LIB_PATH = -L/usr/local/lib -lfastcommon -lfdfsclient -lpthread -ldl -rdynamic
|
LIB_PATH = -L/usr/local/lib -lfastcommon -lfdfsclient -lpthread -ldl -rdynamic
|
||||||
TARGET_PATH = $(TARGET_PATH)
|
TARGET_PATH = $(TARGET_PATH)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
COMPILE = $(CC) $(CFLAGS)
|
COMPILE = $(CC) $(CFLAGS)
|
||||||
INC_PATH = -I/usr/local/include/fastcommon -I/usr/local/include/fastdfs
|
INC_PATH = -I/usr/include/fastcommon -I/usr/include/fastdfs
|
||||||
LIB_PATH = -L/usr/local/lib -lfastcommon -lfdfsclient $(LIBS)
|
LIB_PATH = -L/usr/local/lib -lfastcommon -lfdfsclient $(LIBS)
|
||||||
TARGET_PATH = $(TARGET_PATH)
|
TARGET_PATH = $(TARGET_PATH)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,789 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
|
|
||||||
#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
|
|
||||||
393
common/base64.c
393
common/base64.c
|
|
@ -1,393 +0,0 @@
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
134
common/base64.h
134
common/base64.h
|
|
@ -1,134 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
325
common/chain.c
325
common/chain.c
|
|
@ -1,325 +0,0 @@
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
148
common/chain.h
148
common/chain.h
|
|
@ -1,148 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
|
|
@ -1,163 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 <stdbool.h>
|
|
||||||
#include <inttypes.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 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
|
|
||||||
|
|
@ -1,350 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 "sched_thread.h"
|
|
||||||
#include "connection_pool.h"
|
|
||||||
|
|
||||||
int conn_pool_init(ConnectionPool *cp, int connect_timeout, \
|
|
||||||
const int max_count_per_entry, const int max_idle_time)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=init_pthread_lock(&cp->lock)) != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
cp->connect_timeout = connect_timeout;
|
|
||||||
cp->max_count_per_entry = max_count_per_entry;
|
|
||||||
cp->max_idle_time = max_idle_time;
|
|
||||||
|
|
||||||
return hash_init(&(cp->hash_array), simple_hash, 1024, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
void conn_pool_destroy(ConnectionPool *cp)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&cp->lock);
|
|
||||||
hash_destroy(&(cp->hash_array));
|
|
||||||
pthread_mutex_unlock(&cp->lock);
|
|
||||||
|
|
||||||
pthread_mutex_destroy(&cp->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void conn_pool_disconnect_server(ConnectionInfo *pConnection)
|
|
||||||
{
|
|
||||||
if (pConnection->sock >= 0)
|
|
||||||
{
|
|
||||||
close(pConnection->sock);
|
|
||||||
pConnection->sock = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_pool_connect_server(ConnectionInfo *pConnection, \
|
|
||||||
const int connect_timeout)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (pConnection->sock >= 0)
|
|
||||||
{
|
|
||||||
close(pConnection->sock);
|
|
||||||
}
|
|
||||||
|
|
||||||
pConnection->sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if(pConnection->sock < 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"socket create failed, errno: %d, " \
|
|
||||||
"error info: %s", __LINE__, errno, STRERROR(errno));
|
|
||||||
return errno != 0 ? errno : EPERM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=tcpsetnonblockopt(pConnection->sock)) != 0)
|
|
||||||
{
|
|
||||||
close(pConnection->sock);
|
|
||||||
pConnection->sock = -1;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=connectserverbyip_nb(pConnection->sock, \
|
|
||||||
pConnection->ip_addr, pConnection->port, \
|
|
||||||
connect_timeout)) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"connect to %s:%d fail, errno: %d, " \
|
|
||||||
"error info: %s", __LINE__, pConnection->ip_addr, \
|
|
||||||
pConnection->port, result, STRERROR(result));
|
|
||||||
|
|
||||||
close(pConnection->sock);
|
|
||||||
pConnection->sock = -1;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int conn_pool_get_key(const ConnectionInfo *conn, char *key, int *key_len)
|
|
||||||
{
|
|
||||||
struct in_addr sin_addr;
|
|
||||||
|
|
||||||
if (inet_aton(conn->ip_addr, &sin_addr) == 0)
|
|
||||||
{
|
|
||||||
*key_len = 0;
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int2buff(sin_addr.s_addr, key);
|
|
||||||
*key_len = 4 + sprintf(key + 4, "%d", conn->port);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
|
|
||||||
const ConnectionInfo *conn, int *err_no)
|
|
||||||
{
|
|
||||||
char key[32];
|
|
||||||
int key_len;
|
|
||||||
int bytes;
|
|
||||||
char *p;
|
|
||||||
ConnectionManager *cm;
|
|
||||||
ConnectionNode *node;
|
|
||||||
ConnectionInfo *ci;
|
|
||||||
time_t current_time;
|
|
||||||
|
|
||||||
*err_no = conn_pool_get_key(conn, key, &key_len);
|
|
||||||
if (*err_no != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&cp->lock);
|
|
||||||
cm = (ConnectionManager *)hash_find(&cp->hash_array, key, key_len);
|
|
||||||
if (cm == NULL)
|
|
||||||
{
|
|
||||||
cm = (ConnectionManager *)malloc(sizeof(ConnectionManager));
|
|
||||||
if (cm == NULL)
|
|
||||||
{
|
|
||||||
*err_no = errno != 0 ? errno : ENOMEM;
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"malloc %d bytes fail, errno: %d, " \
|
|
||||||
"error info: %s", __LINE__, \
|
|
||||||
(int)sizeof(ConnectionManager), \
|
|
||||||
*err_no, STRERROR(*err_no));
|
|
||||||
pthread_mutex_unlock(&cp->lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
cm->head = NULL;
|
|
||||||
cm->total_count = 0;
|
|
||||||
cm->free_count = 0;
|
|
||||||
if ((*err_no=init_pthread_lock(&cm->lock)) != 0)
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&cp->lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
hash_insert(&cp->hash_array, key, key_len, cm);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&cp->lock);
|
|
||||||
|
|
||||||
current_time = get_current_time();
|
|
||||||
pthread_mutex_lock(&cm->lock);
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
if (cm->head == NULL)
|
|
||||||
{
|
|
||||||
if ((cp->max_count_per_entry > 0) &&
|
|
||||||
(cm->total_count >= cp->max_count_per_entry))
|
|
||||||
{
|
|
||||||
*err_no = ENOSPC;
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"connections: %d of server %s:%d " \
|
|
||||||
"exceed limit: %d", __LINE__, \
|
|
||||||
cm->total_count, conn->ip_addr, \
|
|
||||||
conn->port, cp->max_count_per_entry);
|
|
||||||
pthread_mutex_unlock(&cm->lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes = sizeof(ConnectionInfo) + sizeof(ConnectionNode);
|
|
||||||
p = (char *)malloc(bytes);
|
|
||||||
if (p == NULL)
|
|
||||||
{
|
|
||||||
*err_no = errno != 0 ? errno : ENOMEM;
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"malloc %d bytes fail, errno: %d, " \
|
|
||||||
"error info: %s", __LINE__, \
|
|
||||||
bytes, *err_no, STRERROR(*err_no));
|
|
||||||
pthread_mutex_unlock(&cm->lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = (ConnectionNode *)(p + sizeof(ConnectionInfo));
|
|
||||||
node->conn = (ConnectionInfo *)p;
|
|
||||||
node->manager = cm;
|
|
||||||
node->next = NULL;
|
|
||||||
node->atime = 0;
|
|
||||||
|
|
||||||
cm->total_count++;
|
|
||||||
pthread_mutex_unlock(&cm->lock);
|
|
||||||
|
|
||||||
memcpy(node->conn, conn, sizeof(ConnectionInfo));
|
|
||||||
node->conn->sock = -1;
|
|
||||||
*err_no = conn_pool_connect_server(node->conn, \
|
|
||||||
cp->connect_timeout);
|
|
||||||
if (*err_no != 0)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&cm->lock);
|
|
||||||
cm->total_count--; //rollback
|
|
||||||
pthread_mutex_unlock(&cm->lock);
|
|
||||||
|
|
||||||
free(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
|
||||||
"server %s:%d, new connection: %d, " \
|
|
||||||
"total_count: %d, free_count: %d", \
|
|
||||||
__LINE__, conn->ip_addr, conn->port, \
|
|
||||||
node->conn->sock, cm->total_count, \
|
|
||||||
cm->free_count);
|
|
||||||
return node->conn;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = cm->head;
|
|
||||||
ci = node->conn;
|
|
||||||
cm->head = node->next;
|
|
||||||
cm->free_count--;
|
|
||||||
|
|
||||||
if (current_time - node->atime > cp->max_idle_time)
|
|
||||||
{
|
|
||||||
cm->total_count--;
|
|
||||||
|
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
|
||||||
"server %s:%d, connection: %d idle " \
|
|
||||||
"time: %d exceeds max idle time: %d, "\
|
|
||||||
"total_count: %d, free_count: %d", \
|
|
||||||
__LINE__, conn->ip_addr, conn->port, \
|
|
||||||
ci->sock, \
|
|
||||||
(int)(current_time - node->atime), \
|
|
||||||
cp->max_idle_time, cm->total_count, \
|
|
||||||
cm->free_count);
|
|
||||||
|
|
||||||
conn_pool_disconnect_server(ci);
|
|
||||||
free(ci);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&cm->lock);
|
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
|
||||||
"server %s:%d, reuse connection: %d, " \
|
|
||||||
"total_count: %d, free_count: %d",
|
|
||||||
__LINE__, conn->ip_addr, conn->port,
|
|
||||||
ci->sock, cm->total_count, cm->free_count);
|
|
||||||
return ci;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_pool_close_connection_ex(ConnectionPool *cp, ConnectionInfo *conn,
|
|
||||||
const bool bForce)
|
|
||||||
{
|
|
||||||
char key[32];
|
|
||||||
int result;
|
|
||||||
int key_len;
|
|
||||||
ConnectionManager *cm;
|
|
||||||
ConnectionNode *node;
|
|
||||||
|
|
||||||
result = conn_pool_get_key(conn, key, &key_len);
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&cp->lock);
|
|
||||||
cm = (ConnectionManager *)hash_find(&cp->hash_array, key, key_len);
|
|
||||||
pthread_mutex_unlock(&cp->lock);
|
|
||||||
if (cm == NULL)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"hash entry of server %s:%d not exist", __LINE__, \
|
|
||||||
conn->ip_addr, conn->port);
|
|
||||||
return ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
node = (ConnectionNode *)(((char *)conn) + sizeof(ConnectionInfo));
|
|
||||||
if (node->manager != cm)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"manager of server entry %s:%d is invalid!", \
|
|
||||||
__LINE__, conn->ip_addr, conn->port);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&cm->lock);
|
|
||||||
if (bForce)
|
|
||||||
{
|
|
||||||
cm->total_count--;
|
|
||||||
|
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
|
||||||
"server %s:%d, release connection: %d, " \
|
|
||||||
"total_count: %d, free_count: %d",
|
|
||||||
__LINE__, conn->ip_addr, conn->port,
|
|
||||||
conn->sock, cm->total_count, cm->free_count);
|
|
||||||
|
|
||||||
conn_pool_disconnect_server(conn);
|
|
||||||
free(conn);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node->atime = get_current_time();
|
|
||||||
node->next = cm->head;
|
|
||||||
cm->head = node;
|
|
||||||
cm->free_count++;
|
|
||||||
|
|
||||||
logDebug("file: "__FILE__", line: %d, " \
|
|
||||||
"server %s:%d, free connection: %d, " \
|
|
||||||
"total_count: %d, free_count: %d",
|
|
||||||
__LINE__, conn->ip_addr, conn->port,
|
|
||||||
conn->sock, cm->total_count, cm->free_count);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&cm->lock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _conn_count_walk(const int index, const HashData *data, void *args)
|
|
||||||
{
|
|
||||||
int *count;
|
|
||||||
ConnectionManager *cm;
|
|
||||||
ConnectionNode *node;
|
|
||||||
|
|
||||||
count = (int *)args;
|
|
||||||
cm = (ConnectionManager *)data->value;
|
|
||||||
node = cm->head;
|
|
||||||
while (node != NULL)
|
|
||||||
{
|
|
||||||
(*count)++;
|
|
||||||
node = node->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int conn_pool_get_connection_count(ConnectionPool *cp)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
count = 0;
|
|
||||||
hash_walk(&cp->hash_array, _conn_count_walk, &count);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
**/
|
|
||||||
|
|
||||||
//connection_pool.h
|
|
||||||
|
|
||||||
#ifndef _CONNECTION_POOL_H
|
|
||||||
#define _CONNECTION_POOL_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include "common_define.h"
|
|
||||||
#include "pthread_func.h"
|
|
||||||
#include "hash.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int sock;
|
|
||||||
int port;
|
|
||||||
char ip_addr[IP_ADDRESS_SIZE];
|
|
||||||
} ConnectionInfo;
|
|
||||||
|
|
||||||
struct tagConnectionManager;
|
|
||||||
|
|
||||||
typedef struct tagConnectionNode {
|
|
||||||
ConnectionInfo *conn;
|
|
||||||
struct tagConnectionManager *manager;
|
|
||||||
struct tagConnectionNode *next;
|
|
||||||
time_t atime; //last access time
|
|
||||||
} ConnectionNode;
|
|
||||||
|
|
||||||
typedef struct tagConnectionManager {
|
|
||||||
ConnectionNode *head;
|
|
||||||
int total_count; //total connections
|
|
||||||
int free_count; //free connections
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
} ConnectionManager;
|
|
||||||
|
|
||||||
typedef struct tagConnectionPool {
|
|
||||||
HashArray hash_array; //key is ip:port, value is ConnectionManager
|
|
||||||
pthread_mutex_t lock;
|
|
||||||
int connect_timeout;
|
|
||||||
int max_count_per_entry; //0 means no limit
|
|
||||||
|
|
||||||
/*
|
|
||||||
connections whose the idle time exceeds this time will be closed
|
|
||||||
*/
|
|
||||||
int max_idle_time;
|
|
||||||
} ConnectionPool;
|
|
||||||
|
|
||||||
int conn_pool_init(ConnectionPool *cp, int connect_timeout, \
|
|
||||||
const int max_count_per_entry, const int max_idle_time);
|
|
||||||
void conn_pool_destroy(ConnectionPool *cp);
|
|
||||||
|
|
||||||
ConnectionInfo *conn_pool_get_connection(ConnectionPool *cp,
|
|
||||||
const ConnectionInfo *conn, int *err_no);
|
|
||||||
|
|
||||||
#define conn_pool_close_connection(cp, conn) \
|
|
||||||
conn_pool_close_connection_ex(cp, conn, false)
|
|
||||||
|
|
||||||
int conn_pool_close_connection_ex(ConnectionPool *cp, ConnectionInfo *conn,
|
|
||||||
const bool bForce);
|
|
||||||
|
|
||||||
void conn_pool_disconnect_server(ConnectionInfo *pConnection);
|
|
||||||
|
|
||||||
int conn_pool_connect_server(ConnectionInfo *pConnection, \
|
|
||||||
const int connect_timeout);
|
|
||||||
|
|
||||||
int conn_pool_get_connection_count(ConnectionPool *cp);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
@ -1,228 +0,0 @@
|
||||||
//fast_mblock.c
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "fast_mblock.h"
|
|
||||||
#include "logger.h"
|
|
||||||
#include "shared_func.h"
|
|
||||||
#include "pthread_func.h"
|
|
||||||
|
|
||||||
int fast_mblock_init(struct fast_mblock_man *mblock, const int element_size, \
|
|
||||||
const int alloc_elements_once)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (element_size <= 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"invalid block size: %d", \
|
|
||||||
__LINE__, element_size);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mblock->element_size = MEM_ALIGN(element_size);
|
|
||||||
if (alloc_elements_once > 0)
|
|
||||||
{
|
|
||||||
mblock->alloc_elements_once = alloc_elements_once;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int block_size;
|
|
||||||
block_size = MEM_ALIGN(sizeof(struct fast_mblock_node) \
|
|
||||||
+ mblock->element_size);
|
|
||||||
mblock->alloc_elements_once = (1024 * 1024) / block_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=init_pthread_lock(&(mblock->lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"init_pthread_lock fail, errno: %d, error info: %s", \
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
mblock->malloc_chain_head = NULL;
|
|
||||||
mblock->free_chain_head = NULL;
|
|
||||||
mblock->total_count = 0;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fast_mblock_prealloc(struct fast_mblock_man *mblock)
|
|
||||||
{
|
|
||||||
struct fast_mblock_node *pNode;
|
|
||||||
struct fast_mblock_malloc *pMallocNode;
|
|
||||||
char *pNew;
|
|
||||||
char *pTrunkStart;
|
|
||||||
char *p;
|
|
||||||
char *pLast;
|
|
||||||
int block_size;
|
|
||||||
int alloc_size;
|
|
||||||
|
|
||||||
block_size = MEM_ALIGN(sizeof(struct fast_mblock_node) + \
|
|
||||||
mblock->element_size);
|
|
||||||
alloc_size = sizeof(struct fast_mblock_malloc) + block_size * \
|
|
||||||
mblock->alloc_elements_once;
|
|
||||||
|
|
||||||
pNew = (char *)malloc(alloc_size);
|
|
||||||
if (pNew == NULL)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"malloc %d bytes fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, alloc_size, errno, STRERROR(errno));
|
|
||||||
return errno != 0 ? errno : ENOMEM;
|
|
||||||
}
|
|
||||||
memset(pNew, 0, alloc_size);
|
|
||||||
|
|
||||||
pMallocNode = (struct fast_mblock_malloc *)pNew;
|
|
||||||
|
|
||||||
pTrunkStart = pNew + sizeof(struct fast_mblock_malloc);
|
|
||||||
pLast = pNew + (alloc_size - block_size);
|
|
||||||
for (p=pTrunkStart; p<pLast; p += block_size)
|
|
||||||
{
|
|
||||||
pNode = (struct fast_mblock_node *)p;
|
|
||||||
pNode->next = (struct fast_mblock_node *)(p + block_size);
|
|
||||||
}
|
|
||||||
((struct fast_mblock_node *)pLast)->next = NULL;
|
|
||||||
mblock->free_chain_head = (struct fast_mblock_node *)pTrunkStart;
|
|
||||||
|
|
||||||
pMallocNode->next = mblock->malloc_chain_head;
|
|
||||||
mblock->malloc_chain_head = pMallocNode;
|
|
||||||
mblock->total_count += mblock->alloc_elements_once;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fast_mblock_destroy(struct fast_mblock_man *mblock)
|
|
||||||
{
|
|
||||||
struct fast_mblock_malloc *pMallocNode;
|
|
||||||
struct fast_mblock_malloc *pMallocTmp;
|
|
||||||
|
|
||||||
if (mblock->malloc_chain_head == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pMallocNode = mblock->malloc_chain_head;
|
|
||||||
while (pMallocNode != NULL)
|
|
||||||
{
|
|
||||||
pMallocTmp = pMallocNode;
|
|
||||||
pMallocNode = pMallocNode->next;
|
|
||||||
|
|
||||||
free(pMallocTmp);
|
|
||||||
}
|
|
||||||
mblock->malloc_chain_head = NULL;
|
|
||||||
mblock->free_chain_head = NULL;
|
|
||||||
mblock->total_count = 0;
|
|
||||||
|
|
||||||
pthread_mutex_destroy(&(mblock->lock));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock)
|
|
||||||
{
|
|
||||||
struct fast_mblock_node *pNode;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_lock(&(mblock->lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_lock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mblock->free_chain_head != NULL)
|
|
||||||
{
|
|
||||||
pNode = mblock->free_chain_head;
|
|
||||||
mblock->free_chain_head = pNode->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((result=fast_mblock_prealloc(mblock)) == 0)
|
|
||||||
{
|
|
||||||
pNode = mblock->free_chain_head;
|
|
||||||
mblock->free_chain_head = pNode->next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pNode = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_unlock(&(mblock->lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_unlock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
return pNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fast_mblock_free(struct fast_mblock_man *mblock, \
|
|
||||||
struct fast_mblock_node *pNode)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_lock(&(mblock->lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_lock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pNode->next = mblock->free_chain_head;
|
|
||||||
mblock->free_chain_head = pNode;
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_unlock(&(mblock->lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_unlock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fast_mblock_free_count(struct fast_mblock_man *mblock)
|
|
||||||
{
|
|
||||||
struct fast_mblock_node *pNode;
|
|
||||||
int count;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_lock(&(mblock->lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_lock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
pNode = mblock->free_chain_head;
|
|
||||||
while (pNode != NULL)
|
|
||||||
{
|
|
||||||
pNode = pNode->next;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result=pthread_mutex_unlock(&(mblock->lock))) != 0)
|
|
||||||
{
|
|
||||||
logError("file: "__FILE__", line: %d, " \
|
|
||||||
"call pthread_mutex_unlock fail, " \
|
|
||||||
"errno: %d, error info: %s", \
|
|
||||||
__LINE__, result, STRERROR(result));
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
/**
|
|
||||||
* 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_mblock.h
|
|
||||||
|
|
||||||
#ifndef _FAST_MBLOCK_H
|
|
||||||
#define _FAST_MBLOCK_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "common_define.h"
|
|
||||||
#include "chain.h"
|
|
||||||
|
|
||||||
/* free node chain */
|
|
||||||
struct fast_mblock_node
|
|
||||||
{
|
|
||||||
struct fast_mblock_node *next;
|
|
||||||
char data[0]; //the data buffer
|
|
||||||
};
|
|
||||||
|
|
||||||
/* malloc chain */
|
|
||||||
struct fast_mblock_malloc
|
|
||||||
{
|
|
||||||
struct fast_mblock_malloc *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fast_mblock_man
|
|
||||||
{
|
|
||||||
struct fast_mblock_node *free_chain_head; //free node chain
|
|
||||||
struct fast_mblock_malloc *malloc_chain_head; //malloc chain to be freed
|
|
||||||
int element_size; //element size
|
|
||||||
int alloc_elements_once; //alloc elements once
|
|
||||||
int total_count; //total element count
|
|
||||||
pthread_mutex_t lock; //the lock for read / write free node chain
|
|
||||||
};
|
|
||||||
|
|
||||||
#define fast_mblock_to_node_ptr(data_ptr) \
|
|
||||||
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
|
|
||||||
&((struct fast_mblock_node *)0)->data))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
mblock init
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
element_size: element size, such as sizeof(struct xxx)
|
|
||||||
alloc_elements_once: malloc elements once, 0 for malloc 1MB once
|
|
||||||
return error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
int fast_mblock_init(struct fast_mblock_man *mblock, const int element_size, \
|
|
||||||
const int alloc_elements_once);
|
|
||||||
|
|
||||||
/**
|
|
||||||
mblock destroy
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
*/
|
|
||||||
void fast_mblock_destroy(struct fast_mblock_man *mblock);
|
|
||||||
|
|
||||||
/**
|
|
||||||
alloc a node from the mblock
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
return the alloced node, return NULL if fail
|
|
||||||
*/
|
|
||||||
struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock);
|
|
||||||
|
|
||||||
/**
|
|
||||||
free a node (put a node to the mblock)
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
pNode: the node to free
|
|
||||||
return the alloced node, return NULL if fail
|
|
||||||
*/
|
|
||||||
int fast_mblock_free(struct fast_mblock_man *mblock, \
|
|
||||||
struct fast_mblock_node *pNode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
get node count of the mblock
|
|
||||||
parameters:
|
|
||||||
mblock: the mblock pointer
|
|
||||||
return the free node count of the mblock, return -1 if fail
|
|
||||||
*/
|
|
||||||
int fast_mblock_free_count(struct fast_mblock_man *mblock);
|
|
||||||
|
|
||||||
#define fast_mblock_total_count(mblock) (mblock)->total_count
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
@ -1,504 +0,0 @@
|
||||||
//fast_task_queue.c
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <inttypes.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: %"PRId64, __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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 nio_thread_data;
|
|
||||||
struct fast_task_info;
|
|
||||||
|
|
||||||
typedef int (*ThreadLoopCallback) (struct nio_thread_data *pThreadData);
|
|
||||||
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;
|
|
||||||
ThreadLoopCallback thread_loop_callback;
|
|
||||||
void *arg; //extra argument pointer
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fast_task_info
|
|
||||||
{
|
|
||||||
IOEventEntry event; //must first
|
|
||||||
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
|
|
||||||
int64_t 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
|
|
||||||
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
int g_fdfs_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
|
int g_fdfs_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
|
||||||
int g_fdfs_network_timeout = DEFAULT_NETWORK_TIMEOUT;
|
int g_fdfs_network_timeout = DEFAULT_NETWORK_TIMEOUT;
|
||||||
char g_fdfs_base_path[MAX_PATH_SIZE] = {'/', 't', 'm', 'p', '\0'};
|
char g_fdfs_base_path[MAX_PATH_SIZE] = {'/', 't', 'm', 'p', '\0'};
|
||||||
Version g_fdfs_version = {5, 3};
|
Version g_fdfs_version = {5, 4};
|
||||||
bool g_use_connection_pool = false;
|
bool g_use_connection_pool = false;
|
||||||
ConnectionPool g_connection_pool;
|
ConnectionPool g_connection_pool;
|
||||||
int g_connection_pool_max_idle_time = 3600;
|
int g_connection_pool_max_idle_time = 3600;
|
||||||
|
|
|
||||||
1403
common/hash.c
1403
common/hash.c
File diff suppressed because it is too large
Load Diff
381
common/hash.h
381
common/hash.h
|
|
@ -1,381 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
|
|
@ -1,331 +0,0 @@
|
||||||
|
|
||||||
/**
|
|
||||||
* 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_ex(const char *url, const int url_len,
|
|
||||||
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 out_len;
|
|
||||||
int alloc_size;
|
|
||||||
int recv_bytes;
|
|
||||||
int result;
|
|
||||||
int sock;
|
|
||||||
int port;
|
|
||||||
bool bNeedAlloc;
|
|
||||||
const char *pDomain;
|
|
||||||
const char *pContent;
|
|
||||||
const char *pURI;
|
|
||||||
char *pPort;
|
|
||||||
char *pSpace;
|
|
||||||
|
|
||||||
*http_status = 0;
|
|
||||||
if (*content == NULL)
|
|
||||||
{
|
|
||||||
bNeedAlloc = true;
|
|
||||||
alloc_size = 64 * 1024;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bNeedAlloc = false;
|
|
||||||
alloc_size = *content_len - 1;
|
|
||||||
}
|
|
||||||
*content_len = 0;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bNeedAlloc)
|
|
||||||
{
|
|
||||||
*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)
|
|
||||||
{
|
|
||||||
if (bNeedAlloc)
|
|
||||||
{
|
|
||||||
alloc_size *= 2;
|
|
||||||
*content = (char *)realloc(*content, alloc_size + 1);
|
|
||||||
if (*content == NULL)
|
|
||||||
{
|
|
||||||
*content_len = 0;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
|
||||||
"buffer size: %d is too small", \
|
|
||||||
__LINE__, alloc_size);
|
|
||||||
return ENOSPC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = tcprecvdata_ex(sock, *content + *content_len, \
|
|
||||||
recv_bytes, network_timeout, &recv_bytes);
|
|
||||||
|
|
||||||
*content_len += recv_bytes;
|
|
||||||
} while (result == 0);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (result == ENOTCONN)
|
|
||||||
{
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
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));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*(*content + *content_len) = '\0';
|
|
||||||
pContent = strstr(*content, "\r\n\r\n");
|
|
||||||
if (pContent == NULL)
|
|
||||||
{
|
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
|
||||||
"response data from %s:%d is invalid", \
|
|
||||||
__LINE__, domain_name, port);
|
|
||||||
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pContent += 4;
|
|
||||||
pSpace = strchr(*content, ' ');
|
|
||||||
if (pSpace == NULL || pSpace >= pContent)
|
|
||||||
{
|
|
||||||
sprintf(error_info, "file: "__FILE__", line: %d, " \
|
|
||||||
"response data from %s:%d is invalid", \
|
|
||||||
__LINE__, domain_name, port);
|
|
||||||
|
|
||||||
result = EINVAL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*http_status = atoi(pSpace + 1);
|
|
||||||
*content_len -= pContent - *content;
|
|
||||||
memcpy(*content, pContent, *content_len);
|
|
||||||
*(*content + *content_len) = '\0';
|
|
||||||
*error_info = '\0';
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
close(sock);
|
|
||||||
if (result != 0 && bNeedAlloc)
|
|
||||||
{
|
|
||||||
free(*content);
|
|
||||||
*content = NULL;
|
|
||||||
*content_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
*content = NULL;
|
|
||||||
return get_url_content_ex(url, strlen(url), connect_timeout, network_timeout,
|
|
||||||
http_status, content, content_len, error_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 in seconds
|
|
||||||
network_timeout: network timeout in 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 when input *content is NULL for auto malloc
|
|
||||||
content_len: input for *content buffer size when *content is NOT NULL,
|
|
||||||
output for content length (bytes)
|
|
||||||
return: 0 for success, != 0 for error
|
|
||||||
**/
|
|
||||||
int get_url_content_ex(const char *url, const int url_len,
|
|
||||||
const int connect_timeout, const int network_timeout,
|
|
||||||
int *http_status, char **content, int *content_len, char *error_info);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
get content from url
|
|
||||||
params:
|
|
||||||
url: the url to fetch, must start as: "http://"
|
|
||||||
connect_timeout: connect timeout in seconds
|
|
||||||
network_timeout: network timeout in 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
|
|
||||||
|
|
||||||
|
|
@ -1,785 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 + 1 + 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
*(pContext->config_path + len++) = '/';
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
179
common/ioevent.c
179
common/ioevent.c
|
|
@ -1,179 +0,0 @@
|
||||||
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
113
common/ioevent.h
113
common/ioevent.h
|
|
@ -1,113 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
#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 *current;
|
|
||||||
IOEventEntry *pEventEntry;
|
|
||||||
|
|
||||||
entry = head->next;
|
|
||||||
while (entry != NULL)
|
|
||||||
{
|
|
||||||
current = entry;
|
|
||||||
entry = entry->next;
|
|
||||||
|
|
||||||
pEventEntry = (IOEventEntry *)current->data;
|
|
||||||
if (pEventEntry != NULL)
|
|
||||||
{
|
|
||||||
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT,
|
|
||||||
current->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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pThreadData->thread_loop_callback != NULL) {
|
|
||||||
pThreadData->thread_loop_callback(pThreadData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
/**
|
|
||||||
* 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
801
common/logger.c
801
common/logger.c
|
|
@ -1,801 +0,0 @@
|
||||||
/**
|
|
||||||
* 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_init2()
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
if ((result=log_init()) != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_take_over_stderr();
|
|
||||||
log_take_over_stdout();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int log_init_ex(LogContext *pContext)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
memset(pContext, 0, sizeof(LogContext));
|
|
||||||
pContext->log_level = LOG_INFO;
|
|
||||||
pContext->log_fd = STDERR_FILENO;
|
|
||||||
pContext->time_precision = LOG_TIME_PRECISION_SECOND;
|
|
||||||
strcpy(pContext->rotate_time_format, "%Y%m%d_%H%M%S");
|
|
||||||
|
|
||||||
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\n", \
|
|
||||||
pContext->log_filename, errno, STRERROR(errno));
|
|
||||||
pContext->log_fd = STDERR_FILENO;
|
|
||||||
return errno != 0 ? errno : EACCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pContext->take_over_stderr) {
|
|
||||||
if (dup2(pContext->log_fd, STDERR_FILENO) < 0) {
|
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
|
||||||
"call dup2 fail, errno: %d, error info: %s\n",
|
|
||||||
__LINE__, errno, STRERROR(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pContext->take_over_stdout) {
|
|
||||||
if (dup2(pContext->log_fd, STDOUT_FILENO) < 0) {
|
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, "
|
|
||||||
"call dup2 fail, errno: %d, error info: %s\n",
|
|
||||||
__LINE__, errno, STRERROR(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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\n", \
|
|
||||||
pContext->log_filename, errno, STRERROR(errno));
|
|
||||||
return errno != 0 ? errno : EACCES;
|
|
||||||
}
|
|
||||||
if (pContext->current_size == 0 && pContext->print_header_callback != NULL)
|
|
||||||
{
|
|
||||||
pContext->print_header_callback(pContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if (log_filename == NULL) {
|
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
|
||||||
"log_filename is NULL!\n", __LINE__);
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
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_set_rotate_time_format(LogContext *pContext, const char *time_format)
|
|
||||||
{
|
|
||||||
snprintf(pContext->rotate_time_format,
|
|
||||||
sizeof(pContext->rotate_time_format),
|
|
||||||
"%s", time_format);
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_set_keep_days(LogContext *pContext, const int keep_days)
|
|
||||||
{
|
|
||||||
pContext->keep_days = keep_days;
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_callback)
|
|
||||||
{
|
|
||||||
pContext->print_header_callback = header_callback;
|
|
||||||
if (pContext->print_header_callback != NULL)
|
|
||||||
{
|
|
||||||
pthread_mutex_lock(&(pContext->log_thread_lock));
|
|
||||||
if (pContext->current_size == 0)
|
|
||||||
{
|
|
||||||
pContext->print_header_callback(pContext);
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&(pContext->log_thread_lock));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_take_over_stderr_ex(LogContext *pContext)
|
|
||||||
{
|
|
||||||
pContext->take_over_stderr = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_take_over_stdout_ex(LogContext *pContext)
|
|
||||||
{
|
|
||||||
pContext->take_over_stdout = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int log_delete_old_files(void *args)
|
|
||||||
{
|
|
||||||
LogContext *pContext;
|
|
||||||
char old_filename[MAX_PATH_SIZE + 32];
|
|
||||||
int len;
|
|
||||||
struct tm tm;
|
|
||||||
time_t the_time;
|
|
||||||
|
|
||||||
if (args == NULL)
|
|
||||||
{
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pContext = (LogContext *)args;
|
|
||||||
if (*(pContext->log_filename) == '\0' || \
|
|
||||||
*(pContext->rotate_time_format) == '\0')
|
|
||||||
{
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pContext->keep_days <= 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
the_time = get_current_time() - pContext->keep_days * 86400;
|
|
||||||
while (1) {
|
|
||||||
the_time -= 86400;
|
|
||||||
localtime_r(&the_time, &tm);
|
|
||||||
memset(old_filename, 0, sizeof(old_filename));
|
|
||||||
len = sprintf(old_filename, "%s.", pContext->log_filename);
|
|
||||||
strftime(old_filename + len, sizeof(old_filename) - len,
|
|
||||||
pContext->rotate_time_format, &tm);
|
|
||||||
if (unlink(old_filename) != 0)
|
|
||||||
{
|
|
||||||
if (errno != ENOENT)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
|
||||||
"unlink %s fail, errno: %d, error info: %s\n", \
|
|
||||||
__LINE__, old_filename, errno, STRERROR(errno));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int log_rotate(LogContext *pContext)
|
|
||||||
{
|
|
||||||
struct tm tm;
|
|
||||||
time_t current_time;
|
|
||||||
int len;
|
|
||||||
char old_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);
|
|
||||||
|
|
||||||
memset(old_filename, 0, sizeof(old_filename));
|
|
||||||
len = sprintf(old_filename, "%s.", pContext->log_filename);
|
|
||||||
strftime(old_filename + len, sizeof(old_filename) - len,
|
|
||||||
pContext->rotate_time_format, &tm);
|
|
||||||
if (access(old_filename, F_OK) == 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
|
||||||
"file: %s already exist, rotate file fail\n",
|
|
||||||
__LINE__, old_filename);
|
|
||||||
}
|
|
||||||
else if (rename(pContext->log_filename, old_filename) != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "file: "__FILE__", line: %d, " \
|
|
||||||
"rename %s to %s fail, errno: %d, error info: %s\n", \
|
|
||||||
__LINE__, pContext->log_filename, old_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, const bool bNeedLock)
|
|
||||||
{
|
|
||||||
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 (bNeedLock && (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);
|
|
||||||
if (bNeedLock)
|
|
||||||
{
|
|
||||||
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 (bNeedLock && (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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void log_it_ex2(LogContext *pContext, const char *caption, \
|
|
||||||
const char *text, const int text_len, \
|
|
||||||
const bool bNeedSync, const bool bNeedLock)
|
|
||||||
{
|
|
||||||
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, bNeedLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_it_ex2(pContext, caption, text, text_len, bNeedSync, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_it_ex2(pContext, caption, text, len, bNeedSync, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#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); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
log_it_ex2(pContext, caption, text, len, bNeedSync, true); \
|
|
||||||
|
|
||||||
|
|
||||||
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, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
299
common/logger.h
299
common/logger.h
|
|
@ -1,299 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
struct log_context;
|
|
||||||
|
|
||||||
//log header line callback
|
|
||||||
typedef void (*LogHeaderCallback)(struct log_context *pContext);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* if stderr to the log file */
|
|
||||||
bool take_over_stderr;
|
|
||||||
|
|
||||||
/* if stdout to the log file */
|
|
||||||
bool take_over_stdout;
|
|
||||||
|
|
||||||
/* time precision */
|
|
||||||
char time_precision;
|
|
||||||
|
|
||||||
/* save the log filename */
|
|
||||||
char log_filename[MAX_PATH_SIZE];
|
|
||||||
|
|
||||||
/* the time format for rotated filename,
|
|
||||||
* default: %Y%m%d_%H%M%S
|
|
||||||
* */
|
|
||||||
char rotate_time_format[32];
|
|
||||||
|
|
||||||
/* keep days for rotated log files */
|
|
||||||
int keep_days;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* log the header (title line) callback
|
|
||||||
* */
|
|
||||||
LogHeaderCallback print_header_callback;
|
|
||||||
} LogContext;
|
|
||||||
|
|
||||||
extern LogContext g_log_context;
|
|
||||||
|
|
||||||
/** init function using global log context
|
|
||||||
* return: 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
int log_init();
|
|
||||||
|
|
||||||
/** init function using global log context, take over stderr and stdout
|
|
||||||
* return: 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
int log_init2();
|
|
||||||
|
|
||||||
#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_take_over_stderr() log_take_over_stderr_ex(&g_log_context)
|
|
||||||
#define log_take_over_stdout() log_take_over_stdout_ex(&g_log_context)
|
|
||||||
|
|
||||||
#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);
|
|
||||||
|
|
||||||
/** set rotate time format, the time format same as function strftime
|
|
||||||
* parameters:
|
|
||||||
* pContext: the log context
|
|
||||||
* time_format: rotate time format
|
|
||||||
* return: none
|
|
||||||
*/
|
|
||||||
void log_set_rotate_time_format(LogContext *pContext, const char *time_format);
|
|
||||||
|
|
||||||
/** set keep days
|
|
||||||
* parameters:
|
|
||||||
* pContext: the log context
|
|
||||||
* keep_days: the keep days
|
|
||||||
* return: none
|
|
||||||
*/
|
|
||||||
void log_set_keep_days(LogContext *pContext, const int keep_days);
|
|
||||||
|
|
||||||
/** set print header callback
|
|
||||||
* parameters:
|
|
||||||
* pContext: the log context
|
|
||||||
* header_callback: the callback
|
|
||||||
* return: none
|
|
||||||
*/
|
|
||||||
void log_set_header_callback(LogContext *pContext, LogHeaderCallback header_callback);
|
|
||||||
|
|
||||||
/** set take_over_stderr to true
|
|
||||||
* return: none
|
|
||||||
*/
|
|
||||||
void log_take_over_stderr_ex(LogContext *pContext);
|
|
||||||
|
|
||||||
/** set take_over_stdout to true
|
|
||||||
* return: none
|
|
||||||
*/
|
|
||||||
void log_take_over_stdout_ex(LogContext *pContext);
|
|
||||||
|
|
||||||
/** 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);
|
|
||||||
|
|
||||||
/** log to file
|
|
||||||
* parameters:
|
|
||||||
* pContext: the log context
|
|
||||||
* caption: such as INFO, ERROR, NULL for no caption
|
|
||||||
* text: text string to log
|
|
||||||
* text_len: text string length (bytes)
|
|
||||||
* bNeedSync: if sync to file immediatelly
|
|
||||||
* return: none
|
|
||||||
*/
|
|
||||||
void log_it_ex2(LogContext *pContext, const char *caption, \
|
|
||||||
const char *text, const int text_len, \
|
|
||||||
const bool bNeedSync, const bool bNeedLock);
|
|
||||||
|
|
||||||
|
|
||||||
/** 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);
|
|
||||||
|
|
||||||
/** delete old log files
|
|
||||||
* parameters:
|
|
||||||
* args: should be (LogContext *)
|
|
||||||
* return: error no, 0 for success, != 0 fail
|
|
||||||
*/
|
|
||||||
int log_delete_old_files(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
|
|
||||||
|
|
||||||
356
common/md5.c
356
common/md5.c
|
|
@ -1,356 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
||||||
55
common/md5.h
55
common/md5.h
|
|
@ -1,55 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
||||||
|
|
@ -1,234 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
|
|
@ -1,193 +0,0 @@
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
|
|
@ -1,508 +0,0 @@
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
|
|
||||||
2083
common/shared_func.c
2083
common/shared_func.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,510 +0,0 @@
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/** 16 bits int convert to buffer (big-endian)
|
|
||||||
* parameters:
|
|
||||||
* n: 16 bits int value
|
|
||||||
* buff: the buffer, at least 2 bytes space, no tail \0
|
|
||||||
* return: none
|
|
||||||
*/
|
|
||||||
void short2buff(const short n, char *buff);
|
|
||||||
|
|
||||||
/** buffer convert to 16 bits int
|
|
||||||
* parameters:
|
|
||||||
* buff: big-endian 2 bytes buffer
|
|
||||||
* return: 16 bits int value
|
|
||||||
*/
|
|
||||||
short buff2short(const char *buff);
|
|
||||||
|
|
||||||
/** 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
|
|
||||||
|
|
||||||
1799
common/sockopt.c
1799
common/sockopt.c
File diff suppressed because it is too large
Load Diff
347
common/sockopt.h
347
common/sockopt.h
|
|
@ -1,347 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 in seconds
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/** recv data (non-block mode) in ms
|
|
||||||
* parameters:
|
|
||||||
* sock: the socket
|
|
||||||
* data: the buffer
|
|
||||||
* size: buffer size (max bytes can receive)
|
|
||||||
* timeout: read timeout in milliseconds
|
|
||||||
* count: store the bytes recveived
|
|
||||||
* return: error no, 0 success, != 0 fail
|
|
||||||
*/
|
|
||||||
int tcprecvdata_nb_ms(int sock, void *data, const int size, \
|
|
||||||
const int timeout_ms, 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
|
|
||||||
|
|
||||||
45
fastdfs.spec
45
fastdfs.spec
|
|
@ -1,13 +1,13 @@
|
||||||
%define FastDFS fastdfs
|
%define FastDFS fastdfs
|
||||||
%define FastdfsServer fastdfs-server
|
%define FDFSServer fastdfs-server
|
||||||
%define ClientName libfdfsclient
|
%define FDFSClient libfdfsclient
|
||||||
%define FastTool fastdfs-tool
|
%define FDFSTool fastdfs-tool
|
||||||
%define FastVersion 5.0.3
|
%define FDFSVersion 5.0.4
|
||||||
|
|
||||||
Name: %{FastDFS}
|
Name: %{FastDFS}
|
||||||
Version: %{FastVersion}
|
Version: %{FDFSVersion}
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: The fastdfs manager
|
Summary: FastDFS server and client
|
||||||
License: GPL
|
License: GPL
|
||||||
Group: Arch/Tech
|
Group: Arch/Tech
|
||||||
URL: http://perso.orange.fr/sebastien.godard/
|
URL: http://perso.orange.fr/sebastien.godard/
|
||||||
|
|
@ -20,31 +20,32 @@ Requires: %__cp %__mv %__chmod %__grep %__mkdir %__install %__id
|
||||||
%description
|
%description
|
||||||
This package provides tracker & storage of fastdfs
|
This package provides tracker & storage of fastdfs
|
||||||
|
|
||||||
%package -n %{FastdfsServer}
|
%package -n %{FDFSServer}
|
||||||
|
Requires: libfastcommon
|
||||||
Summary: fastdfs tracker & storage
|
Summary: fastdfs tracker & storage
|
||||||
|
|
||||||
%package -n %{FastTool}
|
%package -n %{FDFSTool}
|
||||||
Requires: libfastcommon
|
Requires: libfastcommon
|
||||||
Summary: fastdfs tools
|
Summary: fastdfs tools
|
||||||
|
|
||||||
%package -n %{ClientName}
|
%package -n %{FDFSClient}
|
||||||
Requires: libfastcommon
|
Requires: libfastcommon
|
||||||
Summary: The client dynamic library of fastdfs
|
Summary: The client dynamic library of fastdfs
|
||||||
|
|
||||||
%package -n %{ClientName}-devel
|
%package -n %{FDFSClient}-devel
|
||||||
Requires: %{ClientName}
|
Requires: %{FDFSClient}
|
||||||
Summary: The client header of fastdfs
|
Summary: The client header of fastdfs
|
||||||
|
|
||||||
%description -n %{FastdfsServer}
|
%description -n %{FDFSServer}
|
||||||
This package provides tracker & storage of fastdfs
|
This package provides tracker & storage of fastdfs
|
||||||
|
|
||||||
%description -n %{ClientName}
|
%description -n %{FDFSClient}
|
||||||
This package is client dynamic library of fastdfs
|
This package is client dynamic library of fastdfs
|
||||||
|
|
||||||
%description -n %{ClientName}-devel
|
%description -n %{FDFSClient}-devel
|
||||||
This package is client header of fastdfs
|
This package is client header of fastdfs client
|
||||||
|
|
||||||
%description -n %{FastTool}
|
%description -n %{FDFSTool}
|
||||||
This package is tools for fastdfs
|
This package is tools for fastdfs
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
|
|
@ -65,11 +66,11 @@ DESTDIR=$RPM_BUILD_ROOT ./make.sh install
|
||||||
|
|
||||||
#%find_lang %{name}
|
#%find_lang %{name}
|
||||||
|
|
||||||
%post -n %{FastdfsServer}
|
%post -n %{FDFSServer}
|
||||||
/sbin/chkconfig --add fdfs_trackerd
|
/sbin/chkconfig --add fdfs_trackerd
|
||||||
/sbin/chkconfig --add fdfs_storaged
|
/sbin/chkconfig --add fdfs_storaged
|
||||||
|
|
||||||
%preun -n %{FastdfsServer}
|
%preun -n %{FDFSServer}
|
||||||
/sbin/chkconfig --del fdfs_trackerd
|
/sbin/chkconfig --del fdfs_trackerd
|
||||||
/sbin/chkconfig --del fdfs_storaged
|
/sbin/chkconfig --del fdfs_storaged
|
||||||
|
|
||||||
|
|
@ -83,7 +84,7 @@ DESTDIR=$RPM_BUILD_ROOT ./make.sh install
|
||||||
#/usr/local/bin/*
|
#/usr/local/bin/*
|
||||||
#/usr/local/include/*
|
#/usr/local/include/*
|
||||||
|
|
||||||
%files -n %{FastdfsServer}
|
%files -n %{FDFSServer}
|
||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
/usr/bin/fdfs_trackerd
|
/usr/bin/fdfs_trackerd
|
||||||
/usr/bin/fdfs_storaged
|
/usr/bin/fdfs_storaged
|
||||||
|
|
@ -93,15 +94,15 @@ DESTDIR=$RPM_BUILD_ROOT ./make.sh install
|
||||||
/etc/fdfs/tracker.conf.sample
|
/etc/fdfs/tracker.conf.sample
|
||||||
/etc/fdfs/storage.conf.sample
|
/etc/fdfs/storage.conf.sample
|
||||||
|
|
||||||
%files -n %{ClientName}
|
%files -n %{FDFSClient}
|
||||||
/usr/lib64/libfdfsclient*
|
/usr/lib64/libfdfsclient*
|
||||||
/etc/fdfs/client.conf.sample
|
/etc/fdfs/client.conf.sample
|
||||||
|
|
||||||
%files -n %{ClientName}-devel
|
%files -n %{FDFSClient}-devel
|
||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
/usr/include/fastdfs/*
|
/usr/include/fastdfs/*
|
||||||
|
|
||||||
%files -n %{FastTool}
|
%files -n %{FDFSTool}
|
||||||
/usr/bin/fdfs_monitor
|
/usr/bin/fdfs_monitor
|
||||||
/usr/bin/fdfs_test
|
/usr/bin/fdfs_test
|
||||||
/usr/bin/fdfs_test1
|
/usr/bin/fdfs_test1
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ if test "$PHP_FASTDFS_CLIENT" != "no"; then
|
||||||
PHP_SUBST(FASTDFS_CLIENT_SHARED_LIBADD)
|
PHP_SUBST(FASTDFS_CLIENT_SHARED_LIBADD)
|
||||||
|
|
||||||
if test -z "$ROOT"; then
|
if test -z "$ROOT"; then
|
||||||
ROOT=/usr/local
|
ROOT=/usr
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PHP_ADD_INCLUDE($ROOT/include/fastcommon)
|
PHP_ADD_INCLUDE($ROOT/include/fastcommon)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,12 @@
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
COMPILE = $(CC) $(CFLAGS)
|
COMPILE = $(CC) $(CFLAGS)
|
||||||
INC_PATH = -I. -Itrunk_mgr -I../common -I../tracker -I../client -Ifdht_client -I/usr/local/include
|
INC_PATH = -I. -Itrunk_mgr -I../common -I../tracker -I../client -Ifdht_client -I/usr/include/fastcommon
|
||||||
LIB_PATH = -L/usr/local/lib $(LIBS)
|
LIB_PATH = -L/usr/local/lib $(LIBS) -lfastcommon
|
||||||
TARGET_PATH = $(TARGET_PREFIX)/bin
|
TARGET_PATH = $(TARGET_PREFIX)/bin
|
||||||
CONFIG_PATH = $(TARGET_CONF_PATH)
|
CONFIG_PATH = $(TARGET_CONF_PATH)
|
||||||
|
|
||||||
SHARED_OBJS = ../common/hash.o ../common/chain.o \
|
SHARED_OBJS = ../common/fdfs_global.o \
|
||||||
../common/shared_func.o ../common/ini_file_reader.o \
|
|
||||||
../common/logger.o ../common/sockopt.o ../common/fdfs_global.o \
|
|
||||||
../common/base64.o ../common/sched_thread.o \
|
|
||||||
../common/local_ip_func.o ../common/http_func.o \
|
|
||||||
../common/md5.o ../common/pthread_func.o \
|
|
||||||
../common/fast_mblock.o ../common/avl_tree.o \
|
|
||||||
../common/connection_pool.o ../common/process_ctrl.o \
|
|
||||||
../common/ioevent.o ../common/fast_timer.o \
|
|
||||||
../common/fast_task_queue.o ../common/ioevent_loop.o \
|
|
||||||
../tracker/fdfs_shared_func.o ../tracker/tracker_proto.o \
|
../tracker/fdfs_shared_func.o ../tracker/tracker_proto.o \
|
||||||
tracker_client_thread.o storage_global.o storage_func.o \
|
tracker_client_thread.o storage_global.o storage_func.o \
|
||||||
storage_service.o storage_sync.o storage_nio.o storage_dio.o \
|
storage_service.o storage_sync.o storage_nio.o storage_dio.o \
|
||||||
|
|
@ -44,6 +35,6 @@ install:
|
||||||
mkdir -p $(TARGET_PATH)
|
mkdir -p $(TARGET_PATH)
|
||||||
mkdir -p $(CONFIG_PATH)
|
mkdir -p $(CONFIG_PATH)
|
||||||
cp -f $(ALL_PRGS) $(TARGET_PATH)
|
cp -f $(ALL_PRGS) $(TARGET_PATH)
|
||||||
if [ ! -f $(CONFIG_PATH)/storage.conf ]; then cp -f ../conf/storage.conf $(CONFIG_PATH)/storage.conf.sample; fi
|
if [ ! -f $(CONFIG_PATH)/storage.conf.sample ]; then cp -f ../conf/storage.conf $(CONFIG_PATH)/storage.conf.sample; fi
|
||||||
clean:
|
clean:
|
||||||
rm -f $(ALL_OBJS) $(ALL_PRGS)
|
rm -f $(ALL_OBJS) $(ALL_PRGS)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,12 @@
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
COMPILE = $(CC) $(CFLAGS)
|
COMPILE = $(CC) $(CFLAGS)
|
||||||
INC_PATH = -I../common -I/usr/local/include
|
INC_PATH = -I../common -I/usr/include/fastcommon
|
||||||
LIB_PATH = -L/usr/local/lib $(LIBS)
|
LIB_PATH = -L/usr/local/lib $(LIBS) -lfastcommon
|
||||||
TARGET_PATH = $(TARGET_PREFIX)/bin
|
TARGET_PATH = $(TARGET_PREFIX)/bin
|
||||||
CONFIG_PATH = $(TARGET_CONF_PATH)
|
CONFIG_PATH = $(TARGET_CONF_PATH)
|
||||||
|
|
||||||
SHARED_OBJS = ../common/hash.o ../common/chain.o ../common/base64.o \
|
SHARED_OBJS = ../common/fdfs_global.o \
|
||||||
../common/shared_func.o ../common/ini_file_reader.o \
|
|
||||||
../common/logger.o ../common/sockopt.o ../common/fdfs_global.o \
|
|
||||||
../common/sched_thread.o ../common/http_func.o ../common/md5.o \
|
|
||||||
../common/pthread_func.o ../common/local_ip_func.o \
|
|
||||||
../common/connection_pool.o ../common/process_ctrl.o \
|
|
||||||
../common/ioevent.o ../common/fast_timer.o \
|
|
||||||
../common/fast_task_queue.o ../common/ioevent_loop.o \
|
|
||||||
tracker_proto.o tracker_mem.o tracker_service.o tracker_status.o \
|
tracker_proto.o tracker_mem.o tracker_service.o tracker_status.o \
|
||||||
tracker_global.o tracker_func.o \
|
tracker_global.o tracker_func.o \
|
||||||
fdfs_shared_func.o tracker_nio.o tracker_relationship.o \
|
fdfs_shared_func.o tracker_nio.o tracker_relationship.o \
|
||||||
|
|
@ -34,6 +27,6 @@ install:
|
||||||
mkdir -p $(TARGET_PATH)
|
mkdir -p $(TARGET_PATH)
|
||||||
mkdir -p $(CONFIG_PATH)
|
mkdir -p $(CONFIG_PATH)
|
||||||
cp -f $(ALL_PRGS) $(TARGET_PATH)
|
cp -f $(ALL_PRGS) $(TARGET_PATH)
|
||||||
if [ ! -f $(CONFIG_PATH)/tracker.conf ]; then cp -f ../conf/tracker.conf $(CONFIG_PATH)/tracker.conf.sample; fi
|
if [ ! -f $(CONFIG_PATH)/tracker.conf.sample ]; then cp -f ../conf/tracker.conf $(CONFIG_PATH)/tracker.conf.sample; fi
|
||||||
clean:
|
clean:
|
||||||
rm -f $(ALL_OBJS) $(ALL_PRGS)
|
rm -f $(ALL_OBJS) $(ALL_PRGS)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue