refactor: use GTest for running tests (#1383)

* refactor: use google-test on libtransmission tests
This commit is contained in:
Charles Kerr 2020-08-11 13:11:55 -05:00 committed by GitHub
parent 6da4a4dfad
commit 677dc73eac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
201 changed files with 7498 additions and 8100 deletions

3
.gitmodules vendored
View File

@ -22,3 +22,6 @@
path = third-party/miniupnpc
url = https://github.com/transmission/miniupnpc
branch = post-2.0.20170509-transmission
[submodule "third-party/googletest"]
path = third-party/googletest
url = https://github.com/google/googletest.git

View File

@ -111,6 +111,7 @@ set(QT5_MINIMUM 5.2)
if(WIN32)
foreach(L C CXX)
set(CMAKE_${L}_FLAGS "${CMAKE_${L}_FLAGS} -DWIN32")
# Target version (Vista and up)
set(CMAKE_${L}_FLAGS "${CMAKE_${L}_FLAGS} -DWINVER=0x0600 -D_WIN32_WINNT=0x0600")
# Use Unicode API (although we always use W or A names explicitly)
@ -375,10 +376,14 @@ if(WIN32)
endforeach()
endif()
## Compiler standard version
if(CMAKE_VERSION VERSION_LESS "3.1")
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17")
endif()
else()
set(CMAKE_C_STANDARD 99)
@ -387,48 +392,92 @@ else()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(NEEDED_COMPILER_FLAGS
-Wall
-W
-Wcast-align
-Wfloat-equal
-Wmissing-format-attribute
-Wpointer-arith
-Wredundant-decls
-Wundef
-Wunused-parameter
-Wwrite-strings)
### Compiler Warnings
if(NOT CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_VERSION VERSION_GREATER "3.3")
list(APPEND NEEDED_COMPILER_FLAGS
-Wextra
-Winit-self)
endif()
set(C_WARNING_FLAGS)
set(CXX_WARNING_FLAGS)
if(MINGW)
# Disable excessive warnings since we're using __USE_MINGW_ANSI_STDIO
# Hopefully, any potential issues will be spotted on other platforms
list(APPEND NEEDED_COMPILER_FLAGS -Wno-format)
else()
list(APPEND NEEDED_COMPILER_FLAGS -Wformat-security)
endif()
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
set(NEEDED_C_COMPILER_FLAGS
${NEEDED_COMPILER_FLAGS}
-Winline
-Wmissing-declarations
-Wnested-externs
-Wstrict-prototypes)
string(REPLACE ";" " " NEEDED_C_COMPILER_FLAGS_STRING "${NEEDED_C_COMPILER_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${NEEDED_C_COMPILER_FLAGS_STRING}")
set(WARNING_CANDIDATES
-W
-Wall
-Wextra
-Wcast-align
-Wduplicated-cond
-Wextra-semi
-Wextra-semi-stmt
-Wextra-tokens
-Wfloat-equal
-Wgnu
-Winit-self
-Wint-in-bool-context
-Wlogical-op
-Wmissing-format-attribute
-Wnested-externs
-Wnull-dereference
-Wpointer-arith
-Wredundant-decls
-Wredundant-move
-Wreorder-ctor
-Wrestrict
-Wreturn-std-move
-Wself-assign
-Wself-move
-Wsemicolon-before-method-body
-Wsentinel
-Wshadow
-Wsign-compare
-Wsometimes-uninitialized
-Wstrict-prototypes
-Wstring-conversion
-Wsuggest-destructor-override
-Wsuggest-override
-Wuninitialized
-Wunreachable-code
-Wunused
-Wunused-const-variable
-Wunused-parameter
-Wunused-result
-Wwrite-strings
)
set(NEEDED_CXX_COMPILER_FLAGS
${NEEDED_COMPILER_FLAGS})
string(REPLACE ";" " " NEEDED_CXX_COMPILER_FLAGS_STRING "${NEEDED_CXX_COMPILER_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${NEEDED_CXX_COMPILER_FLAGS_STRING}")
if(MINGW)
# Disable excessive warnings since we're using __USE_MINGW_ANSI_STDIO
# Hopefully, any potential issues will be spotted on other platforms
list(APPEND WARNING_CANDIDATES -Wno-format)
else()
list(APPEND WARNING_CANDIDATES -Wformat-security)
endif()
foreach(FLAG ${WARNING_CANDIDATES})
tr_make_id("${FLAG}" FLAG_ID)
# if available, add to C warnings
set(CACHE_ID "${CMAKE_C_COMPILER_ID}_C_HAS${FLAG_ID}")
string(TOLOWER "${CACHE_ID}" CACHE_ID)
check_c_compiler_flag(${FLAG} ${CACHE_ID})
if (${CACHE_ID})
list(APPEND C_WARNING_FLAGS ${FLAG})
endif()
# if available, add to CXX warnings
set(CACHE_ID "${CMAKE_CXX_COMPILER_ID}_CXX_HAS${FLAG_ID}")
string(TOLOWER "${CACHE_ID}" CACHE_ID)
check_cxx_compiler_flag(${FLAG} ${CACHE_ID})
if (${CACHE_ID})
list(APPEND CXX_WARNING_FLAGS ${FLAG})
endif()
unset(CACHE_ID)
unset(FLAG_ID)
endforeach()
unset(WARNING_CANDIDATES)
###
include(LargeFileSupport)
set(NEEDED_HEADERS
@ -524,18 +573,20 @@ else()
endif()
if(NOT CMAKE_VERSION VERSION_LESS "3.7.2")
message(STATUS "Looking for clang-tidy")
find_program(CLANG_TIDY clang-tidy)
if (CLANG_TIDY STREQUAL "CLANG_TIDY-NOTFOUND")
message(STATUS "Looking for clang-tidy - not found")
else()
message(STATUS "Looking for clang-tidy - found")
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY}")
endif()
message(STATUS "Looking for clang-tidy")
find_program(CLANG_TIDY clang-tidy)
if (CLANG_TIDY STREQUAL "CLANG_TIDY-NOTFOUND")
message(STATUS "Looking for clang-tidy - not found")
else()
message(STATUS "Looking for clang-tidy - found")
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY}")
endif()
endif()
if(ENABLE_TESTS)
include(CTest)
enable_testing()
add_subdirectory(tests)
endif()
function(tr_install_web DST_DIR)

View File

@ -24,7 +24,8 @@ SUBDIRS = \
$(CLI_DIR) \
$(GTK_DIR) \
$(MAC_DIR) \
web
web \
tests
EXTRA_DIST = \
qt \

View File

@ -27,6 +27,7 @@ xargs \
find \
qt \
tests \
\( -name '*.cc' -o -name '*.h' \) \
-print0 |
xargs \

View File

@ -16,7 +16,7 @@ AC_CONFIG_MACRO_DIR([m4])
dnl AM_CONFIG_HEADER(config.h)
AC_CONFIG_SRCDIR(libtransmission/transmission.h)
AM_INIT_AUTOMAKE([1.9 tar-pax no-dist-gzip dist-xz foreign])
AM_INIT_AUTOMAKE([1.9 tar-pax no-dist-gzip dist-xz foreign subdir-objects])
LT_INIT
LT_LIB_M
@ -83,7 +83,7 @@ AC_PROG_CXX
AC_C_INLINE
if test "x$GCC" = "xyes" ; then
CFLAGS="$CFLAGS -std=gnu99 -ggdb3 -Wall -W -Wpointer-arith -Wformat-security -Wundef -Wcast-align -Wstrict-prototypes -Wmissing-declarations -Wmissing-format-attribute -Wredundant-decls -Wnested-externs -Wunused-parameter -Wwrite-strings -Winline -Wfloat-equal"
CFLAGS="$CFLAGS -std=gnu99 -ggdb3 -Wall -W -Wpointer-arith -Wformat-security -Wundef -Wcast-align -Wstrict-prototypes -Wmissing-declarations -Wmissing-format-attribute -Wredundant-decls -Wnested-externs -Wunused-parameter -Wwrite-strings -Wfloat-equal"
dnl figure out gcc version
AC_MSG_CHECKING([gcc version])
@ -675,6 +675,9 @@ AC_CONFIG_FILES([Makefile
web/style/transmission/images/buttons/Makefile
web/javascript/Makefile
web/javascript/jquery/Makefile
tests/Makefile
tests/gtest/Makefile
tests/libtransmission/Makefile
po/Makefile.in])
AC_OUTPUT

View File

@ -6,6 +6,9 @@ endif()
include_directories(
${CMAKE_SOURCE_DIR}
)
include_directories(
SYSTEM
${CURL_INCLUDE_DIRS}
${EVENT2_INCLUDE_DIRS}
)

View File

