update source code from FastDFS V5.02

pull/1/head
yuqing 2014-05-29 09:21:50 +08:00
commit 0dd3d17c92
53 changed files with 14333 additions and 0 deletions

27
HISTORY Normal file
View File

@ -0,0 +1,27 @@
Version 1.06 2014-05-28
* update source code from FastDFS V5.02
Version 1.05 2012-07-08
* update source code from FastDFS V3.09
Version 1.04 2011-01-31
* update source code from FastDFS V2.08
Version 1.03 2010-11-16
* add local ip functions local_ip_func.c
Version 1.02 2010-07-02
* sockopt.c: tcprecvfile and tcpdiscard add parameter total_recv_bytes
* sockopt.h add non-block connect function connectserverbyip_nb
* log_init set log to cache to false (no cache)
Version 1.01 2010-05-15
* source file move to directory src
* header files add comments
* logger.h: correct function name from log_destory_ex to log_destroy_ex
* shared_func.h: getExeAbsolutePath change to getAbsolutePath
Version 1.00 2010-05-08
* first version

23
INSTALL Normal file
View File

@ -0,0 +1,23 @@
Copy right 2010 Happy Fish / YuQing
libfastcommon may be copied only under the terms of the Less GNU General
Public License(LGPL).
Please visit the libfastcommon Home Page for more detail.
English language: http://code.google.com/p/libfastcommon/
Chinese language: http://linux.chinaunix.net/bbs/forum-75-1.html
#step 1. download libfastcommon source package and unpack it,
tar xzf libfastcommon_v1.x.tar.gz
#for example:
tar xzf libfastcommon_v1.3.tar.gz
#step 2. enter the libfastcommon dir
cd libfastcommon
#step 3. make
./make.sh
#step 4. make install
./make.sh install

17
README Normal file
View File

@ -0,0 +1,17 @@
Copyright (C) 2010 Happy Fish / YuQing
libfastcommon may be copied only under the terms of the Less GNU General
Public License(LGPL).
Please visit the libfastcommon Home Page for more detail.
English language: http://code.google.com/p/libfastcommon/
Chinese language: http://linux.chinaunix.net/bbs/forum-75-1.html
c common functions library extracted from my open source projects FastDFS and
FastDHT. this library is very simple and stable.
functions including: string, logger, chain, hash, socket, ini file reader,
base64 encode / decode, url encode / decode etc.
detail info please see the c header files.

99
make.sh Executable file
View File

@ -0,0 +1,99 @@
tmp_src_filename=fast_check_bits.c
cat <<EOF > $tmp_src_filename
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
printf("%d\n", sizeof(long));
printf("%d\n", sizeof(off_t));
return 0;
}
EOF
gcc -D_FILE_OFFSET_BITS=64 -o a.out $tmp_src_filename
output=`./a.out`
if [ -f /bin/expr ]; then
EXPR=/bin/expr
else
EXPR=/usr/bin/expr
fi
count=0
int_bytes=4
off_bytes=8
for col in $output; do
if [ $count -eq 0 ]; then
int_bytes=$col
else
off_bytes=$col
fi
count=`$EXPR $count + 1`
done
/bin/rm -f a.out $tmp_src_filename
if [ "$int_bytes" -eq 8 ]; then
OS_BITS=64
else
OS_BITS=32
fi
if [ "$off_bytes" -eq 8 ]; then
OFF_BITS=64
else
OFF_BITS=32
fi
cat <<EOF > src/_os_bits.h
#ifndef _OS_BITS_H
#define _OS_BITS_H
#define OS_BITS $OS_BITS
#define OFF_BITS $OFF_BITS
#endif
EOF
DEBUG_FLAG=1
CFLAGS='-Wall -D_FILE_OFFSET_BITS=64'
if [ "$DEBUG_FLAG" = "1" ]; then
CFLAGS="$CFLAGS -g -DDEBUG_FLAG"
else
CFLAGS="$CFLAGS -O3"
fi
LIBS=''
uname=`uname`
if [ "$uname" = "Linux" ]; then
CFLAGS="$CFLAGS -DOS_LINUX -DIOEVENT_USE_EPOLL"
elif [ "$uname" = "FreeBSD" ]; then
CFLAGS="$CFLAGS -DOS_FREEBSD -DIOEVENT_USE_KQUEUE"
elif [ "$uname" = "SunOS" ]; then
CFLAGS="$CFLAGS -DOS_SUNOS -D_THREAD_SAFE -DIOEVENT_USE_PORT"
LIBS="$LIBS -lsocket -lnsl -lresolv"
export CC=gcc
elif [ "$uname" = "AIX" ]; then
CFLAGS="$CFLAGS -DOS_AIX -D_THREAD_SAFE"
export CC=gcc
elif [ "$uname" = "HP-UX" ]; then
CFLAGS="$CFLAGS -DOS_HPUX"
fi
if [ -f /usr/lib/libpthread.so ] || [ -f /usr/local/lib/libpthread.so ] || [ -f /usr/lib64/libpthread.so ] || [ -f /usr/lib/libpthread.a ] || [ -f /usr/local/lib/libpthread.a ] || [ -f /usr/lib64/libpthread.a ]; then
LIBS="$LIBS -lpthread"
else
line=`nm -D /usr/lib/libc_r.so | grep pthread_create | grep -w T`
if [ -n "$line" ]; then
LIBS="$LIBS -lc_r"
fi
fi
cd src
cp Makefile.in Makefile
perl -pi -e "s#\\\$\(CFLAGS\)#$CFLAGS#g" Makefile
perl -pi -e "s#\\\$\(LIBS\)#$LIBS#g" Makefile
make $1 $2

43
src/Makefile.in Normal file
View File

@ -0,0 +1,43 @@
.SUFFIXES: .c .o .lo
COMPILE = $(CC) $(CFLAGS)
INC_PATH =
LIB_PATH = -L/usr/local/lib $(LIBS)
FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
logger.lo sockopt.lo base64.lo sched_thread.lo \
http_func.lo md5.lo pthread_func.lo local_ip_func.lo \
avl_tree.lo ioevent.lo ioevent_loop.lo fast_task_queue.lo \
fast_timer.lo process_ctrl.lo
HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
shared_func.h pthread_func.h ini_file_reader.h _os_bits.h \
sockopt.h sched_thread.h http_func.h md5.h local_ip_func.h \
avl_tree.h ioevent.h ioevent_loop.h fast_task_queue.h \
fast_timer.h process_ctrl.h
ALL_OBJS = $(STATIC_OBJS) $(FAST_SHARED_OBJS)
ALL_PRGS =
ALL_LIBS = libfastcommon.so.1
all: $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)
libfastcommon.so.1:
$(COMPILE) -o $@ $< -shared $(FAST_SHARED_OBJS) $(LIB_PATH)
.o:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c:
$(COMPILE) -o $@ $< $(STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c.o:
$(COMPILE) -c -o $@ $< $(INC_PATH)
.c.lo:
$(COMPILE) -c -fPIC -o $@ $< $(INC_PATH)
install:
cp -f $(ALL_LIBS) /usr/local/lib/
mkdir -p /usr/local/include/fastcommon
cp -f $(HEADER_FILES) /usr/local/include/fastcommon
ln -fs /usr/local/lib/libfastcommon.so.1 /usr/local/lib/libfastcommon.so
sh ./fast_link_library.sh
clean:
rm -f $(ALL_OBJS) $(ALL_PRGS) $(ALL_LIBS)

7
src/_os_bits.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef _OS_BITS_H
#define _OS_BITS_H
#define OS_BITS 64
#define OFF_BITS 64
#endif

789
src/avl_tree.c Normal file
View File

@ -0,0 +1,789 @@
#include "avl_tree.h"
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
CompareFunc compare_func)
{
tree->root = NULL;
tree->free_data_func = free_data_func;
tree->compare_func = compare_func;
return 0;
}
static void avl_tree_destroy_loop(FreeDataFunc free_data_func, \
AVLTreeNode *pCurrentNode)
{
if (pCurrentNode->left != NULL)
{
avl_tree_destroy_loop(free_data_func, pCurrentNode->left);
}
if (pCurrentNode->right != NULL)
{
avl_tree_destroy_loop(free_data_func, pCurrentNode->right);
}
if (free_data_func != NULL)
{
free_data_func(pCurrentNode->data);
}
free(pCurrentNode);
}
void avl_tree_destroy(AVLTreeInfo *tree)
{
if (tree == NULL)
{
return;
}
if (tree->root != NULL)
{
avl_tree_destroy_loop(tree->free_data_func, tree->root);
tree->root = NULL;
}
}
static AVLTreeNode *createTreeNode(AVLTreeNode *pParentNode, void *target_data)
{
AVLTreeNode *pNewNode;
pNewNode = (AVLTreeNode *)malloc(sizeof(AVLTreeNode));
if (pNewNode == NULL)
{
/*
fprintf(stderr, "file: "__FILE__", line: %d, " \
"malloc %d bytes fail!\n", __LINE__, \
(int)sizeof(AVLTreeNode));
*/
return NULL;
}
pNewNode->left = pNewNode->right = NULL;
pNewNode->data = target_data;
pNewNode->balance = 0;
return pNewNode;
}
static void avlRotateLeft(AVLTreeNode *pRotateNode, AVLTreeNode **ppRaiseNode)
{
*ppRaiseNode = pRotateNode->right;
pRotateNode->right = (*ppRaiseNode)->left;
(*ppRaiseNode)->left = pRotateNode;
}
static void avlRotateRight(AVLTreeNode *pRotateNode, AVLTreeNode **ppRaiseNode)
{
*ppRaiseNode = pRotateNode->left;
pRotateNode->left = (*ppRaiseNode)->right;
(*ppRaiseNode)->right = pRotateNode;
}
static void avlLeftBalanceWhenInsert(AVLTreeNode **pTreeNode, int *taller)
{
AVLTreeNode *leftsub;
AVLTreeNode *rightsub;
leftsub = (*pTreeNode)->left;
switch (leftsub->balance)
{
case -1 :
(*pTreeNode)->balance = leftsub->balance = 0;
avlRotateRight (*pTreeNode, pTreeNode);
*taller = 0;
break;
case 0 :
break;
case 1 :
rightsub = leftsub->right;
switch ( rightsub->balance )
{
case -1:
(*pTreeNode)->balance = 1;
leftsub->balance = 0;
break;
case 0 :
(*pTreeNode)->balance = leftsub->balance = 0;
break;
case 1 :
(*pTreeNode)->balance = 0;
leftsub->balance = -1;
break;
}
rightsub->balance = 0;
avlRotateLeft( leftsub, &((*pTreeNode)->left));
avlRotateRight(*pTreeNode, pTreeNode);
*taller = 0;
}
}
static void avlRightBalanceWhenInsert(AVLTreeNode **pTreeNode, int *taller)
{
AVLTreeNode *rightsub;
AVLTreeNode *leftsub;
rightsub = (*pTreeNode)->right;
switch (rightsub->balance)
{
case 1:
(*pTreeNode)->balance = rightsub->balance = 0;
avlRotateLeft(*pTreeNode, pTreeNode);
*taller = 0;
break;
case 0:
break;
case -1:
leftsub = rightsub->left;
switch (leftsub->balance)
{
case 1 :
(*pTreeNode)->balance = -1;
rightsub->balance = 0;
break;
case 0 :
(*pTreeNode)->balance = rightsub->balance = 0;
break;
case -1 :
(*pTreeNode)->balance = 0;
rightsub->balance = 1;
break;
}
leftsub->balance = 0;
avlRotateRight(rightsub, &((*pTreeNode)->right));
avlRotateLeft(*pTreeNode, pTreeNode);
*taller = 0;
}
}
static int avl_tree_insert_loop(CompareFunc compare_func, AVLTreeNode **pCurrentNode, \
void *target_data, int *taller)
{
int nCompRes;
int success;
if (*pCurrentNode == NULL)
{
*pCurrentNode = createTreeNode(*pCurrentNode, target_data);
if (*pCurrentNode != NULL)
{
*taller = 1;
return 1;
}
else
{
return -ENOMEM;
}
}
nCompRes = compare_func((*pCurrentNode)->data, target_data);
if (nCompRes > 0)
{
success = avl_tree_insert_loop(compare_func, \
&((*pCurrentNode)->left), target_data, taller);
if (*taller != 0)
{
switch ((*pCurrentNode)->balance)
{
case -1:
avlLeftBalanceWhenInsert(pCurrentNode, taller);
break;
case 0:
(*pCurrentNode)->balance = -1;
break;
case 1:
(*pCurrentNode)->balance = 0;
*taller = 0;
break;
}
}
}
else if (nCompRes < 0)
{
success = avl_tree_insert_loop(compare_func, \
&((*pCurrentNode)->right), target_data, taller);
if (*taller != 0)
{
switch ((*pCurrentNode)->balance)
{
case -1:
(*pCurrentNode)->balance = 0;
*taller = 0;
break;
case 0:
(*pCurrentNode)->balance = 1;
break;
case 1:
avlRightBalanceWhenInsert(pCurrentNode, taller);
break;
}
}
}
else
{
return 0;
}
return success;
}
int avl_tree_insert(AVLTreeInfo *tree, void *data)
{
int taller;
taller = 0;
return avl_tree_insert_loop(tree->compare_func, &(tree->root), \
data, &taller);
}
static int avl_tree_replace_loop(CompareFunc compare_func, \
FreeDataFunc free_data_func, AVLTreeNode **pCurrentNode, \
void *target_data, int *taller)
{
int nCompRes;
int success;
if (*pCurrentNode == NULL )
{
*pCurrentNode = createTreeNode(*pCurrentNode, target_data);
if (*pCurrentNode != NULL)
{
*taller = 1;
return 1;
}
else
{
return -ENOMEM;
}
}
nCompRes = compare_func((*pCurrentNode)->data, target_data);
if (nCompRes > 0)
{
success = avl_tree_replace_loop(compare_func, free_data_func,
&((*pCurrentNode)->left), target_data, taller);
if (*taller != 0)
{
switch ((*pCurrentNode)->balance)
{
case -1:
avlLeftBalanceWhenInsert(pCurrentNode, taller);
break;
case 0:
(*pCurrentNode)->balance = -1;
break;
case 1:
(*pCurrentNode)->balance = 0;
*taller = 0;
break;
}
}
}
else if (nCompRes < 0)
{
success = avl_tree_replace_loop(compare_func, free_data_func,
&((*pCurrentNode)->right), target_data, taller);
if (*taller != 0)
{
switch ((*pCurrentNode)->balance)
{
case -1 :
(*pCurrentNode)->balance = 0;
*taller = 0;
break;
case 0 :
(*pCurrentNode)->balance = 1;
break;
case 1 :
avlRightBalanceWhenInsert(pCurrentNode, taller);
break;
}
}
}
else
{
if (free_data_func != NULL)
{
free_data_func((*pCurrentNode)->data);
}
(*pCurrentNode)->data = target_data;
return 0;
}
return success;
}
int avl_tree_replace(AVLTreeInfo *tree, void *data)
{
int taller;
taller = 0;
return avl_tree_replace_loop(tree->compare_func, \
tree->free_data_func, &(tree->root), data, &taller);
}
static AVLTreeNode *avl_tree_find_loop(CompareFunc compare_func, \
AVLTreeNode *pCurrentNode, void *target_data)
{
int nCompRes;
nCompRes = compare_func(pCurrentNode->data, target_data);
if (nCompRes > 0)
{
if (pCurrentNode->left == NULL)
{
return NULL;
}
else
{
return avl_tree_find_loop(compare_func, \
pCurrentNode->left, target_data);
}
}
else if (nCompRes < 0)
{
if (pCurrentNode->right == NULL)
{
return NULL;
}
else
{
return avl_tree_find_loop(compare_func, \
pCurrentNode->right, target_data);
}
}
else
{
return pCurrentNode;
}
}
static void *avl_tree_find_ge_loop(CompareFunc compare_func, \
AVLTreeNode *pCurrentNode, void *target_data)
{
int nCompRes;
void *found;
nCompRes = compare_func(pCurrentNode->data, target_data);
if (nCompRes > 0)
{
if (pCurrentNode->left == NULL)
{
return pCurrentNode->data;
}
found = avl_tree_find_ge_loop(compare_func, \
pCurrentNode->left, target_data);
return found != NULL ? found : pCurrentNode->data;
}
else if (nCompRes < 0)
{
if (pCurrentNode->right == NULL)
{
return NULL;
}
else
{
return avl_tree_find_ge_loop(compare_func, \
pCurrentNode->right, target_data);
}
}
else
{
return pCurrentNode->data;
}
}
void *avl_tree_find(AVLTreeInfo *tree, void *target_data)
{
AVLTreeNode *found;
if (tree->root == NULL)
{
return NULL;
}
found = avl_tree_find_loop(tree->compare_func, \
tree->root, target_data);
return found != NULL ? found->data : NULL;
}
void *avl_tree_find_ge(AVLTreeInfo *tree, void *target_data)
{
void *found;
if (tree->root == NULL)
{
found = NULL;
}
else
{
found = avl_tree_find_ge_loop(tree->compare_func, \
tree->root, target_data);
}
return found;
}
static void avlLeftBalanceWhenDelete(AVLTreeNode **pTreeNode, int *shorter)
{
AVLTreeNode *leftsub;
AVLTreeNode *rightsub;
leftsub = (*pTreeNode)->left;
switch (leftsub->balance)
{
case -1:
(*pTreeNode)->balance = leftsub->balance = 0;
avlRotateRight (*pTreeNode, pTreeNode);
break;
case 0:
leftsub->balance = 1;
avlRotateRight(*pTreeNode, pTreeNode);
*shorter = 0;
break;
case 1:
rightsub = leftsub->right;
switch ( rightsub->balance )
{
case -1:
(*pTreeNode)->balance = 1;
leftsub->balance = 0;
break;
case 0 :
(*pTreeNode)->balance = leftsub->balance = 0;
break;
case 1 :
(*pTreeNode)->balance = 0;
leftsub->balance = -1;
break;
}
rightsub->balance = 0;
avlRotateLeft( leftsub, &((*pTreeNode)->left));
avlRotateRight(*pTreeNode, pTreeNode);
break;
}
}
static void avlRightBalanceWhenDelete(AVLTreeNode **pTreeNode, int *shorter)
{
AVLTreeNode *rightsub;
AVLTreeNode *leftsub;
rightsub = (*pTreeNode)->right;
switch (rightsub->balance)
{
case 1:
(*pTreeNode)->balance = rightsub->balance = 0;
avlRotateLeft(*pTreeNode, pTreeNode);
break;
case 0:
rightsub->balance = -1;
avlRotateLeft(*pTreeNode, pTreeNode);
*shorter = 0;
break;
case -1:
leftsub = rightsub->left;
switch (leftsub->balance)
{
case 1:
(*pTreeNode)->balance = -1;
rightsub->balance = 0;
break;
case 0:
(*pTreeNode)->balance = rightsub->balance = 0;
break;
case -1:
(*pTreeNode)->balance = 0;
rightsub->balance = 1;
break;
}
leftsub->balance = 0;
avlRotateRight(rightsub, &((*pTreeNode)->right));
avlRotateLeft(*pTreeNode, pTreeNode);
break;
}
}
static int avl_tree_delete_loop(AVLTreeInfo *tree, AVLTreeNode **pCurrentNode,\
void *target_data, int *shorter, AVLTreeNode *pDeletedDataNode)
{
int nCompRes;
bool result;
AVLTreeNode *leftsub;
AVLTreeNode *rightsub;
if (pDeletedDataNode != NULL)
{
if ((*pCurrentNode)->right == NULL)
{
pDeletedDataNode->data = (*pCurrentNode)->data;
leftsub = (*pCurrentNode)->left;
free(*pCurrentNode);
*pCurrentNode = leftsub;
*shorter = 1;
return 1;
}
nCompRes = -1;
}
else
{
nCompRes = tree->compare_func((*pCurrentNode)->data, target_data);
}
if (nCompRes > 0)
{
if ((*pCurrentNode)->left == NULL)
{
return 0;
}
result = avl_tree_delete_loop(tree, &((*pCurrentNode)->left), \
target_data, shorter, pDeletedDataNode);
if (*shorter != 0)
{
switch ((*pCurrentNode)->balance)
{
case -1:
(*pCurrentNode)->balance = 0;
break;
case 0:
(*pCurrentNode)->balance = 1;
*shorter = 0;
break;
case 1:
avlRightBalanceWhenDelete(pCurrentNode, shorter);
break;
}
}
return result;
}
else if (nCompRes < 0)
{
if ((*pCurrentNode)->right == NULL)
{
return 0;
}
result = avl_tree_delete_loop(tree, &((*pCurrentNode)->right), \
target_data, shorter, pDeletedDataNode);
if (*shorter != 0)
{
switch ((*pCurrentNode)->balance)
{
case -1:
avlLeftBalanceWhenDelete(pCurrentNode, shorter);
break;
case 0:
(*pCurrentNode)->balance = -1;
*shorter = 0;
break;
case 1:
(*pCurrentNode)->balance = 0;
break;
}
}
return result;
}
else
{
if (tree->free_data_func != NULL)
{
tree->free_data_func((*pCurrentNode)->data);
}
leftsub = (*pCurrentNode)->left;
rightsub = (*pCurrentNode)->right;
if (leftsub == NULL)
{
free(*pCurrentNode);
*pCurrentNode = rightsub;
}
else if (rightsub == NULL)
{
free(*pCurrentNode);
*pCurrentNode = leftsub;
}
else
{
avl_tree_delete_loop(tree, &((*pCurrentNode)->left), \
target_data, shorter, *pCurrentNode);
if (*shorter != 0)
{
switch ((*pCurrentNode)->balance)
{
case -1:
(*pCurrentNode)->balance = 0;
break;
case 0:
(*pCurrentNode)->balance = 1;
*shorter = 0;
break;
case 1:
avlRightBalanceWhenDelete(pCurrentNode, shorter);
break;
}
}
return 1;
}
*shorter = 1;
return 1;
}
}
int avl_tree_delete(AVLTreeInfo *tree, void *data)
{
int shorter;
if (tree->root == NULL)
{
return 0;
}
shorter = 0;
return avl_tree_delete_loop(tree, &(tree->root), data, &shorter, NULL);
}
static int avl_tree_walk_loop(DataOpFunc data_op_func, \
AVLTreeNode *pCurrentNode, void *args)
{
int result;
if (pCurrentNode->left != NULL)
{
result = avl_tree_walk_loop(data_op_func, \
pCurrentNode->left, args);
if (result != 0)
{
return result;
}
}
if ((result=data_op_func(pCurrentNode->data, args)) != 0)
{
return result;
}
/*
if (pCurrentNode->balance >= -1 && pCurrentNode->balance <= 1)
{
//printf("==%d\n", pCurrentNode->balance);
}
else
{
printf("==bad %d!!!!!!!!!!!!\n", pCurrentNode->balance);
}
*/
if (pCurrentNode->right != NULL)
{
result = avl_tree_walk_loop(data_op_func, \
pCurrentNode->right, args);
}
return result;
}
int avl_tree_walk(AVLTreeInfo *tree, DataOpFunc data_op_func, void *args)
{
if (tree->root == NULL)
{
return 0;
}
else
{
return avl_tree_walk_loop(data_op_func, tree->root, args);
}
}
static void avl_tree_count_loop(AVLTreeNode *pCurrentNode, int *count)
{
if (pCurrentNode->left != NULL)
{
avl_tree_count_loop(pCurrentNode->left, count);
}
(*count)++;
if (pCurrentNode->right != NULL)
{
avl_tree_count_loop(pCurrentNode->right, count);
}
}
int avl_tree_count(AVLTreeInfo *tree)
{
int count;
if (tree->root == NULL)
{
return 0;
}
count = 0;
avl_tree_count_loop(tree->root, &count);
return count;
}
int avl_tree_depth(AVLTreeInfo *tree)
{
int depth;
AVLTreeNode *pNode;
if (tree->root == NULL)
{
return 0;
}
depth = 0;
pNode = tree->root;
while (pNode != NULL)
{
if (pNode->balance == -1)
{
pNode = pNode->left;
}
else
{
pNode = pNode->right;
}
depth++;
}
return depth;
}
/*
static void avl_tree_print_loop(AVLTreeNode *pCurrentNode)
{
printf("%ld left: %ld, right: %ld, balance: %d\n", pCurrentNode->data,
pCurrentNode->left != NULL ? pCurrentNode->left->data : 0,
pCurrentNode->right != NULL ? pCurrentNode->right->data : 0,
pCurrentNode->balance);
if (pCurrentNode->left != NULL)
{
avl_tree_print_loop(pCurrentNode->left);
}
if (pCurrentNode->right != NULL)
{
avl_tree_print_loop(pCurrentNode->right);
}
}
void avl_tree_print(AVLTreeInfo *tree)
{
if (tree->root == NULL)
{
return;
}
avl_tree_print_loop(tree->root);
}
*/

47
src/avl_tree.h Normal file
View File

