Compare commits

...

9 Commits

Author SHA1 Message Date
Hongcai Deng 085dd32b28
Merge a16fde8070 into 79cd21f667 2026-06-28 17:06:33 +08:00
YuQing 79cd21f667 change return type of format_ip_address and format_ip_port 2026-06-26 11:08:50 +08:00
YuQing 1edcae9cf4 add function fc_parse_version 2026-06-25 15:13:06 +08:00
YuQing 724b008b0e fc_version() return combined integer version 2026-06-24 08:21:27 +08:00
YuQing 0ebccb5bf0 INSTALL changed for V1.0.85 2026-06-23 15:59:56 +08:00
YuQing cf40f8e42e add function fc_version 2026-06-23 15:39:50 +08:00
YuQing e5fa72b971 upgrade version to 1.0.85 2026-06-23 11:29:07 +08:00
YuQing 701acb9810 add function seconds_to_human_str 2026-06-22 16:46:18 +08:00
Hongcai Deng a16fde8070 fix: compile error when build .so using .a
```
src/libfastcommon.a(hash.o): relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC
```

env: Ubuntu 14.04, gcc 4.8
2017-01-29 14:20:18 +08:00
14 changed files with 289 additions and 85 deletions

View File

@ -1,6 +1,12 @@
Version 1.85 2026-06-08
Version 1.86 2026-06-26
* add function fc_parse_version
* change return type of format_ip_address and format_ip_port
Version 1.85 2026-06-23
* add functions fc_safe_srand and fc_safe_rand for more security under Linux
* add function seconds_to_human_str
* add function fc_version by new files fc_version.h and fc_version.c
Version 1.84 2026-01-16
* fast_task_queue.h: add function free_queue_task_arg_offset

View File

@ -21,5 +21,5 @@ Debian, Ubuntu etc.:
# the command lines as:
git clone https://github.com/happyfish100/libfastcommon.git
cd libfastcommon; git checkout V1.0.84
cd libfastcommon; git checkout V1.0.85
./make.sh clean && ./make.sh && sudo ./make.sh install

View File

@ -3,7 +3,7 @@
%define CommitVersion %(echo $COMMIT_VERSION)
Name: libfastcommon
Version: 1.0.84
Version: 1.0.85
Release: 1%{?dist}
Summary: c common functions library extracted from my open source projects FastDFS
License: LGPL

View File

