/* * 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 . */ #include #include #include #include #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); serveruniq_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; ppconn, (*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); serveruniq_addresses.addrs + server->uniq_addresses.count; for (paddr=server->uniq_addresses.addrs; paddrserver = 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; currentid == 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; currentserver->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; g1group_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; groupgroup_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; sectionsection_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; groupserver_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; groupgroup_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; addr1conn, 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; ppaddrserver_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; gaddrgroup_addrs + ctx->group_array.count; for (gaddr=server->group_addrs; gaddraddress_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; groupgroup_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; hostconn.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; addrgroup_array); host_count = group_host_count = 0; end = items + item_count; for (it=items; itname); 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; gaddrserver_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; sectionsection_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; sectionsection_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; groupcomm_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); servergroup_addrs + ctx->group_array.count; for (gaddr=server->group_addrs; gaddraddress_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; groupgroup_array.groups + ctx->group_array.count; for (group=ctx->group_array.groups; groupfilter.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; addrserver_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; gaddraddress_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; gaddrbuffer_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; groupgroup_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; addraddress_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; gaddrserver_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); serverconnection_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; addrconn.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; addrnet_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; addrconn.ip_addr; } if ((pd=alloc_pd((const char **)ip_addrs, address_array-> count, port)) != NULL) { *result = 0; } else { *result = ENODEV; } return pd; }