The SILC Project

source navigation ]
identifier search ]
freetext search ]
file search ]

silc/lib/silccore/silcid.c

  1 /*
  2 
  3   id.c
  4 
  5   Author: Pekka Riikonen <priikone@silcnet.org>
  6 
  7   Copyright (C) 1997 - 2008 Pekka Riikonen
  8 
  9   This program is free software; you can redistribute it and/or modify
 10   it under the terms of the GNU General Public License as published by
 11   the Free Software Foundation; version 2 of the License.
 12 
 13   This program is distributed in the hope that it will be useful,
 14   but WITHOUT ANY WARRANTY; without even the implied warranty of
 15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16   GNU General Public License for more details.
 17 
 18 */
 19 /* $Id: silcid.c,v 1.19 2008/01/08 15:15:10 priikone Exp $ */
 20 
 21 #include "silc.h"
 22 #include "silcid.h"
 23 
 24 /* ID lengths (in bytes) without the IP address part */
 25 #define ID_SERVER_LEN_PART      4
 26 #define ID_CLIENT_LEN_PART      CLIENTID_HASH_LEN + 1
 27 #define ID_CHANNEL_LEN_PART     4
 28 
 29 /******************************************************************************
 30 
 31                                 ID Payload
 32 
 33 ******************************************************************************/
 34 
 35 struct SilcIDPayloadStruct {
 36   SilcIdType type;
 37   SilcUInt16 len;
 38   unsigned char *id;
 39 };
 40 
 41 /* Parses buffer and return ID payload into payload structure */
 42 
 43 SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
 44                                     SilcUInt32 payload_len)
 45 {
 46   SilcBufferStruct buffer;
 47   SilcIDPayload newp;
 48   int ret;
 49 
 50   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
 51   newp = silc_calloc(1, sizeof(*newp));
 52   if (!newp)
 53     return NULL;
 54 
 55   ret = silc_buffer_unformat(&buffer,
 56                              SILC_STR_UI_SHORT(&newp->type),
 57                              SILC_STR_UI_SHORT(&newp->len),
 58                              SILC_STR_END);
 59   if (ret == -1)
 60     goto err;
 61 
 62   if (newp->type > SILC_ID_CHANNEL)
 63     goto err;
 64 
 65   silc_buffer_pull(&buffer, 4);
 66 
 67   if (newp->len > silc_buffer_len(&buffer) ||
 68       newp->len > SILC_PACKET_MAX_ID_LEN)
 69     goto err;
 70 
 71   ret = silc_buffer_unformat(&buffer,
 72                              SILC_STR_DATA_ALLOC(&newp->id, newp->len),
 73                              SILC_STR_END);
 74   if (ret == -1)
 75     goto err;
 76 
 77   return newp;
 78 
 79  err:
 80   SILC_LOG_DEBUG(("Error parsing ID payload"));
 81   silc_free(newp);
 82   return NULL;
 83 }
 84 
 85 /* Return the ID directly from the raw payload data. */
 86 
 87 SilcBool silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
 88                                   SilcID *ret_id)
 89 {
 90   SilcBufferStruct buffer;
 91   SilcIdType type;
 92   SilcUInt16 idlen;
 93   unsigned char *id_data;
 94   int ret;
 95 
 96   if (!ret_id)
 97     return FALSE;
 98 
 99   silc_buffer_set(&buffer, (unsigned char *)data, len);
100   ret = silc_buffer_unformat(&buffer,
101                              SILC_STR_UI_SHORT(&type),
102                              SILC_STR_UI_SHORT(&idlen),
103                              SILC_STR_END);
104   if (ret == -1)
105     goto err;
106 
107   if (type > SILC_ID_CHANNEL)
108     goto err;
109 
110   silc_buffer_pull(&buffer, 4);
111 
112   if (idlen > silc_buffer_len(&buffer) || idlen > SILC_PACKET_MAX_ID_LEN)
113     goto err;
114 
115   ret = silc_buffer_unformat(&buffer,
116                              SILC_STR_DATA(&id_data, idlen),
117                              SILC_STR_END);
118   if (ret == -1)
119     goto err;
120 
121   ret_id->type = type;
122 
123   if (type == SILC_ID_CLIENT) {
124     if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.client_id,
125                         sizeof(SilcClientID)))
126       goto err;
127   } else if (type == SILC_ID_SERVER) {
128     if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.server_id,
129                         sizeof(SilcServerID)))
130       goto err;
131   } else {
132     if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.channel_id,
133                         sizeof(SilcChannelID)))
134       goto err;
135   }
136 
137   return TRUE;
138 
139  err:
140   SILC_LOG_DEBUG(("Error parsing ID payload"));
141   return FALSE;
142 }
143 
144 /* Encodes ID Payload */
145 
146 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
147 {
148   SilcBuffer buffer;
149   unsigned char id_data[32];
150   SilcUInt32 len;
151 
152   if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &len))
153     return NULL;
154   buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
155                                        len, type);
156   return buffer;
157 }
158 
159 SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
160                                        SilcUInt32 id_len, SilcIdType type)
161 {
162   SilcBuffer buffer;
163 
164   buffer = silc_buffer_alloc_size(4 + id_len);
165   if (!buffer)
166     return NULL;
167   silc_buffer_format(buffer,
168                      SILC_STR_UI_SHORT(type),
169                      SILC_STR_UI_SHORT(id_len),
170                      SILC_STR_DATA(id, id_len),
171                      SILC_STR_END);
172   return buffer;
173 }
174 
175 /* Free ID Payload */
176 
177 void silc_id_payload_free(SilcIDPayload payload)
178 {
179   if (payload) {
180     silc_free(payload->id);
181     silc_free(payload);
182   }
183 }
184 
185 /* Get ID type */
186 
187 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
188 {
189   return payload ? payload->type : 0;
190 }
191 
192 /* Get ID */
193 
194 SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
195                                 SilcUInt32 ret_id_len)
196 {
197   if (!payload)
198     return FALSE;
199   return silc_id_str2id(payload->id, payload->len, payload->type,
200                         ret_id, ret_id_len);
201 }
202 
203 /* Get raw ID data. Data is duplicated. */
204 
205 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
206 {
207   if (!payload)
208     return NULL;
209 
210   return silc_memdup(payload->id, payload->len);
211 }
212 
213 /* Get length of ID */
214 
215 SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload)
216 {
217   return payload ? payload->len : 0;
218 }
219 
220 /* Converts ID to string. */
221 
222 SilcBool silc_id_id2str(const void *id, SilcIdType type,
223                         unsigned char *ret_id, SilcUInt32 ret_id_size,
224                         SilcUInt32 *ret_id_len)
225 {
226   SilcServerID *server_id;
227   SilcClientID *client_id;
228   SilcChannelID *channel_id;
229   SilcUInt32 id_len = silc_id_get_len(id, type);
230 
231   if (id_len > ret_id_size)
232     return FALSE;
233 
234   if (ret_id_len)
235     *ret_id_len = id_len;
236 
237   if (id_len > SILC_PACKET_MAX_ID_LEN)
238     return FALSE;
239 
240   switch(type) {
241   case SILC_ID_SERVER:
242     server_id = (SilcServerID *)id;
243     memcpy(ret_id, server_id->ip.data, server_id->ip.data_len);
244     SILC_PUT16_MSB(server_id->port, &ret_id[server_id->ip.data_len]);
245     SILC_PUT16_MSB(server_id->rnd, &ret_id[server_id->ip.data_len + 2]);
246     return TRUE;
247     break;
248   case SILC_ID_CLIENT:
249     client_id = (SilcClientID *)id;
250     memcpy(ret_id, client_id->ip.data, client_id->ip.data_len);
251     ret_id[client_id->ip.data_len] = client_id->rnd;
252     memcpy(&ret_id[client_id->ip.data_len + 1], client_id->hash,
253            CLIENTID_HASH_LEN);
254     return TRUE;
255     break;
256   case SILC_ID_CHANNEL:
257     channel_id = (SilcChannelID *)id;
258     memcpy(ret_id, channel_id->ip.data, channel_id->ip.data_len);
259     SILC_PUT16_MSB(channel_id->port, &ret_id[channel_id->ip.data_len]);
260     SILC_PUT16_MSB(channel_id->rnd, &ret_id[channel_id->ip.data_len + 2]);
261     return TRUE;
262     break;
263   }
264 
265   return FALSE;
266 }
267 
268 /* Converts string to a ID */
269 
270 SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
271                         SilcIdType type, void *ret_id, SilcUInt32 ret_id_size)
272 {
273   if (id_len > SILC_PACKET_MAX_ID_LEN)
274     return FALSE;
275 
276   switch(type) {
277   case SILC_ID_SERVER:
278     {
279       SilcServerID *server_id = ret_id;
280 
281       if (id_len != ID_SERVER_LEN_PART + 4 &&
282           id_len != ID_SERVER_LEN_PART + 16)
283         return FALSE;
284 
285       if (ret_id_size < sizeof(SilcServerID))
286         return FALSE;
287 
288       memset(ret_id, 0, ret_id_size);
289       memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 4 ?
290                                       16 : 4));
291       server_id->ip.data_len = (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4);
292       SILC_GET16_MSB(server_id->port, &id[server_id->ip.data_len]);
293       SILC_GET16_MSB(server_id->rnd, &id[server_id->ip.data_len + 2]);
294       return TRUE;
295     }
296     break;
297   case SILC_ID_CLIENT:
298     {
299       SilcClientID *client_id = ret_id;
300 
301       if (id_len != ID_CLIENT_LEN_PART + 4 &&
302           id_len != ID_CLIENT_LEN_PART + 16)
303         return FALSE;
304 
305       if (ret_id_size < sizeof(SilcClientID))
306         return FALSE;
307 
308       memset(ret_id, 0, ret_id_size);
309       memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 4 ?
310                                       16 : 4));
311       client_id->ip.data_len = (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4);
312       client_id->rnd = id[client_id->ip.data_len];
313       memcpy(client_id->hash, &id[client_id->ip.data_len + 1],
314              CLIENTID_HASH_LEN);
315       return TRUE;
316     }
317     break;
318   case SILC_ID_CHANNEL:
319     {
320       SilcChannelID *channel_id = ret_id;
321 
322       if (id_len != ID_CHANNEL_LEN_PART + 4 &&
323           id_len != ID_CHANNEL_LEN_PART + 16)
324         return FALSE;
325 
326       if (ret_id_size < sizeof(SilcChannelID))
327         return FALSE;
328 
329       memset(ret_id, 0, ret_id_size);
330       memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 4 ?
331                                        16 : 4));
332       channel_id->ip.data_len = (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4);
333       SILC_GET16_MSB(channel_id->port, &id[channel_id->ip.data_len]);
334       SILC_GET16_MSB(channel_id->rnd, &id[channel_id->ip.data_len + 2]);
335       return TRUE;
336     }
337     break;
338   }
339 
340   return FALSE;
341 }
342 
343 /* Converts string to ID */
344 
345 SilcBool silc_id_str2id2(const unsigned char *id, SilcUInt32 id_len,
346                          SilcIdType type, SilcID *ret_id)
347 {
348   if (!ret_id)
349     return FALSE;
350 
351   ret_id->type = type;
352 
353   switch (type) {
354   case SILC_ID_CLIENT:
355     return silc_id_str2id(id, id_len, type, &ret_id->u.client_id,
356                           sizeof(ret_id->u.client_id));
357     break;
358 
359   case SILC_ID_SERVER:
360     return silc_id_str2id(id, id_len, type, &ret_id->u.server_id,
361                           sizeof(ret_id->u.server_id));
362     break;
363 
364   case SILC_ID_CHANNEL:
365     return silc_id_str2id(id, id_len, type, &ret_id->u.channel_id,
366                           sizeof(ret_id->u.channel_id));
367     break;
368   }
369 
370   return FALSE;
371 }
372 
373 /* Returns length of the ID */
374 
375 SilcUInt32 silc_id_get_len(const void *id, SilcIdType type)
376 {
377   switch(type) {
378   case SILC_ID_SERVER:
379     {
380       SilcServerID *server_id = (SilcServerID *)id;
381       return ID_SERVER_LEN_PART + server_id->ip.data_len;
382     }
383     break;
384   case SILC_ID_CLIENT:
385     {
386       SilcClientID *client_id = (SilcClientID *)id;
387       return ID_CLIENT_LEN_PART + client_id->ip.data_len;
388     }
389     break;
390   case SILC_ID_CHANNEL:
391     {
392       SilcChannelID *channel_id = (SilcChannelID *)id;
393       return ID_CHANNEL_LEN_PART + channel_id->ip.data_len;
394     }
395     break;
396   }
397 
398   return 0;
399 }
400 
401 /* Duplicate ID data */
402 
403 void *silc_id_dup(const void *id, SilcIdType type)
404 {
405   switch(type) {
406   case SILC_ID_SERVER:
407     {
408       SilcServerID *server_id = (SilcServerID *)id;
409       return silc_memdup(server_id, sizeof(*server_id));
410     }
411     break;
412   case SILC_ID_CLIENT:
413     {
414       SilcClientID *client_id = (SilcClientID *)id;
415       return silc_memdup(client_id, sizeof(*client_id));
416     }
417     break;
418   case SILC_ID_CHANNEL:
419     {
420       SilcChannelID *channel_id = (SilcChannelID *)id;
421       return silc_memdup(channel_id, sizeof(*channel_id));
422     }
423     break;
424   }
425 
426   return NULL;
427 }
428 
429 /**************************** Utility functions *****************************/
430 
431 /* Hash a ID. The `user_context' is the ID type. */
432 
433 SilcUInt32 silc_hash_id(void *key, void *user_context)
434 {
435   SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
436   SilcUInt32 h = 0;
437   int i;
438 
439   switch (id_type) {
440   case SILC_ID_CLIENT:
441     {
442       SilcClientID *id = (SilcClientID *)key;
443 
444       /* The client ID is hashed by hashing the hash of the ID
445          (which is a truncated MD5 hash of the nickname) so that we
446          can access the entry from the cache with both Client ID but
447          with just a hash from the ID as well. */
448       return silc_hash_client_id_hash(id->hash, NULL);
449     }
450     break;
451   case SILC_ID_SERVER:
452     {
453       SilcServerID *id = (SilcServerID *)key;
454 
455       h = id->port * id->rnd;
456       for (i = 0; i < id->ip.data_len; i++)
457         h ^= id->ip.data[i];
458 
459       return h;
460     }
461     break;
462   case SILC_ID_CHANNEL:
463     {
464       SilcChannelID *id = (SilcChannelID *)key;
465 
466       h = id->port * id->rnd;
467       for (i = 0; i < id->ip.data_len; i++)
468         h ^= id->ip.data[i];
469 
470       return h;
471     }
472     break;
473   default:
474     break;
475   }
476 
477   return h;
478 }
479 
480 /* Hash Client ID's hash. */
481 
482 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
483 {
484   int i;
485   unsigned char *hash = key;
486   SilcUInt32 h = 0, g;
487 
488   for (i = 0; i < CLIENTID_HASH_LEN; i++) {
489     h = (h << 4) + hash[i];
490     if ((g = h & 0xf0000000)) {
491       h = h ^ (g >> 24);
492       h = h ^ g;
493     }
494   }
495 
496   return h;
497 }
498 
499 /* Compares two ID's. May be used as SilcHashTable comparison function.
500    The Client ID's compares only the hash of the Client ID not any other
501    part of the Client ID. Other ID's are fully compared. */
502 
503 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
504 {
505   SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
506   return (id_type == SILC_ID_CLIENT ?
507           SILC_ID_COMPARE_HASH((SilcClientID *)key1, (SilcClientID *)key2) :
508           SILC_ID_COMPARE_TYPE(key1, key2, id_type));
509 }
510 
511 /* Compares two ID's. Compares full IDs. */
512 
513 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
514 {
515   SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
516   return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
517 }
518 
519 /* Compare two Client ID's entirely and not just the hash from the ID. */
520 
521 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
522                                      void *user_context)
523 {
524   return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);
525 }
526 

This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse