~timkross/cjdns/cjdns

« back to all changes in this revision

Viewing changes to dht/core/Serializing.c

  • Committer: cjdelisle
  • Date: 2011-02-16 23:03:00 UTC
  • Revision ID: git-v1:d475c9c10adc25590bea5e7dc5383b32f66d5eb8
First commit for cjdns.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "dht/core/LegacyConnectorModuleInternal.h"
 
2
#include "dht/DHTConstants.h"
 
3
#include "net/NetworkTools.h"
 
4
#include <string.h>
 
5
 
 
6
/**
 
7
 * Get a bobj_t for a string.
 
8
 *
 
9
 * @param string a benc_bstr_t* object to wrap.
 
10
 * @return a pointer to a bobj_t object allocated on the stack
 
11
 *         which wraps the given string.
 
12
 */
 
13
#define OBJ_PTR_FOR_STRING(string)             \
 
14
    &(bobj_t) {                                \
 
15
        .type = BENC_BSTR,                     \
 
16
        .as.bstr = string                      \
 
17
    }
 
18
 
 
19
/**
 
20
 * Get a bobj_t for a dictionary.
 
21
 *
 
22
 * @param dictionary a benc_dict_entry_t* object to wrap.
 
23
 * @return a bobj_t* object allocated on the stack
 
24
 *         which wraps the given dictionary.
 
25
 */
 
26
#define OBJ_PTR_FOR_DICT(dictionary)           \
 
27
    &(bobj_t) {                                \
 
28
        .type = BENC_DICT,                     \
 
29
        .as.dict = dictionary                  \
 
30
    }
 
31
 
 
32
#define STRING_OBJ(length, chars)              \
 
33
    &(bobj_t) {                                \
 
34
        .type = BENC_BSTR,                     \
 
35
        .as.bstr = &(benc_bstr_t) {            \
 
36
            .len = length,                     \
 
37
            .bytes = chars                     \
 
38
        }                                      \
 
39
    }
 
40
 
 
41
/**
 
42
 * Send a generic message.
 
43
 *
 
44
 * @param address the ip address of the node to ping.
 
45
 * @param messageType the type of message,
 
46
 *                    DHTDHTConstants_query or DHTDHTConstants_reply
 
47
 * @param queryType if messageType is reply then this should be NULL,
 
48
 *                  one of [ping, find_node, get_peers, announce_peer]
 
49
 * @param transactionId a string to expect back if a query, return back if a
 
50
 *                      response.
 
51
 * @param argumentsKey the key to put arguments under.
 
52
 *                     DHTDHTConstants_arguments or DHTDHTConstants_reply.
 
53
 * @param arguments what will go under the "q" or "r" key.
 
54
 * @param wantProtocols if set then additional entries will be added for ip4
 
55
 *                      and/or ip6.
 
56
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
57
 */
 
58
static int sendMessage(struct sockaddr* address,
 
59
                       benc_bstr_t* messageType,
 
60
                       benc_bstr_t* queryType,
 
61
                       benc_bstr_t* transactionId,
 
62
                       benc_bstr_t* argumentsKey,
 
63
                       benc_dict_entry_t* arguments,
 
64
                       int wantProtocols)
 
