Handle http:// torrent urls
This commit is contained in:
parent
b9465c916e
commit
4de06eae0c
11
Makefile
11
Makefile
@ -1,4 +1,5 @@
|
|||||||
MultiThread = Yes
|
MultiThread = Yes
|
||||||
|
HttpTorrent = Yes
|
||||||
InstallPrefix = /usr/local/bin
|
InstallPrefix = /usr/local/bin
|
||||||
|
|
||||||
PROGNAME = torrent-verify
|
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`\""
|
-DBUILD_HASH="\"`git rev-parse --abbrev-ref HEAD` -> `git rev-parse --short HEAD`\"" -DBUILD_DATE="\"`date -I`\""
|
||||||
|
|
||||||
ifeq ($(MultiThread), Yes)
|
ifeq ($(MultiThread), Yes)
|
||||||
CFLAGS += -lpthread
|
LDLIBS += -lpthread
|
||||||
CPPFLAGS += -DMT
|
CPPFLAGS += -DMT
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HttpTorrent), Yes)
|
||||||
|
LDLIBS += -lcurl
|
||||||
|
CPPFLAGS += -DHTTP_TORRENT=1
|
||||||
|
endif
|
||||||
|
|
||||||
SOURCE = $(wildcard subm/heapless-bencode/*.c) $(wildcard src/*.c)
|
SOURCE = $(wildcard subm/heapless-bencode/*.c) $(wildcard src/*.c)
|
||||||
#OBJ = $(addsuffix .o,$(basename $(SOURCE)))
|
#OBJ = $(addsuffix .o,$(basename $(SOURCE)))
|
||||||
OBJS = $(SOURCE:.c=.o)
|
OBJS = $(SOURCE:.c=.o)
|
||||||
@ -25,7 +31,8 @@ uninstall:
|
|||||||
rm -f -- $(InstallPrefix)/$(PROGNAME)
|
rm -f -- $(InstallPrefix)/$(PROGNAME)
|
||||||
|
|
||||||
$(PROGNAME): $(OBJS)
|
$(PROGNAME): $(OBJS)
|
||||||
$(CC) -o $@ $+ $(CFLAGS) $(CPPFLAGS)
|
$(CC) -o $@ $+ $(CFLAGS) $(CPPFLAGS) $(LDLIBS)
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-rm -- $(OBJS) $(PROGNAME)
|
-rm -- $(OBJS) $(PROGNAME)
|
||||||
|
@ -42,6 +42,9 @@ BUILD_HASH " (" BUILD_DATE ")\n"
|
|||||||
#ifdef MT
|
#ifdef MT
|
||||||
"MultiThread support\n"
|
"MultiThread support\n"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HTTP_TORRENT
|
||||||
|
"HTTP Torrent support\n"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
@ -55,7 +58,11 @@ int main(int argc, char** argv) {
|
|||||||
help();
|
help();
|
||||||
|
|
||||||
if (optind >= argc) {
|
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();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
158
src/metainfo.c
158
src/metainfo.c
@ -3,18 +3,30 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "sha1.h"
|
#include "sha1.h"
|
||||||
|
|
||||||
|
#ifdef HTTP_TORRENT
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 128 MiB */
|
/* 128 MiB */
|
||||||
#define MAX_TORRENT_SIZE 128*1024*1024
|
#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
|
* 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,
|
* 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.
|
* 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;
|
int ret = 0;
|
||||||
FILE* f = NULL;
|
FILE* f = NULL;
|
||||||
long size = 0;
|
long size = 0;
|
||||||
@ -67,6 +79,146 @@ end:
|
|||||||
return ret;
|
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) {
|
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);
|
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) {
|
int metainfo_create(metainfo_t* metai, const char* path) {
|
||||||
char* bytes;
|
char* bytes = NULL;
|
||||||
int size;
|
int size = 0;
|
||||||
int ret = metainfo_read(path, &bytes, &size);
|
int ret = metainfo_read(path, &bytes, &size);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
fprintf(stderr, "Metafile reading failed: %s\n", \
|
fprintf(stderr, "Metafile reading failed: %s\n", \
|
||||||
|
Loading…
Reference in New Issue
Block a user