summaryrefslogtreecommitdiff
path: root/src/query.c
diff options
context:
space:
mode:
authorJesper Jensen <jesper@jnsn.dev>2023-07-23 12:15:34 +0200
committerJesper Jensen <jesper@jnsn.dev>2025-04-12 10:21:20 +0200
commit47d4780eb448f839fc6b0644135395f879080ba4 (patch)
tree2c9a84bf45a4b8af5411331db50173fc5a34f630 /src/query.c
parent3515701479fe04f73e9194ee3074457bb85030f6 (diff)
I don't remember
Diffstat (limited to 'src/query.c')
-rw-r--r--src/query.c285
1 files changed, 284 insertions, 1 deletions
diff --git a/src/query.c b/src/query.c
index 6012540..6ca6565 100644
--- a/src/query.c
+++ b/src/query.c
@@ -1,12 +1,14 @@
#include "query.h"
#include "benc.h"
#include "log.h"
+#include "peers.h"
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <arpa/inet.h>
-int handle_request(struct nodeid* self, const char* method, const char* packet, size_t packet_len, char** response, size_t response_len) {
+int handle_request(struct nodeid* self, const char* method, const struct sockaddr* src, socklen_t src_len, const char* packet, size_t packet_len, char** response, size_t response_len) {
if(strcmp(method, "ping") == 0) {
struct bcursor bcursor;
struct benc_node stream[256];
@@ -173,6 +175,287 @@ int handle_request(struct nodeid* self, const char* method, const char* packet,
*response += rc;
assert(*response < end);
} else if(strcmp(method, "get_peers") == 0) {
+ struct bcursor bcursor;
+ struct benc_node stream[256];
+ bcur_open(&bcursor, packet, packet+packet_len, stream, 256);
+
+ if(bcursor.readhead->type != BNT_DICT) {
+ err("Bad query: Packet is not a dict");
+ return QUERY_EBADQ;
+ }
+ if(bcur_next(&bcursor, 1) < 0) {
+ err("Bad query: No token after outer dict start");
+ return QUERY_EBADQ;
+ }
+
+ if(bcur_find_key(&bcursor, (const enum benc_nodetype[]){BNT_STRING}, (const char*[]){"a"}, (const size_t[]){1}, 1) != 0) {
+ err("Bad query: No arguments to request");
+ return QUERY_EBADQ;
+ }
+ bcur_next(&bcursor, 1);
+ if(bcursor.readhead->type != BNT_DICT) {
+ err("Bad query: Wrong value type for request");
+ return QUERY_EBADQ;
+ }
+ // Skip the dict element
+ bcur_next(&bcursor, 1);
+ bool infohash_set = false;
+ struct infohash infohash;
+ while(bcursor.readhead->type != BNT_END) {
+ switch(bcur_find_key(&bcursor, (const enum benc_nodetype[]){BNT_STRING}, (const char*[]){"info_hash"}, (const size_t[]){9}, 1)) {
+ case 0:
+ // Skip the key
+ bcur_next(&bcursor, 1);
+
+ if(bcursor.readhead->type != BNT_STRING) {
+ err("Bad query: Wrong value type for info_hash");
+ return QUERY_EBADQ;
+ }
+
+ if(bcursor.readhead->size != 20) {
+ err("Bad query: Incorrect target length");
+ return QUERY_EBADQ;
+ }
+
+ infohash_set = true;
+ memcpy(&infohash, bcursor.readhead->loc, 20);
+
+ // Skip the value
+ bcur_next(&bcursor, 1);
+ break;
+ }
+ }
+
+ if(!infohash_set) {
+ err("info_hash argument not provided");
+ return QUERY_EBADQ;
+ }
+
+ char* end = (*response) + response_len;
+
+ int rc = snprintf(*response, end-*response, "d2:id20:");
+ if(rc < 0)
+ return QUERY_EBADQ;
+ *response += rc;
+ assert(*response < end);
+
+ memcpy(*response, self, sizeof(struct nodeid));
+ *response += sizeof(struct nodeid);
+ assert(*response < end);
+
+ rc = snprintf(*response, end-*response, "5:token1:t");
+ if(rc < 0)
+ return QUERY_EBADQ;
+ *response += rc;
+ assert(*response < end);
+
+ struct addr* peers;
+ size_t peers_len;
+ get_peers(&infohash, &peers, &peers_len);
+
+ if(peers != NULL) {
+ rc = snprintf(*response, end-*response, "6:valuesl");
+ if(rc < 0)
+ return QUERY_EBADQ;
+ *response += rc;
+ assert(*response < end);
+
+ for(int i = 0; i < peers_len; i++) {
+ *(*response) = '6';
+ *(*response+1) = ':';
+ (*response) += 2;
+ memcpy(*response, &peers[i].ip, sizeof(uint32_t));
+ *response += sizeof(uint32_t); // 4
+ assert(*response < end);
+ memcpy(*response, &peers[i].port, sizeof(uint16_t));
+ *response += sizeof(uint16_t); // 2
+ assert(*response < end);
+ }
+
+ (**response) = 'e';
+ (*response)++;
+ assert(*response < end);
+ } else {
+ // If we didn't get any peers we send back the closest nodes
+ struct entry* closest[8];
+ int found = routing_closest((struct nodeid*)&infohash, 8, closest);
+
+ rc = snprintf(*response, end-*response, "5:nodes%d:", found*26);
+ if(rc < 0)
+ return QUERY_EBADQ;
+ *response += rc;
+ assert(*response < end);
+
+ for(int i = 0; i < found; i++) {
+ memcpy(*response, &closest[i]->id, sizeof(struct nodeid));
+ *response += sizeof(struct nodeid); // 20
+ assert(*response < end);
+ memcpy(*response, &closest[i]->addr.ip, sizeof(uint32_t));
+ *response += sizeof(uint32_t); // 4
+ assert(*response < end);
+ memcpy(*response, &closest[i]->addr.port, sizeof(uint16_t));
+ *response += sizeof(uint16_t); // 2
+ assert(*response < end);
+ }
+ }
+
+ rc = snprintf(*response, end-*response, "e");
+ if(rc < 0)
+ return QUERY_EBADQ;
+ *response += rc;
+ assert(*response < end);
+ } else if(strcmp(method, "announce_peer") == 0) {
+ struct bcursor bcursor;
+ struct benc_node stream[256];
+ bcur_open(&bcursor, packet, packet+packet_len, stream, 256);
+
+ if(bcursor.readhead->type != BNT_DICT) {
+ err("Bad query: Packet is not a dict");
+ return QUERY_EBADQ;
+ }
+ if(bcur_next(&bcursor, 1) < 0) {
+ err("Bad query: No token after outer dict start");
+ return QUERY_EBADQ;
+ }
+
+ if(bcur_find_key(&bcursor, (const enum benc_nodetype[]){BNT_STRING}, (const char*[]){"a"}, (const size_t[]){1}, 1) != 0) {
+ err("Bad query: No arguments to request");
+ return QUERY_EBADQ;
+ }
+ bcur_next(&bcursor, 1);
+ if(bcursor.readhead->type != BNT_DICT) {
+ err("Bad query: Wrong value type for request");
+ return QUERY_EBADQ;
+ }
+ // Skip the dict element
+ bcur_next(&bcursor, 1);
+
+ bool implied_port = false;
+
+ bool infohash_set = false;
+ struct infohash infohash;
+
+ bool port_set = false;
+ uint16_t port;
+
+ bool token_set = false;
+ char token;
+
+ while(bcursor.readhead->type != BNT_END) {
+ switch(bcur_find_key(&bcursor, (const enum benc_nodetype[]){BNT_STRING, BNT_STRING, BNT_STRING, BNT_STRING}, (const char*[]){"implied_port", "info_hash", "port", "token"}, (const size_t[]){12, 9, 4, 5}, 4)) {
+ case 0:
+ // Skip the key
+ bcur_next(&bcursor, 1);
+
+ if(bcursor.readhead->type != BNT_INT) {
+ err("Bad query: Wrong value type for implied_port");
+ return QUERY_EBADQ;
+ }
+
+ if(*bcursor.readhead->loc == '0') {
+ implied_port = false;
+ } else {
+ implied_port = true;
+ }
+
+ // Skip the value
+ bcur_next(&bcursor, 1);
+ break;
+ case 1:
+ // Skip the key
+ bcur_next(&bcursor, 1);
+
+ if(bcursor.readhead->type != BNT_STRING) {
+ err("Bad query: Wrong value type for info_hash");
+ return QUERY_EBADQ;
+ }
+
+ if(bcursor.readhead->size != 20) {
+ err("Bad query: Incorrect info_hash length");
+ return QUERY_EBADQ;
+ }
+
+ infohash_set = true;
+ memcpy(&infohash, bcursor.readhead->loc, 20);
+
+ bcur_next(&bcursor, 1);
+ break;
+ case 2:
+ // Skip the key
+ bcur_next(&bcursor, 1);
+
+ if(bcursor.readhead->type != BNT_INT) {
+ err("Bad query: Wrong value type for port");
+ return QUERY_EBADQ;
+ }
+
+ port_set = true;
+ port = strtol(bcursor.readhead->loc, NULL, 10);
+
+ bcur_next(&bcursor, 1);
+ break;
+ case 3:
+ // Skip the key
+ bcur_next(&bcursor, 1);
+
+ if(bcursor.readhead->type != BNT_STRING) {
+ err("Bad query: Wrong value type for token");
+ return QUERY_EBADQ;
+ }
+
+ if(bcursor.readhead->size != 1) {
+ err("Bad query: Incorrect token length");
+ return QUERY_EBADQ;
+ }
+
+ token_set = true;
+ token = *bcursor.readhead->loc;
+
+ bcur_next(&bcursor, 1);
+ break;
+ }
+ }
+
+ if(!infohash_set || (!implied_port && !port_set) || !token_set) {
+ err("Missing argument to query");
+ return QUERY_EBADQ;
+ }
+
+ if(token != 't') {
+ err("Invalid token");
+ return QUERY_EBADQ;
+ }
+
+ {
+ struct sockaddr_in* ipv4 = (struct sockaddr_in*)src;
+ struct addr src_addr;
+ src_addr.ip = ipv4->sin_addr.s_addr;
+
+ src_addr.port = ipv4->sin_port;
+ if(!implied_port) {
+ src_addr.port = htons(port);
+ }
+ add_peer(&infohash, &src_addr);
+ }
+
+ // Write out the response
+ char* end = (*response) + response_len;
+
+ int rc = snprintf(*response, end-*response, "d2:id20:");
+ if(rc < 0)
+ return QUERY_EBADQ;
+ *response += rc;
+ assert(*response < end);
+
+ memcpy(*response, self, sizeof(struct nodeid));
+ *response += sizeof(struct nodeid);
+ assert(*response < end);
+
+ (**response) = 'e';
+ (*response)++;
+ assert(*response < end);
+
+ return 0;
} else {
return QUERY_EUNK;
}