5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2008 Pekka Riikonen
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.
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.
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
29 /******************************************************************************
33 ******************************************************************************/
35 struct SilcIDPayloadStruct {
41 /* Parses buffer and return ID payload into payload structure */
43 SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
44 SilcUInt32 payload_len)
46 SilcBufferStruct buffer;
50 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
51 newp = silc_calloc(1, sizeof(*newp));
55 ret = silc_buffer_unformat(&buffer,
56 SILC_STR_UI_SHORT(&newp->type),
57 SILC_STR_UI_SHORT(&newp->len),
62 if (newp->type > SILC_ID_CHANNEL)
65 silc_buffer_pull(&buffer, 4);
67 if (newp->len > silc_buffer_len(&buffer) ||
68 newp->len > SILC_PACKET_MAX_ID_LEN)
71 ret = silc_buffer_unformat(&buffer,
72 SILC_STR_DATA_ALLOC(&newp->id, newp->len),
80 SILC_LOG_DEBUG(("Error parsing ID payload"));
85 /* Return the ID directly from the raw payload data. */
87 SilcBool silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len,
90 SilcBufferStruct buffer;
93 unsigned char *id_data;
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),
107 if (type > SILC_ID_CHANNEL)
110 silc_buffer_pull(&buffer, 4);
112 if (idlen > silc_buffer_len(&buffer) || idlen > SILC_PACKET_MAX_ID_LEN)
115 ret = silc_buffer_unformat(&buffer,
116 SILC_STR_DATA(&id_data, idlen),
123 if (type == SILC_ID_CLIENT) {
124 if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.client_id,
125 sizeof(SilcClientID)))
127 } else if (type == SILC_ID_SERVER) {
128 if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.server_id,
129 sizeof(SilcServerID)))
132 if (!silc_id_str2id(id_data, idlen, type, &ret_id->u.channel_id,
133 sizeof(SilcChannelID)))
140 SILC_LOG_DEBUG(("Error parsing ID payload"));
144 /* Encodes ID Payload */
146 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
149 unsigned char id_data[32];
152 if (!silc_id_id2str(id, type, id_data, sizeof(id_data), &len))
154 buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
159 SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
160 SilcUInt32 id_len, SilcIdType type)
164 buffer = silc_buffer_alloc_size(4 + id_len);
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),
175 /* Free ID Payload */
177 void silc_id_payload_free(SilcIDPayload payload)
180 silc_free(payload->id);
187 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
189 return payload ? payload->type : 0;
194 SilcBool silc_id_payload_get_id(SilcIDPayload payload, void *ret_id,
195 SilcUInt32 ret_id_len)
199 return silc_id_str2id(payload->id, payload->len, payload->type,
203 /* Get raw ID data. Data is duplicated. */
205 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
210 return silc_memdup(payload->id, payload->len);
213 /* Get length of ID */
215 SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload)
217 return payload ? payload->len : 0;
220 /* Converts ID to string. */
222 SilcBool silc_id_id2str(const void *id, SilcIdType type,
223 unsigned char *ret_id, SilcUInt32 ret_id_size,
224 SilcUInt32 *ret_id_len)
226 SilcServerID *server_id;
227 SilcClientID *client_id;
228 SilcChannelID *channel_id;
229 SilcUInt32 id_len = silc_id_get_len(id, type);
231 if (id_len > ret_id_size)
235 *ret_id_len = id_len;
237 if (id_len > SILC_PACKET_MAX_ID_LEN)
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]);
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,
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]);
268 /* Converts string to a ID */
270 SilcBool silc_id_str2id(const unsigned char *id, SilcUInt32 id_len,
271 SilcIdType type, void *ret_id, SilcUInt32 ret_id_size)
273 if (id_len > SILC_PACKET_MAX_ID_LEN)
279 SilcServerID *server_id = ret_id;
281 if (id_len != ID_SERVER_LEN_PART + 4 &&
282 id_len != ID_SERVER_LEN_PART + 16)
285 if (ret_id_size < sizeof(SilcServerID))
288 memset(ret_id, 0, ret_id_size);
289 memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 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]);
299 SilcClientID *client_id = ret_id;
301 if (id_len != ID_CLIENT_LEN_PART + 4 &&
302 id_len != ID_CLIENT_LEN_PART + 16)
305 if (ret_id_size < sizeof(SilcClientID))
308 memset(ret_id, 0, ret_id_size);
309 memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 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],
318 case SILC_ID_CHANNEL:
320 SilcChannelID *channel_id = ret_id;
322 if (id_len != ID_CHANNEL_LEN_PART + 4 &&
323 id_len != ID_CHANNEL_LEN_PART + 16)
326 if (ret_id_size < sizeof(SilcChannelID))
329 memset(ret_id, 0, ret_id_size);
330 memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 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]);
343 /* Converts string to ID */
345 SilcBool silc_id_str2id2(const unsigned char *id, SilcUInt32 id_len,
346 SilcIdType type, SilcID *ret_id)
355 return silc_id_str2id(id, id_len, type, &ret_id->u.client_id,
356 sizeof(ret_id->u.client_id));
360 return silc_id_str2id(id, id_len, type, &ret_id->u.server_id,
361 sizeof(ret_id->u.server_id));
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));
373 /* Returns length of the ID */
375 SilcUInt32 silc_id_get_len(const void *id, SilcIdType type)
380 SilcServerID *server_id = (SilcServerID *)id;
381 return ID_SERVER_LEN_PART + server_id->ip.data_len;
386 SilcClientID *client_id = (SilcClientID *)id;
387 return ID_CLIENT_LEN_PART + client_id->ip.data_len;
390 case SILC_ID_CHANNEL:
392 SilcChannelID *channel_id = (SilcChannelID *)id;
393 return ID_CHANNEL_LEN_PART + channel_id->ip.data_len;
401 /* Duplicate ID data */
403 void *silc_id_dup(const void *id, SilcIdType type)
408 SilcServerID *server_id = (SilcServerID *)id;
409 return silc_memdup(server_id, sizeof(*server_id));
414 SilcClientID *client_id = (SilcClientID *)id;
415 return silc_memdup(client_id, sizeof(*client_id));
418 case SILC_ID_CHANNEL:
420 SilcChannelID *channel_id = (SilcChannelID *)id;
421 return silc_memdup(channel_id, sizeof(*channel_id));
429 /**************************** Utility functions *****************************/
431 /* Hash a ID. The `user_context' is the ID type. */
433 SilcUInt32 silc_hash_id(void *key, void *user_context)
435 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
442 SilcClientID *id = (SilcClientID *)key;
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);
453 SilcServerID *id = (SilcServerID *)key;
455 h = id->port * id->rnd;
456 for (i = 0; i < id->ip.data_len; i++)
462 case SILC_ID_CHANNEL:
464 SilcChannelID *id = (SilcChannelID *)key;
466 h = id->port * id->rnd;
467 for (i = 0; i < id->ip.data_len; i++)
480 /* Hash Client ID's hash. */
482 SilcUInt32 silc_hash_client_id_hash(void *key, void *user_context)
485 unsigned char *hash = key;
488 for (i = 0; i < CLIENTID_HASH_LEN; i++) {
489 h = (h << 4) + hash[i];
490 if ((g = h & 0xf0000000)) {
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. */
503 SilcBool silc_hash_id_compare(void *key1, void *key2, void *user_context)
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));
511 /* Compares two ID's. Compares full IDs. */
513 SilcBool silc_hash_id_compare_full(void *key1, void *key2, void *user_context)
515 SilcIdType id_type = (SilcIdType)SILC_PTR_TO_32(user_context);
516 return SILC_ID_COMPARE_TYPE(key1, key2, id_type);
519 /* Compare two Client ID's entirely and not just the hash from the ID. */
521 SilcBool silc_hash_client_id_compare(void *key1, void *key2,
524 return SILC_ID_COMPARE_TYPE(key1, key2, SILC_ID_CLIENT);