1 /**
2 * Copyright (C) 2008 Happy Fish / YuQing
3 *
4 * FastDFS may be copied only under the terms of the GNU General
5 * Public License V3, which may be found in the FastDFS source kit.
6 * Please visit the FastDFS Home Page http://www.fastken.com/ for more detail.
7 **/
8 
9 //client_func.c
10 
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/socket.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16 #include <netdb.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <time.h>
22 #include "fdfs_define.h"
23 #include "fastcommon/logger.h"
24 #include "fdfs_global.h"
25 #include "fastcommon/base64.h"
26 #include "fastcommon/sockopt.h"
27 #include "fastcommon/shared_func.h"
28 #include "fastcommon/ini_file_reader.h"
29 #include "fastcommon/connection_pool.h"
30 #include "tracker_types.h"
31 #include "tracker_proto.h"
32 #include "client_global.h"
33 #include "client_func.h"
34 
storage_cmp_by_ip_and_port(const void * p1,const void * p2)35 static int storage_cmp_by_ip_and_port(const void *p1, const void *p2)
36 {
37 	int res;
38 
39 	res = strcmp(((ConnectionInfo *)p1)->ip_addr,
40 			((ConnectionInfo *)p2)->ip_addr);
41 	if (res != 0)
42 	{
43 		return res;
44 	}
45 
46 	return ((ConnectionInfo *)p1)->port -
47 			((ConnectionInfo *)p2)->port;
48 }
49 
storage_cmp_server_info(const void * p1,const void * p2)50 static int storage_cmp_server_info(const void *p1, const void *p2)
51 {
52 	TrackerServerInfo *server1;
53 	TrackerServerInfo *server2;
54 	ConnectionInfo *pc1;
55 	ConnectionInfo *pc2;
56 	ConnectionInfo *end1;
57 	int res;
58 
59     server1 = (TrackerServerInfo *)p1;
60     server2 = (TrackerServerInfo *)p2;
61 
62     res = server1->count - server2->count;
63     if (res != 0)
64     {
65         return res;
66     }
67 
68     if (server1->count == 1)
69     {
70         return storage_cmp_by_ip_and_port(server1->connections + 0,
71                 server2->connections + 0);
72     }
73 
74     end1 = server1->connections + server1->count;
75     for (pc1=server1->connections,pc2=server2->connections; pc1<end1; pc1++,pc2++)
76     {
77         if ((res=storage_cmp_by_ip_and_port(pc1, pc2)) != 0)
78         {
79             return res;
80         }
81     }
82 
83     return 0;
84 }
85 
insert_into_sorted_servers(TrackerServerGroup * pTrackerGroup,TrackerServerInfo * pInsertedServer)86 static void insert_into_sorted_servers(TrackerServerGroup *pTrackerGroup, \
87 		TrackerServerInfo *pInsertedServer)
88 {
89 	TrackerServerInfo *pDestServer;
90 	for (pDestServer=pTrackerGroup->servers+pTrackerGroup->server_count;
91 		pDestServer>pTrackerGroup->servers; pDestServer--)
92 	{
93 		if (storage_cmp_server_info(pInsertedServer, pDestServer-1) > 0)
94 		{
95 			memcpy(pDestServer, pInsertedServer,
96 				sizeof(TrackerServerInfo));
97 			return;
98 		}
99 
100 		memcpy(pDestServer, pDestServer-1, sizeof(TrackerServerInfo));
101 	}
102 
103 	memcpy(pDestServer, pInsertedServer, sizeof(TrackerServerInfo));
104 }
105 
copy_tracker_servers(TrackerServerGroup * pTrackerGroup,const char * filename,char ** ppTrackerServers)106 static int copy_tracker_servers(TrackerServerGroup *pTrackerGroup,
107 		const char *filename, char **ppTrackerServers)
108 {
109 	char **ppSrc;
110 	char **ppEnd;
111 	TrackerServerInfo destServer;
112     int result;
113 
114 	memset(&destServer, 0, sizeof(TrackerServerInfo));
115     fdfs_server_sock_reset(&destServer);
116 
117 	ppEnd = ppTrackerServers + pTrackerGroup->server_count;
118 	pTrackerGroup->server_count = 0;
119 	for (ppSrc=ppTrackerServers; ppSrc<ppEnd; ppSrc++)
120 	{
121         if ((result=fdfs_parse_server_info(*ppSrc,
122                         FDFS_TRACKER_SERVER_DEF_PORT, &destServer)) != 0)
123         {
124             return result;
125         }
126 
127 		if (bsearch(&destServer, pTrackerGroup->servers,
128 			pTrackerGroup->server_count,
129 			sizeof(TrackerServerInfo),
130 			storage_cmp_server_info) == NULL)
131 		{
132 			insert_into_sorted_servers(pTrackerGroup, &destServer);
133 			pTrackerGroup->server_count++;
134 		}
135 	}
136 
137 	/*
138 	{
139 	TrackerServerInfo *pServer;
140 	for (pServer=pTrackerGroup->servers; pServer<pTrackerGroup->servers+ \
141 		pTrackerGroup->server_count;	pServer++)
142 	{
143 		//printf("server=%s:%d\n", \
144 			pServer->ip_addr, pServer->port);
145 	}
146 	}
147 	*/
148 
149 	return 0;
150 }
151 
fdfs_check_tracker_group(TrackerServerGroup * pTrackerGroup,const char * conf_filename)152 static int fdfs_check_tracker_group(TrackerServerGroup *pTrackerGroup,
153 		const char *conf_filename)
154 {
155     int result;
156 	TrackerServerInfo *pServer;
157 	TrackerServerInfo *pEnd;
158     char error_info[256];
159 
160 	pEnd = pTrackerGroup->servers + pTrackerGroup->server_count;
161 	for (pServer=pTrackerGroup->servers; pServer<pEnd; pServer++)
162 	{
163         if ((result=fdfs_check_server_ips(pServer,
164                         error_info, sizeof(error_info))) != 0)
165         {
166             logError("file: "__FILE__", line: %d, "
167                     "conf file: %s, tracker_server is invalid, "
168                     "error info: %s", __LINE__, conf_filename, error_info);
169             return result;
170         }
171 	}
172 
173     return 0;
174 }
175 
fdfs_load_tracker_group_ex(TrackerServerGroup * pTrackerGroup,const char * conf_filename,IniContext * pIniContext)176 int fdfs_load_tracker_group_ex(TrackerServerGroup *pTrackerGroup,
177 		const char *conf_filename, IniContext *pIniContext)
178 {
179 	int result;
180     int bytes;
181 	char *ppTrackerServers[FDFS_MAX_TRACKERS];
182 
183 	if ((pTrackerGroup->server_count=iniGetValues(NULL, "tracker_server",
184 		pIniContext, ppTrackerServers, FDFS_MAX_TRACKERS)) <= 0)
185 	{
186 		logError("file: "__FILE__", line: %d, "
187 			"conf file \"%s\", item \"tracker_server\" not exist",
188 			__LINE__, conf_filename);
189 		return ENOENT;
190 	}
191 
192     bytes = sizeof(TrackerServerInfo) * pTrackerGroup->server_count;
193 	pTrackerGroup->servers = (TrackerServerInfo *)malloc(bytes);
194 	if (pTrackerGroup->servers == NULL)
195 	{
196 		logError("file: "__FILE__", line: %d, "
197 			"malloc %d bytes fail", __LINE__, bytes);
198 		pTrackerGroup->server_count = 0;
199 		return errno != 0 ? errno : ENOMEM;
200 	}
201 
202 	memset(pTrackerGroup->servers, 0, bytes);
203 	if ((result=copy_tracker_servers(pTrackerGroup, conf_filename,
204 			ppTrackerServers)) != 0)
205 	{
206 		pTrackerGroup->server_count = 0;
207 		free(pTrackerGroup->servers);
208 		pTrackerGroup->servers = NULL;
209 		return result;
210 	}
211 
212 	return fdfs_check_tracker_group(pTrackerGroup, conf_filename);
213 }
214 
fdfs_load_tracker_group(TrackerServerGroup * pTrackerGroup,const char * conf_filename)215 int fdfs_load_tracker_group(TrackerServerGroup *pTrackerGroup,
216 		const char *conf_filename)
217 {
218 	IniContext iniContext;
219 	int result;
220 
221 	if ((result=iniLoadFromFile(conf_filename, &iniContext)) != 0)
222 	{
223 		logError("file: "__FILE__", line: %d, "
224 			"load conf file \"%s\" fail, ret code: %d",
225 			__LINE__, conf_filename, result);
226 		return result;
227 	}
228 
229 	result = fdfs_load_tracker_group_ex(pTrackerGroup,
230             conf_filename, &iniContext);
231 	iniFreeContext(&iniContext);
232 
233 	return result;
234 }
235 
fdfs_get_params_from_tracker(bool * use_storage_id)236 static int fdfs_get_params_from_tracker(bool *use_storage_id)
237 {
238     IniContext iniContext;
239 	int result;
240 	bool continue_flag;
241 
242 	continue_flag = false;
243 	if ((result=fdfs_get_ini_context_from_tracker(&g_tracker_group,
244 		&iniContext, &continue_flag, false, NULL)) != 0)
245     {
246         return result;
247     }
248 
249 	*use_storage_id = iniGetBoolValue(NULL, "use_storage_id",
250             &iniContext, false);
251     iniFreeContext(&iniContext);
252 
253 	if (*use_storage_id)
254 	{
255 		result = fdfs_get_storage_ids_from_tracker_group(
256 				&g_tracker_group);
257 	}
258 
259     return result;
260 }
261 
fdfs_client_do_init_ex(TrackerServerGroup * pTrackerGroup,const char * conf_filename,IniContext * iniContext)262 static int fdfs_client_do_init_ex(TrackerServerGroup *pTrackerGroup, \
263 		const char *conf_filename, IniContext *iniContext)
264 {
265 	char *pBasePath;
266 	int result;
267 	bool use_storage_id;
268 	bool load_fdfs_parameters_from_tracker;
269 
270 	pBasePath = iniGetStrValue(NULL, "base_path", iniContext);
271 	if (pBasePath == NULL)
272 	{
273 		strcpy(g_fdfs_base_path, "/tmp");
274 	}
275 	else
276 	{
277 		snprintf(g_fdfs_base_path, sizeof(g_fdfs_base_path),
278 			"%s", pBasePath);
279 		chopPath(g_fdfs_base_path);
280 		if (!fileExists(g_fdfs_base_path))
281 		{
282 			logError("file: "__FILE__", line: %d, " \
283 				"\"%s\" can't be accessed, error info: %s", \
284 				__LINE__, g_fdfs_base_path, STRERROR(errno));
285 			return errno != 0 ? errno : ENOENT;
286 		}
287 		if (!isDir(g_fdfs_base_path))
288 		{
289 			logError("file: "__FILE__", line: %d, " \
290 				"\"%s\" is not a directory!", \
291 				__LINE__, g_fdfs_base_path);
292 			return ENOTDIR;
293 		}
294 	}
295 
296 	g_fdfs_connect_timeout = iniGetIntValue(NULL, "connect_timeout", \
297 				iniContext, DEFAULT_CONNECT_TIMEOUT);
298 	if (g_fdfs_connect_timeout <= 0)
299 	{
300 		g_fdfs_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
301 	}
302 
303 	g_fdfs_network_timeout = iniGetIntValue(NULL, "network_timeout", \
304 				iniContext, DEFAULT_NETWORK_TIMEOUT);
305 	if (g_fdfs_network_timeout <= 0)
306 	{
307 		g_fdfs_network_timeout = DEFAULT_NETWORK_TIMEOUT;
308 	}
309 
310 	if ((result=fdfs_load_tracker_group_ex(pTrackerGroup, \
311 			conf_filename, iniContext)) != 0)
312 	{
313 		return result;
314 	}
315 
316 	g_anti_steal_token = iniGetBoolValue(NULL, \
317 				"http.anti_steal.check_token", \
318 				iniContext, false);
319 	if (g_anti_steal_token)
320 	{
321 		char *anti_steal_secret_key;
322 
323 		anti_steal_secret_key = iniGetStrValue(NULL, \
324 					"http.anti_steal.secret_key", \
325 					iniContext);
326 		if (anti_steal_secret_key == NULL || \
327 			*anti_steal_secret_key == '\0')
328 		{
329 			logError("file: "__FILE__", line: %d, " \
330 				"param \"http.anti_steal.secret_key\""\
331 				" not exist or is empty", __LINE__);
332 			return EINVAL;
333 		}
334 
335 		buffer_strcpy(&g_anti_steal_secret_key, anti_steal_secret_key);
336 	}
337 
338 	g_tracker_server_http_port = iniGetIntValue(NULL, \
339 				"http.tracker_server_port", \
340 				iniContext, 80);
341 	if (g_tracker_server_http_port <= 0)
342 	{
343 		g_tracker_server_http_port = 80;
344 	}
345 
346 	if ((result=fdfs_connection_pool_init(conf_filename, iniContext)) != 0)
347 	{
348 		return result;
349 	}
350 
351 	load_fdfs_parameters_from_tracker = iniGetBoolValue(NULL, \
352 				"load_fdfs_parameters_from_tracker", \
353 				iniContext, false);
354 	if (load_fdfs_parameters_from_tracker)
355 	{
356 		fdfs_get_params_from_tracker(&use_storage_id);
357 	}
358 	else
359 	{
360 		use_storage_id = iniGetBoolValue(NULL, "use_storage_id", \
361 				iniContext, false);
362 		if (use_storage_id)
363 		{
364 			result = fdfs_load_storage_ids_from_file( \
365 					conf_filename, iniContext);
366 		}
367 	}
368 
369 #ifdef DEBUG_FLAG
370 	logDebug("base_path=%s, " \
371 		"connect_timeout=%d, "\
372 		"network_timeout=%d, "\
373 		"tracker_server_count=%d, " \
374 		"anti_steal_token=%d, " \
375 		"anti_steal_secret_key length=%d, " \
376 		"use_connection_pool=%d, " \
377 		"g_connection_pool_max_idle_time=%ds, " \
378 		"use_storage_id=%d, storage server id count: %d\n", \
379 		g_fdfs_base_path, g_fdfs_connect_timeout, \
380 		g_fdfs_network_timeout, pTrackerGroup->server_count, \
381 		g_anti_steal_token, g_anti_steal_secret_key.length, \
382 		g_use_connection_pool, g_connection_pool_max_idle_time, \
383 		use_storage_id, g_storage_ids_by_id.count);
384 #endif
385 
386 	return 0;
387 }
388 
fdfs_client_init_from_buffer_ex(TrackerServerGroup * pTrackerGroup,const char * buffer)389 int fdfs_client_init_from_buffer_ex(TrackerServerGroup *pTrackerGroup, \
390 		const char *buffer)
391 {
392 	IniContext iniContext;
393 	char *new_buff;
394 	int result;
395 
396 	new_buff = strdup(buffer);
397 	if (new_buff == NULL)
398 	{
399 		logError("file: "__FILE__", line: %d, " \
400 			"strdup %d bytes fail", __LINE__, (int)strlen(buffer));
401 		return ENOMEM;
402 	}
403 
404 	result = iniLoadFromBuffer(new_buff, &iniContext);
405 	free(new_buff);
406 	if (result != 0)
407 	{
408 		logError("file: "__FILE__", line: %d, " \
409 			"load parameters from buffer fail, ret code: %d", \
410 			 __LINE__, result);
411 		return result;
412 	}
413 
414 	result = fdfs_client_do_init_ex(pTrackerGroup, "buffer", &iniContext);
415 	iniFreeContext(&iniContext);
416 	return result;
417 }
418 
fdfs_client_init_ex(TrackerServerGroup * pTrackerGroup,const char * conf_filename)419 int fdfs_client_init_ex(TrackerServerGroup *pTrackerGroup, \
420 		const char *conf_filename)
421 {
422 	IniContext iniContext;
423 	int result;
424 
425 	if ((result=iniLoadFromFile(conf_filename, &iniContext)) != 0)
426 	{
427 		logError("file: "__FILE__", line: %d, " \
428 			"load conf file \"%s\" fail, ret code: %d", \
429 			__LINE__, conf_filename, result);
430 		return result;
431 	}
432 
433 	result = fdfs_client_do_init_ex(pTrackerGroup, conf_filename, \
434 				&iniContext);
435 	iniFreeContext(&iniContext);
436 	return result;
437 }
438 
fdfs_copy_tracker_group(TrackerServerGroup * pDestTrackerGroup,TrackerServerGroup * pSrcTrackerGroup)439 int fdfs_copy_tracker_group(TrackerServerGroup *pDestTrackerGroup, \
440 		TrackerServerGroup *pSrcTrackerGroup)
441 {
442 	int bytes;
443 	TrackerServerInfo *pDestServer;
444 	TrackerServerInfo *pDestServerEnd;
445 
446 	bytes = sizeof(TrackerServerInfo) * pSrcTrackerGroup->server_count;
447 	pDestTrackerGroup->servers = (TrackerServerInfo *)malloc(bytes);
448 	if (pDestTrackerGroup->servers == NULL)
449 	{
450 		logError("file: "__FILE__", line: %d, "
451 			"malloc %d bytes fail", __LINE__, bytes);
452 		return errno != 0 ? errno : ENOMEM;
453 	}
454 
455 	pDestTrackerGroup->server_index = 0;
456 	pDestTrackerGroup->leader_index = 0;
457 	pDestTrackerGroup->server_count = pSrcTrackerGroup->server_count;
458 	memcpy(pDestTrackerGroup->servers, pSrcTrackerGroup->servers, bytes);
459 
460 	pDestServerEnd = pDestTrackerGroup->servers +
461 			pDestTrackerGroup->server_count;
462 	for (pDestServer=pDestTrackerGroup->servers;
463 		pDestServer<pDestServerEnd; pDestServer++)
464 	{
465         fdfs_server_sock_reset(pDestServer);
466 	}
467 
468 	return 0;
469 }
470 
fdfs_tracker_group_equals(TrackerServerGroup * pGroup1,TrackerServerGroup * pGroup2)471 bool fdfs_tracker_group_equals(TrackerServerGroup *pGroup1,
472         TrackerServerGroup *pGroup2)
473 {
474     TrackerServerInfo *pServer1;
475     TrackerServerInfo *pServer2;
476     TrackerServerInfo *pEnd1;
477 
478     if (pGroup1->server_count != pGroup2->server_count)
479     {
480         return false;
481     }
482 
483     pEnd1 = pGroup1->servers + pGroup1->server_count;
484     pServer1 = pGroup1->servers;
485     pServer2 = pGroup2->servers;
486     while (pServer1 < pEnd1)
487     {
488         if (!fdfs_server_equal(pServer1, pServer2))
489         {
490             return false;
491         }
492 
493         pServer1++;
494         pServer2++;
495     }
496 
497     return true;
498 }
499 
fdfs_client_destroy_ex(TrackerServerGroup * pTrackerGroup)500 void fdfs_client_destroy_ex(TrackerServerGroup *pTrackerGroup)
501 {
502 	if (pTrackerGroup->servers != NULL)
503 	{
504 		free(pTrackerGroup->servers);
505 		pTrackerGroup->servers = NULL;
506 
507 		pTrackerGroup->server_count = 0;
508 		pTrackerGroup->server_index = 0;
509 	}
510 }
511 
fdfs_get_file_ext_name_ex(const char * filename,const bool twoExtName)512 const char *fdfs_get_file_ext_name_ex(const char *filename,
513 	const bool twoExtName)
514 {
515 	const char *fileExtName;
516 	const char *p;
517 	const char *pStart;
518 	int extNameLen;
519 
520 	fileExtName = strrchr(filename, '.');
521 	if (fileExtName == NULL)
522 	{
523 		return NULL;
524 	}
525 
526 	extNameLen = strlen(fileExtName + 1);
527 	if (extNameLen > FDFS_FILE_EXT_NAME_MAX_LEN)
528 	{
529 		return NULL;
530 	}
531 
532 	if (strchr(fileExtName + 1, '/') != NULL) //invalid extension name
533 	{
534 		return NULL;
535 	}
536 
537 	if (!twoExtName)
538 	{
539 		return fileExtName + 1;
540 	}
541 
542 	pStart = fileExtName - (FDFS_FILE_EXT_NAME_MAX_LEN - extNameLen) - 1;
543 	if (pStart < filename)
544 	{
545 		pStart = filename;
546 	}
547 
548 	p = fileExtName - 1;  //before .
549 	while ((p > pStart) && (*p != '.'))
550 	{
551 		p--;
552 	}
553 
554 	if (p > pStart)  //found (extension name have a dot)
555 	{
556 		if (strchr(p + 1, '/') == NULL)  //valid extension name
557 		{
558 			return p + 1;   //skip .
559 		}
560 	}
561 
562 	return fileExtName + 1;  //skip .
563 }
564 
565