65
{
 
66
    benc_dict_entry_t* entry = NULL;
 
67
 
 
68
    if (arguments && argumentsKey) {
 
69
       entry = &(benc_dict_entry_t) {
 
70
            .next = entry,
 
71
            .key = argumentsKey,
 
72
            .val = OBJ_PTR_FOR_DICT(arguments)
 
73
        };
 
74
    }
 
75
 
 
76
    /* "t":"aa" */
 
77
    if (transactionId) {
 
78
        entry = &(benc_dict_entry_t) {
 
79
            .next = entry,
 
80
            .key = &DHTConstants_transactionId,
 
81
            .val = OBJ_PTR_FOR_STRING(transactionId)
 
82
        };
 
83
    }
 
84
 
 
85
    /* "y":"q" */
 
86
    if (messageType) {
 
87
        entry = &(benc_dict_entry_t) {
 
88
            .next = entry,
 
89
            .key = &DHTConstants_messageType,
 
90
            .val = OBJ_PTR_FOR_STRING(messageType)
 
91
        };
 
92
    }
 
93
 
 
94
    /* "q":"find_node" */
 
95
    if (queryType) {
 
96
        entry = &(benc_dict_entry_t) {
 
97
            .next = entry,
 
98
            .key = &DHTConstants_query,
 
99
            .val = OBJ_PTR_FOR_STRING(queryType)
 
100
        };
 
101
    }
 
102
 
 
103
    /* IP6 compatibility addon.
 
104
     * Not in original specification.
 
105
     * "want": ["n4", "n6"]
 
106
     */
 
107
    if (wantProtocols > 0) {
 
108
        benc_list_entry_t* wishList = NULL;
 
109
        if (wantProtocols & WANT4) {
 
110
            wishList = &(benc_list_entry_t) {
 
111
                .next = wishList,
 
112
                .elem = OBJ_PTR_FOR_STRING(&DHTConstants_wantIp4)
 
113
            };
 
114
        }
 
115
        if (wantProtocols & WANT6) {
 
116
            wishList = &(benc_list_entry_t) {
 
117
                .next = wishList,
 
118
                .elem = OBJ_PTR_FOR_STRING(&DHTConstants_wantIp6)
 
119
            };
 
120
        }
 
121
        if (wishList != NULL) {
 
122
            entry = &(benc_dict_entry_t) {
 
123
                .next = entry,
 
124
                .key = &DHTConstants_want,
 
125
                .val = &(bobj_t) {
 
126
                    .type = BENC_LIST,
 
127
                    .as.list = wishList
 
128
                }
 
129
            };
 
130
        }
 
131
    }
 
132
 
 
133
    struct DHTMessage message;
 
134
    memset(&message, 0, sizeof(struct DHTMessage));
 
135
 
 
136
    message.addressLength =
 
137
        NetworkTools_addressFromSockaddr((struct sockaddr_storage*) address,
 
138
                                         message.peerAddress);
 
139
    if (message.addressLength < 6) {
 
140
        /* Failed to get the sockaddr. */
 
141
        return -1;
 
142
    }
 
143
 
 
144
 
 
145
    /* The last entry in the list is considered the dictionary. */
 
146
    message.bencoded = OBJ_PTR_FOR_DICT(entry);
 
147
 
 
148
    DHTModules_handleOutgoing(&message, context->registry);
 
149
 
 
150
    /* TODO register an error if one occurs. */
 
151
    return 0;
 
152
}
 
153
 
 
154
 
 
155
/**
 
156
 * INTERNAL Please do not use.
 
157
 * This is used to bridge to legacy dht.
 
158
 *
 
159
 * Send a ping to another node.
 
160
 *
 
161
 * @param address the ip address of the node to ping.
 
162
 * @param addressLength the length of the address, unused.
 
163
 * @param transactionId a string to expect back from the node.
 
164
 * @param transactionIdLength length of transactionId.
 
165
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
166
 */
 
167
int send_ping(struct sockaddr *address,
 
168
              int addressLength,
 
169
              const unsigned char *transactionId,
 
170
              int transactionIdLength)
 
171
{
 
172
    /* Unused. */
 
173
    addressLength = addressLength;
 
174
 
 
175
    /* We're creating this:
 
176
     * ping Query = {
 
177
     *    "t":"aa",
 
178
     *    "y":"q",
 
179
     *    "q":"ping",
 
180
     *    "a":{
 
181
     *        "id":"abcdefghij0123456789"
 
182
     *    }
 
183
     * }
 
184
     *
 
185
     * bencoded = d1:ad2:id20:abcdefghij0123456789e1:q4:ping1:t2:aa1:y1:qe
 
186
     */
 
187
 
 
188
    benc_dict_entry_t arguments = {
 
189
        .next = NULL,
 
190
        .key = &DHTConstants_myId,
 
191
        .val = OBJ_PTR_FOR_STRING(&context->myId)
 
192
    };
 
193
 
 
194
    return sendMessage(address,
 
195
                       &DHTConstants_query,
 
196
                       &DHTConstants_ping,
 
197
                       &(benc_bstr_t) {transactionIdLength, (char*) transactionId},
 
198
                       &DHTConstants_arguments,
 
199
                       &arguments,
 
200
                       0);
 
201
}
 
202
 
 
203
/**
 
204
 * INTERNAL Please do not use.
 
205
 * This is used to bridge to legacy dht.
 
206
 *
 
207
 * Send a pong to another node who pinged us.
 
208
 *
 
209
 * @param address the ip address of the node to ping.
 
210
 * @param addressLength the length of the address, unused.
 
211
 * @param transactionId a string to expect back from the node.
 
212
 * @param transactionIdLength length of transactionId.
 
213
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
214
 */
 
215
int send_pong(struct sockaddr *address,
 
216
              int addressLength,
 
217
              const unsigned char *transactionId,
 
218
              int transactionIdLength)
 
219
{
 
220
    /* Unused. */
 
221
    addressLength = addressLength;
 
222
 
 
223
    /* We are creating this:
 
224
     * Response = {"t":"aa", "y":"r", "r": {"id":"mnopqrstuvwxyz123456"}}
 
225
     * bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
 
226
     */
 
227
 
 
228
    benc_dict_entry_t arguments = {
 
229
        .next = NULL,
 
230
        .key = &DHTConstants_myId,
 
231
        .val = OBJ_PTR_FOR_STRING(&context->myId)
 
232
    };
 
233
 
 
234
    return sendMessage(address,
 
235
                       &DHTConstants_reply,
 
236
                       NULL,
 
237
                       &(benc_bstr_t) {transactionIdLength, (char*) transactionId},
 
238
                       &DHTConstants_reply,
 
239
                       &arguments,
 
240
                       0);
 
241
}
 
242
 
 
243
/**
 
244
 * INTERNAL Please do not use.
 
245
 * This is used to bridge to legacy dht.
 
246
 *
 
247
 * Send a find_node request
 
248
 *
 
249
 * @param address the ip address of the node to ping.
 
250
 * @param addressLength the length of the address, unused.
 
251
 * @param transactionId a string to expect back from the node.
 
252
 * @param transactionIdLength length of transactionId.
 
253
 * @param targetId the ID of the node we are looking for.
 
254
 * @param wantProtocols do we want ip4 or ip6 or both? WANT4 = 1, WANT6 = 2
 
255
 *                      WANT4 & WANT6 = 3.
 
256
 * @param confirm intended to tell the kernel to skip sending an arp packet
 
257
 *                before sending the udp packet. Unused as that functionality
 
258
 *                is the responsibility of the network module.
 
259
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
260
 */
 
261
int send_find_node(struct sockaddr *address,
 
262
                   int addressLength,
 
263
                   const unsigned char *transactionId,
 
264
                   int transactionIdLength,
 
265
                   const unsigned char *targetId,
 
266
                   int wantProtocols,
 
267
                   int confirm)
 
