9a35723a38832fc94ac599558dfe18edc07dc271
[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   uint16 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                                     uint32 payload_len)
46 {
47   SilcBufferStruct buffer;
48   SilcIDPayload new;
49   int ret;
50
51   SILC_LOG_DEBUG(("Parsing ID payload"));
52
53   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
54   new = silc_calloc(1, sizeof(*new));
55
56   ret = silc_buffer_unformat(&buffer,
57                              SILC_STR_UI_SHORT(&new->type),
58                              SILC_STR_UI_SHORT(&new->len),
59                              SILC_STR_END);
60   if (ret == -1)
61     goto err;
62
63   silc_buffer_pull(&buffer, 4);
64
65   if (new->len > buffer.len)
66     goto err;
67
68   ret = silc_buffer_unformat(&buffer,
69                              SILC_STR_UI_XNSTRING_ALLOC(&new->id, new->len),
70                              SILC_STR_END);
71   if (ret == -1)
72     goto err;
73
74   silc_buffer_push(&buffer, 4);
75
76   return new;
77
78  err:
79   silc_free(new);
80   return NULL;
81 }
82
83 /* Return the ID directly from the raw payload data. */
84
85 void *silc_id_payload_parse_id(const unsigned char *data, uint32 len)
86 {
87   SilcBufferStruct buffer;
88   SilcIdType type;
89   uint16 idlen;
90   unsigned char *id_data = NULL;
91   int ret;
92   void *id;
93
94   silc_buffer_set(&buffer, (unsigned char *)data, len);
95   ret = silc_buffer_unformat(&buffer,
96                              SILC_STR_UI_SHORT(&type),
97                              SILC_STR_UI_SHORT(&idlen),
98                              SILC_STR_END);
99   if (ret == -1)
100     goto err;
101
102   silc_buffer_pull(&buffer, 4);
103
104   if (idlen > buffer.len)
105     goto err;
106
107   ret = silc_buffer_unformat(&buffer,
108                              SILC_STR_UI_XNSTRING_ALLOC(&id_data, idlen),
109                              SILC_STR_END);
110   if (ret == -1)
111     goto err;
112
113   id = silc_id_str2id(id_data, idlen, type);
114   silc_free(id_data);
115   return id;
116
117  err:
118   return NULL;
119 }
120
121 /* Encodes ID Payload */
122
123 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
124 {
125   SilcBuffer buffer;
126   unsigned char *id_data;
127   uint32 len;
128
129   id_data = silc_id_id2str(id, type);
130   len = silc_id_get_len(id, type);
131   buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
132                                        len, type);
133   silc_free(id_data);
134   return buffer;
135 }
136
137 SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
138                                        uint32 id_len, SilcIdType type)
139 {
140   SilcBuffer buffer;
141
142   SILC_LOG_DEBUG(("Encoding %s ID payload",
143                   type == SILC_ID_CLIENT ? "Client" :
144                   type == SILC_ID_SERVER ? "Server" : "Channel"));
145
146   buffer = silc_buffer_alloc(4 + id_len);
147   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
148   silc_buffer_format(buffer,
149                      SILC_STR_UI_SHORT(type),
150                      SILC_STR_UI_SHORT(id_len),
151                      SILC_STR_UI_XNSTRING(id, id_len),
152                      SILC_STR_END);
153   return buffer;
154 }
155
156 /* Free ID Payload */
157
158 void silc_id_payload_free(SilcIDPayload payload)
159 {
160   if (payload) {
161     silc_free(payload->id);
162     silc_free(payload);
163   }
164 }
165
166 /* Get ID type */
167
168 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
169 {
170   return payload ? payload->type : 0;
171 }
172
173 /* Get ID */
174
175 void *silc_id_payload_get_id(SilcIDPayload payload)
176 {
177   return payload ? silc_id_str2id(payload->id, payload->len,
178                                   payload->type) : NULL;
179 }
180
181 /* Get raw ID data. Data is duplicated. */
182
183 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
184 {
185   unsigned char *ret;
186
187   if (!payload)
188     return NULL;
189
190   ret = silc_calloc(payload->len, sizeof(*ret));
191   memcpy(ret, payload->id, payload->len);
192   return ret;
193 }
194
195 /* Get length of ID */
196
197 uint32 silc_id_payload_get_len(SilcIDPayload payload)
198 {
199   return payload ? payload->len : 0;
200 }
201
202 /* Converts ID to string. */
203
204 unsigned char *silc_id_id2str(const void *id, SilcIdType type)
205 {
206   unsigned char *ret_id;
207   SilcServerID *server_id;
208   SilcClientID *client_id;
209   SilcChannelID *channel_id;
210   uint32 id_len = silc_id_get_len(id, type);
211
212   switch(type) {
213   case SILC_ID_SERVER:
214     server_id = (SilcServerID *)id;
215     ret_id = silc_calloc(id_len, sizeof(unsigned char));
216     memcpy(ret_id, server_id->ip.data, server_id->ip.data_len);
217     SILC_PUT16_MSB(server_id->port, &ret_id[4]);
218     SILC_PUT16_MSB(server_id->rnd, &ret_id[6]);
219     return ret_id;
220     break;
221   case SILC_ID_CLIENT:
222     client_id = (SilcClientID *)id;
223     ret_id = silc_calloc(id_len, sizeof(unsigned char));
224     memcpy(ret_id, client_id->ip.data, client_id->ip.data_len);
225     ret_id[4] = client_id->rnd;
226     memcpy(&ret_id[5], client_id->hash, CLIENTID_HASH_LEN);
227     return ret_id;
228     break;
229   case SILC_ID_CHANNEL:
230     channel_id = (SilcChannelID *)id;
231     ret_id = silc_calloc(id_len, sizeof(unsigned char));
232     memcpy(ret_id, channel_id->ip.data, channel_id->ip.data_len);
233     SILC_PUT16_MSB(channel_id->port, &ret_id[4]);
234     SILC_PUT16_MSB(channel_id->rnd, &ret_id[6]);
235     return ret_id;
236     break;
237   }
238
239   return NULL;
240 }
241
242 /* Converts string to a ID */
243
244 void *silc_id_str2id(const unsigned char *id, uint32 id_len, SilcIdType type)
245 {
246
247   switch(type) {
248   case SILC_ID_SERVER:
249     {
250       SilcServerID *server_id;
251
252       if (id_len != ID_SERVER_LEN_PART + 4 &&
253           id_len != ID_SERVER_LEN_PART + 16)
254         return NULL;
255
256       server_id = silc_calloc(1, sizeof(*server_id));
257       memcpy(server_id->ip.data, id, (id_len > ID_SERVER_LEN_PART + 4 ?
258                                       16 : 4));
259       server_id->ip.data_len = (id_len > ID_SERVER_LEN_PART + 4 ? 16 : 4);
260       SILC_GET16_MSB(server_id->port, &id[4]);
261       SILC_GET16_MSB(server_id->rnd, &id[6]);
262       return server_id;
263     }
264     break;
265   case SILC_ID_CLIENT:
266     {
267       SilcClientID *client_id;
268
269       if (id_len != ID_CLIENT_LEN_PART + 4 &&
270           id_len != ID_CLIENT_LEN_PART + 16)
271         return NULL;
272
273       client_id = silc_calloc(1, sizeof(*client_id));
274       memcpy(client_id->ip.data, id, (id_len > ID_CLIENT_LEN_PART + 4 ?
275                                       16 : 4));
276       client_id->ip.data_len = (id_len > ID_CLIENT_LEN_PART + 4 ? 16 : 4);
277       client_id->rnd = id[4];
278       memcpy(client_id->hash, &id[5], CLIENTID_HASH_LEN);
279       return client_id;
280     }
281     break;
282   case SILC_ID_CHANNEL:
283     {
284       SilcChannelID *channel_id;
285
286       if (id_len != ID_CHANNEL_LEN_PART + 4 &&
287           id_len != ID_CHANNEL_LEN_PART + 16)
288         return NULL;
289
290       channel_id = silc_calloc(1, sizeof(*channel_id));
291       memcpy(channel_id->ip.data, id, (id_len > ID_CHANNEL_LEN_PART + 4 ?
292                                        16 : 4));
293       channel_id->ip.data_len = (id_len > ID_CHANNEL_LEN_PART + 4 ? 16 : 4);
294       SILC_GET16_MSB(channel_id->port, &id[4]);
295       SILC_GET16_MSB(channel_id->rnd, &id[6]);
296       return channel_id;
297     }
298     break;
299   }
300
301   return NULL;
302 }
303
304 /* Returns length of the ID */
305
306 uint32 silc_id_get_len(const void *id, SilcIdType type)
307 {
308   switch(type) {
309   case SILC_ID_SERVER:
310     {
311       SilcServerID *server_id = (SilcServerID *)id;
312       return ID_SERVER_LEN_PART + server_id->ip.data_len;
313     }
314     break;
315   case SILC_ID_CLIENT:
316     {
317       SilcClientID *client_id = (SilcClientID *)id;
318       return ID_CLIENT_LEN_PART + client_id->ip.data_len;
319     }
320     break;
321   case SILC_ID_CHANNEL:
322     {
323       SilcChannelID *channel_id = (SilcChannelID *)id;
324       return ID_CHANNEL_LEN_PART + channel_id->ip.data_len;
325     }
326     break;
327   }
328
329   return 0;
330 }
331
332 /* Duplicate ID data */
333
334 void *silc_id_dup(const void *id, SilcIdType type)
335 {
336   switch(type) {
337   case SILC_ID_SERVER:
338     {
339       SilcServerID *server_id = (SilcServerID *)id, *new;
340       new = silc_calloc(1, sizeof(*server_id));
341       memcpy(new, server_id, sizeof(*server_id));
342       return new;
343     }
344     break;
345   case SILC_ID_CLIENT:
346     {
347       SilcClientID *client_id = (SilcClientID *)id, *new;
348       new = silc_calloc(1, sizeof(*client_id));
349       memcpy(new, client_id, sizeof(*client_id));
350       return new;
351     }
352     break;
353   case SILC_ID_CHANNEL:
354     {
355       SilcChannelID *channel_id = (SilcChannelID *)id, *new;
356       new = silc_calloc(1, sizeof(*channel_id));
357       memcpy(new, channel_id, sizeof(*channel_id));
358       return new;
359     }
360     break;
361   }
362
363   return NULL;
364 }