@ -1,5 +1,7 @@
project(trgtk)
add_compile_options(${C_WARNING_FLAGS})
if(WITH_LIBAPPINDICATOR)
add_definitions(-DHAVE_LIBAPPINDICATOR)
endif()
@ -119,6 +121,9 @@ set(${PROJECT_NAME}_HEADERS
include_directories(
${CMAKE_SOURCE_DIR}
${PROJECT_BINARY_DIR}
)
include_directories(
SYSTEM
${LIBAPPINDICATOR_INCLUDE_DIRS}
${GTK_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}

View File

@ -39,7 +39,6 @@
#include "util.h"
#define MY_CONFIG_NAME "transmission"
#define MY_READABLE_NAME "transmission-gtk"
static char* gl_confdir = NULL;

View File

@ -656,7 +656,7 @@ static char* get_short_date_string(time_t t)
tr_localtime_r(&t, &tm);
strftime(buf, sizeof(buf), "%d %b %Y", &tm);
return g_locale_to_utf8(buf, -1, NULL, NULL, NULL);
};
}
static void refreshInfo(struct DetailsImpl* di, tr_torrent** torrents, int n)
{
@ -1993,7 +1993,7 @@ static void setPeerViewColumns(GtkTreeView* peer_view)
so create a non-visible column and assign it as the
'expander column. */
{
GtkTreeViewColumn* c = gtk_tree_view_column_new();
c = gtk_tree_view_column_new();
gtk_tree_view_column_set_visible(c, FALSE);
gtk_tree_view_append_column(GTK_TREE_VIEW(peer_view), c);
gtk_tree_view_set_expander_column(GTK_TREE_VIEW(peer_view), c);
@ -2374,7 +2374,6 @@ static void refreshTracker(struct DetailsImpl* di, tr_torrent** torrents, int n)
if (g_hash_table_lookup(hash, gstr->str) == NULL)
{
GtkTreePath* p;
GtkTreeIter iter;
GtkTreeRowReference* ref;
gtk_list_store_insert_with_values(store, &iter, -1,

View File

@ -22,9 +22,7 @@
#include "tr-prefs.h"
#include "util.h"
#define TR_DOWNLOAD_KEY "tr-download-key"
#define TR_COLUMN_ID_KEY "tr-model-column-id-key"
#define TR_PRIORITY_KEY "tr-priority-key"
enum
{

View File

@ -60,19 +60,17 @@ static int get_size_in_pixels(GtkWidget* widget, GtkIconSize icon_size)
static IconCache* icon_cache_new(GtkWidget* for_widget, int icon_size)
{
IconCache* icon_cache;
g_return_val_if_fail(for_widget != NULL, NULL);
icon_cache = g_new0(IconCache, 1);
icon_cache->icon_theme = gtk_icon_theme_get_for_screen(gtk_widget_get_screen(for_widget));
icon_cache->icon_size = get_size_in_pixels(for_widget, icon_size);
icon_cache->cache = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
IconCache* icons = g_new0(IconCache, 1);
icons->icon_theme = gtk_icon_theme_get_for_screen(gtk_widget_get_screen(for_widget));
icons->icon_size = get_size_in_pixels(for_widget, icon_size);
icons->cache = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_object_unref);
g_hash_table_insert(icon_cache->cache, (void*)VOID_PIXBUF_KEY, create_void_pixbuf(icon_cache->icon_size,
icon_cache->icon_size));
g_hash_table_insert(icons->cache, (void*)VOID_PIXBUF_KEY, create_void_pixbuf(icons->icon_size,
icons->icon_size));
return icon_cache;
return icons;
}
static char const* _icon_cache_get_icon_key(GIcon* icon)
@ -183,7 +181,7 @@ static GdkPixbuf* _get_icon_pixbuf(GIcon* icon, int size, GtkIconTheme* theme)
return NULL;
}
static GdkPixbuf* icon_cache_get_mime_type_icon(IconCache* icon_cache, char const* mime_type)
static GdkPixbuf* icon_cache_get_mime_type_icon(IconCache* icons, char const* mime_type)
{
GIcon* icon;
char const* key = NULL;
@ -197,7 +195,7 @@ static GdkPixbuf* icon_cache_get_mime_type_icon(IconCache* icon_cache, char cons
key = VOID_PIXBUF_KEY;
}
pixbuf = g_hash_table_lookup(icon_cache->cache, key);
pixbuf = g_hash_table_lookup(icons->cache, key);
if (pixbuf != NULL)
{
@ -206,11 +204,11 @@ static GdkPixbuf* icon_cache_get_mime_type_icon(IconCache* icon_cache, char cons
return pixbuf;
}
pixbuf = _get_icon_pixbuf(icon, icon_cache->icon_size, icon_cache->icon_theme);
pixbuf = _get_icon_pixbuf(icon, icons->icon_size, icons->icon_theme);
if (pixbuf != NULL)
{
g_hash_table_insert(icon_cache->cache, (gpointer)key, g_object_ref(pixbuf));
g_hash_table_insert(icons->cache, (gpointer)key, g_object_ref(pixbuf));
}
g_object_unref(G_OBJECT(icon));

View File

@ -74,7 +74,7 @@ static void get_capabilities_callback(GObject* source, GAsyncResult* res, gpoint
g_variant_unref(result);
}
static void g_signal_callback(GDBusProxy* proxy UNUSED, char* sender_name UNUSED, char* signal_name, GVariant* params,
static void g_signal_callback(GDBusProxy* dbus_proxy UNUSED, char* sender_name UNUSED, char* signal_name, GVariant* params,
gpointer user_data UNUSED)
{
guint id;

View File

@ -87,7 +87,7 @@ static int core_is_disposed(TrCore const* core)
return core == NULL || core->priv->sorted_model == NULL;
}
G_DEFINE_TYPE_WITH_CODE(TrCore, tr_core, G_TYPE_OBJECT, G_ADD_PRIVATE(TrCore));
G_DEFINE_TYPE_WITH_CODE(TrCore, tr_core, G_TYPE_OBJECT, G_ADD_PRIVATE(TrCore))
static void core_dispose(GObject* o)
{

View File

@ -98,7 +98,7 @@ static gboolean spun_cb_idle(gpointer spin)
struct spin_idle_data* data = g_object_get_data(o, IDLE_DATA);
/* has the user stopped making changes? */
if (g_timer_elapsed(data->last_change, NULL) > 0.33F)
if (g_timer_elapsed(data->last_change, NULL) > 0.33)
{
/* update the core */
tr_quark const key = GPOINTER_TO_INT(g_object_get_data(o, PREF_KEY));
@ -804,8 +804,6 @@ static GtkWidget* remotePage(GObject* core)
GtkCellRenderer* r;
GtkTreeSelection* sel;
GtkTreeView* v;
GtkWidget* w;
GtkWidget* h;
page->store = GTK_LIST_STORE(m);
w = gtk_tree_view_new_with_model(m);

View File

@ -710,13 +710,13 @@ GtkWidget* gtr_window_new(GtkApplication* app, GtkUIManager* ui_mgr, TrCore* cor
{
/* this is to determine the maximum width/height for the label */
int w = 0;
int h = 0;
int width = 0;
int height = 0;
PangoLayout* pango_layout;
pango_layout = gtk_widget_create_pango_layout(ul_lb, "999.99 kB/s");
pango_layout_get_pixel_size(pango_layout, &w, &h);
gtk_widget_set_size_request(ul_lb, w, h);
gtk_widget_set_size_request(dl_lb, w, h);
pango_layout_get_pixel_size(pango_layout, &width, &height);
gtk_widget_set_size_request(ul_lb, width, height);
gtk_widget_set_size_request(dl_lb, width, height);
g_object_set(ul_lb, "halign", GTK_ALIGN_END, "valign", GTK_ALIGN_CENTER, NULL);
g_object_set(dl_lb, "halign", GTK_ALIGN_END, "valign", GTK_ALIGN_CENTER, NULL);
g_object_unref(G_OBJECT(pango_layout));

View File

@ -374,8 +374,8 @@ char const* gtr_get_help_uri(void)
if (uri == NULL)
{
char const* fmt = "https://transmissionbt.com/help/gtk/%d.%dx";
uri = g_strdup_printf(fmt, MAJOR_VERSION, MINOR_VERSION / 10);
uri = g_strdup_printf("https://transmissionbt.com/help/gtk/%d.%dx",
MAJOR_VERSION, MINOR_VERSION / 10);
}
return uri;

View File

@ -1,91 +1,96 @@
project(libtr)
configure_file(version.h.in version.h)
configure_file(
version.h.in
version.h
)
set(THIRD_PARTY_SOURCES ConvertUTF.c jsonsl.c wildmat.c)
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
set(DISABLE_WARNINGS -w)
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
set(DISABLE_WARNINGS -w)
elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro")
set(DISABLE_WARNINGS -erroff)
elseif(MSVC)
set(DISABLE_WARNINGS /w)
endif()
set_source_files_properties(${THIRD_PARTY_SOURCES} PROPERTIES COMPILE_FLAGS ${DISABLE_WARNINGS})
set(PROJECT_FILES
announcer.c
announcer-http.c
announcer-udp.c
bandwidth.c
bitfield.c
blocklist.c
cache.c
clients.c
completion.c
crypto.c
crypto-utils.c
crypto-utils-cyassl.c
crypto-utils-fallback.c
crypto-utils-openssl.c
crypto-utils-polarssl.c
error.c
fdlimit.c
file.c
file-posix.c
file-win32.c
handshake.c
history.c
inout.c
list.c
log.c
magnet.c
makemeta.c
metainfo.c
natpmp.c
net.c
peer-io.c
peer-mgr.c
peer-msgs.c
platform.c
platform-quota.c
port-forwarding.c
ptrarray.c
quark.c
resume.c
rpcimpl.c
rpc-server.c
session.c
session-id.c
subprocess-posix.c
subprocess-win32.c
stats.c
torrent.c
torrent-ctor.c
torrent-magnet.c
tr-dht.c
trevent.c
tr-assert.c
tr-getopt.c
tr-lpd.c
tr-udp.c
tr-utp.c
upnp.c
utils.c
variant-benc.c
variant.c
variant-json.c
verify.c
watchdir.c
watchdir-generic.c
watchdir-inotify.c
watchdir-kqueue.c
watchdir-win32.c
web.c
webseed.c
)
string(REPLACE ";" " " C_WARNING_FLAGS_STR "${C_WARNING_FLAGS}")
foreach(FILE ${PROJECT_FILES})
set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS "${C_WARNING_FLAGS_STR}")
endforeach()
set(THIRD_PARTY_FILES
ConvertUTF.c
jsonsl.c
wildmat.c
)
set(${PROJECT_NAME}_SOURCES
announcer.c
announcer-http.c
announcer-udp.c
bandwidth.c
bitfield.c
blocklist.c
cache.c
clients.c
completion.c
ConvertUTF.c
crypto.c
crypto-utils.c
crypto-utils-cyassl.c
crypto-utils-fallback.c
crypto-utils-openssl.c
crypto-utils-polarssl.c
error.c
fdlimit.c
file.c
file-posix.c
file-win32.c
handshake.c
history.c
inout.c
list.c
log.c
magnet.c
makemeta.c
metainfo.c
natpmp.c
net.c
peer-io.c
peer-mgr.c
peer-msgs.c
platform.c
platform-quota.c
port-forwarding.c
ptrarray.c
quark.c
resume.c
rpcimpl.c
rpc-server.c
session.c
session-id.c
subprocess-posix.c
subprocess-win32.c
stats.c
torrent.c
torrent-ctor.c
torrent-magnet.c
tr-dht.c
trevent.c
tr-assert.c
tr-getopt.c
tr-lpd.c
tr-udp.c
tr-utp.c
upnp.c
utils.c
variant-benc.c
variant.c
variant-json.c
verify.c
watchdir.c
watchdir-generic.c
watchdir-inotify.c
watchdir-kqueue.c
watchdir-win32.c
web.c
webseed.c
wildmat.c
${PROJECT_FILES}
${THIRD_PARTY_FILES}
)
set_source_files_properties(crypto-utils-fallback.c PROPERTIES HEADER_FILE_ONLY ON)
@ -226,6 +231,10 @@ endif()
include_directories(
${PROJECT_SOURCE_DIR}
${PROJECT_BINARY_DIR}
)
include_directories(
SYSTEM
${ZLIB_INCLUDE_DIRS}
${CRYPTO_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}
@ -238,11 +247,11 @@ include_directories(
)
if(ICONV_FOUND)
include_directories(${ICONV_INCLUDE_DIRS})
include_directories(SYSTEM ${ICONV_INCLUDE_DIRS})
endif()
if(ENABLE_UTP)
include_directories(${TP_TOP}/libutp)
include_directories(SYSTEM ${TP_TOP}/libutp)
endif()
add_library(${TR_NAME} STATIC
@ -283,49 +292,3 @@ endif()
if(WIN32)
target_link_libraries(${TR_NAME} crypt32 shlwapi)
endif()
if(ENABLE_TESTS)
add_library(${TR_NAME}-test STATIC
libtransmission-test.c
libtransmission-test.h
)
target_link_libraries(${TR_NAME}-test ${TR_NAME})
set_property(TARGET ${TR_NAME}-test PROPERTY FOLDER "UnitTests")
set(crypto-test_ADD_SOURCES crypto-test-ref.h)
set(subprocess-test_ADD_SOURCES subprocess-test.cmd)
set(watchdir@generic-test_DEFINITIONS WATCHDIR_TEST_FORCE_GENERIC)
foreach(T bitfield blocklist clients crypto error file history json magnet makemeta metainfo move peer-msgs quark rename rpc
session subprocess tr-getopt utils variant watchdir watchdir@generic)
set(TP ${TR_NAME}-test-${T})
if(T MATCHES "^([^@]+)@.+$")
string(REPLACE "@" "-" TP "${TP}")
string(REPLACE "@" "-" T_NAME "${T}")
set(${TP}_TEST_BASENAME "${CMAKE_MATCH_1}")
else()
set(T_NAME "${T}")
set(${TP}_TEST_BASENAME "${T}")
endif()
add_executable(${TP} ${${TP}_TEST_BASENAME}-test.c ${${T}-test_ADD_SOURCES})
target_link_libraries(${TP} ${TR_NAME} ${TR_NAME}-test)
if(DEFINED ${T}-test_DEFINITIONS)
target_compile_definitions(${TP} PRIVATE ${${T}-test_DEFINITIONS})
endif()
add_test(NAME ${T_NAME}-test COMMAND ${TP})
set_property(TARGET ${TP} PROPERTY FOLDER "UnitTests")
endforeach()
if(WIN32)
add_custom_command(TARGET ${TR_NAME}-test-subprocess PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_SOURCE_DIR}/subprocess-test.cmd
$<TARGET_FILE_DIR:${TR_NAME}-test-subprocess>/${TR_NAME}-test-subprocess.cmd)
endif()
endif()
if(INSTALL_LIB)
install(TARGETS ${TR_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${${PROJECT_NAME}_PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${TR_NAME})
endif()

View File

@ -37,6 +37,7 @@ libtransmission_a_SOURCES = \
handshake.c \
history.c \
inout.c \
jsonsl.c \
list.c \
log.c \
magnet.c \
@ -133,7 +134,6 @@ noinst_HEADERS = \
inout.h \
jsonsl.c \
jsonsl.h \
libtransmission-test.h \
list.h \
log.h \
magnet.h \
@ -180,31 +180,6 @@ noinst_HEADERS = \
web.h \
webseed.h
TESTS = \
bitfield-test \
blocklist-test \
clients-test \
crypto-test \
error-test \
file-test \
history-test \
json-test \
magnet-test \
makemeta-test \
metainfo-test \
move-test \
peer-msgs-test \
quark-test \
rename-test \
rpc-test \
session-test \
subprocess-test \
tr-getopt-test \
utils-test \
variant-test \
watchdir-test \
watchdir-generic-test
noinst_PROGRAMS = $(TESTS)
apps_ldadd = \
@ -222,100 +197,3 @@ apps_ldadd = \
@ZLIB_LIBS@ \
${LIBM}
TEST_SOURCES = libtransmission-test.c
bitfield_test_SOURCES = bitfield-test.c $(TEST_SOURCES)
bitfield_test_LDADD = ${apps_ldadd}
bitfield_test_LDFLAGS = ${apps_ldflags}
blocklist_test_SOURCES = blocklist-test.c $(TEST_SOURCES)
blocklist_test_LDADD = ${apps_ldadd}
blocklist_test_LDFLAGS = ${apps_ldflags}
clients_test_SOURCES = clients-test.c $(TEST_SOURCES)
clients_test_LDADD = ${apps_ldadd}
clients_test_LDFLAGS = ${apps_ldflags}
crypto_test_SOURCES = crypto-test.c crypto-test-ref.h $(TEST_SOURCES)
crypto_test_LDADD = ${apps_ldadd}
crypto_test_LDFLAGS = ${apps_ldflags}
error_test_SOURCES = error-test.c $(TEST_SOURCES)
error_test_LDADD = ${apps_ldadd}
error_test_LDFLAGS = ${apps_ldflags}
file_test_SOURCES = file-test.c $(TEST_SOURCES)
file_test_LDADD = ${apps_ldadd}
file_test_LDFLAGS = ${apps_ldflags}
history_test_SOURCES = history-test.c $(TEST_SOURCES)
history_test_LDADD = ${apps_ldadd}
history_test_LDFLAGS = ${apps_ldflags}
json_test_SOURCES = json-test.c $(TEST_SOURCES)
json_test_LDADD = ${apps_ldadd}
json_test_LDFLAGS = ${apps_ldflags}
quark_test_SOURCES = quark-test.c $(TEST_SOURCES)
quark_test_LDADD = ${apps_ldadd}
quark_test_LDFLAGS = ${apps_ldflags}
magnet_test_SOURCES = magnet-test.c $(TEST_SOURCES)
magnet_test_LDADD = ${apps_ldadd}
magnet_test_LDFLAGS = ${apps_ldflags}
metainfo_test_SOURCES = metainfo-test.c $(TEST_SOURCES)
metainfo_test_LDADD = ${apps_ldadd}
metainfo_test_LDFLAGS = ${apps_ldflags}
makemeta_test_SOURCES = makemeta-test.c $(TEST_SOURCES)
makemeta_test_LDADD = ${apps_ldadd}
makemeta_test_LDFLAGS = ${apps_ldflags}
move_test_SOURCES = move-test.c $(TEST_SOURCES)
move_test_LDADD = ${apps_ldadd}
move_test_LDFLAGS = ${apps_ldflags}
peer_msgs_test_SOURCES = peer-msgs-test.c $(TEST_SOURCES)
peer_msgs_test_LDADD = ${apps_ldadd}
peer_msgs_test_LDFLAGS = ${apps_ldflags}
rpc_test_SOURCES = rpc-test.c $(TEST_SOURCES)
rpc_test_LDADD = ${apps_ldadd}
rpc_test_LDFLAGS = ${apps_ldflags}
session_test_SOURCES = session-test.c $(TEST_SOURCES)
session_test_LDADD = ${apps_ldadd}
session_test_LDFLAGS = ${apps_ldflags}
subprocess_test_SOURCES = subprocess-test.c $(TEST_SOURCES)
subprocess_test_LDADD = ${apps_ldadd}
subprocess_test_LDFLAGS = ${apps_ldflags}
tr_getopt_test_SOURCES = tr-getopt-test.c $(TEST_SOURCES)
tr_getopt_test_LDADD = ${apps_ldadd}
tr_getopt_test_LDFLAGS = ${apps_ldflags}
utils_test_SOURCES = utils-test.c $(TEST_SOURCES)
utils_test_LDADD = ${apps_ldadd}
utils_test_LDFLAGS = ${apps_ldflags}
variant_test_SOURCES = variant-test.c $(TEST_SOURCES)
variant_test_LDADD = ${apps_ldadd}
variant_test_LDFLAGS = ${apps_ldflags}
watchdir_test_SOURCES = watchdir-test.c $(TEST_SOURCES)
watchdir_test_LDADD = ${apps_ldadd}
watchdir_test_LDFLAGS = ${apps_ldflags}
watchdir_generic_test_SOURCES = watchdir-test.c $(TEST_SOURCES)
watchdir_generic_test_LDADD = ${apps_ldadd}
watchdir_generic_test_LDFLAGS = ${apps_ldflags}
watchdir_generic_test_CPPFLAGS = -DWATCHDIR_TEST_FORCE_GENERIC $(AM_CPPFLAGS)
rename_test_SOURCES = rename-test.c $(TEST_SOURCES)
rename_test_LDADD = ${apps_ldadd}
rename_test_LDFLAGS = ${apps_ldflags}
EXTRA_DIST = \
subprocess-test.cmd

View File

@ -8,7 +8,7 @@
#pragma once
#ifndef __LIBTRANSMISSION_ANNOUNCER_MODULE__
#ifndef LIBTRANSMISSION_ANNOUNCER_MODULE
#error only the libtransmission announcer module should #include this header.
#endif

View File

@ -13,7 +13,7 @@
#include <event2/buffer.h>
#include <event2/http.h> /* for HTTP_OK */
#define __LIBTRANSMISSION_ANNOUNCER_MODULE__
#define LIBTRANSMISSION_ANNOUNCER_MODULE
#include "transmission.h"
#include "announcer-common.h"
@ -396,8 +396,6 @@ static void on_scrape_done(tr_session* session, bool did_connect, bool did_timeo
int64_t intVal;
tr_variant* files;
tr_variant* flags;
size_t len;
char const* str;
bool const variant_loaded = tr_variantFromBenc(&top, msg, msglen) == 0;
if (tr_env_key_exists("TR_CURL_VERBOSE"))
@ -424,6 +422,8 @@ static void on_scrape_done(tr_session* session, bool did_connect, bool did_timeo
if (variant_loaded)
{
size_t len;
char const* str;
if (tr_variantDictFindStr(&top, TR_KEY_failure_reason, &str, &len))
{
response->errmsg = tr_strndup(str, len);

View File

@ -13,7 +13,7 @@
#include <event2/dns.h>
#include <event2/util.h>
#define __LIBTRANSMISSION_ANNOUNCER_MODULE__
#define LIBTRANSMISSION_ANNOUNCER_MODULE
#include "transmission.h"
#include "announcer.h"

View File

@ -14,7 +14,7 @@
#include <event2/buffer.h>
#include <event2/event.h> /* evtimer */
#define __LIBTRANSMISSION_ANNOUNCER_MODULE__
#define LIBTRANSMISSION_ANNOUNCER_MODULE
#include "transmission.h"
#include "announcer.h"

View File

@ -1,244 +0,0 @@
/*
* This file Copyright (C) 2010-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <string.h> /* strlen() */
#include "transmission.h"
#include "crypto-utils.h"
#include "bitfield.h"
#include "utils.h" /* tr_free */
#include "libtransmission-test.h"
static int test_bitfield_count_range(void)
{
int begin;
int end;
int count1;
int count2;
int const bitCount = 100 + tr_rand_int_weak(1000);
tr_bitfield bf;
/* generate a random bitfield */
tr_bitfieldConstruct(&bf, bitCount);
for (int i = 0, n = tr_rand_int_weak(bitCount); i < n; ++i)
{
tr_bitfieldAdd(&bf, tr_rand_int_weak(bitCount));
}
begin = tr_rand_int_weak(bitCount);
do
{
end = tr_rand_int_weak(bitCount);
}
while (end == begin);
/* ensure end <= begin */
if (end < begin)
{
int const tmp = begin;
begin = end;
end = tmp;
}
/* test the bitfield */
count1 = 0;
for (int i = begin; i < end; ++i)
{
if (tr_bitfieldHas(&bf, i))
{
++count1;
}
}
count2 = tr_bitfieldCountRange(&bf, begin, end);
check_int(count1, ==, count2);
/* cleanup */
tr_bitfieldDestruct(&bf);
return 0;
}
static int test_bitfields(void)
{
unsigned int bitcount = 500;
tr_bitfield field;
tr_bitfieldConstruct(&field, bitcount);
/* test tr_bitfieldAdd */
for (unsigned int i = 0; i < bitcount; i++)
{
if (i % 7 == 0)
{
tr_bitfieldAdd(&field, i);
}
}
for (unsigned int i = 0; i < bitcount; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (i % 7 == 0));
}
/* test tr_bitfieldAddRange */
tr_bitfieldAddRange(&field, 0, bitcount);
for (unsigned int i = 0; i < bitcount; i++)
{
check(tr_bitfieldHas(&field, i));
}
/* test tr_bitfieldRem */
for (unsigned int i = 0; i < bitcount; i++)
{
if (i % 7 != 0)
{
tr_bitfieldRem(&field, i);
}
}
for (unsigned int i = 0; i < bitcount; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (i % 7 == 0));
}
/* test tr_bitfieldRemRange in the middle of a boundary */
tr_bitfieldAddRange(&field, 0, 64);
tr_bitfieldRemRange(&field, 4, 21);
for (unsigned int i = 0; i < 64; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (i < 4 || i >= 21));
}
/* test tr_bitfieldRemRange on the boundaries */
tr_bitfieldAddRange(&field, 0, 64);
tr_bitfieldRemRange(&field, 8, 24);
for (unsigned int i = 0; i < 64; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (i < 8 || i >= 24));
}
/* test tr_bitfieldRemRange when begin & end is on the same word */
tr_bitfieldAddRange(&field, 0, 64);
tr_bitfieldRemRange(&field, 4, 5);
for (unsigned int i = 0; i < 64; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (i < 4 || i >= 5));
}
/* test tr_bitfieldAddRange */
tr_bitfieldRemRange(&field, 0, 64);
tr_bitfieldAddRange(&field, 4, 21);
for (unsigned int i = 0; i < 64; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (4 <= i && i < 21));
}
/* test tr_bitfieldAddRange on the boundaries */
tr_bitfieldRemRange(&field, 0, 64);
tr_bitfieldAddRange(&field, 8, 24);
for (unsigned int i = 0; i < 64; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (8 <= i && i < 24));
}
/* test tr_bitfieldAddRange when begin & end is on the same word */
tr_bitfieldRemRange(&field, 0, 64);
tr_bitfieldAddRange(&field, 4, 5);
for (unsigned int i = 0; i < 64; i++)
{
check_bool(tr_bitfieldHas(&field, i), ==, (4 <= i && i < 5));
}
tr_bitfieldDestruct(&field);
return 0;
}
static int test_bitfield_has_all_none(void)
{
tr_bitfield field;
tr_bitfieldConstruct(&field, 3);
check(!tr_bitfieldHasAll(&field));
check(tr_bitfieldHasNone(&field));
tr_bitfieldAdd(&field, 0);
check(!tr_bitfieldHasAll(&field));
check(!tr_bitfieldHasNone(&field));
tr_bitfieldRem(&field, 0);
tr_bitfieldAdd(&field, 1);
check(!tr_bitfieldHasAll(&field));
check(!tr_bitfieldHasNone(&field));
tr_bitfieldRem(&field, 1);
tr_bitfieldAdd(&field, 2);
check(!tr_bitfieldHasAll(&field));
check(!tr_bitfieldHasNone(&field));
tr_bitfieldAdd(&field, 0);
tr_bitfieldAdd(&field, 1);
check(tr_bitfieldHasAll(&field));
check(!tr_bitfieldHasNone(&field));
tr_bitfieldSetHasNone(&field);
check(!tr_bitfieldHasAll(&field));
check(tr_bitfieldHasNone(&field));
tr_bitfieldSetHasAll(&field);
check(tr_bitfieldHasAll(&field));
check(!tr_bitfieldHasNone(&field));
tr_bitfieldDestruct(&field);
tr_bitfieldConstruct(&field, 0);
check(!tr_bitfieldHasAll(&field));
check(!tr_bitfieldHasNone(&field));
tr_bitfieldSetHasNone(&field);
check(!tr_bitfieldHasAll(&field));
check(tr_bitfieldHasNone(&field));
tr_bitfieldSetHasAll(&field);
check(tr_bitfieldHasAll(&field));
check(!tr_bitfieldHasNone(&field));
tr_bitfieldDestruct(&field);
return 0;
}
int main(void)
{
testFunc const tests[] =
{
test_bitfields,
test_bitfield_has_all_none
};
int ret = runTests(tests, NUM_TESTS(tests));
/* bitfield count range */
for (int l = 0; l < 10000; ++l)
{
if (test_bitfield_count_range() != 0)
{
++ret;
}
}
return ret;
}

View File

@ -13,6 +13,9 @@
#endif
#include "transmission.h"
#include "tr-macros.h"
TR_BEGIN_DECLS
/** @brief Implementation of the BitTorrent spec's Bitfield array of bits */
typedef struct tr_bitfield
@ -91,3 +94,5 @@ static inline bool tr_bitfieldHasNone(tr_bitfield const* b)
}
bool tr_bitfieldHas(tr_bitfield const* b, size_t n);
TR_END_DECLS

View File

@ -1,159 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <stdio.h>
#include <string.h> /* strlen() */
#include "transmission.h"
#include "blocklist.h"
#include "file.h"
#include "net.h"
#include "session.h" /* tr_sessionIsAddressBlocked() */
#include "utils.h"
#include "libtransmission-test.h"
static char const* contents1 =
"10.5.6.7/8\n"
"Austin Law Firm:216.16.1.144-216.16.1.151\n"
"Sargent Controls and Aerospace:216.19.18.0-216.19.18.255\n"
"Corel Corporation:216.21.157.192-216.21.157.223\n"
"Fox Speed Channel:216.79.131.192-216.79.131.223\n";
static char const* contents2 =
"10.5.6.7/8\n"
"Austin Law Firm:216.16.1.144-216.16.1.151\n"
"Sargent Controls and Aerospace:216.19.18.0-216.19.18.255\n"
"Corel Corporation:216.21.157.192-216.21.157.223\n"
"Fox Speed Channel:216.79.131.192-216.79.131.223\n"
"Evilcorp:216.88.88.0-216.88.88.255\n";
static void create_text_file(char const* path, char const* contents)
{
tr_sys_file_t fd;
char* dir;
dir = tr_sys_path_dirname(path, NULL);
tr_sys_dir_create(dir, TR_SYS_DIR_CREATE_PARENTS, 0700, NULL);
tr_free(dir);
fd = tr_sys_file_open(path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
tr_sys_file_write(fd, contents, strlen(contents), NULL, NULL);
tr_sys_file_close(fd, NULL);
libttest_sync();
}
static bool address_is_blocked(tr_session* session, char const* address_str)
{
struct tr_address addr;
tr_address_from_string(&addr, address_str);
return tr_sessionIsAddressBlocked(session, &addr);
}
static int test_parsing(void)
{
char* path;
tr_session* session;
/* init the session */
session = libttest_session_init(NULL);
check(!tr_blocklistExists(session));
check_int(tr_blocklistGetRuleCount(session), ==, 0);
/* init the blocklist */
path = tr_buildPath(tr_sessionGetConfigDir(session), "blocklists", "level1", NULL);
create_text_file(path, contents1);
tr_free(path);
tr_sessionReloadBlocklists(session);
check(tr_blocklistExists(session));
check_int(tr_blocklistGetRuleCount(session), ==, 5);
/* enable the blocklist */
check(!tr_blocklistIsEnabled(session));
tr_blocklistSetEnabled(session, true);
check(tr_blocklistIsEnabled(session));
/* test blocked addresses */
check(!address_is_blocked(session, "0.0.0.1"));
check(address_is_blocked(session, "10.1.2.3"));
check(!address_is_blocked(session, "216.16.1.143"));
check(address_is_blocked(session, "216.16.1.144"));
check(address_is_blocked(session, "216.16.1.145"));
check(address_is_blocked(session, "216.16.1.146"));
check(address_is_blocked(session, "216.16.1.147"));
check(address_is_blocked(session, "216.16.1.148"));
check(address_is_blocked(session, "216.16.1.149"));
check(address_is_blocked(session, "216.16.1.150"));
check(address_is_blocked(session, "216.16.1.151"));
check(!address_is_blocked(session, "216.16.1.152"));
check(!address_is_blocked(session, "216.16.1.153"));
check(!address_is_blocked(session, "217.0.0.1"));
check(!address_is_blocked(session, "255.0.0.1"));
/* cleanup */
libttest_session_close(session);
return 0;
}
/***
****
***/
static int test_updating(void)
{
char* path;
tr_session* session;
/* init the session */
session = libttest_session_init(NULL);
path = tr_buildPath(tr_sessionGetConfigDir(session), "blocklists", "level1", NULL);
/* no blocklist to start with... */
check_int(tr_blocklistGetRuleCount(session), ==, 0);
/* test that updated source files will get loaded */
create_text_file(path, contents1);
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 5);
/* test that updated source files will get loaded */
create_text_file(path, contents2);
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 6);
/* test that updated source files will get loaded */
create_text_file(path, contents1);
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 5);
/* ensure that new files, if bad, get skipped */
create_text_file(path, "# nothing useful\n");
tr_sessionReloadBlocklists(session);
check_int(tr_blocklistGetRuleCount(session), ==, 5);
/* cleanup */
libttest_session_close(session);
tr_free(path);
return 0;
}
/***
****
***/
int main(void)
{
testFunc const tests[] =
{
test_parsing,
test_updating
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -12,6 +12,10 @@
#error only libtransmission should #include this header.
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
struct tr_address;
typedef struct tr_blocklistFile tr_blocklistFile;
@ -33,3 +37,5 @@ void tr_blocklistFileSetEnabled(tr_blocklistFile* b, bool isEnabled);
bool tr_blocklistFileHasAddress(tr_blocklistFile* b, struct tr_address const* addr);
int tr_blocklistFileSetContent(tr_blocklistFile* b, char const* filename);
TR_END_DECLS

View File

@ -12,6 +12,10 @@
#error only libtransmission should #include this header.
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
struct evbuffer;
typedef struct tr_cache tr_cache;
@ -49,3 +53,5 @@ int tr_cacheFlushDone(tr_cache* cache);
int tr_cacheFlushTorrent(tr_cache* cache, tr_torrent* torrent);
int tr_cacheFlushFile(tr_cache* cache, tr_torrent* torrent, tr_file_index_t file);
TR_END_DECLS

View File

@ -1,63 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "transmission.h"
#include "clients.h"
#include "libtransmission-test.h"
#define TEST_CLIENT(A, B) \
tr_clientForId(buf, sizeof(buf), A); \
check_str(buf, ==, B);
int main(void)
{
char buf[128];
TEST_CLIENT("-FC1013-", "FileCroc 1.0.1.3");
TEST_CLIENT("-MR1100-", "Miro 1.1.0.0");
TEST_CLIENT("-TR0006-", "Transmission 0.6");
TEST_CLIENT("-TR0072-", "Transmission 0.72");
TEST_CLIENT("-TR111Z-", "Transmission 1.11+");
TEST_CLIENT("O1008132", "Osprey 1.0.0");
TEST_CLIENT("TIX0193-", "Tixati 1.93");
TEST_CLIENT("-UT341\0-", "\xc2\xb5Torrent 3.4.1");
TEST_CLIENT("-BT791\0-", "BitTorrent 7.9.1");
TEST_CLIENT("-BT791B-", "BitTorrent 7.9.1 (Beta)");
/* Xfplay 9.9.92 to 9.9.94 uses "-XF9992-" */
TEST_CLIENT("-XF9992-", "Xfplay 9.9.92");
/* Older Xfplay versions have three digit version number */
TEST_CLIENT("-XF9990-", "Xfplay 9.9.9");
/* PicoTorrent */
TEST_CLIENT("-PI0091-", "PicoTorrent 0.09.1");
TEST_CLIENT("-PI0120-", "PicoTorrent 0.12.0");
/* Free Download Manager */
TEST_CLIENT("-FD51R\xFF-", "Free Download Manager 5.1.27");
TEST_CLIENT("-FD51W\xFF-", "Free Download Manager 5.1.32");
TEST_CLIENT("-FD51@\xFF-", "Free Download Manager 5.1.x"); /* Negative test case */
/* Folx */
TEST_CLIENT("-FL51FF-", "Folx 5.x"); /* Folx v5.2.1.13690 */
/* Baidu Netdisk */
TEST_CLIENT("-BN0001-", "Baidu Netdisk"); /* Baidu Netdisk Client v5.5.4 */
/* gobbledygook */
TEST_CLIENT("-IIO\x10\x2D\x04-", "-IIO%10-%04-");
TEST_CLIENT("-I\05O\x08\x03\x01-", "-I%05O%08%03%01-");
TEST_CLIENT("\x65\x78\x62\x63\x00\x38\x7A\x44\x63\x10\x2D\x6E\x9A\xD6\x72\x3B\x33\x9F\x35\xA9", "BitComet 0.56");
TEST_CLIENT("\x65\x78\x62\x63\x00\x38\x4C\x4F\x52\x44\x32\x00\x04\x8E\xCE\xD5\x7B\xD7\x10\x28", "BitLord 0.56");
/* cleanup */
return 0;
}

View File

@ -12,8 +12,14 @@
#error only libtransmission should #include this header.
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
/**
* @brief parse a peer-id into a human-readable client name and version number
* @ingroup utils
*/
char* tr_clientForId(char* buf, size_t buflen, void const* peer_id);
TR_END_DECLS

View File

@ -1,317 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <string.h>
#include "transmission.h"
#include "crypto.h"
#include "crypto-utils.h"
#include "utils.h"
#include "libtransmission-test.h"
#include "crypto-test-ref.h"
static int test_torrent_hash(void)
{
tr_crypto a;
uint8_t hash[SHA_DIGEST_LENGTH];
for (uint8_t i = 0; i < SHA_DIGEST_LENGTH; ++i)
{
hash[i] = i;
}
tr_cryptoConstruct(&a, NULL, true);
check(!tr_cryptoHasTorrentHash(&a));
check_ptr(tr_cryptoGetTorrentHash(&a), ==, NULL);
tr_cryptoSetTorrentHash(&a, hash);
check(tr_cryptoHasTorrentHash(&a));
check_ptr(tr_cryptoGetTorrentHash(&a), !=, NULL);
check_mem(tr_cryptoGetTorrentHash(&a), ==, hash, SHA_DIGEST_LENGTH);
tr_cryptoDestruct(&a);
for (uint8_t i = 0; i < SHA_DIGEST_LENGTH; ++i)
{
hash[i] = i + 1;
}
tr_cryptoConstruct(&a, hash, false);
check(tr_cryptoHasTorrentHash(&a));
check_ptr(tr_cryptoGetTorrentHash(&a), !=, NULL);
check_mem(tr_cryptoGetTorrentHash(&a), ==, hash, SHA_DIGEST_LENGTH);
tr_cryptoSetTorrentHash(&a, NULL);
check(!tr_cryptoHasTorrentHash(&a));
check_ptr(tr_cryptoGetTorrentHash(&a), ==, NULL);
tr_cryptoDestruct(&a);
return 0;
}
static int test_encrypt_decrypt(void)
{
tr_crypto a;
tr_crypto_ b;
uint8_t hash[SHA_DIGEST_LENGTH];
char const test1[] = { "test1" };
char buf11[sizeof(test1)];
char buf12[sizeof(test1)];
char const test2[] = { "@#)C$@)#(*%bvkdjfhwbc039bc4603756VB3)" };
char buf21[sizeof(test2)];
char buf22[sizeof(test2)];
int public_key_length;
for (int i = 0; i < SHA_DIGEST_LENGTH; ++i)
{
hash[i] = (uint8_t)i;
}
tr_cryptoConstruct(&a, hash, false);
tr_cryptoConstruct_(&b, hash, true);
check(tr_cryptoComputeSecret(&a, tr_cryptoGetMyPublicKey_(&b, &public_key_length)));
check(tr_cryptoComputeSecret_(&b, tr_cryptoGetMyPublicKey(&a, &public_key_length)));
tr_cryptoEncryptInit(&a);
tr_cryptoEncrypt(&a, sizeof(test1), test1, buf11);
tr_cryptoDecryptInit_(&b);
tr_cryptoDecrypt_(&b, sizeof(test1), buf11, buf12);
check_str(buf12, ==, test1);
tr_cryptoEncryptInit_(&b);
tr_cryptoEncrypt_(&b, sizeof(test2), test2, buf21);
tr_cryptoDecryptInit(&a);
tr_cryptoDecrypt(&a, sizeof(test2), buf21, buf22);
check_str(buf22, ==, test2);
tr_cryptoDestruct_(&b);
tr_cryptoDestruct(&a);
return 0;
}
static int test_sha1(void)
{
uint8_t hash[SHA_DIGEST_LENGTH];
uint8_t hash_[SHA_DIGEST_LENGTH];
check(tr_sha1(hash, "test", 4, NULL));
check(tr_sha1_(hash_, "test", 4, NULL));
check_mem(hash, ==, "\xa9\x4a\x8f\xe5\xcc\xb1\x9b\xa6\x1c\x4c\x08\x73\xd3\x91\xe9\x87\x98\x2f\xbb\xd3", SHA_DIGEST_LENGTH);
check_mem(hash, ==, hash_, SHA_DIGEST_LENGTH);
check(tr_sha1(hash, "1", 1, "22", 2, "333", 3, NULL));
check(tr_sha1_(hash_, "1", 1, "22", 2, "333", 3, NULL));
check_mem(hash, ==, "\x1f\x74\x64\x8e\x50\xa6\xa6\x70\x8e\xc5\x4a\xb3\x27\xa1\x63\xd5\x53\x6b\x7c\xed", SHA_DIGEST_LENGTH);
check_mem(hash, ==, hash_, SHA_DIGEST_LENGTH);
return 0;
}
static int test_ssha1(void)
{
struct
{
char const* const plain_text;
char const* const ssha1;
}
test_data[] =
{
{ "test", "{15ad0621b259a84d24dcd4e75b09004e98a3627bAMbyRHJy" },
{ "QNY)(*#$B)!_X$B !_B#($^!)*&$%CV!#)&$C!@$(P*)", "{10e2d7acbb104d970514a147cd16d51dfa40fb3c0OSwJtOL" }
};
#define HASH_COUNT (4 * 1024)
for (size_t i = 0; i < TR_N_ELEMENTS(test_data); ++i)
{
char* const phrase = tr_strdup(test_data[i].plain_text);
char** hashes = tr_new(char*, HASH_COUNT);
check(tr_ssha1_matches(test_data[i].ssha1, phrase));
check(tr_ssha1_matches_(test_data[i].ssha1, phrase));
for (size_t j = 0; j < HASH_COUNT; ++j)
{
hashes[j] = j % 2 == 0 ? tr_ssha1(phrase) : tr_ssha1_(phrase);
check_ptr(hashes[j], !=, NULL);
/* phrase matches each of generated hashes */
check(tr_ssha1_matches(hashes[j], phrase));
check(tr_ssha1_matches_(hashes[j], phrase));
}
for (size_t j = 0; j < HASH_COUNT; ++j)
{
/* all hashes are different */
for (size_t k = 0; k < HASH_COUNT; ++k)
{
if (k != j)
{
check_str(hashes[j], !=, hashes[k]);
}
}
}
/* exchange two first chars */
phrase[0] ^= phrase[1];
phrase[1] ^= phrase[0];
phrase[0] ^= phrase[1];
for (size_t j = 0; j < HASH_COUNT; ++j)
{
/* changed phrase doesn't match the hashes */
check(!tr_ssha1_matches(hashes[j], phrase));
check(!tr_ssha1_matches_(hashes[j], phrase));
}
for (size_t j = 0; j < HASH_COUNT; ++j)
{
tr_free(hashes[j]);
}
tr_free(hashes);
tr_free(phrase);
}
#undef HASH_COUNT
/* should work with different salt lengths as well */
check(tr_ssha1_matches("{a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", "test"));
check(tr_ssha1_matches("{d209a21d3bc4f8fc4f8faf347e69f3def597eb170pySy4ai1ZPMjeU1", "test"));
return 0;
}
static int test_random(void)
{
/* test that tr_rand_int() stays in-bounds */
for (int i = 0; i < 100000; ++i)
{
int const val = tr_rand_int(100);
check_int(val, >=, 0);
check_int(val, <, 100);
}
return 0;
}
static bool base64_eq(char const* a, char const* b)
{
for (;; ++a, ++b)
{
while (*a == '\r' || *a == '\n')
{
++a;
}
while (*b == '\r' || *b == '\n')
{
++b;
}
if (*a == '\0' || *b == '\0' || *a != *b)
{
break;
}
}
return *a == *b;
}
static int test_base64(void)
{
size_t len;
char* in;
char* out;
out = tr_base64_encode_str("YOYO!", &len);
check_uint(len, ==, strlen(out));
check(base64_eq("WU9ZTyE=", out));
in = tr_base64_decode_str(out, &len);
check_uint(len, ==, 5);
check_str(in, ==, "YOYO!");
tr_free(in);
tr_free(out);
out = tr_base64_encode("", 0, &len);
check_uint(len, ==, 0);
check_str(out, ==, "");
tr_free(out);
out = tr_base64_decode("", 0, &len);
check_uint(len, ==, 0);
check_str(out, ==, "");
tr_free(out);
out = tr_base64_encode(NULL, 0, &len);
check_uint(len, ==, 0);
check_str(out, ==, NULL);
out = tr_base64_decode(NULL, 0, &len);
check_uint(len, ==, 0);
check_str(out, ==, NULL);
#define MAX_BUF_SIZE 1024
for (size_t i = 1; i <= MAX_BUF_SIZE; ++i)
{
char buf[MAX_BUF_SIZE + 1];
for (size_t j = 0; j < i; ++j)
{
buf[j] = (char)tr_rand_int_weak(256);
}
out = tr_base64_encode(buf, i, &len);
check_uint(len, ==, strlen(out));
in = tr_base64_decode(out, len, &len);
check_uint(len, ==, i);
check_mem(in, ==, buf, len);
tr_free(in);
tr_free(out);
for (size_t j = 0; j < i; ++j)
{
buf[j] = (char)(1 + tr_rand_int_weak(255));
}
buf[i] = '\0';
out = tr_base64_encode_str(buf, &len);
check_uint(len, ==, strlen(out));
in = tr_base64_decode_str(out, &len);
check_uint(len, ==, i);
check_str(buf, ==, in);
tr_free(in);
tr_free(out);
}
#undef MAX_BUF_SIZE
return 0;
}
int main(void)
{
testFunc const tests[] =
{
test_torrent_hash,
test_encrypt_decrypt,
test_sha1,
test_ssha1,
test_random,
test_base64
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -81,7 +81,6 @@ static bool check_openssl_result(int result, int expected_result, bool expected_
}
#define check_result(result) check_openssl_result((result), 1, true, __FILE__, __LINE__)
#define check_result_eq(result, x_result) check_openssl_result((result), (x_result), true, __FILE__, __LINE__)
#define check_result_neq(result, x_result) check_openssl_result((result), (x_result), false, __FILE__, __LINE__)
static bool check_openssl_pointer(void* pointer, char const* file, int line)

View File

@ -13,12 +13,10 @@
#include <stddef.h>
#include "transmission.h" /* SHA_DIGEST_LENGTH */
#include "tr-macros.h"
#include "utils.h" /* TR_GNUC_MALLOC, TR_GNUC_NULL_TERMINATED */
#ifdef __cplusplus
extern "C"
{
#endif
TR_BEGIN_DECLS
/**
*** @addtogroup utils Utilities
@ -193,7 +191,7 @@ void* tr_base64_decode_str(char const* input, size_t* output_length) TR_GNUC_MAL
/**
* @brief Wrapper around tr_binary_to_hex() for SHA_DIGEST_LENGTH.
*/
static inline void tr_sha1_to_hex(char* hex, uint8_t const* sha1)
static inline void tr_sha1_to_hex(void* hex, void const* sha1)
{
tr_binary_to_hex(sha1, hex, SHA_DIGEST_LENGTH);
}
@ -201,15 +199,13 @@ static inline void tr_sha1_to_hex(char* hex, uint8_t const* sha1)
/**
* @brief Wrapper around tr_hex_to_binary() for SHA_DIGEST_LENGTH.
*/
static inline void tr_hex_to_sha1(uint8_t* sha1, char const* hex)
static inline void tr_hex_to_sha1(void* sha1, void const* hex)
{
tr_hex_to_binary(hex, sha1, SHA_DIGEST_LENGTH);
}
/** @} */
#ifdef __cplusplus
}
#endif
TR_END_DECLS
#endif /* TR_CRYPTO_UTILS_H */

View File

@ -6,6 +6,7 @@
*
*/
// NB: crypto-test-ref.h needs this, so use it instead of #pragma once
#ifndef TR_ENCRYPTION_H
#define TR_ENCRYPTION_H
@ -16,8 +17,11 @@
#include <inttypes.h>
#include "crypto-utils.h"
#include "tr-macros.h"
#include "utils.h" /* TR_GNUC_NULL_TERMINATED */
TR_BEGIN_DECLS
/**
*** @addtogroup peers
*** @{
@ -71,4 +75,6 @@ bool tr_cryptoSecretKeySha1(tr_crypto const* crypto, void const* prepend_data, s
/* @} */
#endif
TR_END_DECLS
#endif // TR_ENCRYPTION_H

View File

@ -1,82 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "transmission.h"
#include "error.h"
#include "libtransmission-test.h"
static int test_error_set(void)
{
tr_error* err = NULL;
tr_error_prefix(&err, "error: ");
check_ptr(err, ==, NULL);
tr_error_set(&err, 1, "error: %s (%d)", "oops", 2);
check(err != NULL);
check_int(err->code, ==, 1);
check_str(err->message, ==, "error: oops (2)");
tr_error_clear(&err);
check_ptr(err, ==, NULL);
tr_error_set_literal(&err, 2, "oops");
check_ptr(err, !=, NULL);
check_int(err->code, ==, 2);
check_str(err->message, ==, "oops");
tr_error_prefix(&err, "error: ");
check_ptr(err, !=, NULL);
check_int(err->code, ==, 2);
check_str(err->message, ==, "error: oops");
tr_error_free(err);
return 0;
}
static int test_error_propagate(void)
{
tr_error* err = NULL;
tr_error* err2 = NULL;
tr_error_set_literal(&err, 1, "oops");
check_ptr(err, !=, NULL);
check_int(err->code, ==, 1);
check_str(err->message, ==, "oops");
tr_error_propagate(&err2, &err);
check_ptr(err2, !=, NULL);
check_int(err2->code, ==, 1);
check_str(err2->message, ==, "oops");
check_ptr(err, ==, NULL);
tr_error_propagate_prefixed(&err, &err2, "error: ");
check_ptr(err, !=, NULL);
check_int(err->code, ==, 1);
check_str(err->message, ==, "error: oops");
check_ptr(err2, ==, NULL);
tr_error_propagate(NULL, &err);
check_ptr(err, ==, NULL);
tr_error_free(err2);
return 0;
}
int main(void)
{
testFunc const tests[] =
{
test_error_set,
test_error_propagate
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -12,10 +12,7 @@
#include "tr-macros.h"
#ifdef __cplusplus
extern "C"
{
#endif
TR_BEGIN_DECLS
/**
* @addtogroup error Error reporting
@ -134,6 +131,4 @@ void tr_error_propagate_prefixed(tr_error** new_error, tr_error** old_error, cha
/** @} */
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -1,9 +0,0 @@
#!/bin/sh
err=0
count=0
while [ $err -eq 0 ]; do
count=$((count + 1))
echo starting run number $count
make check
err=$?
done

View File

@ -844,6 +844,8 @@ skip_darwin_fcntl:
bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, tr_error** error)
{
(void)size;
TR_ASSERT(handle != TR_BAD_SYS_FILE);
bool ret = false;

File diff suppressed because it is too large Load Diff

View File

@ -15,10 +15,9 @@
#include <windows.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
struct tr_error;
@ -664,6 +663,4 @@ bool tr_sys_dir_close(tr_sys_dir_t handle, struct tr_error** error);
/** @} */
/** @} */
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -1,35 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <string.h> /* memset() */
#include "transmission.h"
#include "history.h"
#include "libtransmission-test.h"
static int test1(void)
{
tr_recentHistory h;
memset(&h, 0, sizeof(tr_recentHistory));
tr_historyAdd(&h, 10000, 1);
check_int((int)tr_historyGet(&h, 12000, 1000), ==, 0);
check_int((int)tr_historyGet(&h, 12000, 3000), ==, 1);
check_int((int)tr_historyGet(&h, 12000, 5000), ==, 1);
tr_historyAdd(&h, 20000, 1);
check_int((int)tr_historyGet(&h, 22000, 1000), ==, 0);
check_int((int)tr_historyGet(&h, 22000, 3000), ==, 1);
check_int((int)tr_historyGet(&h, 22000, 15000), ==, 2);
check_int((int)tr_historyGet(&h, 22000, 20000), ==, 2);
return 0;
}
MAIN_SINGLE_TEST(test1)

View File

@ -12,6 +12,12 @@
#error only libtransmission should #include this header.
#endif
#include <time.h> /* time_t */
#include "tr-macros.h"
TR_BEGIN_DECLS
/**
* A generic short-term memory object that remembers how many times
* something happened over the last N seconds.
@ -54,3 +60,5 @@ void tr_historyAdd(tr_recentHistory*, time_t when, unsigned int n);
* @param seconds how many seconds to count back through.
*/
unsigned int tr_historyGet(tr_recentHistory const*, time_t when, unsigned int seconds);
TR_END_DECLS

View File

@ -1,286 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <string.h> /* strlen() */
#include <locale.h> /* setlocale() */
#define __LIBTRANSMISSION_VARIANT_MODULE__
#include "transmission.h"
#include "utils.h" /* tr_free */
#include "variant.h"
#include "variant-common.h"
#include "libtransmission-test.h"
static int test_elements(void)
{
char const* in;
tr_variant top;
char const* str;
bool f;
double d;
int64_t i;
int err = 0;
tr_quark key;
in =
"{ \"string\": \"hello world\","
" \"escaped\": \"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\","
" \"int\": 5, "
" \"float\": 6.5, "
" \"true\": true, "
" \"false\": false, "
" \"null\": null }";
err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, ==, 0);
check(tr_variantIsDict(&top));
str = NULL;
key = tr_quark_new("string", 6);
check(tr_variantDictFindStr(&top, key, &str, NULL));
check_str(str, ==, "hello world");
check(tr_variantDictFindStr(&top, tr_quark_new("escaped", 7), &str, NULL));
check_str(str, ==, "bell \b formfeed \f linefeed \n carriage return \r tab \t");
i = 0;
check(tr_variantDictFindInt(&top, tr_quark_new("int", 3), &i));
check_int(i, ==, 5);
d = 0;
check(tr_variantDictFindReal(&top, tr_quark_new("float", 5), &d));
check_int(((int)(d * 10)), ==, 65);
f = false;
check(tr_variantDictFindBool(&top, tr_quark_new("true", 4), &f));
check_int(f, ==, true);
check(tr_variantDictFindBool(&top, tr_quark_new("false", 5), &f));
check_int(f, ==, false);
check(tr_variantDictFindStr(&top, tr_quark_new("null", 4), &str, NULL));
check_str(str, ==, "");
if (err == 0)
{
tr_variantFree(&top);
}
return 0;
}
static int test_utf8(void)
{
char const* in = "{ \"key\": \"Letöltések\" }";
tr_variant top;
char const* str;
char* json;
int err;
tr_quark const key = tr_quark_new("key", 3);
err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, ==, 0);
check(tr_variantIsDict(&top));
check(tr_variantDictFindStr(&top, key, &str, NULL));
check_str(str, ==, "Letöltések");
if (err == 0)
{
tr_variantFree(&top);
}
in = "{ \"key\": \"\\u005C\" }";
err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, ==, 0);
check(tr_variantIsDict(&top));
check(tr_variantDictFindStr(&top, key, &str, NULL));
check_str(str, ==, "\\");
if (err == 0)
{
tr_variantFree(&top);
}
/**
* 1. Feed it JSON-escaped nonascii to the JSON decoder.
* 2. Confirm that the result is UTF-8.
* 3. Feed the same UTF-8 back into the JSON encoder.
* 4. Confirm that the result is JSON-escaped.
* 5. Dogfood that result back into the parser.
* 6. Confirm that the result is UTF-8.
*/
in = "{ \"key\": \"Let\\u00f6lt\\u00e9sek\" }";
err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, ==, 0);
check(tr_variantIsDict(&top));
check(tr_variantDictFindStr(&top, key, &str, NULL));
check_str(str, ==, "Letöltések");
json = tr_variantToStr(&top, TR_VARIANT_FMT_JSON, NULL);
if (err == 0)
{
tr_variantFree(&top);
}
check_ptr(json, !=, NULL);
check_str(strstr(json, "\\u00f6"), !=, NULL);
check_str(strstr(json, "\\u00e9"), !=, NULL);
err = tr_variantFromJson(&top, json, strlen(json));
check_int(err, ==, 0);
check(tr_variantIsDict(&top));
check(tr_variantDictFindStr(&top, key, &str, NULL));
check_str(str, ==, "Letöltések");
if (err == 0)
{
tr_variantFree(&top);
}
tr_free(json);
return 0;
}
static int test1(void)
{
char const* in =
"{\n"
" \"headers\": {\n"
" \"type\": \"request\",\n"
" \"tag\": 666\n"
" },\n"
" \"body\": {\n"
" \"name\": \"torrent-info\",\n"
" \"arguments\": {\n"
" \"ids\": [ 7, 10 ]\n"
" }\n"
" }\n"
"}\n";
tr_variant top;
tr_variant* headers;
tr_variant* body;
tr_variant* args;
tr_variant* ids;
char const* str;
int64_t i;
int const err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, ==, 0);
check(tr_variantIsDict(&top));
check_ptr((headers = tr_variantDictFind(&top, tr_quark_new("headers", 7))), !=, NULL);
check(tr_variantIsDict(headers));
check(tr_variantDictFindStr(headers, tr_quark_new("type", 4), &str, NULL));
check_str(str, ==, "request");
check(tr_variantDictFindInt(headers, TR_KEY_tag, &i));
check_int(i, ==, 666);
check_ptr((body = tr_variantDictFind(&top, tr_quark_new("body", 4))), !=, NULL);
check(tr_variantDictFindStr(body, TR_KEY_name, &str, NULL));
check_str(str, ==, "torrent-info");
check_ptr((args = tr_variantDictFind(body, tr_quark_new("arguments", 9))), !=, NULL);
check(tr_variantIsDict(args));
check_ptr((ids = tr_variantDictFind(args, TR_KEY_ids)), !=, NULL);
check(tr_variantIsList(ids));
check_uint(tr_variantListSize(ids), ==, 2);
check(tr_variantGetInt(tr_variantListChild(ids, 0), &i));
check_int(i, ==, 7);
check(tr_variantGetInt(tr_variantListChild(ids, 1), &i));
check_int(i, ==, 10);
tr_variantFree(&top);
return 0;
}
static int test2(void)
{
tr_variant top;
char const* in = " ";
int err;
top.type = 0;
err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, !=, 0);
check(!tr_variantIsDict(&top));
return 0;
}
static int test3(void)
{
char const* in =
"{ \"error\": 2,"
" \"errorString\": \"torrent not registered with this tracker 6UHsVW'*C\","
" \"eta\": 262792,"
" \"id\": 25,"
" \"leftUntilDone\": 2275655680 }";
tr_variant top;
char const* str;
int const err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, ==, 0);
check(tr_variantDictFindStr(&top, TR_KEY_errorString, &str, NULL));
check_str(str, ==, "torrent not registered with this tracker 6UHsVW'*C");
tr_variantFree(&top);
return 0;
}
static int test_unescape(void)
{
char const* in = "{ \"string-1\": \"\\/usr\\/lib\" }";
tr_variant top;
char const* str;
int const err = tr_variantFromJson(&top, in, strlen(in));
check_int(err, ==, 0);
check(tr_variantDictFindStr(&top, tr_quark_new("string-1", 8), &str, NULL));
check_str(str, ==, "/usr/lib");
tr_variantFree(&top);
return 0;
}
int main(void)
{
char const* comma_locales[] =
{
"da_DK.UTF-8",
"fr_FR.UTF-8",
"ru_RU.UTF-8"
};
testFunc const tests[] =
{
test_elements,
test_utf8,
test1,
test2,
test3,
test_unescape
};
/* run the tests in a locale with a decimal point of '.' */
setlocale(LC_NUMERIC, "C");
int ret = runTests(tests, NUM_TESTS(tests));
/* run the tests in a locale with a decimal point of ',' */
bool is_locale_set = false;
for (size_t i = 0; !is_locale_set && i < TR_N_ELEMENTS(comma_locales); ++i)
{
is_locale_set = setlocale(LC_NUMERIC, comma_locales[i]) != NULL;
}
if (!is_locale_set)
{
fprintf(stderr, "WARNING: unable to run locale-specific json tests. add a locale like %s or %s\n", comma_locales[0],
comma_locales[1]);
}
else
{
ret += runTests(tests, NUM_TESTS(tests));
}
return ret;
}

View File

@ -1,589 +0,0 @@
/*
* This file Copyright (C) 2013-2017 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h> /* mkstemp() */
#include <string.h> /* strcmp() */
#ifndef _WIN32
#include <unistd.h> /* sync() */
#endif
#include "transmission.h"
#include "crypto-utils.h"
#include "error.h"
#include "file.h"
#include "platform.h" /* TR_PATH_DELIMETER */
#include "torrent.h"
#include "tr-assert.h"
#include "trevent.h"
#include "variant.h"
#include "libtransmission-test.h"
bool verbose = false;
int current_test = 0;
bool should_print(bool pass)
{
if (!pass)
{
return true;
}
if (verbose)
{
return true;
}
return false;
#ifdef VERBOSE
return true;
#else
return false;
#endif
}
bool libtest_check(char const* file, int line, bool pass, bool condition, char const* condition_str)
{
if (should_print(pass))
{
fprintf(stderr, "%s %s:%d: %s (%s)\n", pass ? "PASS" : "FAIL", file, line, condition_str, condition ? "true" : "false");
}
return pass;
}
bool libtest_check_bool(char const* file, int line, bool pass, bool lhs, bool rhs, char const* lhs_str, char const* op_str,
char const* rhs_str)
{
if (should_print(pass))
{
fprintf(stderr, "%s %s:%d: %s %s %s (%s %s %s)\n", pass ? "PASS" : "FAIL", file, line, lhs_str, op_str, rhs_str,
lhs ? "true" : "false", op_str, rhs ? "true" : "false");
}
return pass;
}
bool libtest_check_str(char const* file, int line, bool pass, char const* lhs, char const* rhs, char const* lhs_str,
char const* op_str, char const* rhs_str)
{
if (should_print(pass))
{
char const* const lhs_quote = lhs != NULL ? "\"" : "";
char const* const rhs_quote = rhs != NULL ? "\"" : "";
fprintf(stderr, "%s %s:%d: %s %s %s (%s%s%s %s %s%s%s)\n", pass ? "PASS" : "FAIL", file, line, lhs_str, op_str, rhs_str,
lhs_quote, lhs != NULL ? lhs : "NULL", lhs_quote, op_str, rhs_quote, rhs != NULL ? rhs : "NULL", rhs_quote);
}
return pass;
}
static void print_mem(FILE* stream, void const* data, size_t size)
{
if (data == NULL)
{
fprintf(stream, "NULL");
return;
}
if (size == 0)
{
fprintf(stream, "(no bytes)");
return;
}
uint8_t const* byte_data = data;
fprintf(stream, "x'");
for (size_t i = 0; i < size; ++i)
{
fprintf(stream, "%02x", (unsigned int)byte_data[i]);
}
fprintf(stream, "'");
}
bool libtest_check_mem(char const* file, int line, bool pass, void const* lhs, void const* rhs, size_t size,
char const* lhs_str, char const* op_str, char const* rhs_str)
{
if (should_print(pass))
{
fprintf(stderr, "%s %s:%d: %s %s %s (", pass ? "PASS" : "FAIL", file, line, lhs_str, op_str, rhs_str);
print_mem(stderr, lhs, size);
fprintf(stderr, " %s ", op_str);
print_mem(stderr, rhs, size);
fprintf(stderr, ")\n");
}
return pass;
}
bool libtest_check_int(char const* file, int line, bool pass, intmax_t lhs, intmax_t rhs, char const* lhs_str,
char const* op_str, char const* rhs_str)
{
if (should_print(pass))
{
fprintf(stderr, "%s %s:%d: %s %s %s (%jd %s %jd)\n", pass ? "PASS" : "FAIL", file, line, lhs_str, op_str, rhs_str, lhs,
op_str, rhs);
}
return pass;
}
bool libtest_check_uint(char const* file, int line, bool pass, uintmax_t lhs, uintmax_t rhs, char const* lhs_str,
char const* op_str, char const* rhs_str)
{
if (should_print(pass))
{
fprintf(stderr, "%s %s:%d: %s %s %s (%ju %s %ju)\n", pass ? "PASS" : "FAIL", file, line, lhs_str, op_str, rhs_str, lhs,
op_str, rhs);
}
return pass;
}
bool libtest_check_ptr(char const* file, int line, bool pass, void const* lhs, void const* rhs, char const* lhs_str,
char const* op_str, char const* rhs_str)
{
if (should_print(pass))
{
fprintf(stderr, "%s %s:%d: %s %s %s (%p %s %p)\n", pass ? "PASS" : "FAIL", file, line, lhs_str, op_str, rhs_str, lhs,
op_str, rhs);
}
return pass;
}
int runTests(testFunc const* const tests, int numTests)
{
int ret = 0;
(void)current_test; /* Use test even if we don't have any tests to run */
for (int i = 0; i < numTests; i++)
{
if ((*tests[i])() != 0)
{
++ret;
}
}
return ret;
}
/***
****
***/
static char* tr_getcwd(void)
{
char* result;
tr_error* error = NULL;
result = tr_sys_dir_get_current(&error);
if (result == NULL)
{
fprintf(stderr, "getcwd error: \"%s\"", error->message);
tr_error_free(error);
result = tr_strdup("");
}
return result;
}
char* libtest_sandbox_create(void)
{
char* path = tr_getcwd();
char* sandbox = tr_buildPath(path, "sandbox-XXXXXX", NULL);
tr_free(path);
tr_sys_dir_create_temp(sandbox, NULL);
return tr_sys_path_native_separators(sandbox);
}
static void rm_rf(char const* killme)
{
tr_sys_path_info info;
if (!tr_sys_path_get_info(killme, 0, &info, NULL))
{
return;
}
tr_sys_dir_t odir = info.type == TR_SYS_PATH_IS_DIRECTORY ? tr_sys_dir_open(killme, NULL) : TR_BAD_SYS_DIR;
if (odir != TR_BAD_SYS_DIR)
{
char const* name;
while ((name = tr_sys_dir_read_name(odir, NULL)) != NULL)
{
if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
{
char* tmp = tr_buildPath(killme, name, NULL);
rm_rf(tmp);
tr_free(tmp);
}
}
tr_sys_dir_close(odir, NULL);
}
if (verbose)
{
fprintf(stderr, "cleanup: removing %s\n", killme);
}
tr_sys_path_remove(killme, NULL);
}
void libtest_sandbox_destroy(char const* sandbox)
{
rm_rf(sandbox);
}
/***
****
***/
#define MEM_K 1024
#define MEM_K_STR "KiB"
#define MEM_M_STR "MiB"
#define MEM_G_STR "GiB"
#define MEM_T_STR "TiB"
#define DISK_K 1000
#define DISK_K_STR "kB"
#define DISK_M_STR "MB"
#define DISK_G_STR "GB"
#define DISK_T_STR "TB"
#define SPEED_K 1000
#define SPEED_K_STR "kB/s"
#define SPEED_M_STR "MB/s"
#define SPEED_G_STR "GB/s"
#define SPEED_T_STR "TB/s"
tr_session* libttest_session_init(tr_variant* settings)
{
size_t len;
char const* str;
char* sandbox;
char* path;
tr_quark q;
static bool formatters_inited = false;
tr_session* session;
tr_variant local_settings;
tr_variantInitDict(&local_settings, 10);
if (settings == NULL)
{
settings = &local_settings;
}
sandbox = libtest_sandbox_create();
if (!formatters_inited)
{
formatters_inited = true;
tr_formatter_mem_init(MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR);
tr_formatter_size_init(DISK_K, DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR);
tr_formatter_speed_init(SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR);
}
/* download dir */
q = TR_KEY_download_dir;
if (tr_variantDictFindStr(settings, q, &str, &len))
{
path = tr_strdup_printf("%s/%*.*s", sandbox, (int)len, (int)len, str);
}
else
{
path = tr_buildPath(sandbox, "Downloads", NULL);
}
tr_sys_dir_create(path, TR_SYS_DIR_CREATE_PARENTS, 0700, NULL);
tr_variantDictAddStr(settings, q, path);
tr_free(path);
/* incomplete dir */
q = TR_KEY_incomplete_dir;
if (tr_variantDictFindStr(settings, q, &str, &len))
{
path = tr_strdup_printf("%s/%*.*s", sandbox, (int)len, (int)len, str);
}
else
{
path = tr_buildPath(sandbox, "Incomplete", NULL);
}
tr_variantDictAddStr(settings, q, path);
tr_free(path);
path = tr_buildPath(sandbox, "blocklists", NULL);
tr_sys_dir_create(path, TR_SYS_DIR_CREATE_PARENTS, 0700, NULL);
tr_free(path);
q = TR_KEY_port_forwarding_enabled;
if (tr_variantDictFind(settings, q) == NULL)
{
tr_variantDictAddBool(settings, q, false);
}
q = TR_KEY_dht_enabled;
if (tr_variantDictFind(settings, q) == NULL)
{
tr_variantDictAddBool(settings, q, false);
}
q = TR_KEY_message_level;
if (tr_variantDictFind(settings, q) == NULL)
{
tr_variantDictAddInt(settings, q, verbose ? TR_LOG_DEBUG : TR_LOG_ERROR);
}
session = tr_sessionInit(sandbox, !verbose, settings);
tr_free(sandbox);
tr_variantFree(&local_settings);
return session;
}
void libttest_session_close(tr_session* session)
{
char* sandbox;
sandbox = tr_strdup(tr_sessionGetConfigDir(session));
tr_sessionClose(session);
tr_logFreeQueue(tr_logGetQueue());
session = NULL;
libtest_sandbox_destroy(sandbox);
tr_free(sandbox);
}
/***
****
***/
tr_torrent* libttest_zero_torrent_init(tr_session* session)
{
int err;
size_t metainfo_len;
char* metainfo;
char const* metainfo_base64;
tr_torrent* tor;
tr_ctor* ctor;
/*
1048576 files-filled-with-zeroes/1048576
4096 files-filled-with-zeroes/4096
512 files-filled-with-zeroes/512
*/
metainfo_base64 =
"ZDg6YW5ub3VuY2UzMTpodHRwOi8vd3d3LmV4YW1wbGUuY29tL2Fubm91bmNlMTA6Y3JlYXRlZCBi"
"eTI1OlRyYW5zbWlzc2lvbi8yLjYxICgxMzQwNykxMzpjcmVhdGlvbiBkYXRlaTEzNTg3MDQwNzVl"
"ODplbmNvZGluZzU6VVRGLTg0OmluZm9kNTpmaWxlc2xkNjpsZW5ndGhpMTA0ODU3NmU0OnBhdGhs"
"NzoxMDQ4NTc2ZWVkNjpsZW5ndGhpNDA5NmU0OnBhdGhsNDo0MDk2ZWVkNjpsZW5ndGhpNTEyZTQ6"
"cGF0aGwzOjUxMmVlZTQ6bmFtZTI0OmZpbGVzLWZpbGxlZC13aXRoLXplcm9lczEyOnBpZWNlIGxl"
"bmd0aGkzMjc2OGU2OnBpZWNlczY2MDpRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJtGExUv1726aj"
"/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJtGExUv17"
"26aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJtGEx"
"Uv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GIQxhJ"
"tGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZCS1GI"
"QxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8KT9ZC"
"S1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9umo/8K"
"T9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9e9um"
"o/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRhMVL9"
"e9umo/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMYSbRh"
"MVL9e9umo/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLUYhDGEm0YTFS/XvbpqP/Ck/WQktRiEMY"
"SbRhMVL9e9umo/8KT9ZCS1GIQxhJtGExUv1726aj/wpP1kJLOlf5A+Tz30nMBVuNM2hpV3wg/103"
"OnByaXZhdGVpMGVlZQ==";
/* create the torrent ctor */
metainfo = tr_base64_decode_str(metainfo_base64, &metainfo_len);
TR_ASSERT(metainfo != NULL);
TR_ASSERT(metainfo_len > 0);
TR_ASSERT(session != NULL);
ctor = tr_ctorNew(session);
tr_ctorSetMetainfo(ctor, (uint8_t*)metainfo, metainfo_len);
tr_ctorSetPaused(ctor, TR_FORCE, true);
/* create the torrent */
err = 0;
tor = tr_torrentNew(ctor, &err, NULL);
TR_ASSERT(err == 0);
/* cleanup */
tr_free(metainfo);
tr_ctorFree(ctor);
return tor;
}
void libttest_zero_torrent_populate(tr_torrent* tor, bool complete)
{
for (tr_file_index_t i = 0; i < tor->info.fileCount; ++i)
{
int err;
tr_sys_file_t fd;
char* path;
char* dirname;
tr_file const* file = &tor->info.files[i];
if (!complete && i == 0)
{
path = tr_strdup_printf("%s%c%s.part", tor->currentDir, TR_PATH_DELIMITER, file->name);
}
else
{
path = tr_strdup_printf("%s%c%s", tor->currentDir, TR_PATH_DELIMITER, file->name);
}
dirname = tr_sys_path_dirname(path, NULL);
tr_sys_dir_create(dirname, TR_SYS_DIR_CREATE_PARENTS, 0700, NULL);
fd = tr_sys_file_open(path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
for (uint64_t j = 0; j < file->length; ++j)
{
tr_sys_file_write(fd, (!complete && i == 0 && j < tor->info.pieceSize) ? "\1" : "\0", 1, NULL, NULL);
}
tr_sys_file_close(fd, NULL);
tr_free(dirname);
tr_free(path);
path = tr_torrentFindFile(tor, i);
TR_ASSERT(path != NULL);
err = errno;
TR_ASSERT(tr_sys_path_exists(path, NULL));
errno = err;
tr_free(path);
}
libttest_sync();
libttest_blockingTorrentVerify(tor);
if (complete)
{
TR_ASSERT(tr_torrentStat(tor)->leftUntilDone == 0);
}
else
{
TR_ASSERT(tr_torrentStat(tor)->leftUntilDone == tor->info.pieceSize);
}
}
/***
****
***/
static void onVerifyDone(tr_torrent* tor UNUSED, bool aborted UNUSED, void* done)
{
*(bool*)done = true;
}
void libttest_blockingTorrentVerify(tr_torrent* tor)
{
TR_ASSERT(tor->session != NULL);
TR_ASSERT(!tr_amInEventThread(tor->session));
bool done = false;
tr_torrentVerify(tor, onVerifyDone, &done);
while (!done)
{
tr_wait_msec(10);
}
}
static void build_parent_dir(char const* path)
{
char* dir;
tr_error* error = NULL;
int const tmperr = errno;
dir = tr_sys_path_dirname(path, NULL);
tr_sys_dir_create(dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error);
TR_ASSERT(error == NULL);
tr_free(dir);
errno = tmperr;
}
void libtest_create_file_with_contents(char const* path, void const* payload, size_t n)
{
tr_sys_file_t fd;
int const tmperr = errno;
build_parent_dir(path);
fd = tr_sys_file_open(path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE, 0600, NULL);
tr_sys_file_write(fd, payload, n, NULL, NULL);
tr_sys_file_close(fd, NULL);
libttest_sync();
errno = tmperr;
}
void libtest_create_file_with_string_contents(char const* path, char const* str)
{
libtest_create_file_with_contents(path, str, strlen(str));
}
void libtest_create_tmpfile_with_contents(char* tmpl, void const* payload, size_t n)
{
tr_sys_file_t fd;
int const tmperr = errno;
uint64_t n_left = n;
tr_error* error = NULL;
build_parent_dir(tmpl);
fd = tr_sys_file_open_temp(tmpl, NULL);
while (n_left > 0)
{
uint64_t n;
if (!tr_sys_file_write(fd, payload, n_left, &n, &error))
{
fprintf(stderr, "Error writing '%s': %s\n", tmpl, error->message);
tr_error_free(error);
break;
}
n_left -= n;
}
tr_sys_file_close(fd, NULL);
libttest_sync();
errno = tmperr;
}
void libttest_sync(void)
{
#ifndef _WIN32
sync();
#endif
}

View File

@ -1,192 +0,0 @@
/*
* This file Copyright (C) 2010-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
/* Note VERBOSE needs to be (un)defined before including this file */
#pragma once
#include <stdio.h>
#include <string.h> /* strlen() */
#include "transmission.h"
#include "utils.h" /* tr_strcmp0() */
extern int current_test;
extern bool verbose;
bool should_print(bool pass);
bool libtest_check(char const* file, int line, bool pass, bool condition, char const* condition_str);
bool libtest_check_bool(char const* file, int line, bool pass, bool lhs, bool rhs, char const* lhs_str, char const* op_str,
char const* rhs_str);
bool libtest_check_str(char const* file, int line, bool pass, char const* lhs, char const* rhs, char const* lhs_str,
char const* op_str, char const* rhs_str);
bool libtest_check_mem(char const* file, int line, bool pass, void const* lhs, void const* rhs, size_t size,
char const* lhs_str, char const* op_str, char const* rhs_str);
bool libtest_check_int(char const* file, int line, bool pass, intmax_t lhs, intmax_t rhs, char const* lhs_str,
char const* op_str, char const* rhs_str);
bool libtest_check_uint(char const* file, int line, bool pass, uintmax_t lhs, uintmax_t rhs, char const* lhs_str,
char const* op_str, char const* rhs_str);
bool libtest_check_ptr(char const* file, int line, bool pass, void const* lhs, void const* rhs, char const* lhs_str,
char const* op_str, char const* rhs_str);
/***
****
***/
#define check(condition) \
do \
{ \
++current_test; \
\
bool const check_result = (condition); \
\
if (!libtest_check(__FILE__, __LINE__, check_result, check_result, #condition)) \
{ \
return current_test; \
} \
} \
while (0)
#define check_bool(lhs, op, rhs) \
do \
{ \
++current_test; \
\
bool const check_lhs = (lhs); \
bool const check_rhs = (rhs); \
\
bool const check_result = check_lhs op check_rhs; \
\
if (!libtest_check_bool(__FILE__, __LINE__, check_result, check_lhs, check_rhs, #lhs, #op, #rhs)) \
{ \
return current_test; \
} \
} \
while (0)
#define check_str(lhs, op, rhs) \
do \
{ \
++current_test; \
\
char const* const check_lhs = (lhs); \
char const* const check_rhs = (rhs); \
\
bool const check_result = tr_strcmp0(check_lhs, check_rhs) op 0; \
\
if (!libtest_check_str(__FILE__, __LINE__, check_result, check_lhs, check_rhs, #lhs, #op, #rhs)) \
{ \
return current_test; \
} \
} \
while (0)
#define check_mem(lhs, op, rhs, size) \
do \
{ \
++current_test; \
\
void const* const check_lhs = (lhs); \
void const* const check_rhs = (rhs); \
size_t const check_mem_size = (size); \
\
bool const check_result = tr_memcmp0(check_lhs, check_rhs, check_mem_size) op 0; \
\
if (!libtest_check_mem(__FILE__, __LINE__, check_result, check_lhs, check_rhs, check_mem_size, #lhs, #op, #rhs)) \
{ \
return current_test; \
} \
} \
while (0)
#define check_int(lhs, op, rhs) \
do \
{ \
++current_test; \
\
intmax_t const check_lhs = (lhs); \
intmax_t const check_rhs = (rhs); \
\
bool const check_result = check_lhs op check_rhs; \
\
if (!libtest_check_int(__FILE__, __LINE__, check_result, check_lhs, check_rhs, #lhs, #op, #rhs)) \
{ \
return current_test; \
} \
} \
while (0)
#define check_uint(lhs, op, rhs) \
do \
{ \
++current_test; \
\
uintmax_t const check_lhs = (lhs); \
uintmax_t const check_rhs = (rhs); \
\
bool const check_result = check_lhs op check_rhs; \
\
if (!libtest_check_uint(__FILE__, __LINE__, check_result, check_lhs, check_rhs, #lhs, #op, #rhs)) \
{ \
return current_test; \
} \
} \
while (0)
#define check_ptr(lhs, op, rhs) \
do \
{ \
++current_test; \
\
void const* const check_lhs = (lhs); \
void const* const check_rhs = (rhs); \
\
bool const check_result = check_lhs op check_rhs; \
\
if (!libtest_check_ptr(__FILE__, __LINE__, check_result, check_lhs, check_rhs, #lhs, #op, #rhs)) \
{ \
return current_test; \
} \
} \
while (0)
/***
****
***/
typedef int (* testFunc)(void);
#define NUM_TESTS(tarray) ((int)(sizeof(tarray) / sizeof(tarray[0])))
int runTests(testFunc const* const tests, int numTests);
#define MAIN_SINGLE_TEST(test) \
int main(void) \
{ \
testFunc const tests[] = { test }; \
return runTests(tests, 1); \
}
tr_session* libttest_session_init(struct tr_variant* settings);
void libttest_session_close(tr_session* session);
void libttest_zero_torrent_populate(tr_torrent* tor, bool complete);
tr_torrent* libttest_zero_torrent_init(tr_session* session);
void libttest_blockingTorrentVerify(tr_torrent* tor);
void libtest_create_file_with_contents(char const* path, void const* contents, size_t n);
void libtest_create_tmpfile_with_contents(char* tmpl, void const* payload, size_t n);
void libtest_create_file_with_string_contents(char const* path, char const* str);
char* libtest_sandbox_create(void);
void libtest_sandbox_destroy(char const* sandbox);
void libttest_sync(void);

View File

@ -11,12 +11,10 @@
#include <stddef.h> /* size_t */
#include "file.h" /* tr_sys_file_t */
#include "tr-macros.h"
#include "utils.h" /* TR_GNUC_PRINTF, TR_GNUC_NONNULL */
#ifdef __cplusplus
extern "C"
{
#endif
TR_BEGIN_DECLS
#define TR_LOG_MAX_QUEUE_LENGTH 10000
@ -77,8 +75,6 @@ void tr_logAddDeep(char const* file, int line, char const* name, char const* fmt
/** @brief set the buffer with the current time formatted for deep logging. */
char* tr_logGetTimeStr(char* buf, size_t buflen) TR_GNUC_NONNULL(1);
#ifdef __cplusplus
}
#endif
/** @} */
TR_END_DECLS

View File

@ -1,69 +0,0 @@
/*
* This file Copyright (C) 2010-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "transmission.h"
#include "magnet.h"
#include "utils.h"
#include "libtransmission-test.h"
static int test1(void)
{
char const* uri;
tr_magnet_info* info;
uint8_t const dec[] =
{
210, 53, 64, 16, 163, 202, 74, 222, 91, 116,
39, 187, 9, 58, 98, 163, 137, 159, 243, 129
};
uri =
"magnet:?xt=urn:btih:"
"d2354010a3ca4ade5b7427bb093a62a3899ff381"
"&dn=Display%20Name"
"&tr=http%3A%2F%2Ftracker.openbittorrent.com%2Fannounce"
"&tr=http%3A%2F%2Ftracker.opentracker.org%2Fannounce"
"&ws=http%3A%2F%2Fserver.webseed.org%2Fpath%2Fto%2Ffile";
info = tr_magnetParse(uri);
check_ptr(info, !=, NULL);
check_int(info->trackerCount, ==, 2);
check_str(info->trackers[0], ==, "http://tracker.openbittorrent.com/announce");
check_str(info->trackers[1], ==, "http://tracker.opentracker.org/announce");
check_int(info->webseedCount, ==, 1);
check_str(info->webseeds[0], ==, "http://server.webseed.org/path/to/file");
check_str(info->displayName, ==, "Display Name");
check_mem(info->hash, ==, dec, 20);
tr_magnetFree(info);
info = NULL;
/* same thing but in base32 encoding */
uri =
"magnet:?xt=urn:btih:"
"2I2UAEFDZJFN4W3UE65QSOTCUOEZ744B"
"&dn=Display%20Name"
"&tr=http%3A%2F%2Ftracker.openbittorrent.com%2Fannounce"
"&ws=http%3A%2F%2Fserver.webseed.org%2Fpath%2Fto%2Ffile"
"&tr=http%3A%2F%2Ftracker.opentracker.org%2Fannounce";
info = tr_magnetParse(uri);
check(info != NULL);
check_int(info->trackerCount, ==, 2);
check_str(info->trackers[0], ==, "http://tracker.openbittorrent.com/announce");
check_str(info->trackers[1], ==, "http://tracker.opentracker.org/announce");
check_int(info->webseedCount, ==, 1);
check_str(info->webseeds[0], ==, "http://server.webseed.org/path/to/file");
check_str(info->displayName, ==, "Display Name");
check_mem(info->hash, ==, dec, 20);
tr_magnetFree(info);
info = NULL;
return 0;
}
MAIN_SINGLE_TEST(test1)

View File

@ -12,9 +12,12 @@
#error only libtransmission should #include this header.
#endif
#include "tr-macros.h"
#include "transmission.h"
#include "variant.h"
TR_BEGIN_DECLS
typedef struct tr_magnet_info
{
uint8_t hash[20];
@ -36,3 +39,5 @@ struct tr_variant;
void tr_magnetCreateMetainfo(tr_magnet_info const*, tr_variant*);
void tr_magnetFree(tr_magnet_info* info);
TR_END_DECLS

View File

@ -1,288 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "libtransmission-test.h"
#include "transmission.h"
#include "crypto-utils.h"
#include "file.h"
#include "makemeta.h"
#include <stdlib.h> /* mktemp() */
#include <string.h> /* strlen() */
static int test_single_file_impl(tr_tracker_info const* trackers, size_t const trackerCount, void const* payload,
size_t const payloadSize, char const* comment, bool isPrivate)
{
char* sandbox;
char* input_file;
char* torrent_file;
tr_metainfo_builder* builder;
tr_ctor* ctor;
tr_parse_result parse_result;
tr_info inf;
char* tmpstr;
/* set up our local test sandbox */
sandbox = libtest_sandbox_create();
/* create a single input file */
input_file = tr_buildPath(sandbox, "test.XXXXXX", NULL);
libtest_create_tmpfile_with_contents(input_file, payload, payloadSize);
builder = tr_metaInfoBuilderCreate(input_file);
check_str(builder->top, ==, input_file);
check_int(builder->fileCount, ==, 1);
check_str(builder->files[0].filename, ==, input_file);
check_int(builder->files[0].size, ==, payloadSize);
check_int(builder->totalSize, ==, payloadSize);
check(!builder->isFolder);
check(!builder->abortFlag);
/* have tr_makeMetaInfo() build the .torrent file */
torrent_file = tr_strdup_printf("%s.torrent", input_file);
tr_makeMetaInfo(builder, torrent_file, trackers, trackerCount, comment, isPrivate);
check_bool(isPrivate, ==, builder->isPrivate);
check_str(builder->outputFile, ==, torrent_file);
check_str(builder->comment, ==, comment);
check_int(builder->trackerCount, ==, trackerCount);
while (!builder->isDone)
{
tr_wait_msec(100);
}
/* now let's check our work: parse the .torrent file */
ctor = tr_ctorNew(NULL);
libttest_sync();
tr_ctorSetMetainfoFromFile(ctor, torrent_file);
parse_result = tr_torrentParse(ctor, &inf);
check_int(parse_result, ==, TR_PARSE_OK);
/* quick check of some of the parsed metainfo */
check_int(inf.totalSize, ==, payloadSize);
tmpstr = tr_sys_path_basename(input_file, NULL);
check_str(inf.name, ==, tmpstr);
tr_free(tmpstr);
check_str(inf.comment, ==, comment);
check_int(inf.fileCount, ==, 1);
check_int(inf.isPrivate, ==, isPrivate);
check(!inf.isFolder);
check_int(inf.trackerCount, ==, trackerCount);
/* cleanup */
tr_free(torrent_file);
tr_free(input_file);
tr_ctorFree(ctor);
tr_metainfoFree(&inf);
tr_metaInfoBuilderFree(builder);
libtest_sandbox_destroy(sandbox);
tr_free(sandbox);
return 0;
}
static int test_single_file(void)
{
tr_tracker_info trackers[16];
size_t trackerCount;
bool isPrivate;
char const* comment;
char const* payload;
size_t payloadSize;
trackerCount = 0;
trackers[trackerCount].tier = trackerCount;
trackers[trackerCount].announce = (char*)"udp://tracker.openbittorrent.com:80";
++trackerCount;
trackers[trackerCount].tier = trackerCount;
trackers[trackerCount].announce = (char*)"udp://tracker.publicbt.com:80";
++trackerCount;
payload = "Hello, World!\n";
payloadSize = strlen(payload);
comment = "This is the comment";
isPrivate = false;
test_single_file_impl(trackers, trackerCount, payload, payloadSize, comment, isPrivate);
return 0;
}
static int test_single_directory_impl(tr_tracker_info const* trackers, size_t const trackerCount, void const** payloads,
size_t const* payloadSizes, size_t const payloadCount, char const* comment,
bool const isPrivate)
{
char* sandbox;
char* torrent_file;
tr_metainfo_builder* builder;
tr_ctor* ctor;
tr_parse_result parse_result;
tr_info inf;
char* top;
char** files;
size_t totalSize;
char* tmpstr;
/* set up our local test sandbox */
sandbox = libtest_sandbox_create();
/* create the top temp directory */
top = tr_buildPath(sandbox, "folder.XXXXXX", NULL);
tr_sys_dir_create_temp(top, NULL);
/* build the payload files that go into the top temp directory */
files = tr_new(char*, payloadCount);
totalSize = 0;
for (size_t i = 0; i < payloadCount; i++)
{
char tmpl[16];
tr_snprintf(tmpl, sizeof(tmpl), "file.%04zu%s", i, "XXXXXX");
files[i] = tr_buildPath(top, tmpl, NULL);
libtest_create_tmpfile_with_contents(files[i], payloads[i], payloadSizes[i]);
totalSize += payloadSizes[i];
}
libttest_sync();
/* init the builder */
builder = tr_metaInfoBuilderCreate(top);
check(!builder->abortFlag);
check_str(builder->top, ==, top);
check_int(builder->fileCount, ==, payloadCount);
check_int(builder->totalSize, ==, totalSize);
check(builder->isFolder);
for (size_t i = 0; i < builder->fileCount; i++)
{
check_str(builder->files[i].filename, ==, files[i]);
check_int(builder->files[i].size, ==, payloadSizes[i]);
}
/* call tr_makeMetaInfo() to build the .torrent file */
torrent_file = tr_strdup_printf("%s.torrent", top);
tr_makeMetaInfo(builder, torrent_file, trackers, trackerCount, comment, isPrivate);
check_bool(isPrivate, ==, builder->isPrivate);
check_str(builder->outputFile, ==, torrent_file);
check_str(builder->comment, ==, comment);
check_int(builder->trackerCount, ==, trackerCount);
while (!builder->isDone)
{
tr_wait_msec(100);
}
/* now let's check our work: parse the .torrent file */
ctor = tr_ctorNew(NULL);
libttest_sync();
tr_ctorSetMetainfoFromFile(ctor, torrent_file);
parse_result = tr_torrentParse(ctor, &inf);
check_int(parse_result, ==, TR_PARSE_OK);
/* quick check of some of the parsed metainfo */
check_int(inf.totalSize, ==, totalSize);
tmpstr = tr_sys_path_basename(top, NULL);
check_str(inf.name, ==, tmpstr);
tr_free(tmpstr);
check_str(inf.comment, ==, comment);
check_int(inf.fileCount, ==, payloadCount);
check_int(inf.isPrivate, ==, isPrivate);
check_int(inf.isFolder, ==, builder->isFolder);
check_int(inf.trackerCount, ==, trackerCount);
/* cleanup */
tr_free(torrent_file);
tr_ctorFree(ctor);
tr_metainfoFree(&inf);
tr_metaInfoBuilderFree(builder);
for (size_t i = 0; i < payloadCount; i++)
{
tr_free(files[i]);
}
tr_free(files);
libtest_sandbox_destroy(sandbox);
tr_free(sandbox);
tr_free(top);
return 0;
}
static int test_single_directory_random_payload_impl(tr_tracker_info const* trackers, size_t const trackerCount,
size_t const maxFileCount, size_t const maxFileSize, char const* comment,
bool const isPrivate)
{
void** payloads;
size_t* payloadSizes;
size_t payloadCount;
/* build random payloads */
payloadCount = 1 + tr_rand_int_weak(maxFileCount);
payloads = tr_new0(void*, payloadCount);
payloadSizes = tr_new0(size_t, payloadCount);
for (size_t i = 0; i < payloadCount; i++)
{
size_t const n = 1 + tr_rand_int_weak(maxFileSize);
payloads[i] = tr_new(char, n);
tr_rand_buffer(payloads[i], n);
payloadSizes[i] = n;
}
/* run the test */
test_single_directory_impl(trackers, trackerCount, (void const**)payloads, payloadSizes, payloadCount, comment, isPrivate);
/* cleanup */
for (size_t i = 0; i < payloadCount; i++)
{
tr_free(payloads[i]);
}
tr_free(payloads);
tr_free(payloadSizes);
return 0;
}
#define DEFAULT_MAX_FILE_COUNT 16
#define DEFAULT_MAX_FILE_SIZE 1024
static int test_single_directory_random_payload(void)
{
tr_tracker_info trackers[16];
size_t trackerCount;
bool isPrivate;
char const* comment;
trackerCount = 0;
trackers[trackerCount].tier = trackerCount;
trackers[trackerCount].announce = (char*)"udp://tracker.openbittorrent.com:80";
++trackerCount;
trackers[trackerCount].tier = trackerCount;
trackers[trackerCount].announce = (char*)"udp://tracker.publicbt.com:80";
++trackerCount;
comment = "This is the comment";
isPrivate = false;
for (size_t i = 0; i < 10; i++)
{
test_single_directory_random_payload_impl(trackers, trackerCount, DEFAULT_MAX_FILE_COUNT, DEFAULT_MAX_FILE_SIZE,
comment, isPrivate);
}
return 0;
}
int main(void)
{
testFunc const tests[] =
{
test_single_file,
test_single_directory_random_payload
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -43,12 +43,11 @@ static struct FileList* getFiles(char const* dir, char const* base, struct FileL
return NULL;
}
char* buf;
char* buf = tr_buildPath(dir, base, NULL);
tr_sys_path_native_separators(buf);
tr_sys_path_info info;
tr_error* error = NULL;
buf = tr_buildPath(dir, base, NULL);
if (!tr_sys_path_get_info(buf, 0, &info, &error))
{
tr_logAddError(_("Torrent Creator is skipping file \"%s\": %s"), buf, error->message);

View File

@ -8,10 +8,10 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include "tr-macros.h"
#include "transmission.h"
TR_BEGIN_DECLS
typedef struct tr_metainfo_builder_file
{
@ -117,6 +117,4 @@ void tr_metaInfoBuilderFree(tr_metainfo_builder*);
void tr_makeMetaInfo(tr_metainfo_builder* builder, char const* outputFile, tr_tracker_info const* trackers, int trackerCount,
char const* comment, bool isPrivate);
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -595,14 +595,14 @@ static char const* tr_metainfoParseImpl(tr_session const* session, tr_info* inf,
}
else
{
size_t len;
char* bstr = tr_variantToStr(infoDict, TR_VARIANT_FMT_BENC, &len);
tr_sha1(inf->hash, bstr, (int)len, NULL);
size_t blen;
char* bstr = tr_variantToStr(infoDict, TR_VARIANT_FMT_BENC, &blen);
tr_sha1(inf->hash, bstr, (int)blen, NULL);
tr_sha1_to_hex(inf->hashString, inf->hash);
if (infoDictLength != NULL)
{
*infoDictLength = len;
*infoDictLength = blen;
}
tr_free(bstr);
@ -706,9 +706,9 @@ static char const* tr_metainfoParseImpl(tr_session const* session, tr_info* inf,
inf->pieceCount = len / SHA_DIGEST_LENGTH;
inf->pieces = tr_new0(tr_piece, inf->pieceCount);
for (tr_piece_index_t i = 0; i < inf->pieceCount; i++)
for (tr_piece_index_t pi = 0; pi < inf->pieceCount; ++pi)
{
memcpy(inf->pieces[i].hash, &raw[i * SHA_DIGEST_LENGTH], SHA_DIGEST_LENGTH);
memcpy(inf->pieces[pi].hash, &raw[pi * SHA_DIGEST_LENGTH], SHA_DIGEST_LENGTH);
}
}

View File

@ -14,6 +14,9 @@
#include "transmission.h"
#include "variant.h"
#include "tr-macros.h"
TR_BEGIN_DECLS
enum tr_metainfo_basename_format
{
@ -33,3 +36,5 @@ void tr_metainfoMigrateFile(tr_session const* session, tr_info const* info, enum
/** @brief Private function that's exposed here only for unit tests */
char* tr_metainfo_sanitize_path_component(char const* str, size_t len, bool* is_adjusted);
TR_END_DECLS

View File

@ -1,240 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <string.h> /* strcmp() */
#include <stdio.h>
#include <event2/buffer.h>
#include "transmission.h"
#include "cache.h"
#include "file.h"
#include "resume.h"
#include "trevent.h"
#include "torrent.h" /* tr_isTorrent() */
#include "variant.h"
#include "libtransmission-test.h"
/***
****
***/
static void zeroes_completeness_func(tr_torrent* torrent UNUSED, tr_completeness completeness, bool wasRunning UNUSED,
void* user_data)
{
*(tr_completeness*)user_data = completeness;
}
#define check_file_location(tor, i, expected_path) \
do \
{ \
char* path = tr_torrentFindFile(tor, i); \
char* expected = expected_path; \
check_str(path, ==, expected); \
tr_free(expected); \
tr_free(path); \
} \
while (0)
struct test_incomplete_dir_data
{
tr_session* session;
tr_torrent* tor;
tr_block_index_t block;
tr_piece_index_t pieceIndex;
uint32_t offset;
struct evbuffer* buf;
bool done;
};
static void test_incomplete_dir_threadfunc(void* vdata)
{
struct test_incomplete_dir_data* data = vdata;
tr_cacheWriteBlock(data->session->cache, data->tor, 0, data->offset, data->tor->blockSize, data->buf);
tr_torrentGotBlock(data->tor, data->block);
data->done = true;
}
static int test_incomplete_dir_impl(char const* incomplete_dir, char const* download_dir)
{
tr_session* session;
tr_torrent* tor;
tr_completeness completeness;
tr_completeness const completeness_unset = -1;
time_t const deadline = time(NULL) + 300;
tr_variant settings;
/* init the session */
tr_variantInitDict(&settings, 3);
tr_variantDictAddStr(&settings, TR_KEY_download_dir, download_dir);
tr_variantDictAddStr(&settings, TR_KEY_incomplete_dir, incomplete_dir);
tr_variantDictAddBool(&settings, TR_KEY_incomplete_dir_enabled, true);
session = libttest_session_init(&settings);
tr_variantFree(&settings);
download_dir = tr_sessionGetDownloadDir(session);
incomplete_dir = tr_sessionGetIncompleteDir(session);
/* init an incomplete torrent.
the test zero_torrent will be missing its first piece */
tor = libttest_zero_torrent_init(session);
libttest_zero_torrent_populate(tor, false);
check_uint(tr_torrentStat(tor)->leftUntilDone, ==, tor->info.pieceSize);
check_file_location(tor, 0, tr_strdup_printf("%s/%s.part", incomplete_dir, tor->info.files[0].name));
check_file_location(tor, 1, tr_buildPath(incomplete_dir, tor->info.files[1].name, NULL));
check_uint(tr_torrentStat(tor)->leftUntilDone, ==, tor->info.pieceSize);
completeness = completeness_unset;
tr_torrentSetCompletenessCallback(tor, zeroes_completeness_func, &completeness);
/* now finish writing it */
{
tr_block_index_t first;
tr_block_index_t last;
char* zero_block = tr_new0(char, tor->blockSize);
struct test_incomplete_dir_data data;
data.session = session;
data.tor = tor;
data.pieceIndex = 0;
data.buf = evbuffer_new();
tr_torGetPieceBlockRange(tor, data.pieceIndex, &first, &last);
for (tr_block_index_t block_index = first; block_index <= last; ++block_index)
{
evbuffer_add(data.buf, zero_block, tor->blockSize);
data.block = block_index;
data.done = false;
data.offset = data.block * tor->blockSize;
tr_runInEventThread(session, test_incomplete_dir_threadfunc, &data);
do
{
tr_wait_msec(50);
}
while (!data.done);
}
evbuffer_free(data.buf);
tr_free(zero_block);
}
libttest_blockingTorrentVerify(tor);
check_uint(tr_torrentStat(tor)->leftUntilDone, ==, 0);
while (completeness == completeness_unset && time(NULL) <= deadline)
{
tr_wait_msec(50);
}
check_int(completeness, ==, TR_SEED);
for (tr_file_index_t file_index = 0; file_index < tor->info.fileCount; ++file_index)
{
check_file_location(tor, file_index, tr_buildPath(download_dir, tor->info.files[file_index].name, NULL));
}
/* cleanup */
tr_torrentRemove(tor, true, tr_sys_path_remove);
libttest_session_close(session);
return 0;
}
static int test_incomplete_dir(void)
{
int rv;
/* test what happens when incompleteDir is a subdir of downloadDir*/
if ((rv = test_incomplete_dir_impl("Downloads/Incomplete", "Downloads")) != 0)
{
return rv;
}
/* test what happens when downloadDir is a subdir of incompleteDir */
if ((rv = test_incomplete_dir_impl("Downloads", "Downloads/Complete")) != 0)
{
return rv;
}
/* test what happens when downloadDir and incompleteDir are siblings */
if ((rv = test_incomplete_dir_impl("Incomplete", "Downloads")) != 0)
{
return rv;
}
return 0;
}
/***
****
***/
static int test_set_location(void)
{
int state;
char* target_dir;
tr_torrent* tor;
tr_session* session;
time_t const deadline = time(NULL) + 300;
/* init the session */
session = libttest_session_init(NULL);
target_dir = tr_buildPath(tr_sessionGetConfigDir(session), "target", NULL);
tr_sys_dir_create(target_dir, TR_SYS_DIR_CREATE_PARENTS, 0777, NULL);
/* init a torrent. */
tor = libttest_zero_torrent_init(session);
libttest_zero_torrent_populate(tor, true);
libttest_blockingTorrentVerify(tor);
check_uint(tr_torrentStat(tor)->leftUntilDone, ==, 0);
/* now move it */
state = -1;
tr_torrentSetLocation(tor, target_dir, true, NULL, &state);
while (state == TR_LOC_MOVING && time(NULL) <= deadline)
{
tr_wait_msec(50);
}
check_int(state, ==, TR_LOC_DONE);
/* confirm the torrent is still complete after being moved */
libttest_blockingTorrentVerify(tor);
check_uint(tr_torrentStat(tor)->leftUntilDone, ==, 0);
/* confirm the filest really got moved */
libttest_sync();
for (tr_file_index_t file_index = 0; file_index < tor->info.fileCount; ++file_index)
{
check_file_location(tor, file_index, tr_buildPath(target_dir, tor->info.files[file_index].name, NULL));
}
/* cleanup */
tr_free(target_dir);
tr_torrentRemove(tor, true, tr_sys_path_remove);
libttest_session_close(session);
return 0;
}
/***
****
***/
int main(void)
{
testFunc const tests[] =
{
test_incomplete_dir,
test_set_location
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -168,11 +168,11 @@ int tr_natpmpPulse(struct tr_natpmp* nat, tr_port private_port, bool is_enabled,
if (val >= 0)
{
int const private_port = resp.pnu.newportmapping.privateport;
int const unmapped_port = resp.pnu.newportmapping.privateport;
tr_logAddNamedInfo(getKey(), _("no longer forwarding port %d"), private_port);
tr_logAddNamedInfo(getKey(), _("no longer forwarding port %d"), unmapped_port);
if (nat->private_port == private_port)
if (nat->private_port == unmapped_port)
{
nat->private_port = 0;
nat->public_port = 0;

View File

@ -34,6 +34,7 @@
#include <event2/util.h>
#include <stdint.h>
#include <libutp/utp.h>
#include "transmission.h"
@ -766,3 +767,17 @@ bool tr_address_is_valid_for_peers(tr_address const* addr, tr_port port)
return port != 0 && tr_address_is_valid(addr) && !isIPv6LinkLocalAddress(addr) && !isIPv4MappedAddress(addr) &&
!isMartianAddr(addr);
}
struct tr_peer_socket tr_peer_socket_tcp_create(tr_socket_t const handle)
{
TR_ASSERT(handle != TR_BAD_SOCKET);
struct tr_peer_socket const ret = { .type = TR_PEER_SOCKET_TYPE_TCP, .handle.tcp = handle };
return ret;
}
struct tr_peer_socket tr_peer_socket_utp_create(struct UTPSocket* const handle)
{
TR_ASSERT(handle != NULL);
struct tr_peer_socket const ret = { .type = TR_PEER_SOCKET_TYPE_UTP, .handle.utp = handle };
return ret;
}

View File

@ -35,6 +35,10 @@
#include <netinet/in.h>
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
#ifdef _WIN32
typedef SOCKET tr_socket_t;
#define TR_BAD_SOCKET INVALID_SOCKET
@ -129,10 +133,6 @@ enum
struct tr_session;
struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed);
struct tr_peer_socket tr_netOpenPeerUTPSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed);
tr_socket_t tr_netBindTCP(tr_address const* addr, tr_port port, bool suppressMsgs);
tr_socket_t tr_netAccept(tr_session* session, tr_socket_t bound, tr_address* setme_addr, tr_port* setme_port);
@ -154,3 +154,5 @@ bool tr_net_hasIPv6(tr_port);
char* tr_net_strerror(char* buf, size_t buflen, int err);
unsigned char const* tr_globalIPv6(void);
TR_END_DECLS

View File

@ -13,6 +13,7 @@
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <stdint.h>
#include <libutp/utp.h>
#include "transmission.h"

View File

@ -113,15 +113,15 @@ tr_peerIo* tr_peerIoNewOutgoing(tr_session* session, struct tr_bandwidth* parent
uint8_t const* torrentHash, bool isSeed, bool utp);
tr_peerIo* tr_peerIoNewIncoming(tr_session* session, struct tr_bandwidth* parent, struct tr_address const* addr, tr_port port,
struct tr_peer_socket socket);
struct tr_peer_socket const socket);
void tr_peerIoRefImpl(char const* file, int line, tr_peerIo* io);
#define tr_peerIoRef(io) tr_peerIoRefImpl(__FILE__, __LINE__, (io));
#define tr_peerIoRef(io) tr_peerIoRefImpl(__FILE__, __LINE__, (io))
void tr_peerIoUnrefImpl(char const* file, int line, tr_peerIo* io);
#define tr_peerIoUnref(io) tr_peerIoUnrefImpl(__FILE__, __LINE__, (io));
#define tr_peerIoUnref(io) tr_peerIoUnrefImpl(__FILE__, __LINE__, (io))
#define PEER_IO_MAGIC_NUMBER 206745

View File

@ -13,6 +13,7 @@
#include <event2/event.h>
#include <stdint.h>
#include <libutp/utp.h>
#include "transmission.h"
@ -60,8 +61,6 @@ enum
/* max number of peers to ask for per second overall.
* this throttle is to avoid overloading the router */
MAX_CONNECTIONS_PER_SECOND = 12,
/* */
MAX_CONNECTIONS_PER_PULSE = (int)(MAX_CONNECTIONS_PER_SECOND * (RECONNECT_PERIOD_MSEC / 1000.0)),
/* number of bad pieces a peer is allowed to send before we ban them */
MAX_BAD_PIECES_PER_PEER = 5,
/* amount of time to keep a list of request pieces lying around
@ -2098,7 +2097,6 @@ static bool myHandshakeDoneCB(tr_handshake* handshake, tr_peerIo* io, bool readA
else
{
tr_quark client;
tr_peerIo* io;
char buf[128];
if (peer_id != NULL)
@ -2110,9 +2108,9 @@ static bool myHandshakeDoneCB(tr_handshake* handshake, tr_peerIo* io, bool readA
client = TR_KEY_NONE;
}
io = tr_handshakeStealIO(handshake); /* this steals its refcount too, which is balanced by our unref in peerDelete() */
tr_peerIoSetParent(io, &s->tor->bandwidth);
createBitTorrentPeer(s->tor, io, atom, client);
tr_peerIo* stolen = tr_handshakeStealIO(handshake); /* this steals its refcount too, which is balanced by our unref in peerDelete() */
tr_peerIoSetParent(stolen, &s->tor->bandwidth);
createBitTorrentPeer(s->tor, stolen, atom, client);
success = true;
}
@ -2559,17 +2557,17 @@ void tr_peerUpdateProgress(tr_torrent* tor, tr_peer* peer)
}
/* clamp the progress range */
if (peer->progress < 0.0)
if (peer->progress < 0.0f)
{
peer->progress = 0.0;
peer->progress = 0.0f;
}
if (peer->progress > 1.0)
if (peer->progress > 1.0f)
{
peer->progress = 1.0;
peer->progress = 1.0f;
}
if (peer->atom != NULL && peer->progress >= 1.0)
if (peer->atom != NULL && peer->progress >= 1.0f)
{
atomSetSeed(tor->swarm, peer->atom);
}
@ -2699,9 +2697,9 @@ uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
return 0;
}
size_t const n = tr_ptrArraySize(&s->peers);
size_t const peer_count = tr_ptrArraySize(&s->peers);
if (n == 0)
if (peer_count == 0)
{
return 0;
}
@ -2709,7 +2707,7 @@ uint64_t tr_peerMgrGetDesiredAvailable(tr_torrent const* tor)
{
tr_peer const** peers = (tr_peer const**)tr_ptrArrayBase(&s->peers);
for (size_t i = 0; i < n; ++i)
for (size_t i = 0; i < peer_count; ++i)
{
if (peers[i]->atom != NULL && atomIsSeed(peers[i]->atom))
{
@ -3779,6 +3777,7 @@ static void reconnectPulse(evutil_socket_t foo UNUSED, short bar UNUSED, void* v
}
/* try to make new peer connections */
int const MAX_CONNECTIONS_PER_PULSE = (int)(MAX_CONNECTIONS_PER_SECOND * (RECONNECT_PERIOD_MSEC / 1000.0));
makeNewPeerConnections(mgr, MAX_CONNECTIONS_PER_PULSE);
}
@ -4002,7 +4001,7 @@ static void atomPulse(evutil_socket_t foo UNUSED, short bar UNUSED, void* vmgr)
s->pool = TR_PTR_ARRAY_INIT;
qsort(keep, keepCount, sizeof(struct peer_atom*), compareAtomPtrsByAddress);
for (int i = 0; i < keepCount; ++i)
for (i = 0; i < keepCount; ++i)
{
tr_ptrArrayAppend(&s->pool, keep[i]);
}

View File

@ -20,6 +20,7 @@
#include "net.h" /* tr_address */
#include "peer-common.h"
#include "peer-socket.h"
#include "quark.h"
/**
@ -87,7 +88,7 @@ bool tr_peerMgrDidPeerRequest(tr_torrent const* torrent, tr_peer const* peer, tr
void tr_peerMgrRebuildRequests(tr_torrent* torrent);
void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address* addr, tr_port port, struct tr_peer_socket socket);
void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address* addr, tr_port port, struct tr_peer_socket const socket);
tr_pex* tr_peerMgrCompactToPex(void const* compact, size_t compactLen, uint8_t const* added_f, size_t added_f_len,
size_t* setme_pex_count);

View File

@ -1117,15 +1117,15 @@ static void parseUtMetadata(tr_peerMsgs* msgs, uint32_t msglen, struct evbuffer*
}
else
{
tr_variant tmp;
tr_variant v;
struct evbuffer* payload;
struct evbuffer* out = msgs->outMessages;
/* build the rejection message */
tr_variantInitDict(&tmp, 2);
tr_variantDictAddInt(&tmp, TR_KEY_msg_type, METADATA_MSG_TYPE_REJECT);
tr_variantDictAddInt(&tmp, TR_KEY_piece, piece);
payload = tr_variantToBuf(&tmp, TR_VARIANT_FMT_BENC);
tr_variantInitDict(&v, 2);
tr_variantDictAddInt(&v, TR_KEY_msg_type, METADATA_MSG_TYPE_REJECT);
tr_variantDictAddInt(&v, TR_KEY_piece, piece);
payload = tr_variantToBuf(&v, TR_VARIANT_FMT_BENC);
/* write it out as a LTEP message to our outMessages buffer */
evbuffer_add_uint32(out, 2 * sizeof(uint8_t) + evbuffer_get_length(payload));
@ -1137,7 +1137,7 @@ static void parseUtMetadata(tr_peerMsgs* msgs, uint32_t msglen, struct evbuffer*
/* cleanup */
evbuffer_free(payload);
tr_variantFree(&tmp);
tr_variantFree(&v);
}
}

View File

@ -14,6 +14,9 @@
#include "net.h"
#include "tr-assert.h"
#include "tr-macros.h"
TR_BEGIN_DECLS
enum tr_peer_socket_type
{
@ -36,14 +39,15 @@ struct tr_peer_socket
#define TR_PEER_SOCKET_INIT ((struct tr_peer_socket){ .type = TR_PEER_SOCKET_TYPE_NONE })
static inline struct tr_peer_socket tr_peer_socket_tcp_create(tr_socket_t const handle)
{
TR_ASSERT(handle != TR_BAD_SOCKET);
return (struct tr_peer_socket){ .type = TR_PEER_SOCKET_TYPE_TCP, .handle.tcp = handle };
}
struct tr_peer_socket tr_peer_socket_tcp_create(tr_socket_t const handle);
static inline struct tr_peer_socket tr_peer_socket_utp_create(struct UTPSocket* const handle)
{
TR_ASSERT(handle != NULL);
return (struct tr_peer_socket){ .type = TR_PEER_SOCKET_TYPE_UTP, .handle.utp = handle };
}
struct tr_peer_socket tr_peer_socket_utp_create(struct UTPSocket* const handle);
struct tr_session;
struct tr_address;
struct tr_peer_socket tr_netOpenPeerSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed);
struct tr_peer_socket tr_netOpenPeerUTPSocket(tr_session* session, tr_address const* addr, tr_port port, bool clientIsSeed);
TR_END_DECLS

View File

@ -1,49 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <string.h> /* strlen() */
#include "transmission.h"
#include "quark.h"
#include "libtransmission-test.h"
static int test_static_quarks(void)
{
for (int i = 0; i < TR_N_KEYS; i++)
{
tr_quark q;
size_t len;
char const* str;
str = tr_quark_get_string((tr_quark)i, &len);
check_uint(len, ==, strlen(str));
check(tr_quark_lookup(str, len, &q));
check_int((int)q, ==, i);
}
for (int i = 0; i + 1 < TR_N_KEYS; i++)
{
size_t len1;
size_t len2;
char const* str1;
char const* str2;
str1 = tr_quark_get_string((tr_quark)i, &len1);
str2 = tr_quark_get_string((tr_quark)(i + 1), &len2);
check_str(str1, <, str2);
}
tr_quark const q = tr_quark_new(NULL, TR_BAD_SIZE);
check_int((int)q, ==, TR_KEY_NONE);
check_str(tr_quark_get_string(q, NULL), ==, "");
return 0;
}
MAIN_SINGLE_TEST(test_static_quarks)

View File

@ -8,10 +8,9 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
/* Quarks — a 2-way association between a string and a unique integer identifier */
typedef size_t tr_quark;
@ -435,6 +434,4 @@ tr_quark tr_quark_new(void const* str, size_t len);
****
***/
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -1,587 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <errno.h>
#include <stdio.h> /* fopen() */
#include <string.h> /* strcmp() */
#include "transmission.h"
#include "crypto-utils.h"
#include "file.h"
#include "resume.h"
#include "torrent.h" /* tr_isTorrent() */
#include "tr-assert.h"
#include "variant.h"
#include "libtransmission-test.h"
/***
****
***/
static tr_session* session = NULL;
#define check_have_none(tor, totalSize) \
do \
{ \
tr_stat const* tst = tr_torrentStat(tor); \
check_int(tst->activity, ==, TR_STATUS_STOPPED); \
check_int(tst->error, ==, TR_STAT_OK); \
check_uint(tst->sizeWhenDone, ==, totalSize); \
check_uint(tst->leftUntilDone, ==, totalSize); \
check_uint(tor->info.totalSize, ==, totalSize); \
check_uint(tst->haveValid, ==, 0); \
} \
while (0)
static bool testFileExistsAndConsistsOfThisString(tr_torrent const* tor, tr_file_index_t fileIndex, char const* str)
{
char* path;
size_t const str_len = strlen(str);
bool success = false;
path = tr_torrentFindFile(tor, fileIndex);
if (path != NULL)
{
TR_ASSERT(tr_sys_path_exists(path, NULL));
size_t contents_len;
uint8_t* contents = tr_loadFile(path, &contents_len, NULL);
success = contents != NULL && str_len == contents_len && memcmp(contents, str, contents_len) == 0;
tr_free(contents);
tr_free(path);
}
return success;
}
static void onRenameDone(tr_torrent* tor UNUSED, char const* oldpath UNUSED, char const* newname UNUSED, int error,
void* user_data)
{
*(int*)user_data = error;
}
static int torrentRenameAndWait(tr_torrent* tor, char const* oldpath, char const* newname)
{
int error = -1;
tr_torrentRenamePath(tor, oldpath, newname, onRenameDone, &error);
do
{
tr_wait_msec(10);
}
while (error == -1);
return error;
}
static void torrentRemoveAndWait(tr_torrent* tor, int expected_torrent_count)
{
tr_torrentRemove(tor, false, NULL);
while (tr_sessionCountTorrents(session) != expected_torrent_count)
{
tr_wait_msec(10);
}
}
/***
****
***/
static void create_single_file_torrent_contents(char const* top)
{
char* path = tr_buildPath(top, "hello-world.txt", NULL);
libtest_create_file_with_string_contents(path, "hello, world!\n");
tr_free(path);
}
static tr_torrent* create_torrent_from_base64_metainfo(tr_ctor* ctor, char const* metainfo_base64)
{
int err;
size_t metainfo_len;
char* metainfo;
tr_torrent* tor;
/* create the torrent ctor */
metainfo = tr_base64_decode_str(metainfo_base64, &metainfo_len);
TR_ASSERT(metainfo != NULL);
TR_ASSERT(metainfo_len > 0);
tr_ctorSetMetainfo(ctor, (uint8_t*)metainfo, metainfo_len);
tr_ctorSetPaused(ctor, TR_FORCE, true);
/* create the torrent */
err = 0;
tor = tr_torrentNew(ctor, &err, NULL);
TR_ASSERT(err == 0);
/* cleanup */
tr_free(metainfo);
return tor;
}
static int test_single_filename_torrent(void)
{
uint64_t loaded;
tr_torrent* tor;
char* tmpstr;
size_t const totalSize = 14;
tr_ctor* ctor;
tr_stat const* st;
/* this is a single-file torrent whose file is hello-world.txt, holding the string "hello, world!" */
ctor = tr_ctorNew(session);
tor = create_torrent_from_base64_metainfo(ctor,
"ZDEwOmNyZWF0ZWQgYnkyNTpUcmFuc21pc3Npb24vMi42MSAoMTM0MDcpMTM6Y3JlYXRpb24gZGF0"
"ZWkxMzU4NTQ5MDk4ZTg6ZW5jb2Rpbmc1OlVURi04NDppbmZvZDY6bGVuZ3RoaTE0ZTQ6bmFtZTE1"
"OmhlbGxvLXdvcmxkLnR4dDEyOnBpZWNlIGxlbmd0aGkzMjc2OGU2OnBpZWNlczIwOukboJcrkFUY"
"f6LvqLXBVvSHqCk6Nzpwcml2YXRlaTBlZWU=");
check(tr_isTorrent(tor));
/* sanity check the info */
check_int(tor->info.fileCount, ==, 1);
check_str(tor->info.files[0].name, ==, "hello-world.txt");
check(!tor->info.files[0].is_renamed);
/* sanity check the (empty) stats */
libttest_blockingTorrentVerify(tor);
check_have_none(tor, totalSize);
create_single_file_torrent_contents(tor->currentDir);
/* sanity check the stats again, now that we've added the file */
libttest_blockingTorrentVerify(tor);
st = tr_torrentStat(tor);
check_int(st->activity, ==, TR_STATUS_STOPPED);
check_int(st->error, ==, TR_STAT_OK);
check_uint(st->leftUntilDone, ==, 0);
check_uint(st->haveUnchecked, ==, 0);
check_uint(st->desiredAvailable, ==, 0);
check_uint(st->sizeWhenDone, ==, totalSize);
check_uint(st->haveValid, ==, totalSize);
/**
*** okay! we've finally put together all the scaffolding to test
*** renaming a single-file torrent
**/
/* confirm that bad inputs get caught */
check_int(torrentRenameAndWait(tor, "hello-world.txt", NULL), ==, EINVAL);
check_int(torrentRenameAndWait(tor, "hello-world.txt", ""), ==, EINVAL);
check_int(torrentRenameAndWait(tor, "hello-world.txt", "."), ==, EINVAL);
check_int(torrentRenameAndWait(tor, "hello-world.txt", ".."), ==, EINVAL);
check_int(torrentRenameAndWait(tor, "hello-world.txt", "hello-world.txt"), ==, 0);
check_int(torrentRenameAndWait(tor, "hello-world.txt", "hello/world.txt"), ==, EINVAL);
check(!tor->info.files[0].is_renamed);
check_str(tor->info.files[0].name, ==, "hello-world.txt");
/***
**** Now try a rename that should succeed
***/
tmpstr = tr_buildPath(tor->currentDir, "hello-world.txt", NULL);
check(tr_sys_path_exists(tmpstr, NULL));
check_str(tr_torrentName(tor), ==, "hello-world.txt");
check_int(torrentRenameAndWait(tor, tor->info.name, "foobar"), ==, 0);
check(!tr_sys_path_exists(tmpstr, NULL)); /* confirm the old filename can't be found */
tr_free(tmpstr);
check(tor->info.files[0].is_renamed); /* confirm the file's 'renamed' flag is set */
check_str(tr_torrentName(tor), ==, "foobar"); /* confirm the torrent's name is now 'foobar' */
check_str(tor->info.files[0].name, ==, "foobar"); /* confirm the file's name is now 'foobar' in our struct */
check_str(strstr(tor->info.torrent, "foobar"), ==, NULL); /* confirm the name in the .torrent file hasn't changed */
tmpstr = tr_buildPath(tor->currentDir, "foobar", NULL);
check(tr_sys_path_exists(tmpstr, NULL)); /* confirm the file's name is now 'foobar' on the disk */
tr_free(tmpstr);
check(testFileExistsAndConsistsOfThisString(tor, 0, "hello, world!\n")); /* confirm the contents are right */
/* (while it's renamed: confirm that the .resume file remembers the changes) */
tr_torrentSaveResume(tor);
libttest_sync();
loaded = tr_torrentLoadResume(tor, ~0, ctor, NULL);
check_str(tr_torrentName(tor), ==, "foobar");
check_uint((loaded & TR_FR_NAME), !=, 0);
/***
**** ...and rename it back again
***/
tmpstr = tr_buildPath(tor->currentDir, "foobar", NULL);
check(tr_sys_path_exists(tmpstr, NULL));
check_int(torrentRenameAndWait(tor, "foobar", "hello-world.txt"), ==, 0);
check(!tr_sys_path_exists(tmpstr, NULL));
check(tor->info.files[0].is_renamed);
check_str(tor->info.files[0].name, ==, "hello-world.txt");
check_str(tr_torrentName(tor), ==, "hello-world.txt");
tr_free(tmpstr);
check(testFileExistsAndConsistsOfThisString(tor, 0, "hello, world!\n"));
/* cleanup */
tr_ctorFree(ctor);
torrentRemoveAndWait(tor, 0);
return 0;
}
/***
****
****
****
***/
static void create_multifile_torrent_contents(char const* top)
{
char* path;
path = tr_buildPath(top, "Felidae", "Felinae", "Acinonyx", "Cheetah", "Chester", NULL);
libtest_create_file_with_string_contents(path, "It ain't easy bein' cheesy.\n");
tr_free(path);
path = tr_buildPath(top, "Felidae", "Pantherinae", "Panthera", "Tiger", "Tony", NULL);
libtest_create_file_with_string_contents(path, "Theyre Grrrrreat!\n");
tr_free(path);
path = tr_buildPath(top, "Felidae", "Felinae", "Felis", "catus", "Kyphi", NULL);
libtest_create_file_with_string_contents(path, "Inquisitive\n");
tr_free(path);
path = tr_buildPath(top, "Felidae", "Felinae", "Felis", "catus", "Saffron", NULL);
libtest_create_file_with_string_contents(path, "Tough\n");
tr_free(path);
libttest_sync();
}
static int test_multifile_torrent(void)
{
uint64_t loaded;
tr_torrent* tor;
tr_ctor* ctor;
char* str;
char* tmp;
static size_t const totalSize = 67;
tr_stat const* st;
tr_file const* files;
char const* strings[4];
char const* expected_files[4] =
{
"Felidae/Felinae/Acinonyx/Cheetah/Chester",
"Felidae/Felinae/Felis/catus/Kyphi",
"Felidae/Felinae/Felis/catus/Saffron",
"Felidae/Pantherinae/Panthera/Tiger/Tony"
};
char const* expected_contents[4] =
{
"It ain't easy bein' cheesy.\n",
"Inquisitive\n",
"Tough\n",
"Theyre Grrrrreat!\n"
};
ctor = tr_ctorNew(session);
tor = create_torrent_from_base64_metainfo(ctor,
"ZDEwOmNyZWF0ZWQgYnkyNTpUcmFuc21pc3Npb24vMi42MSAoMTM0MDcpMTM6Y3JlYXRpb24gZGF0"
"ZWkxMzU4NTU1NDIwZTg6ZW5jb2Rpbmc1OlVURi04NDppbmZvZDU6ZmlsZXNsZDY6bGVuZ3RoaTI4"
"ZTQ6cGF0aGw3OkZlbGluYWU4OkFjaW5vbnl4NzpDaGVldGFoNzpDaGVzdGVyZWVkNjpsZW5ndGhp"
"MTJlNDpwYXRobDc6RmVsaW5hZTU6RmVsaXM1OmNhdHVzNTpLeXBoaWVlZDY6bGVuZ3RoaTZlNDpw"
"YXRobDc6RmVsaW5hZTU6RmVsaXM1OmNhdHVzNzpTYWZmcm9uZWVkNjpsZW5ndGhpMjFlNDpwYXRo"
"bDExOlBhbnRoZXJpbmFlODpQYW50aGVyYTU6VGlnZXI0OlRvbnllZWU0Om5hbWU3OkZlbGlkYWUx"
"MjpwaWVjZSBsZW5ndGhpMzI3NjhlNjpwaWVjZXMyMDp27buFkmy8ICfNX4nsJmt0Ckm2Ljc6cHJp"
"dmF0ZWkwZWVl");
check(tr_isTorrent(tor));
files = tor->info.files;
/* sanity check the info */
check_str(tor->info.name, ==, "Felidae");
check_uint(tor->info.totalSize, ==, totalSize);
check_uint(tor->info.fileCount, ==, 4);
for (tr_file_index_t i = 0; i < 4; ++i)
{
check_str(files[i].name, ==, expected_files[i]);
}
/* sanity check the (empty) stats */
libttest_blockingTorrentVerify(tor);
check_have_none(tor, totalSize);
/* build the local data */
create_multifile_torrent_contents(tor->currentDir);
/* sanity check the (full) stats */
libttest_blockingTorrentVerify(tor);
st = tr_torrentStat(tor);
check_int(st->activity, ==, TR_STATUS_STOPPED);
check_int(st->error, ==, TR_STAT_OK);
check_uint(st->leftUntilDone, ==, 0);
check_uint(st->haveUnchecked, ==, 0);
check_uint(st->desiredAvailable, ==, 0);
check_uint(st->sizeWhenDone, ==, totalSize);
check_uint(st->haveValid, ==, totalSize);
/**
*** okay! let's test renaming.
**/
/* rename a leaf... */
check_int(torrentRenameAndWait(tor, "Felidae/Felinae/Felis/catus/Kyphi", "placeholder"), ==, 0);
check_str(files[1].name, ==, "Felidae/Felinae/Felis/catus/placeholder");
check(testFileExistsAndConsistsOfThisString(tor, 1, "Inquisitive\n"));
/* ...and back again */
check_int(torrentRenameAndWait(tor, "Felidae/Felinae/Felis/catus/placeholder", "Kyphi"), ==, 0);
check_str(files[1].name, ==, "Felidae/Felinae/Felis/catus/Kyphi");
testFileExistsAndConsistsOfThisString(tor, 1, "Inquisitive\n");
/* rename a branch... */
check_int(torrentRenameAndWait(tor, "Felidae/Felinae/Felis/catus", "placeholder"), ==, 0);
check_str(files[0].name, ==, expected_files[0]);
check_str(files[1].name, ==, "Felidae/Felinae/Felis/placeholder/Kyphi");
check_str(files[2].name, ==, "Felidae/Felinae/Felis/placeholder/Saffron");
check_str(files[3].name, ==, expected_files[3]);
check(testFileExistsAndConsistsOfThisString(tor, 1, expected_contents[1]));
check(testFileExistsAndConsistsOfThisString(tor, 2, expected_contents[2]));
check(!files[0].is_renamed);
check(files[1].is_renamed);
check(files[2].is_renamed);
check(!files[3].is_renamed);
/* (while the branch is renamed: confirm that the .resume file remembers the changes) */
tr_torrentSaveResume(tor);
/* this is a bit dodgy code-wise, but let's make sure the .resume file got the name */
tr_free(files[1].name);
tor->info.files[1].name = tr_strdup("gabba gabba hey");
loaded = tr_torrentLoadResume(tor, ~0, ctor, NULL);
check_uint((loaded & TR_FR_FILENAMES), !=, 0);
check_str(files[0].name, ==, expected_files[0]);
check_str(files[1].name, ==, "Felidae/Felinae/Felis/placeholder/Kyphi");
check_str(files[2].name, ==, "Felidae/Felinae/Felis/placeholder/Saffron");
check_str(files[3].name, ==, expected_files[3]);
/* ...and back again */
check_int(torrentRenameAndWait(tor, "Felidae/Felinae/Felis/placeholder", "catus"), ==, 0);
for (tr_file_index_t i = 0; i < 4; ++i)
{
check_str(files[i].name, ==, expected_files[i]);
check(testFileExistsAndConsistsOfThisString(tor, i, expected_contents[i]));
}
check(!files[0].is_renamed);
check(files[1].is_renamed);
check(files[2].is_renamed);
check(!files[3].is_renamed);
/***
**** Test it an incomplete torrent...
***/
/* remove the directory Felidae/Felinae/Felis/catus */
str = tr_torrentFindFile(tor, 1);
check_str(str, !=, NULL);
tr_sys_path_remove(str, NULL);
tr_free(str);
str = tr_torrentFindFile(tor, 2);
check_str(str, !=, NULL);
tr_sys_path_remove(str, NULL);
tmp = tr_sys_path_dirname(str, NULL);
tr_sys_path_remove(tmp, NULL);
tr_free(tmp);
tr_free(str);
libttest_sync();
libttest_blockingTorrentVerify(tor);
testFileExistsAndConsistsOfThisString(tor, 0, expected_contents[0]);
for (tr_file_index_t i = 1; i <= 2; ++i)
{
str = tr_torrentFindFile(tor, i);
check_str(str, ==, NULL);
tr_free(str);
}
testFileExistsAndConsistsOfThisString(tor, 3, expected_contents[3]);
/* rename a branch... */
check_int(torrentRenameAndWait(tor, "Felidae/Felinae/Felis/catus", "foo"), ==, 0);
check_str(files[0].name, ==, expected_files[0]);
check_str(files[1].name, ==, "Felidae/Felinae/Felis/foo/Kyphi");
check_str(files[2].name, ==, "Felidae/Felinae/Felis/foo/Saffron");
check_str(files[3].name, ==, expected_files[3]);
/* ...and back again */
check_int(torrentRenameAndWait(tor, "Felidae/Felinae/Felis/foo", "catus"), ==, 0);
for (tr_file_index_t i = 0; i < 4; ++i)
{
check_str(files[i].name, ==, expected_files[i]);
}
check_int(torrentRenameAndWait(tor, "Felidae", "gabba"), ==, 0);
strings[0] = "gabba/Felinae/Acinonyx/Cheetah/Chester";
strings[1] = "gabba/Felinae/Felis/catus/Kyphi";
strings[2] = "gabba/Felinae/Felis/catus/Saffron";
strings[3] = "gabba/Pantherinae/Panthera/Tiger/Tony";
for (tr_file_index_t i = 0; i < 4; ++i)
{
check_str(files[i].name, ==, strings[i]);
testFileExistsAndConsistsOfThisString(tor, i, expected_contents[i]);
}
/* rename the root, then a branch, and then a leaf... */
check_int(torrentRenameAndWait(tor, "gabba", "Felidae"), ==, 0);
check_int(torrentRenameAndWait(tor, "Felidae/Pantherinae/Panthera/Tiger", "Snow Leopard"), ==, 0);
check_int(torrentRenameAndWait(tor, "Felidae/Pantherinae/Panthera/Snow Leopard/Tony", "10.6"), ==, 0);
strings[0] = "Felidae/Felinae/Acinonyx/Cheetah/Chester";
strings[1] = "Felidae/Felinae/Felis/catus/Kyphi";
strings[2] = "Felidae/Felinae/Felis/catus/Saffron";
strings[3] = "Felidae/Pantherinae/Panthera/Snow Leopard/10.6";
for (tr_file_index_t i = 0; i < 4; ++i)
{
check_str(files[i].name, ==, strings[i]);
testFileExistsAndConsistsOfThisString(tor, i, expected_contents[i]);
}
tr_ctorFree(ctor);
torrentRemoveAndWait(tor, 0);
/**
*** Test renaming prefixes (shouldn't work)
**/
ctor = tr_ctorNew(session);
tor = create_torrent_from_base64_metainfo(ctor,
"ZDEwOmNyZWF0ZWQgYnkyNTpUcmFuc21pc3Npb24vMi42MSAoMTM0MDcpMTM6Y3JlYXRpb24gZGF0"
"ZWkxMzU4NTU1NDIwZTg6ZW5jb2Rpbmc1OlVURi04NDppbmZvZDU6ZmlsZXNsZDY6bGVuZ3RoaTI4"
"ZTQ6cGF0aGw3OkZlbGluYWU4OkFjaW5vbnl4NzpDaGVldGFoNzpDaGVzdGVyZWVkNjpsZW5ndGhp"
"MTJlNDpwYXRobDc6RmVsaW5hZTU6RmVsaXM1OmNhdHVzNTpLeXBoaWVlZDY6bGVuZ3RoaTZlNDpw"
"YXRobDc6RmVsaW5hZTU6RmVsaXM1OmNhdHVzNzpTYWZmcm9uZWVkNjpsZW5ndGhpMjFlNDpwYXRo"
"bDExOlBhbnRoZXJpbmFlODpQYW50aGVyYTU6VGlnZXI0OlRvbnllZWU0Om5hbWU3OkZlbGlkYWUx"
"MjpwaWVjZSBsZW5ndGhpMzI3NjhlNjpwaWVjZXMyMDp27buFkmy8ICfNX4nsJmt0Ckm2Ljc6cHJp"
"dmF0ZWkwZWVl");
check(tr_isTorrent(tor));
files = tor->info.files;
/* rename prefix of top */
check_int(torrentRenameAndWait(tor, "Feli", "FelidaeX"), ==, EINVAL);
check_str(tor->info.name, ==, "Felidae");
check(!files[0].is_renamed);
check(!files[1].is_renamed);
check(!files[2].is_renamed);
check(!files[3].is_renamed);
/* rename false path */
check_int(torrentRenameAndWait(tor, "Felidae/FelinaeX", "Genus Felinae"), ==, EINVAL);
check_str(tor->info.name, ==, "Felidae");
check(!files[0].is_renamed);
check(!files[1].is_renamed);
check(!files[2].is_renamed);
check(!files[3].is_renamed);
/***
****
***/
/* cleanup */
tr_ctorFree(ctor);
torrentRemoveAndWait(tor, 0);
return 0;
}
/***
****
***/
static int test_partial_file(void)
{
tr_torrent* tor;
tr_stat const* st;
tr_file_stat* fst;
uint32_t const pieceCount = 33;
uint32_t const pieceSize = 32768;
uint32_t const length[] = { 1048576, 4096, 512 };
uint64_t const totalSize = length[0] + length[1] + length[2];
char const* strings[3];
/***
**** create our test torrent with an incomplete .part file
***/
tor = libttest_zero_torrent_init(session);
check_uint(tor->info.totalSize, ==, totalSize);
check_uint(tor->info.pieceSize, ==, pieceSize);
check_uint(tor->info.pieceCount, ==, pieceCount);
check_str(tor->info.files[0].name, ==, "files-filled-with-zeroes/1048576");
check_str(tor->info.files[1].name, ==, "files-filled-with-zeroes/4096");
check_str(tor->info.files[2].name, ==, "files-filled-with-zeroes/512");
libttest_zero_torrent_populate(tor, false);
fst = tr_torrentFiles(tor, NULL);
check_uint(fst[0].bytesCompleted, ==, length[0] - pieceSize);
check_uint(fst[1].bytesCompleted, ==, length[1]);
check_uint(fst[2].bytesCompleted, ==, length[2]);
tr_torrentFilesFree(fst, tor->info.fileCount);
st = tr_torrentStat(tor);
check_uint(st->sizeWhenDone, ==, totalSize);
check_uint(st->leftUntilDone, ==, pieceSize);
/***
****
***/
check_int(torrentRenameAndWait(tor, "files-filled-with-zeroes", "foo"), ==, 0);
check_int(torrentRenameAndWait(tor, "foo/1048576", "bar"), ==, 0);
strings[0] = "foo/bar";
strings[1] = "foo/4096";
strings[2] = "foo/512";
for (tr_file_index_t i = 0; i < 3; ++i)
{
check_str(tor->info.files[i].name, ==, strings[i]);
}
strings[0] = "foo/bar.part";
for (tr_file_index_t i = 0; i < 3; ++i)
{
char* expected = tr_buildPath(tor->currentDir, strings[i], NULL);
char* path = tr_torrentFindFile(tor, i);
check_str(path, ==, expected);
tr_free(path);
tr_free(expected);
}
torrentRemoveAndWait(tor, 0);
return 0;
}
/***
****
***/
int main(void)
{
testFunc const tests[] =
{
test_single_filename_torrent,
test_multifile_torrent,
test_partial_file
};
session = libttest_session_init(NULL);
int ret = runTests(tests, NUM_TESTS(tests));
libttest_session_close(session);
return ret;
}

View File

@ -593,7 +593,6 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
uint8_t const* raw;
size_t rawlen;
tr_variant* l;
tr_variant* b;
struct tr_bitfield blocks = TR_BITFIELD_INIT;
if (tr_variantDictFindList(prog, TR_KEY_time_checked, &l))
@ -667,6 +666,7 @@ static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor)
err = NULL;
tr_bitfieldConstruct(&blocks, tor->blockCount);
tr_variant* b;
if ((b = tr_variantDictFind(prog, TR_KEY_blocks)) != NULL)
{
size_t buflen;

View File

@ -12,6 +12,10 @@
#error only libtransmission should #include this header.
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
enum
{
TR_FR_DOWNLOADED = (1 << 0),
@ -49,3 +53,5 @@ void tr_torrentSaveResume(tr_torrent* tor);
void tr_torrentRemoveResume(tr_torrent const* tor);
int tr_torrentRenameResume(tr_torrent const* tor, char const* newname);
TR_END_DECLS

View File

@ -1,166 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "transmission.h"
#include "rpcimpl.h"
#include "utils.h"
#include "variant.h"
#include "libtransmission-test.h"
static int test_list(void)
{
size_t len;
int64_t i;
char const* str;
tr_variant top;
tr_rpc_parse_list_str(&top, "12", TR_BAD_SIZE);
check(tr_variantIsInt(&top));
check(tr_variantGetInt(&top, &i));
check_int(i, ==, 12);
tr_variantFree(&top);
tr_rpc_parse_list_str(&top, "12", 1);
check(tr_variantIsInt(&top));
check(tr_variantGetInt(&top, &i));
check_int(i, ==, 1);
tr_variantFree(&top);
tr_rpc_parse_list_str(&top, "6,7", TR_BAD_SIZE);
check(tr_variantIsList(&top));
check_uint(tr_variantListSize(&top), ==, 2);
check(tr_variantGetInt(tr_variantListChild(&top, 0), &i));
check_int(i, ==, 6);
check(tr_variantGetInt(tr_variantListChild(&top, 1), &i));
check_int(i, ==, 7);
tr_variantFree(&top);
tr_rpc_parse_list_str(&top, "asdf", TR_BAD_SIZE);
check(tr_variantIsString(&top));
check(tr_variantGetStr(&top, &str, &len));
check_uint(len, ==, 4);
check_str(str, ==, "asdf");
tr_variantFree(&top);
tr_rpc_parse_list_str(&top, "1,3-5", TR_BAD_SIZE);
check(tr_variantIsList(&top));
check_uint(tr_variantListSize(&top), ==, 4);
check(tr_variantGetInt(tr_variantListChild(&top, 0), &i));
check_int(i, ==, 1);
check(tr_variantGetInt(tr_variantListChild(&top, 1), &i));
check_int(i, ==, 3);
check(tr_variantGetInt(tr_variantListChild(&top, 2), &i));
check_int(i, ==, 4);
check(tr_variantGetInt(tr_variantListChild(&top, 3), &i));
check_int(i, ==, 5);
tr_variantFree(&top);
return 0;
}
/***
****
***/
static void rpc_response_func(tr_session* session UNUSED, tr_variant* response, void* setme)
{
*(tr_variant*)setme = *response;
tr_variantInitBool(response, false);
}
static int test_session_get_and_set(void)
{
tr_session* session;
tr_variant request;
tr_variant response;
tr_variant* args;
tr_torrent* tor;
session = libttest_session_init(NULL);
tor = libttest_zero_torrent_init(session);
check_ptr(tor, !=, NULL);
tr_variantInitDict(&request, 1);
tr_variantDictAddStr(&request, TR_KEY_method, "session-get");
tr_rpc_request_exec_json(session, &request, rpc_response_func, &response);
tr_variantFree(&request);
check(tr_variantIsDict(&response));
check(tr_variantDictFindDict(&response, TR_KEY_arguments, &args));
check_ptr(tr_variantDictFind(args, TR_KEY_alt_speed_down), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_alt_speed_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_alt_speed_time_begin), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_alt_speed_time_day), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_alt_speed_time_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_alt_speed_time_end), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_alt_speed_up), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_blocklist_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_blocklist_size), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_blocklist_url), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_cache_size_mb), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_config_dir), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_dht_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_download_dir), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_download_dir_free_space), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_download_queue_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_download_queue_size), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_encryption), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_idle_seeding_limit), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_idle_seeding_limit_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_incomplete_dir), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_incomplete_dir_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_lpd_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_peer_limit_global), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_peer_limit_per_torrent), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_peer_port), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_peer_port_random_on_start), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_pex_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_port_forwarding_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_queue_stalled_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_queue_stalled_minutes), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_rename_partial_files), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_rpc_version), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_rpc_version_minimum), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_script_torrent_done_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_script_torrent_done_filename), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_seed_queue_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_seed_queue_size), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_seedRatioLimit), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_seedRatioLimited), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_speed_limit_down), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_speed_limit_down_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_speed_limit_up), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_speed_limit_up_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_start_added_torrents), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_trash_original_torrent_files), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_units), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_utp_enabled), !=, NULL);
check_ptr(tr_variantDictFind(args, TR_KEY_version), !=, NULL);
tr_variantFree(&response);
/* cleanup */
tr_torrentRemove(tor, false, NULL);
libttest_session_close(session);
return 0;
}
/***
****
***/
int main(void)
{
testFunc const tests[] =
{
test_list,
test_session_get_and_set
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -121,7 +121,6 @@ static tr_torrent** getTorrents(tr_session* session, tr_variant* args, int* setm
for (int i = 0; i < n; ++i)
{
char const* str;
tr_torrent* tor;
tr_variant* node = tr_variantListChild(ids, i);
@ -730,9 +729,9 @@ static void initField(tr_torrent* const tor, tr_info const* const inf, tr_stat c
{
size_t byte_count = 0;
void* bytes = tr_torrentCreatePieceBitfield(tor, &byte_count);
char* str = tr_base64_encode(bytes, byte_count, NULL);
tr_variantInitStr(initme, str != NULL ? str : "", TR_BAD_SIZE);
tr_free(str);
char* enc = tr_base64_encode(bytes, byte_count, NULL);
tr_variantInitStr(initme, enc != NULL ? enc : "", TR_BAD_SIZE);
tr_free(enc);
tr_free(bytes);
}
else

View File

@ -8,14 +8,12 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include "transmission.h"
#include "tr-macros.h"
#include "variant.h"
TR_BEGIN_DECLS
/***
**** RPC processing
***/
@ -32,6 +30,4 @@ void tr_rpc_request_exec_uri(tr_session* session, void const* request_uri, size_
void tr_rpc_parse_list_str(tr_variant* setme, char const* list_str, size_t list_str_len);
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -8,10 +8,9 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
typedef struct tr_session_id* tr_session_id_t;
@ -52,6 +51,4 @@ char const* tr_session_id_get_current(tr_session_id_t session_id);
*/
bool tr_session_id_is_local(char const* session_id);
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -1,139 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "transmission.h"
#include "session.h"
#include "session-id.h"
#include "utils.h"
#include "version.h"
#undef VERBOSE
#include "libtransmission-test.h"
static int testPeerId(void)
{
uint8_t peer_id[PEER_ID_LEN + 1];
for (int i = 0; i < 100000; ++i)
{
int val = 0;
tr_peerIdInit(peer_id);
check_uint(strlen((char*)peer_id), ==, PEER_ID_LEN);
check_mem(peer_id, ==, PEERID_PREFIX, 8);
for (int j = 8; j < PEER_ID_LEN; ++j)
{
char tmp[2] = { (char)peer_id[j], '\0' };
val += strtoul(tmp, NULL, 36);
}
check_int(val % 36, ==, 0);
}
return 0;
}
static int test_session_id(void)
{
tr_session_id_t session_id;
char const* session_id_str_1 = NULL;
char const* session_id_str_2 = NULL;
char const* session_id_str_3 = NULL;
check(!tr_session_id_is_local(NULL));
check(!tr_session_id_is_local(""));
check(!tr_session_id_is_local("test"));
session_id = tr_session_id_new();
check_ptr(session_id, !=, NULL);
tr_timeUpdate(0);
session_id_str_1 = tr_session_id_get_current(session_id);
check_str(session_id_str_1, !=, NULL);
check_uint(strlen(session_id_str_1), ==, 48);
session_id_str_1 = tr_strdup(session_id_str_1);
check(tr_session_id_is_local(session_id_str_1));
tr_timeUpdate(60 * 60 - 1);
check(tr_session_id_is_local(session_id_str_1));
session_id_str_2 = tr_session_id_get_current(session_id);
check_str(session_id_str_2, !=, NULL);
check_uint(strlen(session_id_str_2), ==, 48);
check_str(session_id_str_2, ==, session_id_str_1);
tr_timeUpdate(60 * 60);
check(tr_session_id_is_local(session_id_str_1));
session_id_str_2 = tr_session_id_get_current(session_id);
check_str(session_id_str_2, !=, NULL);
check_uint(strlen(session_id_str_2), ==, 48);
check_str(session_id_str_2, !=, session_id_str_1);
session_id_str_2 = tr_strdup(session_id_str_2);
check(tr_session_id_is_local(session_id_str_2));
check(tr_session_id_is_local(session_id_str_1));
tr_timeUpdate(60 * 60 * 2);
check(tr_session_id_is_local(session_id_str_2));
check(tr_session_id_is_local(session_id_str_1));
session_id_str_3 = tr_session_id_get_current(session_id);
check_str(session_id_str_3, !=, NULL);
check_uint(strlen(session_id_str_3), ==, 48);
check_str(session_id_str_3, !=, session_id_str_2);
check_str(session_id_str_3, !=, session_id_str_1);
session_id_str_3 = tr_strdup(session_id_str_3);
check(tr_session_id_is_local(session_id_str_3));
check(tr_session_id_is_local(session_id_str_2));
check(!tr_session_id_is_local(session_id_str_1));
tr_timeUpdate(60 * 60 * 10);
check(tr_session_id_is_local(session_id_str_3));
check(tr_session_id_is_local(session_id_str_2));
check(!tr_session_id_is_local(session_id_str_1));
check(!tr_session_id_is_local(NULL));
check(!tr_session_id_is_local(""));
check(!tr_session_id_is_local("test"));
tr_session_id_free(session_id);
check(!tr_session_id_is_local(session_id_str_3));
check(!tr_session_id_is_local(session_id_str_2));
check(!tr_session_id_is_local(session_id_str_1));
tr_free((char*)session_id_str_3);
tr_free((char*)session_id_str_2);
tr_free((char*)session_id_str_1);
return 0;
}
int main(void)
{
testFunc const tests[] =
{
testPeerId,
test_session_id
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -21,6 +21,7 @@
#include <event2/dns.h> /* evdns_base_free() */
#include <event2/event.h>
#include <stdint.h>
#include <libutp/utp.h>
// #define TR_SHOW_DEPRECATED
@ -1489,7 +1490,7 @@ static void turtleUpdateTable(struct tr_turtle_info* t)
end += MINUTES_PER_DAY;
}
for (int i = begin; i < end; ++i)
for (time_t i = begin; i < end; ++i)
{
tr_bitfieldAdd(b, (i + day * MINUTES_PER_DAY) % MINUTES_PER_WEEK);
}

View File

@ -17,9 +17,12 @@
#include "bandwidth.h"
#include "bitfield.h"
#include "net.h"
#include "tr-macros.h"
#include "utils.h"
#include "variant.h"
TR_BEGIN_DECLS
typedef enum
{
TR_NET_OK,
@ -320,3 +323,5 @@ bool tr_sessionGetActiveSpeedLimit_Bps(tr_session const* session, tr_direction d
void tr_sessionGetNextQueuedTorrents(tr_session* session, tr_direction dir, size_t numwanted, tr_ptrArray* setme);
int tr_sessionCountQueueFreeSlots(tr_session* session, tr_direction);
TR_END_DECLS

View File

@ -1,401 +0,0 @@
/*
* This file Copyright (C) 2017 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <stdlib.h>
#include "transmission.h"
#include "error.h"
#include "file.h"
#include "subprocess.h"
#include "utils.h"
#include "libtransmission-test.h"
static char arg_dump_args[] = "--dump-args";
static char arg_dump_env[] = "--dump-env";
static char arg_dump_cwd[] = "--dump-cwd";
static char* self_path = NULL;
static int test_spawn_async_missing_exe(void)
{
char missing_exe_path[] = TR_IF_WIN32("C:\\", "/") "tr-missing-test-exe" TR_IF_WIN32(".exe", "");
char* const args[] =
{
missing_exe_path,
NULL
};
tr_error* error = NULL;
bool const ret = tr_spawn_async(args, NULL, NULL, &error);
check_bool(ret, ==, false);
check_ptr(error, !=, NULL);
check_int(error->code, !=, 0);
check_str(error->message, !=, NULL);
tr_error_clear(&error);
return 0;
}
static int test_spawn_async_args(void)
{
char* const test_dir = libtest_sandbox_create();
char* const result_path = tr_sys_path_native_separators(tr_buildPath(test_dir, "result.txt", NULL));
bool const allow_batch_metachars = TR_IF_WIN32(false, true) || !tr_str_has_suffix(self_path, ".cmd");
char test_arg_1[] = "arg1 ";
char test_arg_2[] = " arg2";
char test_arg_3[] = "";
char test_arg_4[] = "\"arg3'^! $PATH %PATH% \\";
char* const args[] =
{
self_path,
result_path,
arg_dump_args,
test_arg_1,
test_arg_2,
test_arg_3,
allow_batch_metachars ? test_arg_4 : NULL,
NULL
};
tr_error* error = NULL;
bool const ret = tr_spawn_async(args, NULL, NULL, &error);
check_bool(ret, ==, true);
check_ptr(error, ==, NULL);
while (!tr_sys_path_exists(result_path, NULL))
{
tr_wait_msec(10);
}
tr_sys_file_t fd = tr_sys_file_open(result_path, TR_SYS_FILE_READ, 0, NULL);
check_int(fd, !=, TR_BAD_SYS_FILE);
char buffer[1024];
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_arg_1);
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_arg_2);
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_arg_3);
if (allow_batch_metachars)
{
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_arg_4);
}
check(!tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
tr_sys_file_close(fd, NULL);
tr_free(result_path);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_spawn_async_env(void)
{
char* const test_dir = libtest_sandbox_create();
char* const result_path = tr_sys_path_native_separators(tr_buildPath(test_dir, "result.txt", NULL));
char test_env_key_1[] = "VAR1";
char test_env_key_2[] = "_VAR_2_";
char test_env_key_3[] = "vAr#";
char test_env_key_4[] = "FOO";
char test_env_key_5[] = "ZOO";
char test_env_key_6[] = "TR_MISSING_TEST_ENV_KEY";
char test_env_value_1[] = "value1 ";
char test_env_value_2[] = " value2";
char test_env_value_3[] = " \"value3'^! $PATH %PATH% ";
char test_env_value_4[] = "bar";
char test_env_value_5[] = "jar";
char* const args[] =
{
self_path,
result_path,
arg_dump_env,
test_env_key_1,
test_env_key_2,
test_env_key_3,
test_env_key_4,
test_env_key_5,
test_env_key_6,
NULL
};
char* const env[] =
{
tr_strdup_printf("%s=%s", test_env_key_1, test_env_value_1),
tr_strdup_printf("%s=%s", test_env_key_2, test_env_value_2),
tr_strdup_printf("%s=%s", test_env_key_3, test_env_value_3),
tr_strdup_printf("%s=%s", test_env_key_5, test_env_value_5),
NULL
};
/* Inherited */
char foo_env_value[] = "FOO=bar";
putenv(foo_env_value);
/* Overridden */
char zoo_env_value[] = "ZOO=tar";
putenv(zoo_env_value);
tr_error* error = NULL;
bool const ret = tr_spawn_async(args, env, NULL, &error);
check_bool(ret, ==, true);
check_ptr(error, ==, NULL);
while (!tr_sys_path_exists(result_path, NULL))
{
tr_wait_msec(10);
}
tr_sys_file_t fd = tr_sys_file_open(result_path, TR_SYS_FILE_READ, 0, NULL);
check_int(fd, !=, TR_BAD_SYS_FILE);
char buffer[1024];
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_env_value_1);
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_env_value_2);
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_env_value_3);
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_env_value_4);
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, test_env_value_5);
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(buffer, ==, "<null>");
check(!tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
tr_sys_file_close(fd, NULL);
tr_free_ptrv((void* const*)env);
tr_free(result_path);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_spawn_async_cwd_explicit(void)
{
char* const test_dir = libtest_sandbox_create();
char* const result_path = tr_sys_path_native_separators(tr_buildPath(test_dir, "result.txt", NULL));
char* const args[] =
{
self_path,
result_path,
arg_dump_cwd,
NULL
};
tr_error* error = NULL;
bool const ret = tr_spawn_async(args, NULL, test_dir, &error);
check_bool(ret, ==, true);
check_ptr(error, ==, NULL);
while (!tr_sys_path_exists(result_path, NULL))
{
tr_wait_msec(10);
}
tr_sys_file_t fd = tr_sys_file_open(result_path, TR_SYS_FILE_READ, 0, NULL);
check_int(fd, !=, TR_BAD_SYS_FILE);
char buffer[1024];
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(tr_sys_path_native_separators(buffer), ==, tr_sys_path_native_separators(test_dir));
check(!tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
tr_sys_file_close(fd, NULL);
tr_free(result_path);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_spawn_async_cwd_inherit(void)
{
char* const test_dir = libtest_sandbox_create();
char* const result_path = tr_sys_path_native_separators(tr_buildPath(test_dir, "result.txt", NULL));
char* const expected_cwd = tr_sys_dir_get_current(NULL);
char* const args[] =
{
self_path,
result_path,
arg_dump_cwd,
NULL
};
tr_error* error = NULL;
bool const ret = tr_spawn_async(args, NULL, NULL, &error);
check_bool(ret, ==, true);
check_ptr(error, ==, NULL);
while (!tr_sys_path_exists(result_path, NULL))
{
tr_wait_msec(10);
}
tr_sys_file_t fd = tr_sys_file_open(result_path, TR_SYS_FILE_READ, 0, NULL);
check_int(fd, !=, TR_BAD_SYS_FILE);
char buffer[1024];
check(tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
check_str(tr_sys_path_native_separators(buffer), ==, tr_sys_path_native_separators(expected_cwd));
check(!tr_sys_file_read_line(fd, buffer, sizeof(buffer), NULL));
tr_sys_file_close(fd, NULL);
tr_free(expected_cwd);
tr_free(result_path);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_spawn_async_cwd_missing(void)
{
char* const test_dir = libtest_sandbox_create();
char* const result_path = tr_sys_path_native_separators(tr_buildPath(test_dir, "result.txt", NULL));
char* const args[] =
{
self_path,
result_path,
arg_dump_cwd,
NULL
};
tr_error* error = NULL;
bool const ret = tr_spawn_async(args, NULL, TR_IF_WIN32("C:\\", "/") "tr-missing-test-work-dir", &error);
check_bool(ret, ==, false);
check_ptr(error, !=, NULL);
check_int(error->code, !=, 0);
check_str(error->message, !=, NULL);
tr_error_clear(&error);
tr_free(result_path);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
int main(int argc, char** argv)
{
self_path = tr_sys_path_resolve(argv[0], NULL);
if (argc >= 3)
{
char* const result_path = argv[1];
char* const test_action = argv[2];
char* const tmp_result_path = tr_strdup_printf("%s.tmp", result_path);
tr_sys_file_t const fd = tr_sys_file_open(tmp_result_path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE |
TR_SYS_FILE_TRUNCATE, 0644, NULL);
if (fd == TR_BAD_SYS_FILE)
{
tr_free(tmp_result_path);
return 1;
}
if (strcmp(test_action, arg_dump_args) == 0)
{
for (int i = 3; i < argc; ++i)
{
tr_sys_file_write_line(fd, argv[i], NULL);
}
}
else if (strcmp(test_action, arg_dump_env) == 0)
{
for (int i = 3; i < argc; ++i)
{
char* const value = tr_env_get_string(argv[i], "<null>");
tr_sys_file_write_line(fd, value, NULL);
tr_free(value);
}
}
else if (strcmp(test_action, arg_dump_cwd) == 0)
{
char* const value = tr_sys_dir_get_current(NULL);
tr_sys_file_write_line(fd, value != NULL ? value : "<null>", NULL);
tr_free(value);
}
else
{
tr_sys_file_close(fd, NULL);
tr_sys_path_remove(tmp_result_path, NULL);
tr_free(tmp_result_path);
return 1;
}
tr_sys_file_close(fd, NULL);
tr_sys_path_rename(tmp_result_path, result_path, NULL);
tr_free(tmp_result_path);
return 0;
}
testFunc const tests[] =
{
test_spawn_async_missing_exe,
test_spawn_async_args,
test_spawn_async_env,
test_spawn_async_cwd_explicit,
test_spawn_async_cwd_inherit,
test_spawn_async_cwd_missing
};
int ret = runTests(tests, NUM_TESTS(tests));
#ifdef _WIN32
strcpy(self_path + strlen(self_path) - 4, ".cmd");
int ret2 = runTests(tests, NUM_TESTS(tests));
if (ret == 0)
{
ret = ret2;
}
#endif
tr_free(self_path);
return ret;
}

View File

@ -8,4 +8,10 @@
#pragma once
#include "tr-macros.h"
TR_BEGIN_DECLS
bool tr_spawn_async(char* const* cmd, char* const* env, char const* work_dir, struct tr_error** error);
TR_END_DECLS

View File

@ -1301,14 +1301,14 @@ tr_torrent_activity tr_torrentGetActivity(tr_torrent const* tor)
return ret;
}
static time_t torrentGetIdleSecs(tr_torrent const* tor)
static int torrentGetIdleSecs(tr_torrent const* tor)
{
int idle_secs;
tr_torrent_activity const activity = tr_torrentGetActivity(tor);
if ((activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_SEED) && tor->startDate != 0)
{
idle_secs = difftime(tr_time(), MAX(tor->startDate, tor->activityDate));
idle_secs = (int)difftime(tr_time(), MAX(tor->startDate, tor->activityDate));
}
else
{

View File

@ -16,9 +16,12 @@
#include "completion.h" /* tr_completion */
#include "session.h" /* tr_sessionLock(), tr_sessionUnlock() */
#include "tr-assert.h"
#include "tr-macros.h"
#include "utils.h" /* TR_GNUC_PRINTF */
#include "ptrarray.h"
TR_BEGIN_DECLS
struct tr_torrent_tiers;
struct tr_magnet_info;
@ -466,3 +469,5 @@ static inline tr_direction tr_torrentGetQueueDirection(tr_torrent const* tor)
{
return tr_torrentIsSeed(tor) ? TR_UP : TR_DOWN;
}
TR_END_DECLS

View File

@ -66,7 +66,7 @@
static struct event* dht_timer = NULL;
static unsigned char myid[20];
static tr_session* session = NULL;
static tr_session* session_ = NULL;
static void timer_callback(evutil_socket_t s, short type, void* ignore);
@ -145,7 +145,7 @@ static void bootstrap_from_name(char const* name, tr_port port, int af)
nap(15);
if (bootstrap_done(session, af))
if (bootstrap_done(session_, af))
{
break;
}
@ -162,7 +162,7 @@ static void dht_bootstrap(void* closure)
int num = cl->len / 6;
int num6 = cl->len6 / 18;
if (session != cl->session)
if (session_ != cl->session)
{
return;
}
@ -217,7 +217,7 @@ static void dht_bootstrap(void* closure)
nap(15);
}
if (bootstrap_done(session, 0))
if (bootstrap_done(session_, 0))
{
break;
}
@ -265,7 +265,7 @@ static void dht_bootstrap(void* closure)
*p = '\0';
bootstrap_from_name(buf, port, bootstrap_af(session));
bootstrap_from_name(buf, port, bootstrap_af(session_));
if (bootstrap_done(cl->session, 0))
{
@ -299,7 +299,7 @@ static void dht_bootstrap(void* closure)
tr_logAddNamedInfo("DHT", "Attempting bootstrap from dht.transmissionbt.com");
}
bootstrap_from_name("dht.transmissionbt.com", 6881, bootstrap_af(session));
bootstrap_from_name("dht.transmissionbt.com", 6881, bootstrap_af(session_));
}
}
@ -330,7 +330,7 @@ int tr_dhtInit(tr_session* ss)
size_t len6;
struct bootstrap_closure* cl;
if (session != NULL) /* already initialized */
if (session_ != NULL) /* already initialized */
{
return -1;
}
@ -397,17 +397,17 @@ int tr_dhtInit(tr_session* ss)
goto fail;
}
session = ss;
session_ = ss;
cl = tr_new(struct bootstrap_closure, 1);
cl->session = session;
cl->session = session_;
cl->nodes = nodes;
cl->nodes6 = nodes6;
cl->len = len;
cl->len6 = len6;
tr_threadNew(dht_bootstrap, cl);
dht_timer = evtimer_new(session->event_base, timer_callback, session);
dht_timer = evtimer_new(session_->event_base, timer_callback, session_);
tr_timerAdd(dht_timer, 0, tr_rand_int_weak(1000000));
tr_logAddNamedDbg("DHT", "DHT initialized");
@ -419,13 +419,13 @@ fail:
tr_free(nodes);
tr_logAddNamedDbg("DHT", "DHT initialization failed (errno = %d)", errno);
session = NULL;
session_ = NULL;
return -1;
}
void tr_dhtUninit(tr_session* ss)
{
if (session != ss)
if (session_ != ss)
{
return;
}
@ -492,12 +492,12 @@ void tr_dhtUninit(tr_session* ss)
dht_uninit();
tr_logAddNamedDbg("DHT", "Done uninitializing DHT");
session = NULL;
session_ = NULL;
}
bool tr_dhtEnabled(tr_session const* ss)
{
return ss != NULL && ss == session;
return ss != NULL && ss == session_;
}
struct getstatus_closure
@ -644,8 +644,8 @@ static void callback(void* ignore UNUSED, int event, unsigned char const* info_h
if (event == DHT_EVENT_VALUES || event == DHT_EVENT_VALUES6)
{
tr_torrent* tor;
tr_sessionLock(session);
tor = tr_torrentFindFromHash(session, info_hash);
tr_sessionLock(session_);
tor = tr_torrentFindFromHash(session_, info_hash);
if (tor != NULL && tr_torrentAllowsDHT(tor))
{
@ -670,11 +670,11 @@ static void callback(void* ignore UNUSED, int event, unsigned char const* info_h
tr_logAddTorDbg(tor, "Learned %d %s peers from DHT", (int)n, event == DHT_EVENT_VALUES6 ? "IPv6" : "IPv4");
}
tr_sessionUnlock(session);
tr_sessionUnlock(session_);
}
else if (event == DHT_EVENT_SEARCH_DONE || event == DHT_EVENT_SEARCH_DONE6)
{
tr_torrent* tor = tr_torrentFindFromHash(session, info_hash);
tr_torrent* tor = tr_torrentFindFromHash(session_, info_hash);
if (tor != NULL)
{
@ -714,7 +714,7 @@ static int tr_dhtAnnounce(tr_torrent* tor, int af, bool announce)
if (status >= TR_DHT_POOR)
{
rc = dht_search(tor->info.hash, announce ? tr_sessionGetPeerPort(session) : 0, af, callback, NULL);
rc = dht_search(tor->info.hash, announce ? tr_sessionGetPeerPort(session_) : 0, af, callback, NULL);
if (rc >= 1)
{
@ -779,7 +779,7 @@ void tr_dhtCallback(unsigned char* buf, int buflen, struct sockaddr* from, sockl
{
TR_ASSERT(tr_isSession(sv));
if (sv != session)
if (sv != session_)
{
return;
}
@ -808,7 +808,7 @@ void tr_dhtCallback(unsigned char* buf, int buflen, struct sockaddr* from, sockl
/* Being slightly late is fine,
and has the added benefit of adding some jitter. */
tr_timerAdd(dht_timer, tosleep, tr_rand_int_weak(1000000));
tr_timerAdd(dht_timer, (int)tosleep, tr_rand_int_weak(1000000));
}
static void timer_callback(evutil_socket_t s UNUSED, short type UNUSED, void* session)

View File

@ -1,184 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include "transmission.h"
#include "tr-getopt.h"
#include "libtransmission-test.h"
static struct tr_option const options[] =
{
{ 'p', "private", "Allow this torrent to only be used with the specified tracker(s)", "p", false, NULL },
{ 'o', "outfile", "Save the generated .torrent to this filename", "o", true, "<file>" },
{ 's', "piecesize", "Set how many KiB each piece should be, overriding the preferred default", "s", true, "<size in KiB>" },
{ 'c', "comment", "Add a comment", "c", true, "<comment>" },
{ 't', "tracker", "Add a tracker's announce URL", "t", true, "<url>" },
{ 'q', "pooka", "Pooka", "pk", false, NULL },
{ 'V', "version", "Show version number and exit", "V", false, NULL },
{ 0, NULL, NULL, NULL, false, NULL }
};
static int run_test(int argc, char const** argv, int expected_n, int* expected_c, char const** expected_optarg)
{
int c;
int n;
char const* optarg;
n = 0;
tr_optind = 1;
while ((c = tr_getopt("summary", argc, argv, options, &optarg)) != TR_OPT_DONE)
{
check_int(n, <, expected_n);
check_int(c, ==, expected_c[n]);
check_str(optarg, ==, expected_optarg[n]);
++n;
}
check_int(n, ==, expected_n);
return 0;
}
/***
****
***/
static int test_no_options(void)
{
int argc = 1;
char const* argv[] = { "/some/path/tr-getopt-test" };
int expected_n = 0;
int expected_c[] = { 0 };
char const* expected_optarg[] = { NULL };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_short_noarg(void)
{
int argc = 2;
char const* argv[] = { "/some/path/tr-getopt-test", "-p" };
int expected_n = 1;
int expected_c[] = { 'p' };
char const* expected_optarg[] = { NULL };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_long_noarg(void)
{
int argc = 2;
char const* argv[] = { "/some/path/tr-getopt-test", "--private" };
int expected_n = 1;
int expected_c[] = { 'p' };
char const* expected_optarg[] = { NULL };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_short_with_arg(void)
{
int argc = 3;
char const* argv[] = { "/some/path/tr-getopt-test", "-o", "/tmp/outfile" };
int expected_n = 1;
int expected_c[] = { 'o' };
char const* expected_optarg[] = { "/tmp/outfile" };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_long_with_arg(void)
{
int argc = 3;
char const* argv[] = { "/some/path/tr-getopt-test", "--outfile", "/tmp/outfile" };
int expected_n = 1;
int expected_c[] = { 'o' };
char const* expected_optarg[] = { "/tmp/outfile" };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_short_with_arg_after_eq(void)
{
int argc = 2;
char const* argv[] = { "/some/path/tr-getopt-test", "-o=/tmp/outfile" };
int expected_n = 1;
int expected_c[] = { 'o' };
char const* expected_optarg[] = { "/tmp/outfile" };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_long_with_arg_after_eq(void)
{
int argc = 2;
char const* argv[] = { "/some/path/tr-getopt-test", "--outfile=/tmp/outfile" };
int expected_n = 1;
int expected_c[] = { 'o' };
char const* expected_optarg[] = { "/tmp/outfile" };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_unknown_option(void)
{
int argc = 2;
char const* argv[] = { "/some/path/tr-getopt-test", "-z" };
int expected_n = 1;
int expected_c[] = { TR_OPT_UNK };
char const* expected_optarg[] = { "-z" };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_missing_arg(void)
{
int argc = 2;
char const* argv[] = { "/some/path/tr-getopt-test", "-o" };
int expected_n = 1;
int expected_c[] = { TR_OPT_ERR };
char const* expected_optarg[] = { NULL };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_lots_of_options(void)
{
int argc = 6;
char const* argv[] = { "/some/path/tr-getopt-test", "--piecesize=4", "-c", "hello world", "-p", "--tracker=foo" };
int expected_n = 4;
int expected_c[] = { 's', 'c', 'p', 't' };
char const* expected_optarg[] = { "4", "hello world", NULL, "foo" };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
static int test_match_longer_key(void)
{
/* confirm that this resolves to 'q' and not 'p' */
int argc = 2;
char const* argv[] = { "/some/path/tr-getopt-test", "-pk" };
int expected_n = 1;
int expected_c[] = { 'q' };
char const* expected_optarg[] = { NULL };
return run_test(argc, argv, expected_n, expected_c, expected_optarg);
}
/***
****
***/
int main(void)
{
testFunc const tests[] =
{
test_no_options,
test_short_noarg,
test_long_noarg,
test_short_with_arg,
test_long_with_arg,
test_short_with_arg_after_eq,
test_long_with_arg_after_eq,
test_unknown_option,
test_missing_arg,
test_match_longer_key,
test_lots_of_options
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -8,10 +8,9 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
/**
* @addtogroup utils Utilities
@ -52,8 +51,6 @@ int tr_getopt(char const* summary, int argc, char const* const* argv, tr_option
/** @brief prints the `Usage' help section to stdout */
void tr_getopt_usage(char const* appName, char const* description, tr_option const* opts);
#ifdef __cplusplus
} /* extern "C" */
#endif
/** @} */
TR_END_DECLS

View File

@ -173,3 +173,12 @@
#define TR_INET6_ADDRSTRLEN 46
#define TR_BAD_SIZE ((size_t)-1)
/* Guard C code in headers, while including them from C++ */
#ifdef __cplusplus
#define TR_BEGIN_DECLS extern "C" {
#define TR_END_DECLS }
#else
#define TR_BEGIN_DECLS
#define TR_END_DECLS
#endif

View File

@ -32,6 +32,7 @@ THE SOFTWARE.
#include <event2/event.h>
#include <stdint.h>
#include <libutp/utp.h>
#include "transmission.h"

View File

@ -23,6 +23,7 @@ THE SOFTWARE.
#include <event2/event.h>
#include <stdint.h>
#include <libutp/utp.h>
#include "transmission.h"
@ -36,12 +37,12 @@ THE SOFTWARE.
#include "tr-utp.h"
#include "utils.h"
#ifndef WITH_UTP
#define MY_NAME "UTP"
#define dbgmsg(...) tr_logAddDeepNamed(MY_NAME, __VA_ARGS__)
#ifndef WITH_UTP
void UTP_Close(struct UTPSocket* socket)
{
tr_logAddNamedError(MY_NAME, "UTP_Close(%p) was called.", socket);

View File

@ -14,11 +14,6 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
/***
****
**** Basic Types
@ -32,6 +27,8 @@ extern "C"
#include "tr-macros.h"
TR_BEGIN_DECLS
typedef uint32_t tr_file_index_t;
typedef uint32_t tr_piece_index_t;
/* assuming a 16 KiB block, a 32-bit block index gives us a maximum torrent size of 63 TiB.
@ -721,6 +718,7 @@ void tr_sessionSetTorrentDoneScript(tr_session*, char const* scriptFilename);
typedef enum
{
TR_LOG_SILENT = 0,
TR_LOG_ERROR = 1,
TR_LOG_INFO = 2,
TR_LOG_DEBUG = 3,
@ -1888,6 +1886,4 @@ static inline bool tr_isDirection(tr_direction d)
return d == TR_UP || d == TR_DOWN;
}
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -12,8 +12,9 @@
#error only libtransmission should #include this header.
#endif
/**
**/
#include "tr-macros.h"
TR_BEGIN_DECLS
void tr_eventInit(tr_session*);
@ -22,3 +23,5 @@ void tr_eventClose(tr_session*);
bool tr_amInEventThread(tr_session const*);
void tr_runInEventThread(tr_session*, void (* func)(void*), void* user_data);
TR_END_DECLS

View File

@ -1,588 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <limits.h> /* INT_MAX */
#include <math.h> /* sqrt() */
#include <string.h> /* strlen() */
#include <stdlib.h> /* setenv(), unsetenv() */
#ifdef _WIN32
#include <windows.h>
#define setenv(key, value, unused) SetEnvironmentVariableA(key, value)
#define unsetenv(key) SetEnvironmentVariableA(key, NULL)
#endif
#include "transmission.h"
#include "ConvertUTF.h" /* tr_utf8_validate*/
#include "platform.h"
#include "crypto-utils.h" /* tr_rand_int_weak */
#include "utils.h"
#include "web.h"
#define SPEED_TEST 0
#if SPEED_TEST
#define VERBOSE
#endif
#include "libtransmission-test.h"
static int test_strip_positional_args(void)
{
char const* in;
char const* out;
char const* expected;
in = "Hello %1$s foo %2$.*f";
expected = "Hello %s foo %.*f";
out = tr_strip_positional_args(in);
check_str(out, ==, expected);
in = "Hello %1$'d foo %2$'f";
expected = "Hello %d foo %f";
out = tr_strip_positional_args(in);
check_str(out, ==, expected);
return 0;
}
static int test_strstrip(void)
{
char* in;
char* out;
/* strstrip */
in = tr_strdup(" test ");
out = tr_strstrip(in);
check_ptr(in, ==, out);
check_str(out, ==, "test");
tr_free(in);
/* strstrip */
in = tr_strdup(" test test ");
out = tr_strstrip(in);
check_ptr(in, ==, out);
check_str(out, ==, "test test");
tr_free(in);
/* strstrip */
in = tr_strdup("test");
out = tr_strstrip(in);
check_ptr(in, ==, out);
check_str(out, ==, "test");
tr_free(in);
return 0;
}
static int test_strjoin(void)
{
char* out;
char const* in1[] = { "one", "two" };
out = tr_strjoin(in1, 2, ", ");
check_str(out, ==, "one, two");
tr_free(out);
char const* in2[] = { "hello" };
out = tr_strjoin(in2, 1, "###");
check_str(out, ==, "hello");
tr_free(out);
char const* in3[] = { "a", "b", "ccc", "d", "eeeee" };
out = tr_strjoin(in3, 5, " ");
check_str(out, ==, "a b ccc d eeeee");
tr_free(out);
char const* in4[] = { "7", "ate", "9" };
out = tr_strjoin(in4, 3, "");
check_str(out, ==, "7ate9");
tr_free(out);
char const** in5;
out = tr_strjoin(in5, 0, "a");
check_str(out, ==, "");
tr_free(out);
return 0;
}
static int test_buildpath(void)
{
char* out;
out = tr_buildPath("foo", "bar", NULL);
check_str(out, ==, "foo" TR_PATH_DELIMITER_STR "bar");
tr_free(out);
out = tr_buildPath("", "foo", "bar", NULL);
check_str(out, ==, TR_PATH_DELIMITER_STR "foo" TR_PATH_DELIMITER_STR "bar");
tr_free(out);
return 0;
}
static int test_utf8(void)
{
char const* in;
char* out;
in = "hello world";
out = tr_utf8clean(in, TR_BAD_SIZE);
check_str(out, ==, in);
tr_free(out);
in = "hello world";
out = tr_utf8clean(in, 5);
check_str(out, ==, "hello");
tr_free(out);
/* this version is not utf-8 (but cp866) */
in = "\x92\xE0\xE3\xA4\xAD\xAE \xA1\xEB\xE2\xEC \x81\xAE\xA3\xAE\xAC";
out = tr_utf8clean(in, 17);
check_ptr(out, !=, NULL);
check(strlen(out) == 17 || strlen(out) == 33);
check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
tr_free(out);
/* same string, but utf-8 clean */
in = "Трудно быть Богом";
out = tr_utf8clean(in, TR_BAD_SIZE);
check_ptr(out, !=, NULL);
check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
check_str(out, ==, in);
tr_free(out);
in = "\xF4\x00\x81\x82";
out = tr_utf8clean(in, 4);
check_ptr(out, !=, NULL);
check(strlen(out) == 1 || strlen(out) == 2);
check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
tr_free(out);
in = "\xF4\x33\x81\x82";
out = tr_utf8clean(in, 4);
check_ptr(out, !=, NULL);
check(strlen(out) == 4 || strlen(out) == 7);
check(tr_utf8_validate(out, TR_BAD_SIZE, NULL));
tr_free(out);
return 0;
}
static int test_numbers(void)
{
int count;
int* numbers;
numbers = tr_parseNumberRange("1-10,13,16-19", TR_BAD_SIZE, &count);
check_int(count, ==, 15);
check_int(numbers[0], ==, 1);
check_int(numbers[5], ==, 6);
check_int(numbers[9], ==, 10);
check_int(numbers[10], ==, 13);
check_int(numbers[11], ==, 16);
check_int(numbers[14], ==, 19);
tr_free(numbers);
numbers = tr_parseNumberRange("1-5,3-7,2-6", TR_BAD_SIZE, &count);
check_int(count, ==, 7);
check_ptr(numbers, !=, NULL);
for (int i = 0; i < count; ++i)
{
check_int(numbers[i], ==, i + 1);
}
tr_free(numbers);
numbers = tr_parseNumberRange("1-Hello", TR_BAD_SIZE, &count);
check_int(count, ==, 0);
check_ptr(numbers, ==, NULL);
numbers = tr_parseNumberRange("1-", TR_BAD_SIZE, &count);
check_int(count, ==, 0);
check_ptr(numbers, ==, NULL);
numbers = tr_parseNumberRange("Hello", TR_BAD_SIZE, &count);
check_int(count, ==, 0);
check_ptr(numbers, ==, NULL);
return 0;
}
static int compareInts(void const* va, void const* vb)
{
int const a = *(int const*)va;
int const b = *(int const*)vb;
return a - b;
}
static int test_lowerbound(void)
{
int const A[] = { 1, 2, 3, 3, 3, 5, 8 };
int const expected_pos[] = { 0, 1, 2, 5, 5, 6, 6, 6, 7, 7 };
bool const expected_exact[] = { true, true, true, false, true, false, false, true, false, false };
int const N = TR_N_ELEMENTS(A);
for (int i = 1; i <= 10; i++)
{
bool exact;
int const pos = tr_lowerBound(&i, A, N, sizeof(int), compareInts, &exact);
#if 0
fprintf(stderr, "searching for %d. ", i);
fprintf(stderr, "result: index = %d, ", pos);
if (pos != N)
{
fprintf(stderr, "A[%d] == %d\n", pos, A[pos]);
}
else
{
fprintf(stderr, "which is off the end.\n");
}
#endif
check_int(pos, ==, expected_pos[i - 1]);
check_int(exact, ==, expected_exact[i - 1]);
}
return 0;
}
static int test_quickFindFirst_Iteration(size_t const k, size_t const n, int* buf, int range)
{
int highest_low;
int lowest_high;
/* populate buf with random ints */
for (size_t i = 0; i < n; ++i)
{
buf[i] = tr_rand_int_weak(range);
}
/* find the best k */
tr_quickfindFirstK(buf, n, sizeof(int), compareInts, k);
/* confirm that the smallest K ints are in the first slots K slots in buf */
highest_low = INT_MIN;
for (size_t i = 0; i < k; ++i)
{
if (highest_low < buf[i])
{
highest_low = buf[i];
}
}
lowest_high = INT_MAX;
for (size_t i = k; i < n; ++i)
{
if (lowest_high > buf[i])
{
lowest_high = buf[i];
}
}
check_int(highest_low, <=, lowest_high);
return 0;
}
static int test_quickfindFirst(void)
{
size_t const k = 10;
size_t const n = 100;
size_t const n_trials = 1000;
int* buf = tr_new(int, n);
for (size_t i = 0; i < n_trials; ++i)
{
check_int(test_quickFindFirst_Iteration(k, n, buf, 100), ==, 0);
}
tr_free(buf);
return 0;
}
static int test_memmem(void)
{
char const haystack[12] = "abcabcabcabc";
char const needle[3] = "cab";
check_ptr(tr_memmem(haystack, sizeof(haystack), haystack, sizeof(haystack)), ==, haystack);
check_ptr(tr_memmem(haystack, sizeof(haystack), needle, sizeof(needle)), ==, haystack + 2);
check_ptr(tr_memmem(needle, sizeof(needle), haystack, sizeof(haystack)), ==, NULL);
return 0;
}
static int test_hex(void)
{
char hex1[41];
char hex2[41];
uint8_t binary[20];
memcpy(hex1, "fb5ef5507427b17e04b69cef31fa3379b456735a", 41);
tr_hex_to_binary(hex1, binary, 20);
tr_binary_to_hex(binary, hex2, 20);
check_str(hex1, ==, hex2);
return 0;
}
static int test_array(void)
{
size_t array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t n = TR_N_ELEMENTS(array);
tr_removeElementFromArray(array, 5U, sizeof(size_t), n);
--n;
for (size_t i = 0; i < n; ++i)
{
check_int(array[i], ==, i < 5 ? i : i + 1);
}
tr_removeElementFromArray(array, 0U, sizeof(size_t), n);
--n;
for (size_t i = 0; i < n; ++i)
{
check_int(array[i], ==, i < 4 ? i + 1 : i + 2);
}
tr_removeElementFromArray(array, n - 1, sizeof(size_t), n);
--n;
for (size_t i = 0; i < n; ++i)
{
check_int(array[i], ==, i < 4 ? i + 1 : i + 2);
}
return 0;
}
static int test_url(void)
{
int port;
char* scheme;
char* host;
char* path;
char* str;
char const* url;
url = "http://1";
check(tr_urlParse(url, TR_BAD_SIZE, &scheme, &host, &port, &path));
check_str(scheme, ==, "http");
check_str(host, ==, "1");
check_str(path, ==, "/");
check_int(port, ==, 80);
tr_free(scheme);
tr_free(path);
tr_free(host);
url = "http://www.some-tracker.org/some/path";
check(tr_urlParse(url, TR_BAD_SIZE, &scheme, &host, &port, &path));
check_str(scheme, ==, "http");
check_str(host, ==, "www.some-tracker.org");
check_str(path, ==, "/some/path");
check_int(port, ==, 80);
tr_free(scheme);
tr_free(path);
tr_free(host);
url = "http://www.some-tracker.org:80/some/path";
check(tr_urlParse(url, TR_BAD_SIZE, &scheme, &host, &port, &path));
check_str(scheme, ==, "http");
check_str(host, ==, "www.some-tracker.org");
check_str(path, ==, "/some/path");
check_int(port, ==, 80);
tr_free(scheme);
tr_free(path);
tr_free(host);
url = "http%3A%2F%2Fwww.example.com%2F~user%2F%3Ftest%3D1%26test1%3D2";
str = tr_http_unescape(url, strlen(url));
check_str(str, ==, "http://www.example.com/~user/?test=1&test1=2");
tr_free(str);
return 0;
}
static int test_truncd(void)
{
char buf[32];
double const nan = sqrt(-1);
tr_snprintf(buf, sizeof(buf), "%.2f%%", 99.999);
check_str(buf, ==, "100.00%");
tr_snprintf(buf, sizeof(buf), "%.2f%%", tr_truncd(99.999, 2));
check_str(buf, ==, "99.99%");
tr_snprintf(buf, sizeof(buf), "%.4f", tr_truncd(403650.656250, 4));
check_str(buf, ==, "403650.6562");
tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(2.15, 2));
check_str(buf, ==, "2.15");
tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(2.05, 2));
check_str(buf, ==, "2.05");
tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(3.3333, 2));
check_str(buf, ==, "3.33");
tr_snprintf(buf, sizeof(buf), "%.0f", tr_truncd(3.3333, 0));
check_str(buf, ==, "3");
tr_snprintf(buf, sizeof(buf), "%.0f", tr_truncd(3.9999, 0));
check_str(buf, ==, "3");
#if !(defined(_MSC_VER) || (defined(__MINGW32__) && defined(__MSVCRT__)))
/* FIXME: MSCVRT behaves differently in case of nan */
tr_snprintf(buf, sizeof(buf), "%.2f", tr_truncd(nan, 2));
check(strstr(buf, "nan") != NULL || strstr(buf, "NaN") != NULL);
#else
(void)nan;
#endif
return 0;
}
static char* test_strdup_printf_valist(char const* fmt, ...) TR_GNUC_PRINTF(1, 2);
static char* test_strdup_printf_valist(char const* fmt, ...)
{
va_list args;
char* ret;
va_start(args, fmt);
ret = tr_strdup_vprintf(fmt, args);
va_end(args);
return ret;
}
static int test_strdup_printf(void)
{
char* s;
char* s2;
char* s3;
s = tr_strdup_printf("%s", "test");
check_str(s, ==, "test");
tr_free(s);
s = tr_strdup_printf("%d %s %c %u", -1, "0", '1', 2);
check_str(s, ==, "-1 0 1 2");
tr_free(s);
s3 = tr_malloc0(4098);
memset(s3, '-', 4097);
s3[2047] = 't';
s3[2048] = 'e';
s3[2049] = 's';
s3[2050] = 't';
s2 = tr_malloc0(4096);
memset(s2, '-', 4095);
s2[2047] = '%';
s2[2048] = 's';
s = tr_strdup_printf(s2, "test");
check_str(s, ==, s3);
tr_free(s);
tr_free(s2);
s = tr_strdup_printf("%s", s3);
check_str(s, ==, s3);
tr_free(s);
tr_free(s3);
s = test_strdup_printf_valist("\n-%s-%s-%s-\n", "\r", "\t", "\b");
check_str(s, ==, "\n-\r-\t-\b-\n");
tr_free(s);
return 0;
}
static int test_env(void)
{
char const* test_key = "TR_TEST_ENV";
int x;
char* s;
unsetenv(test_key);
check(!tr_env_key_exists(test_key));
x = tr_env_get_int(test_key, 123);
check_int(x, ==, 123);
s = tr_env_get_string(test_key, NULL);
check_str(s, ==, NULL);
s = tr_env_get_string(test_key, "a");
check_str(s, ==, "a");
tr_free(s);
setenv(test_key, "", 1);
check(tr_env_key_exists(test_key));
x = tr_env_get_int(test_key, 456);
check_int(x, ==, 456);
s = tr_env_get_string(test_key, NULL);
check_str(s, ==, "");
tr_free(s);
s = tr_env_get_string(test_key, "b");
check_str(s, ==, "");
tr_free(s);
setenv(test_key, "135", 1);
check(tr_env_key_exists(test_key));
x = tr_env_get_int(test_key, 789);
check_int(x, ==, 135);
s = tr_env_get_string(test_key, NULL);
check_str(s, ==, "135");
tr_free(s);
s = tr_env_get_string(test_key, "c");
check_str(s, ==, "135");
tr_free(s);
return 0;
}
int main(void)
{
testFunc const tests[] =
{
test_array,
test_buildpath,
test_hex,
test_lowerbound,
test_quickfindFirst,
test_memmem,
test_numbers,
test_strip_positional_args,
test_strdup_printf,
test_strstrip,
test_strjoin,
test_truncd,
test_url,
test_utf8,
test_env
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -702,7 +702,7 @@ void tr_wait_msec(long int msec)
****
***/
int tr_snprintf(char* buf, size_t buflen, char const* fmt, ...)
int tr_snprintf(void* buf, size_t buflen, char const* fmt, ...)
{
int len;
va_list args;
@ -718,7 +718,7 @@ int tr_snprintf(char* buf, size_t buflen, char const* fmt, ...)
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen (src); if retval >= siz, truncation occurred.
*/
size_t tr_strlcpy(char* dst, void const* src, size_t siz)
size_t tr_strlcpy(void* dst, void const* src, size_t siz)
{
TR_ASSERT(dst != NULL);
TR_ASSERT(src != NULL);
@ -787,35 +787,39 @@ double tr_getRatio(uint64_t numerator, uint64_t denominator)
return ratio;
}
void tr_binary_to_hex(void const* input, char* output, size_t byte_length)
void tr_binary_to_hex(void const* vinput, void* voutput, size_t byte_length)
{
static char const hex[] = "0123456789abcdef";
uint8_t const* input_octets = input;
uint8_t const* input = vinput;
char* output = voutput;
/* go from back to front to allow for in-place conversion */
input_octets += byte_length;
input += byte_length;
output += byte_length * 2;
*output = '\0';
while (byte_length-- > 0)
{
unsigned int const val = *(--input_octets);
unsigned int const val = *(--input);
*(--output) = hex[val & 0xf];
*(--output) = hex[val >> 4];
}
}
void tr_hex_to_binary(char const* input, void* output, size_t byte_length)
void tr_hex_to_binary(void const* vinput, void* voutput, size_t byte_length)
{
static char const hex[] = "0123456789abcdef";
uint8_t* output_octets = output;
uint8_t const* input = (uint8_t const*)vinput;
uint8_t* output = voutput;
for (size_t i = 0; i < byte_length; ++i)
{
int const hi = strchr(hex, tolower(*input++)) - hex;
int const lo = strchr(hex, tolower(*input++)) - hex;
*output_octets++ = (uint8_t)((hi << 4) | lo);
*output++ = (uint8_t)((hi << 4) | lo);
}
}
@ -1020,7 +1024,7 @@ bool tr_urlParse(char const* url, size_t url_len, char** setme_scheme, char** se
****
***/
void tr_removeElementFromArray(void* array, unsigned int index_to_remove, size_t sizeof_element, size_t nmemb)
void tr_removeElementFromArray(void* array, size_t index_to_remove, size_t sizeof_element, size_t nmemb)
{
char* a = array;

View File

@ -13,10 +13,9 @@
#include <stddef.h> /* size_t */
#include <time.h> /* time_t */
#ifdef __cplusplus
extern "C"
{
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
/***
****
@ -229,10 +228,10 @@ char* tr_strdup_printf(char const* fmt, ...) TR_GNUC_MALLOC TR_GNUC_PRINTF(1, 2)
char* tr_strdup_vprintf(char const* fmt, va_list args) TR_GNUC_MALLOC TR_GNUC_PRINTF(1, 0);
/** @brief Portability wrapper for strlcpy() that uses the system implementation if available */
size_t tr_strlcpy(char* dst, void const* src, size_t siz);
size_t tr_strlcpy(void* dst, void const* src, size_t siz);
/** @brief Portability wrapper for snprintf() that uses the system implementation if available */
int tr_snprintf(char* buf, size_t buflen, char const* fmt, ...) TR_GNUC_PRINTF(3, 4) TR_GNUC_NONNULL(1, 3);
int tr_snprintf(void* buf, size_t buflen, char const* fmt, ...) TR_GNUC_PRINTF(3, 4) TR_GNUC_NONNULL(1, 3);
/** @brief Convenience wrapper around strerorr() guaranteed to not return NULL
@param errnum the error number to describe */
@ -263,8 +262,8 @@ char* tr_strjoin(char const* const* arr, size_t len, char const* delim);
int compareInt(void const* va, void const* vb);
void tr_binary_to_hex(void const* input, char* output, size_t byte_length) TR_GNUC_NONNULL(1, 2);
void tr_hex_to_binary(char const* input, void* output, size_t byte_length) TR_GNUC_NONNULL(1, 2);
void tr_binary_to_hex(void const* input, void* output, size_t byte_length) TR_GNUC_NONNULL(1, 2);
void tr_hex_to_binary(void const* input, void* output, size_t byte_length) TR_GNUC_NONNULL(1, 2);
/** @brief convenience function to determine if an address is an IP address (IPv4 or IPv6) */
bool tr_addressIsIP(char const* address);
@ -334,7 +333,7 @@ int tr_gettimeofday(struct timeval* tv);
bool tr_moveFile(char const* oldpath, char const* newpath, struct tr_error** error) TR_GNUC_NONNULL(1, 2);
/** @brief convenience function to remove an item from an array */
void tr_removeElementFromArray(void* array, unsigned int index_to_remove, size_t sizeof_element, size_t nmemb);
void tr_removeElementFromArray(void* array, size_t index_to_remove, size_t sizeof_element, size_t nmemb);
/***
****
@ -389,6 +388,7 @@ extern unsigned int tr_size_K;
/* format a speed from KBps into a user-readable string. */
char* tr_formatter_speed_KBps(char* buf, double KBps, size_t buflen);
// FIXME(ckerr): bytes should be a size_t
/* format a memory size from bytes into a user-readable string. */
char* tr_formatter_mem_B(char* buf, int64_t bytes, size_t buflen);
@ -398,6 +398,7 @@ static inline char* tr_formatter_mem_MB(char* buf, double MBps, size_t buflen)
return tr_formatter_mem_B(buf, (int64_t)(MBps * tr_mem_K * tr_mem_K), buflen);
}
// FIXME(ckerr): bytes should be a size_t
/* format a file size from bytes into a user-readable string. */
char* tr_formatter_size_B(char* buf, int64_t bytes, size_t buflen);
@ -422,12 +423,6 @@ char* tr_env_get_string(char const* key, char const* default_value);
void tr_net_init(void);
/***
****
***/
#ifdef __cplusplus
}
#endif
/** @} */
TR_END_DECLS

View File

@ -15,7 +15,7 @@
#include "ConvertUTF.h"
#define __LIBTRANSMISSION_VARIANT_MODULE__
#define LIBTRANSMISSION_VARIANT_MODULE
#include "transmission.h"
#include "ptrarray.h"
@ -39,8 +39,10 @@
* but to handle it as a signed 64bit integer is mandatory to handle
* "large files" aka .torrent for more that 4Gbyte
*/
int tr_bencParseInt(uint8_t const* buf, uint8_t const* bufend, uint8_t const** setme_end, int64_t* setme_val)
int tr_bencParseInt(void const* vbuf, void const* vbufend, uint8_t const** setme_end, int64_t* setme_val)
{
uint8_t const* const buf = (uint8_t const*)vbuf;
uint8_t const* const bufend = (uint8_t const*)vbufend;
char* endptr;
void const* begin;
void const* end;
@ -88,9 +90,12 @@ int tr_bencParseInt(uint8_t const* buf, uint8_t const* bufend, uint8_t const** s
* Note that there is no constant beginning delimiter, and no ending delimiter.
* Example: 4:spam represents the string "spam"
*/
int tr_bencParseStr(uint8_t const* buf, uint8_t const* bufend, uint8_t const** setme_end, uint8_t const** setme_str,
int tr_bencParseStr(void const* vbuf, void const* vbufend, uint8_t const** setme_end, uint8_t const** setme_str,
size_t* setme_strlen)
{
uint8_t const* const buf = (uint8_t const*)vbuf;
uint8_t const* const bufend = (uint8_t const*)vbufend;
void const* end;
size_t len;
char* ulend;

View File

@ -8,10 +8,14 @@
#pragma once
#ifndef __LIBTRANSMISSION_VARIANT_MODULE__
#ifndef LIBTRANSMISSION_VARIANT_MODULE
#error only libtransmission/variant-*.c should #include this header.
#endif
#include "tr-macros.h"
TR_BEGIN_DECLS
typedef void (* VariantWalkFunc)(tr_variant const* val, void* user_data);
struct VariantWalkFuncs
@ -37,10 +41,12 @@ void tr_variantInit(tr_variant* v, char type);
int tr_jsonParse(char const* source, void const* vbuf, size_t len, tr_variant* setme_benc, char const** setme_end);
/** @brief Private function that's exposed here only for unit tests */
int tr_bencParseInt(uint8_t const* buf, uint8_t const* bufend, uint8_t const** setme_end, int64_t* setme_val);
int tr_bencParseInt(void const* buf, void const* bufend, uint8_t const** setme_end, int64_t* setme_val);
/** @brief Private function that's exposed here only for unit tests */
int tr_bencParseStr(uint8_t const* buf, uint8_t const* bufend, uint8_t const** setme_end, uint8_t const** setme_str,
int tr_bencParseStr(void const* buf, void const* bufend, uint8_t const** setme_end, uint8_t const** setme_str,
size_t* setme_strlen);
int tr_variantParseBenc(void const* buf, void const* end, tr_variant* top, char const** setme_end);
TR_END_DECLS

View File

@ -15,14 +15,11 @@
#include <event2/buffer.h> /* evbuffer_add() */
#include <event2/util.h> /* evutil_strtoll() */
#define JSONSL_STATE_USER_FIELDS /* no fields */
#include "jsonsl.h"
#include "jsonsl.c"
#define __LIBTRANSMISSION_VARIANT_MODULE__
#define LIBTRANSMISSION_VARIANT_MODULE
#include "transmission.h"
#include "ConvertUTF.h"
#include "jsonsl.h"
#include "list.h"
#include "log.h"
#include "ptrarray.h"
@ -246,8 +243,7 @@ static char* extract_escaped_string(char const* in, size_t in_len, size_t* len,
if (ConvertUTF32toUTF8(&str32_walk, str32_end, &str8_walk, str8_end, 0) == 0)
{
size_t const len = str8_walk - str8_buf;
evbuffer_add(buf, str8_buf, len);
evbuffer_add(buf, str8_buf, str8_walk - str8_buf);
unescaped = true;
}

View File

@ -1,598 +0,0 @@
/*
* This file Copyright (C) 2013-2014 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <ctype.h> /* isspace() */
#include <errno.h> /* EILSEQ */
#include <string.h> /* strlen(), strncmp() */
#include <event2/buffer.h>
#define __LIBTRANSMISSION_VARIANT_MODULE__
#include "transmission.h"
#include "utils.h" /* tr_free */
#include "variant.h"
#include "variant-common.h"
#include "libtransmission-test.h"
#ifndef _WIN32
#define STACK_SMASH_DEPTH (1 * 1000 * 1000)
#else
#define STACK_SMASH_DEPTH (100 * 1000)
#endif
static int testInt(void)
{
uint8_t buf[128];
int64_t val;
int err;
uint8_t const* end;
/* good int string */
tr_snprintf((char*)buf, sizeof(buf), "i64e");
err = tr_bencParseInt(buf, buf + 4, &end, &val);
check_int(err, ==, 0);
check_int(val, ==, 64);
check_ptr(end, ==, buf + 4);
/* missing 'e' */
end = NULL;
val = 888;
err = tr_bencParseInt(buf, buf + 3, &end, &val);
check_int(err, ==, EILSEQ);
check_int(val, ==, 888);
check_ptr(end, ==, NULL);
/* empty buffer */
err = tr_bencParseInt(buf, buf + 0, &end, &val);
check_int(err, ==, EILSEQ);
check_int(val, ==, 888);
check_ptr(end, ==, NULL);
/* bad number */
tr_snprintf((char*)buf, sizeof(buf), "i6z4e");
err = tr_bencParseInt(buf, buf + 5, &end, &val);
check_int(err, ==, EILSEQ);
check_int(val, ==, 888);
check_ptr(end, ==, NULL);
/* negative number */
tr_snprintf((char*)buf, sizeof(buf), "i-3e");
err = tr_bencParseInt(buf, buf + 4, &end, &val);
check_int(err, ==, 0);
check_int(val, ==, -3);
check_ptr(end, ==, buf + 4);
/* zero */
tr_snprintf((char*)buf, sizeof(buf), "i0e");
err = tr_bencParseInt(buf, buf + 4, &end, &val);
check_int(err, ==, 0);
check_int(val, ==, 0);
check_ptr(end, ==, buf + 3);
/* no leading zeroes allowed */
val = 0;
end = NULL;
tr_snprintf((char*)buf, sizeof(buf), "i04e");
err = tr_bencParseInt(buf, buf + 4, &end, &val);
check_int(err, ==, EILSEQ);
check_int(val, ==, 0);
check_ptr(end, ==, NULL);
return 0;
}
static int testStr(void)
{
uint8_t buf[128];
int err;
int n;
uint8_t const* end;
uint8_t const* str;
size_t len;
/* string len is designed to overflow */
n = tr_snprintf((char*)buf, sizeof(buf), "%zu:boat", (size_t)(SIZE_MAX - 2));
err = tr_bencParseStr(buf, buf + n, &end, &str, &len);
check_int(err, ==, EILSEQ);
check_uint(len, ==, 0);
check_ptr(str, ==, NULL);
check_ptr(end, ==, NULL);
/* good string */
n = tr_snprintf((char*)buf, sizeof(buf), "4:boat");
err = tr_bencParseStr(buf, buf + n, &end, &str, &len);
check_int(err, ==, 0);
check_uint(len, ==, 4);
check_mem(str, ==, "boat", len);
check_ptr(end, ==, buf + 6);
str = NULL;
end = NULL;
len = 0;
/* string goes past end of buffer */
err = tr_bencParseStr(buf, buf + (n - 1), &end, &str, &len);
check_int(err, ==, EILSEQ);
check_uint(len, ==, 0);
check_ptr(str, ==, NULL);
check_ptr(end, ==, NULL);
/* empty string */
n = tr_snprintf((char*)buf, sizeof(buf), "0:");
err = tr_bencParseStr(buf, buf + n, &end, &str, &len);
check_int(err, ==, 0);
check_uint(len, ==, 0);
check_uint(*str, ==, '\0');
check_ptr(end, ==, buf + 2);
str = NULL;
end = NULL;
len = 0;
/* short string */
n = tr_snprintf((char*)buf, sizeof(buf), "3:boat");
err = tr_bencParseStr(buf, buf + n, &end, &str, &len);
check_int(err, ==, 0);
check_uint(len, ==, 3);
check_mem(str, ==, "boa", len);
check_ptr(end, ==, buf + 5);
str = NULL;
end = NULL;
len = 0;
return 0;
}
static int testString(char const* str, bool isGood)
{
tr_variant val;
char const* end = NULL;
char* saved;
size_t const len = strlen(str);
size_t savedLen;
int err;
err = tr_variantFromBencFull(&val, str, len, NULL, &end);
if (!isGood)
{
check_int(err, !=, 0);
}
else
{
check_int(err, ==, 0);
#if 0
fprintf(stderr, "in: [%s]\n", str);
fprintf(stderr, "out:\n%s", tr_variantToStr(&val, TR_VARIANT_FMT_JSON, NULL));
#endif
check_ptr(end, ==, str + len);
saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &savedLen);
check_str(saved, ==, str);
check_uint(savedLen, ==, len);
tr_free(saved);
tr_variantFree(&val);
}
return 0;
}
static int testParse(void)
{
tr_variant val;
tr_variant* child;
tr_variant* child2;
char buf[512];
char const* end;
int err;
size_t len;
int64_t i;
char* saved;
tr_snprintf((char*)buf, sizeof(buf), "i64e");
err = tr_variantFromBencFull(&val, buf, sizeof(buf), NULL, &end);
check_int(err, ==, 0);
check(tr_variantGetInt(&val, &i));
check_int(i, ==, 64);
check_ptr(end, ==, buf + 4);
tr_variantFree(&val);
tr_snprintf((char*)buf, sizeof(buf), "li64ei32ei16ee");
err = tr_variantFromBencFull(&val, buf, sizeof(buf), NULL, &end);
check_int(err, ==, 0);
check_ptr(end, ==, buf + strlen((char*)buf));
check_uint(val.val.l.count, ==, 3);
check(tr_variantGetInt(&val.val.l.vals[0], &i));
check_int(i, ==, 64);
check(tr_variantGetInt(&val.val.l.vals[1], &i));
check_int(i, ==, 32);
check(tr_variantGetInt(&val.val.l.vals[2], &i));
check_int(i, ==, 16);
saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &len);
check_str(saved, ==, buf);
tr_free(saved);
tr_variantFree(&val);
end = NULL;
tr_snprintf((char*)buf, sizeof(buf), "lllee");
err = tr_variantFromBencFull(&val, buf, sizeof(buf), NULL, &end);
check_int(err, !=, 0);
check_ptr(end, ==, NULL);
end = NULL;
tr_snprintf((char*)buf, sizeof(buf), "le");
err = tr_variantFromBencFull(&val, buf, sizeof(buf), NULL, &end);
check_int(err, ==, 0);
check_ptr(end, ==, buf + 2);
saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &len);
check_str(saved, ==, "le");
tr_free(saved);
tr_variantFree(&val);
if ((err = testString("llleee", true)) != 0)
{
return err;
}
if ((err = testString("d3:cow3:moo4:spam4:eggse", true)) != 0)
{
return err;
}
if ((err = testString("d4:spaml1:a1:bee", true)) != 0)
{
return err;
}
if ((err = testString("d5:greenli1ei2ei3ee4:spamd1:ai123e3:keyi214eee", true)) != 0)
{
return err;
}
if ((err = testString("d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee", true)) != 0)
{
return err;
}
if ((err = testString("d8:completei1e8:intervali1800e12:min intervali1800e5:peers0:e", true)) != 0)
{
return err;
}
if ((err = testString("d1:ai0e1:be", false)) != 0) /* odd number of children */
{
return err;
}
if ((err = testString("", false)) != 0)
{
return err;
}
if ((err = testString(" ", false)) != 0)
{
return err;
}
/* nested containers
* parse an unsorted dict
* save as a sorted dict */
end = NULL;
tr_snprintf((char*)buf, sizeof(buf), "lld1:bi32e1:ai64eeee");
err = tr_variantFromBencFull(&val, buf, sizeof(buf), NULL, &end);
check_int(err, ==, 0);
check_ptr(end, ==, buf + strlen((char const*)buf));
check_ptr((child = tr_variantListChild(&val, 0)), !=, NULL);
check_ptr((child2 = tr_variantListChild(child, 0)), !=, NULL);
saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &len);
check_str(saved, ==, "lld1:ai64e1:bi32eeee");
tr_free(saved);
tr_variantFree(&val);
/* too many endings */
end = NULL;
tr_snprintf((char*)buf, sizeof(buf), "leee");
err = tr_variantFromBencFull(&val, buf, sizeof(buf), NULL, &end);
check_int(err, ==, 0);
check_ptr(end, ==, buf + 2);
saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &len);
check_str(saved, ==, "le");
tr_free(saved);
tr_variantFree(&val);
/* no ending */
end = NULL;
tr_snprintf((char*)buf, sizeof(buf), "l1:a1:b1:c");
err = tr_variantFromBencFull(&val, buf, strlen(buf), NULL, &end);
check_int(err, !=, 0);
/* incomplete string */
end = NULL;
tr_snprintf((char*)buf, sizeof(buf), "1:");
err = tr_variantFromBencFull(&val, buf, strlen(buf), NULL, &end);
check_int(err, !=, 0);
return 0;
}
static void stripWhitespace(char* in)
{
char* out = in;
for (; !tr_str_is_empty(in); ++in)
{
if (!isspace(*in))
{
*out++ = *in;
}
}
*out = '\0';
}
static int testJSONSnippet(char const* benc_str, char const* expected)
{
tr_variant top;
char* serialized;
struct evbuffer* buf;
tr_variantFromBenc(&top, benc_str, strlen(benc_str));
buf = tr_variantToBuf(&top, TR_VARIANT_FMT_JSON);
serialized = (char*)evbuffer_pullup(buf, -1);
stripWhitespace(serialized);
#if 0
fprintf(stderr, "benc: %s\n", benc_str);
fprintf(stderr, "json: %s\n", serialized);
fprintf(stderr, "want: %s\n", expected);
#endif
check_str(serialized, ==, expected);
tr_variantFree(&top);
evbuffer_free(buf);
return 0;
}
static int testJSON(void)
{
int val;
char const* benc_str;
char const* expected;
benc_str = "i6e";
expected = "6";
if ((val = testJSONSnippet(benc_str, expected)) != 0)
{
return val;
}
benc_str = "d5:helloi1e5:worldi2ee";
expected = "{\"hello\":1,\"world\":2}";
if ((val = testJSONSnippet(benc_str, expected)) != 0)
{
return val;
}
benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3eee";
expected = "{\"foo\":[1,2,3],\"hello\":1,\"world\":2}";
if ((val = testJSONSnippet(benc_str, expected)) != 0)
{
return val;
}
benc_str = "d5:helloi1e5:worldi2e3:fooli1ei2ei3ed1:ai0eeee";
expected = "{\"foo\":[1,2,3,{\"a\":0}],\"hello\":1,\"world\":2}";
if ((val = testJSONSnippet(benc_str, expected)) != 0)
{
return val;
}
benc_str = "d4:argsd6:statusle7:status2lee6:result7:successe";
expected = "{\"args\":{\"status\":[],\"status2\":[]},\"result\":\"success\"}";
if ((val = testJSONSnippet(benc_str, expected)) != 0)
{
return val;
}
return 0;
}
static int testMerge(void)
{
size_t len;
tr_variant dest;
tr_variant src;
int64_t i;
char const* s;
tr_quark const i1 = tr_quark_new("i1", 2);
tr_quark const i2 = tr_quark_new("i2", 2);
tr_quark const i3 = tr_quark_new("i3", 2);
tr_quark const i4 = tr_quark_new("i4", 2);
tr_quark const s5 = tr_quark_new("s5", 2);
tr_quark const s6 = tr_quark_new("s6", 2);
tr_quark const s7 = tr_quark_new("s7", 2);
tr_quark const s8 = tr_quark_new("s8", 2);
/* initial dictionary (default values) */
tr_variantInitDict(&dest, 10);
tr_variantDictAddInt(&dest, i1, 1);
tr_variantDictAddInt(&dest, i2, 2);
tr_variantDictAddInt(&dest, i4, -35); /* remains untouched */
tr_variantDictAddStr(&dest, s5, "abc");
tr_variantDictAddStr(&dest, s6, "def");
tr_variantDictAddStr(&dest, s7, "127.0.0.1"); /* remains untouched */
/* new dictionary, will overwrite items in dest */
tr_variantInitDict(&src, 10);
tr_variantDictAddInt(&src, i1, 1); /* same value */
tr_variantDictAddInt(&src, i2, 4); /* new value */
tr_variantDictAddInt(&src, i3, 3); /* new key:value */
tr_variantDictAddStr(&src, s5, "abc"); /* same value */
tr_variantDictAddStr(&src, s6, "xyz"); /* new value */
tr_variantDictAddStr(&src, s8, "ghi"); /* new key:value */
tr_variantMergeDicts(&dest, /*const*/ &src);
check(tr_variantDictFindInt(&dest, i1, &i));
check_int(i, ==, 1);
check(tr_variantDictFindInt(&dest, i2, &i));
check_int(i, ==, 4);
check(tr_variantDictFindInt(&dest, i3, &i));
check_int(i, ==, 3);
check(tr_variantDictFindInt(&dest, i4, &i));
check_int(i, ==, -35);
check(tr_variantDictFindStr(&dest, s5, &s, &len));
check_uint(len, ==, 3);
check_str(s, ==, "abc");
check(tr_variantDictFindStr(&dest, s6, &s, &len));
check_uint(len, ==, 3);
check_str(s, ==, "xyz");
check(tr_variantDictFindStr(&dest, s7, &s, &len));
check_uint(len, ==, 9);
check_str(s, ==, "127.0.0.1");
check(tr_variantDictFindStr(&dest, s8, &s, &len));
check_uint(len, ==, 3);
check_str(s, ==, "ghi");
tr_variantFree(&dest);
tr_variantFree(&src);
return 0;
}
static int testStackSmash(void)
{
size_t len;
int err;
char* in;
char const* end;
tr_variant val;
char* saved;
int const depth = STACK_SMASH_DEPTH;
in = tr_new(char, depth * 2 + 1);
for (int i = 0; i < depth; ++i)
{
in[i] = 'l';
in[depth + i] = 'e';
}
in[depth * 2] = '\0';
err = tr_variantFromBencFull(&val, in, depth * 2, NULL, &end);
check_int(err, ==, 0);
check_ptr(end, ==, in + depth * 2);
saved = tr_variantToStr(&val, TR_VARIANT_FMT_BENC, &len);
check_str(saved, ==, in);
tr_free(in);
tr_free(saved);
tr_variantFree(&val);
return 0;
}
static int testBool(void)
{
tr_variant top;
int64_t intVal;
bool boolVal;
tr_quark const key1 = tr_quark_new("key1", 4);
tr_quark const key2 = tr_quark_new("key2", 4);
tr_quark const key3 = tr_quark_new("key3", 4);
tr_quark const key4 = tr_quark_new("key4", 4);
tr_variantInitDict(&top, 0);
tr_variantDictAddBool(&top, key1, false);
tr_variantDictAddBool(&top, key2, 0);
tr_variantDictAddInt(&top, key3, true);
tr_variantDictAddInt(&top, key4, 1);
check(tr_variantDictFindBool(&top, key1, &boolVal));
check(!boolVal);
check(tr_variantDictFindBool(&top, key2, &boolVal));
check(!boolVal);
check(tr_variantDictFindBool(&top, key3, &boolVal));
check(boolVal);
check(tr_variantDictFindBool(&top, key4, &boolVal));
check(boolVal);
check(tr_variantDictFindInt(&top, key1, &intVal));
check_int(intVal, ==, 0);
check(tr_variantDictFindInt(&top, key2, &intVal));
check_int(intVal, ==, 0);
check(tr_variantDictFindInt(&top, key3, &intVal));
check_int(intVal, !=, 0);
check(tr_variantDictFindInt(&top, key4, &intVal));
check_int(intVal, !=, 0);
tr_variantFree(&top);
return 0;
}
static int testParse2(void)
{
tr_variant top;
tr_variant top2;
int64_t intVal;
char const* strVal;
double realVal;
bool boolVal;
size_t len;
char* benc;
char const* end;
size_t strLen;
tr_quark const key_bool = tr_quark_new("this-is-a-bool", TR_BAD_SIZE);
tr_quark const key_real = tr_quark_new("this-is-a-real", TR_BAD_SIZE);
tr_quark const key_int = tr_quark_new("this-is-an-int", TR_BAD_SIZE);
tr_quark const key_str = tr_quark_new("this-is-a-string", TR_BAD_SIZE);
tr_variantInitDict(&top, 0);
tr_variantDictAddBool(&top, key_bool, true);
tr_variantDictAddInt(&top, key_int, 1234);
tr_variantDictAddReal(&top, key_real, 0.5);
tr_variantDictAddStr(&top, key_str, "this-is-a-string");
benc = tr_variantToStr(&top, TR_VARIANT_FMT_BENC, &len);
check_str(benc, ==, "d14:this-is-a-booli1e14:this-is-a-real8:0.50000016:this-is-a-string16:this-is-a-string14:this-is-an-"
"inti1234ee");
check_int(tr_variantFromBencFull(&top2, benc, len, NULL, &end), ==, 0);
check_ptr(end, ==, benc + len);
check(tr_variantIsDict(&top2));
check(tr_variantDictFindInt(&top, key_int, &intVal));
check_int(intVal, ==, 1234);
check(tr_variantDictFindBool(&top, key_bool, &boolVal));
check(boolVal);
check(tr_variantDictFindStr(&top, key_str, &strVal, &strLen));
check_uint(strLen, ==, 16);
check_str(strVal, ==, "this-is-a-string");
check(tr_variantDictFindReal(&top, key_real, &realVal));
check_int((int)(realVal * 100), ==, 50);
tr_variantFree(&top2);
tr_free(benc);
tr_variantFree(&top);
return 0;
}
int main(void)
{
static testFunc const tests[] =
{
testInt,
testStr,
testParse,
testJSON,
testMerge,
testBool,
testParse2,
testStackSmash
};
return runTests(tests, NUM_TESTS(tests));
}

View File

@ -31,7 +31,7 @@
#include <event2/buffer.h>
#define __LIBTRANSMISSION_VARIANT_MODULE__
#define LIBTRANSMISSION_VARIANT_MODULE
#include "transmission.h"
#include "ConvertUTF.h"
@ -821,13 +821,13 @@ static void nodeDestruct(struct SaveNode* node)
* easier to read, but was vulnerable to a smash-stacking
* attack via maliciously-crafted data. (#667)
*/
void tr_variantWalk(tr_variant const* v, struct VariantWalkFuncs const* walkFuncs, void* user_data, bool sort_dicts)
void tr_variantWalk(tr_variant const* v_in, struct VariantWalkFuncs const* walkFuncs, void* user_data, bool sort_dicts)
{
int stackSize = 0;
int stackAlloc = 64;
struct SaveNode* stack = tr_new(struct SaveNode, stackAlloc);
nodeConstruct(&stack[stackSize++], v, sort_dicts);
nodeConstruct(&stack[stackSize++], v_in, sort_dicts);
while (stackSize > 0)
{

View File

@ -8,14 +8,13 @@
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <inttypes.h> /* int64_t */
#include <inttypes.h> /* for int64_t */
#include "tr-macros.h"
#include "quark.h"
TR_BEGIN_DECLS
struct evbuffer;
struct tr_error;
@ -280,6 +279,4 @@ void tr_variantMergeDicts(tr_variant* dict_target, tr_variant const* dict_source
/* @} */
#ifdef __cplusplus
}
#endif
TR_END_DECLS

View File

@ -8,7 +8,7 @@
#pragma once
#ifndef __LIBTRANSMISSION_WATCHDIR_MODULE__
#ifndef LIBTRANSMISSION_WATCHDIR_MODULE
#error only the libtransmission watchdir module should #include this header.
#endif

View File

@ -10,7 +10,7 @@
#include <event2/event.h>
#define __LIBTRANSMISSION_WATCHDIR_MODULE__
#define LIBTRANSMISSION_WATCHDIR_MODULE
#include "transmission.h"
#include "log.h"

View File

@ -17,7 +17,7 @@
#include <event2/bufferevent.h>
#include <event2/event.h>
#define __LIBTRANSMISSION_WATCHDIR_MODULE__
#define LIBTRANSMISSION_WATCHDIR_MODULE
#include "transmission.h"
#include "log.h"

View File

@ -21,7 +21,7 @@
#include <event2/event.h>
#define __LIBTRANSMISSION_WATCHDIR_MODULE__
#define LIBTRANSMISSION_WATCHDIR_MODULE
#include "transmission.h"
#include "log.h"

View File

@ -1,400 +0,0 @@
/*
* This file Copyright (C) 2015-2016 Mnemosyne LLC
*
* It may be used under the GNU GPL versions 2 or 3
* or any future license endorsed by Mnemosyne LLC.
*
*/
#include <event2/event.h>
#include "transmission.h"
#include "file.h"
#include "net.h"
#include "utils.h"
#include "watchdir.h"
#include "libtransmission-test.h"
/***
****
***/
typedef struct callback_data
{
tr_watchdir_t dir;
char* name;
tr_watchdir_status result;
}
callback_data;
#define CB_DATA_STATIC_INIT { NULL, NULL, 0 }
static struct event_base* ev_base = NULL;
extern struct timeval tr_watchdir_generic_interval;
extern unsigned int tr_watchdir_retry_limit;
extern struct timeval tr_watchdir_retry_start_interval;
extern struct timeval tr_watchdir_retry_max_interval;
static struct timeval const FIFTY_MSEC = { .tv_sec = 0, .tv_usec = 50000 };
static struct timeval const ONE_HUNDRED_MSEC = { .tv_sec = 0, .tv_usec = 100000 };
static struct timeval const TWO_HUNDRED_MSEC = { .tv_sec = 0, .tv_usec = 200000 };
static void process_events(void)
{
event_base_loopexit(ev_base, &TWO_HUNDRED_MSEC);
event_base_dispatch(ev_base);
}
static tr_watchdir_status callback(tr_watchdir_t dir, char const* name, void* context)
{
callback_data* const data = context;
if (data->result != TR_WATCHDIR_RETRY)
{
data->dir = dir;
if (data->name != NULL)
{
tr_free(data->name);
}
data->name = tr_strdup(name);
}
return data->result;
}
static void reset_callback_data(callback_data* data, tr_watchdir_status result)
{
tr_free(data->name);
data->dir = NULL;
data->name = NULL;
data->result = result;
}
static void create_file(char const* parent_dir, char const* name)
{
char* const path = tr_buildPath(parent_dir, name, NULL);
libtest_create_file_with_string_contents(path, "");
tr_free(path);
}
static void create_dir(char const* parent_dir, char const* name)
{
char* const path = tr_buildPath(parent_dir, name, NULL);
tr_sys_dir_create(path, 0, 0700, NULL);
tr_free(path);
}
static tr_watchdir_t create_watchdir(char const* path, tr_watchdir_cb callback, void* callback_user_data,
struct event_base* event_base)
{
#ifdef WATCHDIR_TEST_FORCE_GENERIC
bool const force_generic = true;
#else
bool const force_generic = false;
#endif
return tr_watchdir_new(path, callback, callback_user_data, event_base, force_generic);
}
/***
****
***/
static int test_construct(void)
{
char* const test_dir = libtest_sandbox_create();
tr_watchdir_t wd;
ev_base = event_base_new();
wd = create_watchdir(test_dir, &callback, NULL, ev_base);
check_ptr(wd, !=, NULL);
check(tr_sys_path_is_same(test_dir, tr_watchdir_get_path(wd), NULL));
process_events();
tr_watchdir_free(wd);
event_base_free(ev_base);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_initial_scan(void)
{
char* const test_dir = libtest_sandbox_create();
ev_base = event_base_new();
/* Speed up generic implementation */
tr_watchdir_generic_interval = ONE_HUNDRED_MSEC;
{
callback_data wd_data = CB_DATA_STATIC_INIT;
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
tr_watchdir_t wd = create_watchdir(test_dir, &callback, &wd_data, ev_base);
check_ptr(wd, !=, NULL);
process_events();
check_ptr(wd_data.dir, ==, NULL);
check_ptr(wd_data.name, ==, NULL);
tr_watchdir_free(wd);
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
}
create_file(test_dir, "test");
{
callback_data wd_data = CB_DATA_STATIC_INIT;
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
tr_watchdir_t wd = create_watchdir(test_dir, &callback, &wd_data, ev_base);
check_ptr(wd, !=, NULL);
process_events();
check_ptr(wd_data.dir, ==, wd);
check_str(wd_data.name, ==, "test");
tr_watchdir_free(wd);
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
}
event_base_free(ev_base);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_watch(void)
{
char* const test_dir = libtest_sandbox_create();
callback_data wd_data = CB_DATA_STATIC_INIT;
tr_watchdir_t wd;
ev_base = event_base_new();
/* Speed up generic implementation */
tr_watchdir_generic_interval = ONE_HUNDRED_MSEC;
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
wd = create_watchdir(test_dir, &callback, &wd_data, ev_base);
check_ptr(wd, !=, NULL);
process_events();
check_ptr(wd_data.dir, ==, NULL);
check_ptr(wd_data.name, ==, NULL);
create_file(test_dir, "test");
process_events();
check_ptr(wd_data.dir, ==, wd);
check_str(wd_data.name, ==, "test");
reset_callback_data(&wd_data, TR_WATCHDIR_IGNORE);
create_file(test_dir, "test2");
process_events();
check_ptr(wd_data.dir, ==, wd);
check_str(wd_data.name, ==, "test2");
reset_callback_data(&wd_data, TR_WATCHDIR_IGNORE);
create_dir(test_dir, "test3");
process_events();
check_ptr(wd_data.dir, ==, NULL);
check_ptr(wd_data.name, ==, NULL);
tr_watchdir_free(wd);
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
event_base_free(ev_base);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_watch_two_dirs(void)
{
char* const test_dir = libtest_sandbox_create();
char* const dir1 = tr_buildPath(test_dir, "a", NULL);
char* const dir2 = tr_buildPath(test_dir, "b", NULL);
callback_data wd1_data = CB_DATA_STATIC_INIT;
callback_data wd2_data = CB_DATA_STATIC_INIT;
tr_watchdir_t wd1;
tr_watchdir_t wd2;
ev_base = event_base_new();
/* Speed up generic implementation */
tr_watchdir_generic_interval = ONE_HUNDRED_MSEC;
create_dir(dir1, NULL);
create_dir(dir2, NULL);
reset_callback_data(&wd1_data, TR_WATCHDIR_ACCEPT);
wd1 = create_watchdir(dir1, &callback, &wd1_data, ev_base);
check_ptr(wd1, !=, NULL);
reset_callback_data(&wd2_data, TR_WATCHDIR_ACCEPT);
wd2 = create_watchdir(dir2, &callback, &wd2_data, ev_base);
check_ptr(wd2, !=, NULL);
process_events();
check_ptr(wd1_data.dir, ==, NULL);
check_ptr(wd1_data.name, ==, NULL);
check_ptr(wd2_data.dir, ==, NULL);
check_ptr(wd2_data.name, ==, NULL);
create_file(dir1, "test");
process_events();
check_ptr(wd1_data.dir, ==, wd1);
check_str(wd1_data.name, ==, "test");
check_ptr(wd2_data.dir, ==, NULL);
check_ptr(wd2_data.name, ==, NULL);
reset_callback_data(&wd1_data, TR_WATCHDIR_ACCEPT);
reset_callback_data(&wd2_data, TR_WATCHDIR_ACCEPT);
create_file(dir2, "test2");
process_events();
check_ptr(wd1_data.dir, ==, NULL);
check_ptr(wd1_data.name, ==, NULL);
check_ptr(wd2_data.dir, ==, wd2);
check_str(wd2_data.name, ==, "test2");
reset_callback_data(&wd1_data, TR_WATCHDIR_IGNORE);
reset_callback_data(&wd2_data, TR_WATCHDIR_IGNORE);
create_file(dir1, "test3");
create_file(dir2, "test4");
process_events();
check_ptr(wd1_data.dir, ==, wd1);
check_str(wd1_data.name, ==, "test3");
check_ptr(wd2_data.dir, ==, wd2);
check_str(wd2_data.name, ==, "test4");
reset_callback_data(&wd1_data, TR_WATCHDIR_ACCEPT);
reset_callback_data(&wd2_data, TR_WATCHDIR_ACCEPT);
create_file(dir1, "test5");
create_dir(dir2, "test5");
process_events();
check_ptr(wd1_data.dir, ==, wd1);
check_str(wd1_data.name, ==, "test5");
check_ptr(wd2_data.dir, ==, NULL);
check_ptr(wd2_data.name, ==, NULL);
reset_callback_data(&wd1_data, TR_WATCHDIR_ACCEPT);
reset_callback_data(&wd2_data, TR_WATCHDIR_ACCEPT);
create_dir(dir1, "test6");
create_file(dir2, "test6");
process_events();
check_ptr(wd1_data.dir, ==, NULL);
check_ptr(wd1_data.name, ==, NULL);
check_ptr(wd2_data.dir, ==, wd2);
check_str(wd2_data.name, ==, "test6");
reset_callback_data(&wd1_data, TR_WATCHDIR_ACCEPT);
reset_callback_data(&wd2_data, TR_WATCHDIR_ACCEPT);
create_dir(dir1, "test7");
create_dir(dir2, "test7");
process_events();
check_ptr(wd1_data.dir, ==, NULL);
check_ptr(wd1_data.name, ==, NULL);
check_ptr(wd2_data.dir, ==, NULL);
check_ptr(wd2_data.name, ==, NULL);
tr_watchdir_free(wd2);
reset_callback_data(&wd2_data, TR_WATCHDIR_ACCEPT);
tr_watchdir_free(wd1);
reset_callback_data(&wd1_data, TR_WATCHDIR_ACCEPT);
event_base_free(ev_base);
tr_free(dir2);
tr_free(dir1);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
static int test_retry(void)
{
char* const test_dir = libtest_sandbox_create();
callback_data wd_data = CB_DATA_STATIC_INIT;
tr_watchdir_t wd;
ev_base = event_base_new();
/* Speed up generic implementation */
tr_watchdir_generic_interval = ONE_HUNDRED_MSEC;
/* Tune retry logic */
tr_watchdir_retry_limit = 10;
tr_watchdir_retry_start_interval = FIFTY_MSEC;
tr_watchdir_retry_max_interval = tr_watchdir_retry_start_interval;
reset_callback_data(&wd_data, TR_WATCHDIR_RETRY);
wd = create_watchdir(test_dir, &callback, &wd_data, ev_base);
check_ptr(wd, !=, NULL);
process_events();
check_ptr(wd_data.dir, ==, NULL);
check_ptr(wd_data.name, ==, NULL);
create_file(test_dir, "test");
process_events();
check_ptr(wd_data.dir, ==, NULL);
check_ptr(wd_data.name, ==, NULL);
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
process_events();
check_ptr(wd_data.dir, ==, wd);
check_str(wd_data.name, ==, "test");
tr_watchdir_free(wd);
reset_callback_data(&wd_data, TR_WATCHDIR_ACCEPT);
event_base_free(ev_base);
libtest_sandbox_destroy(test_dir);
tr_free(test_dir);
return 0;
}
/***
****
***/
int main(void)
{
testFunc const tests[] =
{
test_construct,
test_initial_scan,
test_watch,
test_watch_two_dirs,
test_retry
};
tr_net_init();
return runTests(tests, NUM_TESTS(tests));
}

Some files were not shown because too many files have changed in this diff Show More