268
{
 
269
    /* Unused. */
 
270
    addressLength = addressLength;
 
271
    confirm = confirm;
 
272
 
 
273
    /* We're creating this:
 
274
     * find_node Query = {
 
275
     *     "t":"aa",
 
276
     *     "y":"q",
 
277
     *     "q":"find_node",
 
278
     *     "a": {
 
279
     *         "id":"abcdefghij0123456789",
 
280
     *         "target":"mnopqrstuvwxyz123456"
 
281
     *     }
 
282
     * }
 
283
     *
 
284
     * bencoded:
 
285
     * d1:ad2:id20:abcdefghij01234567896:target20:mnopqrstuvwxyz123456e
 
286
     * 1:q9:find_node1:t2:aa1:y1:qe
 
287
     */
 
288
 
 
289
    /* "a": {
 
290
     *     "id":"abcdefghij0123456789",
 
291
     *     "target":"mnopqrstuvwxyz123456"
 
292
     * }
 
293
     */
 
294
    benc_dict_entry_t arguments = {
 
295
        .key = &DHTConstants_myId,
 
296
        .val = OBJ_PTR_FOR_STRING(&context->myId),
 
297
        .next = &(benc_dict_entry_t) {
 
298
            .next = NULL,
 
299
            .key = &DHTConstants_targetId,
 
300
            .val = STRING_OBJ(20, (char*) targetId)
 
301
        }
 
302
    };
 
303
 
 
304
    return sendMessage(address,
 
305
                       &DHTConstants_query,
 
306
                       &DHTConstants_findNode,
 
307
                       &(benc_bstr_t) {transactionIdLength, (char*) transactionId},
 
308
                       &DHTConstants_arguments,
 
309
                       &arguments,
 
310
                       wantProtocols);
 
311
}
 
312
 
 
313
/**
 
314
 * INTERNAL Please do not use.
 
315
 * This is used to bridge to legacy dht.
 
316
 *
 
317
 * Send a find_node request
 
318
 *
 
319
 * @param address the ip address of the node to ping.
 
320
 * @param addressLength the length of the address, unused.
 
321
 * @param transactionId a string to expect back from the node.
 
322
 * @param transactionIdLength length of transactionId.
 
323
 * @param infohash the hash for the torrent which we are looking for.
 
324
 *                 this will always be 20 bytes long.
 
325
 * @param wantProtocols do we want ip4 or ip6 or both? WANT4 = 1, WANT6 = 2
 
326
 *                      WANT4 & WANT6 = 3.
 
327
 * @param confirm intended to tell the kernel to skip sending an arp packet
 
328
 *                before sending the udp packet. Unused as that functionality
 
329
 *                is the responsibility of the network module.
 
330
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
331
 */
 
332
int send_get_peers(struct sockaddr *address,
 
333
                   int addressLength,
 
334
                   unsigned char *transactionId,
 
335
                   int transactionIdLength,
 
336
                   unsigned char *infoHash,
 
337
                   int wantProtocols,
 
338
                   int confirm)
 
339
{
 
340
    /* Unused. */
 
341
    addressLength = addressLength;
 
342
    confirm = confirm;
 
343
 
 
344
    /* We're creating this:
 
345
     * get_peers Query = {
 
346
     *     "t":"aa",
 
347
     *     "y":"q",
 
348
     *     "q":"get_peers",
 
349
     *     "a": {
 
350
     *         "id":"abcdefghij0123456789",
 
351
     *         "info_hash":"mnopqrstuvwxyz123456"
 
352
     *     }
 
353
     * }
 
354
     *
 
355
     * bencoded:
 
356
     * d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456e
 
357
     * 1:q9:get_peers1:t2:aa1:y1:qe
 
358
     */
 
359
 
 
360
    /* {
 
361
     *     "id":"abcdefghij0123456789",
 
362
     *     "info_hash":"mnopqrstuvwxyz123456"
 
363
     * }
 
364
     */
 
365
    benc_dict_entry_t arguments = {
 
366
        .key = &DHTConstants_myId,
 
367
        .val = OBJ_PTR_FOR_STRING(&context->myId),
 
368
        .next = &(benc_dict_entry_t) {
 
369
            .next = NULL,
 
370
            .key = &DHTConstants_infoHash,
 
371
            .val = STRING_OBJ(20, (char*) infoHash)
 
372
        }
 
373
    };
 
374
 
 
375
    return sendMessage(address,
 
376
                       &DHTConstants_query,
 
377
                       &DHTConstants_getPeers,
 
378
                       &(benc_bstr_t) {transactionIdLength, (char*) transactionId},
 
379
                       &DHTConstants_arguments,
 
380
                       &arguments,
 
381
                       wantProtocols);
 
382
}
 
