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