@ -0,0 +1,47 @@
#ifndef AVL_TREE_H
#define AVL_TREE_H
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "common_define.h"
typedef struct tagAVLTreeNode {
void *data;
struct tagAVLTreeNode *left;
struct tagAVLTreeNode *right;
byte balance;
} AVLTreeNode;
typedef int (*DataOpFunc) (void *data, void *args);
typedef struct tagAVLTreeInfo {
AVLTreeNode *root;
FreeDataFunc free_data_func;
CompareFunc compare_func;
} AVLTreeInfo;
#ifdef __cplusplus
extern "C" {
#endif
int avl_tree_init(AVLTreeInfo *tree, FreeDataFunc free_data_func, \
CompareFunc compare_func);
void avl_tree_destroy(AVLTreeInfo *tree);
int avl_tree_insert(AVLTreeInfo *tree, void *data);
int avl_tree_replace(AVLTreeInfo *tree, void *data);
int avl_tree_delete(AVLTreeInfo *tree, void *data);
void *avl_tree_find(AVLTreeInfo *tree, void *target_data);
void *avl_tree_find_ge(AVLTreeInfo *tree, void *target_data);
int avl_tree_walk(AVLTreeInfo *tree, DataOpFunc data_op_func, void *args);
int avl_tree_count(AVLTreeInfo *tree);
int avl_tree_depth(AVLTreeInfo *tree);
//void avl_tree_print(AVLTreeInfo *tree);
#ifdef __cplusplus
}
#endif
#endif

393
src/base64.c Normal file
View File

@ -0,0 +1,393 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "base64.h"
/**
* Marker value for chars we just ignore, e.g. \n \r high ascii
*/
#define BASE64_IGNORE -1
/**
* Marker for = trailing pad
*/
#define BASE64_PAD -2
/**
* determines how long the lines are that are generated by encode.
* Ignored by decode.
* @param length 0 means no newlines inserted. Must be a multiple of 4.
*/
void base64_set_line_length(struct base64_context *context, const int length)
{
context->line_length = (length / 4) * 4;
}
/**
* How lines are separated.
* Ignored by decode.
* @param context->line_separator may be "" but not null.
* Usually contains only a combination of chars \n and \r.
* Could be any chars not in set A-Z a-z 0-9 + /.
*/
void base64_set_line_separator(struct base64_context *context, \
const char *pLineSeparator)
{
context->line_sep_len = snprintf(context->line_separator, \
sizeof(context->line_separator), "%s", pLineSeparator);
}
void base64_init_ex(struct base64_context *context, const int nLineLength, \
const unsigned char chPlus, const unsigned char chSplash, \
const unsigned char chPad)
{
int i;
memset(context, 0, sizeof(struct base64_context));
context->line_length = nLineLength;
context->line_separator[0] = '\n';
context->line_separator[1] = '\0';
context->line_sep_len = 1;
// build translate valueToChar table only once.
// 0..25 -> 'A'..'Z'
for (i=0; i<=25; i++)
{
context->valueToChar[i] = (char)('A'+i);
}
// 26..51 -> 'a'..'z'
for (i=0; i<=25; i++ )
{
context->valueToChar[i+26] = (char)('a'+i);
}
// 52..61 -> '0'..'9'
for (i=0; i<=9; i++ )
{
context->valueToChar[i+52] = (char)('0'+i);
}
context->valueToChar[62] = chPlus;
context->valueToChar[63] = chSplash;
memset(context->charToValue, BASE64_IGNORE, sizeof(context->charToValue));
for (i=0; i<64; i++ )
{
context->charToValue[context->valueToChar[i]] = i;
}
context->pad_ch = chPad;
context->charToValue[chPad] = BASE64_PAD;
}
int base64_get_encode_length(struct base64_context *context, const int nSrcLen)
{
// Each group or partial group of 3 bytes becomes four chars
// covered quotient
int outputLength;
outputLength = ((nSrcLen + 2) / 3) * 4;
// account for trailing newlines, on all but the very last line
if (context->line_length != 0)
{
int lines = (outputLength + context->line_length - 1) /
context->line_length - 1;
if ( lines > 0 )
{
outputLength += lines * context->line_sep_len;
}
}
return outputLength;
}
/**
* Encode an arbitrary array of bytes as base64 printable ASCII.
* It will be broken into lines of 72 chars each. The last line is not
* terminated with a line separator.
* The output will always have an even multiple of data characters,
* exclusive of \n. It is padded out with =.
*/
char *base64_encode_ex(struct base64_context *context, const char *src, \
const int nSrcLen, char *dest, int *dest_len, const bool bPad)
{
int linePos;
int leftover;
int combined;
char *pDest;
int c0, c1, c2, c3;
unsigned char *pRaw;
unsigned char *pEnd;
const char *ppSrcs[2];
int lens[2];
char szPad[3];
int k;
int loop;
if (nSrcLen <= 0)
{
*dest = '\0';
*dest_len = 0;
return dest;
}
linePos = 0;
lens[0] = (nSrcLen / 3) * 3;
lens[1] = 3;
leftover = nSrcLen - lens[0];
ppSrcs[0] = src;
ppSrcs[1] = szPad;
szPad[0] = szPad[1] = szPad[2] = '\0';
switch (leftover)
{
case 0:
default:
loop = 1;
break;
case 1:
loop = 2;
szPad[0] = src[nSrcLen-1];
break;
case 2:
loop = 2;
szPad[0] = src[nSrcLen-2];
szPad[1] = src[nSrcLen-1];
break;
}
pDest = dest;
for (k=0; k<loop; k++)
{
pEnd = (unsigned char *)ppSrcs[k] + lens[k];
for (pRaw=(unsigned char *)ppSrcs[k]; pRaw<pEnd; pRaw+=3)
{
// Start a new line if next 4 chars won't fit on the current line
// We can't encapsulete the following code since the variable need to
// be local to this incarnation of encode.
linePos += 4;
if (linePos > context->line_length)
{
if (context->line_length != 0)
{
memcpy(pDest, context->line_separator, context->line_sep_len);
pDest += context->line_sep_len;
}
linePos = 4;
}
// get next three bytes in unsigned form lined up,
// in big-endian order
combined = ((*pRaw) << 16) | ((*(pRaw+1)) << 8) | (*(pRaw+2));
// break those 24 bits into a 4 groups of 6 bits,
// working LSB to MSB.
c3 = combined & 0x3f;
combined >>= 6;
c2 = combined & 0x3f;
combined >>= 6;
c1 = combined & 0x3f;
combined >>= 6;
c0 = combined & 0x3f;
// Translate into the equivalent alpha character
// emitting them in big-endian order.
*pDest++ = context->valueToChar[c0];
*pDest++ = context->valueToChar[c1];
*pDest++ = context->valueToChar[c2];
*pDest++ = context->valueToChar[c3];
}
}
*pDest = '\0';
*dest_len = pDest - dest;
// deal with leftover bytes
switch (leftover)
{
case 0:
default:
// nothing to do
break;
case 1:
// One leftover byte generates xx==
if (bPad)
{
*(pDest-1) = context->pad_ch;
*(pDest-2) = context->pad_ch;
}
else
{
*(pDest-2) = '\0';
*dest_len -= 2;
}
break;
case 2:
// Two leftover bytes generates xxx=
if (bPad)
{
*(pDest-1) = context->pad_ch;
}
else
{
*(pDest-1) = '\0';
*dest_len -= 1;
}
break;
} // end switch;
return dest;
}
char *base64_decode_auto(struct base64_context *context, const char *src, \
const int nSrcLen, char *dest, int *dest_len)
{
int nRemain;
int nPadLen;
int nNewLen;
char tmpBuff[256];
char *pBuff;
nRemain = nSrcLen % 4;
if (nRemain == 0)
{
return base64_decode(context, src, nSrcLen, dest, dest_len);
}
nPadLen = 4 - nRemain;
nNewLen = nSrcLen + nPadLen;
if (nNewLen <= sizeof(tmpBuff))
{
pBuff = tmpBuff;
}
else
{
pBuff = (char *)malloc(nNewLen);
if (pBuff == NULL)
{
fprintf(stderr, "Can't malloc %d bytes\n", \
nSrcLen + nPadLen + 1);
*dest_len = 0;
*dest = '\0';
return dest;
}
}
memcpy(pBuff, src, nSrcLen);
memset(pBuff + nSrcLen, context->pad_ch, nPadLen);
base64_decode(context, pBuff, nNewLen, dest, dest_len);
if (pBuff != tmpBuff)
{
free(pBuff);
}
return dest;
}
/**
* decode a well-formed complete base64 string back into an array of bytes.
* It must have an even multiple of 4 data characters (not counting \n),
* padded out with = as needed.
*/
char *base64_decode(struct base64_context *context, const char *src, \
const int nSrcLen, char *dest, int *dest_len)
{
// tracks where we are in a cycle of 4 input chars.
int cycle;
// where we combine 4 groups of 6 bits and take apart as 3 groups of 8.
int combined;
// will be an even multiple of 4 chars, plus some embedded \n
int dummies;
int value;
unsigned char *pSrc;
unsigned char *pSrcEnd;
char *pDest;
cycle = 0;
combined = 0;
dummies = 0;
pDest = dest;
pSrcEnd = (unsigned char *)src + nSrcLen;
for (pSrc=(unsigned char *)src; pSrc<pSrcEnd; pSrc++)
{
value = context->charToValue[*pSrc];
switch (value)
{
case BASE64_IGNORE:
// e.g. \n, just ignore it.
break;
case BASE64_PAD:
value = 0;
dummies++;
// fallthrough
default:
/* regular value character */
switch (cycle)
{
case 0:
combined = value;
cycle = 1;
break;
case 1:
combined <<= 6;
combined |= value;
cycle = 2;
break;
case 2:
combined <<= 6;
combined |= value;
cycle = 3;
break;
case 3:
combined <<= 6;
combined |= value;
// we have just completed a cycle of 4 chars.
// the four 6-bit values are in combined in big-endian order
// peel them off 8 bits at a time working lsb to msb
// to get our original 3 8-bit bytes back
*pDest++ = (char)(combined >> 16);
*pDest++ = (char)((combined & 0x0000FF00) >> 8);
*pDest++ = (char)(combined & 0x000000FF);
cycle = 0;
break;
}
break;
}
} // end for
if (cycle != 0)
{
*dest = '\0';
*dest_len = 0;
fprintf(stderr, "Input to decode not an even multiple of " \
"4 characters; pad with %c\n", context->pad_ch);
return dest;
}
*dest_len = (pDest - dest) - dummies;
*(dest + (*dest_len)) = '\0';
return dest;
}

134
src/base64.h Normal file
View File

@ -0,0 +1,134 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//base64.h
#ifndef _BASE64_H
#define _BASE64_H
#include "common_define.h"
struct base64_context
{
char line_separator[16];
int line_sep_len;
/**
* max chars per line, excluding line_separator. A multiple of 4.
*/
int line_length;
/**
* letter of the alphabet used to encode binary values 0..63
*/
unsigned char valueToChar[64];
/**
* binary value encoded by a given letter of the alphabet 0..63
*/
int charToValue[256];
int pad_ch;
};
#ifdef __cplusplus
extern "C" {
#endif
/** use stardand base64 charset
*/
#define base64_init(context, nLineLength) \
base64_init_ex(context, nLineLength, '+', '/', '=')
/** stardand base64 encode
*/
#define base64_encode(context, src, nSrcLen, dest, dest_len) \
base64_encode_ex(context, src, nSrcLen, dest, dest_len, true)
/** base64 init function, before use base64 function, you should call
* this function
* parameters:
* context: the base64 context
* nLineLength: length of a line, 0 for never add line seperator
* chPlus: specify a char for base64 char plus (+)
* chSplash: specify a char for base64 char splash (/)
* chPad: specify a char for base64 padding char =
* return: none
*/
void base64_init_ex(struct base64_context *context, const int nLineLength, \
const unsigned char chPlus, const unsigned char chSplash, \
const unsigned char chPad);
/** calculate the encoded length of the source buffer
* parameters:
* context: the base64 context
* nSrcLen: the source buffer length
* return: the encoded length of the source buffer
*/
int base64_get_encode_length(struct base64_context *context, const int nSrcLen);
/** base64 encode buffer
* parameters:
* context: the base64 context
* src: the source buffer
* nSrcLen: the source buffer length
* dest: the dest buffer
* dest_len: return dest buffer length
* bPad: if padding
* return: the encoded buffer
*/
char *base64_encode_ex(struct base64_context *context, const char *src, \
const int nSrcLen, char *dest, int *dest_len, const bool bPad);
/** base64 decode buffer, work only with padding source string
* parameters:
* context: the base64 context
* src: the source buffer with padding
* nSrcLen: the source buffer length
* dest: the dest buffer
* dest_len: return dest buffer length
* return: the decoded buffer
*/
char *base64_decode(struct base64_context *context, const char *src, \
const int nSrcLen, char *dest, int *dest_len);
/** base64 decode buffer, can work with no padding source string
* parameters:
* context: the base64 context
* src: the source buffer with padding or no padding
* nSrcLen: the source buffer length
* dest: the dest buffer
* dest_len: return dest buffer length
* return: the decoded buffer
*/
char *base64_decode_auto(struct base64_context *context, const char *src, \
const int nSrcLen, char *dest, int *dest_len);
/** set line separator string, such as \n or \r\n
* parameters:
* context: the base64 context
* pLineSeparator: the line separator string
* return: none
*/
void base64_set_line_separator(struct base64_context *context, \
const char *pLineSeparator);
/** set line length, 0 for never add line separators
* parameters:
* context: the base64 context
* length: the line length
* return: none
*/
void base64_set_line_length(struct base64_context *context, const int length);
#ifdef __cplusplus
}
#endif
#endif

325
src/chain.c Normal file
View File

@ -0,0 +1,325 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "chain.h"
//#include "use_mmalloc.h"
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
CompareFunc compareFunc)
{
if (pList == NULL)
{
return;
}
pList->head = NULL;
pList->tail = NULL;
pList->type = type;
pList->freeDataFunc = freeDataFunc;
pList->compareFunc = compareFunc;
return;
}
void chain_destroy(ChainList *pList)
{
ChainNode *pNode;
ChainNode *pDeleted;
if (pList == NULL || pList->head == NULL)
{
return;
}
pNode = pList->head;
while (pNode != NULL)
{
pDeleted = pNode;
pNode = pNode->next;
freeChainNode(pList, pDeleted);
}
pList->head = pList->tail = NULL;
}
void freeChainNode(ChainList *pList, ChainNode *pChainNode)
{
if (pList->freeDataFunc != NULL)
{
pList->freeDataFunc(pChainNode->data);
}
free(pChainNode);
}
int insertNodePrior(ChainList *pList, void *data)
{
ChainNode *pNode;
if (pList == NULL)
{
return EINVAL;
}
pNode = (ChainNode *)malloc(sizeof(ChainNode));
if (pNode == NULL)
{
return ENOMEM;
}
pNode->data = data;
pNode->next = pList->head;
pList->head = pNode;
if (pList->tail == NULL)
{
pList->tail = pNode;
}
return 0;
}
int appendNode(ChainList *pList, void *data)
{
ChainNode *pNode;
if (pList == NULL)
{
return EINVAL;
}
pNode = (ChainNode *)malloc(sizeof(ChainNode));
if (pNode == NULL)
{
return ENOMEM;
}
pNode->data = data;
pNode->next = NULL;
if (pList->tail != NULL)
{
pList->tail->next = pNode;
}
pList->tail = pNode;
if (pList->head == NULL)
{
pList->head = pNode;
}
return 0;
}
int insertNodeAsc(ChainList *pList, void *data)
{
ChainNode *pNew;
ChainNode *pNode;
ChainNode *pPrevious;
if (pList == NULL || pList->compareFunc == NULL)
{
return EINVAL;
}
pNew = (ChainNode *)malloc(sizeof(ChainNode));
if (pNew == NULL)
{
return ENOMEM;
}
pNew->data = data;
pPrevious = NULL;
pNode = pList->head;
while (pNode != NULL && pList->compareFunc(pNode->data, data) < 0)
{
pPrevious = pNode;
pNode = pNode->next;
}
pNew->next = pNode;
if (pPrevious == NULL)
{
pList->head = pNew;
}
else
{
pPrevious->next = pNew;
}
if (pNode == NULL)
{
pList->tail = pNew;
}
return 0;
}
int addNode(ChainList *pList, void *data)
{
if (pList->type == CHAIN_TYPE_INSERT)
{
return insertNodePrior(pList, data);
}
else if (pList->type == CHAIN_TYPE_APPEND)
{
return appendNode(pList, data);
}
else
{
return insertNodeAsc(pList, data);
}
}
void deleteNodeEx(ChainList *pList, ChainNode *pPreviousNode, \
ChainNode *pDeletedNode)
{
if (pDeletedNode == pList->head)
{
pList->head = pDeletedNode->next;
}
else
{
pPreviousNode->next = pDeletedNode->next;
}
if (pDeletedNode == pList->tail)
{
pList->tail = pPreviousNode;
}
freeChainNode(pList, pDeletedNode);
}
void deleteToNodePrevious(ChainList *pList, ChainNode *pPreviousNode, \
ChainNode *pDeletedNext)
{
ChainNode *pNode;
ChainNode *pDeletedNode;
if (pPreviousNode == NULL)
{
pNode = pList->head;
pList->head = pDeletedNext;
}
else
{
pNode = pPreviousNode->next;
pPreviousNode->next = pDeletedNext;
}
while (pNode != NULL && pNode != pDeletedNext)
{
pDeletedNode = pNode;
pNode = pNode->next;
freeChainNode(pList, pDeletedNode);
}
if (pDeletedNext == NULL)
{
pList->tail = pPreviousNode;
}
}
void *chain_pop_head(ChainList *pList)
{
ChainNode *pDeletedNode;
void *data;
pDeletedNode = pList->head;
if (pDeletedNode == NULL)
{
return NULL;
}
pList->head = pDeletedNode->next;
if (pList->head == NULL)
{
pList->tail = NULL;
}
data = pDeletedNode->data;
free(pDeletedNode);
return data;
}
int chain_count(ChainList *pList)
{
ChainNode *pNode;
int count;
count = 0;
pNode = pList->head;
while (pNode != NULL)
{
count++;
pNode = pNode->next;
}
return count;
}
int deleteNode(ChainList *pList, void *data, bool bDeleteAll)
{
ChainNode *pNode;
ChainNode *pPrevious;
ChainNode *pDeleted;
int nCount;
int nCompareRes;
if (pList == NULL || pList->compareFunc == NULL)
{
return -EINVAL;
}
nCount = 0;
pPrevious = NULL;
pNode = pList->head;
while (pNode != NULL)
{
nCompareRes = pList->compareFunc(pNode->data, data);
if (nCompareRes == 0)
{
pDeleted = pNode;
pNode = pNode->next;
deleteNodeEx(pList, pPrevious, pDeleted);
nCount++;
if (!bDeleteAll)
{
break;
}
continue;
}
else if(nCompareRes > 0 && pList->type == CHAIN_TYPE_SORTED)
{
break;
}
pPrevious = pNode;
pNode = pNode->next;
}
return nCount;
}
int deleteOne(ChainList *pList, void *data)
{
return deleteNode(pList, data, false);
}
int deleteAll(ChainList *pList, void *data)
{
return deleteNode(pList, data, true);
}

148
src/chain.h Normal file
View File

@ -0,0 +1,148 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#ifndef CHAIN_H
#define CHAIN_H
#include "common_define.h"
#define CHAIN_TYPE_INSERT 0 //insert new node before head
#define CHAIN_TYPE_APPEND 1 //insert new node after tail
#define CHAIN_TYPE_SORTED 2 //sorted chain
typedef struct tagChainNode
{
void *data;
struct tagChainNode *next;
} ChainNode;
typedef struct
{
int type;
ChainNode *head;
ChainNode *tail;
FreeDataFunc freeDataFunc;
CompareFunc compareFunc;
} ChainList;
#ifdef __cplusplus
extern "C" {
#endif
/** chain init function
* parameters:
* pList: the chain list
* type: chain type, value is one of following:
* CHAIN_TYPE_INSERT: insert new node before head
* CHAIN_TYPE_APPEND: insert new node after tail
* CHAIN_TYPE_SORTED: sorted chain
* freeDataFunc: free data function pointer, can be NULL
* compareFunc: compare data function pointer, can be NULL,
* must set when type is CHAIN_TYPE_SORTED
* return: none
*/
void chain_init(ChainList *pList, const int type, FreeDataFunc freeDataFunc, \
CompareFunc compareFunc);
/** destroy chain
* parameters:
* pList: the chain list
* return: none
*/
void chain_destroy(ChainList *pList);
/** get the chain node count
* parameters:
* pList: the chain list
* return: chain node count
*/
int chain_count(ChainList *pList);
/** add a new node to the chain
* parameters:
* pList: the chain list
* data: the data to add
* return: error no, 0 for success, != 0 fail
*/
int addNode(ChainList *pList, void *data);
/** free the chain node
* parameters:
* pList: the chain list
* pChainNode: the chain node to free
* return: none
*/
void freeChainNode(ChainList *pList, ChainNode *pChainNode);
/** delete the chain node
* parameters:
* pList: the chain list
* pPreviousNode: the previous chain node
* pDeletedNode: the chain node to delete
* return: none
*/
void deleteNodeEx(ChainList *pList, ChainNode *pPreviousNode, \
ChainNode *pDeletedNode);
/** delete the chain nodes from pPreviousNode->next to pDeletedNext
* (not including pDeletedNext)
* parameters:
* pList: the chain list
* pPreviousNode: the previous chain node, delete from pPreviousNode->next
* pDeletedNext: the chain node after the deleted node
* return: none
*/
void deleteToNodePrevious(ChainList *pList, ChainNode *pPreviousNode, \
ChainNode *pDeletedNext);
/** delete the chain node using data compare function
* parameters:
* pList: the chain list
* data: the first node whose data equals this will be deleted
* return: delete chain node count, < 0 fail
*/
int deleteOne(ChainList *pList, void *data);
/** delete all chain nodes using data compare function
* parameters:
* pList: the chain list
* data: the node whose data equals this will be deleted
* return: delete chain node count, < 0 fail
*/
int deleteAll(ChainList *pList, void *data);
/** pop up a chain nodes from chain head
* parameters:
* pList: the chain list
* return: the head node, return NULL when the chain is empty
*/
void *chain_pop_head(ChainList *pList);
/** add a chain nodes before the chain head
* parameters:
* pList: the chain list
* data: the node to insert
* return: error no, 0 for success, != 0 fail
*/
int insertNodePrior(ChainList *pList, void *data);
/** add a chain nodes after the chain tail
* parameters:
* pList: the chain list
* data: the node to insert
* return: error no, 0 for success, != 0 fail
*/
int appendNode(ChainList *pList, void *data);
#ifdef __cplusplus
}
#endif
#endif

169
src/common_define.h Normal file
View File

@ -0,0 +1,169 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//common_define.h
#ifndef _COMMON_DEFINE_H_
#define _COMMON_DEFINE_H_
#include <pthread.h>
#include <errno.h>
#ifdef WIN32
#include <windows.h>
#include <winsock.h>
typedef UINT in_addr_t;
#define FILE_SEPERATOR "\\"
#define THREAD_ENTRANCE_FUNC_DECLARE DWORD WINAPI
#define THREAD_RETURN_VALUE 0
typedef DWORD (WINAPI *ThreadEntranceFunc)(LPVOID lpThreadParameter);
#else
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#define FILE_SEPERATOR "/"
typedef int SOCKET;
#define closesocket close
#define INVALID_SOCKET -1
#define THREAD_ENTRANCE_FUNC_DECLARE void *
typedef void *LPVOID;
#define THREAD_RETURN_VALUE NULL
typedef void * (*ThreadEntranceFunc)(LPVOID lpThreadParameter);
#endif
#ifndef WIN32
extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
#endif
#ifdef OS_LINUX
#define PTHREAD_MUTEX_ERRORCHECK PTHREAD_MUTEX_ERRORCHECK_NP
#endif
#include "_os_bits.h"
#ifdef OS_BITS
#if OS_BITS == 64
#define INT64_PRINTF_FORMAT "%ld"
#else
#define INT64_PRINTF_FORMAT "%lld"
#endif
#else
#define INT64_PRINTF_FORMAT "%lld"
#endif
#ifdef OFF_BITS
#if OFF_BITS == 64
#define OFF_PRINTF_FORMAT INT64_PRINTF_FORMAT
#else
#define OFF_PRINTF_FORMAT "%d"
#endif
#else
#define OFF_PRINTF_FORMAT INT64_PRINTF_FORMAT
#endif
#ifndef WIN32
#define USE_SENDFILE
#endif
#define MAX_PATH_SIZE 256
#define LOG_FILE_DIR "logs"
#define CONF_FILE_DIR "conf"
#define DEFAULT_CONNECT_TIMEOUT 30
#define DEFAULT_NETWORK_TIMEOUT 30
#define DEFAULT_MAX_CONNECTONS 256
#define DEFAULT_WORK_THREADS 4
#define SYNC_LOG_BUFF_DEF_INTERVAL 10
#define TIME_NONE -1
#define IP_ADDRESS_SIZE 16
#define INFINITE_FILE_SIZE (256 * 1024LL * 1024 * 1024 * 1024 * 1024LL)
#ifndef __cplusplus
#ifndef true
typedef char bool;
#define true 1
#define false 0
#endif
#endif
#ifndef byte
#define byte signed char
#endif
#ifndef ubyte
#define ubyte unsigned char
#endif
#ifndef WIN32
#ifndef INADDR_NONE
#define INADDR_NONE ((in_addr_t) 0xffffffff)
#endif
#endif
#ifndef ECANCELED
#define ECANCELED 125
#endif
#ifndef ENONET
#define ENONET 64 /* Machine is not on the network */
#endif
#define IS_UPPER_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
#define STRERROR(no) (strerror(no) != NULL ? strerror(no) : "Unkown error")
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
byte hour;
byte minute;
} TimeInfo;
typedef struct
{
char major;
char minor;
} Version;
typedef struct
{
char *key;
char *value;
} KeyValuePair;
typedef struct
{
char *buff;
int alloc_size;
int length;
} BufferInfo;
typedef void (*FreeDataFunc)(void *ptr);
typedef int (*CompareFunc)(void *p1, void *p2);
typedef void* (*MallocFunc)(size_t size);
#define TO_UPPERCASE(c) (((c) >= 'a' && (c) <= 'z') ? (c) - 32 : c)
#define MEM_ALIGN(x) (((x) + 7) & (~7))
#ifdef WIN32
#define strcasecmp _stricmp
#endif
#ifdef __cplusplus
}
#endif
#endif