383
 
 
384
struct LegacyConnectorModule_internal_node {
 
385
    char addressPort[18];
 
386
    benc_list_entry_t entry;
 
387
    bobj_t obj;
 
388
    benc_bstr_t string;
 
389
};
 
390
 
 
391
/**
 
392
 * INTERNAL Please do not use.
 
393
 * This is used to bridge to legacy dht.
 
394
 *
 
395
 * Respond to either a find node or a get peers request.
 
396
 *
 
397
 * @param address the ip address of the node to ping.
 
398
 * @param addressLength the length of address, unused.
 
399
 * @param transactionId a number to prevent confusion if multiple
 
400
 *                      "transactions" are happening with the same peer.
 
401
 * @param transactionIdLength length of transactionId.
 
402
 * @param nodes a buffer containing 20 byte ids of nodes to send.
 
403
 * @param nodesLength the length of nodes.
 
404
 * @param nodes6 a buffer containing 20 byte ids of ip6 nodes to send.
 
405
 * @param nodes6Length the length of nodes6.
 
406
 * @param addressType one of AF_INET or AF_INET6, the protocol which our peer
 
407
 *                    used to connect to us.
 
408
 * @param store a storage structure for ip addresses of peers.
 
409
 * @param token a random number which must be reflected back to us if the node
 
410
 *              announces that he has a torrent.
 
411
 * @param tokenLength the length of token.
 
412
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
413
 */
 
414
int send_nodes_peers(struct sockaddr *address,
 
415
                     int addressLength,
 
416
                     const unsigned char *transactionId,
 
417
                     int transactionIdLength,
 
418
                     const unsigned char *nodes,
 
419
                     int nodesLength,
 
420
                     const unsigned char *nodes6,
 
421
                     int nodes6Length,
 
422
                     int addressType,
 
423
                     struct storage *store,
 
424
                     const unsigned char *token,
 
425
                     int tokenLength)
 
