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