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 #include <time.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <netinet/in.h>
19 #include "logger.h"
20 #include "shared_func.h"
21 #include "local_ip_func.h"
22 #include "id_generator.h"
23
id_generator_init_extra_ex(struct idg_context * context,const char * filename,const int machine_id,const int mid_bits,const int extra_bits,const int sn_bits,const mode_t mode)24 int id_generator_init_extra_ex(struct idg_context *context, const char *filename,
25 const int machine_id, const int mid_bits, const int extra_bits,
26 const int sn_bits, const mode_t mode)
27 {
28 int result;
29 int mid;
30 if (mid_bits < 2 || mid_bits > 20)
31 {
32 logError("file: "__FILE__", line: %d, "
33 "invalid bits of machine id: %d",
34 __LINE__, mid_bits);
35 context->fd = -1;
36 return EINVAL;
37 }
38 if (extra_bits < 0 || extra_bits > 16)
39 {
40 logError("file: "__FILE__", line: %d, "
41 "invalid bits of extra data: %d",
42 __LINE__, extra_bits);
43 context->fd = -1;
44 return EINVAL;
45 }
46 if (sn_bits < 8)
47 {
48 logError("file: "__FILE__", line: %d, "
49 "invalid bits of serial no: %d < 8",
50 __LINE__, sn_bits);
51 context->fd = -1;
52 return EINVAL;
53 }
54 if (mid_bits + extra_bits + sn_bits > 32)
55 {
56 logError("file: "__FILE__", line: %d, "
57 "invalid mid_bits + extra_bits + sn_bits: %d > 32",
58 __LINE__, mid_bits + extra_bits + sn_bits);
59 context->fd = -1;
60 return EINVAL;
61 }
62
63 if (machine_id < 0 || machine_id >= (1 << mid_bits))
64 {
65 logError("file: "__FILE__", line: %d, "
66 "invalid machine id: %d",
67 __LINE__, machine_id);
68 context->fd = -1;
69 return EINVAL;
70 }
71 if (machine_id != 0)
72 {
73 mid = machine_id;
74 }
75 else
76 {
77 const char *local_ip;
78 const char *private_ip;
79 struct in_addr ip_addr;
80
81 private_ip = get_first_local_private_ip();
82 if (private_ip != NULL)
83 {
84 local_ip = private_ip;
85 }
86 else
87 {
88 local_ip = get_first_local_ip();
89 if (local_ip == NULL)
90 {
91 logError("file: "__FILE__", line: %d, "
92 "can't get local ip address", __LINE__);
93 context->fd = -1;
94 return ENOENT;
95 }
96 else if (strcmp(local_ip, LOCAL_LOOPBACK_IP) == 0)
97 {
98 logWarning("file: "__FILE__", line: %d, "
99 "can't get local ip address, set to %s",
100 __LINE__, LOCAL_LOOPBACK_IP);
101 }
102 }
103
104 if (inet_pton(AF_INET, local_ip, &ip_addr) != 1)
105 {
106 logError("file: "__FILE__", line: %d, "
107 "invalid local ip address: %s",
108 __LINE__, local_ip);
109 context->fd = -1;
110 return EINVAL;
111 }
112
113 logDebug("ip_addr: %s, s_addr: 0x%08X",
114 local_ip, ip_addr.s_addr);
115
116 mid = ntohl(ip_addr.s_addr) & ((1 << mid_bits) - 1);
117 }
118
119 if ((context->fd = open(filename, O_RDWR)) < 0)
120 {
121 if (errno == ENOENT)
122 {
123 mode_t old_mode;
124 old_mode = umask(0);
125 if ((context->fd=open(filename, O_RDWR | O_CREAT, mode)) < 0)
126 {
127 result = errno != 0 ? errno : EACCES;
128 }
129 else
130 {
131 result = 0;
132 }
133 umask(old_mode);
134 }
135 else
136 {
137 result = errno != 0 ? errno : EACCES;
138 }
139
140 if (result != 0)
141 {
142 logError("file: "__FILE__", line: %d, "
143 "open file \"%s\" fail, "
144 "errno: %d, error info: %s", __LINE__,
145 filename, result, STRERROR(result));
146 return result;
147 }
148 }
149
150 context->machine_id = mid;
151 context->mid_bits = mid_bits;
152 context->extra_bits = extra_bits;
153 context->sn_bits = sn_bits;
154 context->mes_bits_sum = mid_bits + extra_bits + sn_bits;
155 context->masked_mid = ((int64_t)mid) << (extra_bits + sn_bits);
156 context->extra_mask = ((int64_t)1 << (extra_bits + sn_bits)) -
157 ((int64_t)1 << sn_bits);
158 context->sn_mask = ((int64_t)1 << sn_bits) - 1;
159
160 logDebug("mid: 0x%08X, masked_mid: 0x%08"PRIX64", extra_mask: 0x%08"PRIX64", "
161 "sn_mask: 0x%08"PRIX64, mid, context->masked_mid,
162 context->extra_mask, context->sn_mask);
163
164 return 0;
165 }
166
id_generator_init_extra(struct idg_context * context,const char * filename,const int machine_id,const int mid_bits,const int extra_bits,const int sn_bits)167 int id_generator_init_extra(struct idg_context *context, const char *filename,
168 const int machine_id, const int mid_bits, const int extra_bits,
169 const int sn_bits)
170 {
171 return id_generator_init_extra_ex(context, filename,
172 machine_id, mid_bits, extra_bits, sn_bits,
173 ID_GENERATOR_DEFAULT_FILE_MODE);
174 }
175
id_generator_destroy(struct idg_context * context)176 void id_generator_destroy(struct idg_context *context)
177 {
178 if (context->fd >= 0)
179 {
180 close(context->fd);
181 context->fd = -1;
182 }
183 }
184
id_generator_next_extra_ptr(struct idg_context * context,const int * extra,int64_t * id)185 int id_generator_next_extra_ptr(struct idg_context *context,
186 const int *extra, int64_t *id)
187 {
188 int result;
189 int len;
190 int bytes;
191 int new_extra;
192 int64_t sn;
193 char buff[32];
194 char *endptr;
195
196 if ((result=file_write_lock(context->fd)) != 0)
197 {
198 *id = 0;
199 return result;
200 }
201
202 do
203 {
204 if (lseek(context->fd, 0L, SEEK_SET) == -1)
205 {
206 result = errno != 0 ? errno : EACCES;
207 logError("file: "__FILE__", line: %d, "
208 "file lseek fail, "
209 "errno: %d, error info: %s", __LINE__,
210 result, STRERROR(result));
211 sn = 0;
212 break;
213 }
214
215 if ((bytes=read(context->fd, buff, sizeof(buff) - 1)) < 0)
216 {
217 result = errno != 0 ? errno : EACCES;
218 logError("file: "__FILE__", line: %d, "
219 "file read fail, "
220 "errno: %d, error info: %s", __LINE__,
221 result, STRERROR(result));
222 sn = 0;
223 break;
224 }
225 *(buff + bytes) = '\0';
226
227 sn = strtoll(buff, &endptr, 10);
228 ++sn;
229
230 if (lseek(context->fd, 0L, SEEK_SET) == -1)
231 {
232 result = errno != 0 ? errno : EACCES;
233 logError("file: "__FILE__", line: %d, "
234 "cal lseek fail, "
235 "errno: %d, error info: %s", __LINE__,
236 result, STRERROR(result));
237 break;
238 }
239
240 len = sprintf(buff, "%-20"PRId64, sn);
241 if ((bytes=write(context->fd, buff, len)) != len)
242 {
243 result = errno != 0 ? errno : EACCES;
244 logError("file: "__FILE__", line: %d, "
245 "file write %d bytes fail, written: %d bytes, "
246 "errno: %d, error info: %s", __LINE__,
247 len, bytes, result, STRERROR(result));
248 break;
249 }
250 } while (0);
251
252 file_unlock(context->fd);
253
254 if (extra == NULL)
255 {
256 new_extra = sn % (1 << context->extra_bits);
257 }
258 else
259 {
260 new_extra = *extra;
261 }
262
263 *id = (((int64_t)time(NULL)) << context->mes_bits_sum) |
264 context->masked_mid |
265 ((new_extra << context->sn_bits) & context->extra_mask) |
266 (sn & context->sn_mask);
267 return result;
268 }
269