1816 lines
56 KiB
C
1816 lines
56 KiB
C
/*
|
|
* Copyright (c) 2020 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 <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <netdb.h>
|
|
#include "logger.h"
|
|
#include "shared_func.h"
|
|
#include "sockopt.h"
|
|
#include "server_id_func.h"
|
|
|
|
#define GROUP_SECTION_PREFIX_STR "group-"
|
|
#define GROUP_SECTION_PREFIX_LEN (sizeof(GROUP_SECTION_PREFIX_STR) - 1)
|
|
|
|
#define SERVER_SECTION_PREFIX_STR "server-"
|
|
#define SERVER_SECTION_PREFIX_LEN (sizeof(SERVER_SECTION_PREFIX_STR) - 1)
|
|
|
|
#define SERVER_ITEM_PORT_STR "port"
|
|
#define SERVER_ITEM_PORT_LEN (sizeof(SERVER_ITEM_PORT_STR) - 1)
|
|
|
|
#define SERVER_ITEM_HOST_STR "host"
|
|
#define SERVER_ITEM_HOST_LEN (sizeof(SERVER_ITEM_HOST_STR) - 1)
|
|
|
|
#define SERVER_ITEM_HOST_AFFIX_STR "-host"
|
|
#define SERVER_ITEM_HOST_AFFIX_LEN (sizeof(SERVER_ITEM_HOST_AFFIX_STR) - 1)
|
|
|
|
#define SERVER_ITEM_PORT_AFFIX_STR "-port"
|
|
#define SERVER_ITEM_PORT_AFFIX_LEN (sizeof(SERVER_ITEM_PORT_AFFIX_STR) - 1)
|
|
|
|
#define IP_PORT_MAP_COUNT(ctx) ctx->sorted_server_arrays.by_ip_port.count
|
|
#define IP_PORT_MAPS(ctx) ctx->sorted_server_arrays.by_ip_port.maps
|
|
|
|
#define FC_SERVER_GROUP_PORT(group) \
|
|
(group->server_port > 0 ? group->server_port : group->port)
|
|
|
|
static int fc_server_cmp_server_id(const void *p1, const void *p2)
|
|
{
|
|
return ((FCServerInfo *)p1)->id - ((FCServerInfo *)p2)->id;
|
|
}
|
|
|
|
static int fc_server_cmp_ip_and_port(const void *p1, const void *p2)
|
|
{
|
|
FCServerMap *m1;
|
|
FCServerMap *m2;
|
|
int result;
|
|
int sub;
|
|
int min;
|
|
|
|
m1 = (FCServerMap *)p1;
|
|
m2 = (FCServerMap *)p2;
|
|
|
|
sub = m1->ip_addr.len - m2->ip_addr.len;
|
|
if (sub < 0) {
|
|
min = m1->ip_addr.len;
|
|
} else {
|
|
min = m2->ip_addr.len;
|
|
}
|
|
|
|
if (min > 0) {
|
|
result = memcmp(m1->ip_addr.str, m2->ip_addr.str, min);
|
|
if (result != 0) {
|
|
return result;
|
|
}
|
|
}
|
|
if (sub != 0) {
|
|
return sub;
|
|
}
|
|
|
|
return m1->port - m2->port;
|
|
}
|
|
|
|
static int fc_server_cmp_address_ptr(const void *p1, const void *p2)
|
|
{
|
|
FCAddressInfo **addr1;
|
|
FCAddressInfo **addr2;
|
|
int result;
|
|
|
|
addr1 = (FCAddressInfo **)p1;
|
|
addr2 = (FCAddressInfo **)p2;
|
|
if ((result=strcmp((*addr1)->conn.ip_addr, (*addr2)->conn.ip_addr)) != 0) {
|
|
return result;
|
|
}
|
|
return (*addr1)->conn.port - (*addr2)->conn.port;
|
|
}
|
|
|
|
FCServerInfo *fc_server_get_by_id(FCServerConfig *ctx,
|
|
const int server_id)
|
|
{
|
|
FCServerInfo target;
|
|
|
|
target.id = server_id;
|
|
return (FCServerInfo *)bsearch(&target, FC_SID_SERVERS(*ctx),
|
|
FC_SID_SERVER_COUNT(*ctx), sizeof(FCServerInfo),
|
|
fc_server_cmp_server_id);
|
|
}
|
|
|
|
static int fc_server_calc_ip_port_count(FCServerConfig *ctx)
|
|
{
|
|
FCServerInfo *server;
|
|
FCServerInfo *send;
|
|
int count;
|
|
|
|
count = 0;
|
|
send = FC_SID_SERVERS(*ctx) + FC_SID_SERVER_COUNT(*ctx);
|
|
for (server=FC_SID_SERVERS(*ctx); server<send; server++) {
|
|
count += server->uniq_addresses.count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static int fc_server_check_alloc_group_addresses(FCAddressPtrArray *array)
|
|
{
|
|
int new_alloc;
|
|
int bytes;
|
|
FCAddressInfo **new_addrs;
|
|
|
|
if (array->count < array->alloc) {
|
|
return 0;
|
|
}
|
|
|
|
new_alloc = array->alloc > 0 ? 2 * array->alloc : 2;
|
|
bytes = sizeof(FCAddressInfo *) * new_alloc;
|
|
new_addrs = (FCAddressInfo **)fc_malloc(bytes);
|
|
if (new_addrs == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
memset(new_addrs, 0, bytes);
|
|
|
|
if (array->addrs != NULL) {
|
|
memcpy(new_addrs, array->addrs, sizeof(FCAddressInfo *) * array->count);
|
|
free(array->addrs);
|
|
}
|
|
|
|
array->addrs = new_addrs;
|
|
array->alloc = new_alloc;
|
|
return 0;
|
|
}
|
|
|
|
static FCAddressInfo *fc_server_add_to_uniq_addresses(
|
|
FCAddressPtrArray *addr_ptr_array, const FCAddressInfo *addr)
|
|
{
|
|
FCAddressInfo *p;
|
|
FCAddressInfo **pp;
|
|
FCAddressInfo **end;
|
|
|
|
end = addr_ptr_array->addrs + addr_ptr_array->count;
|
|
for (pp=addr_ptr_array->addrs; pp<end; pp++) {
|
|
if (FC_CONNECTION_SERVER_EQUAL1(addr->conn, (*pp)->conn)) {
|
|
return *pp;
|
|
}
|
|
}
|
|
|
|
if (fc_server_check_alloc_group_addresses(addr_ptr_array) != 0) {
|
|
return NULL;
|
|
}
|
|
p = (FCAddressInfo *)fc_malloc(sizeof(FCAddressInfo));
|
|
if (p == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
*p = *addr;
|
|
addr_ptr_array->addrs[addr_ptr_array->count++] = p;
|
|
return p;
|
|
}
|
|
|
|
static int fc_server_init_ip_port_array(FCServerConfig *ctx)
|
|
{
|
|
int count;
|
|
int bytes;
|
|
FCServerMapArray *map_array;
|
|
FCServerMap *map;
|
|
FCServerInfo *server;
|
|
FCServerInfo *send;
|
|
FCAddressInfo **paddr;
|
|
FCAddressInfo **pend;
|
|
|
|
map_array = &ctx->sorted_server_arrays.by_ip_port;
|
|
|
|
count = fc_server_calc_ip_port_count(ctx);
|
|
bytes = sizeof(FCServerMap) * count;
|
|
map_array->maps = (FCServerMap *)fc_malloc(bytes);
|
|
if (map_array->maps == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
memset(map_array->maps, 0, bytes);
|
|
|
|
send = FC_SID_SERVERS(*ctx) + FC_SID_SERVER_COUNT(*ctx);
|
|
map = map_array->maps;
|
|
for (server=FC_SID_SERVERS(*ctx); server<send; server++) {
|
|
pend = server->uniq_addresses.addrs + server->uniq_addresses.count;
|
|
for (paddr=server->uniq_addresses.addrs; paddr<pend; paddr++) {
|
|
map->server = server;
|
|
FC_SET_STRING(map->ip_addr, (*paddr)->conn.ip_addr);
|
|
map->port = (*paddr)->conn.port;
|
|
map++;
|
|
}
|
|
}
|
|
|
|
map_array->count = map - map_array->maps;
|
|
qsort(map_array->maps, map_array->count, sizeof(FCServerMap),
|
|
fc_server_cmp_ip_and_port);
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_check_id_duplicated(FCServerConfig *ctx,
|
|
const char *config_filename)
|
|
{
|
|
FCServerInfo *previous;
|
|
FCServerInfo *current;
|
|
FCServerInfo *send;
|
|
|
|
previous = FC_SID_SERVERS(*ctx) + 0;
|
|
send = FC_SID_SERVERS(*ctx) + FC_SID_SERVER_COUNT(*ctx);
|
|
for (current=FC_SID_SERVERS(*ctx) + 1; current<send; current++) {
|
|
if (current->id == previous->id) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config file: %s, duplicate server id: %d",
|
|
__LINE__, config_filename, current->id);
|
|
return EEXIST;
|
|
}
|
|
previous = current;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_check_ip_port(FCServerConfig *ctx,
|
|
const char *config_filename)
|
|
{
|
|
FCServerMap *previous;
|
|
FCServerMap *current;
|
|
FCServerMap *end;
|
|
char formatted_ip[FORMATTED_IP_SIZE];
|
|
int id1;
|
|
int id2;
|
|
|
|
previous = IP_PORT_MAPS(ctx) + 0;
|
|
end = IP_PORT_MAPS(ctx) + IP_PORT_MAP_COUNT(ctx);
|
|
for (current=IP_PORT_MAPS(ctx)+1; current<end; current++) {
|
|
if (fc_server_cmp_ip_and_port(current, previous) == 0) {
|
|
if (previous->server->id < current->server->id) {
|
|
id1 = previous->server->id;
|
|
id2 = current->server->id;
|
|
} else {
|
|
id1 = current->server->id;
|
|
id2 = previous->server->id;
|
|
}
|
|
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);
|
|
return EEXIST;
|
|
}
|
|
|
|
previous = current;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
FCServerInfo *fc_server_get_by_ip_port_ex(FCServerConfig *ctx,
|
|
const string_t *ip_addr, const int port)
|
|
{
|
|
FCServerMap target;
|
|
FCServerMap *found;
|
|
|
|
target.ip_addr = *ip_addr;
|
|
target.port = port;
|
|
found = (FCServerMap *)bsearch(&target, IP_PORT_MAPS(ctx),
|
|
IP_PORT_MAP_COUNT(ctx), sizeof(FCServerMap),
|
|
fc_server_cmp_ip_and_port);
|
|
if (found != NULL) {
|
|
return found->server;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static inline void fc_server_set_group_ptr_name(FCServerGroupInfo *ginfo,
|
|
const char *group_name)
|
|
{
|
|
ginfo->group_name.str = ginfo->name_buff;
|
|
ginfo->group_name.len = snprintf(ginfo->name_buff,
|
|
sizeof(ginfo->name_buff) - 1, "%s", group_name);
|
|
if (ginfo->group_name.len == 0) {
|
|
return;
|
|
}
|
|
|
|
fc_trim(ginfo->group_name.str);
|
|
ginfo->group_name.len = strlen(ginfo->group_name.str);
|
|
}
|
|
|
|
static inline void fc_server_set_ip_prefix(FCServerGroupInfo *ginfo,
|
|
const char *ip_prefix)
|
|
{
|
|
ginfo->filter.ip_prefix.str = ginfo->filter.prefix_buff;
|
|
if (ip_prefix != NULL) {
|
|
ginfo->filter.ip_prefix.len = snprintf(ginfo->filter.prefix_buff,
|
|
sizeof(ginfo->filter.prefix_buff) - 1, "%s", ip_prefix);
|
|
}
|
|
}
|
|
|
|
static inline int fc_server_set_comm_type(FCCommunicationType *comm_type,
|
|
const char *config_filename, const char *section_name,
|
|
const char *comm_type_str, const FCCommunicationType default_comm_type)
|
|
{
|
|
if (comm_type_str == NULL) {
|
|
*comm_type = default_comm_type;
|
|
return 0;
|
|
} else if (strcasecmp(comm_type_str, "socket") == 0) {
|
|
*comm_type = fc_comm_type_sock;
|
|
return 0;
|
|
} else if (strcasecmp(comm_type_str, "rdma") == 0) {
|
|
*comm_type = fc_comm_type_rdma;
|
|
return 0;
|
|
} else {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, "
|
|
"invalid communication: %s!", __LINE__,
|
|
config_filename, section_name, comm_type_str);
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
static int load_comm_type_and_smart_polling(IniFullContext *ini_ctx,
|
|
FCCommunicationType *comm_type, FCSmartPollingConfig *smart_polling,
|
|
const FCCommunicationType default_comm_type,
|
|
const FCSmartPollingConfig *default_smart_polling)
|
|
{
|
|
int result;
|
|
char *comm_type_str;
|
|
|
|
comm_type_str = iniGetStrValue(ini_ctx->section_name,
|
|
"communication", ini_ctx->context);
|
|
if (comm_type_str == NULL) {
|
|
comm_type_str = iniGetStrValue(ini_ctx->section_name,
|
|
"comm_type", ini_ctx->context);
|
|
}
|
|
if ((result=fc_server_set_comm_type(comm_type, ini_ctx->filename,
|
|
ini_ctx->section_name, comm_type_str,
|
|
default_comm_type)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (*comm_type == fc_comm_type_sock) {
|
|
smart_polling->enabled = false;
|
|
smart_polling->switch_on_iops = 0;
|
|
smart_polling->switch_on_count = 0;
|
|
} else {
|
|
smart_polling->enabled = iniGetBoolValue(ini_ctx->section_name,
|
|
"smart_polling", ini_ctx->context,
|
|
default_smart_polling->enabled);
|
|
smart_polling->switch_on_iops = iniGetIntValue(ini_ctx->section_name,
|
|
"polling_switch_on_iops", ini_ctx->context,
|
|
default_smart_polling->switch_on_iops);
|
|
smart_polling->switch_on_count = iniGetIntValue(ini_ctx->section_name,
|
|
"polling_switch_on_count", ini_ctx->context,
|
|
default_smart_polling->switch_on_count);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline int load_buffer_size(IniFullContext *ini_ctx,
|
|
const int default_buffer_size)
|
|
{
|
|
int buffer_size;
|
|
buffer_size = iniGetByteValue(ini_ctx->section_name, "buffer_size",
|
|
ini_ctx->context, default_buffer_size);
|
|
return iniCheckAndCorrectIntValue(ini_ctx, "buffer_size",
|
|
buffer_size, 8 * 1024, 8 * 1024 * 1024);
|
|
}
|
|
|
|
static int fc_server_load_one_group(FCServerConfig *ctx,
|
|
IniFullContext *ini_ctx, const int group_count)
|
|
{
|
|
int result;
|
|
FCServerGroupInfo *group;
|
|
char new_name[FAST_INI_ITEM_NAME_SIZE];
|
|
char *port_str;
|
|
char *net_type;
|
|
char *ip_prefix;
|
|
|
|
strcpy(new_name, ini_ctx->section_name);
|
|
group = ctx->group_array.groups + ctx->group_array.count;
|
|
fc_server_set_group_ptr_name(group, new_name + GROUP_SECTION_PREFIX_LEN);
|
|
if (group->group_name.len == 0) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, no group name!",
|
|
__LINE__, ini_ctx->filename, ini_ctx->section_name);
|
|
return EINVAL;
|
|
}
|
|
|
|
port_str = iniGetStrValue(ini_ctx->section_name,
|
|
SERVER_ITEM_PORT_STR, ini_ctx->context);
|
|
if (port_str == NULL) {
|
|
if (group_count == 1) {
|
|
group->port = ctx->default_port;
|
|
} else {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, no item: %s!",
|
|
__LINE__, ini_ctx->filename, ini_ctx->section_name,
|
|
SERVER_ITEM_PORT_STR);
|
|
return ENOENT;
|
|
}
|
|
} else {
|
|
char *endptr = NULL;
|
|
group->port = strtol(port_str, &endptr, 10);
|
|
if (group->port <= 0 || (endptr != NULL && *endptr != '\0')) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, item: %s, "
|
|
"invalid port: %s", __LINE__, ini_ctx->filename,
|
|
ini_ctx->section_name, SERVER_ITEM_PORT_STR, port_str);
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
net_type = iniGetStrValue(ini_ctx->section_name,
|
|
"net_type", ini_ctx->context);
|
|
group->filter.net_type = fc_get_net_type_by_name(net_type);
|
|
if (group->filter.net_type == FC_NET_TYPE_NONE) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, invalid net_type: %s",
|
|
__LINE__, ini_ctx->filename, group->group_name.str, net_type);
|
|
return EINVAL;
|
|
}
|
|
|
|
ip_prefix = iniGetStrValue(ini_ctx->section_name,
|
|
"ip_prefix", ini_ctx->context);
|
|
fc_server_set_ip_prefix(group, ip_prefix);
|
|
|
|
if ((result=load_comm_type_and_smart_polling(ini_ctx,
|
|
&group->comm_type, &group->smart_polling,
|
|
ctx->comm_type, &ctx->smart_polling)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (group->comm_type == fc_comm_type_sock) {
|
|
group->buffer_size = 0;
|
|
} else {
|
|
group->buffer_size = load_buffer_size(ini_ctx, ctx->buffer_size);
|
|
}
|
|
|
|
ctx->group_array.count++;
|
|
return 0;
|
|
}
|
|
|
|
static int check_group_ports_duplicate(FCServerConfig *ctx,
|
|
const char *config_filename)
|
|
{
|
|
FCServerGroupInfo *g1;
|
|
FCServerGroupInfo *g2;
|
|
FCServerGroupInfo *end;
|
|
int port1;
|
|
int port2;
|
|
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (g1=ctx->group_array.groups; g1<end; g1++) {
|
|
port1 = FC_SERVER_GROUP_PORT(g1);
|
|
for (g2=g1+1; g2<end; g2++) {
|
|
port2 = FC_SERVER_GROUP_PORT(g2);
|
|
if (port1 == port2) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, the port: %d of group: %.*s "
|
|
"is same to group: %.*s", __LINE__, config_filename,
|
|
port1, g1->group_name.len, g1->group_name.str,
|
|
g2->group_name.len, g2->group_name.str);
|
|
return EEXIST;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_cmp_group_info(const void *p1, const void *p2)
|
|
{
|
|
return strcmp(((FCServerGroupInfo *)p1)->name_buff,
|
|
((FCServerGroupInfo *)p2)->name_buff);
|
|
}
|
|
|
|
static void fc_server_sort_groups(FCServerConfig *ctx)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
|
|
if (ctx->group_array.count <= 1) {
|
|
return;
|
|
}
|
|
|
|
qsort(ctx->group_array.groups, ctx->group_array.count,
|
|
sizeof(FCServerGroupInfo), fc_server_cmp_group_info);
|
|
|
|
//must reset stirng_t pointer
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (group=ctx->group_array.groups; group<end; group++) {
|
|
group->group_name.str = group->name_buff;
|
|
group->filter.ip_prefix.str = group->filter.prefix_buff;
|
|
}
|
|
}
|
|
|
|
static int fc_server_load_groups(FCServerConfig *ctx,
|
|
IniFullContext *ini_ctx)
|
|
{
|
|
int result;
|
|
int count;
|
|
IniSectionInfo sections[FC_MAX_GROUP_COUNT];
|
|
IniSectionInfo *section;
|
|
IniSectionInfo *end;
|
|
|
|
if ((result=iniGetSectionNamesByPrefix(ini_ctx->context,
|
|
GROUP_SECTION_PREFIX_STR, sections,
|
|
FC_MAX_GROUP_COUNT, &count)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, get sections by prefix %s fail, "
|
|
"errno: %d, error info: %s", __LINE__, ini_ctx->filename,
|
|
GROUP_SECTION_PREFIX_STR, result, STRERROR(result));
|
|
return result;
|
|
}
|
|
|
|
if (count == 0) {
|
|
ctx->group_array.count = 1;
|
|
memset(ctx->group_array.groups, 0, sizeof(FCServerGroupInfo));
|
|
fc_server_set_group_ptr_name(ctx->group_array.groups + 0, "");
|
|
ctx->group_array.groups[0].port = iniGetIntValue(NULL, "port",
|
|
ini_ctx->context, ctx->default_port);
|
|
return 0;
|
|
}
|
|
|
|
end = sections + count;
|
|
for (section=sections; section<end; section++) {
|
|
ini_ctx->section_name = section->section_name;
|
|
if ((result=fc_server_load_one_group(ctx, ini_ctx, count)) != 0) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
fc_server_sort_groups(ctx);
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_alloc_servers(FCServerInfoArray *array,
|
|
const int target_count)
|
|
{
|
|
int bytes;
|
|
|
|
bytes = sizeof(FCServerInfo) * target_count;
|
|
array->servers = (FCServerInfo *)fc_malloc(bytes);
|
|
if (array->servers == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
memset(array->servers, 0, bytes);
|
|
|
|
array->alloc = target_count;
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_check_alloc_group_address_ptrs(FCAddressPtrArray *array)
|
|
{
|
|
int new_alloc;
|
|
int bytes;
|
|
FCAddressInfo **new_addrs;
|
|
|
|
if (array->count < array->alloc) {
|
|
return 0;
|
|
}
|
|
|
|
new_alloc = array->alloc > 0 ? 2 * array->alloc : 1;
|
|
bytes = sizeof(FCAddressInfo *) * new_alloc;
|
|
new_addrs = (FCAddressInfo **)fc_malloc(bytes);
|
|
if (new_addrs == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
memset(new_addrs, 0, bytes);
|
|
|
|
if (array->addrs != NULL) {
|
|
memcpy(new_addrs, array->addrs, sizeof(FCAddressInfo *) * array->count);
|
|
free(array->addrs);
|
|
}
|
|
|
|
array->addrs = new_addrs;
|
|
array->alloc = new_alloc;
|
|
return 0;
|
|
}
|
|
|
|
static inline void fc_server_clear_server_port(FCServerGroupArray *array)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
|
|
end = array->groups + array->count;
|
|
for (group=array->groups; group<end; group++) {
|
|
group->server_port = 0;
|
|
}
|
|
}
|
|
|
|
FCServerGroupInfo *fc_server_get_group_by_name(FCServerConfig *ctx,
|
|
const string_t *group_name)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (group=ctx->group_array.groups; group<end; group++) {
|
|
if (fc_string_equal(&group->group_name, group_name)) {
|
|
return group;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int fc_server_load_group_port(FCServerConfig *ctx,
|
|
const char *config_filename, const char *section_name,
|
|
const string_t *group_name, IniItem *port_item)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
char *endptr;
|
|
|
|
if ((group=fc_server_get_group_by_name(ctx, group_name)) == NULL) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, group: %.*s "
|
|
"in item: %s not found!", __LINE__, config_filename,
|
|
section_name, group_name->len, group_name->str,
|
|
port_item->name);
|
|
return ENOENT;
|
|
}
|
|
|
|
endptr = NULL;
|
|
group->server_port = strtol(port_item->value, &endptr, 10);
|
|
if (group->server_port <= 0 || (endptr != NULL && *endptr != '\0')) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, item: %s, "
|
|
"invalid port: %s", __LINE__, config_filename,
|
|
section_name, port_item->name, port_item->value);
|
|
return EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_server_addresses_duplicate(FCServerConfig *ctx,
|
|
const char *config_filename, const char *section_name,
|
|
FCAddressInfo *addresses, const int count)
|
|
{
|
|
FCAddressInfo *addr1;
|
|
FCAddressInfo *addr2;
|
|
FCAddressInfo *end;
|
|
char port_caption[32];
|
|
char port_prompt[16];
|
|
|
|
if (count <= 1) {
|
|
return 0;
|
|
}
|
|
|
|
end = addresses + count;
|
|
for (addr1=addresses; addr1<end; addr1++) {
|
|
for (addr2=addr1+1; addr2<end; addr2++) {
|
|
if (FC_CONNECTION_SERVER_EQUAL1(addr1->conn, addr2->conn)) {
|
|
if (addr1->conn.port > 0) {
|
|
strcpy(port_caption, " and port");
|
|
sprintf(port_prompt, ":%d", addr1->conn.port);
|
|
} else {
|
|
*port_caption = *port_prompt = '\0';
|
|
}
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, duplicate ip%s %s%s",
|
|
__LINE__, config_filename, section_name, port_caption,
|
|
addr1->conn.ip_addr, port_prompt);
|
|
return EEXIST;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_addresses_duplicate(FCServerConfig *ctx,
|
|
const char *config_filename, const char *section_name,
|
|
FCGroupAddresses *group_addr)
|
|
{
|
|
FCAddressInfo **ppaddr;
|
|
FCAddressInfo **ppend;
|
|
FCAddressInfo **pprevious;
|
|
char formatted_ip[FORMATTED_IP_SIZE];
|
|
|
|
if (group_addr->address_array.count <= 1) {
|
|
return 0;
|
|
}
|
|
|
|
qsort(group_addr->address_array.addrs, group_addr->address_array.count,
|
|
sizeof(FCAddressInfo *), fc_server_cmp_address_ptr);
|
|
pprevious = group_addr->address_array.addrs;
|
|
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) {
|
|
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);
|
|
return EEXIST;
|
|
}
|
|
pprevious = ppaddr;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_server_group_addresses_duplicate(FCServerConfig *ctx,
|
|
FCServerInfo *server, const char *config_filename,
|
|
const char *section_name)
|
|
{
|
|
int result;
|
|
FCGroupAddresses *gaddr;
|
|
FCGroupAddresses *end;
|
|
|
|
end = server->group_addrs + ctx->group_array.count;
|
|
for (gaddr=server->group_addrs; gaddr<end; gaddr++) {
|
|
if ((result=check_addresses_duplicate(ctx, config_filename,
|
|
section_name, gaddr)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_server_group_min_hosts(FCServerConfig *ctx,
|
|
FCServerInfo *server, const char *config_filename,
|
|
const char *section_name)
|
|
{
|
|
FCGroupAddresses *gaddr;
|
|
FCGroupAddresses *end;
|
|
|
|
end = server->group_addrs + ctx->group_array.count;
|
|
for (gaddr=server->group_addrs; gaddr<end; gaddr++) {
|
|
if (gaddr->address_array.count < ctx->min_hosts_each_group) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, group: %.*s, "
|
|
"host count: %d < %d!", __LINE__, config_filename,
|
|
section_name, gaddr->server_group->group_name.len,
|
|
gaddr->server_group->group_name.str,
|
|
gaddr->address_array.count,
|
|
ctx->min_hosts_each_group);
|
|
return ENOENT;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool fc_server_group_match(const FCServerGroupInfo *group,
|
|
const FCAddressInfo *addr)
|
|
{
|
|
int ip_len;
|
|
|
|
if ((addr->conn.port > 0) && (addr->conn.port !=
|
|
FC_SERVER_GROUP_PORT(group)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ((group->filter.net_type != FC_NET_TYPE_ANY) &&
|
|
((addr->net_type & group->filter.net_type) !=
|
|
group->filter.net_type))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (group->filter.ip_prefix.len > 0) {
|
|
ip_len = strlen(addr->conn.ip_addr);
|
|
if (!(ip_len >= group->filter.ip_prefix.len &&
|
|
memcmp(addr->conn.ip_addr,
|
|
group->filter.ip_prefix.str,
|
|
group->filter.ip_prefix.len) == 0))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static int fc_server_set_address(FCServerConfig *ctx,
|
|
FCAddressInfo *addr, const char *config_filename,
|
|
const char *section_name, const char *item_name,
|
|
const char *host, const int default_port)
|
|
{
|
|
int result;
|
|
|
|
if ((result=conn_pool_parse_server_info(host, &addr->conn,
|
|
default_port)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, "
|
|
"item: %s, invalid host: %s", __LINE__,
|
|
config_filename, section_name, item_name, host);
|
|
return result;
|
|
}
|
|
|
|
addr->net_type = fc_get_net_type_by_ip(addr->conn.ip_addr);
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_set_group_server_address(FCServerInfo *server,
|
|
FCGroupAddresses *group_addr, const FCAddressInfo *address)
|
|
{
|
|
FCAddressInfo *addr;
|
|
int result;
|
|
|
|
addr = fc_server_add_to_uniq_addresses(&server->uniq_addresses, address);
|
|
if (addr == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
if ((result=fc_server_check_alloc_group_address_ptrs(
|
|
&group_addr->address_array)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
group_addr->address_array.addrs[group_addr->address_array.count++] = addr;
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_load_group_server(FCServerConfig *ctx,
|
|
FCServerInfo *server, const char *config_filename,
|
|
const char *section_name, const string_t *group_name,
|
|
IniItem *host_item)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCGroupAddresses *group_addr;
|
|
FCAddressInfo address;
|
|
int result;
|
|
int group_index;
|
|
|
|
if ((group=fc_server_get_group_by_name(ctx, group_name)) == NULL) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, group: %.*s "
|
|
"in item: %s not found!", __LINE__, config_filename,
|
|
section_name, group_name->len, group_name->str,
|
|
host_item->name);
|
|
return ENOENT;
|
|
}
|
|
|
|
group_index = group - ctx->group_array.groups;
|
|
group_addr = server->group_addrs + group_index;
|
|
if (group_addr->address_array.count >= FC_MAX_SERVER_IP_COUNT) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, "
|
|
"too many %s items exceeds %d", __LINE__,
|
|
config_filename, section_name,
|
|
host_item->name, FC_MAX_SERVER_IP_COUNT);
|
|
return ENOSPC;
|
|
}
|
|
|
|
if ((result=fc_server_set_address(ctx, &address, config_filename,
|
|
section_name, host_item->name, host_item->value,
|
|
FC_SERVER_GROUP_PORT(group))) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
address.conn.comm_type = group->comm_type;
|
|
if ((result=fc_server_set_group_server_address(server,
|
|
group_addr, &address)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_set_host(FCServerConfig *ctx, FCServerInfo *server,
|
|
const char *config_filename, const char *section_name,
|
|
const FCAddressInfo *addr)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
FCGroupAddresses *group_addr;
|
|
const FCAddressInfo *new_addr;
|
|
FCAddressInfo addr_holder;
|
|
char formatted_ip[FORMATTED_IP_SIZE];
|
|
int result;
|
|
int count;
|
|
int group_index;
|
|
|
|
count = 0;
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (group=ctx->group_array.groups; group<end; group++) {
|
|
if (fc_server_group_match(group, addr)) {
|
|
group_index = group - ctx->group_array.groups;
|
|
group_addr = server->group_addrs + group_index;
|
|
if (group_addr->address_array.count >= FC_MAX_SERVER_IP_COUNT) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, "
|
|
"too many %s items for group %.*s exceeds %d",
|
|
__LINE__, config_filename, section_name,
|
|
SERVER_ITEM_HOST_STR, group->group_name.len,
|
|
group->group_name.str, FC_MAX_SERVER_IP_COUNT);
|
|
return ENOSPC;
|
|
}
|
|
|
|
if (addr->conn.port == 0) {
|
|
addr_holder = *addr;
|
|
addr_holder.conn.port = FC_SERVER_GROUP_PORT(group);
|
|
addr_holder.conn.comm_type = group->comm_type;
|
|
new_addr = &addr_holder;
|
|
} else {
|
|
if (addr->conn.comm_type == group->comm_type) {
|
|
new_addr = addr;
|
|
} else {
|
|
addr_holder = *addr;
|
|
addr_holder.conn.comm_type = group->comm_type;
|
|
new_addr = &addr_holder;
|
|
}
|
|
}
|
|
|
|
if ((result=fc_server_set_group_server_address(server,
|
|
group_addr, new_addr)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count == 0) {
|
|
char port_prompt[16];
|
|
if (addr->conn.port > 0) {
|
|
sprintf(port_prompt, ":%d", addr->conn.port);
|
|
} else {
|
|
*port_prompt = '\0';
|
|
}
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, "
|
|
"host %s%s not belong to any group",
|
|
__LINE__, config_filename, section_name,
|
|
addr->conn.ip_addr, port_prompt);
|
|
return ENOENT;
|
|
}
|
|
|
|
if (!ctx->share_between_groups && (count > 1 && addr->conn.port > 0)) {
|
|
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);
|
|
return EEXIST;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_set_hosts(FCServerConfig *ctx, FCServerInfo *server,
|
|
const char *config_filename, const char *section_name,
|
|
char **hosts, const int host_count)
|
|
{
|
|
int result;
|
|
FCAddressInfo addresses[FC_MAX_SERVER_IP_COUNT];
|
|
FCAddressInfo *addr;
|
|
FCAddressInfo *addr_end;
|
|
char **host;
|
|
char **hend;
|
|
int no_port_count;
|
|
|
|
no_port_count = 0;
|
|
addr = addresses;
|
|
hend = hosts + host_count;
|
|
for (host=hosts; host<hend; host++) {
|
|
if ((result=fc_server_set_address(ctx, addr, config_filename,
|
|
section_name, SERVER_ITEM_HOST_STR, *host, 0)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (addr->conn.port == 0) {
|
|
no_port_count++;
|
|
}
|
|
addr++;
|
|
}
|
|
|
|
if ((result=check_server_addresses_duplicate(ctx, config_filename,
|
|
section_name, addresses, host_count)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (no_port_count > 0 && !ctx->share_between_groups) {
|
|
if ((result=check_group_ports_duplicate(ctx, config_filename)) != 0) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
addr_end = addresses + host_count;
|
|
for (addr=addresses; addr<addr_end; addr++) {
|
|
if ((result=fc_server_set_host(ctx, server, config_filename,
|
|
section_name, addr)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_load_hosts(FCServerConfig *ctx, FCServerInfo *server,
|
|
const char *config_filename, IniContext *ini_context,
|
|
const char *section_name)
|
|
{
|
|
IniItem *items;
|
|
IniItem *it;
|
|
IniItem *end;
|
|
char *hosts[FC_MAX_SERVER_IP_COUNT];
|
|
int item_count;
|
|
int host_count;
|
|
int group_host_count;
|
|
int name_len;
|
|
int result;
|
|
string_t group_name;
|
|
|
|
items = iniGetSectionItems(section_name, ini_context, &item_count);
|
|
if (item_count == 0) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, no items!",
|
|
__LINE__, config_filename, section_name);
|
|
return EINVAL;
|
|
}
|
|
|
|
fc_server_clear_server_port(&ctx->group_array);
|
|
|
|
host_count = group_host_count = 0;
|
|
end = items + item_count;
|
|
for (it=items; it<end; it++) {
|
|
name_len = strlen(it->name);
|
|
if (name_len > SERVER_ITEM_PORT_AFFIX_LEN &&
|
|
memcmp(it->name + name_len - SERVER_ITEM_PORT_AFFIX_LEN,
|
|
SERVER_ITEM_PORT_AFFIX_STR, SERVER_ITEM_PORT_AFFIX_LEN) == 0)
|
|
{
|
|
group_name.str = it->name;
|
|
group_name.len = name_len - SERVER_ITEM_PORT_AFFIX_LEN;
|
|
if ((result=fc_server_load_group_port(ctx, config_filename,
|
|
section_name, &group_name, it)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
} else if (name_len > SERVER_ITEM_HOST_AFFIX_LEN &&
|
|
memcmp(it->name + name_len - SERVER_ITEM_HOST_AFFIX_LEN,
|
|
SERVER_ITEM_HOST_AFFIX_STR, SERVER_ITEM_HOST_AFFIX_LEN) == 0)
|
|
{
|
|
group_name.str = it->name;
|
|
group_name.len = name_len - SERVER_ITEM_HOST_AFFIX_LEN;
|
|
if ((result=fc_server_load_group_server(ctx, server,
|
|
config_filename, section_name,
|
|
&group_name, it)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
group_host_count++;
|
|
} else if (name_len == SERVER_ITEM_HOST_LEN && memcmp(it->name,
|
|
SERVER_ITEM_HOST_STR, SERVER_ITEM_HOST_LEN) == 0)
|
|
{
|
|
if (host_count >= FC_MAX_SERVER_IP_COUNT) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, "
|
|
"too many %s items exceeds %d", __LINE__,
|
|
config_filename, section_name,
|
|
SERVER_ITEM_HOST_STR, FC_MAX_SERVER_IP_COUNT);
|
|
return ENOSPC;
|
|
}
|
|
|
|
hosts[host_count++] = it->value;
|
|
} else {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, unkown item name: %s",
|
|
__LINE__, config_filename, section_name, it->name);
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
if (host_count == 0 && group_host_count == 0) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, no item: %s or *%s!",
|
|
__LINE__, config_filename, section_name,
|
|
SERVER_ITEM_HOST_STR, SERVER_ITEM_HOST_AFFIX_STR);
|
|
return ENOENT;
|
|
}
|
|
|
|
if (host_count > 0) {
|
|
if ((result=fc_server_set_hosts(ctx, server, config_filename,
|
|
section_name, hosts, host_count)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
|
|
if ((result=check_server_group_addresses_duplicate(ctx, server,
|
|
config_filename, section_name)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (ctx->min_hosts_each_group > 0) {
|
|
if ((result=check_server_group_min_hosts(ctx, server,
|
|
config_filename, section_name)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void fc_server_set_group_ptr(FCServerConfig *ctx, FCServerInfo *server)
|
|
{
|
|
FCGroupAddresses *gaddr;
|
|
FCGroupAddresses *end;
|
|
|
|
end = server->group_addrs + ctx->group_array.count;
|
|
for (gaddr=server->group_addrs; gaddr<end; gaddr++) {
|
|
gaddr->server_group = ctx->group_array.groups + (gaddr -
|
|
server->group_addrs);
|
|
}
|
|
}
|
|
|
|
static int fc_server_load_one_server(FCServerConfig *ctx,
|
|
const char *config_filename, IniContext *ini_context,
|
|
const char *section_name)
|
|
{
|
|
FCServerInfo *server;
|
|
char *endptr;
|
|
int result;
|
|
|
|
server = FC_SID_SERVERS(*ctx) + FC_SID_SERVER_COUNT(*ctx);
|
|
endptr = NULL;
|
|
server->id = strtol(section_name + SERVER_SECTION_PREFIX_LEN,
|
|
&endptr, 10);
|
|
if (server->id <= 0 || (endptr != NULL && *endptr != '\0')) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, section: %s, invalid server id! "
|
|
"server section format is [%s$id]",
|
|
__LINE__, config_filename, section_name,
|
|
SERVER_SECTION_PREFIX_STR);
|
|
return EINVAL;
|
|
}
|
|
|
|
fc_server_set_group_ptr(ctx, server);
|
|
if ((result=fc_server_load_hosts(ctx, server, config_filename,
|
|
ini_context, section_name)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
FC_SID_SERVER_COUNT(*ctx)++;
|
|
return 0;
|
|
}
|
|
|
|
static int fc_server_load_servers(FCServerConfig *ctx,
|
|
const char *config_filename, IniContext *ini_context)
|
|
{
|
|
#define FIXED_SECTION_COUNT 16
|
|
int result;
|
|
int section_count;
|
|
int server_count;
|
|
IniSectionInfo *sections;
|
|
IniSectionInfo fixed[FIXED_SECTION_COUNT];
|
|
IniSectionInfo *section;
|
|
IniSectionInfo *end;
|
|
int alloc_bytes;
|
|
|
|
section_count = iniGetSectionCountByPrefix(ini_context,
|
|
SERVER_SECTION_PREFIX_STR);
|
|
if (section_count == 0) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, no server section such as [%s$id]",
|
|
__LINE__, config_filename, SERVER_SECTION_PREFIX_STR);
|
|
return ENOENT;
|
|
}
|
|
|
|
if (section_count < FIXED_SECTION_COUNT) {
|
|
sections = fixed;
|
|
} else {
|
|
alloc_bytes = sizeof(IniSectionInfo) * section_count;
|
|
sections = (IniSectionInfo *)fc_malloc(alloc_bytes);
|
|
if (sections == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
}
|
|
|
|
do {
|
|
if ((result=iniGetSectionNamesByPrefix(ini_context,
|
|
SERVER_SECTION_PREFIX_STR, sections,
|
|
section_count, §ion_count)) != 0)
|
|
{
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, get sections by prefix %s fail, "
|
|
"errno: %d, error info: %s", __LINE__, config_filename,
|
|
SERVER_SECTION_PREFIX_STR, result, STRERROR(result));
|
|
break;
|
|
}
|
|
|
|
end = sections + section_count;
|
|
server_count = 0;
|
|
for (section=sections; section<end; section++) {
|
|
if (is_digital_string(section->section_name +
|
|
SERVER_SECTION_PREFIX_LEN))
|
|
{
|
|
++server_count;
|
|
}
|
|
}
|
|
if (server_count == 0) {
|
|
logError("file: "__FILE__", line: %d, "
|
|
"config filename: %s, no server section such as [%s$id]",
|
|
__LINE__, config_filename, SERVER_SECTION_PREFIX_STR);
|
|
return ENOENT;
|
|
}
|
|
|
|
if ((result=fc_server_alloc_servers(&ctx->sorted_server_arrays.
|
|
by_id, server_count)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
for (section=sections; section<end; section++) {
|
|
if (!is_digital_string(section->section_name +
|
|
SERVER_SECTION_PREFIX_LEN))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ((result=fc_server_load_one_server(ctx, config_filename,
|
|
ini_context, section->section_name)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
} while (0);
|
|
|
|
if (sections != fixed) {
|
|
free(sections);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void load_connection_thread_local(FCServerConfig *ctx,
|
|
IniContext *ini_context, const char *config_filename)
|
|
{
|
|
char *connection_thread_local;
|
|
|
|
connection_thread_local = iniGetStrValue(NULL,
|
|
"connection_thread_local", ini_context);
|
|
if (connection_thread_local == NULL || *connection_thread_local == '\0') {
|
|
ctx->connection_thread_local = fc_connection_thread_local_auto;
|
|
} else if (strcasecmp(connection_thread_local, "auto") == 0) {
|
|
ctx->connection_thread_local = fc_connection_thread_local_auto;
|
|
} else if (strcasecmp(connection_thread_local, "yes") == 0) {
|
|
ctx->connection_thread_local = fc_connection_thread_local_yes;
|
|
} else if (strcasecmp(connection_thread_local, "no") == 0) {
|
|
ctx->connection_thread_local = fc_connection_thread_local_no;
|
|
} else {
|
|
logWarning("file: "__FILE__", line: %d, "
|
|
"config file: %s, invalid connection_thread_local: %s, "
|
|
"set to auto!", __LINE__, config_filename,
|
|
connection_thread_local);
|
|
ctx->connection_thread_local = fc_connection_thread_local_auto;
|
|
}
|
|
}
|
|
|
|
static int fc_server_load_data(FCServerConfig *ctx,
|
|
IniContext *ini_context, const char *config_filename)
|
|
{
|
|
int result;
|
|
bool have_rdma;
|
|
IniFullContext full_ini_ctx;
|
|
FCSmartPollingConfig default_smart_polling;
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
|
|
FAST_INI_SET_FULL_CTX_EX(full_ini_ctx,
|
|
config_filename, NULL, ini_context);
|
|
default_smart_polling.enabled = true;
|
|
default_smart_polling.switch_on_iops = 10240;
|
|
default_smart_polling.switch_on_count = 3;
|
|
if ((result=load_comm_type_and_smart_polling(&full_ini_ctx,
|
|
&ctx->comm_type, &ctx->smart_polling,
|
|
fc_comm_type_sock, &default_smart_polling)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
ctx->buffer_size = load_buffer_size(&full_ini_ctx, 256 * 1024);
|
|
if ((result=fc_server_load_groups(ctx, &full_ini_ctx)) != 0) {
|
|
return result;
|
|
}
|
|
|
|
have_rdma = false;
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (group=ctx->group_array.groups; group<end; group++) {
|
|
if (group->comm_type != fc_comm_type_sock) {
|
|
have_rdma = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!have_rdma) {
|
|
ctx->buffer_size = 0;
|
|
}
|
|
load_connection_thread_local(ctx, ini_context, config_filename);
|
|
|
|
if ((result=fc_server_load_servers(ctx, config_filename,
|
|
ini_context)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
qsort(FC_SID_SERVERS(*ctx), FC_SID_SERVER_COUNT(*ctx),
|
|
sizeof(FCServerInfo), fc_server_cmp_server_id);
|
|
if ((result=fc_server_check_id_duplicated(ctx, config_filename)) != 0) {
|
|
return result;
|
|
}
|
|
|
|
if ((result=fc_server_init_ip_port_array(ctx)) != 0) {
|
|
return result;
|
|
}
|
|
|
|
return fc_server_check_ip_port(ctx, config_filename);
|
|
}
|
|
|
|
#define FC_SERVER_INIT_CONTEXT(ctx, port, min_hosts, shared) \
|
|
do { \
|
|
memset(ctx, 0, sizeof(FCServerConfig)); \
|
|
ctx->default_port = port; \
|
|
ctx->min_hosts_each_group = min_hosts; \
|
|
ctx->share_between_groups = shared; \
|
|
} while (0)
|
|
|
|
int fc_server_load_from_file_ex(FCServerConfig *ctx,
|
|
const char *config_filename, const int default_port,
|
|
const int min_hosts_each_group, const bool share_between_groups)
|
|
{
|
|
IniContext ini_context;
|
|
int result;
|
|
|
|
FC_SERVER_INIT_CONTEXT(ctx, default_port, min_hosts_each_group,
|
|
share_between_groups);
|
|
|
|
if ((result=iniLoadFromFile1(config_filename, &ini_context,
|
|
FAST_INI_FLAGS_DISABLE_SAME_SECTION_MERGE)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
result = fc_server_load_data(ctx, &ini_context, config_filename);
|
|
iniFreeContext(&ini_context);
|
|
return result;
|
|
}
|
|
|
|
int fc_server_load_from_buffer_ex(FCServerConfig *ctx, char *content,
|
|
const char *caption, const int default_port,
|
|
const int min_hosts_each_group, const bool share_between_groups)
|
|
{
|
|
IniContext ini_context;
|
|
int result;
|
|
|
|
FC_SERVER_INIT_CONTEXT(ctx, default_port, min_hosts_each_group,
|
|
share_between_groups);
|
|
if ((result=iniLoadFromBuffer1(content, &ini_context,
|
|
FAST_INI_FLAGS_DISABLE_SAME_SECTION_MERGE)) != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
result = fc_server_load_data(ctx, &ini_context, caption);
|
|
iniFreeContext(&ini_context);
|
|
return result;
|
|
}
|
|
|
|
int fc_server_load_from_ini_context_ex(FCServerConfig *ctx,
|
|
IniContext *ini_context, const char *config_filename,
|
|
const int default_port, const int min_hosts_each_group,
|
|
const bool share_between_groups)
|
|
{
|
|
FC_SERVER_INIT_CONTEXT(ctx, default_port, min_hosts_each_group,
|
|
share_between_groups);
|
|
return fc_server_load_data(ctx, ini_context, config_filename);
|
|
}
|
|
|
|
static void fc_server_free_addresses(FCServerConfig *ctx)
|
|
{
|
|
FCServerInfo *server;
|
|
FCServerInfo *send;
|
|
FCGroupAddresses *gaddr;
|
|
FCGroupAddresses *gend;
|
|
|
|
send = FC_SID_SERVERS(*ctx) + FC_SID_SERVER_COUNT(*ctx);
|
|
for (server=FC_SID_SERVERS(*ctx); server<send; server++) {
|
|
gend = server->group_addrs + ctx->group_array.count;
|
|
for (gaddr=server->group_addrs; gaddr<gend; gaddr++) {
|
|
if (gaddr->address_array.addrs != NULL) {
|
|
free(gaddr->address_array.addrs);
|
|
gaddr->address_array.addrs = NULL;
|
|
gaddr->address_array.count = gaddr->address_array.alloc = 0;
|
|
}
|
|
}
|
|
if (server->uniq_addresses.addrs != NULL) {
|
|
free(server->uniq_addresses.addrs);
|
|
server->uniq_addresses.addrs = NULL;
|
|
server->uniq_addresses.count = server->uniq_addresses.alloc = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void fc_server_destroy(FCServerConfig *ctx)
|
|
{
|
|
if (IP_PORT_MAPS(ctx) != NULL) {
|
|
free(IP_PORT_MAPS(ctx));
|
|
IP_PORT_MAPS(ctx) = NULL;
|
|
IP_PORT_MAP_COUNT(ctx) = 0;
|
|
}
|
|
|
|
if (FC_SID_SERVERS(*ctx) != NULL) {
|
|
fc_server_free_addresses(ctx);
|
|
|
|
free(FC_SID_SERVERS(*ctx));
|
|
FC_SID_SERVERS(*ctx) = NULL;
|
|
FC_SID_SERVER_COUNT(*ctx) = 0;
|
|
}
|
|
}
|
|
|
|
static FCServerGroupInfo *address_uniq_match_group(FCServerConfig *ctx,
|
|
const FCAddressInfo *addr)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
FCServerGroupInfo *matched;
|
|
|
|
matched = NULL;
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (group=ctx->group_array.groups; group<end; group++) {
|
|
if (fc_server_group_match(group, addr)) {
|
|
if (matched != NULL) {
|
|
return NULL;
|
|
} else {
|
|
matched = group;
|
|
}
|
|
}
|
|
}
|
|
|
|
return matched;
|
|
}
|
|
|
|
static int fc_groups_to_string(FCServerConfig *ctx, FastBuffer *buffer)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
const char *net_type_caption;
|
|
int result;
|
|
|
|
if ((result=fast_buffer_check(buffer, FC_MAX_GROUP_COUNT * 256)) != 0) {
|
|
return result;
|
|
}
|
|
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (group=ctx->group_array.groups; group<end; group++) {
|
|
net_type_caption = get_net_type_caption(group->filter.net_type);
|
|
if (strcmp(net_type_caption, NET_TYPE_ANY_STR) == 0) {
|
|
net_type_caption = "";
|
|
}
|
|
|
|
fast_buffer_append(buffer,
|
|
"[%s%.*s]\n"
|
|
"port = %d\n",
|
|
GROUP_SECTION_PREFIX_STR,
|
|
group->group_name.len, group->group_name.str,
|
|
group->port);
|
|
|
|
if (group->comm_type != fc_comm_type_sock) {
|
|
fast_buffer_append(buffer,
|
|
"communication = %s\n"
|
|
"smart_polling = %d\n"
|
|
"polling_switch_on_iops = %d\n"
|
|
"polling_switch_on_count = %d\n",
|
|
fc_comm_type_str(group->comm_type),
|
|
group->smart_polling.enabled,
|
|
group->smart_polling.switch_on_iops,
|
|
group->smart_polling.switch_on_count);
|
|
if (group->buffer_size != ctx->buffer_size) {
|
|
fast_buffer_append(buffer, "buffer_size = %d KB\n",
|
|
group->buffer_size / 1024);
|
|
}
|
|
}
|
|
|
|
fast_buffer_append(buffer,
|
|
"net_type = %s\n"
|
|
"ip_prefix = %.*s\n\n",
|
|
net_type_caption, group->filter.ip_prefix.len,
|
|
group->filter.ip_prefix.str);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void fc_group_servers_to_string(FCServerConfig *ctx,
|
|
FCGroupAddresses *gaddr, FastBuffer *buffer)
|
|
{
|
|
FCAddressInfo **addr;
|
|
FCAddressInfo **end;
|
|
char formatted_ip[FORMATTED_IP_SIZE];
|
|
|
|
end = gaddr->address_array.addrs + gaddr->address_array.count;
|
|
for (addr=gaddr->address_array.addrs; addr<end; addr++) {
|
|
if (address_uniq_match_group(ctx, *addr) == gaddr->server_group) {
|
|
fast_buffer_append_buff(buffer, SERVER_ITEM_HOST_STR,
|
|
SERVER_ITEM_HOST_LEN);
|
|
} else {
|
|
fast_buffer_append(buffer, "%.*s%s",
|
|
gaddr->server_group->group_name.len,
|
|
gaddr->server_group->group_name.str,
|
|
SERVER_ITEM_HOST_AFFIX_STR);
|
|
}
|
|
fast_buffer_append(buffer, " = %s:%u\n",
|
|
format_ip_address((*addr)->conn.ip_addr, formatted_ip),
|
|
(*addr)->conn.port);
|
|
}
|
|
}
|
|
|
|
static int fc_one_server_to_string(FCServerConfig *ctx,
|
|
FCServerInfo *server, FastBuffer *buffer)
|
|
{
|
|
FCGroupAddresses *gaddr;
|
|
FCGroupAddresses *end;
|
|
int bytes;
|
|
int result;
|
|
|
|
bytes = 32;
|
|
end = server->group_addrs + ctx->group_array.count;
|
|
for (gaddr=server->group_addrs; gaddr<end; gaddr++) {
|
|
bytes += (IP_ADDRESS_SIZE + 128) * gaddr->address_array.count;
|
|
}
|
|
|
|
if ((result=fast_buffer_check(buffer, bytes)) != 0) {
|
|
return result;
|
|
}
|
|
|
|
fast_buffer_append(buffer, "[%s%d]\n",
|
|
SERVER_SECTION_PREFIX_STR, server->id);
|
|
|
|
for (gaddr=server->group_addrs; gaddr<end; gaddr++) {
|
|
fc_group_servers_to_string(ctx, gaddr, buffer);
|
|
}
|
|
|
|
fast_buffer_append_buff(buffer, "\n", 1);
|
|
return 0;
|
|
}
|
|
|
|
static int fc_servers_to_string(FCServerConfig *ctx, FastBuffer *buffer)
|
|
{
|
|
FCServerInfo *server;
|
|
FCServerInfo *end;
|
|
int result;
|
|
|
|
end = FC_SID_SERVERS(*ctx) + FC_SID_SERVER_COUNT(*ctx);
|
|
for (server=FC_SID_SERVERS(*ctx); server<end; server++) {
|
|
if ((result=fc_one_server_to_string(ctx, server, buffer)) != 0) {
|
|
return result;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fc_server_to_config_string(FCServerConfig *ctx, FastBuffer *buffer)
|
|
{
|
|
int result;
|
|
|
|
if (ctx->buffer_size > 0) {
|
|
if ((result=fast_buffer_check(buffer, 1024)) != 0) {
|
|
return result;
|
|
}
|
|
fast_buffer_append(buffer, "buffer_size = %d KB\n",
|
|
ctx->buffer_size / 1024);
|
|
}
|
|
|
|
fc_server_clear_server_port(&ctx->group_array);
|
|
if ((result=fc_groups_to_string(ctx, buffer)) != 0) {
|
|
return result;
|
|
}
|
|
|
|
return fc_servers_to_string(ctx, buffer);
|
|
}
|
|
|
|
static void fc_server_log_groups(FCServerConfig *ctx)
|
|
{
|
|
FCServerGroupInfo *group;
|
|
FCServerGroupInfo *end;
|
|
char buff[1024];
|
|
char *p;
|
|
|
|
end = ctx->group_array.groups + ctx->group_array.count;
|
|
for (group=ctx->group_array.groups; group<end; group++) {
|
|
p = buff + sprintf(buff, "group_name: %.*s, port: %d",
|
|
group->group_name.len, group->group_name.str,
|
|
group->port);
|
|
if (group->comm_type != fc_comm_type_sock) {
|
|
p += sprintf(p, ", communication: %s, smart_polling: %d, "
|
|
"polling_switch_on_iops: %d, polling_switch_on_count: %d",
|
|
fc_comm_type_str(group->comm_type),
|
|
group->smart_polling.enabled,
|
|
group->smart_polling.switch_on_iops,
|
|
group->smart_polling.switch_on_count);
|
|
if (group->buffer_size != ctx->buffer_size) {
|
|
p += sprintf(p, ", buffer_size = %d KB",
|
|
group->buffer_size / 1024);
|
|
}
|
|
}
|
|
p += sprintf(p, ", net_type: %s, ip_prefix: %.*s",
|
|
get_net_type_caption(group->filter.net_type),
|
|
group->filter.ip_prefix.len, group->filter.ip_prefix.str);
|
|
|
|
log_it1(LOG_INFO, buff, p - buff);
|
|
}
|
|
}
|
|
|
|
static void fc_server_log_group_servers(FCGroupAddresses *gaddr)
|
|
{
|
|
FCAddressInfo **addr;
|
|
FCAddressInfo **end;
|
|
char formatted_ip[FORMATTED_IP_SIZE];
|
|
|
|
end = gaddr->address_array.addrs + gaddr->address_array.count;
|
|
for (addr=gaddr->address_array.addrs; addr<end; addr++) {
|
|
logInfo(" %d. %s:%u", (int)(addr - gaddr->address_array.addrs + 1),
|
|
format_ip_address((*addr)->conn.ip_addr, formatted_ip),
|
|
(*addr)->conn.port);
|
|
}
|
|
}
|
|
|
|
static void fc_server_log_one_server(FCServerConfig *ctx, FCServerInfo *server)
|
|
{
|
|
FCGroupAddresses *gaddr;
|
|
FCGroupAddresses *end;
|
|
|
|
logInfo("server id: %d", server->id);
|
|
|
|
end = server->group_addrs + ctx->group_array.count;
|
|
for (gaddr=server->group_addrs; gaddr<end; gaddr++) {
|
|
logInfo("[group-%.*s] ip count: %d", FC_PRINTF_STAR_STRING_PARAMS(
|
|
gaddr->server_group->group_name),
|
|
gaddr->address_array.count);
|
|
fc_server_log_group_servers(gaddr);
|
|
}
|
|
logInfo(" ");
|
|
}
|
|
|
|
static void fc_server_log_servers(FCServerConfig *ctx)
|
|
{
|
|
FCServerInfo *server;
|
|
FCServerInfo *end;
|
|
|
|
logInfo("server count: %d, unique ip and port count: %d",
|
|
FC_SID_SERVER_COUNT(*ctx),
|
|
IP_PORT_MAP_COUNT(ctx));
|
|
|
|
end = FC_SID_SERVERS(*ctx) + FC_SID_SERVER_COUNT(*ctx);
|
|
for (server=FC_SID_SERVERS(*ctx); server<end; server++) {
|
|
fc_server_log_one_server(ctx, server);
|
|
}
|
|
}
|
|
|
|
void fc_server_to_log(FCServerConfig *ctx)
|
|
{
|
|
char buff[256];
|
|
char *p;
|
|
|
|
p = buff + sprintf(buff, "connection_thread_local: %s",
|
|
fc_connection_thread_local_str(ctx->connection_thread_local));
|
|
if (ctx->buffer_size > 0) {
|
|
p += sprintf(p, ", buffer_size: %d KB", ctx->buffer_size / 1024);
|
|
}
|
|
log_it1(LOG_INFO, buff, p - buff);
|
|
|
|
fc_server_log_groups(ctx);
|
|
fc_server_log_servers(ctx);
|
|
}
|
|
|
|
int fc_server_make_connection_ex(FCAddressPtrArray *addr_array,
|
|
ConnectionInfo *conn, const char *service_name,
|
|
const int connect_timeout, const char *bind_ipaddr,
|
|
const bool log_connect_error)
|
|
{
|
|
FCAddressInfo **current;
|
|
FCAddressInfo **addr;
|
|
FCAddressInfo **end;
|
|
int result;
|
|
|
|
if (addr_array->count <= 0) {
|
|
return ENOENT;
|
|
}
|
|
|
|
current = addr_array->addrs + addr_array->index;
|
|
conn_pool_set_server_info(conn, (*current)->conn.ip_addr,
|
|
(*current)->conn.port);
|
|
conn->comm_type = (*current)->conn.comm_type;
|
|
if ((result=G_COMMON_CONNECTION_CALLBACKS[conn->comm_type].
|
|
make_connection(conn, service_name, connect_timeout * 1000,
|
|
bind_ipaddr, log_connect_error)) == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (addr_array->count == 1) {
|
|
return result;
|
|
}
|
|
|
|
end = addr_array->addrs + addr_array->count;
|
|
for (addr=addr_array->addrs; addr<end; addr++) {
|
|
if (addr == current) {
|
|
continue;
|
|
}
|
|
|
|
conn_pool_set_server_info(conn, (*addr)->conn.ip_addr,
|
|
(*addr)->conn.port);
|
|
conn->comm_type = (*addr)->conn.comm_type;
|
|
if ((result=G_COMMON_CONNECTION_CALLBACKS[conn->comm_type].
|
|
make_connection(conn, service_name, connect_timeout * 1000,
|
|
bind_ipaddr, log_connect_error)) == 0)
|
|
{
|
|
addr_array->index = addr - addr_array->addrs;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const FCAddressInfo *fc_server_get_address_by_peer(
|
|
FCAddressPtrArray *addr_array, const char *peer_ip)
|
|
{
|
|
FCAddressInfo **addr;
|
|
FCAddressInfo **end;
|
|
int net_type;
|
|
|
|
if (addr_array->count == 1) {
|
|
return *(addr_array->addrs);
|
|
}
|
|
if (addr_array->count == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
net_type = fc_get_net_type_by_ip(peer_ip);
|
|
end = addr_array->addrs + addr_array->count;
|
|
for (addr=addr_array->addrs; addr<end; addr++) {
|
|
if ((*addr)->net_type == net_type) {
|
|
return *addr;
|
|
}
|
|
}
|
|
|
|
return *(addr_array->addrs);
|
|
}
|
|
|
|
struct ibv_pd *fc_alloc_rdma_pd(fc_alloc_pd_callback alloc_pd,
|
|
FCAddressPtrArray *address_array, int *result)
|
|
{
|
|
char *ip_addrs[FC_MAX_SERVER_IP_COUNT];
|
|
char **ip_addr;
|
|
FCAddressInfo **addr;
|
|
FCAddressInfo **end;
|
|
struct ibv_pd *pd;
|
|
int port;
|
|
|
|
if (address_array->count == 0) {
|
|
port = 0;
|
|
} else {
|
|
port = address_array->addrs[0]->conn.port;
|
|
}
|
|
|
|
end = address_array->addrs + address_array->count;
|
|
for (addr=address_array->addrs, ip_addr=ip_addrs;
|
|
addr<end; addr++, ip_addr++)
|
|
{
|
|
*ip_addr = (*addr)->conn.ip_addr;
|
|
}
|
|
|
|
if ((pd=alloc_pd((const char **)ip_addrs, address_array->
|
|
count, port)) != NULL)
|
|
{
|
|
*result = 0;
|
|
} else {
|
|
*result = ENODEV;
|
|
}
|
|
return pd;
|
|
}
|