@ -23,7 +23,7 @@
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include "common_define.h"
#include "fc_version.h"
#include "local_ip_func.h"
#include "logger.h"
#include "hash.h"
@ -33,10 +33,6 @@
#include "system_info.h"
#include "fastcommon.h"
#define MAJOR_VERSION 1
#define MINOR_VERSION 0
#define PATCH_VERSION 8
#define IDG_FLAGS_EXTRA_DATA_BY_MOD 1
#define PHP_IDG_RESOURCE_NAME "fastcommon_idg"
@ -311,13 +307,13 @@ PHP_RSHUTDOWN_FUNCTION(fastcommon)
PHP_MINFO_FUNCTION(fastcommon)
{
char mc_info[64];
sprintf(mc_info, "fastcommon v%d.%02d support",
MAJOR_VERSION, MINOR_VERSION);
char mc_info[64];
sprintf(mc_info, "fastcommon v%d.%d.%d supported",
FC_MAJOR_VERSION, FC_MINOR_VERSION, FC_PATCH_VERSION);
php_info_print_table_start();
php_info_print_table_header(2, mc_info, "enabled");
php_info_print_table_end();
php_info_print_table_start();
php_info_print_table_header(2, mc_info, "enabled");
php_info_print_table_end();
}
/*
@ -326,13 +322,14 @@ return client library version
*/
ZEND_FUNCTION(fastcommon_version)
{
char szVersion[16];
int len;
Version version;
char szVersion[16];
int len;
len = sprintf(szVersion, "%d.%d.%d",
MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION);
ZEND_RETURN_STRINGL(szVersion, len, 1);
fc_version(&version);
len = sprintf(szVersion, "%d.%d.%d", version.major,
version.minor, version.patch);
ZEND_RETURN_STRINGL(szVersion, len, 1);
}
/*

View File

@ -17,7 +17,8 @@ FAST_SHARED_OBJS = hash.lo chain.lo shared_func.lo ini_file_reader.lo \
multi_socket_client.lo skiplist_set.lo uniq_skiplist.lo \
json_parser.lo buffered_file_writer.lo server_id_func.lo \
fc_queue.lo sorted_queue.lo fc_memory.lo shared_buffer.lo \
thread_pool.lo array_allocator.lo sorted_array.lo spinlock.lo
thread_pool.lo array_allocator.lo sorted_array.lo spinlock.lo \
fc_version.lo
FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
logger.o sockopt.o base64.o sched_thread.o \
@ -31,7 +32,8 @@ FAST_STATIC_OBJS = hash.o chain.o shared_func.o ini_file_reader.o \
multi_socket_client.o skiplist_set.o uniq_skiplist.o \
json_parser.o buffered_file_writer.o server_id_func.o \
fc_queue.o sorted_queue.o fc_memory.o shared_buffer.o \
thread_pool.o array_allocator.o sorted_array.o spinlock.o
thread_pool.o array_allocator.o sorted_array.o spinlock.o \
fc_version.o
HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
shared_func.h pthread_func.h ini_file_reader.h _os_define.h \
@ -47,7 +49,7 @@ HEADER_FILES = common_define.h hash.h chain.h logger.h base64.h \
fc_list.h locked_list.h json_parser.h buffered_file_writer.h \
server_id_func.h fc_queue.h sorted_queue.h fc_memory.h \
shared_buffer.h thread_pool.h fc_atomic.h array_allocator.h \
sorted_array.h spinlock.h
sorted_array.h spinlock.h fc_version.h
ALL_OBJS = $(FAST_STATIC_OBJS) $(FAST_SHARED_OBJS)
@ -66,7 +68,7 @@ libfastcommon.a: $(FAST_STATIC_OBJS)
.c:
$(COMPILE) -o $@ $< $(FAST_STATIC_OBJS) $(LIB_PATH) $(INC_PATH)
.c.o:
$(COMPILE) -c -o $@ $< $(INC_PATH)
$(COMPILE) -c -fPIC -o $@ $< $(INC_PATH)
.c.lo:
$(COMPILE) -c -fPIC -o $@ $< $(INC_PATH)
install:

View File

@ -372,6 +372,16 @@ typedef void* (*MallocFunc)(size_t size);
#define FC_SET_CHAIN_TAIL_NEXT(chain, type, ptr) \
((type *)(chain).tail)->next = ptr
#define FC_VERSION_TO_INT(major, minor, patch) \
(major * 1000 * 1000 + minor * 1000 + patch)
#define FC_VERSION_TO_INT1(version) \
FC_VERSION_TO_INT((version).major, \
(version).minor, (version).patch)
#define FC_COMPARE_INT_VERSIONS_TO_OPERATOR_STR(v1, v2) \
(v1 < v2 ? "<" : (v1 == v2 ? "==" : ">"))
#ifdef WIN32
#define strcasecmp _stricmp
#endif

24
src/fc_version.c Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2026 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "fc_version.h"
int fc_version(Version *version)
{
version->major = FC_MAJOR_VERSION;
version->minor = FC_MINOR_VERSION;
version->patch = FC_PATCH_VERSION;
return FC_VERSION_TO_INT1(*version);
}

40
src/fc_version.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2026 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//fc_version.h
#ifndef _FC_VERSION_H
#define _FC_VERSION_H
#include "common_define.h"
#define FC_MAJOR_VERSION 1
#define FC_MINOR_VERSION 0
#define FC_PATCH_VERSION 85
#define FC_VERSION_INT FC_VERSION_TO_INT(FC_MAJOR_VERSION, \
FC_MINOR_VERSION, FC_PATCH_VERSION)
#ifdef __cplusplus
extern "C" {
#endif
int fc_version(Version *version);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -140,26 +140,27 @@ static int fast_multi_sock_client_do_send(FastMultiSockClient *client,
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else if (errno == EINTR) { //should retry
format_ip_address(entry->conn->ip_addr, formatted_ip);
logDebug("file: "__FILE__", line: %d, "
"server: %s:%u, ignore interupt signal", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port);
formatted_ip, entry->conn->port);
continue;
} else {
result = errno != 0 ? errno : ECONNRESET;
format_ip_address(entry->conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"send to server %s:%u fail, "
"errno: %d, error info: %s", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, result, strerror(result));
formatted_ip, entry->conn->port,
result, strerror(result));
break;
}
} else if (bytes == 0) {
format_ip_address(entry->conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"send to server %s:%u, sock: %d fail, "
"connection disconnected", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
"connection disconnected", __LINE__, formatted_ip,
entry->conn->port, entry->conn->sock);
result = ECONNRESET;
@ -203,10 +204,10 @@ static int fast_multi_sock_client_send_data(FastMultiSockClient *client,
if (client->entries[i].conn->sock < 0) {
client->entries[i].error_no = ENOTCONN;
client->entries[i].done = true;
format_ip_address(client->entries[i].conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"NOT connected to %s:%u", __LINE__,
format_ip_address(client->entries[i].conn->ip_addr,
formatted_ip), client->entries[i].conn->port);
formatted_ip, client->entries[i].conn->port);
continue;
}
@ -256,26 +257,27 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
if (errno == EAGAIN || errno == EWOULDBLOCK) {
break;
} else if (errno == EINTR) { //should retry
format_ip_address(entry->conn->ip_addr, formatted_ip);
logDebug("file: "__FILE__", line: %d, "
"server: %s:%u, ignore interupt signal", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port);
formatted_ip, entry->conn->port);
continue;
} else {
result = errno != 0 ? errno : ECONNRESET;
format_ip_address(entry->conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"server: %s:%u, recv failed, "
"errno: %d, error info: %s", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, result, strerror(result));
formatted_ip, entry->conn->port,
result, strerror(result));
break;
}
} else if (bytes == 0) {
format_ip_address(entry->conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"server: %s:%u, sock: %d, recv failed, "
"connection disconnected", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
"connection disconnected", __LINE__, formatted_ip,
entry->conn->port, entry->conn->sock);
result = ECONNRESET;
@ -290,10 +292,10 @@ static int fast_multi_sock_client_do_recv(FastMultiSockClient *client,
entry->recv_stage = fms_stage_recv_body;
body_length = client->get_body_length_func(&entry->recv_buffer);
if (body_length < 0) {
format_ip_address(entry->conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"server: %s:%u, body_length: %d < 0", __LINE__,
format_ip_address(entry->conn->ip_addr, formatted_ip),
entry->conn->port, body_length);
formatted_ip, entry->conn->port, body_length);
result = EPIPE;
break;
} else if (body_length == 0) {
@ -374,10 +376,10 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
&client->ioevent, index);
if (event & IOEVENT_ERROR) {
format_ip_address(entry->conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"server: %s:%u, recv error event: %d, connection "
"reset", __LINE__, format_ip_address(entry->conn->
ip_addr, formatted_ip), entry->conn->port, event);
"server: %s:%u, recv error event: %d, connection reset",
__LINE__, formatted_ip, entry->conn->port, event);
fast_multi_sock_client_finish(client, entry, ECONNRESET);
continue;
@ -404,10 +406,10 @@ static int fast_multi_sock_client_deal_io(FastMultiSockClient *client)
if (!client->entries[i].done) {
fast_multi_sock_client_finish(client,
client->entries + i, ETIMEDOUT);
format_ip_address(client->entries[i].conn->ip_addr, formatted_ip);
logError("file: "__FILE__", line: %d, "
"recv from %s:%u timedout", __LINE__,
format_ip_address(client->entries[i].conn->ip_addr,
formatted_ip), client->entries[i].conn->port);
formatted_ip, client->entries[i].conn->port);
}
}
}

View File

@ -259,11 +259,11 @@ static int fc_server_check_ip_port(FCServerConfig *ctx,
id1 = current->server->id;
id2 = previous->server->id;
}
format_ip_address(previous->ip_addr.str, formatted_ip);
logError("file: "__FILE__", line: %d, "
"config file: %s, duplicate ip:port %s:%u, "
"the server ids: %d, %d", __LINE__,
config_filename, format_ip_address(previous->ip_addr.str,
formatted_ip), previous->port, id1, id2);
"the server ids: %d, %d", __LINE__, config_filename,
formatted_ip, previous->port, id1, id2);
return EEXIST;
}
@ -714,14 +714,14 @@ static int check_addresses_duplicate(FCServerConfig *ctx,
ppend = group_addr->address_array.addrs + group_addr->address_array.count;
for (ppaddr=group_addr->address_array.addrs+1; ppaddr<ppend; ppaddr++) {
if (fc_server_cmp_address_ptr(ppaddr, pprevious) == 0) {
format_ip_address((*ppaddr)->conn.ip_addr, formatted_ip),
logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, group: %.*s, "
"duplicate ip and port: %s:%u", __LINE__,
config_filename, section_name,
group_addr->server_group->group_name.len,
group_addr->server_group->group_name.str,
format_ip_address((*ppaddr)->conn.ip_addr, formatted_ip),
(*ppaddr)->conn.port);
formatted_ip, (*ppaddr)->conn.port);
return EEXIST;
}
pprevious = ppaddr;
@ -967,12 +967,12 @@ static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
}
if (!ctx->share_between_groups && (count > 1 && addr->conn.port > 0)) {
format_ip_address(addr->conn.ip_addr, formatted_ip),
logError("file: "__FILE__", line: %d, "
"config filename: %s, section: %s, "
"host %s:%u belongs to %d groups",
__LINE__, config_filename, section_name,
format_ip_address(addr->conn.ip_addr, formatted_ip),
addr->conn.port, count);
formatted_ip, addr->conn.port, count);
return EEXIST;
}
@ -1544,9 +1544,10 @@ static void fc_group_servers_to_string(FCServerConfig *ctx,
gaddr->server_group->group_name.str,
SERVER_ITEM_HOST_AFFIX_STR);
}
format_ip_address((*addr)->conn.ip_addr, formatted_ip),
fast_buffer_append(buffer, " = %s:%u\n",
format_ip_address((*addr)->conn.ip_addr, formatted_ip),
(*addr)->conn.port);
formatted_ip, (*addr)->conn.port);
}
}
@ -1655,9 +1656,9 @@ static void fc_server_log_group_servers(FCGroupAddresses *gaddr)
end = gaddr->address_array.addrs + gaddr->address_array.count;
for (addr=gaddr->address_array.addrs; addr<end; addr++) {
format_ip_address((*addr)->conn.ip_addr, formatted_ip),
logInfo(" %d. %s:%u", (int)(addr - gaddr->address_array.addrs + 1),
format_ip_address((*addr)->conn.ip_addr, formatted_ip),
(*addr)->conn.port);
formatted_ip, (*addr)->conn.port);
}
}

View File

@ -3353,6 +3353,117 @@ const char *bytes_to_human_str(const int64_t bytes, char *buff)
return buff;
}
static int format_number_with_unit(const int n, const char *unit_str,
const int unit_len, char *buff, const bool add_leading_space)
{
char *p;
if (n <= 0)
{
return 0;
}
p = buff;
if (add_leading_space)
{
*p++ = ' ';
}
if (n == 1)
{
*p++ = '1';
*p++ = ' ';
memcpy(p, unit_str, unit_len);
p += unit_len;
}
else
{
p += fc_itoa(n, p);
*p++ = ' ';
memcpy(p, unit_str, unit_len);
p += unit_len;
*p++ = 's';
}
return p - buff;
}
static inline int format_number_unit_first(const int n, const char *unit_str,
const int unit_len, char *buff)
{
const bool add_leading_space = false;
return format_number_with_unit(n, unit_str,
unit_len, buff, add_leading_space);
}
static inline int format_number_unit_next(const int n, const char *unit_str,
const int unit_len, char *buff)
{
const bool add_leading_space = true;
return format_number_with_unit(n, unit_str,
unit_len, buff, add_leading_space);
}
const char *seconds_to_human_str(const int64_t seconds, char *buff)
{
int64_t remains;
int day;
int hour;
int minute;
int second;
char *p;
if (seconds > 0)
{
remains = seconds;
}
else
{
remains = 0;
}
day = remains / (24 * 3600);
remains %= (24 * 3600);
hour = remains / 3600;
remains %= 3600;
minute = remains / 60;
second = remains % 60;
p = buff;
if (day > 0)
{
p += format_number_unit_first(day, "day", 3, p);
p += format_number_unit_next(hour, "hour", 4, p);
p += format_number_unit_next(minute, "minute", 6, p);
p += format_number_unit_next(second, "second", 6, p);
}
else if (hour > 0)
{
p += format_number_unit_first(hour, "hour", 4, p);
p += format_number_unit_next(minute, "minute", 6, p);
p += format_number_unit_next(second, "second", 6, p);
}
else if (minute > 0)
{
p += format_number_unit_first(minute, "minute", 6, p);
p += format_number_unit_next(second, "second", 6, p);
}
else if (second > 0)
{
p += format_number_unit_first(second, "second", 6, p);
}
else
{
*p++ = '0';
*p++ = ' ';
memcpy(p, "second", 6);
p += 6;
}
*p = '\0';
return buff;
}
bool starts_with(const char *str, const char *needle)
{
int str_len;
@ -4580,3 +4691,27 @@ int fc_safe_rand()
return (n & RAND_MAX);
}
#endif
int fc_parse_version(const char *src, Version *version)
{
const char *p;
int numbers[2];
int i;
numbers[0] = numbers[1] = 0;
p = src;
for (i=0; i<2; i++) {
p = strchr(p, '.');
if (p == NULL) {
break;
}
p++;
numbers[i] = strtol(p, NULL, 10);
}
version->major = strtol(src, NULL, 10);
version->minor = numbers[0];
version->patch = numbers[1];
return FC_VERSION_TO_INT1(*version);
}

View File

@ -1210,6 +1210,8 @@ static inline const char *double_to_comma_str(const double d,
const char *bytes_to_human_str(const int64_t bytes, char *buff);
const char *seconds_to_human_str(const int64_t seconds, char *buff);
/** if the string starts with the needle string
* parameters:
* str: the string to detect
@ -1875,6 +1877,8 @@ int fc_safe_rand();
#define fc_safe_rand() rand()
#endif
int fc_parse_version(const char *src, Version *version);
#ifdef __cplusplus
}
#endif

View File

@ -706,11 +706,11 @@ static inline bool is_ipv6_addr(const char *ip)
return (*ip == ':' || strchr(ip, ':') != NULL); //ipv6
}
static inline const char *format_ip_address(const char *ip, char *buff)
static inline int format_ip_address(const char *ip, char *buff)
{
int ip_len;
if (is_ipv6_addr(ip))
{
int ip_len;
char *p;
ip_len = strlen(ip);
@ -720,17 +720,17 @@ static inline const char *format_ip_address(const char *ip, char *buff)
p += ip_len;
*p++ = ']';
*p = '\0';
return p - buff;
}
else
{
strcpy(buff, ip);
ip_len = strlen(ip);
memcpy(buff, ip, ip_len + 1);
return ip_len;
}
return buff;
}
static inline const char *format_ip_port(const char *ip,
const int port, char *buff)
static inline int format_ip_port(const char *ip, const int port, char *buff)
{
int ip_len;
bool is_ipv6;
@ -753,7 +753,7 @@ static inline const char *format_ip_port(const char *ip,
p += fc_itoa(port, p);
*p = '\0';
return buff;
return p - buff;
}
void tcp_set_try_again_when_interrupt(const bool value);

View File

@ -960,33 +960,16 @@ int get_sysinfo(struct fast_sysinfo *info)
int get_kernel_version(Version *version)
{
struct utsname name;
char *p;
int numbers[2];
int i;
if (uname(&name) < 0)
{
logError("file: "__FILE__", line: %d, "
"call uname fail, errno: %d, error info: %s",
__LINE__, errno, STRERROR(errno));
logError("file: "__FILE__", line: %d, "
"call uname fail, errno: %d, error info: %s",
__LINE__, errno, STRERROR(errno));
return errno != 0 ? errno : EFAULT;
}
numbers[0] = numbers[1] = 0;
p = name.release;
for (i=0; i<2; i++) {
p = strchr(p, '.');
if (p == NULL) {
break;
}
p++;
numbers[i] = strtol(p, NULL, 10);
}
version->major = strtol(name.release, NULL, 10);
version->minor = numbers[0];
version->patch = numbers[1];
fc_parse_version(name.release, version);
return 0;
}