26
src/fast_link_library.sh Executable file
View File

@ -0,0 +1,26 @@
tmp_src_filename=_fast_check_bits_.c
cat <<EOF > $tmp_src_filename
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
printf("%d\n", (int)sizeof(long));
return 0;
}
EOF
gcc -D_FILE_OFFSET_BITS=64 -o a.out $tmp_src_filename
OS_BITS=`./a.out`
rm $tmp_src_filename a.out
TARGET_LIB="/usr/local/lib"
if [ "`id -u`" = "0" ]; then
ln -fs $TARGET_LIB/libfastcommon.so.1 /usr/lib/libfastcommon.so
if [ "$OS_BITS" = "8" ]; then
ln -fs $TARGET_LIB/libfastcommon.so.1 /usr/lib64/libfastcommon.so
fi
fi

503
src/fast_task_queue.c Normal file
View File

@ -0,0 +1,503 @@
//fast_task_queue.c
#include <errno.h>
#include <sys/resource.h>
#include <pthread.h>
#include "fast_task_queue.h"
#include "logger.h"
#include "shared_func.h"
#include "pthread_func.h"
static struct fast_task_queue g_free_queue;
struct mpool_chain {
struct fast_task_info *blocks;
struct fast_task_info *last_block; //last block
struct mpool_chain *next;
} *g_mpool = NULL;
#define ALIGNED_TASK_INFO_SIZE MEM_ALIGN(sizeof(struct fast_task_info))
int task_queue_init(struct fast_task_queue *pQueue)
{
int result;
if ((result=init_pthread_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"init_pthread_lock fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
pQueue->head = NULL;
pQueue->tail = NULL;
return 0;
}
static struct mpool_chain *malloc_mpool(const int block_size, \
const int total_alloc_size)
{
struct fast_task_info *pTask;
char *p;
char *pCharEnd;
struct mpool_chain *mpool;
mpool = (struct mpool_chain *)malloc(sizeof(struct mpool_chain));
if (mpool == NULL)
{
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, (int)sizeof(struct mpool_chain), \
errno, STRERROR(errno));
return NULL;
}
mpool->next = NULL;
mpool->blocks = (struct fast_task_info *)malloc(total_alloc_size);
if (mpool->blocks == NULL)
{
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, total_alloc_size, \
errno, STRERROR(errno));
free(mpool);
return NULL;
}
memset(mpool->blocks, 0, total_alloc_size);
pCharEnd = ((char *)mpool->blocks) + total_alloc_size;
for (p=(char *)mpool->blocks; p<pCharEnd; p += block_size)
{
pTask = (struct fast_task_info *)p;
pTask->size = g_free_queue.min_buff_size;
pTask->arg = p + ALIGNED_TASK_INFO_SIZE;
if (g_free_queue.malloc_whole_block)
{
pTask->data = (char *)pTask->arg + \
g_free_queue.arg_size;
}
else
{
pTask->data = (char *)malloc(pTask->size);
if (pTask->data == NULL)
{
char *pt;
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, pTask->size, \
errno, STRERROR(errno));
for (pt=(char *)mpool->blocks; pt < p; \
pt += block_size)
{
free(((struct fast_task_info *)pt)->data);
}
free(mpool->blocks);
free(mpool);
return NULL;
}
}
}
mpool->last_block = (struct fast_task_info *)(pCharEnd - block_size);
for (p=(char *)mpool->blocks; p<(char *)mpool->last_block; p += block_size)
{
pTask = (struct fast_task_info *)p;
pTask->next = (struct fast_task_info *)(p + block_size);
}
mpool->last_block->next = NULL;
return mpool;
}
int free_queue_init(const int max_connections, const int min_buff_size, \
const int max_buff_size, const int arg_size)
{
int64_t total_size;
struct mpool_chain *mpool;
int block_size;
int alloc_size;
int result;
int loop_count;
int aligned_min_size;
int aligned_max_size;
int aligned_arg_size;
rlim_t max_data_size;
if ((result=init_pthread_lock(&(g_free_queue.lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"init_pthread_lock fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
aligned_min_size = MEM_ALIGN(min_buff_size);
aligned_max_size = MEM_ALIGN(max_buff_size);
aligned_arg_size = MEM_ALIGN(arg_size);
block_size = ALIGNED_TASK_INFO_SIZE + aligned_arg_size;
alloc_size = block_size * max_connections;
if (aligned_max_size > aligned_min_size)
{
total_size = alloc_size;
g_free_queue.malloc_whole_block = false;
max_data_size = 0;
}
else
{
struct rlimit rlimit_data;
if (getrlimit(RLIMIT_DATA, &rlimit_data) < 0)
{
logError("file: "__FILE__", line: %d, " \
"call getrlimit fail, " \
"errno: %d, error info: %s", \
__LINE__, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
if (rlimit_data.rlim_cur == RLIM_INFINITY)
{
max_data_size = 256 * 1024 * 1024;
}
else
{
max_data_size = rlimit_data.rlim_cur;
if (max_data_size > 256 * 1024 * 1024)
{
max_data_size = 256 * 1024 * 1024;
}
}
if (max_data_size >= (int64_t)(block_size + aligned_min_size) *
(int64_t)max_connections)
{
total_size = alloc_size + (int64_t)aligned_min_size *
max_connections;
g_free_queue.malloc_whole_block = true;
block_size += aligned_min_size;
}
else
{
total_size = alloc_size;
g_free_queue.malloc_whole_block = false;
max_data_size = 0;
}
}
logDebug("file: "__FILE__", line: %d, " \
"max_connections: %d, min_buff_size: %d, max_buff_size: %d, " \
"block_size: %d, arg_size: %d, max_data_size: %d, " \
"total_size: "INT64_PRINTF_FORMAT, __LINE__, \
max_connections, aligned_min_size, aligned_max_size, \
block_size, aligned_arg_size, (int)max_data_size, total_size);
g_free_queue.max_connections = max_connections;
g_free_queue.min_buff_size = aligned_min_size;
g_free_queue.max_buff_size = aligned_max_size;
g_free_queue.arg_size = aligned_arg_size;
if ((!g_free_queue.malloc_whole_block) || \
(total_size <= max_data_size))
{
loop_count = 1;
mpool = malloc_mpool(block_size, total_size);
if (mpool == NULL)
{
return errno != 0 ? errno : ENOMEM;
}
g_mpool = mpool;
}
else
{
struct mpool_chain *previous_mpool;
int remain_count;
int alloc_once;
int current_count;
int current_alloc_size;
mpool = NULL;
previous_mpool = NULL;
loop_count = 0;
remain_count = max_connections;
alloc_once = max_data_size / block_size;
while (remain_count > 0)
{
current_count = (remain_count > alloc_once) ? \
alloc_once : remain_count;
current_alloc_size = block_size * current_count;
mpool = malloc_mpool(block_size, current_alloc_size);
if (mpool == NULL)
{
free_queue_destroy();
return errno != 0 ? errno : ENOMEM;
}
if (previous_mpool == NULL)
{
g_mpool = mpool;
}
else
{
previous_mpool->next = mpool;
previous_mpool->last_block->next = mpool->blocks;
}
previous_mpool = mpool;
remain_count -= current_count;
loop_count++;
}
logDebug("file: "__FILE__", line: %d, " \
"alloc_once: %d", __LINE__, alloc_once);
}
logDebug("file: "__FILE__", line: %d, " \
"malloc task info as whole: %d, malloc loop count: %d", \
__LINE__, g_free_queue.malloc_whole_block, loop_count);
if (g_mpool != NULL)
{
g_free_queue.head = g_mpool->blocks;
g_free_queue.tail = mpool->last_block;
/*
struct fast_task_info *pTask;
int task_count = 0;
pTask = g_free_queue.head;
while (pTask != NULL)
{
task_count++;
pTask = pTask->next;
}
logDebug("file: "__FILE__", line: %d, " \
"task count: %d", __LINE__, task_count);
*/
}
return 0;
}
void free_queue_destroy()
{
struct mpool_chain *mpool;
struct mpool_chain *mp;
if (g_mpool == NULL)
{
return;
}
if (!g_free_queue.malloc_whole_block)
{
char *p;
char *pCharEnd;
int block_size;
struct fast_task_info *pTask;
block_size = ALIGNED_TASK_INFO_SIZE + g_free_queue.arg_size;
pCharEnd = ((char *)g_mpool->blocks) + block_size * \
g_free_queue.max_connections;
for (p=(char *)g_mpool->blocks; p<pCharEnd; p += block_size)
{
pTask = (struct fast_task_info *)p;
if (pTask->data != NULL)
{
free(pTask->data);
pTask->data = NULL;
}
}
}
mpool = g_mpool;
while (mpool != NULL)
{
mp = mpool;
mpool = mpool->next;
free(mp->blocks);
free(mp);
}
g_mpool = NULL;
pthread_mutex_destroy(&(g_free_queue.lock));
}
struct fast_task_info *free_queue_pop()
{
return task_queue_pop(&g_free_queue);;
}
int free_queue_push(struct fast_task_info *pTask)
{
char *new_buff;
int result;
*(pTask->client_ip) = '\0';
pTask->length = 0;
pTask->offset = 0;
pTask->req_count = 0;
if (pTask->size > g_free_queue.min_buff_size) //need thrink
{
new_buff = (char *)malloc(g_free_queue.min_buff_size);
if (new_buff == NULL)
{
logWarning("file: "__FILE__", line: %d, " \
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, g_free_queue.min_buff_size, \
errno, STRERROR(errno));
}
else
{
free(pTask->data);
pTask->size = g_free_queue.min_buff_size;
pTask->data = new_buff;
}
}
if ((result=pthread_mutex_lock(&g_free_queue.lock)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
pTask->next = g_free_queue.head;
g_free_queue.head = pTask;
if (g_free_queue.tail == NULL)
{
g_free_queue.tail = pTask;
}
if ((result=pthread_mutex_unlock(&g_free_queue.lock)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return result;
}
int free_queue_count()
{
return task_queue_count(&g_free_queue);
}
int task_queue_push(struct fast_task_queue *pQueue, \
struct fast_task_info *pTask)
{
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
pTask->next = NULL;
if (pQueue->tail == NULL)
{
pQueue->head = pTask;
}
else
{
pQueue->tail->next = pTask;
}
pQueue->tail = pTask;
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return 0;
}
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue)
{
struct fast_task_info *pTask;
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return NULL;
}
pTask = pQueue->head;
if (pTask != NULL)
{
pQueue->head = pTask->next;
if (pQueue->head == NULL)
{
pQueue->tail = NULL;
}
}
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return pTask;
}
int task_queue_count(struct fast_task_queue *pQueue)
{
struct fast_task_info *pTask;
int count;
int result;
if ((result=pthread_mutex_lock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return 0;
}
count = 0;
pTask = pQueue->head;
while (pTask != NULL)
{
pTask = pTask->next;
count++;
}
if ((result=pthread_mutex_unlock(&(pQueue->lock))) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return count;
}

96
src/fast_task_queue.h Normal file
View File

@ -0,0 +1,96 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//fast_task_queue.h
#ifndef _FAST_TASK_QUEUE_H
#define _FAST_TASK_QUEUE_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "common_define.h"
#include "ioevent.h"
#include "fast_timer.h"
struct fast_task_info;
typedef int (*TaskFinishCallBack) (struct fast_task_info *pTask);
typedef void (*TaskCleanUpCallBack) (struct fast_task_info *pTask);
typedef void (*IOEventCallback) (int sock, short event, void *arg);
typedef struct ioevent_entry
{
int fd;
FastTimerEntry timer;
IOEventCallback callback;
} IOEventEntry;
struct nio_thread_data
{
struct ioevent_puller ev_puller;
struct fast_timer timer;
int pipe_fds[2];
struct fast_task_info *deleted_list;
};
struct fast_task_info
{
IOEventEntry event;
char client_ip[IP_ADDRESS_SIZE];
void *arg; //extra argument pointer
char *data; //buffer for write or recv
int size; //alloc size
int length; //data length
int offset; //current offset
int req_count; //request count
TaskFinishCallBack finish_callback;
struct nio_thread_data *thread_data;
struct fast_task_info *next;
};
struct fast_task_queue
{
struct fast_task_info *head;
struct fast_task_info *tail;
pthread_mutex_t lock;
int max_connections;
int min_buff_size;
int max_buff_size;
int arg_size;
bool malloc_whole_block;
};
#ifdef __cplusplus
extern "C" {
#endif
int free_queue_init(const int max_connections, const int min_buff_size, \
const int max_buff_size, const int arg_size);
void free_queue_destroy();
int free_queue_push(struct fast_task_info *pTask);
struct fast_task_info *free_queue_pop();
int free_queue_count();
int task_queue_init(struct fast_task_queue *pQueue);
int task_queue_push(struct fast_task_queue *pQueue, \
struct fast_task_info *pTask);
struct fast_task_info *task_queue_pop(struct fast_task_queue *pQueue);
int task_queue_count(struct fast_task_queue *pQueue);
#ifdef __cplusplus
}
#endif
#endif

BIN
src/fast_task_queue.o Normal file

Binary file not shown.

175
src/fast_timer.c Normal file
View File

@ -0,0 +1,175 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "logger.h"
#include "fast_timer.h"
int fast_timer_init(FastTimer *timer, const int slot_count,
const int64_t current_time)
{
int bytes;
if (slot_count <= 0 || current_time <= 0) {
return EINVAL;
}
timer->slot_count = slot_count;
timer->base_time = current_time; //base time for slot 0
timer->current_time = current_time;
bytes = sizeof(FastTimerSlot) * slot_count;
timer->slots = (FastTimerSlot *)malloc(bytes);
if (timer->slots == NULL) {
return errno != 0 ? errno : ENOMEM;
}
memset(timer->slots, 0, bytes);
return 0;
}
void fast_timer_destroy(FastTimer *timer)
{
if (timer->slots != NULL) {
free(timer->slots);
timer->slots = NULL;
}
}
#define TIMER_GET_SLOT_INDEX(timer, expires) \
(((expires) - timer->base_time) % timer->slot_count)
#define TIMER_GET_SLOT_POINTER(timer, expires) \
(timer->slots + TIMER_GET_SLOT_INDEX(timer, expires))
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry)
{
FastTimerSlot *slot;
slot = TIMER_GET_SLOT_POINTER(timer, entry->expires >
timer->current_time ? entry->expires : timer->current_time);
entry->next = slot->head.next;
if (slot->head.next != NULL) {
slot->head.next->prev = entry;
}
entry->prev = &slot->head;
slot->head.next = entry;
return 0;
}
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
const int64_t new_expires)
{
if (new_expires == entry->expires) {
return 0;
}
if (new_expires < entry->expires) {
fast_timer_remove(timer, entry);
entry->expires = new_expires;
return fast_timer_add(timer, entry);
}
entry->rehash = TIMER_GET_SLOT_INDEX(timer, new_expires) !=
TIMER_GET_SLOT_INDEX(timer, entry->expires);
entry->expires = new_expires; //lazy move
return 0;
}
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry)
{
if (entry->prev == NULL) {
return ENOENT; //already removed
}
if (entry->next != NULL) {
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
entry->next = NULL;
}
else {
entry->prev->next = NULL;
}
entry->prev = NULL;
return 0;
}
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time)
{
if (timer->current_time >= current_time) {
return NULL;
}
return TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
}
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
FastTimerEntry *head)
{
FastTimerSlot *slot;
FastTimerEntry *entry;
FastTimerEntry *first;
FastTimerEntry *last;
FastTimerEntry *tail;
int count;
head->prev = NULL;
head->next = NULL;
if (timer->current_time >= current_time) {
return 0;
}
first = NULL;
last = NULL;
tail = head;
count = 0;
while (timer->current_time < current_time) {
slot = TIMER_GET_SLOT_POINTER(timer, timer->current_time++);
entry = slot->head.next;
while (entry != NULL) {
if (entry->expires >= current_time) { //not expired
if (first != NULL) {
first->prev->next = entry;
entry->prev = first->prev;
tail->next = first;
first->prev = tail;
tail = last;
first = NULL;
}
if (entry->rehash) {
last = entry;
entry = entry->next;
last->rehash = false;
fast_timer_remove(timer, last);
fast_timer_add(timer, last);
continue;
}
}
else {
count++;
if (first == NULL) {
first = entry;
}
}
last = entry;
entry = entry->next;
}
if (first != NULL) {
first->prev->next = NULL;
tail->next = first;
first->prev = tail;
tail = last;
first = NULL;
}
}
if (count > 0) {
tail->next = NULL;
}
return count;
}

48
src/fast_timer.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef __FAST_TIMER_H__
#define __FAST_TIMER_H__
#include <stdint.h>
#include "common_define.h"
typedef struct fast_timer_entry {
int64_t expires;
void *data;
struct fast_timer_entry *prev;
struct fast_timer_entry *next;
bool rehash;
} FastTimerEntry;
typedef struct fast_timer_slot {
struct fast_timer_entry head;
} FastTimerSlot;
typedef struct fast_timer {
int slot_count; //time wheel slot count
int64_t base_time; //base time for slot 0
int64_t current_time;
FastTimerSlot *slots;
} FastTimer;
#ifdef __cplusplus
extern "C" {
#endif
int fast_timer_init(FastTimer *timer, const int slot_count,
const int64_t current_time);
void fast_timer_destroy(FastTimer *timer);
int fast_timer_add(FastTimer *timer, FastTimerEntry *entry);
int fast_timer_remove(FastTimer *timer, FastTimerEntry *entry);
int fast_timer_modify(FastTimer *timer, FastTimerEntry *entry,
const int64_t new_expires);
FastTimerSlot *fast_timer_slot_get(FastTimer *timer, const int64_t current_time);
int fast_timer_timeouts_get(FastTimer *timer, const int64_t current_time,
FastTimerEntry *head);
#ifdef __cplusplus
}
#endif
#endif

BIN
src/fast_timer.o Normal file

Binary file not shown.

1402
src/hash.c Normal file

File diff suppressed because it is too large Load Diff

381
src/hash.h Normal file
View File

@ -0,0 +1,381 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#ifndef _HASH_H_
#define _HASH_H_
#include <sys/types.h>
#include <pthread.h>
#include "common_define.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CRC32_XINIT 0xFFFFFFFF /* initial value */
#define CRC32_XOROT 0xFFFFFFFF /* final xor value */
typedef int (*HashFunc) (const void *key, const int key_len);
#ifdef HASH_STORE_HASH_CODE
#define HASH_CODE(pHash, hash_data) hash_data->hash_code
#else
#define HASH_CODE(pHash, hash_data) ((unsigned int)pHash->hash_func( \
hash_data->key, hash_data->key_len))
#endif
#define CALC_NODE_MALLOC_BYTES(key_len, value_size) \
sizeof(HashData) + key_len + value_size
#define FREE_HASH_DATA(pHash, hash_data) \
pHash->item_count--; \
pHash->bytes_used -= CALC_NODE_MALLOC_BYTES(hash_data->key_len, \
hash_data->malloc_value_size); \
free(hash_data);
typedef struct tagHashData
{
int key_len;
int value_len;
int malloc_value_size;
#ifdef HASH_STORE_HASH_CODE
unsigned int hash_code;
#endif
char *value;
struct tagHashData *next;
char key[0];
} HashData;
typedef int64_t (*ConvertValueFunc)(const HashData *old_data, const int inc,
char *new_value, int *new_value_len, void *arg);
typedef struct tagHashArray
{
HashData **buckets;
HashFunc hash_func;
int item_count;
unsigned int *capacity;
double load_factor;
int64_t max_bytes;
int64_t bytes_used;
bool is_malloc_capacity;
bool is_malloc_value;
unsigned int lock_count;
pthread_mutex_t *locks;
} HashArray;
typedef struct tagHashStat
{
unsigned int capacity;
int item_count;
int bucket_used;
double bucket_avg_length;
int bucket_max_length;
} HashStat;
/**
* hash walk function
* parameters:
* index: item index based 0
* data: hash data, including key and value
* args: passed by hash_walk function
* return 0 for success, != 0 for error
*/
typedef int (*HashWalkFunc)(const int index, const HashData *data, void *args);
#define hash_init(pHash, hash_func, capacity, load_factor) \
hash_init_ex(pHash, hash_func, capacity, load_factor, 0, false)
#define hash_insert(pHash, key, key_len, value) \
hash_insert_ex(pHash, key, key_len, value, 0, true)
/**
* hash init function
* parameters:
* pHash: the hash table
* hash_func: hash function
* capacity: init capacity
* load_factor: hash load factor, such as 0.75
* max_bytes: max memory can be used (bytes)
* bMallocValue: if need malloc value buffer
* return 0 for success, != 0 for error
*/
int hash_init_ex(HashArray *pHash, HashFunc hash_func, \
const unsigned int capacity, const double load_factor, \
const int64_t max_bytes, const bool bMallocValue);
/**
* set hash locks function
* parameters:
* lock_count: the lock count
* return 0 for success, != 0 for error
*/
int hash_set_locks(HashArray *pHash, const int lock_count);
/**
* convert the value
* parameters:
* HashData: the old hash data
* inc: the increasement value
* new_value: return the new value
* new_value_len: return the length of the new value
* arg: the user data
* return the number after increasement
*/
int64_t hash_inc_value(const HashData *old_data, const int inc,
char *new_value, int *new_value_len, void *arg);
#define hash_inc(pHash, key, key_len, inc, value, value_len) \
hash_inc_ex(pHash, key, key_len, inc, value, value_len, \
hash_inc_value, NULL)
/**
* atomic increase value
* parameters:
* pHash: the hash table
* key: the key to insert
* key_len: length of th key
* inc: the increasement value
* value: return the new value
* value_len: return the length of the new value
* convert_func: the convert function
* arg: the arg to convert function
* return 0 for success, != 0 for error (errno)
*
*/
int hash_inc_ex(HashArray *pHash, const void *key, const int key_len,
const int inc, char *value, int *value_len,
ConvertValueFunc convert_func, void *arg);
/**
* hash destroy function
* parameters:
* pHash: the hash table
* return none
*/
void hash_destroy(HashArray *pHash);
/**
* hash insert key
* parameters:
* pHash: the hash table
* key: the key to insert
* key_len: length of th key
* value: the value
* value_len: length of the value
* needLock: if need lock
* return >= 0 for success, 0 for key already exist (update),
* 1 for new key (insert), < 0 for error
*/
int hash_insert_ex(HashArray *pHash, const void *key, const int key_len, \
void *value, const int value_len, const bool needLock);
/**
* hash find key
* parameters:
* pHash: the hash table
* key: the key to find
* key_len: length of th key
* return user data, return NULL when the key not exist
*/
void *hash_find(HashArray *pHash, const void *key, const int key_len);
/**
* hash find key
* parameters:
* pHash: the hash table
* key: the key to find
* key_len: length of th key
* return hash data, return NULL when the key not exist
*/
HashData *hash_find_ex(HashArray *pHash, const void *key, const int key_len);
/**
* hash get the value of the key
* parameters:
* pHash: the hash table
* key: the key to find
* key_len: length of th key
* value: store the value
* value_len: input for the max size of the value
* output for the length fo the value
* return 0 for success, != 0 fail (errno)
*/
int hash_get(HashArray *pHash, const void *key, const int key_len,
void *value, int *value_len);
/**
* hash partial set
* parameters:
* pHash: the hash table
* key: the key to insert
* key_len: length of th key
* value: the value
* offset: the offset of existed value
* value_len: length of the value
* return 0 for success, != 0 fail (errno)
*/
int hash_partial_set(HashArray *pHash, const void *key, const int key_len,
const char *value, const int offset, const int value_len);
/**
* hash delete key
* parameters:
* pHash: the hash table
* key: the key to delete
* key_len: length of th key
* return 0 for success, != 0 fail (errno)
*/
int hash_delete(HashArray *pHash, const void *key, const int key_len);
/**
* hash walk (iterator)
* parameters:
* pHash: the hash table
* walkFunc: walk (interator) function
* args: extra args which will be passed to walkFunc
* return 0 for success, != 0 fail (errno)
*/
int hash_walk(HashArray *pHash, HashWalkFunc walkFunc, void *args);
/**
* get hash item count
* parameters:
* pHash: the hash table
* return item count
*/
int hash_count(HashArray *pHash);
/**
* hash best optimize
* parameters:
* pHash: the hash table
* suggest_capacity: suggest init capacity for speed
* return >0 for success, < 0 fail (errno)
*/
int hash_best_op(HashArray *pHash, const int suggest_capacity);
/**
* hash stat
* parameters:
* pHash: the hash table
* pStat: return stat info
* stat_by_lens: return stats array by bucket length
* stat_by_lens[0] empty buckets count
* stat_by_lens[1] contain 1 key buckets count
* stat_by_lens[2] contain 2 key buckets count, etc
* stat_size: stats array size (contain max elments)
* return 0 for success, != 0 fail (errno)
*/
int hash_stat(HashArray *pHash, HashStat *pStat, \
int *stat_by_lens, const int stat_size);
/**
* print hash stat info
* parameters:
* pHash: the hash table
* return none
*/
void hash_stat_print(HashArray *pHash);
/**
* lock the bucket of hash table
* parameters:
* pHash: the hash table
* bucket_index: the index of bucket
* return 0 for success, != 0 fail (errno)
*/
int hash_bucket_lock(HashArray *pHash, const unsigned int bucket_index);
/**
* unlock the bucket of hash table
* parameters:
* pHash: the hash table
* bucket_index: the index of bucket
* return 0 for success, != 0 fail (errno)
*/
int hash_bucket_unlock(HashArray *pHash, const unsigned int bucket_index);
int RSHash(const void *key, const int key_len);
int JSHash(const void *key, const int key_len);
int JSHash_ex(const void *key, const int key_len, \
const int init_value);
int PJWHash(const void *key, const int key_len);
int PJWHash_ex(const void *key, const int key_len, \
const int init_value);
int ELFHash(const void *key, const int key_len);
int ELFHash_ex(const void *key, const int key_len, \
const int init_value);
int BKDRHash(const void *key, const int key_len);
int BKDRHash_ex(const void *key, const int key_len, \
const int init_value);
int SDBMHash(const void *key, const int key_len);
int SDBMHash_ex(const void *key, const int key_len, \
const int init_value);
int Time33Hash(const void *key, const int key_len);
int Time33Hash_ex(const void *key, const int key_len, \
const int init_value);
int DJBHash(const void *key, const int key_len);
int DJBHash_ex(const void *key, const int key_len, \
const int init_value);
int APHash(const void *key, const int key_len);
int APHash_ex(const void *key, const int key_len, \
const int init_value);
int calc_hashnr (const void* key, const int key_len);
int calc_hashnr1(const void* key, const int key_len);
int calc_hashnr1_ex(const void* key, const int key_len, \
const int init_value);
int simple_hash(const void* key, const int key_len);
int simple_hash_ex(const void* key, const int key_len, \
const int init_value);
int CRC32(void *key, const int key_len);
int CRC32_ex(void *key, const int key_len, \
const int init_value);
#define CRC32_FINAL(crc) (crc ^ CRC32_XOROT)
#define INIT_HASH_CODES4(hash_codes) \
hash_codes[0] = CRC32_XINIT; \
hash_codes[1] = 0; \
hash_codes[2] = 0; \
hash_codes[3] = 0; \
#define CALC_HASH_CODES4(buff, buff_len, hash_codes) \
hash_codes[0] = CRC32_ex(buff, buff_len, hash_codes[0]); \
hash_codes[1] = ELFHash_ex(buff, buff_len, hash_codes[1]); \
hash_codes[2] = simple_hash_ex(buff, buff_len, hash_codes[2]); \
hash_codes[3] = Time33Hash_ex(buff, buff_len, hash_codes[3]); \
#define FINISH_HASH_CODES4(hash_codes) \
hash_codes[0] = CRC32_FINAL(hash_codes[0]); \
#ifdef __cplusplus
}
#endif
#endif

302
src/http_func.c Normal file
View File

@ -0,0 +1,302 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <fcntl.h>
#include "sockopt.h"
#include "logger.h"
#include "shared_func.h"
int get_url_content(const char *url, const int connect_timeout, \
const int network_timeout, int *http_status, \
char **content, int *content_len, char *error_info)
{
char domain_name[256];
char ip_addr[IP_ADDRESS_SIZE];
char out_buff[4096];
int domain_len;
int url_len;
int out_len;
int alloc_size;
int recv_bytes;
int result;
int sock;
int port;
const char *pDomain;
const char *pContent;
const char *pURI;
char *pPort;
char *pSpace;
*http_status = 0;
*content_len = 0;
*content = NULL;
url_len = strlen(url);
if (url_len <= 7 || strncasecmp(url, "http://", 7) != 0)
{
sprintf(error_info, "file: "__FILE__", line: %d, " \
"invalid url.", __LINE__);
return EINVAL;
}
pDomain = url + 7;
pURI = strchr(pDomain, '/');
if (pURI == NULL)
{
domain_len = url_len - 7;
pURI = "/";
}
else
{
domain_len = pURI - pDomain;
}
if (domain_len >= sizeof(domain_name))
{
sprintf(error_info, "file: "__FILE__", line: %d, " \
"domain is too large, exceed %d.", \
__LINE__, (int)sizeof(domain_name));
return EINVAL;
}
memcpy(domain_name, pDomain, domain_len);
*(domain_name + domain_len) = '\0';
pPort = strchr(domain_name, ':');
if (pPort == NULL)
{
port = 80;
}
else
{
*pPort = '\0';
port = atoi(pPort + 1);
}
if (getIpaddrByName(domain_name, ip_addr, \
sizeof(ip_addr)) == INADDR_NONE)
{
sprintf(error_info, "file: "__FILE__", line: %d, " \
"resolve domain \"%s\" fail.", \
__LINE__, domain_name);
return EINVAL;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0)
{
sprintf(error_info, "file: "__FILE__", line: %d, " \
"socket create failed, errno: %d, " \
"error info: %s", __LINE__, \
errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
if ((result=connectserverbyip_nb_auto(sock, ip_addr, port, \
connect_timeout)) != 0)
{
close(sock);
sprintf(error_info, "file: "__FILE__", line: %d, " \
"connect to %s:%d fail, errno: %d, " \
"error info: %s", __LINE__, domain_name, \
port, result, STRERROR(result));
return result;
}
out_len = snprintf(out_buff, sizeof(out_buff), \
"GET %s HTTP/1.0\r\n" \
"Host: %s:%d\r\n" \
"Connection: close\r\n" \
"\r\n", pURI, domain_name, port);
if ((result=tcpsenddata(sock, out_buff, out_len, network_timeout)) != 0)
{
close(sock);
sprintf(error_info, "file: "__FILE__", line: %d, " \
"send data to %s:%d fail, errno: %d, " \
"error info: %s", __LINE__, domain_name, \
port, result, STRERROR(result));
return result;
}
alloc_size = 64 * 1024;
*content = (char *)malloc(alloc_size + 1);
if (*content == NULL)
{
close(sock);
result = errno != 0 ? errno : ENOMEM;
sprintf(error_info, "file: "__FILE__", line: %d, " \
"malloc %d bytes fail, errno: %d, " \
"error info: %s", __LINE__, alloc_size + 1, \
result, STRERROR(result));
return result;
}
do
{
recv_bytes = alloc_size - *content_len;
if (recv_bytes <= 0)
{
alloc_size *= 2;
*content = (char *)realloc(*content, alloc_size + 1);
if (*content == NULL)
{
close(sock);
result = errno != 0 ? errno : ENOMEM;
sprintf(error_info, "file: "__FILE__", line: %d, " \
"realloc %d bytes fail, errno: %d, " \
"error info: %s", __LINE__, \
alloc_size + 1, \
result, STRERROR(result));
return result;
}
recv_bytes = alloc_size - *content_len;
}
result = tcprecvdata_ex(sock, *content + *content_len, \
recv_bytes, network_timeout, &recv_bytes);
*content_len += recv_bytes;
} while (result == 0);
if (result != ENOTCONN)
{
close(sock);
free(*content);
*content = NULL;
*content_len = 0;
sprintf(error_info, "file: "__FILE__", line: %d, " \
"recv data from %s:%d fail, errno: %d, " \
"error info: %s", __LINE__, domain_name, \
port, result, STRERROR(result));
return result;
}
*(*content + *content_len) = '\0';
pContent = strstr(*content, "\r\n\r\n");
if (pContent == NULL)
{
close(sock);
free(*content);
*content = NULL;
*content_len = 0;
sprintf(error_info, "file: "__FILE__", line: %d, " \
"response data from %s:%d is invalid", \
__LINE__, domain_name, port);
return EINVAL;
}
pContent += 4;
pSpace = strchr(*content, ' ');
if (pSpace == NULL || pSpace >= pContent)
{
close(sock);
free(*content);
*content = NULL;
*content_len = 0;
sprintf(error_info, "file: "__FILE__", line: %d, " \
"response data from %s:%d is invalid", \
__LINE__, domain_name, port);
return EINVAL;
}
*http_status = atoi(pSpace + 1);
*content_len -= pContent - *content;
memcpy(*content, pContent, *content_len);
*(*content + *content_len) = '\0';
close(sock);
*error_info = '\0';
return 0;
}
int http_parse_query(char *url, KeyValuePair *params, const int max_count)
{
KeyValuePair *pCurrent;
KeyValuePair *pEnd;
char *pParamStart;
char *p;
char *pStrEnd;
int value_len;
pParamStart = strchr(url, '?');
if (pParamStart == NULL)
{
return 0;
}
*pParamStart = '\0';
pEnd = params + max_count;
pCurrent = params;
p = pParamStart + 1;
while (p != NULL && *p != '\0')
{
if (pCurrent >= pEnd)
{
return pCurrent - params;
}
pCurrent->key = p;
pStrEnd = strchr(p, '&');
if (pStrEnd == NULL)
{
p = NULL;
}
else
{
*pStrEnd = '\0';
p = pStrEnd + 1;
}
pStrEnd = strchr(pCurrent->key, '=');
if (pStrEnd == NULL)
{
continue;
}
*pStrEnd = '\0';
pCurrent->value = pStrEnd + 1;
if (*pCurrent->key == '\0')
{
continue;
}
urldecode(pCurrent->value, strlen(pCurrent->value), \
pCurrent->value, &value_len);
pCurrent++;
}
return pCurrent - params;
}

54
src/http_func.h Normal file
View File

@ -0,0 +1,54 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#ifndef _HTTP_FUNC_H
#define _HTTP_FUNC_H
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "common_define.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
get content from url
params:
url: the url to fetch, must start as: "http://"
connect_timeout: connect timeout (seconds)
network_timeout: network timeout (seconds)
http_status: return http status code, 200 for Ok
content: return the content (HTTP body only, not including HTTP header),
*content should be freed by caller
content_len: return content length (bytes)
return: 0 for success, != 0 for error
**/
int get_url_content(const char *url, const int connect_timeout, \
const int network_timeout, int *http_status, \
char **content, int *content_len, char *error_info);
/**
parse url
params:
url: the url to parse
params: params array to store param and it's value
max_count: max param count
return: param count
**/
int http_parse_query(char *url, KeyValuePair *params, const int max_count);
#ifdef __cplusplus
}
#endif
#endif

784
src/ini_file_reader.c Normal file
View File

@ -0,0 +1,784 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//ini_file_reader.c
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include "shared_func.h"
#include "logger.h"
#include "http_func.h"
#include "ini_file_reader.h"
#define _LINE_BUFFER_SIZE 512
#define _ALLOC_ITEMS_ONCE 8
static int iniDoLoadFromFile(const char *szFilename, \
IniContext *pContext);
static int iniDoLoadItemsFromBuffer(char *content, \
IniContext *pContext);
static int iniCompareByItemName(const void *p1, const void *p2)
{
return strcmp(((IniItem *)p1)->name, ((IniItem *)p2)->name);
}
static int iniInitContext(IniContext *pContext)
{
int result;
memset(pContext, 0, sizeof(IniContext));
pContext->current_section = &pContext->global;
if ((result=hash_init(&pContext->sections, PJWHash, 10, 0.75)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"hash_init fail, errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
return result;
}
static int iniSortHashData(const int index, const HashData *data, void *args)
{
IniSection *pSection;
pSection = (IniSection *)data->value;
if (pSection->count > 1)
{
qsort(pSection->items, pSection->count, \
sizeof(IniItem), iniCompareByItemName);
}
return 0;
}
static void iniSortItems(IniContext *pContext)
{
if (pContext->global.count > 1)
{
qsort(pContext->global.items, pContext->global.count, \
sizeof(IniItem), iniCompareByItemName);
}
hash_walk(&pContext->sections, iniSortHashData, NULL);
}
int iniLoadFromFile(const char *szFilename, IniContext *pContext)
{
int result;
int len;
char *pLast;
char full_filename[MAX_PATH_SIZE];
if ((result=iniInitContext(pContext)) != 0)
{
return result;
}
if (strncasecmp(szFilename, "http://", 7) == 0)
{
*pContext->config_path = '\0';
snprintf(full_filename, sizeof(full_filename),"%s",szFilename);
}
else
{
if (*szFilename == '/')
{
pLast = strrchr(szFilename, '/');
len = pLast - szFilename;
if (len >= sizeof(pContext->config_path))
{
logError("file: "__FILE__", line: %d, "\
"the path of the config file: %s is " \
"too long!", __LINE__, szFilename);
return ENOSPC;
}
memcpy(pContext->config_path, szFilename, len);
*(pContext->config_path + len) = '\0';
snprintf(full_filename, sizeof(full_filename), \
"%s", szFilename);
}
else
{
memset(pContext->config_path, 0, \
sizeof(pContext->config_path));
if (getcwd(pContext->config_path, sizeof( \
pContext->config_path)) == NULL)
{
logError("file: "__FILE__", line: %d, " \
"getcwd fail, errno: %d, " \
"error info: %s", \
__LINE__, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
len = strlen(pContext->config_path);
if (len > 0 && pContext->config_path[len - 1] == '/')
{
len--;
*(pContext->config_path + len) = '\0';
}
snprintf(full_filename, sizeof(full_filename), \
"%s/%s", pContext->config_path, szFilename);
pLast = strrchr(szFilename, '/');
if (pLast != NULL)
{
int tail_len;
tail_len = pLast - szFilename;
if (len + tail_len >= sizeof( \
pContext->config_path))
{
logError("file: "__FILE__", line: %d, "\
"the path of the config " \
"file: %s is too long!", \
__LINE__, szFilename);
return ENOSPC;
}
memcpy(pContext->config_path + len, \
szFilename, tail_len);
len += tail_len;
*(pContext->config_path + len) = '\0';
}
}
}
result = iniDoLoadFromFile(full_filename, pContext);
if (result == 0)
{
iniSortItems(pContext);
}
else
{
iniFreeContext(pContext);
}
return result;
}
static int iniDoLoadFromFile(const char *szFilename, \
IniContext *pContext)
{
char *content;
int result;
int http_status;
int content_len;
int64_t file_size;
char error_info[512];
if (strncasecmp(szFilename, "http://", 7) == 0)
{
if ((result=get_url_content(szFilename, 10, 60, &http_status, \
&content, &content_len, error_info)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"get_url_content fail, " \
"url: %s, error info: %s", \
__LINE__, szFilename, error_info);
return result;
}
if (http_status != 200)
{
free(content);
logError("file: "__FILE__", line: %d, " \
"HTTP status code: %d != 200, url: %s", \
__LINE__, http_status, szFilename);
return EINVAL;
}
}
else
{
if ((result=getFileContent(szFilename, &content, \
&file_size)) != 0)
{
return result;
}
}
result = iniDoLoadItemsFromBuffer(content, pContext);
free(content);
return result;
}
int iniLoadFromBuffer(char *content, IniContext *pContext)
{
int result;
if ((result=iniInitContext(pContext)) != 0)
{
return result;
}
result = iniDoLoadItemsFromBuffer(content, pContext);
if (result == 0)
{
iniSortItems(pContext);
}
else
{
iniFreeContext(pContext);
}
return result;
}
static int iniDoLoadItemsFromBuffer(char *content, IniContext *pContext)
{
IniSection *pSection;
IniItem *pItem;
char *pLine;
char *pLastEnd;
char *pEqualChar;
char *pIncludeFilename;
char full_filename[MAX_PATH_SIZE];
int nLineLen;
int nNameLen;
int nValueLen;
int result;
result = 0;
pLastEnd = content - 1;
pSection = pContext->current_section;
if (pSection->count > 0)
{
pItem = pSection->items + pSection->count;
}
else
{
pItem = pSection->items;
}
while (pLastEnd != NULL)
{
pLine = pLastEnd + 1;
pLastEnd = strchr(pLine, '\n');
if (pLastEnd != NULL)
{
*pLastEnd = '\0';
}
if (*pLine == '#' && \
strncasecmp(pLine+1, "include", 7) == 0 && \
(*(pLine+8) == ' ' || *(pLine+8) == '\t'))
{
pIncludeFilename = strdup(pLine + 9);
if (pIncludeFilename == NULL)
{
logError("file: "__FILE__", line: %d, " \
"strdup %d bytes fail", __LINE__, \
(int)strlen(pLine + 9) + 1);
result = errno != 0 ? errno : ENOMEM;
break;
}
trim(pIncludeFilename);
if (strncasecmp(pIncludeFilename, "http://", 7) == 0)
{
snprintf(full_filename, sizeof(full_filename),\
"%s", pIncludeFilename);
}
else
{
if (*pIncludeFilename == '/')
{
snprintf(full_filename, sizeof(full_filename), \
"%s", pIncludeFilename);
}
else
{
snprintf(full_filename, sizeof(full_filename), \
"%s/%s", pContext->config_path, \
pIncludeFilename);
}
if (!fileExists(full_filename))
{
logError("file: "__FILE__", line: %d, " \
"include file \"%s\" not exists, " \
"line: \"%s\"", __LINE__, \
pIncludeFilename, pLine);
free(pIncludeFilename);
result = ENOENT;
break;
}
}
result = iniDoLoadFromFile(full_filename, pContext);
if (result != 0)
{
free(pIncludeFilename);
break;
}
pSection = pContext->current_section;
if (pSection->count > 0)
{
pItem = pSection->items + pSection->count; //must re-asign
}
else
{
pItem = pSection->items;
}
free(pIncludeFilename);
continue;
}
trim(pLine);
if (*pLine == '#' || *pLine == '\0')
{
continue;
}
nLineLen = strlen(pLine);
if (*pLine == '[' && *(pLine + (nLineLen - 1)) == ']') //section
{
char *section_name;
int section_len;
*(pLine + (nLineLen - 1)) = '\0';
section_name = pLine + 1; //skip [
trim(section_name);
if (*section_name == '\0') //global section
{
pContext->current_section = &pContext->global;
pSection = pContext->current_section;
if (pSection->count > 0)
{
pItem = pSection->items + pSection->count;
}
else
{
pItem = pSection->items;
}
continue;
}
section_len = strlen(section_name);
pSection = (IniSection *)hash_find(&pContext->sections,\
section_name, section_len);
if (pSection == NULL)
{
pSection = (IniSection *)malloc(sizeof(IniSection));
if (pSection == NULL)
{
result = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, "\
"malloc %d bytes fail, " \
"errno: %d, error info: %s", \
__LINE__, \
(int)sizeof(IniSection), \
result, STRERROR(result));
break;
}
memset(pSection, 0, sizeof(IniSection));
result = hash_insert(&pContext->sections, \
section_name, section_len, pSection);
if (result < 0)
{
result *= -1;
logError("file: "__FILE__", line: %d, "\
"insert into hash table fail, "\
"errno: %d, error info: %s", \
__LINE__, result, \
STRERROR(result));
break;
}
else
{
result = 0;
}
}
pContext->current_section = pSection;
if (pSection->count > 0)
{
pItem = pSection->items + pSection->count;
}
else
{
pItem = pSection->items;
}
continue;
}
pEqualChar = strchr(pLine, '=');
if (pEqualChar == NULL)
{
continue;
}
nNameLen = pEqualChar - pLine;
nValueLen = strlen(pLine) - (nNameLen + 1);
if (nNameLen > FAST_INI_ITEM_NAME_LEN)
{
nNameLen = FAST_INI_ITEM_NAME_LEN;
}
if (nValueLen > FAST_INI_ITEM_VALUE_LEN)
{
nValueLen = FAST_INI_ITEM_VALUE_LEN;
}
if (pSection->count >= pSection->alloc_count)
{
pSection->alloc_count += _ALLOC_ITEMS_ONCE;
pSection->items=(IniItem *)realloc(pSection->items,
sizeof(IniItem) * pSection->alloc_count);
if (pSection->items == NULL)
{
logError("file: "__FILE__", line: %d, " \
"realloc %d bytes fail", __LINE__, \
(int)sizeof(IniItem) * \
pSection->alloc_count);
result = errno != 0 ? errno : ENOMEM;
break;
}
pItem = pSection->items + pSection->count;
memset(pItem, 0, sizeof(IniItem) * \
(pSection->alloc_count - pSection->count));
}
memcpy(pItem->name, pLine, nNameLen);
memcpy(pItem->value, pEqualChar + 1, nValueLen);
trim(pItem->name);
trim(pItem->value);
pSection->count++;
pItem++;
}
return result;
}
static int iniFreeHashData(const int index, const HashData *data, void *args)
{
IniSection *pSection;
pSection = (IniSection *)data->value;
if (pSection == NULL)
{
return 0;
}
if (pSection->items != NULL)
{
free(pSection->items);
memset(pSection, 0, sizeof(IniSection));
}
free(pSection);
((HashData *)data)->value = NULL;
return 0;
}
void iniFreeContext(IniContext *pContext)
{
if (pContext == NULL)
{
return;
}
if (pContext->global.items != NULL)
{
free(pContext->global.items);
memset(&pContext->global, 0, sizeof(IniSection));
}
hash_walk(&pContext->sections, iniFreeHashData, NULL);
hash_destroy(&pContext->sections);
}
#define INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
targetItem, pItem, return_val) \
if (szSectionName == NULL || *szSectionName == '\0') \
{ \
pSection = &pContext->global; \
} \
else \
{ \
pSection = (IniSection *)hash_find(&pContext->sections, \
szSectionName, strlen(szSectionName)); \
if (pSection == NULL) \
{ \
return return_val; \
} \
} \
\
if (pSection->count <= 0) \
{ \
return return_val; \
} \
\
snprintf(targetItem.name, sizeof(targetItem.name), "%s", szItemName); \
pItem = (IniItem *)bsearch(&targetItem, pSection->items, \
pSection->count, sizeof(IniItem), iniCompareByItemName);
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext)
{
IniItem targetItem;
IniSection *pSection;
IniItem *pItem;
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
targetItem, pItem, NULL)
if (pItem == NULL)
{
return NULL;
}
else
{
return pItem->value;
}
}
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const int64_t nDefaultValue)
{
char *pValue;
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
if (pValue == NULL)
{
return nDefaultValue;
}
else
{
return strtoll(pValue, NULL, 10);
}
}
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const int nDefaultValue)
{
char *pValue;
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
if (pValue == NULL)
{
return nDefaultValue;
}
else
{
return atoi(pValue);
}
}
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const double dbDefaultValue)
{
char *pValue;
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
if (pValue == NULL)
{
return dbDefaultValue;
}
else
{
return strtod(pValue, NULL);
}
}
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const bool bDefaultValue)
{
char *pValue;
pValue = iniGetStrValue(szSectionName, szItemName, pContext);
if (pValue == NULL)
{
return bDefaultValue;
}
else
{
return strcasecmp(pValue, "true") == 0 ||
strcasecmp(pValue, "yes") == 0 ||
strcasecmp(pValue, "on") == 0 ||
strcmp(pValue, "1") == 0;
}
}
int iniGetValues(const char *szSectionName, const char *szItemName, \
IniContext *pContext, char **szValues, const int max_values)
{
IniItem targetItem;
IniSection *pSection;
IniItem *pFound;
IniItem *pItem;
IniItem *pItemEnd;
char **ppValues;
if (max_values <= 0)
{
return 0;
}
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
targetItem, pFound, 0)
if (pFound == NULL)
{
return 0;
}
ppValues = szValues;
*ppValues++ = pFound->value;
for (pItem=pFound-1; pItem>=pSection->items; pItem--)
{
if (strcmp(pItem->name, szItemName) != 0)
{
break;
}
if (ppValues - szValues < max_values)
{
*ppValues++ = pItem->value;
}
}
pItemEnd = pSection->items + pSection->count;
for (pItem=pFound+1; pItem<pItemEnd; pItem++)
{
if (strcmp(pItem->name, szItemName) != 0)
{
break;
}
if (ppValues - szValues < max_values)
{
*ppValues++ = pItem->value;
}
}
return ppValues - szValues;
}
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
IniContext *pContext, int *nTargetCount)
{
IniItem targetItem;
IniSection *pSection;
IniItem *pFound;
IniItem *pItem;
IniItem *pItemEnd;
IniItem *pItemStart;
*nTargetCount = 0;
INI_FIND_ITEM(szSectionName, szItemName, pContext, pSection, \
targetItem, pFound, NULL)
if (pFound == NULL)
{
return NULL;
}
*nTargetCount = 1;
for (pItem=pFound-1; pItem>=pSection->items; pItem--)
{
if (strcmp(pItem->name, szItemName) != 0)
{
break;
}
(*nTargetCount)++;
}
pItemStart = pFound - (*nTargetCount) + 1;
pItemEnd = pSection->items + pSection->count;
for (pItem=pFound+1; pItem<pItemEnd; pItem++)
{
if (strcmp(pItem->name, szItemName) != 0)
{
break;
}
(*nTargetCount)++;
}
return pItemStart;
}
static int iniPrintHashData(const int index, const HashData *data, void *args)
{
IniSection *pSection;
IniItem *pItem;
IniItem *pItemEnd;
char section_name[256];
int section_len;
int i;
pSection = (IniSection *)data->value;
if (pSection == NULL)
{
return 0;
}
section_len = data->key_len;
if (section_len >= sizeof(section_name))
{
section_len = sizeof(section_name) - 1;
}
memcpy(section_name, data->key, section_len);
*(section_name + section_len) = '\0';
printf("section: %s, item count: %d\n", section_name, pSection->count);
if (pSection->count > 0)
{
i = 0;
pItemEnd = pSection->items + pSection->count;
for (pItem=pSection->items; pItem<pItemEnd; pItem++)
{
printf("%d. %s=%s\n", ++i, pItem->name, pItem->value);
}
}
printf("\n");
return 0;
}
void iniPrintItems(IniContext *pContext)
{
IniItem *pItem;
IniItem *pItemEnd;
int i;
printf("global section, item count: %d\n", pContext->global.count);
if (pContext->global.count > 0)
{
i = 0;
pItemEnd = pContext->global.items + pContext->global.count;
for (pItem=pContext->global.items; pItem<pItemEnd; pItem++)
{
printf("%d. %s=%s\n", ++i, pItem->name, pItem->value);
}
}
printf("\n");
hash_walk(&pContext->sections, iniPrintHashData, NULL);
}

