/** * Copyright (C) 2008 Happy Fish / YuQing * * FastDFS may be copied only under the terms of the GNU General * Public License V3, which may be found in the FastDFS source kit. * Please visit the FastDFS Home Page http://www.fastken.com/ for more detail. **/ //client_func.c #include #include #include #include #include #include #include #include #include #include #include #include "fdfs_define.h" #include "fastcommon/logger.h" #include "fdfs_global.h" #include "fastcommon/base64.h" #include "fastcommon/sockopt.h" #include "fastcommon/shared_func.h" #include "fastcommon/ini_file_reader.h" #include "fastcommon/connection_pool.h" #include "tracker_types.h" #include "tracker_proto.h" #include "client_global.h" #include "client_func.h" static int storage_cmp_by_ip_and_port(const void *p1, const void *p2) { int res; res = strcmp(((ConnectionInfo *)p1)->ip_addr, ((ConnectionInfo *)p2)->ip_addr); if (res != 0) { return res; } return ((ConnectionInfo *)p1)->port - ((ConnectionInfo *)p2)->port; } static int storage_cmp_server_info(const void *p1, const void *p2) { TrackerServerInfo *server1; TrackerServerInfo *server2; ConnectionInfo *pc1; ConnectionInfo *pc2; ConnectionInfo *end1; int res; server1 = (TrackerServerInfo *)p1; server2 = (TrackerServerInfo *)p2; res = server1->count - server2->count; if (res != 0) { return res; } if (server1->count == 1) { return storage_cmp_by_ip_and_port(server1->connections + 0, server2->connections + 0); } end1 = server1->connections + server1->count; for (pc1=server1->connections,pc2=server2->connections; pc1servers+pTrackerGroup->server_count; pDestServer>pTrackerGroup->servers; pDestServer--) { if (storage_cmp_server_info(pInsertedServer, pDestServer-1) > 0) { memcpy(pDestServer, pInsertedServer, sizeof(TrackerServerInfo)); return; } memcpy(pDestServer, pDestServer-1, sizeof(TrackerServerInfo)); } memcpy(pDestServer, pInsertedServer, sizeof(TrackerServerInfo)); } static int copy_tracker_servers(TrackerServerGroup *pTrackerGroup, const char *filename, char **ppTrackerServers) { char **ppSrc; char **ppEnd; TrackerServerInfo destServer; int result; memset(&destServer, 0, sizeof(TrackerServerInfo)); fdfs_server_sock_reset(&destServer); ppEnd = ppTrackerServers + pTrackerGroup->server_count; pTrackerGroup->server_count = 0; for (ppSrc=ppTrackerServers; ppSrcservers, pTrackerGroup->server_count, sizeof(TrackerServerInfo), storage_cmp_server_info) == NULL) { insert_into_sorted_servers(pTrackerGroup, &destServer); pTrackerGroup->server_count++; } } /* { TrackerServerInfo *pServer; for (pServer=pTrackerGroup->servers; pServerservers+ \ pTrackerGroup->server_count; pServer++) { //printf("server=%s:%u\n", \ pServer->ip_addr, pServer->port); } } */ return 0; } static int fdfs_check_tracker_group(TrackerServerGroup *pTrackerGroup, const char *conf_filename) { int result; TrackerServerInfo *pServer; TrackerServerInfo *pEnd; char error_info[256]; pEnd = pTrackerGroup->servers + pTrackerGroup->server_count; for (pServer=pTrackerGroup->servers; pServerserver_count=iniGetValues(NULL, "tracker_server", pIniContext, ppTrackerServers, FDFS_MAX_TRACKERS)) <= 0) { logError("file: "__FILE__", line: %d, " "conf file \"%s\", item \"tracker_server\" not exist", __LINE__, conf_filename); return ENOENT; } bytes = sizeof(TrackerServerInfo) * pTrackerGroup->server_count; pTrackerGroup->servers = (TrackerServerInfo *)malloc(bytes); if (pTrackerGroup->servers == NULL) { logError("file: "__FILE__", line: %d, " "malloc %d bytes fail", __LINE__, bytes); pTrackerGroup->server_count = 0; return errno != 0 ? errno : ENOMEM; } memset(pTrackerGroup->servers, 0, bytes); if ((result=copy_tracker_servers(pTrackerGroup, conf_filename, ppTrackerServers)) != 0) { pTrackerGroup->server_count = 0; free(pTrackerGroup->servers); pTrackerGroup->servers = NULL; return result; } return fdfs_check_tracker_group(pTrackerGroup, conf_filename); } int fdfs_load_tracker_group(TrackerServerGroup *pTrackerGroup, const char *conf_filename) { IniContext iniContext; int result; if ((result=iniLoadFromFile(conf_filename, &iniContext)) != 0) { logError("file: "__FILE__", line: %d, " "load conf file \"%s\" fail, ret code: %d", __LINE__, conf_filename, result); return result; } result = fdfs_load_tracker_group_ex(pTrackerGroup, conf_filename, &iniContext); iniFreeContext(&iniContext); return result; } static int fdfs_get_params_from_tracker(bool *use_storage_id) { IniContext iniContext; int result; bool continue_flag; continue_flag = false; if ((result=fdfs_get_ini_context_from_tracker(&g_tracker_group, &iniContext, &continue_flag)) != 0) { return result; } *use_storage_id = iniGetBoolValue(NULL, "use_storage_id", &iniContext, false); iniFreeContext(&iniContext); if (*use_storage_id) { result = fdfs_get_storage_ids_from_tracker_group( &g_tracker_group); } return result; } static int fdfs_client_do_init_ex(TrackerServerGroup *pTrackerGroup, \ const char *conf_filename, IniContext *iniContext) { char *pBasePath; int result; bool use_storage_id; bool load_fdfs_parameters_from_tracker; pBasePath = iniGetStrValue(NULL, "base_path", iniContext); if (pBasePath == NULL) { strcpy(SF_G_BASE_PATH_STR, "/tmp"); } else { snprintf(SF_G_BASE_PATH_STR, sizeof(SF_G_BASE_PATH_STR), "%s", pBasePath); chopPath(SF_G_BASE_PATH_STR); if (!fileExists(SF_G_BASE_PATH_STR)) { logError("file: "__FILE__", line: %d, " \ "\"%s\" can't be accessed, error info: %s", \ __LINE__, SF_G_BASE_PATH_STR, STRERROR(errno)); return errno != 0 ? errno : ENOENT; } if (!isDir(SF_G_BASE_PATH_STR)) { logError("file: "__FILE__", line: %d, " \ "\"%s\" is not a directory!", \ __LINE__, SF_G_BASE_PATH_STR); return ENOTDIR; } } SF_G_CONNECT_TIMEOUT = iniGetIntValue(NULL, "connect_timeout", \ iniContext, DEFAULT_CONNECT_TIMEOUT); if (SF_G_CONNECT_TIMEOUT <= 0) { SF_G_CONNECT_TIMEOUT = DEFAULT_CONNECT_TIMEOUT; } SF_G_NETWORK_TIMEOUT = iniGetIntValue(NULL, "network_timeout", \ iniContext, DEFAULT_NETWORK_TIMEOUT); if (SF_G_NETWORK_TIMEOUT <= 0) { SF_G_NETWORK_TIMEOUT = DEFAULT_NETWORK_TIMEOUT; } if ((result=fdfs_load_tracker_group_ex(pTrackerGroup, \ conf_filename, iniContext)) != 0) { return result; } g_anti_steal_token = iniGetBoolValue(NULL, \ "http.anti_steal.check_token", \ iniContext, false); if (g_anti_steal_token) { char *anti_steal_secret_key; anti_steal_secret_key = iniGetStrValue(NULL, \ "http.anti_steal.secret_key", \ iniContext); if (anti_steal_secret_key == NULL || \ *anti_steal_secret_key == '\0') { logError("file: "__FILE__", line: %d, " \ "param \"http.anti_steal.secret_key\""\ " not exist or is empty", __LINE__); return EINVAL; } buffer_strcpy(&g_anti_steal_secret_key, anti_steal_secret_key); } g_tracker_server_http_port = iniGetIntValue(NULL, \ "http.tracker_server_port", \ iniContext, 80); if (g_tracker_server_http_port <= 0) { g_tracker_server_http_port = 80; } if ((result=fdfs_connection_pool_init(conf_filename, iniContext)) != 0) { return result; } load_fdfs_parameters_from_tracker = iniGetBoolValue(NULL, "load_fdfs_parameters_from_tracker", iniContext, false); if (load_fdfs_parameters_from_tracker) { if ((result=fdfs_get_params_from_tracker(&use_storage_id)) != 0) { return result; } } else { use_storage_id = iniGetBoolValue(NULL, "use_storage_id", iniContext, false); if (use_storage_id) { if ((result=fdfs_load_storage_ids_from_file( conf_filename, iniContext)) != 0) { return result; } } } if (use_storage_id) { FDFSStorageIdInfo *idInfo; FDFSStorageIdInfo *end; char *connect_first_by; end = g_storage_ids_by_id.ids + g_storage_ids_by_id.count; for (idInfo=g_storage_ids_by_id.ids; idInfoip_addrs.count > 1) { g_multi_storage_ips = true; break; } } if (g_multi_storage_ips) { connect_first_by = iniGetStrValue(NULL, "connect_first_by", iniContext); if (connect_first_by != NULL && strncasecmp(connect_first_by, "last", 4) == 0) { g_connect_first_by = fdfs_connect_first_by_last_connected; } } } #ifdef DEBUG_FLAG logDebug("base_path=%s, " "connect_timeout=%d, " "network_timeout=%d, " "tracker_server_count=%d, " "anti_steal_token=%d, " "anti_steal_secret_key length=%d, " "use_connection_pool=%d, " "g_connection_pool_max_idle_time=%ds, " "use_storage_id=%d, connect_first_by=%s, " "storage server id count: %d, " "multi storage ips: %d\n", SF_G_BASE_PATH_STR, SF_G_CONNECT_TIMEOUT, SF_G_NETWORK_TIMEOUT, pTrackerGroup->server_count, g_anti_steal_token, g_anti_steal_secret_key.length, g_use_connection_pool, g_connection_pool_max_idle_time, use_storage_id, g_connect_first_by == fdfs_connect_first_by_tracker ? "tracker" : "last-connected", g_storage_ids_by_id.count, g_multi_storage_ips); #endif return 0; } int fdfs_client_init_from_buffer_ex(TrackerServerGroup *pTrackerGroup, \ const char *buffer) { IniContext iniContext; char *new_buff; int result; new_buff = strdup(buffer); if (new_buff == NULL) { logError("file: "__FILE__", line: %d, " \ "strdup %d bytes fail", __LINE__, (int)strlen(buffer)); return ENOMEM; } result = iniLoadFromBuffer(new_buff, &iniContext); free(new_buff); if (result != 0) { logError("file: "__FILE__", line: %d, " \ "load parameters from buffer fail, ret code: %d", \ __LINE__, result); return result; } result = fdfs_client_do_init_ex(pTrackerGroup, "buffer", &iniContext); iniFreeContext(&iniContext); return result; } int fdfs_client_init_ex(TrackerServerGroup *pTrackerGroup, \ const char *conf_filename) { IniContext iniContext; int result; if ((result=iniLoadFromFile(conf_filename, &iniContext)) != 0) { logError("file: "__FILE__", line: %d, " \ "load conf file \"%s\" fail, ret code: %d", \ __LINE__, conf_filename, result); return result; } result = fdfs_client_do_init_ex(pTrackerGroup, conf_filename, \ &iniContext); iniFreeContext(&iniContext); return result; } int fdfs_copy_tracker_group(TrackerServerGroup *pDestTrackerGroup, \ TrackerServerGroup *pSrcTrackerGroup) { int bytes; TrackerServerInfo *pDestServer; TrackerServerInfo *pDestServerEnd; bytes = sizeof(TrackerServerInfo) * pSrcTrackerGroup->server_count; pDestTrackerGroup->servers = (TrackerServerInfo *)malloc(bytes); if (pDestTrackerGroup->servers == NULL) { logError("file: "__FILE__", line: %d, " "malloc %d bytes fail", __LINE__, bytes); return errno != 0 ? errno : ENOMEM; } pDestTrackerGroup->server_index = 0; pDestTrackerGroup->leader_index = 0; pDestTrackerGroup->server_count = pSrcTrackerGroup->server_count; memcpy(pDestTrackerGroup->servers, pSrcTrackerGroup->servers, bytes); pDestServerEnd = pDestTrackerGroup->servers + pDestTrackerGroup->server_count; for (pDestServer=pDestTrackerGroup->servers; pDestServerserver_count != pGroup2->server_count) { return false; } pEnd1 = pGroup1->servers + pGroup1->server_count; pServer1 = pGroup1->servers; pServer2 = pGroup2->servers; while (pServer1 < pEnd1) { if (!fdfs_server_equal(pServer1, pServer2)) { return false; } pServer1++; pServer2++; } return true; } void fdfs_client_destroy_ex(TrackerServerGroup *pTrackerGroup) { if (pTrackerGroup->servers != NULL) { free(pTrackerGroup->servers); pTrackerGroup->servers = NULL; pTrackerGroup->server_count = 0; pTrackerGroup->server_index = 0; } } const char *fdfs_get_file_ext_name_ex(const char *filename, const bool twoExtName) { const char *fileExtName; const char *p; const char *pStart; int extNameLen; fileExtName = strrchr(filename, '.'); if (fileExtName == NULL) { return NULL; } extNameLen = strlen(fileExtName + 1); if (extNameLen > FDFS_FILE_EXT_NAME_MAX_LEN) { return NULL; } if (strchr(fileExtName + 1, '/') != NULL) //invalid extension name { return NULL; } if (!twoExtName) { return fileExtName + 1; } pStart = fileExtName - (FDFS_FILE_EXT_NAME_MAX_LEN - extNameLen) - 1; if (pStart < filename) { pStart = filename; } p = fileExtName - 1; //before . while ((p > pStart) && (*p != '.')) { p--; } if (p > pStart) //found (extension name have a dot) { if (strchr(p + 1, '/') == NULL) //valid extension name { return p + 1; //skip . } } return fileExtName + 1; //skip . }