comparison src/gt_guid.c @ 0:d39e1d0d75b6

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