166
src/ini_file_reader.h Normal file
View File

@ -0,0 +1,166 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//ini_file_reader.h
#ifndef INI_FILE_READER_H
#define INI_FILE_READER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common_define.h"
#include "hash.h"
#define FAST_INI_ITEM_NAME_LEN 64
#define FAST_INI_ITEM_VALUE_LEN 256
typedef struct
{
char name[FAST_INI_ITEM_NAME_LEN + 1];
char value[FAST_INI_ITEM_VALUE_LEN + 1];
} IniItem;
typedef struct
{
IniItem *items;
int count; //item count
int alloc_count;
} IniSection;
typedef struct
{
IniSection global;
HashArray sections; //key is session name, and value is IniSection
IniSection *current_section; //for load from ini file
char config_path[MAX_PATH_SIZE]; //save the config filepath
} IniContext;
#ifdef __cplusplus
extern "C" {
#endif
/** load ini items from file
* parameters:
* szFilename: the filename, can be an URL
* pContext: the ini context
* return: error no, 0 for success, != 0 fail
*/
int iniLoadFromFile(const char *szFilename, IniContext *pContext);
/** load ini items from string buffer
* parameters:
* content: the string buffer to parse
* pContext: the ini context
* return: error no, 0 for success, != 0 fail
*/
int iniLoadFromBuffer(char *content, IniContext *pContext);
/** free ini context
* parameters:
* pContext: the ini context
* return: none
*/
void iniFreeContext(IniContext *pContext);
/** get item string value
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* return: item value, return NULL when the item not exist
*/
char *iniGetStrValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext);
/** get item string value
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* szValues: string array to store the values
* max_values: max string array elements
* return: item value count
*/
int iniGetValues(const char *szSectionName, const char *szItemName, \
IniContext *pContext, char **szValues, const int max_values);
/** get item int value (32 bits)
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* nDefaultValue: the default value
* return: item value, return nDefaultValue when the item not exist
*/
int iniGetIntValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const int nDefaultValue);
/** get item string value array
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* nTargetCount: store the item value count
* return: item value array, return NULL when the item not exist
*/
IniItem *iniGetValuesEx(const char *szSectionName, const char *szItemName, \
IniContext *pContext, int *nTargetCount);
/** get item int64 value (64 bits)
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* nDefaultValue: the default value
* return: int64 value, return nDefaultValue when the item not exist
*/
int64_t iniGetInt64Value(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const int64_t nDefaultValue);
/** get item boolean value
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* bDefaultValue: the default value
* return: item boolean value, return bDefaultValue when the item not exist
*/
bool iniGetBoolValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const bool bDefaultValue);
/** get item double value
* parameters:
* szSectionName: the section name, NULL or empty string for
* global section
* szItemName: the item name
* pContext: the ini context
* dbDefaultValue: the default value
* return: item value, return dbDefaultValue when the item not exist
*/
double iniGetDoubleValue(const char *szSectionName, const char *szItemName, \
IniContext *pContext, const double dbDefaultValue);
/** print all items
* parameters:
* pContext: the ini context
* return: none
*/
void iniPrintItems(IniContext *pContext);
#ifdef __cplusplus
}
#endif
#endif

