rev |
line source |
paulo@0
|
1 /*
|
paulo@0
|
2 * $Id: gt_guid.c,v 1.18 2006/01/28 16:57:56 mkern Exp $
|
paulo@0
|
3 *
|
paulo@0
|
4 * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net)
|
paulo@0
|
5 *
|
paulo@0
|
6 * This program is free software; you can redistribute it and/or modify it
|
paulo@0
|
7 * under the terms of the GNU General Public License as published by the
|
paulo@0
|
8 * Free Software Foundation; either version 2, or (at your option) any
|
paulo@0
|
9 * later version.
|
paulo@0
|
10 *
|
paulo@0
|
11 * This program is distributed in the hope that it will be useful, but
|
paulo@0
|
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
paulo@0
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
paulo@0
|
14 * General Public License for more details.
|
paulo@0
|
15 */
|
paulo@0
|
16
|
paulo@0
|
17 #include "gt_gnutella.h"
|
paulo@0
|
18 #include "sha1.h"
|
paulo@0
|
19
|
paulo@0
|
20 /*****************************************************************************/
|
paulo@0
|
21
|
paulo@0
|
22 /* global guid identifying this client */
|
paulo@0
|
23 gt_guid_t *GT_SELF_GUID;
|
paulo@0
|
24
|
paulo@0
|
25 /*****************************************************************************/
|
paulo@0
|
26
|
paulo@0
|
27 /* seed for generating unique numbers */
|
paulo@0
|
28 static unsigned int seed = 0;
|
paulo@0
|
29
|
paulo@0
|
30 /* map binary numbers to hexadecimal */
|
paulo@0
|
31 static char bin_to_hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
paulo@0
|
32 'a', 'b', 'c', 'd', 'e', 'f' };
|
paulo@0
|
33
|
paulo@0
|
34 /* guid filled with all zeroes */
|
paulo@0
|
35 static gt_guid_t zero_guid[GT_GUID_LEN] = { 0 };
|
paulo@0
|
36
|
paulo@0
|
37 /*****************************************************************************/
|
paulo@0
|
38
|
paulo@0
|
39 /* TODO: use /dev/urandom when available */
|
paulo@0
|
40 static unsigned int rng_seed (void)
|
paulo@0
|
41 {
|
paulo@0
|
42 sha1_state_t sha1;
|
paulo@0
|
43 struct timeval tv;
|
paulo@0
|
44 unsigned int seed;
|
paulo@0
|
45 int i;
|
paulo@0
|
46 unsigned char hash[SHA1_BINSIZE];
|
paulo@0
|
47
|
paulo@0
|
48 gt_sha1_init (&sha1);
|
paulo@0
|
49 platform_gettimeofday (&tv, NULL);
|
paulo@0
|
50
|
paulo@0
|
51 gt_sha1_append (&sha1, &tv.tv_usec, sizeof (tv.tv_usec));
|
paulo@0
|
52 gt_sha1_append (&sha1, &tv.tv_sec, sizeof (tv.tv_sec));
|
paulo@0
|
53
|
paulo@0
|
54 #ifdef HAVE_GETPID
|
paulo@0
|
55 {
|
paulo@0
|
56 pid_t pid = getpid();
|
paulo@0
|
57 gt_sha1_append (&sha1, &pid, sizeof (pid));
|
paulo@0
|
58 }
|
paulo@0
|
59 #endif
|
paulo@0
|
60
|
paulo@0
|
61 #ifdef WIN32
|
paulo@0
|
62 {
|
paulo@0
|
63 DWORD process_id = GetCurrentProcessId();
|
paulo@0
|
64 gt_sha1_append (&sha1, &process_id, sizeof (process_id));
|
paulo@0
|
65 }
|
paulo@0
|
66 #endif
|
paulo@0
|
67
|
paulo@0
|
68 #ifdef HAVE_GETPPID
|
paulo@0
|
69 {
|
paulo@0
|
70 pid_t ppid = getppid();
|
paulo@0
|
71 gt_sha1_append (&sha1, &ppid, sizeof (ppid));
|
paulo@0
|
72 }
|
paulo@0
|
73 #endif /* WIN32 */
|
paulo@0
|
74
|
paulo@0
|
75 memset (hash, 0, sizeof (hash));
|
paulo@0
|
76 gt_sha1_finish (&sha1, hash);
|
paulo@0
|
77
|
paulo@0
|
78 seed = 0;
|
paulo@0
|
79 i = 0;
|
paulo@0
|
80
|
paulo@0
|
81 /* crush the hash into an unsigned int */
|
paulo@0
|
82 while (i < SHA1_BINSIZE)
|
paulo@0
|
83 {
|
paulo@0
|
84 unsigned int t;
|
paulo@0
|
85 size_t len;
|
paulo@0
|
86
|
paulo@0
|
87 t = 0;
|
paulo@0
|
88 len = MIN (sizeof (unsigned int), SHA1_BINSIZE - i);
|
paulo@0
|
89
|
paulo@0
|
90 memcpy (&t, &hash[i], len);
|
paulo@0
|
91
|
paulo@0
|
92 seed ^= t;
|
paulo@0
|
93 i += len;
|
paulo@0
|
94 }
|
paulo@0
|
95
|
paulo@0
|
96 return seed;
|
paulo@0
|
97 }
|
paulo@0
|
98
|
paulo@0
|
99 void gt_guid_init (gt_guid_t *guid)
|
paulo@0
|
100 {
|
paulo@0
|
101 int i;
|
paulo@0
|
102
|
paulo@0
|
103 if (!seed)
|
paulo@0
|
104 {
|
paulo@0
|
105 seed = rng_seed();
|
paulo@0
|
106 srand (seed);
|
paulo@0
|
107 }
|
paulo@0
|
108
|
paulo@0
|
109 for (i = GT_GUID_LEN - 1; i >= 0; i--)
|
paulo@0
|
110 guid[i] = 256.0 * rand() / (RAND_MAX + 1.0);
|
paulo@0
|
111
|
paulo@0
|
112 /* mark this GUID as coming from a "new" client */
|
paulo@0
|
113 guid[8] = 0xff;
|
paulo@0
|
114 guid[15] = 0x01;
|
paulo@0
|
115 }
|
paulo@0
|
116
|
paulo@0
|
117 gt_guid_t *gt_guid_new (void)
|
paulo@0
|
118 {
|
paulo@0
|
119 gt_guid_t *guid;
|
paulo@0
|
120
|
paulo@0
|
121 if (!(guid = malloc (GT_GUID_LEN)))
|
paulo@0
|
122 return NULL;
|
paulo@0
|
123
|
paulo@0
|
124 gt_guid_init (guid);
|
paulo@0
|
125
|
paulo@0
|
126 return guid;
|
paulo@0
|
127 }
|
paulo@0
|
128
|
paulo@0
|
129 int gt_guid_cmp (const gt_guid_t *a, const gt_guid_t *b)
|
paulo@0
|
130 {
|
paulo@0
|
131 if (!a)
|
paulo@0
|
132 return (b == NULL ? 0 : -1);
|
paulo@0
|
133 else if (!b)
|
paulo@0
|
134 return (a == NULL ? 0 : +1);
|
paulo@0
|
135
|
paulo@0
|
136 return memcmp (a, b, GT_GUID_LEN);
|
paulo@0
|
137 }
|
paulo@0
|
138
|
paulo@0
|
139 char *gt_guid_str (const gt_guid_t *guid)
|
paulo@0
|
140 {
|
paulo@0
|
141 static char buf[128];
|
paulo@0
|
142 unsigned char c;
|
paulo@0
|
143 int pos;
|
paulo@0
|
144 int len;
|
paulo@0
|
145
|
paulo@0
|
146 if (!guid)
|
paulo@0
|
147 return NULL;
|
paulo@0
|
148
|
paulo@0
|
149 pos = 0;
|
paulo@0
|
150 len = GT_GUID_LEN;
|
paulo@0
|
151
|
paulo@0
|
152 while (len-- > 0)
|
paulo@0
|
153 {
|
paulo@0
|
154 c = *guid++;
|
paulo@0
|
155
|
paulo@0
|
156 buf[pos++] = bin_to_hex[(c & 0xf0) >> 4];
|
paulo@0
|
157 buf[pos++] = bin_to_hex[(c & 0x0f)];
|
paulo@0
|
158 }
|
paulo@0
|
159
|
paulo@0
|
160 buf[pos] = 0;
|
paulo@0
|
161
|
paulo@0
|
162 return buf;
|
paulo@0
|
163 }
|
paulo@0
|
164
|
paulo@0
|
165 gt_guid_t *gt_guid_dup (const gt_guid_t *guid)
|
paulo@0
|
166 {
|
paulo@0
|
167 gt_guid_t *new_guid;
|
paulo@0
|
168
|
paulo@0
|
169 if (!(new_guid = malloc (GT_GUID_LEN)))
|
paulo@0
|
170 return NULL;
|
paulo@0
|
171
|
paulo@0
|
172 memcpy (new_guid, guid, GT_GUID_LEN);
|
paulo@0
|
173
|
paulo@0
|
174 return new_guid;
|
paulo@0
|
175 }
|
paulo@0
|
176
|
paulo@0
|
177 static unsigned char hex_char_to_bin (char x)
|
paulo@0
|
178 {
|
paulo@0
|
179 if (x >= '0' && x <= '9')
|
paulo@0
|
180 return (x - '0');
|
paulo@0
|
181
|
paulo@0
|
182 x = toupper (x);
|
paulo@0
|
183
|
paulo@0
|
184 return ((x - 'A') + 10);
|
paulo@0
|
185 }
|
paulo@0
|
186
|
paulo@0
|
187 static int hex_to_bin (const char *hex, unsigned char *bin, int len)
|
paulo@0
|
188 {
|
paulo@0
|
189 unsigned char value;
|
paulo@0
|
190
|
paulo@0
|
191 while (isxdigit (hex[0]) && isxdigit (hex[1]) && len-- > 0)
|
paulo@0
|
192 {
|
paulo@0
|
193 value = (hex_char_to_bin (*hex++) << 4) & 0xf0;
|
paulo@0
|
194 value |= (hex_char_to_bin (*hex++) & 0x0f);
|
paulo@0
|
195 *bin++ = value;
|
paulo@0
|
196 }
|
paulo@0
|
197
|
paulo@0
|
198 return (len <= 0) ? TRUE : FALSE;
|
paulo@0
|
199 }
|
paulo@0
|
200
|
paulo@0
|
201 gt_guid_t *gt_guid_bin (const char *guid_ascii)
|
paulo@0
|
202 {
|
paulo@0
|
203 gt_guid_t *guid;
|
paulo@0
|
204
|
paulo@0
|
205 if (!guid_ascii)
|
paulo@0
|
206 return NULL;
|
paulo@0
|
207
|
paulo@0
|
208 if (!(guid = malloc (GT_GUID_LEN)))
|
paulo@0
|
209 return NULL;
|
paulo@0
|
210
|
paulo@0
|
211 if (!hex_to_bin (guid_ascii, guid, GT_GUID_LEN))
|
paulo@0
|
212 {
|
paulo@0
|
213 free (guid);
|
paulo@0
|
214 return NULL;
|
paulo@0
|
215 }
|
paulo@0
|
216
|
paulo@0
|
217 return guid;
|
paulo@0
|
218 }
|
paulo@0
|
219
|
paulo@0
|
220 /*****************************************************************************/
|
paulo@0
|
221
|
paulo@0
|
222 BOOL gt_guid_is_empty (const gt_guid_t *guid)
|
paulo@0
|
223 {
|
paulo@0
|
224 if (!guid)
|
paulo@0
|
225 return TRUE;
|
paulo@0
|
226
|
paulo@0
|
227 return memcmp (guid, zero_guid, GT_GUID_LEN) == 0;
|
paulo@0
|
228 }
|
paulo@0
|
229
|
paulo@0
|
230 /*****************************************************************************/
|
paulo@0
|
231
|
paulo@0
|
232 /*
|
paulo@0
|
233 * Load the client GUID for this node.
|
paulo@0
|
234 */
|
paulo@0
|
235 static gt_guid_t *get_client_id (char *conf_path)
|
paulo@0
|
236 {
|
paulo@0
|
237 FILE *f;
|
paulo@0
|
238 gt_guid_t *client_id = NULL;
|
paulo@0
|
239 char *buf = NULL;
|
paulo@0
|
240
|
paulo@0
|
241 /*
|
paulo@0
|
242 * There are people who distribute giFT packages which include the
|
paulo@0
|
243 * developer's client-id file. These packages (mainly KCeasy derivatives,
|
paulo@0
|
244 * I think) are widely enough distributed that other gnutella developers
|
paulo@0
|
245 * have noticed the problem and notified me. To prevent this problem in
|
paulo@0
|
246 * future versions I have forced randomization of the GUID on each startup
|
paulo@0
|
247 * below. --mkern
|
paulo@0
|
248 */
|
paulo@0
|
249 #if 0
|
paulo@0
|
250 if ((f = fopen (gift_conf_path (conf_path), "r")))
|
paulo@0
|
251 {
|
paulo@0
|
252 while (file_read_line (f, &buf))
|
paulo@0
|
253 {
|
paulo@0
|
254 char *id;
|
paulo@0
|
255 char *line;
|
paulo@0
|
256
|
paulo@0
|
257 free (client_id);
|
paulo@0
|
258 client_id = NULL;
|
paulo@0
|
259
|
paulo@0
|
260 line = buf;
|
paulo@0
|
261 id = string_sep_set (&line, "\r\n");
|
paulo@0
|
262
|
paulo@0
|
263 if (string_isempty (id))
|
paulo@0
|
264 continue;
|
paulo@0
|
265
|
paulo@0
|
266 client_id = gt_guid_bin (id);
|
paulo@0
|
267 }
|
paulo@0
|
268
|
paulo@0
|
269 fclose (f);
|
paulo@0
|
270 }
|
paulo@0
|
271 #endif
|
paulo@0
|
272
|
paulo@0
|
273 /* TODO: regenerate when client guid is pretty old */
|
paulo@0
|
274 if (client_id != NULL)
|
paulo@0
|
275 return client_id;
|
paulo@0
|
276
|
paulo@0
|
277 /*
|
paulo@0
|
278 * Create a new client identifier
|
paulo@0
|
279 */
|
paulo@0
|
280 client_id = gt_guid_new ();
|
paulo@0
|
281 assert (client_id != NULL);
|
paulo@0
|
282
|
paulo@0
|
283 /* store the id in ~/.giFT/Gnutella/clientid */
|
paulo@0
|
284 if (!(f = fopen (gift_conf_path (conf_path), "w")))
|
paulo@0
|
285 {
|
paulo@0
|
286 GIFT_ERROR (("clientid storage file: %s", GIFT_STRERROR ()));
|
paulo@0
|
287 return client_id;
|
paulo@0
|
288 }
|
paulo@0
|
289
|
paulo@0
|
290 fprintf (f, "%s\n", gt_guid_str (client_id));
|
paulo@0
|
291 fclose (f);
|
paulo@0
|
292
|
paulo@0
|
293 return client_id;
|
paulo@0
|
294 }
|
paulo@0
|
295
|
paulo@0
|
296 void gt_guid_self_init (void)
|
paulo@0
|
297 {
|
paulo@0
|
298 GT_SELF_GUID = get_client_id ("Gnutella/client-id");
|
paulo@0
|
299
|
paulo@0
|
300 /* remove the old clientid file which used an inferior random number
|
paulo@0
|
301 * generator */
|
paulo@0
|
302 remove (gift_conf_path ("Gnutella/clientid"));
|
paulo@0
|
303 }
|
paulo@0
|
304
|
paulo@0
|
305 void gt_guid_self_cleanup (void)
|
paulo@0
|
306 {
|
paulo@0
|
307 free (GT_SELF_GUID);
|
paulo@0
|
308 GT_SELF_GUID = NULL;
|
paulo@0
|
309 }
|