426
{
 
427
    addressLength = addressLength;
 
428
 
 
429
    /* Might be doing any of 3 things :/
 
430
     *
 
431
     * if tokenLength == 0 then this is a response to a find_node
 
432
     * else if storage == NULL then this is a response to a get_peers
 
433
     *     request but we don't know any peers so we send a node instead.
 
434
     * else this is a response to a get_peers request and we do know
 
435
     *     peers.
 
436
     */
 
437
 
 
438
    benc_dict_entry_t* arguments = NULL;
 
439
 
 
440
    if(nodes && nodesLength > 0) {
 
441
        arguments = &(benc_dict_entry_t) {
 
442
            .next = arguments,
 
443
            .key = &DHTConstants_nodes,
 
444
            .val = STRING_OBJ(nodesLength, (char*) nodes)
 
445
        };
 
446
    }
 
447
 
 
448
    if(nodes6 && nodes6Length > 0) {
 
449
        arguments = &(benc_dict_entry_t) {
 
450
            .next = arguments,
 
451
            .key = &DHTConstants_nodes6,
 
452
            .val = STRING_OBJ(nodes6Length, (char*) nodes6)
 
453
        };
 
454
    }
 
455
 
 
456
    if(token && tokenLength > 0) {
 
457
        arguments = &(benc_dict_entry_t) {
 
458
            .next = arguments,
 
459
            .key = &DHTConstants_authToken,
 
460
            .val = STRING_OBJ(tokenLength, (char*) token)
 
461
        };
 
462
    }
 
463
 
 
464
    if(store && store->numpeers > 0) {
 
465
        int numPeers = store->numpeers;
 
466
        int startingPoint = random() % numPeers;
 
467
        int i = startingPoint;
 
468
        int valuesReturned = 0;
 
469
        int addrLength = (addressType == AF_INET) ? 4 : 16;
 
470
 
 
471
        /* Since you can't define stack variables in a loop. Next best... */
 
472
        struct LegacyConnectorModule_internal_node nodes[51];
 
473
        memset(nodes, 0, sizeof(struct LegacyConnectorModule_internal_node) * 51);
 
474
        struct LegacyConnectorModule_internal_node* node = nodes;
 
475
        node->entry.next = NULL;
 
476
 
 
477
        do {
 
478
            if (store->peers[i].len == addrLength) {
 
479
                unsigned short bigEndianPort = htons(store->peers[i].port);
 
480
 
 
481
                memcpy(node->addressPort, store->peers[i].ip, addrLength);
 
482
                memcpy((char*) (node->addressPort + addrLength),
 
483
                       (char*) &bigEndianPort,
 
484
                       2);
 
485
 
 
486
                node->string.bytes = node->addressPort;
 
487
                node->string.len = addrLength + 2;
 
488
                node->obj.type = BENC_BSTR;
 
489
                node->obj.as.bstr = &node->string;
 
490
                node->entry.elem = &node->obj;
 
491
 
 
492
                valuesReturned++;
 
493
                node++;
 
494
                node->entry.next = &node[-1].entry;
 
495
            }
 
496
            i = (i + 1) % numPeers;
 
497
        } while (i != startingPoint && valuesReturned < 50);
 
498
 
 
499
        if (node->entry.next != NULL) {
 
500
            arguments = &(benc_dict_entry_t) {
 
501
                .next = arguments,
 
502
                .key = &DHTConstants_values,
 
503
                .val = &(bobj_t) {
 
504
                    .type = BENC_LIST,
 
505
                    .as.list = node->entry.next
 
506
                }
 
507
            };
 
508
        }
 
509
    }
 
510
 
 
511
    arguments = &(benc_dict_entry_t) {
 
512
        .key = &DHTConstants_myId,
 
513
        .val = OBJ_PTR_FOR_STRING(&context->myId),
 
514
        .next = arguments
 
515
    };
 
516
 
 
517
    return sendMessage(address,
 
518
                       &DHTConstants_reply,
 
519
                       NULL,
 
520
                       &(benc_bstr_t) {transactionIdLength, (char*) transactionId},
 
521
                       &DHTConstants_reply,
 
522
                       arguments,
 
523
                       0);
 
524
}
 
525
 
 
526
/**
 
527
 * INTERNAL Please do not use.
 
528
 * This is used to bridge to legacy dht.
 
529
 *
 
530
 * Send an announce_peer query.
 
531
 *
 
532
 * @param address the ip address of the node to ping.
 
533
 * @param addressLength the length of address, unused.
 
534
 * @param transactionId a number to prevent confusion if multiple
 
535
 *                      "transactions" are happening with the same peer.
 
536
 * @param transactionIdLength length of transactionId.
 
537
 * @param infohash the hash for the torrent which we are looking for.
 
538
 *                 this will always be 20 bytes long.
 
539
 * @param port the port number which this node is announcing from.
 
540
 * @param token a cookie which we use to prove that we own this ip address
 
541
 *              and we are not spoofing.
 
542
 * @param tokenLength the length of token.
 
543
 * @param confirm intended to tell the kernel to skip sending an arp packet
 
544
 *                before sending the udp packet. Unused as that functionality
 
545
 *                is the responsibility of the network module.
 
546
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
547
 */
 
548
int send_announce_peer(struct sockaddr *address,
 
549
                       int addressLength,
 
550
                       unsigned char *transactionId,
 
551
                       int transactionIdLength,
 
552
                       unsigned char *infoHash,
 
553
                       unsigned short port,
 
554
                       unsigned char *token,
 
555
                       int tokenLength,
 
556
                       int confirm)
 