102
src/io_opt.c Normal file
View File

@ -0,0 +1,102 @@
/**
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
*
* FastLib may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastLib source kit.
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
**/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include "io_opt.h"
int mkdir_by_cascading(const char *path,mode_t mode)
{
int length,pointer_postion = 0;
char *postion;
char *path_temp = path;
char cwd[MAX_PATH_SIZE];
char *subfolder;
int is_error = 0;
int result = 0;
if(NULL == getcwd(cwd,sizeof(cwd)))
{
return -1;
}
if(*path_temp == '/')
{
if(-1 == chdir("/"))
{
return -2;
}
pointer_postion ++;
}
while(pointer_postion != strlen(path_temp))
{
postion = strchr(path_temp+pointer_postion,'/');
if(0 == postion)
{
length = strlen(path_temp) - pointer_postion;
}
else
{
length = postion - path_temp - pointer_postion;
}
do
{
subfolder = (char *)calloc(length,sizeof(char));
if(NULL == subfolder)
{
result = -3;
break;
}
memcpy(subfolder,path_temp+pointer_postion,length);
if(is_dir(subfolder))
{
if(-1 == chdir(subfolder))
{
result = -2;
break;
}
}
if(-1 == mkdir(subfolder,mode))
{
result = -4;
break;
}
if(-1 == chdir(subfolder))
{
result = -2;
break;
}
}while(0);
if(NULL != subfolder)
{
free(subfolder);
subfolder = NULL;
}
pointer_postion += 0 == postion ? length : length + 1;
}
return result;
}
int is_dir(const char *dir_path) {
struct stat buf;
if (0 != stat(dir_path, &buf)) {
return 0;
}
return S_ISDIR(buf.st_mode);
}

41
src/io_opt.h Normal file
View File

@ -0,0 +1,41 @@
/**
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
*
* FastLib may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastLib source kit.
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
**/
#ifndef IO_OPT_H_
#define IO_OPT_H_
#ifndef MAX_PATH_SIZE
#define MAX_PATH_SIZE 1024
#endif
/*
* create the dir by full dir_path
* parameters:
* path : the dir full path
* mode : the mode for mkdir
* return:
* 0:create dir is success
* -1 : get current path is error;
* -2 : change dir is error;
* -3 : malloc memory to subfolder is error
* -4 : create dir is error;
*/
int mkdir_by_cascading(const char *path,mode_t mode);
/*
* check the first parameter is the dir
* parameters:
* path : the dir full path
* return:
* 0:the path is dir
* not 0: the path is not dir
*/
int is_dir(const char *path);
#endif /* IO_OPT_H_ */

179
src/ioevent.c Normal file
View File

@ -0,0 +1,179 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "ioevent.h"
#if IOEVENT_USE_KQUEUE
/* we define these here as numbers, because for kqueue mapping them to a combination of
* filters / flags is hard to do. */
int kqueue_ev_convert(int16_t event, uint16_t flags)
{
int r;
if (event == EVFILT_READ) {
r = KPOLLIN;
}
else if (event == EVFILT_WRITE) {
r = KPOLLOUT;
}
else {
r = 0;
}
if (flags & EV_EOF) {
r |= KPOLLHUP;
}
return r;
}
#endif
int ioevent_init(IOEventPoller *ioevent, const int size,
const int timeout, const int extra_events)
{
int bytes;
ioevent->size = size;
ioevent->extra_events = extra_events;
#if IOEVENT_USE_EPOLL
ioevent->timeout = timeout;
ioevent->poll_fd = epoll_create(ioevent->size);
bytes = sizeof(struct epoll_event) * size;
ioevent->events = (struct epoll_event *)malloc(bytes);
#elif IOEVENT_USE_KQUEUE
ioevent->timeout.tv_sec = timeout / 1000;
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
ioevent->poll_fd = kqueue();
bytes = sizeof(struct kevent) * size;
ioevent->events = (struct kevent *)malloc(bytes);
#elif IOEVENT_USE_PORT
ioevent->timeout.tv_sec = timeout / 1000;
ioevent->timeout.tv_nsec = 1000000 * (timeout % 1000);
ioevent->poll_fd = port_create();
bytes = sizeof(port_event_t) * size;
ioevent->events = (port_event_t *)malloc(bytes);
#endif
if (ioevent->events == NULL) {
return errno != 0 ? errno : ENOMEM;
}
return 0;
}
void ioevent_destroy(IOEventPoller *ioevent)
{
if (ioevent->events != NULL) {
free(ioevent->events);
ioevent->events = NULL;
}
if (ioevent->poll_fd >=0) {
close(ioevent->poll_fd);
ioevent->poll_fd = -1;
}
}
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
void *data)
{
#if IOEVENT_USE_EPOLL
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = e | ioevent->extra_events;
ev.data.ptr = data;
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_ADD, fd, &ev);
#elif IOEVENT_USE_KQUEUE
struct kevent ev[2];
int n = 0;
if (e & IOEVENT_READ) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
}
if (e & IOEVENT_WRITE) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
}
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
#elif IOEVENT_USE_PORT
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
#endif
}
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
void *data)
{
#if IOEVENT_USE_EPOLL
struct epoll_event ev;
memset(&ev, 0, sizeof(ev));
ev.events = e | ioevent->extra_events;
ev.data.ptr = data;
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_MOD, fd, &ev);
#elif IOEVENT_USE_KQUEUE
struct kevent ev[2];
int n = 0;
if (e & IOEVENT_READ) {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | ioevent->extra_events, 0, 0, data);
}
else {
EV_SET(&ev[n++], fd, EVFILT_READ, EV_DELETE, 0, 0, data);
}
if (e & IOEVENT_WRITE) {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | ioevent->extra_events, 0, 0, data);
}
else {
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_DELETE, 0, 0, data);
}
return kevent(ioevent->poll_fd, ev, n, NULL, 0, NULL);
#elif IOEVENT_USE_PORT
return port_associate(ioevent->poll_fd, PORT_SOURCE_FD, fd, e, data);
#endif
}
int ioevent_detach(IOEventPoller *ioevent, const int fd)
{
#if IOEVENT_USE_EPOLL
return epoll_ctl(ioevent->poll_fd, EPOLL_CTL_DEL, fd, NULL);
#elif IOEVENT_USE_PORT
return port_dissociate(ioevent->poll_fd, PORT_SOURCE_FD, fd);
#else
return 0;
#endif
}
int ioevent_poll(IOEventPoller *ioevent)
{
#if IOEVENT_USE_EPOLL
return epoll_wait(ioevent->poll_fd, ioevent->events, ioevent->size, ioevent->timeout);
#elif IOEVENT_USE_KQUEUE
return kevent(ioevent->poll_fd, NULL, 0, ioevent->events, ioevent->size, &ioevent->timeout);
#elif IOEVENT_USE_PORT
int result;
int retval;
unsigned int nget = 1;
if((retval = port_getn(ioevent->poll_fd, ioevent->events,
ioevent->size, &nget, &ioevent->timeout)) == 0)
{
result = (int)nget;
} else {
switch(errno) {
case EINTR:
case EAGAIN:
case ETIME:
if (nget > 0) {
result = (int)nget;
}
else {
result = 0;
}
break;
default:
result = -1;
break;
}
}
return result;
#else
#error port me
#endif
}

113
src/ioevent.h Normal file
View File

@ -0,0 +1,113 @@
#ifndef __IOEVENT_H__
#define __IOEVENT_H__
#include <stdint.h>
#include <poll.h>
#include <sys/time.h>
#define IOEVENT_TIMEOUT 0x8000
#if IOEVENT_USE_EPOLL
#include <sys/epoll.h>
#define IOEVENT_EDGE_TRIGGER EPOLLET
#define IOEVENT_READ EPOLLIN
#define IOEVENT_WRITE EPOLLOUT
#define IOEVENT_ERROR (EPOLLERR | EPOLLPRI | EPOLLHUP)
#elif IOEVENT_USE_KQUEUE
#include <sys/event.h>
#define IOEVENT_EDGE_TRIGGER EV_CLEAR
#define KPOLLIN 0x001
#define KPOLLPRI 0x002
#define KPOLLOUT 0x004
#define KPOLLERR 0x010
#define KPOLLHUP 0x020
#define IOEVENT_READ KPOLLIN
#define IOEVENT_WRITE KPOLLOUT
#define IOEVENT_ERROR (KPOLLHUP | KPOLLPRI | KPOLLHUP)
#ifdef __cplusplus
extern "C" {
#endif
int kqueue_ev_convert(int16_t event, uint16_t flags);
#ifdef __cplusplus
}
#endif
#elif IOEVENT_USE_PORT
#include <port.h>
#define IOEVENT_EDGE_TRIGGER 0
#define IOEVENT_READ POLLIN
#define IOEVENT_WRITE POLLOUT
#define IOEVENT_ERROR (POLLERR | POLLPRI | POLLHUP)
#endif
typedef struct ioevent_puller {
int size; //max events (fd)
int extra_events;
int poll_fd;
#if IOEVENT_USE_EPOLL
struct epoll_event *events;
int timeout;
#elif IOEVENT_USE_KQUEUE
struct kevent *events;
struct timespec timeout;
#elif IOEVENT_USE_PORT
port_event_t *events;
timespec_t timeout;
#endif
} IOEventPoller;
#if IOEVENT_USE_EPOLL
#define IOEVENT_GET_EVENTS(ioevent, index) \
ioevent->events[index].events
#elif IOEVENT_USE_KQUEUE
#define IOEVENT_GET_EVENTS(ioevent, index) kqueue_ev_convert( \
ioevent->events[index].filter, ioevent->events[index].flags)
#elif IOEVENT_USE_PORT
#define IOEVENT_GET_EVENTS(ioevent, index) \
ioevent->events[index].portev_events
#else
#error port me
#endif
#if IOEVENT_USE_EPOLL
#define IOEVENT_GET_DATA(ioevent, index) \
ioevent->events[index].data.ptr
#elif IOEVENT_USE_KQUEUE
#define IOEVENT_GET_DATA(ioevent, index) \
ioevent->events[index].udata
#elif IOEVENT_USE_PORT
#define IOEVENT_GET_DATA(ioevent, index) \
ioevent->events[index].portev_user
#else
#error port me
#endif
#ifdef __cplusplus
extern "C" {
#endif
int ioevent_init(IOEventPoller *ioevent, const int size,
const int timeout, const int extra_events);
void ioevent_destroy(IOEventPoller *ioevent);
int ioevent_attach(IOEventPoller *ioevent, const int fd, const int e,
void *data);
int ioevent_modify(IOEventPoller *ioevent, const int fd, const int e,
void *data);
int ioevent_detach(IOEventPoller *ioevent, const int fd);
int ioevent_poll(IOEventPoller *ioevent);
#ifdef __cplusplus
}
#endif
#endif

BIN
src/ioevent.o Normal file

Binary file not shown.

150
src/ioevent_loop.c Normal file
View File

