updates.
[silc.git] / lib / silccore / silcid.c
1 /*
2
3   id.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2001 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silcid.h"
24
25 /* ID lengths (in bytes) without the IP address part */
26 #define ID_SERVER_LEN_PART      4
27 #define ID_CLIENT_LEN_PART      CLIENTID_HASH_LEN + 1
28 #define ID_CHANNEL_LEN_PART     4
29
30 /******************************************************************************
31
32                                 ID Payload
33
34 ******************************************************************************/
35
36 struct SilcIDPayloadStruct {
37   SilcIdType type;
38   SilcUInt16 len;
39   unsigned char *id;
40 };
41
42 /* Parses buffer and return ID payload into payload structure */
43
44 SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
45                                     SilcUInt32 payload_len)
46 {
47   SilcBufferStruct buffer;
48   SilcIDPayload newp;
49   int ret;
50
51   SILC_LOG_DEBUG(("Parsing ID payload"));
52
53   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
54   newp = silc_calloc(1, sizeof(*newp));
55   if (!newp)
56     return NULL;
57
58   ret = silc_buffer_unformat(&buffer,
59                              SILC_STR_UI_SHORT(&newp->type),
60                              SILC_STR_UI_SHORT(&newp->len),
61                              SILC_STR_END);
62   if (ret == -1)
63     goto err;
64
65   silc_buffer_pull(&buffer, 4);
66
67   if (newp->len > buffer.len)
68     goto err;
69
70   ret = silc_buffer_unformat(&buffer,
71                              SILC_STR_UI_XNSTRING_ALLOC(&newp->id, newp->len),
72                              SILC_STR_END);
73   if (ret == -1)
74     goto err;
75
76   silc_buffer_push(&buffer, 4);
77
78   return newp;
79
80  err:
81   silc_free(newp);
82   return NULL;
83 }
84
85 /* Return the ID directly from the raw payload data. */
86
87 void *silc_id_payload_parse_id(const unsigned char *data, SilcUInt32 len)
88 {
89   SilcBufferStruct buffer;
90   SilcIdType type;
91   SilcUInt16 idlen;
92   unsigned char *id_data = NULL;
93   int ret;
94   void *id;
95
96   silc_buffer_set(&buffer, (unsigned char *)data, len);
97   ret = silc_buffer_unformat(&buffer,
98                              SILC_STR_UI_SHORT(&type),
99                              SILC_STR_UI_SHORT(&idlen),
100                              SILC_STR_END);
101   if (ret == -1)
102     goto err;
103
104   silc_buffer_pull(&buffer, 4);
105
106   if (idlen > buffer.len)
107     goto err;
108
109   ret = silc_buffer_unformat(&buffer,
110                              SILC_STR_UI_XNSTRING_ALLOC(&id_data, idlen),
111                              SILC_STR_END);
112   if (ret == -1)
113     goto err;
114
115   id = silc_id_str2id(id_data, idlen, type);
116   silc_free(id_data);
117   return id;
118
119  err:
120   return NULL;
121 }
122
123 /* Encodes ID Payload */
124
125 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
126 {
127   SilcBuffer buffer;
128   unsigned char *id_data;
129   SilcUInt32 len;
130
131   id_data = silc_id_id2str(id, type);
132   len = silc_id_get_len(id, type);
133   buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
134                                        len, type);
135   silc_free(id_data);
136   return buffer;
137 }
138
139 SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
140                                        SilcUInt32 id_len, SilcIdType type)
141 {
142   SilcBuffer buffer;
143
144   SILC_LOG_DEBUG(("Encoding %s ID payload",
145                   type == SILC_ID_CLIENT ? "Client" :
146                   type == SILC_ID_SERVER ? "Server" : "Channel"));
147
148   buffer = silc_buffer_alloc_size(4 + id_len);
149   if (!buffer)
150     return NULL;
151   silc_buffer_format(buffer,
152                      SILC_STR_UI_SHORT(type),
153                      SILC_STR_UI_SHORT(id_len),
154                      SILC_STR_UI_XNSTRING(id, id_len),
155                      SILC_STR_END);
156   return buffer;
157 }
158
159 /* Free ID Payload */
160
161 void silc_id_payload_free(SilcIDPayload payload)
162 {
163   if (payload) {
164     silc_free(payload->id);
165     silc_free(payload);
166   }
167 }
168
169 /* Get ID type */
170
171 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
172 {
173   return payload ? payload->type : 0;
174 }
175
176 /* Get ID */
177
178 void *silc_id_payload_get_id(SilcIDPayload payload)
179 {
180   return payload ? silc_id_str2id(payload->id, payload->len,
181                                   payload->type) : NULL;
182 }
183
184 /* Get raw ID data. Data is duplicated. */
185
186 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
187 {
188   if (!payload)
189     return NULL;
190
191   return silc_memdup(payload->id, payload->len);
192 }
193
194 /* Get length of ID */
195
196 SilcUInt32 silc_id_payload_get_len(SilcIDPayload payload)
197 {
198   return payload ? payload->len : 0;
199 }
200
201 /* Converts ID to string. */
202
203 unsigned char *silc_id_id2str(const void *id, SilcIdType type)
204 {
205   unsigned char *ret_id;
206   SilcServerID *server_id;
207   SilcClientID *client_id;
208   SilcChannelID *channel_id;
209   SilcUInt32 id_len = silc_id_get_len(id, type);
210
211   switch(type) {
212   case SILC_ID_SERVER:
213     server_id = (SilcServerID *)id;
214     ret_id = silc_calloc(id_len, sizeof(unsigned char));
215     if (!ret_id)
216       return NULL;
217     memcpy(ret_id, server_id->ip.data, server_id->ip.data_len);
218     SILC_PUT16_MSB(server_id->port, &ret_id[4]);
219     SILC_PUT16_MSB(server_id->rnd, &ret_id[6]);
220     return ret_id;
221     break;
222   case SILC_ID_CLIENT:
223     client_id = (SilcClientID *)id;
224     ret_id = silc_calloc(id_len, sizeof(unsigned char));
225     if (!ret_id)
226       return NULL;
227     memcpy(ret_id, client_id->ip.data, client_id->ip.data_len);
228     ret_id[4] = client_id->rnd;
229     memcpy(&ret_id[5], client_id->hash, CLIENTID_HASH_LEN);
230     return ret_id;
231     break;
232   case SILC_ID_CHANNEL:
233     channel_id = (SilcChannelID *)id;
234     ret_id = silc_calloc(id_len, sizeof(unsigned char));
235     if (!ret_id)
236       return NULL;
237     memcpy(ret_id, channel_id->ip.data, channel_id->ip.data_len);
238     SILC_PUT16_MSB(channel_id->port, &ret_id[4]);
239     SILC_PUT16_MSB(channel_id->rnd, &ret_id[6]);
240     return ret_id;
241     break;
242   }
243
244   return NULL;
245 }
246
247 /* Converts string to a ID */
248
249 void *silc_id_str2id(const unsigned char *id, SilcUInt32 id_len, SilcIdType type)
250 {
251
252   switch(type) {
253   case SILC_ID_SERVER:
254     {
255       SilcServerID *server_id;
256
257       if (id_len != ID_SERVER_LEN_PART + 4 &&
258           id_len != ID_SERVER_LEN_PART + 16)
259         return NULL;
260
261       server_id = silc_calloc(1, sizeof(*server_id));
262       if (!server_id)
263         return NULL;
264       memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 4 ?
265                                       16 : 4));
266       server_id->ip.data_len = (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4);
267       SILC_GET16_MSB(server_id->port, &id[4]);
268       SILC_GET16_MSB(server_id->rnd, &id[6]);
269       return server_id;
270     }
271     break;
272   case SILC_ID_CLIENT:
273     {
274       SilcClientID *client_id;
275
276       if (id_len != ID_CLIENT_LEN_PART + 4 &&
277           id_len != ID_CLIENT_LEN_PART + 16)
278         return NULL;
279
280       client_id = silc_calloc(1, sizeof(*client_id));
281       if (!client_id)
282         return NULL;
283       memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 4 ?
284                                       16 : 4));
285       client_id->ip.data_len = (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4);
286       client_id->rnd = id[4];
287       memcpy(client_id->hash, &id[5], CLIENTID_HASH_LEN);
288       return client_id;
289     }
290     break;
291   case SILC_ID_CHANNEL:
292     {
293       SilcChannelID *channel_id;
294
295       if (id_len != ID_CHANNEL_LEN_PART + 4 &&
296           id_len != ID_CHANNEL_LEN_PART + 16)
297         return NULL;
298
299       channel_id = silc_calloc(1, sizeof(*channel_id));
300       if (!channel_id)
301         return NULL;
302       memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 4 ?
303                                        16 : 4));
304       channel_id->ip.data_len = (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4);
305       SILC_GET16_MSB(channel_id->port, &id[4]);
306       SILC_GET16_MSB(channel_id->rnd, &id[6]);
307       return channel_id;
308     }
309     break;
310   }
311
312   return NULL;
313 }
314
315 /* Returns length of the ID */
316
317 SilcUInt32 silc_id_get_len(const void *id, SilcIdType type)
318 {
319   switch(type) {
320   case SILC_ID_SERVER:
321     {
322       SilcServerID *server_id = (SilcServerID *)id;
323       return ID_SERVER_LEN_PART + server_id->ip.data_len;
324     }
325     break;
326   case SILC_ID_CLIENT:
327     {
328       SilcClientID *client_id = (SilcClientID *)id;
329       return ID_CLIENT_LEN_PART + client_id->ip.data_len;
330     }
331     break;
332   case SILC_ID_CHANNEL:
333     {
334       SilcChannelID *channel_id = (SilcChannelID *)id;
335       return ID_CHANNEL_LEN_PART + channel_id->ip.data_len;
336     }
337     break;
338   }
339
340   return 0;
341 }
342
343 /* Duplicate ID data */
344
345 void *silc_id_dup(const void *id, SilcIdType type)
346 {
347   switch(type) {
348   case SILC_ID_SERVER:
349     {
350       SilcServerID *server_id = (SilcServerID *)id;
351       return silc_memdup(server_id, sizeof(*server_id));
352     }
353     break;
354   case SILC_ID_CLIENT:
355     {
356       SilcClientID *client_id = (SilcClientID *)id;
357       return silc_memdup(client_id, sizeof(*client_id));
358     }
359     break;
360   case SILC_ID_CHANNEL:
361     {
362       SilcChannelID *channel_id = (SilcChannelID *)id;
363       return silc_memdup(channel_id, sizeof(*channel_id));
364     }
365     break;
366   }
367
368   return NULL;
369 }