557
{
 
558
    /* Unused. */
 
559
    addressLength = addressLength;
 
560
    confirm = confirm;
 
561
 
 
562
    /* We are creating this:
 
563
     * announce_peer Query = {
 
564
     *     "t":"aa",
 
565
     *     "y":"q",
 
566
     *     "q":"announce_peer",
 
567
     *     "a": {
 
568
     *         "id":"abcdefghij0123456789",
 
569
     *         "info_hash":"mnopqrstuvwxyz123456",
 
570
     *         "port": 6881,
 
571
     *         "token": "aoeusnth"
 
572
     *     }
 
573
     * }
 
574
     *
 
575
     * bencoded:
 
576
     * d1:ad2:id20:abcdefghij01234567899:info_hash20:mnopqrstuvwxyz123456
 
577
     * 4:porti6881e5:token8:aoeusnthe1:q13:announce_peer1:t2:aa1:y1:qe
 
578
     */
 
579
 
 
580
    benc_dict_entry_t* arguments = NULL;
 
581
 
 
582
    if (infoHash) {
 
583
        arguments = &(benc_dict_entry_t) {
 
584
            .next = arguments,
 
585
            .key = &DHTConstants_infoHash,
 
586
            .val = STRING_OBJ(20, (char*) infoHash)
 
587
        };
 
588
    }
 
589
 
 
590
    if(token && tokenLength > 0) {
 
591
        arguments = &(benc_dict_entry_t) {
 
592
            .next = arguments,
 
593
            .key = &DHTConstants_authToken,
 
594
            .val = STRING_OBJ(tokenLength, (char*) token)
 
595
        };
 
596
    }
 
597
 
 
598
    arguments = &(benc_dict_entry_t) {
 
599
        .next = arguments,
 
600
        .key = &DHTConstants_myId,
 
601
        .val = OBJ_PTR_FOR_STRING(&context->myId)
 
602
    };
 
603
 
 
604
    arguments = &(benc_dict_entry_t) {
 
605
        .next = arguments,
 
606
        .key = &DHTConstants_port,
 
607
        .val = &(bobj_t) {
 
608
            .type = BENC_INT,
 
609
            .as.int_ = port
 
610
        }
 
611
    };
 
612
 
 
613
    return sendMessage(address,
 
614
                       &DHTConstants_query,
 
615
                       &DHTConstants_announcePeer,
 
616
                       &(benc_bstr_t) {transactionIdLength, (char*) transactionId},
 
617
                       &DHTConstants_arguments,
 
618
                       arguments,
 
619
                       0);
 
620
}
 
621
 
 
622
/**
 
623
 * INTERNAL Please do not use.
 
624
 * This is used to bridge to legacy dht.
 
625
 *
 
626
 * Send a response to an announce_peer query.
 
627
 *
 
628
 * @param address the ip address of the node to ping.
 
629
 * @param addressLength the length of address, unused.
 
630
 * @param transactionId a number to prevent confusion if multiple
 
631
 *                      "transactions" are happening with the same peer.
 
632
 * @param transactionIdLength length of transactionId.
 
633
 * @return 0 if all goes well, -1 if there is an error and errno will be set.
 
634
 */
 
635
int send_peer_announced(struct sockaddr *address,
 
636
                        int addressLength,
 
637
                        unsigned char *transactionId,
 
638
                        int transactionIdLength)
 