@ -0,0 +1,150 @@
#include "sched_thread.h"
#include "logger.h"
#include "ioevent_loop.h"
static void deal_ioevents(IOEventPoller *ioevent, const int count)
{
int i;
int event;
IOEventEntry *pEntry;
for (i=0; i<count; i++)
{
event = IOEVENT_GET_EVENTS(ioevent, i);
pEntry = (IOEventEntry *)IOEVENT_GET_DATA(ioevent, i);
pEntry->callback(pEntry->fd, event, pEntry->timer.data);
}
}
static void deal_timeouts(FastTimerEntry *head)
{
FastTimerEntry *entry;
FastTimerEntry *curent;
IOEventEntry *pEventEntry;
entry = head->next;
while (entry != NULL)
{
curent = entry;
entry = entry->next;
pEventEntry = (IOEventEntry *)curent->data;
if (pEventEntry != NULL)
{
pEventEntry->callback(pEventEntry->fd, IOEVENT_TIMEOUT,
curent->data);
}
}
}
int ioevent_loop(struct nio_thread_data *pThreadData,
IOEventCallback recv_notify_callback, TaskCleanUpCallBack
clean_up_callback, volatile bool *continue_flag)
{
int result;
IOEventEntry ev_notify;
FastTimerEntry head;
struct fast_task_info *pTask;
time_t last_check_time;
int count;
memset(&ev_notify, 0, sizeof(ev_notify));
ev_notify.fd = pThreadData->pipe_fds[0];
ev_notify.callback = recv_notify_callback;
if (ioevent_attach(&pThreadData->ev_puller,
pThreadData->pipe_fds[0], IOEVENT_READ,
&ev_notify) != 0)
{
result = errno != 0 ? errno : ENOMEM;
logCrit("file: "__FILE__", line: %d, " \
"ioevent_attach fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
last_check_time = g_current_time;
while (*continue_flag)
{
pThreadData->deleted_list = NULL;
count = ioevent_poll(&pThreadData->ev_puller);
if (count > 0)
{
deal_ioevents(&pThreadData->ev_puller, count);
}
else if (count < 0)
{
result = errno != 0 ? errno : EINVAL;
if (result != EINTR)
{
logError("file: "__FILE__", line: %d, " \
"ioevent_poll fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
}
if (pThreadData->deleted_list != NULL)
{
count = 0;
while (pThreadData->deleted_list != NULL)
{
pTask = pThreadData->deleted_list;
pThreadData->deleted_list = pTask->next;
clean_up_callback(pTask);
count++;
}
logInfo("cleanup task count: %d", count);
}
if (g_current_time - last_check_time > 0)
{
last_check_time = g_current_time;
count = fast_timer_timeouts_get(
&pThreadData->timer, g_current_time, &head);
if (count > 0)
{
deal_timeouts(&head);
}
}
}
return 0;
}
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
int sock, short event, IOEventCallback callback, const int timeout)
{
int result;
pTask->thread_data = pThread;
pTask->event.fd = sock;
pTask->event.callback = callback;
if (ioevent_attach(&pThread->ev_puller,
sock, event, pTask) < 0)
{
result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, " \
"ioevent_attach fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
pTask->event.timer.data = pTask;
pTask->event.timer.expires = g_current_time + timeout;
result = fast_timer_add(&pThread->timer, &pTask->event.timer);
if (result != 0)
{
logError("file: "__FILE__", line: %d, " \
"fast_timer_add fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
return 0;
}

22
src/ioevent_loop.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _IOEVENT_LOOP_H
#define _IOEVENT_LOOP_H
#include "fast_task_queue.h"
#ifdef __cplusplus
extern "C" {
#endif
int ioevent_loop(struct nio_thread_data *pThreadData,
IOEventCallback recv_notify_callback, TaskCleanUpCallBack
clean_up_callback, volatile bool *continue_flag);
int ioevent_set(struct fast_task_info *pTask, struct nio_thread_data *pThread,
int sock, short event, IOEventCallback callback, const int timeout);
#ifdef __cplusplus
}
#endif
#endif

BIN
src/ioevent_loop.o Normal file

Binary file not shown.

134
src/local_ip_func.c Normal file
View File

@ -0,0 +1,134 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include "logger.h"
#include "sockopt.h"
#include "shared_func.h"
#include "local_ip_func.h"
int g_local_host_ip_count = 0;
char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \
IP_ADDRESS_SIZE];
char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE] = {0};
bool is_local_host_ip(const char *client_ip)
{
char *p;
char *pEnd;
pEnd = g_local_host_ip_addrs + \
IP_ADDRESS_SIZE * g_local_host_ip_count;
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
{
if (strcmp(client_ip, p) == 0)
{
return true;
}
}
return false;
}
int insert_into_local_host_ip(const char *client_ip)
{
if (is_local_host_ip(client_ip))
{
return 0;
}
if (g_local_host_ip_count >= FAST_MAX_LOCAL_IP_ADDRS)
{
return -1;
}
strcpy(g_local_host_ip_addrs + \
IP_ADDRESS_SIZE * g_local_host_ip_count, \
client_ip);
g_local_host_ip_count++;
return 1;
}
static void log_local_host_ip_addrs()
{
char *p;
char *pEnd;
char buff[512];
int len;
len = sprintf(buff, "local_host_ip_count: %d,", g_local_host_ip_count);
pEnd = g_local_host_ip_addrs + \
IP_ADDRESS_SIZE * g_local_host_ip_count;
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
{
len += sprintf(buff + len, " %s", p);
}
logInfo("%s", buff);
}
void load_local_host_ip_addrs()
{
#define STORAGE_MAX_ALIAS_PREFIX_COUNT 4
char ip_addresses[FAST_MAX_LOCAL_IP_ADDRS][IP_ADDRESS_SIZE];
int count;
int k;
char *if_alias_prefixes[STORAGE_MAX_ALIAS_PREFIX_COUNT];
int alias_count;
insert_into_local_host_ip("127.0.0.1");
memset(if_alias_prefixes, 0, sizeof(if_alias_prefixes));
if (*g_if_alias_prefix == '\0')
{
alias_count = 0;
}
else
{
alias_count = splitEx(g_if_alias_prefix, ',', \
if_alias_prefixes, STORAGE_MAX_ALIAS_PREFIX_COUNT);
for (k=0; k<alias_count; k++)
{
trim(if_alias_prefixes[k]);
}
}
if (gethostaddrs(if_alias_prefixes, alias_count, ip_addresses, \
FAST_MAX_LOCAL_IP_ADDRS, &count) != 0)
{
return;
}
for (k=0; k<count; k++)
{
insert_into_local_host_ip(ip_addresses[k]);
}
log_local_host_ip_addrs();
//print_local_host_ip_addrs();
}
void print_local_host_ip_addrs()
{
char *p;
char *pEnd;
printf("local_host_ip_count=%d\n", g_local_host_ip_count);
pEnd = g_local_host_ip_addrs + \
IP_ADDRESS_SIZE * g_local_host_ip_count;
for (p=g_local_host_ip_addrs; p<pEnd; p+=IP_ADDRESS_SIZE)
{
printf("%d. %s\n", (int)((p-g_local_host_ip_addrs)/ \
IP_ADDRESS_SIZE)+1, p);
}
printf("\n");
}

42
src/local_ip_func.h Normal file
View File

@ -0,0 +1,42 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//local_ip_func.h
#ifndef _LOCAL_IP_FUNC_H
#define _LOCAL_IP_FUNC_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "common_define.h"
#define FAST_IF_ALIAS_PREFIX_MAX_SIZE 32
#define FAST_MAX_LOCAL_IP_ADDRS 16
#ifdef __cplusplus
extern "C" {
#endif
extern int g_local_host_ip_count;
extern char g_local_host_ip_addrs[FAST_MAX_LOCAL_IP_ADDRS * \
IP_ADDRESS_SIZE];
extern char g_if_alias_prefix[FAST_IF_ALIAS_PREFIX_MAX_SIZE];
void load_local_host_ip_addrs();
bool is_local_host_ip(const char *client_ip);
int insert_into_local_host_ip(const char *client_ip);
void print_local_host_ip_addrs();
#ifdef __cplusplus
}
#endif
#endif

668
src/logger.c Normal file
View File

@ -0,0 +1,668 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <pthread.h>
#include "shared_func.h"
#include "pthread_func.h"
#include "sched_thread.h"
#include "logger.h"
#ifndef LINE_MAX
#define LINE_MAX 2048
#endif
#define LOG_BUFF_SIZE 64 * 1024
LogContext g_log_context = {LOG_INFO, STDERR_FILENO, NULL};
static int log_fsync(LogContext *pContext, const bool bNeedLock);
static int check_and_mk_log_dir(const char *base_path)
{
char data_path[MAX_PATH_SIZE];
snprintf(data_path, sizeof(data_path), "%s/logs", base_path);
if (!fileExists(data_path))
{
if (mkdir(data_path, 0755) != 0)
{
fprintf(stderr, "mkdir \"%s\" fail, " \
"errno: %d, error info: %s", \
data_path, errno, STRERROR(errno));
return errno != 0 ? errno : EPERM;
}
}
return 0;
}
int log_init()
{
if (g_log_context.log_buff != NULL)
{
return 0;
}
return log_init_ex(&g_log_context);
}
int log_init_ex(LogContext *pContext)
{
int result;
memset(pContext, 0, sizeof(LogContext));
pContext->log_level = LOG_INFO;
pContext->log_fd = STDERR_FILENO;
pContext->log_to_cache = false;
pContext->rotate_immediately = false;
pContext->time_precision = LOG_TIME_PRECISION_SECOND;
pContext->log_buff = (char *)malloc(LOG_BUFF_SIZE);
if (pContext->log_buff == NULL)
{
fprintf(stderr, "malloc %d bytes fail, " \
"errno: %d, error info: %s", \
LOG_BUFF_SIZE, errno, STRERROR(errno));
return errno != 0 ? errno : ENOMEM;
}
pContext->pcurrent_buff = pContext->log_buff;
if ((result=init_pthread_lock(&(pContext->log_thread_lock))) != 0)
{
return result;
}
return 0;
}
static int log_open(LogContext *pContext)
{
if ((pContext->log_fd = open(pContext->log_filename, O_WRONLY | \
O_CREAT | O_APPEND, 0644)) < 0)
{
fprintf(stderr, "open log file \"%s\" to write fail, " \
"errno: %d, error info: %s", \
pContext->log_filename, errno, STRERROR(errno));
pContext->log_fd = STDERR_FILENO;
return errno != 0 ? errno : EACCES;
}
pContext->current_size = lseek(pContext->log_fd, 0, SEEK_END);
if (pContext->current_size < 0)
{
fprintf(stderr, "lseek file \"%s\" fail, " \
"errno: %d, error info: %s", \
pContext->log_filename, errno, STRERROR(errno));
return errno != 0 ? errno : EACCES;
}
return 0;
}
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
const char *filename_prefix)
{
int result;
if ((result=check_and_mk_log_dir(base_path)) != 0)
{
return result;
}
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s/logs/%s.log", \
base_path, filename_prefix);
return log_open(pContext);
}
int log_set_filename_ex(LogContext *pContext, const char *log_filename)
{
snprintf(pContext->log_filename, MAX_PATH_SIZE, "%s", log_filename);
return log_open(pContext);
}
void log_set_cache_ex(LogContext *pContext, const bool bLogCache)
{
pContext->log_to_cache = bLogCache;
}
void log_set_time_precision(LogContext *pContext, const int time_precision)
{
pContext->time_precision = time_precision;
}
void log_destroy_ex(LogContext *pContext)
{
if (pContext->log_fd >= 0 && pContext->log_fd != STDERR_FILENO)
{
log_fsync(pContext, true);
close(pContext->log_fd);
pContext->log_fd = STDERR_FILENO;
pthread_mutex_destroy(&pContext->log_thread_lock);
}
if (pContext->log_buff != NULL)
{
free(pContext->log_buff);
pContext->log_buff = NULL;
pContext->pcurrent_buff = NULL;
}
}
int log_sync_func(void *args)
{
if (args == NULL)
{
return EINVAL;
}
return log_fsync((LogContext *)args, true);
}
int log_notify_rotate(void *args)
{
if (args == NULL)
{
return EINVAL;
}
((LogContext *)args)->rotate_immediately = true;
return 0;
}
static int log_rotate(LogContext *pContext)
{
struct tm tm;
time_t current_time;
char new_filename[MAX_PATH_SIZE + 32];
if (*(pContext->log_filename) == '\0')
{
return ENOENT;
}
close(pContext->log_fd);
current_time = get_current_time();
localtime_r(&current_time, &tm);
sprintf(new_filename, "%s.%04d%02d%02d_%02d%02d%02d", \
pContext->log_filename, \
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
tm.tm_hour, tm.tm_min, tm.tm_sec);
if (rename(pContext->log_filename, new_filename) != 0)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"rename %s to %s fail, errno: %d, error info: %s", \
__LINE__, pContext->log_filename, new_filename, \
errno, STRERROR(errno));
}
return log_open(pContext);
}
static int log_check_rotate(LogContext *pContext, const bool bNeedLock)
{
int result;
if (pContext->log_fd == STDERR_FILENO)
{
if (pContext->current_size > 0)
{
pContext->current_size = 0;
}
return ENOENT;
}
if (bNeedLock)
{
pthread_mutex_lock(&(pContext->log_thread_lock));
}
if (pContext->rotate_immediately)
{
result = log_rotate(pContext);
pContext->rotate_immediately = false;
}
else
{
result = 0;
}
if (bNeedLock)
{
pthread_mutex_unlock(&(pContext->log_thread_lock));
}
return result;
}
static int log_fsync(LogContext *pContext, const bool bNeedLock)
{
int result;
int lock_res;
int write_bytes;
write_bytes = pContext->pcurrent_buff - pContext->log_buff;
if (write_bytes == 0)
{
if (!pContext->rotate_immediately)
{
return 0;
}
else
{
return log_check_rotate(pContext, bNeedLock);
}
}
if (bNeedLock && ((lock_res=pthread_mutex_lock( \
&(pContext->log_thread_lock))) != 0))
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, lock_res, STRERROR(lock_res));
}
if (pContext->rotate_size > 0)
{
pContext->current_size += write_bytes;
if (pContext->current_size > pContext->rotate_size)
{
pContext->rotate_immediately = true;
log_check_rotate(pContext, false);
}
}
result = 0;
do
{
write_bytes = pContext->pcurrent_buff - pContext->log_buff;
if (write(pContext->log_fd, pContext->log_buff, write_bytes) != \
write_bytes)
{
result = errno != 0 ? errno : EIO;
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call write fail, errno: %d, error info: %s\n",\
__LINE__, result, STRERROR(result));
break;
}
if (pContext->log_fd != STDERR_FILENO)
{
if (fsync(pContext->log_fd) != 0)
{
result = errno != 0 ? errno : EIO;
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call fsync fail, errno: %d, error info: %s\n",\
__LINE__, result, STRERROR(result));
break;
}
}
if (pContext->rotate_immediately)
{
result = log_check_rotate(pContext, false);
}
} while (0);
pContext->pcurrent_buff = pContext->log_buff;
if (bNeedLock && ((lock_res=pthread_mutex_unlock( \
&(pContext->log_thread_lock))) != 0))
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, lock_res, STRERROR(lock_res));
}
return result;
}
static void doLogEx(LogContext *pContext, struct timeval *tv, \
const char *caption, const char *text, const int text_len, \
const bool bNeedSync)
{
struct tm tm;
int time_fragment;
int buff_len;
int result;
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
{
time_fragment = 0;
}
else
{
if (pContext->time_precision == LOG_TIME_PRECISION_MSECOND)
{
time_fragment = tv->tv_usec / 1000;
}
else
{
time_fragment = tv->tv_usec;
}
}
localtime_r(&tv->tv_sec, &tm);
if ((result=pthread_mutex_lock(&pContext->log_thread_lock)) != 0)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_lock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
if (text_len + 64 > LOG_BUFF_SIZE)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"log buff size: %d < log text length: %d ", \
__LINE__, LOG_BUFF_SIZE, text_len + 64);
pthread_mutex_unlock(&(pContext->log_thread_lock));
return;
}
if ((pContext->pcurrent_buff - pContext->log_buff) + text_len + 64 \
> LOG_BUFF_SIZE)
{
log_fsync(pContext, false);
}
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
{
buff_len = sprintf(pContext->pcurrent_buff, \
"[%04d-%02d-%02d %02d:%02d:%02d] ", \
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
tm.tm_hour, tm.tm_min, tm.tm_sec);
}
else
{
buff_len = sprintf(pContext->pcurrent_buff, \
"[%04d-%02d-%02d %02d:%02d:%02d.%03d] ", \
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, \
tm.tm_hour, tm.tm_min, tm.tm_sec, time_fragment);
}
pContext->pcurrent_buff += buff_len;
if (caption != NULL)
{
buff_len = sprintf(pContext->pcurrent_buff, "%s - ", caption);
pContext->pcurrent_buff += buff_len;
}
memcpy(pContext->pcurrent_buff, text, text_len);
pContext->pcurrent_buff += text_len;
*pContext->pcurrent_buff++ = '\n';
if (!pContext->log_to_cache || bNeedSync)
{
log_fsync(pContext, false);
}
if ((result=pthread_mutex_unlock(&(pContext->log_thread_lock))) != 0)
{
fprintf(stderr, "file: "__FILE__", line: %d, " \
"call pthread_mutex_unlock fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
}
static void doLog(LogContext *pContext, const char *caption, \
const char *text, const int text_len, const bool bNeedSync)
{
struct timeval tv;
if (pContext->time_precision == LOG_TIME_PRECISION_SECOND)
{
tv.tv_sec = get_current_time();
tv.tv_usec = 0;
}
else
{
gettimeofday(&tv, NULL);
}
doLogEx(pContext, &tv, caption, text, text_len, bNeedSync);
}
void log_it_ex1(LogContext *pContext, const int priority, \
const char *text, const int text_len)
{
bool bNeedSync;
char *caption;
switch(priority)
{
case LOG_DEBUG:
bNeedSync = true;
caption = "DEBUG";
break;
case LOG_INFO:
bNeedSync = true;
caption = "INFO";
break;
case LOG_NOTICE:
bNeedSync = false;
caption = "NOTICE";
break;
case LOG_WARNING:
bNeedSync = false;
caption = "WARNING";
break;
case LOG_ERR:
bNeedSync = false;
caption = "ERROR";
break;
case LOG_CRIT:
bNeedSync = true;
caption = "CRIT";
break;
case LOG_ALERT:
bNeedSync = true;
caption = "ALERT";
break;
case LOG_EMERG:
bNeedSync = true;
caption = "EMERG";
break;
default:
bNeedSync = false;
caption = "UNKOWN";
break;
}
doLog(pContext, caption, text, text_len, bNeedSync);
}
void log_it_ex(LogContext *pContext, const int priority, const char *format, ...)
{
bool bNeedSync;
char text[LINE_MAX];
char *caption;
int len;
va_list ap;
va_start(ap, format);
len = vsnprintf(text, sizeof(text), format, ap);
va_end(ap);
switch(priority)
{
case LOG_DEBUG:
bNeedSync = true;
caption = "DEBUG";
break;
case LOG_INFO:
bNeedSync = true;
caption = "INFO";
break;
case LOG_NOTICE:
bNeedSync = false;
caption = "NOTICE";
break;
case LOG_WARNING:
bNeedSync = false;
caption = "WARNING";
break;
case LOG_ERR:
bNeedSync = false;
caption = "ERROR";
break;
case LOG_CRIT:
bNeedSync = true;
caption = "CRIT";
break;
case LOG_ALERT:
bNeedSync = true;
caption = "ALERT";
break;
case LOG_EMERG:
bNeedSync = true;
caption = "EMERG";
break;
default:
bNeedSync = false;
caption = "UNKOWN";
break;
}
doLog(pContext, caption, text, len, bNeedSync);
}
#define _DO_LOG(pContext, priority, caption, bNeedSync) \
char text[LINE_MAX]; \
int len; \
\
if (pContext->log_level < priority) \
{ \
return; \
} \
\
{ \
va_list ap; \
va_start(ap, format); \
len = vsnprintf(text, sizeof(text), format, ap); \
va_end(ap); \
} \
\
doLog(pContext, caption, text, len, bNeedSync); \
void logEmergEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_EMERG, "EMERG", true)
}
void logAlertEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_ALERT, "ALERT", true)
}
void logCritEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_CRIT, "CRIT", true)
}
void logErrorEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_ERR, "ERROR", false)
}
void logWarningEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_WARNING, "WARNING", false)
}
void logNoticeEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_NOTICE, "NOTICE", false)
}
void logInfoEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_INFO, "INFO", false)
}
void logDebugEx(LogContext *pContext, const char *format, ...)
{
_DO_LOG(pContext, LOG_DEBUG, "DEBUG", false)
}
void logAccess(LogContext *pContext, struct timeval *tvStart, \
const char *format, ...)
{
char text[LINE_MAX];
int len;
va_list ap;
va_start(ap, format);
len = vsnprintf(text, sizeof(text), format, ap);
va_end(ap);
doLogEx(pContext, tvStart, NULL, text, len, false);
}
#ifndef LOG_FORMAT_CHECK
void logEmerg(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_EMERG, "EMERG", true)
}
void logAlert(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_ALERT, "ALERT", true)
}
void logCrit(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_CRIT, "CRIT", true)
}
void logError(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_ERR, "ERROR", false)
}
void logWarning(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_WARNING, "WARNING", false)
}
void logNotice(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_NOTICE, "NOTICE", false)
}
void logInfo(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_INFO, "INFO", true)
}
void logDebug(const char *format, ...)
{
_DO_LOG((&g_log_context), LOG_DEBUG, "DEBUG", true)
}
#endif

212
src/logger.h Normal file
View File

@ -0,0 +1,212 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//logger.h
#ifndef LOGGER_H
#define LOGGER_H
#include <syslog.h>
#include <sys/time.h>
#include "common_define.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_TIME_PRECISION_SECOND 's' //second
#define LOG_TIME_PRECISION_MSECOND 'm' //millisecond
#define LOG_TIME_PRECISION_USSECOND 'u' //microsecond
typedef struct log_context
{
/* log level value please see: sys/syslog.h
default value is LOG_INFO */
int log_level;
/* default value is STDERR_FILENO */
int log_fd;
/* cache buffer */
char *log_buff;
/* string end in the cache buffer for next sprintf */
char *pcurrent_buff;
/* mutext lock */
pthread_mutex_t log_thread_lock;
/*
rotate the log when the log file exceeds this parameter
rotate_size > 0 means need rotate log by log file size
*/
int64_t rotate_size;
/* log file current size */
int64_t current_size;
/* if write to buffer firstly, then sync to disk.
default value is false (no cache) */
bool log_to_cache;
/* if rotate the access log */
bool rotate_immediately;
/* time precision */
char time_precision;
/* save the log filename */
char log_filename[MAX_PATH_SIZE];
} LogContext;
extern LogContext g_log_context;
/** init function using global log context
* return: 0 for success, != 0 fail
*/
int log_init();
#define log_set_prefix(base_path, filename_prefix) \
log_set_prefix_ex(&g_log_context, base_path, filename_prefix)
#define log_set_filename(log_filename) \
log_set_filename_ex(&g_log_context, log_filename)
#define log_set_cache(bLogCache) log_set_cache_ex(&g_log_context, bLogCache)
#define log_destroy() log_destroy_ex(&g_log_context)
/** init function, use stderr for output by default
* parameters:
* pContext: the log context
* return: 0 for success, != 0 fail
*/
int log_init_ex(LogContext *pContext);
/** set log filename prefix, such as "tracker", the log filename will be
* ${base_path}/logs/tracker.log
* parameters:
* pContext: the log context
* base_path: base path
* filename_prefix: log filename prefix
* return: 0 for success, != 0 fail
*/
int log_set_prefix_ex(LogContext *pContext, const char *base_path, \
const char *filename_prefix);
/** set log filename
* parameters:
* pContext: the log context
* log_filename: log filename
* return: 0 for success, != 0 fail
*/
int log_set_filename_ex(LogContext *pContext, const char *log_filename);
/** set if use log cache
* parameters:
* pContext: the log context
* bLogCache: true for cache in buffer, false directly write to disk
* return: none
*/
void log_set_cache_ex(LogContext *pContext, const bool bLogCache);
/** set time precision
* parameters:
* pContext: the log context
* time_precision: the time precision
* return: none
*/
void log_set_time_precision(LogContext *pContext, const int time_precision);
/** destroy function
* parameters:
* pContext: the log context
* bLogCache: true for cache in buffer, false directly write to disk
* return: none
*/
void log_destroy_ex(LogContext *pContext);
/** log to file
* parameters:
* pContext: the log context
* priority: unix priority
* format: printf format
* ...: arguments for printf format
* return: none
*/
void log_it_ex(LogContext *pContext, const int priority, \
const char *format, ...);
/** log to file
* parameters:
* pContext: the log context
* priority: unix priority
* text: text string to log
* text_len: text string length (bytes)
* return: none
*/
void log_it_ex1(LogContext *pContext, const int priority, \
const char *text, const int text_len);
/** sync log buffer to log file
* parameters:
* args: should be (LogContext *)
* return: error no, 0 for success, != 0 fail
*/
int log_sync_func(void *args);
/** set rotate flag to true
* parameters:
* args: should be (LogContext *)
* return: error no, 0 for success, != 0 fail
*/
int log_notify_rotate(void *args);
void logEmergEx(LogContext *pContext, const char *format, ...);
void logCritEx(LogContext *pContext, const char *format, ...);
void logAlertEx(LogContext *pContext, const char *format, ...);
void logErrorEx(LogContext *pContext, const char *format, ...);
void logWarningEx(LogContext *pContext, const char *format, ...);
void logNoticeEx(LogContext *pContext, const char *format, ...);
void logInfoEx(LogContext *pContext, const char *format, ...);
void logDebugEx(LogContext *pContext, const char *format, ...);
void logAccess(LogContext *pContext, struct timeval *tvStart, \
const char *format, ...);
//#define LOG_FORMAT_CHECK
#ifdef LOG_FORMAT_CHECK /*only for format check*/
#define logEmerg printf
#define logCrit printf
#define logAlert printf
#define logError printf
#define logWarning printf
#define logNotice printf
#define logInfo printf
#define logDebug printf
#else
/* following functions use global log context: g_log_context */
void logEmerg(const char *format, ...);
void logCrit(const char *format, ...);
void logAlert(const char *format, ...);
void logError(const char *format, ...);
void logWarning(const char *format, ...);
void logNotice(const char *format, ...);
void logInfo(const char *format, ...);
void logDebug(const char *format, ...);
#endif
#ifdef __cplusplus
}
#endif
#endif

356
src/md5.c Normal file
View File

