Handle http:// torrent urls
This commit is contained in:
parent
b9465c916e
commit
4de06eae0c
11
Makefile
11
Makefile
@ -1,4 +1,5 @@
|
||||
MultiThread = Yes
|
||||
HttpTorrent = Yes
|
||||
InstallPrefix = /usr/local/bin
|
||||
|
||||
PROGNAME = torrent-verify
|
||||
@ -8,10 +9,15 @@ CPPFLAGS = -DPROGRAM_NAME='"$(PROGNAME)"' -DBUILD_INFO \
|
||||
-DBUILD_HASH="\"`git rev-parse --abbrev-ref HEAD` -> `git rev-parse --short HEAD`\"" -DBUILD_DATE="\"`date -I`\""
|
||||
|
||||
ifeq ($(MultiThread), Yes)
|
||||
CFLAGS += -lpthread
|
||||
LDLIBS += -lpthread
|
||||
CPPFLAGS += -DMT
|
||||
endif
|
||||
|
||||
ifeq ($(HttpTorrent), Yes)
|
||||
LDLIBS += -lcurl
|
||||
CPPFLAGS += -DHTTP_TORRENT=1
|
||||
endif
|
||||
|
||||
SOURCE = $(wildcard subm/heapless-bencode/*.c) $(wildcard src/*.c)
|
||||
#OBJ = $(addsuffix .o,$(basename $(SOURCE)))
|
||||
OBJS = $(SOURCE:.c=.o)
|
||||
@ -25,7 +31,8 @@ uninstall:
|
||||
rm -f -- $(InstallPrefix)/$(PROGNAME)
|
||||
|
||||
$(PROGNAME): $(OBJS)
|
||||
$(CC) -o $@ $+ $(CFLAGS) $(CPPFLAGS)
|
||||
$(CC) -o $@ $+ $(CFLAGS) $(CPPFLAGS) $(LDLIBS)
|
||||
|
||||
|
||||
clean:
|
||||
-rm -- $(OBJS) $(PROGNAME)
|
||||
|
@ -42,6 +42,9 @@ BUILD_HASH " (" BUILD_DATE ")\n"
|
||||
#ifdef MT
|
||||
"MultiThread support\n"
|
||||
#endif
|
||||
#ifdef HTTP_TORRENT
|
||||
"HTTP Torrent support\n"
|
||||
#endif
|
||||
#endif
|
||||
);
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -55,7 +58,11 @@ int main(int argc, char** argv) {
|
||||
help();
|
||||
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "Provide at least one torrent file\n");
|
||||
fprintf(stderr, "Provide at least one torrent file"
|
||||
#ifdef HTTP_TORRENT
|
||||
" or an http link to a torrent file"
|
||||
#endif
|
||||
"\n");
|
||||
usage();
|
||||
}
|
||||
|
||||
|
158
src/metainfo.c
158
src/metainfo.c
@ -3,18 +3,30 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
#ifdef HTTP_TORRENT
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
/* 128 MiB */
|
||||
#define MAX_TORRENT_SIZE 128*1024*1024
|
||||
|
||||
#ifdef HTTP_TORRENT
|
||||
struct http_metainfo {
|
||||
int64_t c_size, max_size;
|
||||
char *data;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read the file in memory, and return the pointer to it (which needs to be
|
||||
* freed) in out_contents and the size in out_size. If the file is too big,
|
||||
* fail. Returns 0 on success and an errno on fail.
|
||||
*/
|
||||
static int metainfo_read(const char* path, char** out_contents, int* out_size) {
|
||||
static int metainfo_read_file(const char* path, char** out_contents, int* out_size) {
|
||||
int ret = 0;
|
||||
FILE* f = NULL;
|
||||
long size = 0;
|
||||
@ -67,6 +79,146 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HTTP_TORRENT
|
||||
static size_t metainfo_read_http_headercb(char *buf, size_t size, size_t n,
|
||||
void *data) {
|
||||
struct http_metainfo *h_meta = (struct http_metainfo*)data;
|
||||
const char *cl_header = "content-length";
|
||||
char *sep = memchr(buf, ':', size * n);
|
||||
|
||||
if (!sep || (sep - buf) != strlen(cl_header))
|
||||
goto end;
|
||||
|
||||
if (strncmp(cl_header, buf, strlen(cl_header)) == 0) {
|
||||
char *endp;
|
||||
int64_t len;
|
||||
|
||||
sep += 2;
|
||||
errno = 0;
|
||||
len = strtoll(sep, &endp, 10);
|
||||
if (sep != endp && errno == 0)
|
||||
h_meta->max_size = len;
|
||||
}
|
||||
|
||||
end:
|
||||
return size * n;
|
||||
}
|
||||
|
||||
static size_t metainfo_read_http_writecb(char *ptr, size_t size, size_t n,
|
||||
void *data) {
|
||||
struct http_metainfo *h_meta = (struct http_metainfo*)data;
|
||||
size_t bytes = size * n;
|
||||
|
||||
if (h_meta->max_size >= MAX_TORRENT_SIZE)
|
||||
goto fail; /* Stop processing if too large */
|
||||
|
||||
if (h_meta->max_size == -1) {
|
||||
/* If no content-length, make a dinamic array */
|
||||
h_meta->max_size = 0;
|
||||
} else if (!h_meta->data) {
|
||||
/* We have content-size, and we haven't alloced yet */
|
||||
h_meta->data = malloc(h_meta->max_size);
|
||||
}
|
||||
|
||||
size_t free_space = h_meta->max_size - h_meta->c_size;
|
||||
|
||||
if (bytes > free_space) {
|
||||
while (bytes > free_space) {
|
||||
if (h_meta->max_size == 0)
|
||||
h_meta->max_size = 2048;
|
||||
|
||||
h_meta->max_size *= 2;
|
||||
free_space = h_meta->max_size - h_meta->c_size;
|
||||
}
|
||||
|
||||
void *n_data = realloc(h_meta->data, h_meta->max_size);
|
||||
if (!n_data)
|
||||
goto fail;
|
||||
|
||||
h_meta->data = n_data;
|
||||
}
|
||||
|
||||
if (h_meta->c_size + bytes > MAX_TORRENT_SIZE)
|
||||
goto fail;
|
||||
|
||||
memcpy(&h_meta->data[h_meta->c_size], ptr, bytes);
|
||||
h_meta->c_size += bytes;
|
||||
|
||||
return bytes;
|
||||
|
||||
fail:
|
||||
if (h_meta->data)
|
||||
free(h_meta->data);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Download the file in memory, and return the pointer to it (which needs to be
|
||||
* freed) in out_contents and the size in out_size. If the file is too big,
|
||||
* fail. Returns 0 on success and an errno on fail.
|
||||
*/
|
||||
static int metainfo_read_http(const char* url, char** out_contents, int* out_size) {
|
||||
#ifdef HTTP_TORRENT
|
||||
char errbuf[CURL_ERROR_SIZE];
|
||||
CURL *curl = curl_easy_init();
|
||||
CURLcode res;
|
||||
struct http_metainfo h_meta = {
|
||||
.c_size = 0,
|
||||
.max_size = -1,
|
||||
.data = NULL,
|
||||
};
|
||||
|
||||
if (!curl) {
|
||||
return -1; /* Not errno but eh */
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &h_meta);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &h_meta);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, metainfo_read_http_headercb);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, metainfo_read_http_writecb);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if (res) {
|
||||
fprintf(stderr, "libCurl error: %s\n", errbuf);
|
||||
return res;
|
||||
}
|
||||
|
||||
*out_contents = h_meta.data;
|
||||
*out_size = h_meta.c_size; /* caller will free */
|
||||
|
||||
return 0;
|
||||
#else
|
||||
__builtin_unreachable(); /* Could be better tbh */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Read/download the file in memory, and return the pointer to it (which needs to be
|
||||
* freed) in out_contents and the size in out_size. If the file is too big,
|
||||
* fail. Returns 0 on success and an errno on fail.
|
||||
*/
|
||||
static int metainfo_read(const char* path, char** out_contents, int* out_size) {
|
||||
#ifdef HTTP_TORRENT
|
||||
const int has_http = 1;
|
||||
#else
|
||||
const int has_http = 0;
|
||||
#endif
|
||||
|
||||
if (strncmp(path, "http", 4) == 0) {
|
||||
if (!has_http)
|
||||
return ENOPROTOOPT;
|
||||
return metainfo_read_http(path, out_contents, out_size);
|
||||
}
|
||||
|
||||
return metainfo_read_file(path, out_contents, out_size);
|
||||
}
|
||||
|
||||
static int len_strcmp(const char* s1, int s1_len, const char* s2, int s2_len) {
|
||||
return (s1_len == s2_len) && (strncmp(s1, s2, s1_len) == 0);
|
||||
}
|
||||
@ -173,8 +325,8 @@ static int metainfo_parse(metainfo_t* metai, bencode_t* benc) {
|
||||
}
|
||||
|
||||
int metainfo_create(metainfo_t* metai, const char* path) {
|
||||
char* bytes;
|
||||
int size;
|
||||
char* bytes = NULL;
|
||||
int size = 0;
|
||||
int ret = metainfo_read(path, &bytes, &size);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Metafile reading failed: %s\n", \
|
||||
|
Loading…
Reference in New Issue
Block a user