639
{
 
640
    /* Unused. */
 
641
    addressLength = addressLength;
 
642
 
 
643
    /* We are creating this:
 
644
     * Response = {
 
645
     *     "t":"aa",
 
646
     *     "y":"r",
 
647
     *     "r": {
 
648
     *         "id":"mnopqrstuvwxyz123456"
 
649
     *     }
 
650
     * }
 
651
     *
 
652
     * bencoded = d1:rd2:id20:mnopqrstuvwxyz123456e1:t2:aa1:y1:re
 
653
     */
 
654
 
 
655
    benc_dict_entry_t* arguments = &(benc_dict_entry_t) {
 
656
        .next = NULL,
 
657
        .key = &DHTConstants_myId,
 
658
        .val = OBJ_PTR_FOR_STRING(&context->myId)
 
659
    };
 
660
 
 
661
    return sendMessage(address,
 
662
                       &DHTConstants_reply,
 
663
                       NULL,
 
664
                       &(benc_bstr_t) {transactionIdLength, (char*) transactionId},
 
665
                       &DHTConstants_reply,
 
666
                       arguments,
 
667
                       0);
 
668
}
 
669
 
 
670
int send_error(struct sockaddr *address,
 
671
               int addressLength,
 
672
               unsigned char *transactionId,
 
673
               int transactionIdLength,
 
674
               int code,
 
675
               const char *errorMessage)
 
676
{
 
677
    /* Unused. */
 
678
    addressLength = addressLength;
 
679
 
 
680
    /* We are creating this:
 
681
     * generic error = {
 
682
     *    "t":"aa",
 
683
     *    "y":"e",
 
684
     *    "e":[
 
685
     *        201,
 
686
     *        "A Generic Error Ocurred"
 
687
     *    ]
 
688
     * }
 
689
     *
 
690
     * bencoded = d1:eli201e23:A Generic Error Ocurrede1:t2:aa1:y1:ee
 
691
     */
 
692
 
 
693
    benc_dict_entry_t* entry = NULL;
 
694
 
 
695
    /* "t":"aa" */
 
696
    if (transactionId && transactionIdLength > 0) {
 
697
        entry = &(benc_dict_entry_t) {
 
698
            .next = entry,
 
699
            .key = &DHTConstants_transactionId,
 
700
            .val = STRING_OBJ(transactionIdLength, (char*) transactionId)
 
701
        };
 
702
    }
 
703
 
 
704
    /* "y":"e" */
 
705
    entry = &(benc_dict_entry_t) {
 
706
        .next = entry,
 
707
        .key = &DHTConstants_messageType,
 
708
        .val = OBJ_PTR_FOR_STRING(&DHTConstants_error)
 
709
    };
 
710
 
 
711
    /* "e": [201, "A Generic Error Ocurred"] */
 
712
    entry = &(benc_dict_entry_t) {
 
713
        .next = entry,
 
714
        .key = &DHTConstants_error,
 
715
        .val = &(bobj_t) {
 
716
            .type = BENC_LIST,
 
717
            .as.list = &(benc_list_entry_t) {
 
718
                .elem = &(bobj_t) { .type = BENC_INT, .as.int_ = code },
 
719
                .next = &(benc_list_entry_t) {
 
720
                    .elem = STRING_OBJ(strlen(errorMessage), (char*) errorMessage),
 
721
                    .next = NULL
 
722
                }
 
723
            }
 
724
        }
 
725
    };
 
726
 
 
727
    struct DHTMessage message;
 
728
    memset(&message, 0, sizeof(struct DHTMessage));
 
729
 
 
730
    message.addressLength =
 
731
        NetworkTools_addressFromSockaddr((struct sockaddr_storage*) address,
 
732
                                         message.peerAddress);
 
733
    if (message.addressLength < 6) {
 
734
        /* Failed to get the sockaddr. */
 
735
        return -1;
 
736
    }
 
737
 
 
738
    /* The last entry in the list is considered the dictionary. */
 
739
    message.bencoded = OBJ_PTR_FOR_DICT(entry);
 
740
 
 
741
    DHTModules_handleOutgoing(&message, context->registry);
 
742
 
 
743
    /* TODO register an error if one occurs. */
 
744
    return 0;
 
745
}
 
746
 
 
747
 
 
748
#undef OBJ_PTR_FOR_STRING
 
749
#undef OBJ_PTR_FOR_DICT
 
750
#undef STRING_OBJ