@ -0,0 +1,356 @@
#include "md5.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Transform (UINT4[4], unsigned char[64]);
static void Encode (unsigned char *, UINT4 *, unsigned int);
static void Decode (UINT4 *, unsigned char *, unsigned int);
static void MD5_memcpy (POINTER, POINTER, unsigned int);
static void MD5_memset (POINTER, int, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/*
* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/*
* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/*
* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is
* separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/*
* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void
my_md5_init(MD5_CTX *context)
{
context->count[0] = context->count[1] = 0;
/*
* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/*
* MD5 block update operation. Continues an MD5 message-digest operation,
* processing another message block, and updating the context.
*/
void
my_md5_update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4) inputLen >> 29);
partLen = 64 - index;
/*
* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD5_memcpy
((POINTER) & context->buffer[index], (POINTER) input, partLen);
MD5Transform(context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform(context->state, &input[i]);
index = 0;
} else
i = 0;
/* Buffer remaining input */
MD5_memcpy
((POINTER) & context->buffer[index], (POINTER) & input[i],
inputLen - i);
}
/*
* MD5 finalization. Ends an MD5 message-digest operation, writing the the
* message digest and zeroizing the context.
*/
void
my_md5_final(unsigned char digest[16], MD5_CTX *context)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode(bits, context->count, 8);
/*
* Pad out to 56 mod 64.
*/
index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
my_md5_update(context, PADDING, padLen);
/* Append length (before padding) */
my_md5_update(context, bits, 8);
/* Store state in digest */
Encode(digest, context->state, 16);
/*
* Zeroize sensitive information.
*/
MD5_memset((POINTER) context, 0, sizeof(*context));
}
/*
* MD5 basic transformation. Transforms state based on block.
*/
static void
MD5Transform(UINT4 state[4], unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3],
x[16];
Decode(x, block, 64);
/* Round 1 */
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/*
* Zeroize sensitive information.
*
*/
MD5_memset((POINTER) x, 0, sizeof(x));
}
/*
* Encodes input (UINT4) into output (unsigned char). Assumes len is a
* multiple of 4.
*/
static void
Encode(unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char) (input[i] & 0xff);
output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
}
}
/*
* Decodes input (unsigned char) into output (UINT4). Assumes len is a
* multiple of 4.
*/
static void
Decode(UINT4 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
(((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
}
/*
* Note: Replace "for loop" with standard memcpy if possible.
*/
static void
MD5_memcpy(POINTER output, POINTER input, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/*
* Note: Replace "for loop" with standard memset if possible.
*/
static void
MD5_memset(POINTER output, int value, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
((char *) output)[i] = (char) value;
}
/*
* Digests a string
*/
int my_md5_string(char *string,unsigned char digest[16])
{
MD5_CTX context;
unsigned int len = strlen(string);
my_md5_init(&context);
my_md5_update(&context, (unsigned char *)string, len);
my_md5_final(digest, &context);
return 0;
}
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16])
{
MD5_CTX context;
my_md5_init(&context);
my_md5_update(&context, (unsigned char *)buffer, len);
my_md5_final(digest, &context);
return 0;
}
int my_md5_file(char *filename,unsigned char digest[16])
{
FILE *file;
MD5_CTX context;
int len;
unsigned char buffer[1024];
if ((file = fopen(filename, "rb")) == NULL)
return -1;
else {
my_md5_init(&context);
while ((len = fread(buffer, 1, 1024, file)) > 0)
{
my_md5_update(&context, buffer, len);
}
my_md5_final(digest, &context);
fclose(file);
}
return 0;
}

55
src/md5.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef MCL_MD5_H
#define MCL_MD5_H
#include <stdio.h>
typedef unsigned char *POINTER;
typedef unsigned short int UINT2;
typedef unsigned int UINT4;
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
#ifdef __cplusplus
extern "C" {
#endif
/** md5 for string
* parameters:
* string: the string to md5
* digest: store the md5 digest
* return: 0 for success, != 0 fail
*/
int my_md5_string(char *string, unsigned char digest[16]);
/** md5 for file
* parameters:
* filename: the filename whose content to md5
* digest: store the md5 digest
* return: 0 for success, != 0 fail
*/
int my_md5_file(char *filename, unsigned char digest[16]);
/** md5 for buffer
* parameters:
* buffer: the buffer to md5
* len: the buffer length
* digest: store the md5 digest
* return: 0 for success, != 0 fail
*/
int my_md5_buffer(char *buffer, unsigned int len, unsigned char digest[16]);
void my_md5_init (MD5_CTX *);
void my_md5_update (MD5_CTX *, unsigned char *, unsigned int);
void my_md5_final (unsigned char [16], MD5_CTX *);
#ifdef __cplusplus
}
#endif
#endif

234
src/process_ctrl.c Normal file
View File

@ -0,0 +1,234 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "shared_func.h"
#include "logger.h"
#include "process_ctrl.h"
int get_pid_from_file(const char *pidFilename, pid_t *pid)
{
char buff[32];
int64_t file_size;
int result;
if (access(pidFilename, F_OK) != 0) {
return errno != 0 ? errno : EPERM;
}
file_size = sizeof(buff) - 1;
if ((result=getFileContentEx(pidFilename, buff, 0, &file_size)) != 0) {
return result;
}
*(buff + file_size) = '\0';
*pid = strtol(buff, NULL, 10);
if (*pid == 0) {
return EINVAL;
}
return 0;
}
int write_to_pid_file(const char *pidFilename)
{
char buff[32];
int len;
len = sprintf(buff, "%d", (int)getpid());
return writeToFile(pidFilename, buff, len);
}
int delete_pid_file(const char *pidFilename)
{
if (unlink(pidFilename) == 0) {
return 0;
}
else {
return errno != 0 ? errno : ENOENT;
}
}
static int do_stop(const char *pidFilename, const bool bShowError, pid_t *pid)
{
int result;
if ((result=get_pid_from_file(pidFilename, pid)) != 0) {
if (bShowError) {
if (result == ENOENT) {
fprintf(stderr, "pid file: %s not exist!\n", pidFilename);
}
else {
fprintf(stderr, "get pid from file: %s fail, " \
"errno: %d, error info: %s\n",
pidFilename, result, strerror(result));
}
}
return result;
}
if (kill(*pid, SIGTERM) == 0) {
return 0;
}
else {
result = errno != 0 ? errno : EPERM;
if (bShowError || result != ESRCH) {
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
(int)*pid, result, strerror(result));
}
return result;
}
}
int process_stop(const char *pidFilename)
{
pid_t pid;
int result;
result = do_stop(pidFilename, true, &pid);
if (result != 0) {
return result;
}
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
do {
sleep(1);
} while (kill(pid, SIGTERM) == 0);
fprintf(stderr, "pid [%d] exit.\n", (int)pid);
return 0;
}
int process_restart(const char *pidFilename)
{
int result;
pid_t pid;
result = do_stop(pidFilename, false, &pid);
if (result == 0) {
fprintf(stderr, "waiting for pid [%d] exit ...\n", (int)pid);
do {
sleep(1);
} while (kill(pid, SIGTERM) == 0);
fprintf(stderr, "starting ...\n");
}
if (result == ENOENT || result == ESRCH) {
return 0;
}
return result;
}
int process_exist(const char *pidFilename)
{
pid_t pid;
int result;
if ((result=get_pid_from_file(pidFilename, &pid)) != 0) {
if (result == ENOENT) {
return false;
}
else {
fprintf(stderr, "get pid from file: %s fail, " \
"errno: %d, error info: %s\n",
pidFilename, result, strerror(result));
return true;
}
}
if (kill(pid, 0) == 0) {
return true;
}
else if (errno == ENOENT || errno == ESRCH) {
return false;
}
else {
fprintf(stderr, "kill pid: %d fail, errno: %d, error info: %s\n",
(int)pid, errno, strerror(errno));
return true;
}
}
int get_base_path_from_conf_file(const char *filename, char *base_path,
const int path_size)
{
char *pBasePath;
IniContext iniContext;
int result;
memset(&iniContext, 0, sizeof(IniContext));
if ((result=iniLoadFromFile(filename, &iniContext)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"load conf file \"%s\" fail, ret code: %d", \
__LINE__, filename, result);
return result;
}
do
{
pBasePath = iniGetStrValue(NULL, "base_path", &iniContext);
if (pBasePath == NULL)
{
logError("file: "__FILE__", line: %d, " \
"conf file \"%s\" must have item " \
"\"base_path\"!", __LINE__, filename);
result = ENOENT;
break;
}
snprintf(base_path, path_size, "%s", pBasePath);
chopPath(base_path);
if (!fileExists(base_path))
{
logError("file: "__FILE__", line: %d, " \
"\"%s\" can't be accessed, error info: %s", \
__LINE__, base_path, STRERROR(errno));
result = errno != 0 ? errno : ENOENT;
break;
}
if (!isDir(base_path))
{
logError("file: "__FILE__", line: %d, " \
"\"%s\" is not a directory!", \
__LINE__, base_path);
result = ENOTDIR;
break;
}
} while (0);
iniFreeContext(&iniContext);
return result;
}
int process_action(const char *pidFilename, const char *action, bool *stop)
{
*stop = false;
if (action == NULL)
{
return 0;
}
if (strcmp(action, "stop") == 0)
{
*stop = true;
return process_stop(pidFilename);
}
else if (strcmp(action, "restart") == 0)
{
return process_restart(pidFilename);
}
else if (strcmp(action, "start") == 0)
{
return 0;
}
else
{
fprintf(stderr, "invalid action: %s\n", action);
return EINVAL;
}
}

37
src/process_ctrl.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef PROCESS_CTRL_H
#define PROCESS_CTRL_H
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifdef __cplusplus
extern "C" {
#endif
int get_base_path_from_conf_file(const char *filename, char *base_path,
const int path_size);
int get_pid_from_file(const char *pidFilename, pid_t *pid);
int write_to_pid_file(const char *pidFilename);
int delete_pid_file(const char *pidFilename);
int process_stop(const char *pidFilename);
int process_restart(const char *pidFilename);
int process_exist(const char *pidFilename);
int process_action(const char *pidFilename, const char *action, bool *stop);
#ifdef __cplusplus
}
#endif
#endif

BIN
src/process_ctrl.o Normal file

Binary file not shown.

193
src/pthread_func.c Normal file
View File

@ -0,0 +1,193 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/file.h>
#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include "pthread_func.h"
#include "logger.h"
int init_pthread_lock(pthread_mutex_t *pthread_lock)
{
pthread_mutexattr_t mat;
int result;
if ((result=pthread_mutexattr_init(&mat)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutexattr_init fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
if ((result=pthread_mutexattr_settype(&mat, \
PTHREAD_MUTEX_ERRORCHECK)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutexattr_settype fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
if ((result=pthread_mutex_init(pthread_lock, &mat)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_mutex_init fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
if ((result=pthread_mutexattr_destroy(&mat)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call thread_mutexattr_destroy fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
return 0;
}
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size)
{
size_t old_stack_size;
size_t new_stack_size;
int result;
if ((result=pthread_attr_init(pattr)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_attr_init fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
if ((result=pthread_attr_getstacksize(pattr, &old_stack_size)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_attr_getstacksize fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
if (stack_size > 0)
{
if (old_stack_size != stack_size)
{
new_stack_size = stack_size;
}
else
{
new_stack_size = 0;
}
}
else if (old_stack_size < 1 * 1024 * 1024)
{
new_stack_size = 1 * 1024 * 1024;
}
else
{
new_stack_size = 0;
}
if (new_stack_size > 0)
{
if ((result=pthread_attr_setstacksize(pattr, \
new_stack_size)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_attr_setstacksize fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
}
if ((result=pthread_attr_setdetachstate(pattr, \
PTHREAD_CREATE_DETACHED)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"call pthread_attr_setdetachstate fail, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
return result;
}
return 0;
}
int create_work_threads(int *count, void *(*start_func)(void *), \
void *arg, pthread_t *tids, const int stack_size)
{
int result;
pthread_attr_t thread_attr;
pthread_t *ptid;
pthread_t *ptid_end;
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
{
return result;
}
result = 0;
ptid_end = tids + (*count);
for (ptid=tids; ptid<ptid_end; ptid++)
{
if ((result=pthread_create(ptid, &thread_attr, \
start_func, arg)) != 0)
{
*count = ptid - tids;
logError("file: "__FILE__", line: %d, " \
"create thread failed, startup threads: %d, " \
"errno: %d, error info: %s", \
__LINE__, *count, \
result, STRERROR(result));
break;
}
}
pthread_attr_destroy(&thread_attr);
return result;
}
int kill_work_threads(pthread_t *tids, const int count)
{
int result;
pthread_t *ptid;
pthread_t *ptid_end;
ptid_end = tids + count;
for (ptid=tids; ptid<ptid_end; ptid++)
{
if ((result=pthread_kill(*ptid, SIGINT)) != 0)
{
logError("file: "__FILE__", line: %d, " \
"kill thread failed, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
}
return 0;
}

36
src/pthread_func.h Normal file
View File

@ -0,0 +1,36 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#ifndef PTHREAD_FUNC_H
#define PTHREAD_FUNC_H
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "common_define.h"
#ifdef __cplusplus
extern "C" {
#endif
int init_pthread_lock(pthread_mutex_t *pthread_lock);
int init_pthread_attr(pthread_attr_t *pattr, const int stack_size);
int create_work_threads(int *count, void *(*start_func)(void *), \
void *arg, pthread_t *tids, const int stack_size);
int kill_work_threads(pthread_t *tids, const int count);
#ifdef __cplusplus
}
#endif
#endif

256
src/pthread_pool.c Normal file
View File

@ -0,0 +1,256 @@
/**
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
*
* FastLib may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastLib source kit.
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
**/
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "pthread_pool.h"
/*
*the thread pool
*/
static threadpool_info_t *pool;
/*
* the thread callback function proxy
* parameters:
* arg:the thread callback function parameter
*/
static void *callback_proxy(void *arg);
/*
* push the thread into the pool
* parameters:
* thread:the thread will push into the poolbool
* return:
* 0:success
* >0 : fail
*/
static int push2pool(thread_info_t *thread);
static void *callback_proxy(void *arg)
{
thread_info_t* thread = (thread_info_t *) arg;
while(initialized == pool->state)
{
thread->func(thread->arg);
if(pool == NULL || initialized != pool->state) break;
pthread_mutex_lock(&thread->mutex_locker);
if(0 == push2pool(thread))
{
pthread_cond_wait(&thread->run_locker,&thread->mutex_locker);
pthread_mutex_unlock(&thread->mutex_locker);
}
else
{
pthread_mutex_unlock( &thread->mutex_locker );
pthread_cond_destroy( &thread->run_locker );
pthread_mutex_destroy( &thread->mutex_locker );
free( thread );
break;
}
}
pthread_mutex_lock(&pool->mutex_locker);
pool->current_size --;
if(0 >= pool->current_size) pthread_cond_signal(&pool->empty_locker);
pthread_mutex_unlock(&pool->mutex_locker);
return NULL;
}
static int push2pool(thread_info_t *thread)
{
int result = -1;
do
{
pthread_mutex_lock(&pool->mutex_locker);
if( pool->current_index < pool->total_size )
{
pool->list[ pool->current_index ] = thread;
pool->current_index++;
result = 0;
pthread_cond_signal( &pool->run_locker);
if( pool->current_index >= pool->current_size )
{
pthread_cond_signal( &pool->full_locker );
}
}
}while(0);
pthread_mutex_unlock(&pool->mutex_locker);
return result;
}
int threadpool_init(int size)
{
if(0 >= size)
{
return -1;
}
pool = (threadpool_info_t *) malloc(sizeof(threadpool_info_t));
if(NULL == pool)
{
return -2;
}
memset(pool,0,sizeof(threadpool_info_t));
pool->state = initializing;
pool->total_size = size;
pool->current_size = 0;
pool->current_index = 0;
pthread_mutex_init(&pool->mutex_locker,NULL);
pthread_cond_init(&pool->run_locker,NULL);
pthread_cond_init(&pool->empty_locker,NULL);
pthread_cond_init(&pool->full_locker,NULL);
pool->list = (thread_info_t **) malloc(sizeof(thread_info_t*) * size);
if(NULL == pool->list)
{
pthread_cond_destroy(&pool->run_locker);
pthread_cond_destroy(&pool->empty_locker);
pthread_cond_destroy(&pool->full_locker);
pthread_mutex_destroy(&pool->mutex_locker);
free(pool);
return -2;
}
pool->state = initialized;
return 0;
}
int threadpool_run(callback func,void *arg)
{
if(NULL == pool)
{
return -1;
}
int result = 0;
do
{
pthread_mutex_lock(&pool->mutex_locker);
if(NULL == pool || initialized != pool->state) //the pool cannot use
{
result = -1;
break;
}
//current size is >= the max pool size and all thread are busy now
while(pool->current_index <= 0 && pool->current_size >= pool->total_size)
{
pthread_cond_wait(&pool->run_locker,&pool->mutex_locker);
}
if(0 >= pool->current_index)
{
thread_info_t * thread = (thread_info_t *) malloc(sizeof(thread_info_t));
if(NULL == thread)
{
result = -2;
break;
}
memset(thread,0,sizeof(thread_info_t));
pthread_mutex_init(&thread->mutex_locker,NULL);
pthread_cond_init(&thread->run_locker,NULL);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
thread->arg = arg;
thread->func = func;
if(0 == pthread_create(&thread->id,&attr,callback_proxy,thread))
{
pool->current_size ++;
}
else
{
result = -3;
pthread_mutex_destroy(&thread->mutex_locker);
pthread_cond_destroy(&thread->run_locker);
free(thread);
}
break;
}
else
{
pool->current_index --;//because the array begin with 0
thread_info_t *thread = pool->list[ pool->current_index ];
pool->list[ pool->current_index ] = NULL;
thread->func = func;
thread->arg = arg;
pthread_mutex_lock( &thread->mutex_locker );
pthread_cond_signal( &thread->run_locker ) ;
pthread_mutex_unlock ( &thread->mutex_locker );
}
}while(0);
pthread_mutex_unlock(&pool->mutex_locker);
return result;
return 0;
}
int threadpool_free()
{
if(NULL == pool) return 0;
pthread_mutex_lock( &pool->mutex_locker);
if( pool->current_index < pool->current_size )
{
pthread_cond_wait( &pool->full_locker, &pool->mutex_locker );
}
pool->state = uninstalling;
int i = 0;
for( i = 0; i < pool->current_index; i++ )
{
thread_info_t *thread = pool->list[i];
pthread_mutex_lock( &thread->mutex_locker );
pthread_cond_signal( &thread->run_locker ) ;
pthread_mutex_unlock ( &thread->mutex_locker );
}
if(0 < pool->current_size)
{
pthread_cond_wait( &pool->empty_locker, &pool->mutex_locker);
}
for( i = 0; i < pool->current_index; i++ )
{
free( pool->list[ i ] );
pool->list[ i ] = NULL;
}
pthread_mutex_unlock( &pool->mutex_locker );
pool->current_index = 0;
pthread_mutex_destroy( &pool->mutex_locker );
pthread_cond_destroy( &pool->run_locker );
pthread_cond_destroy( &pool->full_locker );
pthread_cond_destroy( &pool->empty_locker );
free( pool->list );
pool->list = NULL;
free( pool);
pool = NULL;
return 0;
}

116
src/pthread_pool.h Normal file
View File

@ -0,0 +1,116 @@
/**
* Copyright (C) 2008 Seapeak.Xu / xvhfeng@gmail.com
*
* FastLib may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastLib source kit.
* Please visit the FastLib Home Page http://www.csource.org/ for more detail.
**/
#ifndef PTHREAD_POOL_H_
#define PTHREAD_POOL_H_
#include <pthread.h>
/*
* define the callback function type of thread
*/
typedef void (*callback)(void *);
/*
* the thread pool state
* member:
* uninit : not initialize the thread pool.
* initing : initializing the thread pool.
* using : the pool can use.
* uninstalling : uninstalling the thread pool.
* uninstalled : uninstall the thread pool is over.
*/
typedef enum threadpool_state
{
uninitialized,
initializing,
initialized,
uninstalling,
uninstalled,
}thread_state_t;
/*
* define the thread type which in the pool
* members:
* id : the thread id
* mutex_locker : the mutext locker
* run_locker : the locker for noticing the thread do running or waitting
* func : the callback function for thread
* arg : the callback parameter
*/
typedef struct thread_info
{
pthread_t id;
pthread_mutex_t mutex_locker;
pthread_cond_t run_locker;
callback func;
void *arg;
}thread_info_t;
/*
* the structure for the thread pool
* member:
* list : the initialazed thread list
* mutex_locker : the mutex locker for the thread operation.
* run_locker : the locker for noticing the thread do running or waitting.
* full_locker : the locker notice the thread is stoping when free the thread pool and the pool is not full .
* empry_Locker : the locker notice the thread waitting for the busy thread work over,then do with the thread.
* state : the pool's current state.
* total_size : the pool max size;
* current_size : the thread count for the current pool ;
* current_index : the busy thread in the pool index.
*/
typedef struct threadpool_info
{
thread_info_t **list;
pthread_mutex_t mutex_locker;
pthread_cond_t run_locker;
pthread_cond_t full_locker;
pthread_cond_t empty_locker;
thread_state_t state;
int total_size;
int current_size;
int current_index;
}threadpool_info_t;
/*
* initialize the thread pool
* parameters:
* size : thread pool max size
* return:
* 0:initialize pool success;
* -1:the size parameter is less 0;
* -2:initialize pool is fail,malloc memory for pool or pool->list is error;
*/
int threadpool_init(int size);
/*
* run the function with the thread from pool
* parameter:
* func:the thread callback function
* arg:the parameter of callback function
* return:
* 0 : success
* -1: the pool is NULL;
* -2 : malloc memory for thread is error;
* -3 : create thread is error;
*/
int threadpool_run(callback func,void *arg);
/*
* free and destroy the thread pool memory
* return:
* 0 : success
* less 0 : fail
*/
int threadpool_destroy();
#endif /* PTHREAD_POOL_H_ */

508
src/sched_thread.c Normal file
View File

@ -0,0 +1,508 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "sched_thread.h"
#include "shared_func.h"
#include "pthread_func.h"
#include "logger.h"
volatile bool g_schedule_flag = false;
volatile time_t g_current_time = 0;
static ScheduleArray waiting_schedule_array = {NULL, 0};
static int waiting_del_id = -1;
static int sched_cmp_by_next_call_time(const void *p1, const void *p2)
{
return ((ScheduleEntry *)p1)->next_call_time - \
((ScheduleEntry *)p2)->next_call_time;
}
static int sched_init_entries(ScheduleArray *pScheduleArray)
{
ScheduleEntry *pEntry;
ScheduleEntry *pEnd;
time_t time_base;
struct tm tm_current;
struct tm tm_base;
if (pScheduleArray->count < 0)
{
logError("file: "__FILE__", line: %d, " \
"schedule count %d < 0", \
__LINE__, pScheduleArray->count);
return EINVAL;
}
if (pScheduleArray->count == 0)
{
return 0;
}
g_current_time = time(NULL);
localtime_r((time_t *)&g_current_time, &tm_current);
pEnd = pScheduleArray->entries + pScheduleArray->count;
for (pEntry=pScheduleArray->entries; pEntry<pEnd; pEntry++)
{
if (pEntry->interval <= 0)
{
logError("file: "__FILE__", line: %d, " \
"shedule interval %d <= 0", \
__LINE__, pEntry->interval);
return EINVAL;
}
if (pEntry->time_base.hour == TIME_NONE)
{
pEntry->next_call_time = g_current_time + \
pEntry->interval;
}
else
{
if (tm_current.tm_hour > pEntry->time_base.hour || \
(tm_current.tm_hour == pEntry->time_base.hour \
&& tm_current.tm_min >= pEntry->time_base.minute))
{
memcpy(&tm_base, &tm_current, sizeof(struct tm));
}
else
{
time_base = g_current_time - 24 * 3600;
localtime_r(&time_base, &tm_base);
}
tm_base.tm_hour = pEntry->time_base.hour;
tm_base.tm_min = pEntry->time_base.minute;
tm_base.tm_sec = 0;
time_base = mktime(&tm_base);
pEntry->next_call_time = g_current_time + \
pEntry->interval - (g_current_time - \
time_base) % pEntry->interval;
}
/*
{
char buff1[32];
char buff2[32];
logInfo("id=%d, current time=%s, first call time=%s\n", \
pEntry->id, formatDatetime(g_current_time, \
"%Y-%m-%d %H:%M:%S", buff1, sizeof(buff1)), \
formatDatetime(pEntry->next_call_time, \
"%Y-%m-%d %H:%M:%S", buff2, sizeof(buff2)));
}
*/
}
return 0;
}
static void sched_make_chain(ScheduleContext *pContext)
{
ScheduleArray *pScheduleArray;
ScheduleEntry *pEntry;
pScheduleArray = &(pContext->scheduleArray);
if (pScheduleArray->count == 0)
{
pContext->head = NULL;
pContext->tail = NULL;
return;
}
qsort(pScheduleArray->entries, pScheduleArray->count, \
sizeof(ScheduleEntry), sched_cmp_by_next_call_time);
pContext->head = pScheduleArray->entries;
pContext->tail = pScheduleArray->entries + (pScheduleArray->count - 1);
for (pEntry=pScheduleArray->entries; pEntry<pContext->tail; pEntry++)
{
pEntry->next = pEntry + 1;
}
pContext->tail->next = NULL;
}
static int sched_check_waiting(ScheduleContext *pContext)
{
ScheduleArray *pScheduleArray;
ScheduleEntry *newEntries;
ScheduleEntry *pWaitingEntry;
ScheduleEntry *pWaitingEnd;
ScheduleEntry *pSchedEntry;
ScheduleEntry *pSchedEnd;
int allocCount;
int newCount;
int result;
int deleteCount;
pScheduleArray = &(pContext->scheduleArray);
deleteCount = 0;
if (waiting_del_id >= 0)
{
pSchedEnd = pScheduleArray->entries + pScheduleArray->count;
for (pSchedEntry=pScheduleArray->entries; \
pSchedEntry<pSchedEnd; pSchedEntry++)
{
if (pSchedEntry->id == waiting_del_id)
{
break;
}
}
if (pSchedEntry < pSchedEnd)
{
pSchedEntry++;
while (pSchedEntry < pSchedEnd)
{
memcpy(pSchedEntry - 1, pSchedEntry, \
sizeof(ScheduleEntry));
pSchedEntry++;
}
deleteCount++;
pScheduleArray->count--;
logDebug("file: "__FILE__", line: %d, " \
"delete task id: %d, " \
"current schedule count: %d", __LINE__, \
waiting_del_id, pScheduleArray->count);
}
waiting_del_id = -1;
}
if (waiting_schedule_array.count == 0)
{
if (deleteCount > 0)
{
sched_make_chain(pContext);
return 0;
}
return ENOENT;
}
allocCount = pScheduleArray->count + waiting_schedule_array.count;
newEntries = (ScheduleEntry *)malloc(sizeof(ScheduleEntry) * allocCount);
if (newEntries == NULL)
{
result = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes failed, " \
"errno: %d, error info: %s", \
__LINE__, (int)sizeof(ScheduleEntry) * allocCount, \
result, STRERROR(result));
if (deleteCount > 0)
{
sched_make_chain(pContext);
}
return result;
}
if (pScheduleArray->count > 0)
{
memcpy(newEntries, pScheduleArray->entries, \
sizeof(ScheduleEntry) * pScheduleArray->count);
}
newCount = pScheduleArray->count;
pWaitingEnd = waiting_schedule_array.entries + waiting_schedule_array.count;
for (pWaitingEntry=waiting_schedule_array.entries; \
pWaitingEntry<pWaitingEnd; pWaitingEntry++)
{
pSchedEnd = newEntries + newCount;
for (pSchedEntry=newEntries; pSchedEntry<pSchedEnd; \
pSchedEntry++)
{
if (pWaitingEntry->id == pSchedEntry->id)
{
memcpy(pSchedEntry, pWaitingEntry, \
sizeof(ScheduleEntry));
break;
}
}
if (pSchedEntry == pSchedEnd)
{
memcpy(pSchedEntry, pWaitingEntry, \
sizeof(ScheduleEntry));
newCount++;
}
}
logDebug("file: "__FILE__", line: %d, " \
"schedule add entries: %d, replace entries: %d",
__LINE__, newCount - pScheduleArray->count, \
waiting_schedule_array.count - (newCount - pScheduleArray->count));
if (pScheduleArray->entries != NULL)
{
free(pScheduleArray->entries);
}
pScheduleArray->entries = newEntries;
pScheduleArray->count = newCount;
free(waiting_schedule_array.entries);
waiting_schedule_array.count = 0;
waiting_schedule_array.entries = NULL;
sched_make_chain(pContext);
return 0;
}
static void *sched_thread_entrance(void *args)
{
ScheduleContext *pContext;
ScheduleEntry *pPrevious;
ScheduleEntry *pCurrent;
ScheduleEntry *pSaveNext;
ScheduleEntry *pNode;
ScheduleEntry *pUntil;
int exec_count;
int i;
int sleep_time;
pContext = (ScheduleContext *)args;
if (sched_init_entries(&(pContext->scheduleArray)) != 0)
{
free(pContext);
return NULL;
}
sched_make_chain(pContext);
g_schedule_flag = true;
while (*(pContext->pcontinue_flag))
{
sched_check_waiting(pContext);
if (pContext->scheduleArray.count == 0) //no schedule entry
{
sleep(1);
g_current_time = time(NULL);
continue;
}
g_current_time = time(NULL);
sleep_time = pContext->head->next_call_time - g_current_time;
/*
//fprintf(stderr, "count=%d, sleep_time=%d\n", \
pContext->scheduleArray.count, sleep_time);
*/
while (sleep_time > 0 && *(pContext->pcontinue_flag))
{
sleep(1);
g_current_time = time(NULL);
if (sched_check_waiting(pContext) == 0)
{
break;
}
sleep_time--;
}
if (!(*(pContext->pcontinue_flag)))
{
break;
}
exec_count = 0;
pCurrent = pContext->head;
while (*(pContext->pcontinue_flag) && (pCurrent != NULL \
&& pCurrent->next_call_time <= g_current_time))
{
//fprintf(stderr, "exec task id=%d\n", pCurrent->id);
pCurrent->task_func(pCurrent->func_args);
pCurrent->next_call_time = g_current_time + \
pCurrent->interval;
pCurrent = pCurrent->next;
exec_count++;
}
if (exec_count == 0 || pContext->scheduleArray.count == 1)
{
continue;
}
if (exec_count > pContext->scheduleArray.count / 2)
{
sched_make_chain(pContext);
continue;
}
pNode = pContext->head;
pContext->head = pCurrent; //new chain head
for (i=0; i<exec_count; i++)
{
if (pNode->next_call_time >= pContext->tail->next_call_time)
{
pContext->tail->next = pNode;
pContext->tail = pNode;
pNode = pNode->next;
pContext->tail->next = NULL;
continue;
}
pPrevious = NULL;
pUntil = pContext->head;
while (pUntil != NULL && \
pNode->next_call_time > pUntil->next_call_time)
{
pPrevious = pUntil;
pUntil = pUntil->next;
}
pSaveNext = pNode->next;
if (pPrevious == NULL)
{
pContext->head = pNode;
}
else
{
pPrevious->next = pNode;
}
pNode->next = pUntil;
pNode = pSaveNext;
}
}
g_schedule_flag = false;
logDebug("file: "__FILE__", line: %d, " \
"schedule thread exit", __LINE__);
free(pContext);
return NULL;
}
static int sched_dup_array(const ScheduleArray *pSrcArray, \
ScheduleArray *pDestArray)
{
int result;
int bytes;
if (pSrcArray->count == 0)
{
pDestArray->entries = NULL;
pDestArray->count = 0;
return 0;
}
bytes = sizeof(ScheduleEntry) * pSrcArray->count;
pDestArray->entries = (ScheduleEntry *)malloc(bytes);
if (pDestArray->entries == NULL)
{
result = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes failed, " \
"errno: %d, error info: %s", \
__LINE__, bytes, result, STRERROR(result));
return result;
}
memcpy(pDestArray->entries, pSrcArray->entries, bytes);
pDestArray->count = pSrcArray->count;
return 0;
}
int sched_add_entries(const ScheduleArray *pScheduleArray)
{
int result;
if (pScheduleArray->count == 0)
{
logDebug("file: "__FILE__", line: %d, " \
"no schedule entry", __LINE__);
return ENOENT;
}
while (waiting_schedule_array.entries != NULL)
{
logDebug("file: "__FILE__", line: %d, " \
"waiting for schedule array ready ...", __LINE__);
sleep(1);
}
if ((result=sched_dup_array(pScheduleArray, &waiting_schedule_array))!=0)
{
return result;
}
return sched_init_entries(&waiting_schedule_array);
}
int sched_del_entry(const int id)
{
if (id < 0)
{
logError("file: "__FILE__", line: %d, " \
"id: %d is invalid!", __LINE__, id);
return EINVAL;
}
while (waiting_del_id >= 0)
{
logDebug("file: "__FILE__", line: %d, " \
"waiting for delete ready ...", __LINE__);
sleep(1);
}
waiting_del_id = id;
return 0;
}
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid, \
const int stack_size, bool * volatile pcontinue_flag)
{
int result;
pthread_attr_t thread_attr;
ScheduleContext *pContext;
pContext = (ScheduleContext *)malloc(sizeof(ScheduleContext));
if (pContext == NULL)
{
result = errno != 0 ? errno : ENOMEM;
logError("file: "__FILE__", line: %d, " \
"malloc %d bytes failed, " \
"errno: %d, error info: %s", \
__LINE__, (int)sizeof(ScheduleContext), \
result, STRERROR(result));
return result;
}
if ((result=init_pthread_attr(&thread_attr, stack_size)) != 0)
{
free(pContext);
return result;
}
if ((result=sched_dup_array(pScheduleArray, \
&(pContext->scheduleArray))) != 0)
{
free(pContext);
return result;
}
pContext->pcontinue_flag = pcontinue_flag;
if ((result=pthread_create(ptid, &thread_attr, \
sched_thread_entrance, pContext)) != 0)
{
free(pContext);
logError("file: "__FILE__", line: %d, " \
"create thread failed, " \
"errno: %d, error info: %s", \
__LINE__, result, STRERROR(result));
}
pthread_attr_destroy(&thread_attr);
return result;
}

78
src/sched_thread.h Normal file
View File

@ -0,0 +1,78 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#ifndef _SCHED_THREAD_H_
#define _SCHED_THREAD_H_
#include <time.h>
#include "common_define.h"
typedef int (*TaskFunc) (void *args);
typedef struct tagScheduleEntry
{
int id; //the task id
/* the time base to execute task, such as 00:00, interval is 3600,
means execute the task every hour as 1:00, 2:00, 3:00 etc. */
TimeInfo time_base;
int interval; //the interval for execute task, unit is second
TaskFunc task_func; //callback function
void *func_args; //arguments pass to callback function
/* following are internal fields, do not set manually! */
time_t next_call_time;
struct tagScheduleEntry *next;
} ScheduleEntry;
typedef struct
{
ScheduleEntry *entries;
int count;
} ScheduleArray;
typedef struct
{
ScheduleArray scheduleArray;
ScheduleEntry *head; //schedule chain head
ScheduleEntry *tail; //schedule chain tail
bool *pcontinue_flag;
} ScheduleContext;
#ifdef __cplusplus
extern "C" {
#endif
extern volatile bool g_schedule_flag; //schedule continue running flag
extern volatile time_t g_current_time; //the current time
#define get_current_time() (g_schedule_flag ? g_current_time: time(NULL))
int sched_add_entries(const ScheduleArray *pScheduleArray);
int sched_del_entry(const int id);
/** execute the schedule thread
* parameters:
* pScheduleArray: schedule task
* ptid: store the schedule thread id
* stack_size: set thread stack size (byes)
* pcontinue_flag: main process continue running flag
* return: error no, 0 for success, != 0 fail
*/
int sched_start(ScheduleArray *pScheduleArray, pthread_t *ptid, \
const int stack_size, bool * volatile pcontinue_flag);
#ifdef __cplusplus
}
#endif
#endif

2069
src/shared_func.c Normal file

File diff suppressed because it is too large Load Diff

495
src/shared_func.h Normal file
View File

@ -0,0 +1,495 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
#ifndef SHARED_FUNC_H
#define SHARED_FUNC_H
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "common_define.h"
#include "ini_file_reader.h"
#ifdef __cplusplus
extern "C" {
#endif
/** lowercase the string
* parameters:
* src: input string, will be changed
* return: lowercased string
*/
char *toLowercase(char *src);
/** uppercase the string
* parameters:
* src: input string, will be changed
* return: uppercased string
*/
char *toUppercase(char *src);
/** date format to string
* parameters:
* nTime: unix timestamp
* szDateFormat: date format, more detail man strftime
* buff: store the formated result, can be NULL
* buff_size: buffer size, max bytes can contain
* return: formated date string
*/
char *formatDatetime(const time_t nTime, \
const char *szDateFormat, \
char *buff, const int buff_size);
/** get character count, only support GB charset
* parameters:
* s: the string
* return: character count
*/
int getCharLen(const char *s);
/** replace \r and \n to space
* parameters:
* s: the string
* return: replaced string
*/
char *replaceCRLF2Space(char *s);
/** get the filename absolute path
* parameters:
* fileame: the filename
* szAbsPath: store the absolute path
* pathSize: max bytes to contain
* return: absolute path, NULL for fail
*/
char *getAbsolutePath(const char *fileame, char *szAbsPath, \
const int pathSize);
/** get the executable file absolute filename
* parameters:
* exeFilename: the executable filename
* szAbsFilename: store the absolute filename
* maxSize: max bytes to contain
* return: absolute filename, NULL for fail
*/
char *getExeAbsoluteFilename(const char *exeFilename, char *szAbsFilename, \
const int maxSize);
#ifndef WIN32
/** get running process count by program name such as fdfs_trackerd
* parameters:
* progName: the program name
* bAllOwners: false for only get my proccess count
* return: proccess count, >= 0 success, < 0 fail
*/
int getProccessCount(const char *progName, const bool bAllOwners);
/** get running process ids by program name such as fdfs_trackerd
* parameters:
* progName: the program name
* bAllOwners: false for only get my proccess count
* pids: store the pids
* arrSize: max pids
* return: proccess count, >= 0 success, < 0 fail
*/
int getUserProcIds(const char *progName, const bool bAllOwners, \
int pids[], const int arrSize);
/** execute program, get it's output
* parameters:
* command: the program
* output: store ouput result
* buff_size: output max size (bytes)
* return: error no, 0 success, != 0 fail
*/
int getExecResult(const char *command, char *output, const int buff_size);
#endif
/** daemon init
* parameters:
* bCloseFiles: if close the stdin, stdout and stderr
* return: none
*/
void daemon_init(bool bCloseFiles);
/** convert buffer content to hex string such as 0B82A1
* parameters:
* s: the buffer
* len: the buffer length
* szHexBuff: store the hex string (must have enough space)
* return: hex string (szHexBuff)
*/
char *bin2hex(const char *s, const int len, char *szHexBuff);
/** parse hex string to binary content
* parameters:
* s: the hex string such as 8B04CD
* szBinBuff: store the converted binary content(must have enough space)
* nDestLen: store the converted content length
* return: converted binary content (szBinBuff)
*/
char *hex2bin(const char *s, char *szBinBuff, int *nDestLen);
/** print binary buffer as hex string
* parameters:
* s: the buffer
* len: the buffer length
* return: none
*/
void printBuffHex(const char *s, const int len);
/** 32 bits int convert to buffer (big-endian)
* parameters:
* n: 32 bits int value
* buff: the buffer, at least 4 bytes space, no tail \0
* return: none
*/
void int2buff(const int n, char *buff);
/** buffer convert to 32 bits int
* parameters:
* buff: big-endian 4 bytes buffer
* return: 32 bits int value
*/
int buff2int(const char *buff);
/** long (64 bits) convert to buffer (big-endian)
* parameters:
* n: 64 bits int value
* buff: the buffer, at least 8 bytes space, no tail \0
* return: none
*/
void long2buff(int64_t n, char *buff);
/** buffer convert to 64 bits int
* parameters:
* buff: big-endian 8 bytes buffer
* return: 64 bits int value
*/
int64_t buff2long(const char *buff);
/** trim leading spaces ( \t\r\n)
* parameters:
* pStr: the string to trim
* return: trimed string porinter as pStr
*/
char *trim_left(char *pStr);
/** trim tail spaces ( \t\r\n)
* parameters:
* pStr: the string to trim
* return: trimed string porinter as pStr
*/
char *trim_right(char *pStr);
/** trim leading and tail spaces ( \t\r\n)
* parameters:
* pStr: the string to trim
* return: trimed string porinter as pStr
*/
char *trim(char *pStr);
/** copy string to BufferInfo
* parameters:
* pBuff: the dest buffer
* str: source string
* return: error no, 0 success, != 0 fail
*/
int buffer_strcpy(BufferInfo *pBuff, const char *str);
/** copy binary buffer to BufferInfo
* parameters:
* pBuff: the dest buffer
* buff: source buffer
* len: source buffer length
* return: error no, 0 success, != 0 fail
*/
int buffer_memcpy(BufferInfo *pBuff, const char *buff, const int len);
/** url encode
* parameters:
* src: the source string to encode
* src_len: source string length
* dest: store dest string
* dest_len: store the dest string length
* return: error no, 0 success, != 0 fail
*/
char *urlencode(const char *src, const int src_len, char *dest, int *dest_len);
/** url decode
* parameters:
* src: the source string to decode
* src_len: source string length
* dest: store dest string
* dest_len: store the dest string length
* return: error no, 0 success, != 0 fail
*/
char *urldecode(const char *src, const int src_len, char *dest, int *dest_len);
/** get char occurs count
* parameters:
* src: the source string
* seperator: find this char occurs times
* return: char occurs count
*/
int getOccurCount(const char *src, const char seperator);
/** split string
* parameters:
* src: the source string, will be modified by this function
* seperator: seperator char
* nMaxCols: max columns (max split count)
* nColCount: store the columns (array elements) count
* return: string array, should call freeSplit to free, return NULL when fail
*/
char **split(char *src, const char seperator, const int nMaxCols, \
int *nColCount);
/** free split results
* parameters:
* p: return by function split
* return: none
*/
void freeSplit(char **p);
/** split string
* parameters:
* src: the source string, will be modified by this function
* seperator: seperator char
* pCols: store split strings
* nMaxCols: max columns (max split count)
* return: string array / column count
*/
int splitEx(char *src, const char seperator, char **pCols, const int nMaxCols);
/** split string
* parameters:
* src: the source string, will be modified by this function
* seperator: seperator char
* pCols: store split strings
* nMaxCols: max columns (max split count)
* return: string array / column count
*/
int my_strtok(char *src, const char *delim, char **pCols, const int nMaxCols);
/** check file exist
* parameters:
* filename: the filename
* return: true if file exists, otherwise false
*/
bool fileExists(const char *filename);
/** check if a directory
* parameters:
* filename: the filename
* return: true for directory
*/
bool isDir(const char *filename);
/** check if a regular file
* parameters:
* filename: the filename
* return: true for regular file
*/
bool isFile(const char *filename);
/** check if filename securty, /../ ocur in filename not allowed
* parameters:
* filename: the filename
* len: filename length
* return: true for regular file
*/
bool is_filename_secure(const char *filename, const int len);
/** load log_level from config context
* parameters:
* pIniContext: the config context
* return: none
*/
void load_log_level(IniContext *pIniContext);
/** load log_level from config file
* parameters:
* conf_filename: the config filename
* return: none
*/
int load_log_level_ex(const char *conf_filename);
/** set global log level
* parameters:
* pLogLevel: log level string value
* return: none
*/
void set_log_level(char *pLogLevel);
/** load allow hosts from config context
* parameters:
* pIniContext: the config context
* allow_ip_addrs: store allow ip addresses
* allow_ip_count: store allow ip address count
* return: error no , 0 success, != 0 fail
*/
int load_allow_hosts(IniContext *pIniContext, \
in_addr_t **allow_ip_addrs, int *allow_ip_count);
/** get time item from config context
* parameters:
* pIniContext: the config context
* item_name: item name in config file, time format: hour:minute, such as 15:25
* pTimeInfo: store time info
* default_hour: default hour value
* default_minute: default minute value
* return: error no , 0 success, != 0 fail
*/
int get_time_item_from_conf(IniContext *pIniContext, \
const char *item_name, TimeInfo *pTimeInfo, \
const byte default_hour, const byte default_minute);
/** trim path tail char /
* parameters:
* filePath: the file path to chop
* return: none
*/
void chopPath(char *filePath);
/** get file content
* parameters:
* filename: the filename
* buff: return the buff, must be freed
* file_size: store the file size
* return: error no , 0 success, != 0 fail
*/
int getFileContent(const char *filename, char **buff, int64_t *file_size);
/** get file content
* parameters:
* filename: the filename
* buff: the buff to store file content
* offset: the start offset
* size: specify the size to fetch and return the fetched size
* return: error no , 0 success, != 0 fail
*/
int getFileContentEx(const char *filename, char *buff, \
int64_t offset, int64_t *size);
/** write to file
* parameters:
* filename: the filename to write
* buff: the buffer to write
* file_size: the file size
* return: error no , 0 success, != 0 fail
*/
int writeToFile(const char *filename, const char *buff, const int file_size);
/** safe write to file, first write to tmp file, then rename to true filename
* parameters:
* filename: the filename to write
* buff: the buffer to write
* file_size: the file size
* return: error no , 0 success, != 0 fail
*/
int safeWriteToFile(const char *filename, const char *buff, \
const int file_size);
/** get a line from file
* parameters:
* fd: the fd to read
* buff: the buffer to store the line
* size: the buffer max size
* once_bytes: the bytes per read
* return: error no , 0 success, != 0 fail
*/
int fd_gets(int fd, char *buff, const int size, int once_bytes);
/** set unix rlimit
* parameters:
* resource: resource id, please see sys/resource.h
* value: the value to set
* return: error no , 0 success, != 0 fail
*/
int set_rlimit(int resource, const rlim_t value);
/** set non block mode
* parameters:
* fd: the fd to set
* adding_flags: the flags to add
* return: error no , 0 success, != 0 fail
*/
int fd_add_flags(int fd, int adding_flags);
/** set non block mode
* parameters:
* fd: the fd to set
* return: error no , 0 success, != 0 fail
*/
#define set_nonblock(fd) fd_add_flags(fd, O_NONBLOCK)
/** set run by group and user
* parameters:
* group_name: the group name, can be NULL or empty
* username: the username, can be NULL or empty
* return: error no , 0 success, != 0 fail
*/
int set_run_by(const char *group_name, const char *username);
/** compare ip address, type is (in_addr_t *)
* parameters:
* p1: the first ip address
* p2: the second ip address
* return: > 0 when p1 > p2, 0 when p1 == p2, < 0 when p1 < p2
*/
int cmp_by_ip_addr_t(const void *p1, const void *p2);
/** parse bytes
* parameters:
* pStr: the string to parse
* default_unit_bytes: default unit if not specified the unit like MB etc.
* bytes: store the parsed bytes
* return: error no , 0 success, != 0 fail
*/
int parse_bytes(char *pStr, const int default_unit_bytes, int64_t *bytes);
/** set rand seed
* return: error no , 0 success, != 0 fail
*/
int set_rand_seed();
/** set timer wrapper
* parameters:
* first_remain_seconds: remain time for first time, in seconds
* interval: the interval
* sighandler: handler function
* return: error no , 0 success, != 0 fail
*/
int set_timer(const int first_remain_seconds, const int interval, \
void (*sighandler)(int));
/** set file access and modified times
* parameters:
* filename: the file to modify times
* new_time: the time to set
* return: error no , 0 success, != 0 fail
*/
int set_file_utimes(const char *filename, const time_t new_time);
/** ignore singal pipe (SIGPIPE)
* return: error no , 0 success, != 0 fail
*/
int ignore_signal_pipe();
#ifdef __cplusplus
}
#endif
#endif

1744
src/sockopt.c Normal file

File diff suppressed because it is too large Load Diff

335
src/sockopt.h Normal file
View File

@ -0,0 +1,335 @@
/**
* Copyright (C) 2008 Happy Fish / YuQing
*
* FastDFS may be copied only under the terms of the GNU General
* Public License V3, which may be found in the FastDFS source kit.
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//socketopt.h
#ifndef _SOCKETOPT_H_
#define _SOCKETOPT_H_
#include "common_define.h"
#define FDFS_WRITE_BUFF_SIZE 256 * 1024
#ifdef __cplusplus
extern "C" {
#endif
typedef int (*getnamefunc)(int socket, struct sockaddr *address, \
socklen_t *address_len);
typedef int (*tcpsenddatafunc)(int sock, void* data, const int size, \
const int timeout);
typedef int (*tcprecvdata_exfunc)(int sock, void *data, const int size, \
const int timeout, int *count);
#define getSockIpaddr(sock, buff, bufferSize) \
getIpaddr(getsockname, sock, buff, bufferSize)
#define getPeerIpaddr(sock, buff, bufferSize) \
getIpaddr(getpeername, sock, buff, bufferSize)
/** get a line from socket
* parameters:
* sock: the socket
* s: the buffer
* size: buffer size (max bytes can receive)
* timeout: read timeout
* return: error no, 0 success, != 0 fail
*/
int tcpgets(int sock, char *s, const int size, const int timeout);
/** recv data (block mode)
* parameters:
* sock: the socket
* data: the buffer
* size: buffer size (max bytes can receive)
* timeout: read timeout
* count: store the bytes recveived
* return: error no, 0 success, != 0 fail
*/
int tcprecvdata_ex(int sock, void *data, const int size, \
const int timeout, int *count);
/** recv data (non-block mode)
* parameters:
* sock: the socket
* data: the buffer
* size: buffer size (max bytes can receive)
* timeout: read timeout
* count: store the bytes recveived
* return: error no, 0 success, != 0 fail
*/
int tcprecvdata_nb_ex(int sock, void *data, const int size, \
const int timeout, int *count);
/** send data (block mode)
* parameters:
* sock: the socket
* data: the buffer to send
* size: buffer size
* timeout: write timeout
* return: error no, 0 success, != 0 fail
*/
int tcpsenddata(int sock, void* data, const int size, const int timeout);
/** send data (non-block mode)
* parameters:
* sock: the socket
* data: the buffer to send
* size: buffer size
* timeout: write timeout
* return: error no, 0 success, != 0 fail
*/
int tcpsenddata_nb(int sock, void* data, const int size, const int timeout);
/** connect to server by block mode
* parameters:
* sock: the socket
* server_ip: ip address of the server
* server_port: port of the server
* return: error no, 0 success, != 0 fail
*/
int connectserverbyip(int sock, const char *server_ip, const short server_port);
/** connect to server by non-block mode
* parameters:
* sock: the socket
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* auto_detect: if detect and adjust the block mode of the socket
* return: error no, 0 success, != 0 fail
*/
int connectserverbyip_nb_ex(int sock, const char *server_ip, \
const short server_port, const int timeout, \
const bool auto_detect);
/** connect to server by non-block mode, the socket must be set to non-block
* parameters:
* sock: the socket, must be set to non-block
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* return: error no, 0 success, != 0 fail
*/
#define connectserverbyip_nb(sock, server_ip, server_port, timeout) \
connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, false)
/** connect to server by non-block mode, auto detect socket block mode
* parameters:
* sock: the socket, can be block mode
* server_ip: ip address of the server
* server_port: port of the server
* timeout: connect timeout in seconds
* return: error no, 0 success, != 0 fail
*/
#define connectserverbyip_nb_auto(sock, server_ip, server_port, timeout) \
connectserverbyip_nb_ex(sock, server_ip, server_port, timeout, true)
/** accept client connect request
* parameters:
* sock: the server socket
* timeout: read timeout
* err_no: store the error no, 0 for success
* return: client socket, < 0 for error
*/
int nbaccept(int sock, const int timeout, int *err_no);
/** set socket options
* parameters:
* sock: the socket
* timeout: read & write timeout
* return: error no, 0 success, != 0 fail
*/
int tcpsetserveropt(int fd, const int timeout);
/** set socket non-block options
* parameters:
* sock: the socket
* return: error no, 0 success, != 0 fail
*/
int tcpsetnonblockopt(int fd);
/** set socket no delay on send data
* parameters:
* sock: the socket
* timeout: read & write timeout
* return: error no, 0 success, != 0 fail
*/
int tcpsetnodelay(int fd, const int timeout);
/** set socket keep-alive
* parameters:
* sock: the socket
* idleSeconds: max idle time (seconds)
* return: error no, 0 success, != 0 fail
*/
int tcpsetkeepalive(int fd, const int idleSeconds);
/** print keep-alive related parameters
* parameters:
* sock: the socket
* return: error no, 0 success, != 0 fail
*/
int tcpprintkeepalive(int fd);
/** get ip address
* parameters:
* getname: the function name, should be getpeername or getsockname
* sock: the socket
* buff: buffer to store the ip address
* bufferSize: the buffer size (max bytes)
* return: in_addr_t, INADDR_NONE for fail
*/
in_addr_t getIpaddr(getnamefunc getname, int sock, \
char *buff, const int bufferSize);
/** get hostname by it's ip address
* parameters:
* szIpAddr: the ip address
* buff: buffer to store the hostname
* bufferSize: the buffer size (max bytes)
* return: hostname, empty buffer for error
*/
char *getHostnameByIp(const char *szIpAddr, char *buff, const int bufferSize);
/** get by ip address by it's hostname
* parameters:
* name: the hostname
* buff: buffer to store the ip address
* bufferSize: the buffer size (max bytes)
* return: in_addr_t, INADDR_NONE for fail
*/
in_addr_t getIpaddrByName(const char *name, char *buff, const int bufferSize);
/** bind wrapper
* parameters:
* sock: the socket
* bind_ipaddr: the ip address to bind
* port: the port to bind
* return: error no, 0 success, != 0 fail
*/
int socketBind(int sock, const char *bind_ipaddr, const int port);
/** start a socket server (socket, bind and listen)
* parameters:
* sock: the socket
* bind_ipaddr: the ip address to bind
* port: the port to bind
* err_no: store the error no
* return: >= 0 server socket, < 0 fail
*/
int socketServer(const char *bind_ipaddr, const int port, int *err_no);
#define tcprecvdata(sock, data, size, timeout) \
tcprecvdata_ex(sock, data, size, timeout, NULL)
#define tcpsendfile(sock, filename, file_bytes, timeout, total_send_bytes) \
tcpsendfile_ex(sock, filename, 0, file_bytes, timeout, total_send_bytes)
#define tcprecvdata_nb(sock, data, size, timeout) \
tcprecvdata_nb_ex(sock, data, size, timeout, NULL)
/** send a file
* parameters:
* sock: the socket
* filename: the file to send
* file_offset: file offset, start position
* file_bytes: send file length
* timeout: write timeout
* total_send_bytes: store the send bytes
* return: error no, 0 success, != 0 fail
*/
int tcpsendfile_ex(int sock, const char *filename, const int64_t file_offset, \
const int64_t file_bytes, const int timeout, int64_t *total_send_bytes);
/** receive data to a file
* parameters:
* sock: the socket
* filename: the file to write
* file_bytes: file size (bytes)
* fsync_after_written_bytes: call fsync every x bytes
* timeout: read/recv timeout
* true_file_bytes: store the true file bytes
* return: error no, 0 success, != 0 fail
*/
int tcprecvfile(int sock, const char *filename, const int64_t file_bytes, \
const int fsync_after_written_bytes, const int timeout, \
int64_t *true_file_bytes);
#define tcprecvinfinitefile(sock, filename, fsync_after_written_bytes, \
timeout, file_bytes) \
tcprecvfile(sock, filename, INFINITE_FILE_SIZE, \
fsync_after_written_bytes, timeout, file_bytes)
/** receive data to a file
* parameters:
* sock: the socket
* filename: the file to write
* file_bytes: file size (bytes)
* fsync_after_written_bytes: call fsync every x bytes
* hash_codes: return hash code of file content
* timeout: read/recv timeout
* return: error no, 0 success, != 0 fail
*/
int tcprecvfile_ex(int sock, const char *filename, const int64_t file_bytes, \
const int fsync_after_written_bytes, \
unsigned int *hash_codes, const int timeout);
/** receive specified data and discard
* parameters:
* sock: the socket
* bytes: data bytes to discard
* timeout: read timeout
* total_recv_bytes: store the total recv bytes
* return: error no, 0 success, != 0 fail
*/
int tcpdiscard(int sock, const int bytes, const int timeout, \
int64_t *total_recv_bytes);
/** get local host ip addresses
* parameters:
* ip_addrs: store the ip addresses
* max_count: max ip address (max ip_addrs elements)
* count: store the ip address count
* return: error no, 0 success, != 0 fail
*/
int getlocaladdrs(char ip_addrs[][IP_ADDRESS_SIZE], \
const int max_count, int *count);
/** get local host ip addresses
* parameters:
* ip_addrs: store the ip addresses
* max_count: max ip address (max ip_addrs elements)
* count: store the ip address count
* return: error no, 0 success, != 0 fail
*/
int getlocaladdrs1(char ip_addrs[][IP_ADDRESS_SIZE], \
const int max_count, int *count);
/** get local host ip addresses by if alias prefix
* parameters:
* if_alias_prefixes: if alias prefixes, such as eth, bond etc.
* prefix_count: if alias prefix count
* ip_addrs: store the ip addresses
* max_count: max ip address (max ip_addrs elements)
* count: store the ip address count
* return: error no, 0 success, != 0 fail
*/
int gethostaddrs(char **if_alias_prefixes, const int prefix_count, \
char ip_addrs[][IP_ADDRESS_SIZE], const int max_count, int *count);
#ifdef __cplusplus
}
#endif
#endif