annotate 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
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 }