Ryan Tharp 6 years ago
commit 9f33edeed0

@ -19,7 +19,7 @@ else()
CHECK_CXX_COMPILER_FLAG("-std=c++17" COMPILER_SUPPORTS_CXX17)
endif()
option(HAVE_CXX17_FILESYSTEM "Enable if your C++ compiler and runtime library implements std::[experimental::]filesystem" OFF)
option(HAVE_CXX17_FILESYSTEM "Disable if your C++ compiler and runtime library lacks std::[experimental::]filesystem" ON)
if(COMPILER_SUPPORTS_CXX11 AND NOT HAVE_CXX17_FILESYSTEM)
add_cxxflags("-std=c++11")
@ -34,6 +34,8 @@ else()
message(ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++11 or C++17 support. Please use a different C++ compiler.")
endif()
add_cxxflags("-fpermissive")
if(DEBIAN)
add_definitions(-DDEBIAN)
endif()
@ -144,7 +146,14 @@ else()
)
endif()
set(LIBS ${SODIUM_LIB} ${THREAD_LIB})
if(JEMALLOC)
set(MALLOC_LIB jemalloc)
endif()
set(LIBS ${SODIUM_LIB} ${THREAD_LIB} ${MALLOC_LIB})
if(HAVE_CXX17_FILESYSTEM)
set(LIBS ${LIBS} stdc++fs)
endif()
set(LIB lokinet)
set(SHARED_LIB ${LIB})
@ -155,7 +164,8 @@ set(TT_ROOT vendor/libtuntap-master)
add_definitions(-D${CMAKE_SYSTEM_NAME})
if (UNIX)
add_definitions(-DUNIX)
add_definitions(-DUNIX)
add_definitions(-DPOSIX)
endif()
if(UNIX)
@ -179,6 +189,7 @@ if(UNIX)
elseif(WIN32 OR MINGW)
set(LIBTUNTAP_IMPL ${TT_ROOT}/tuntap-windows.c)
add_definitions(-DWIN32_LEAN_AND_MEAN)
add_definitions(-DWIN32)
else()
message(FATAL_ERROR "What operating system _are_ you building on/for?")
endif(UNIX)
@ -189,7 +200,7 @@ set(LIBTUNTAP_SRC_BASE
${TT_ROOT}/tuntap_log.cpp
${LIBTUNTAP_IMPL})
if (UNIX)
set(LIBTUNTAP_SRC
set(LIBTUNTAP_SRC
${TT_ROOT}/tuntap-unix.c
${LIBTUNTAP_SRC_BASE})
endif()
@ -250,7 +261,7 @@ set(LIB_PLATFORM_SRC
${ANDROID_PLATFORM_SRC}
# process isolation implementation
${ISOLATE_PROC_SRC}
# tun
# tun
${LIBTUNTAP_SRC}
# win32 inline procs
llarp/win32_inet.c
@ -305,7 +316,24 @@ set(NTRU_SRC
crypto/libntrup/src/ntru.cpp
)
set(LIB_SRC
set(UTP_SRC
libutp/utp_callbacks.cpp
libutp/utp_utils.cpp
libutp/utp_internal.cpp
libutp/utp_api.cpp
libutp/utp_packedsockaddr.cpp
libutp/utp_hash.cpp
)
if(WIN32)
set(UTP_SRC ${UTP_SRC} libutp/libutp_inet_ntop.cpp)
endif()
set(LIB_SRC
${UTP_SRC}
${NTRU_SRC}
llarp/address_info.cpp
llarp/bencode.cpp
@ -331,7 +359,6 @@ set(LIB_SRC
llarp/pathbuilder.cpp
llarp/pathset.cpp
llarp/proofofwork.cpp
llarp/relay_ack.cpp
llarp/relay_commit.cpp
llarp/relay_up_down.cpp
llarp/router_contact.cpp
@ -346,16 +373,11 @@ set(LIB_SRC
llarp/dht/find_router.cpp
llarp/dht/got_intro.cpp
llarp/dht/got_router.cpp
llarp/dht/search_job.cpp
llarp/dht/publish_intro.cpp
llarp/handlers/tun.cpp
llarp/iwp/frame_header.cpp
llarp/iwp/frame_state.cpp
llarp/iwp/session.cpp
llarp/iwp/server.cpp
llarp/iwp/transit_message.cpp
llarp/iwp/xmit.cpp
llarp/link/encoder.cpp
llarp/link/curvecp.cpp
llarp/link/server.cpp
llarp/link/utp.cpp
llarp/routing/dht_message.cpp
llarp/routing/message_parser.cpp
llarp/routing/path_confirm.cpp
@ -371,6 +393,10 @@ set(LIB_SRC
)
set(RC_SRC
daemon/rcutil.cpp
)
set(DNS_SRC
llarp/dns.cpp
llarp/dns_iptracker.cpp
@ -399,7 +425,7 @@ set(CLIENT_SRC
client/main.cpp
)
set(ALL_SRC ${CLIENT_SRC} daemon/rcutil.cpp ${EXE_SRC} ${DNS_SRC} ${LIB_PLATFORM_SRC} ${LIB_SRC} ${TEST_SRC} ${CPP_BACKPORT_SRC})
set(ALL_SRC ${CLIENT_SRC} ${RC_SRC} ${EXE_SRC} ${DNS_SRC} ${LIB_PLATFORM_SRC} ${LIB_SRC} ${TEST_SRC} ${CPP_BACKPORT_SRC})
foreach(F ${ALL_SRC})
set_source_files_properties(${F} PROPERTIES COMPILE_FLAGS -DLOG_TAG=\\\"${F}\\\")
@ -408,11 +434,15 @@ endforeach(F)
set(LIB lokinet)
set(SHARED_LIB ${LIB})
set(STATIC_LIB ${LIB}-static)
set(BACKPORT_LIB ${LIB}-backport)
set(PLATFORM_LIB ${LIB}-platform)
set(ANDROID_LIB ${LIB}android)
# TODO: exclude this from includes and expose stuff properly for rcutil
include_directories(llarp)
include_directories(include)
include_directories(vendor/cppbackport-master/lib)
# Neuro Linux box hack:
include_directories(/usr/local/include)
include_directories(${sodium_INCLUDE_DIR})
@ -421,15 +451,19 @@ include_directories(contrib/msc/include)
link_directories(contrib/msc/lib)
endif()
set(RC_EXE rcutil)
set(DNS_EXE dns)
if(SHADOW)
add_shadow_plugin(shadow-plugin-${SHARED_LIB} ${EXE_SRC} ${LIB_SRC} ${LIB_PLATFORM_SRC} ${CPP_BACKPORT_SRC})
target_link_libraries(shadow-plugin-${SHARED_LIB} ${LIBS})
install(TARGETS shadow-plugin-${SHARED_LIB} DESTINATION plugins)
else()
add_executable(rcutil daemon/rcutil.cpp)
add_executable(${RC_EXE} ${RC_SRC})
add_executable(${EXE} ${EXE_SRC})
add_executable(${CLIENT_EXE} ${CLIENT_SRC})
add_executable(dns ${DNS_SRC})
add_executable(${DNS_EXE} ${DNS_SRC})
if(NOT WIN32)
@ -441,57 +475,57 @@ else()
if(WITH_STATIC)
add_library(${STATIC_LIB} STATIC ${LIB_SRC})
if(NOT HAVE_CXX17_FILESYSTEM)
add_library(backport-static STATIC ${CPP_BACKPORT_SRC})
add_library(${BACKPORT_LIB} STATIC ${CPP_BACKPORT_SRC})
endif(NOT HAVE_CXX17_FILESYSTEM)
add_library(llarpplatform-static STATIC ${LIB_PLATFORM_SRC})
target_link_libraries(llarpplatform-static ${THREAD_LIB})
add_library(${PLATFORM_LIB} STATIC ${LIB_PLATFORM_SRC})
target_link_libraries(${PLATFORM_LIB} ${THREAD_LIB})
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
target_link_libraries(llarpplatform-static -lcap)
target_link_libraries(${PLATFORM_LIB} -lcap)
endif()
if(NOT HAVE_CXX17_FILESYSTEM)
target_link_libraries(${STATIC_LIB} ${LIBS} backport-static llarpplatform-static)
target_link_libraries(${STATIC_LIB} ${LIBS} ${PLATFORM_LIB} ${BACKPORT_LIB})
else()
target_link_libraries(${STATIC_LIB} ${LIBS} llarpplatform-static)
target_link_libraries(${STATIC_LIB} ${LIBS} ${PLATFORM_LIB})
endif(NOT HAVE_CXX17_FILESYSTEM)
if(NOT WITH_SHARED)
if(NOT HAVE_CXX17_FILESYSTEM)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static)
target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB})
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB})
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB})
if (MINGW)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs iphlpapi)
target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 stdc++fs iphlpapi)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
elseif(WIN32)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 iphlpapi)
target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} backport-static llarpplatform-static ws2_32 iphlpapi)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${BACKPORT_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
endif(MINGW)
else()
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static)
target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB})
if (MINGW)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs iphlpapi)
target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 stdc++fs iphlpapi)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 stdc++fs iphlpapi)
elseif(WIN32)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 iphlpapi)
target_link_libraries(rcutil ${STATIC_LINK_LIBS} ${STATIC_LIB} llarpplatform-static ws2_32 iphlpapi)
target_link_libraries(${EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${CLIENT_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
target_link_libraries(${RC_EXE} ${STATIC_LINK_LIBS} ${STATIC_LIB} ${PLATFORM_LIB} ws2_32 iphlpapi)
endif(MINGW)
endif(NOT HAVE_CXX17_FILESYSTEM)
if (MINGW)
target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB} ws2_32 stdc++fs iphlpapi)
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ${THREAD_LIB} ws2_32 stdc++fs iphlpapi)
elseif(WIN32)
target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB} ws2_32 iphlpapi)
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ${THREAD_LIB} ws2_32 iphlpapi)
endif(MINGW)
target_link_libraries(dns ${STATIC_LIB} llarpplatform-static ${THREAD_LIB})
target_link_libraries(${DNS_EXE} ${STATIC_LIB} ${PLATFORM_LIB} ${THREAD_LIB})
endif(NOT WITH_SHARED)
endif(WITH_STATIC)
if(ANDROID)
add_library(lokinetandroid SHARED jni/lokinet_android.cpp)
target_link_libraries(lokinetandroid ${STATIC_LIB} ${LIBS} log)
add_library(${ANDROID_LIB} SHARED jni/lokinet_android.cpp)
target_link_libraries(${ANDROID_LIB} ${STATIC_LIB} ${LIBS} log)
endif()
if(WITH_SHARED)
@ -506,7 +540,7 @@ else()
endif(MINGW)
target_link_libraries(${SHARED_LIB} ${LIBS} ${THREAD_LIB})
target_link_libraries(${EXE} ${SHARED_LIB})
target_link_libraries(rcutil ${SHARED_LIB})
target_link_libraries(dns ${SHARED_LIB} ${THREAD_LIB})
target_link_libraries(${RC_EXE} ${SHARED_LIB})
target_link_libraries(${DNS_EXE} ${SHARED_LIB} ${THREAD_LIB})
endif(WITH_SHARED)
endif(SHADOW)

@ -43,7 +43,7 @@ clean:
rm -f *.a *.so
debug-configure:
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DTUNTAP=ON
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DTUNTAP=ON
release-configure: clean
cmake -GNinja -DSTATIC_LINK=ON -DCMAKE_BUILD_TYPE=Release -DRELEASE_MOTTO="$(shell cat motto.txt)" -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX) -DTUNTAP=ON

@ -18,6 +18,7 @@ def clientNodeName(id): return 'client-node-%03d' % id
def main():
ap = AP()
ap.add_argument('--valgrind', type=bool, default=False)
ap.add_argument('--dir', type=str, default='testnet_tmp')
ap.add_argument('--svc', type=int, default=20,
help='number of service nodes')
@ -31,6 +32,11 @@ def main():
args = ap.parse_args()
if args.valgrind:
exe = 'valgrind {}'.format(args.bin)
else:
exe = args.bin
basedir = os.path.abspath(args.dir)
for nodeid in range(args.svc):
@ -47,12 +53,13 @@ def main():
'dir': 'netdb'
}
config['connect'] = {}
for otherid in range(args.svc):
if otherid != nodeid:
name = svcNodeName(otherid)
config['connect'][name] = os.path.join(
basedir, name, 'rc.signed')
for otherid in range(args.connect):
otherid = (nodeid + otherid) % args.svc
name = svcNodeName(otherid)
config['connect'][name] = os.path.join(
basedir, name, 'rc.signed')
d = os.path.join(args.dir, svcNodeName(nodeid))
if not os.path.exists(d):
os.mkdir(d)
@ -106,7 +113,7 @@ stdout_logfile={}/svc-node-%(process_num)03d-log.txt
stdout_logfile_maxbytes=0
process_name = svc-node-%(process_num)03d
numprocs = {}
'''.format(os.path.join(args.dir, 'svc-node-%(process_num)03d'), args.bin, args.dir, args.svc))
'''.format(os.path.join(args.dir, 'svc-node-%(process_num)03d'), exe, args.dir, args.svc))
f.write('''[program:client-node]
directory = {}
command = {}
@ -117,7 +124,7 @@ stdout_logfile={}/client-node-%(process_num)03d-log.txt
stdout_logfile_maxbytes=0
process_name = client-node-%(process_num)03d
numprocs = {}
'''.format(os.path.join(args.dir, 'client-node-%(process_num)03d'),args.bin, args.dir, args.clients))
'''.format(os.path.join(args.dir, 'client-node-%(process_num)03d'), exe, args.dir, args.clients))
f.write('[supervisord]\ndirectory=.\n')

@ -186,7 +186,9 @@ hookChecker(std::string name, const struct sockaddr *from,
job->iterative = true;
job->found = false;
job->hook = &HandleDHTLocate;
llarp_rc_new(&job->result);
// Disable for RC refactor
//llarp_rc_new(&job->result);
memcpy(job->target, binaryPK, PUBKEYSIZE); // set job's target
// llarp_dht_lookup_router(ctx->router->dht, job);

@ -3,7 +3,7 @@
#include <signal.h>
#include "logger.hpp"
#include <llarp/router_contact.h>
#include <llarp/router_contact.hpp>
#include <llarp/time.h>
#include <fstream>
@ -30,39 +30,14 @@ handle_signal(int sig)
#define TESTNET 0
#endif
bool
printNode(struct llarp_nodedb_iter *iter)
{
char ftmp[68] = {0};
const char *hexname =
llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(iter->rc->pubkey, ftmp);
printf("[%zu]=>[%s]\n", iter->index, hexname);
return false;
}
bool
aiLister(struct llarp_ai_list_iter *request, struct llarp_ai *addr)
{
static size_t count = 0;
count++;
llarp::Addr a(*addr);
std::cout << "AddressInfo " << count << ": " << a << std::endl;
return true;
}
void
displayRC(llarp_rc *rc)
displayRC(const llarp::RouterContact &rc)
{
char ftmp[68] = {0};
const char *hexPubSigKey =
llarp::HexEncode< llarp::PubKey, decltype(ftmp) >(rc->pubkey, ftmp);
printf("PubSigKey [%s]\n", hexPubSigKey);
struct llarp_ai_list_iter iter;
// iter.user
iter.visit = &aiLister;
llarp_ai_list_iterate(rc->addrs, &iter);
std::cout << rc.pubkey << std::endl;
for(const auto &addr : rc.addrs)
{
std::cout << "AddressInfo: " << addr << std::endl;
}
}
// fwd declr
@ -75,7 +50,7 @@ HandleDHTLocate(llarp_router_lookup_job *job)
if(job->found)
{
// save to nodedb?
displayRC(&job->result);
displayRC(job->result);
}
// shutdown router
@ -144,6 +119,8 @@ main(int argc, char *argv[])
conffname = defaultConfName;
char *rcfname = nullptr;
char *nodesdir = nullptr;
llarp::RouterContact rc;
while(1)
{
static struct option long_options[] = {
@ -266,95 +243,106 @@ main(int argc, char *argv[])
}
}
#undef MIN
if(!haveRequiredOptions)
{
llarp::LogError("Parameters dont all have their required parameters.\n");
return 0;
}
printf("parsed options\n");
if(!genMode && !updMode && !listMode && !importMode && !exportMode
&& !locateMode && !localMode && !readMode && !findMode && !toB32Mode
&& !toHexMode)
{
llarp::LogError(
"I don't know what to do, no generate or update parameter\n");
return 0;
}
if(!haveRequiredOptions)
{
llarp::LogError("Parameters dont all have their required parameters.\n");
return 0;
}
//printf("parsed options\n");
if(!genMode && !updMode && !listMode && !importMode && !exportMode
&& !locateMode && !localMode && !readMode && !findMode && !toB32Mode
&& !toHexMode)
{
llarp::LogError(
"I don't know what to do, no generate or update parameter\n");
return 1;
}
ctx = llarp_main_init(conffname, !TESTNET);
if(!ctx)
{
llarp::LogError("Cant set up context");
return 1;
}
signal(SIGINT, handle_signal);
llarp::RouterContact tmp;
ctx = llarp_main_init(conffname, !TESTNET);
if(!ctx)
{
llarp::LogError("Cant set up context");
return 0;
}
signal(SIGINT, handle_signal);
llarp_rc tmp;
if(verifyMode)
{
llarp_crypto crypto;
llarp_crypto_libsodium_init(&crypto);
llarp_rc rc;
if(!llarp_rc_read(rcfname, &rc))
llarp_crypto_init(&crypto);
if(!rc.Read(rcfname))
{
std::cout << "failed to read " << rcfname << std::endl;
return 1;
}
if(!llarp_rc_verify_sig(&crypto, &rc))
if(!rc.VerifySignature(&crypto))
{
std::cout << rcfname << " has invalid signature" << std::endl;
return 1;
}
if(!llarp_rc_is_public_router(&rc))
if(!rc.IsPublicRouter())
{
std::cout << rcfname << " is not a public router";
if(llarp_ai_list_size(rc.addrs) == 0)
if(rc.addrs.size() == 0)
{
std::cout << " because it has no public addresses";
}
std::cout << std::endl;
return 1;
}
llarp::PubKey pubkey(rc.pubkey);
llarp::PubKey enckey(rc.enckey);
std::cout << "router identity and dht routing key: " << pubkey << std::endl;
std::cout << "router encryption key: " << enckey << std::endl;
std::cout << "router identity and dht routing key: " << rc.pubkey
<< std::endl;
std::cout << "router encryption key: " << rc.enckey << std::endl;
if(rc.HasNick())
std::cout << "router nickname: " << rc.Nick() << std::endl;
std::cout << "advertised addresses: ";
llarp_ai_list_iter a_itr;
a_itr.user = nullptr;
a_itr.visit = [](llarp_ai_list_iter *, llarp_ai *addrInfo) -> bool {
llarp::Addr addr(*addrInfo);
std::cout << addr << " ";
return true;
};
llarp_ai_list_iterate(rc.addrs, &a_itr);
std::cout << "advertised addresses: " << std::endl;
for(const auto &addr : rc.addrs)
{
std::cout << addr << std::endl;
}
std::cout << std::endl;
std::cout << "advertised exits: ";
if(llarp_xi_list_size(rc.exits))
if(rc.exits.size())
{
llarp_xi_list_iter e_itr;
e_itr.user = nullptr;
e_itr.visit = [](llarp_xi_list_iter *, llarp_xi *xi) -> bool {
std::cout << *xi << " ";
return true;
};
llarp_xi_list_iterate(rc.exits, &e_itr);
for(const auto &exit : rc.exits)
{
std::cout << exit << std::endl;
}
}
else
{
std::cout << "none";
}
std::cout << std::endl;
return 0;
}
// is this Neuro or Jeff's?
// this is the only one...
if(listMode)
{
llarp_crypto crypto;
llarp_crypto_init(&crypto);
auto nodedb = llarp_nodedb_new(&crypto);
llarp_nodedb_iter itr;
itr.visit = [](llarp_nodedb_iter *i) -> bool {
std::cout << i->rc->pubkey << std::endl;
return true;
};
if(llarp_nodedb_load_dir(nodedb, nodesdir) > 0)
llarp_nodedb_iterate_all(nodedb, itr);
llarp_nodedb_free(&nodedb);
return 0;
}
if(importMode)
{
if(rcfname == nullptr)
@ -363,7 +351,7 @@ main(int argc, char *argv[])
return 1;
}
llarp_crypto crypto;
llarp_crypto_libsodium_init(&crypto);
llarp_crypto_init(&crypto);
auto nodedb = llarp_nodedb_new(&crypto);
if(!llarp_nodedb_ensure_dir(nodesdir))
{
@ -372,46 +360,40 @@ main(int argc, char *argv[])
return 1;
}
llarp_nodedb_set_dir(nodedb, nodesdir);
llarp_rc rc;
if(!llarp_rc_read(rcfname, &rc))
if(!rc.Read(rcfname))
{
std::cout << "failed to read " << rcfname << " " << strerror(errno)
<< std::endl;
return 1;
}
if(!llarp_rc_verify_sig(&crypto, &rc))
if(!rc.VerifySignature(&crypto))
{
std::cout << rcfname << " has invalid signature" << std::endl;
return 1;
}
if(!llarp_nodedb_put_rc(nodedb, &rc))
if(!llarp_nodedb_put_rc(nodedb, rc))
{
std::cout << "failed to store " << strerror(errno) << std::endl;
return 1;
}
std::cout << "imported " << llarp::PubKey(rc.pubkey) << std::endl;
std::cout << "imported " << rc.pubkey << std::endl;
return 0;
}
if(genMode)
{
printf("Creating [%s]\n", rcfname);
// Jeff wanted tmp to be stack created
// do we still need to zero it out?
llarp_rc_clear(&tmp);
// if we zero it out then
// allocate fresh pointers that the bencoder can expect to be ready
tmp.addrs = llarp_ai_list_new();
tmp.exits = llarp_xi_list_new();
// set updated timestamp
tmp.last_updated = llarp_time_now_ms();
rc.last_updated = llarp_time_now_ms();
// load longterm identity
llarp_crypto crypt;
llarp_crypto_libsodium_init(&crypt);
llarp_crypto_init(&crypt);
// which is in daemon.ini config: router.encryption-privkey (defaults
// "encryption.key")
@ -419,59 +401,77 @@ main(int argc, char *argv[])
llarp::SecretKey encryption;
llarp_findOrCreateEncryption(&crypt, encryption_keyfile.string().c_str(),
&encryption);
encryption);
llarp_rc_set_pubenckey(&tmp, llarp::seckey_topublic(encryption));
rc.enckey = llarp::seckey_topublic(encryption);
// get identity public sig key
fs::path ident_keyfile = "identity.key";
byte_t identity[SECKEYSIZE];
llarp::SecretKey identity;
llarp_findOrCreateIdentity(&crypt, ident_keyfile.string().c_str(),
identity);
llarp_rc_set_pubsigkey(&tmp, llarp::seckey_topublic(identity));
rc.pubkey = llarp::seckey_topublic(identity);
// this causes a segfault
llarp_rc_sign(&crypt, identity, &tmp);
if(!rc.Sign(&crypt, identity))
{
std::cout << "failed to sign" << std::endl;
return 1;
}
// set filename
fs::path our_rc_file = rcfname;
// write file
llarp_rc_write(&tmp, our_rc_file.string().c_str());
rc.Write(our_rc_file.string().c_str());
//llarp_rc_write(&tmp, our_rc_file.string().c_str());
// release memory for tmp lists
llarp_rc_free(&tmp);
//llarp_rc_free(&tmp);
}
if(updMode)
{
printf("rcutil.cpp - Loading [%s]\n", rcfname);
llarp_rc rc;
llarp_rc_clear(&rc);
llarp_rc_read(rcfname, &rc);
llarp::RouterContact tmp;
//llarp_rc_clear(&rc);
rc.Clear();
// FIXME: new rc api
//llarp_rc_read(rcfname, &rc);
// set updated timestamp
rc.last_updated = llarp_time_now_ms();
// load longterm identity
llarp_crypto crypt;
llarp_crypto_libsodium_init(&crypt);
// no longer used?
//llarp_crypto_libsodium_init(&crypt);
fs::path ident_keyfile = "identity.key";
byte_t identity[SECKEYSIZE];
llarp_findOrCreateIdentity(&crypt, ident_keyfile.string().c_str(),
identity);
// FIXME: update RC API
// get identity public key
const uint8_t *pubkey = llarp::seckey_topublic(identity);
llarp_rc_set_pubsigkey(&rc, pubkey);
llarp_rc_sign(&crypt, identity, &rc);
//const uint8_t *pubkey = llarp::seckey_topublic(identity);
// FIXME: update RC API
//llarp_rc_set_pubsigkey(&rc, pubkey);
// // FIXME: update RC API
//llarp_rc_sign(&crypt, identity, &rc);
// set filename
fs::path our_rc_file_out = "update_debug.rc";
// write file
llarp_rc_write(&tmp, our_rc_file_out.string().c_str());
// FIXME: update RC API
//rc.Write(our_rc_file.string().c_str());
//llarp_rc_write(&tmp, our_rc_file_out.string().c_str());
}
if(listMode)
{
llarp_crypto crypto;
llarp_crypto_libsodium_init(&crypto);
// no longer used?
//llarp_crypto_libsodium_init(&crypto);
auto nodedb = llarp_nodedb_new(&crypto);
llarp_nodedb_iter itr;
itr.visit = [](llarp_nodedb_iter *i) -> bool {
@ -492,7 +492,7 @@ main(int argc, char *argv[])
llarp::HexDecode(rcfname, binaryPK.data());
llarp::LogInfo("Looking for binary: ", binaryPK);
struct llarp_rc *rc = llarp_main_getDatabase(ctx, binaryPK.data());
llarp::RouterContact *rc = llarp_main_getDatabase(ctx, binaryPK.data());
if(!rc)
{
llarp::LogError("Can't load RC from database");
@ -500,7 +500,9 @@ main(int argc, char *argv[])
std::string filename(rcfname);
filename.append(".signed");
llarp::LogInfo("Writing out: ", filename);
llarp_rc_write(rc, filename.c_str());
// FIXME: update RC API
//rc.Write(our_rc_file.string().c_str());
//llarp_rc_write(rc, filename.c_str());
}
if(locateMode)
{
@ -515,7 +517,7 @@ main(int argc, char *argv[])
job->iterative = true;
job->found = false;
job->hook = &HandleDHTLocate;
llarp_rc_new(&job->result);
//llarp_rc_new(&job->result);
memcpy(job->target, binaryPK, PUBKEYSIZE); // set job's target
// create query DHT request
@ -552,7 +554,8 @@ main(int argc, char *argv[])
llarp::LogInfo("Addr ", addr);
llarp::routing::DHTMessage *msg = new llarp::routing::DHTMessage();
// uint64_t txid, const llarp::service::Address& addr
msg->M.push_back(new llarp::dht::FindIntroMessage(tag, 1));
// FIXME: new API?
//msg->M.push_back(new llarp::dht::FindIntroMessage(tag, 1));
// I guess we may need a router to get any replies
llarp::LogInfo("Processing");
@ -561,16 +564,15 @@ main(int argc, char *argv[])
}
if(localMode)
{
llarp_rc *rc = llarp_main_getLocalRC(ctx);
displayRC(rc);
// FIXME: update llarp_main_getLocalRC
//llarp::RouterContact *rc = llarp_main_getLocalRC(ctx);
//displayRC(rc);
}
if(readMode)
{
llarp_rc result;
llarp_rc_clear(&result);
llarp_rc_read(rcfname, &result);
displayRC(&result);
if(rc.Read(rcfname))
displayRC(rc);
}
if(toB32Mode)
{
llarp::LogInfo("Converting hex string ", rcfname);
@ -596,5 +598,5 @@ main(int argc, char *argv[])
}
// it's a unique_ptr, should clean up itself
// llarp_main_free(ctx);
return 1; // success
return 0; // success
}

@ -106,6 +106,12 @@ sent in reply to FRCM only
V: 0
}
* send a GRCM with R to requesters in all linked transactions
* terminate transaction with id T
in response to an exploritory FRCM if the target router is not found the form
{
A: "S",
N: [list, of, router, publickeys, near, target],
R: [],
T: transaction_id_uint64,
V: 0
}

@ -4,8 +4,6 @@
#include <llarp/ev.h>
#include <llarp/logic.h>
#include <llarp/mem.h>
#include <llarp/nodedb.h>
#include <llarp/router.h>
#include <llarp/version.h>
#ifdef __cplusplus
@ -46,10 +44,10 @@ extern "C"
/// put RC into nodeDB
bool
llarp_main_putDatabase(struct llarp_main *ptr, struct llarp_rc *rc);
llarp_main_putDatabase(struct llarp_main *ptr, struct llarp::RouterContact *rc);
/// get RC from nodeDB
struct llarp_rc *
llarp::RouterContact *
llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk);
// fwd declr
@ -83,7 +81,7 @@ extern "C"
uint16_t server_port, const char *upstream_host,
uint16_t upstream_port);
struct llarp_rc *
llarp::RouterContact *
llarp_main_getLocalRC(struct llarp_main *ptr);
void

@ -6,6 +6,7 @@
#include <llarp/threading.hpp>
#include <string>
#include <vector>
#include <llarp/crypto.h>
namespace llarp
{
@ -39,9 +40,9 @@ namespace llarp
IterateDatabase(struct llarp_nodedb_iter i);
bool
PutDatabase(struct llarp_rc *rc);
PutDatabase(struct llarp::RouterContact *rc);
struct llarp_rc *
llarp::RouterContact *
GetDatabase(const byte_t *pk);
int

@ -0,0 +1,80 @@
#ifndef LLARP_AI_HPP
#define LLARP_AI_HPP
#include <llarp/mem.h>
#include <llarp/net.h>
#include <stdbool.h>
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <string>
/**
* address_info.hpp
*
* utilities for handling addresses on the llarp network
*/
/// address information model
namespace llarp
{
struct AddressInfo : public IBEncodeMessage
{
uint16_t rank;
std::string dialect;
llarp::PubKey pubkey;
struct in6_addr ip;
uint16_t port;
AddressInfo() : IBEncodeMessage()
{
}
AddressInfo(const AddressInfo& other)
: IBEncodeMessage()
, rank(other.rank)
, dialect(other.dialect)
, pubkey(other.pubkey)
{
port = other.port;
version = other.version;
memcpy(ip.s6_addr, other.ip.s6_addr, 16);
}
~AddressInfo();
AddressInfo&
operator=(const AddressInfo& other);
bool
operator==(const AddressInfo& other) const;
bool
operator<(const AddressInfo& other) const;
bool
BEncode(llarp_buffer_t* buf) const;
bool
DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf);
friend std::ostream&
operator<<(std::ostream& out, const AddressInfo& a)
{
char tmp[128] = {0};
inet_ntop(AF_INET6, &a.ip, tmp, sizeof(tmp));
return out << tmp << "." << std::to_string(a.port);
}
struct Hash
{
size_t
operator()(const AddressInfo& addr) const
{
return *addr.pubkey.data_l();
}
};
};
} // namespace llarp
#endif

@ -11,8 +11,8 @@
namespace llarp
{
/// aligned buffer, aligns to the nears 8 bytes
template < size_t sz, bool randomize = false >
/// aligned buffer, aligns to the nears Long_t
template < size_t sz, bool randomize = false, typename Long_t = uint64_t >
struct AlignedBuffer
{
AlignedBuffer()
@ -84,7 +84,7 @@ namespace llarp
operator^(const AlignedBuffer& other) const
{
AlignedBuffer< sz > ret;
for(size_t idx = 0; idx < sz / 8; ++idx)
for(size_t idx = 0; idx < sz / sizeof(Long_t); ++idx)
ret.l[idx] = l[idx] ^ other.l[idx];
return ret;
}
@ -92,7 +92,7 @@ namespace llarp
AlignedBuffer&
operator^=(const AlignedBuffer& other)
{
for(size_t idx = 0; idx < sz / 8; ++idx)
for(size_t idx = 0; idx < sz / sizeof(Long_t); ++idx)
l[idx] ^= other.l[idx];
return *this;
}
@ -146,13 +146,13 @@ namespace llarp
return &b[0];
}
uint64_t*
Long_t*
data_l()
{
return &l[0];
}
const uint64_t*
const Long_t*
data_l() const
{
return &l[0];
@ -182,9 +182,7 @@ namespace llarp
return false;
if(strbuf.sz != sz)
{
llarp::LogErrorTag("AlignedBuffer::BDecode",
"bdecode buffer size missmatch ", strbuf.sz,
"!=", sz);
llarp::LogError("bdecode buffer size missmatch ", strbuf.sz, "!=", sz);
return false;
}
memcpy(b, strbuf.base, sz);
@ -194,7 +192,7 @@ namespace llarp
struct Hash
{
size_t
operator()(const AlignedBuffer< sz >& buf) const
operator()(const AlignedBuffer& buf) const
{
return *buf.data_l();
}
@ -203,7 +201,7 @@ namespace llarp
protected:
union {
byte_t b[sz];
uint64_t l[(sz / 8) + (sz % 8)];
Long_t l[(sz / sizeof(Long_t)) + (sz % sizeof(Long_t))];
};
};

@ -6,6 +6,7 @@
#include <llarp/logger.hpp>
#include <llarp/mem.hpp>
#include <set>
#include <fstream>
namespace llarp
{
@ -38,6 +39,20 @@ namespace llarp
return bencode_write_bytestring(buf, k, 1) && bencode_write_uint64(buf, i);
}
template < typename List_t >
bool
BEncodeMaybeReadDictList(const char* k, List_t& item, bool& read,
llarp_buffer_t key, llarp_buffer_t* buf)
{
if(llarp_buffer_eq(key, k))
{
if(!BEncodeReadList(item, buf))
return false;
read = true;
}
return true;
}
template < typename Item_t >
bool
BEncodeMaybeReadDictEntry(const char* k, Item_t& item, bool& read,
@ -105,6 +120,43 @@ namespace llarp
return bencode_end(buf);
}
template < typename Array >
bool
BEncodeWriteDictArray(const char* k, const Array& array, llarp_buffer_t* buf)
{
if(!bencode_write_bytestring(buf, k, 1))
return false;
if(!bencode_start_list(buf))
return false;
for(size_t idx = 0; idx < array.size(); ++idx)
if(!array[idx].BEncode(buf))
return false;
return bencode_end(buf);
}
template < typename Array >
bool
BEncodeReadArray(Array& array, llarp_buffer_t* buf)
{
if(*buf->cur != 'l') // ensure is a list
return false;
buf->cur++;
size_t idx = 0;
while(llarp_buffer_size_left(*buf) && *buf->cur != 'e')
{
if(idx >= array.size())
return false;
if(!array[idx++].BDecode(buf))
return false;
}
if(*buf->cur != 'e') // make sure we're at a list end
return false;
buf->cur++;
return true;
}
template < typename Iter >
bool
BEncodeWriteList(Iter itr, Iter end, llarp_buffer_t* buf)
@ -188,15 +240,23 @@ namespace llarp
}
// TODO: check for shadowed values elsewhere
uint64_t version = 0;
uint64_t version = LLARP_PROTO_VERSION;
static bool
OnKey(dict_reader* r, llarp_buffer_t* k)
{
if(k)
return static_cast< IBEncodeMessage* >(r->user)->DecodeKey(*k,
r->buffer);
return true;
return static_cast< IBEncodeMessage* >(r->user)->HandleKey(k, r->buffer);
}
bool
HandleKey(llarp_buffer_t* k, llarp_buffer_t* val)
{
if(k == nullptr)
return true;
if(DecodeKey(*k, val))
return true;
llarp::LogError("unhandled key '", *k->cur, "'");
return false;
}
template < size_t bufsz, size_t align = 128 >
@ -210,6 +270,52 @@ namespace llarp
}
};
/// read entire file and decode its contents into t
template < typename T >
bool
BDecodeReadFile(const char* fpath, T& t)
{
byte_t* ptr = nullptr;
size_t sz = 0;
{
std::ifstream f;
f.open(fpath);
if(!f.is_open())
return false;
f.seekg(0, std::ios::end);
sz = f.tellg();
f.seekg(0, std::ios::beg);
ptr = new byte_t[sz];
f.read((char*)ptr, sz);
}
llarp_buffer_t buf = InitBuffer(ptr, sz);
auto result = t.BDecode(&buf);
if(!result)
DumpBuffer(buf);
delete[] ptr;
return result;
}
/// bencode and write to file
template < typename T, size_t bufsz >
bool
BEncodeWriteFile(const char* fpath, const T& t)
{
uint8_t tmp[bufsz] = {0};
auto buf = StackBuffer< decltype(tmp) >(tmp);
if(!t.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
{
std::ofstream f;
f.open(fpath);
if(!f.is_open())
return false;
f.write((char*)buf.base, buf.sz);
}
return true;
}
} // namespace llarp
#endif
#endif

@ -15,7 +15,7 @@
#include <cmath>
#include <functional>
#include <queue>
#include <array>
#include <string>
namespace llarp
@ -34,29 +34,11 @@ namespace llarp
{
}
};
template < typename T, typename GetTime >
struct CoDelCompareTime
{
bool
operator()(const T& left, const T& right) const
{
return GetTime()(left) < GetTime()(right);
}
};
template < typename T >
struct CoDelComparePriority
{
bool
operator()(const T& left, const T& right) const
{
return left < right;
}
};
template < typename T, typename GetTime, typename PutTime, typename Compare,
typename Mutex_t = util::Mutex, typename Lock_t = util::Lock,
llarp_time_t dropMs = 5, llarp_time_t initialIntervalMs = 100 >
llarp_time_t dropMs = 5, llarp_time_t initialIntervalMs = 100,
size_t MaxSize = 1024 >
struct CoDelQueue
{
CoDelQueue(const std::string& name) : m_name(name)
@ -67,26 +49,29 @@ namespace llarp
Size()
{
Lock_t lock(m_QueueMutex);
return m_Queue.size();
return m_QueueIdx;
}
template < typename... Args >
bool
EmplaceIf(std::function< bool(T*) > pred, Args&&... args)
EmplaceIf(std::function< bool(T&) > pred, Args&&... args)
{
T* ptr = new T(std::forward< Args >(args)...);
if(!pred(ptr))
{
delete ptr;
Lock_t lock(m_QueueMutex);
if(m_QueueIdx == MaxSize)
return false;
}
PutTime()(ptr);
T* t = &m_Queue[m_QueueIdx];
new(t) T(std::forward< Args >(args)...);
if(!pred(*t))
{
Lock_t lock(m_QueueMutex);
if(firstPut == 0)
firstPut = GetTime()(ptr);
m_Queue.push(ptr);
t->~T();
return false;
}
PutTime()(m_Queue[m_QueueIdx]);
if(firstPut == 0)
firstPut = GetTime()(m_Queue[m_QueueIdx]);
++m_QueueIdx;
return true;
}
@ -94,57 +79,63 @@ namespace llarp
void
Emplace(Args&&... args)
{
T* ptr = new T(std::forward< Args >(args)...);
PutTime()(ptr);
{
Lock_t lock(m_QueueMutex);
if(firstPut == 0)
firstPut = GetTime()(ptr);
m_Queue.push(ptr);
}
Lock_t lock(m_QueueMutex);
if(m_QueueIdx == MaxSize)
return;
T* t = &m_Queue[m_QueueIdx];
new(t) T(std::forward< Args >(args)...);
PutTime()(m_Queue[m_QueueIdx]);
if(firstPut == 0)
firstPut = GetTime()(m_Queue[m_QueueIdx]);
++m_QueueIdx;
}
template < typename Visit >
void
Put(T* ptr)
Process(Visit v)
{
PutTime()(ptr);
{
Lock_t lock(m_QueueMutex);
if(firstPut == 0)
firstPut = GetTime()(ptr);
m_Queue.push(ptr);
}
return Process(v, [](T&) -> bool { return false; });
}
/// visit returns true to discard entry otherwise the entry is
/// re quened
template < typename Visit >
template < typename Visit, typename Filter >
void
ProcessIf(Visit visitor)
Process(Visit visitor, Filter f)
{
llarp_time_t lowest = 0xFFFFFFFFFFFFFFFFUL;
// auto start = llarp_time_now_ms();
// llarp::LogInfo("CoDelQueue::Process - start at ", start);
Lock_t lock(m_QueueMutex);
auto start = firstPut;
Queue_t requeue;
while(m_Queue.size())
if(m_QueueIdx == 1)
{
visitor(m_Queue[0]);
T* t = &m_Queue[0];
t->~T();
m_QueueIdx = 0;
firstPut = 0;
return;
}
size_t idx = 0;
while(m_QueueIdx)
{
llarp::LogDebug("CoDelQueue::Process - queue has ", m_Queue.size());
T* item = m_Queue.top();
auto dlt = start - GetTime()(item);
llarp::LogDebug(m_name, " - queue has ", m_QueueIdx);
T* item = &m_Queue[idx++];
if(f(*item))
break;
--m_QueueIdx;
auto dlt = start - GetTime()(*item);
// llarp::LogInfo("CoDelQueue::Process - dlt ", dlt);
lowest = std::min(dlt, lowest);
if(m_Queue.size() == 1)
if(m_QueueIdx == 0)
{
// llarp::LogInfo("CoDelQueue::Process - single item: lowest ",
// lowest, " dropMs: ", dropMs);
if(lowest > dropMs)
{
item->~T();
nextTickInterval += initialIntervalMs / std::sqrt(++dropNum);
m_Queue.pop();
delete item;
break;
firstPut = 0;
return;
}
else
{
@ -152,40 +143,21 @@ namespace llarp
dropNum = 0;
}
}
// llarp::LogInfo("CoDelQueue::Process - passing");
if(visitor(item))
{
delete item;
}
else
{
requeue.push(item);
}
m_Queue.pop();
visitor(*item);
item->~T();
}
m_Queue = std::move(requeue);
firstPut = 0;
}
template < typename Func >
void
Process(Func visitor)
{
ProcessIf([visitor](T* t) -> bool {
visitor(t);
return true;
});
}
llarp_time_t firstPut = 0;
size_t dropNum = 0;
llarp_time_t nextTickInterval = initialIntervalMs;
Mutex_t m_QueueMutex;
typedef std::priority_queue< T*, std::vector< T* >, Compare > Queue_t;
Queue_t m_Queue;
size_t m_QueueIdx = 0;
T m_Queue[MaxSize];
std::string m_name;
};
} // namespace util
}; // namespace util
} // namespace util
} // namespace llarp
#endif

@ -57,7 +57,7 @@ typedef bool (*llarp_hmac_func)(byte_t *, llarp_buffer_t, const byte_t *);
/// S(sig, secretkey, body)
typedef bool (*llarp_sign_func)(byte_t *, const byte_t *, llarp_buffer_t);
/// V(sig, body, secretkey)
/// V(pubkey, body, sig)
typedef bool (*llarp_verify_func)(const byte_t *, llarp_buffer_t,
const byte_t *);
@ -100,9 +100,9 @@ struct llarp_crypto
bool (*pqe_encrypt)(byte_t *, byte_t *, const byte_t *);
};
/// set crypto function pointers to use libsodium
/// initialize crypto subsystem
void
llarp_crypto_libsodium_init(struct llarp_crypto *c);
llarp_crypto_init(struct llarp_crypto *c);
/// check for initialize crypto
bool

@ -65,11 +65,11 @@ struct iwp_async_intro
uint8_t *buf;
size_t sz;
/// nonce paramter
uint8_t *nonce;
uint8_t nonce[32];
/// remote public key
uint8_t *remote_pubkey;
uint8_t remote_pubkey[32];
/// local private key
uint8_t *secretkey;
uint8_t secretkey[64];
/// callback
iwp_intro_hook hook;
};
@ -184,26 +184,26 @@ struct iwp_async_frame
struct FramePutTime
{
void
operator()(iwp_async_frame *frame) const
operator()(iwp_async_frame &frame) const
{
frame->created = llarp_time_now_ms();
frame.created = llarp_time_now_ms();
}
};
struct FrameGetTime
{
llarp_time_t
operator()(const iwp_async_frame *frame) const
operator()(const iwp_async_frame &frame) const
{
return frame->created;
return frame.created;
}
};
struct FrameCompareTime
{
bool
operator()(const iwp_async_frame *left, const iwp_async_frame *right) const
operator()(const iwp_async_frame &left, const iwp_async_frame &right) const
{
return left->created < right->created;
return left.created < right.created;
}
};
#endif

@ -3,6 +3,8 @@
#include <llarp/buffer.h>
#include <llarp/router.h>
#include <llarp/crypto.hpp>
#include <llarp/router_contact.hpp>
/**
* dht.h
@ -24,6 +26,7 @@ llarp_dht_context_free(struct llarp_dht_context* dht);
void
llarp_dht_context_start(struct llarp_dht_context* ctx, const byte_t* key);
// remove this? dns needs it atm
struct llarp_router_lookup_job;
typedef void (*llarp_router_lookup_handler)(struct llarp_router_lookup_job*);
@ -34,22 +37,19 @@ struct llarp_router_lookup_job
void* user;
llarp_router_lookup_handler hook;
struct llarp_dht_context* dht;
byte_t target[PUBKEYSIZE];
//byte_t target[PUBKEYSIZE];
llarp::PubKey target;
bool found;
// make sure you initialize addr and exits
struct llarp_rc result;
llarp::RouterContact result;
bool iterative;
};
// end dns requirement
/// start allowing dht participation on a context
void
llarp_dht_allow_transit(struct llarp_dht_context* ctx);
/// put router as a dht peer
/// internal function do not use
void
__llarp_dht_put_peer(struct llarp_dht_context* ctx, struct llarp_rc* rc);
/// remove router from tracked dht peer list
/// internal function do not use
void

@ -19,7 +19,8 @@ namespace llarp
Bucket(const Key_t& us) : nodes(XorMetric(us)){};
bool
GetRandomNodeExcluding(Key_t& result, std::set< Key_t > exclude) const
GetRandomNodeExcluding(Key_t& result,
const std::set< Key_t >& exclude) const
{
std::vector< Key_t > candidates;
for(const auto& item : nodes)
@ -50,9 +51,52 @@ namespace llarp
return nodes.size() > 0;
}
bool
GetManyRandom(std::set< Key_t >& result, size_t N) const
{
if(nodes.size() < N)
return false;
if(nodes.size() == N)
{
for(const auto& node : nodes)
{
result.insert(node.first);
}
return true;
}
size_t expecting = N;
size_t sz = nodes.size();
while(N)
{
auto itr = nodes.begin();
std::advance(itr, llarp_randint() % sz);
if(result.insert(itr->first).second)
--N;
}
return result.size() == expecting;
}
bool
GetManyNearExcluding(const Key_t& target, std::set< Key_t >& result,
size_t N, const std::set< Key_t >& exclude) const
{
std::set< Key_t > s;
for(const auto& k : exclude)
s.insert(k);
Key_t peer;
while(N--)
{
if(!FindCloseExcluding(target, peer, s))
return false;
s.insert(peer);
result.insert(peer);
}
return true;
}
bool
FindCloseExcluding(const Key_t& target, Key_t& result,
std::set< Key_t > exclude) const
const std::set< Key_t >& exclude) const
{
Key_t maxdist;
maxdist.Fill(0xff);
@ -91,4 +135,4 @@ namespace llarp
};
} // namespace dht
} // namespace llarp
#endif
#endif

@ -8,7 +8,6 @@
#include <llarp/dht/message.hpp>
#include <llarp/dht/messages/findintro.hpp>
#include <llarp/dht/node.hpp>
#include <llarp/dht/search_job.hpp>
#include <llarp/service/IntroSet.hpp>
#include <set>
@ -17,123 +16,209 @@ namespace llarp
{
namespace dht
{
struct Context
struct TXOwner
{
Context();
~Context();
Key_t node;
uint64_t txid = 0;
SearchJob*
FindPendingTX(const Key_t& owner, uint64_t txid);
TXOwner() = default;
void
RemovePendingTX(const Key_t& owner, uint64_t txid);
TXOwner(const Key_t& k, uint64_t id) : node(k), txid(id)
{
}
void
LookupServiceDirect(const Key_t& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
SearchJob::IntroSetHookFunc handler,
bool iterateive = false,
std::set< Key_t > excludes = {});
bool
operator==(const TXOwner& other) const
{
return txid == other.txid && node == other.node;
}
bool
operator<(const TXOwner& other) const
{
return txid < other.txid || node < other.node;
}
void
LookupRouter(const Key_t& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
llarp_router_lookup_job* job = nullptr,
bool iterative = false, std::set< Key_t > excludes = {});
struct Hash
{
std::size_t
operator()(TXOwner const& o) const noexcept
{
std::size_t sz2;
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
return o.txid ^ (sz2 << 1);
}
};
};
void
LookupIntroSet(const service::Address& addr, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer, uint64_t R,
std::set< Key_t > excludes = {});
struct Context;
template < typename K, typename V >
struct TX
{
TX(const TXOwner& asker, const K& k, Context* p)
: target(k), whoasked(asker)
{
parent = p;
}
virtual ~TX(){};
K target;
Context* parent;
std::set< Key_t > peersAsked;
std::vector< V > valuesFound;
TXOwner whoasked;
void
LookupTag(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
const std::set< service::IntroSet >& include = {},
uint64_t R = 0);
OnFound(const Key_t& askedPeer, const V& value)
{
peersAsked.insert(askedPeer);
valuesFound.push_back(value);
}
virtual void
Start(const TXOwner& peer) = 0;
virtual bool
GetNextPeer(Key_t& next, const std::set< Key_t >& exclude) = 0;
virtual void
DoNextRequest(const Key_t& peer) = 0;
/// return true if we want to persist this tx
bool
AskNextPeer(const Key_t& prevPeer)
{
peersAsked.insert(prevPeer);
Key_t peer;
if(!GetNextPeer(peer, peersAsked))
{
// no more peers
SendReply();
return false;
}
DoNextRequest(peer);
return true;
}
virtual void
SendReply() = 0;
};
typedef std::function< void(const std::vector< service::IntroSet >&) >
IntroSetLookupHandler;
typedef std::function< void(const std::vector< RouterContact >&) >
RouterLookupHandler;
struct Context
{
Context();
~Context();
/// on behalf of whoasked request introset for target from dht router with
/// key askpeer
void
LookupRouterViaJob(llarp_router_lookup_job* job);
LookupIntroSetRecursive(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer, uint64_t R,
IntroSetLookupHandler result = nullptr);
void
LookupTagForPath(const service::Tag& tag, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer);
LookupIntroSetIterative(const service::Address& target,
const Key_t& whoasked, uint64_t whoaskedTX,
const Key_t& askpeer,
IntroSetLookupHandler result = nullptr);
/// on behalf of whoasked request router with public key target from dht
/// router with key askpeer
void
LookupIntroSetForPath(const service::Address& addr, uint64_t txid,
const llarp::PathID_t& path, Key_t askpeer);
LookupRouterRecursive(const RouterID& target, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer,
RouterLookupHandler result = nullptr);
template < typename Job, typename Result >
bool
TryLookupAgain(Job* j, Result r, uint64_t R)
LookupRouter(const RouterID& target, RouterLookupHandler result)
{
const Key_t targetKey = j->target.ToKey();
Key_t askpeer;
std::set< Key_t > exclude = j->asked;
if(!nodes->FindCloseExcluding(targetKey, askpeer, exclude))
{
j->Exausted();
return true;
}
if((OurKey() ^ targetKey) < (askpeer ^ targetKey))
{
j->Exausted();
return true;
}
auto id = ++ids;
TXOwner ownerKey;
ownerKey.node = askpeer;
ownerKey.txid = id;
SearchJob job(j->whoasked, j->txid, r, [j]() { delete j; });
pendingTX[ownerKey] = job;
auto msg = new FindIntroMessage(id, j->target);
msg->R = R;
llarp::LogInfo("asking ", askpeer, " for ", j->target.ToString(),
" with txid=", id);
DHTSendTo(askpeer, msg);
j->asked.insert(std::move(askpeer));
return false;
if(!nodes->FindClosest(target.data(), askpeer))
return false;
LookupRouterRecursive(target, OurKey(), 0, askpeer, result);
return true;
}
/// on behalf of whoasked request introsets with tag from dht router with
/// key askpeer with Recursion depth R
void
DHTSendTo(const Key_t& peer, IMessage* msg);
LookupTagRecursive(const service::Tag& tag, const Key_t& whoasked,
uint64_t whoaskedTX, const Key_t& askpeer, uint64_t R);
/// issue dht lookup for tag via askpeer and send reply to local path
void
LookupIntroSetRelayed(const Key_t& requester, uint64_t txid,
const service::Address& addr, bool recursive,
std::vector< IMessage* >& reply);
LookupTagForPath(const service::Tag& tag, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer);
/// issue dht lookup for router via askpeer and send reply to local path
void
LookupRouterForPath(const RouterID& target, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer);
/// issue dht lookup for introset for addr via askpeer and send reply to
/// local path
void
LookupIntroSetForPath(const service::Address& addr, uint64_t txid,
const llarp::PathID_t& path, const Key_t& askpeer);
/// send a dht message to peer, if keepalive is true then keep the session
/// with that peer alive for 10 seconds
void
DHTSendTo(const Key_t& peer, IMessage* msg, bool keepalive = true);
/// get routers closest to target excluding requester
bool
HandleExploritoryRouterLookup(
const Key_t& requester, uint64_t txid, const RouterID& target,
std::vector< std::unique_ptr< IMessage > >& reply);
std::set< service::IntroSet >
FindRandomIntroSetsWithTag(const service::Tag& tag, size_t max = 2);
FindRandomIntroSetsWithTagExcluding(
const service::Tag& tag, size_t max = 2,
const std::set< service::IntroSet >& excludes = {});
/// handle rc lookup from requester for target
void
LookupRouterRelayed(const Key_t& requester, uint64_t txid,
const Key_t& target, bool recursive,
std::vector< IMessage* >& replies);
std::vector< std::unique_ptr< IMessage > >& replies);
/// relay a dht messeage from a local path to the main network
bool
RelayRequestForPath(const llarp::PathID_t& localPath,
const IMessage* msg);
/// send introset to peer from source with S counter and excluding peers
void
PropagateIntroSetTo(const Key_t& from, uint64_t fromTX,
PropagateIntroSetTo(const Key_t& source, uint64_t sourceTX,
const service::IntroSet& introset, const Key_t& peer,
uint64_t S, const std::set< Key_t >& exclude);
/// initialize dht context and explore every exploreInterval milliseconds
void
Init(const Key_t& us, llarp_router* router);
Init(const Key_t& us, llarp_router* router, llarp_time_t exploreInterval);
/// get localally stored introset by service address
const llarp::service::IntroSet*
GetIntroSetByServiceAddress(const llarp::service::Address& addr) const;
void
QueueRouterLookup(llarp_router_lookup_job* job);
static void
handle_cleaner_timer(void* user, uint64_t orig, uint64_t left);
static void
queue_router_lookup(void* user);
handle_explore_timer(void* user, uint64_t orig, uint64_t left);
/// explore dht for new routers
void
Explore(size_t N = 3);
llarp_router* router = nullptr;
// for router contacts
@ -149,44 +234,144 @@ namespace llarp
return ourKey;
}
private:
void
ScheduleCleanupTimer();
template < typename K, typename V, typename K_Hash,
llarp_time_t requestTimeoutMS = 5000UL >
struct TXHolder
{
// tx who are waiting for a reply for each key
std::unordered_multimap< K, TXOwner, K_Hash > waiting;
// tx timesouts by key
std::unordered_map< K, llarp_time_t, K_Hash > timeouts;
// maps remote peer with tx to handle reply from them
std::unordered_map< TXOwner, std::unique_ptr< TX< K, V > >,
TXOwner::Hash >
tx;
const TX< K, V >*
GetPendingLookupFrom(const TXOwner& owner) const
{
auto itr = tx.find(owner);
if(itr == tx.end())
return nullptr;
else
return itr->second.get();
}
void
CleanupTX();
bool
HasPendingLookupFrom(const TXOwner& owner) const
{
return GetPendingLookupFrom(owner) != nullptr;
}
uint64_t ids;
TX< K, V >*
NewTX(const TXOwner& owner, const K& k, TX< K, V >* t)
{
tx.emplace(owner, std::unique_ptr< TX< K, V > >(t));
waiting.insert(std::make_pair(k, owner));
auto itr = timeouts.find(k);
if(itr == timeouts.end())
timeouts.insert(
std::make_pair(k, llarp_time_now_ms() + requestTimeoutMS));
return t;
}
struct TXOwner
{
Key_t node;
uint64_t txid = 0;
/// mark tx as not fond
void
NotFound(const TXOwner& from)
{
bool sendReply = true;
auto txitr = tx.find(from);
if(txitr == tx.end())
return;
// ask for next peer
if(txitr->second->AskNextPeer(from.node))
sendReply = false;
Inform(from, txitr->second->target, {}, sendReply, sendReply);
}
bool
operator==(const TXOwner& other) const
void
Found(const TXOwner& from, const K& k, const std::vector< V >& values)
{
return txid == other.txid && node == other.node;
Inform(from, k, values, true);
}
bool
operator<(const TXOwner& other) const
/// inform all watches for key of values found
void
Inform(const TXOwner& from, const K& key,
const std::vector< V >& values, bool sendreply = false,
bool removeTimeouts = true)
{
return txid < other.txid || node < other.node;
auto range = waiting.equal_range(key);
auto itr = range.first;
while(itr != range.second)
{
auto txitr = tx.find(itr->second);
if(txitr != tx.end())
{
for(const auto& value : values)
txitr->second->OnFound(from.node, value);
if(sendreply)
{
txitr->second->SendReply();
tx.erase(txitr);
}
}
++itr;
}
if(sendreply)
waiting.erase(key);
if(removeTimeouts)
timeouts.erase(key);
}
};
struct TXOwnerHash
{
std::size_t
operator()(TXOwner const& o) const noexcept
void
Expire(llarp_time_t now)
{
std::size_t sz2;
memcpy(&sz2, &o.node[0], sizeof(std::size_t));
return o.txid ^ (sz2 << 1);
auto itr = timeouts.begin();
while(itr != timeouts.end())
{
if(now > itr->second && now - itr->second >= requestTimeoutMS)
{
Inform(TXOwner{}, itr->first, {}, true, false);
itr = timeouts.erase(itr);
}
else
++itr;
}
}
}; // namespace dht
};
TXHolder< service::Address, service::IntroSet, service::Address::Hash >
pendingIntrosetLookups;
TXHolder< service::Tag, service::IntroSet, service::Tag::Hash >
pendingTagLookups;
TXHolder< RouterID, RouterContact, RouterID::Hash > pendingRouterLookups;
TXHolder< RouterID, RouterID, RouterID::Hash > pendingExploreLookups;
uint64_t
NextID()
{
return ++ids;
}
private:
void
ExploreNetworkVia(const Key_t& peer);
void
ScheduleCleanupTimer();
void
CleanupTX();
uint64_t ids;
std::unordered_map< TXOwner, SearchJob, TXOwnerHash > pendingTX;
Key_t ourKey;
}; // namespace llarp
} // namespace dht
@ -199,4 +384,4 @@ struct llarp_dht_context
llarp_dht_context(llarp_router* router);
};
#endif
#endif

@ -22,20 +22,22 @@ namespace llarp
}
virtual bool
HandleMessage(llarp_dht_context* dht,
std::vector< IMessage* >& replies) const = 0;
HandleMessage(
llarp_dht_context* dht,
std::vector< std::unique_ptr< IMessage > >& replies) const = 0;
Key_t From;
PathID_t pathID;
};
IMessage*
std::unique_ptr< IMessage >
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed = false);
bool
DecodeMesssageList(const Key_t& from, llarp_buffer_t* buf,
std::vector< IMessage* >& dst, bool relayed = false);
DecodeMesssageList(Key_t from, llarp_buffer_t* buf,
std::vector< std::unique_ptr< IMessage > >& dst,
bool relayed = false);
} // namespace dht
} // namespace llarp
#endif
#endif

@ -27,8 +27,9 @@ namespace llarp
S.Zero();
}
FindIntroMessage(uint64_t txid, const llarp::service::Address& addr)
: IMessage({}), S(addr), T(txid)
FindIntroMessage(uint64_t txid, const llarp::service::Address& addr,
uint64_t r)
: IMessage({}), R(r), S(addr), T(txid)
{
N.Zero();
}
@ -43,8 +44,8 @@ namespace llarp
bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< std::unique_ptr< IMessage > >& replies) const;
};
} // namespace dht
} // namespace llarp
#endif
#endif

@ -12,11 +12,18 @@ namespace llarp
{
}
FindRouterMessage(const Key_t& from, const Key_t& target, uint64_t id)
FindRouterMessage(const Key_t& from, const RouterID& target, uint64_t id)
: IMessage(from), K(target), txid(id)
{
}
// exploritory
FindRouterMessage(const Key_t& from, uint64_t id)
: IMessage(from), exploritory(true), txid(id)
{
K.Randomize();
}
~FindRouterMessage();
bool
@ -27,10 +34,11 @@ namespace llarp
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< std::unique_ptr< IMessage > >& replies) const;
Key_t K;
RouterID K;
bool iterative = false;
bool exploritory = false;
uint64_t txid = 0;
uint64_t version = 0;
};
@ -47,8 +55,8 @@ namespace llarp
/// TODO: smart path expiration logic needs to be implemented
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< std::unique_ptr< IMessage > >& replies) const;
};
} // namespace dht
} // namespace llarp
#endif
#endif

@ -31,7 +31,7 @@ namespace llarp
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< std::unique_ptr< IMessage > >& replies) const;
};
struct RelayedGotIntroMessage : public GotIntroMessage
@ -42,8 +42,8 @@ namespace llarp
bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< std::unique_ptr< IMessage > >& replies) const;
};
} // namespace dht
} // namespace llarp
#endif
#endif

@ -1,6 +1,7 @@
#ifndef LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
#define LLARP_DHT_MESSAGES_GOT_ROUTER_HPP
#include <llarp/dht/message.hpp>
#include <llarp/router_contact.hpp>
namespace llarp
{
@ -12,16 +13,17 @@ namespace llarp
: IMessage(from), relayed(tunneled)
{
}
GotRouterMessage(const Key_t& from, uint64_t id, const llarp_rc* result,
GotRouterMessage(const Key_t& from, uint64_t id,
const std::vector< RouterContact >& results,
bool tunneled)
: IMessage(from), txid(id), relayed(tunneled)
: IMessage(from), R(results), txid(id), relayed(tunneled)
{
}
GotRouterMessage(uint64_t id, const std::vector< RouterID >& near,
bool tunneled)
: IMessage({}), N(near), txid(id), relayed(tunneled)
{
if(result)
{
R.emplace_back();
llarp_rc_clear(&R.back());
llarp_rc_copy(&R.back(), result);
}
}
~GotRouterMessage();
@ -34,13 +36,14 @@ namespace llarp
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< std::unique_ptr< IMessage > >& replies) const;
std::vector< llarp_rc > R;
std::vector< RouterContact > R;
std::vector< RouterID > N;
uint64_t txid = 0;
uint64_t version = 0;
bool relayed = false;
};
} // namespace dht
} // namespace llarp
#endif
#endif

@ -38,8 +38,8 @@ namespace llarp
virtual bool
HandleMessage(llarp_dht_context* ctx,
std::vector< IMessage* >& replies) const;
std::vector< std::unique_ptr< IMessage > >& replies) const;
};
} // namespace dht
} // namespace llarp
#endif
#endif

@ -1,7 +1,7 @@
#ifndef LLARP_DHT_NODE_HPP
#define LLARP_DHT_NODE_HPP
#include <llarp/router_contact.h>
#include <llarp/router_contact.hpp>
#include <llarp/dht/key.hpp>
#include <llarp/service/IntroSet.hpp>
@ -11,18 +11,19 @@ namespace llarp
{
struct RCNode
{
llarp_rc* rc;
llarp::RouterContact rc;
Key_t ID;
RCNode() : rc(nullptr)
RCNode()
{
ID.Zero();
}
RCNode(llarp_rc* other) : rc(other)
RCNode(const llarp::RouterContact& other)
{
ID = other->pubkey;
rc = other;
ID = other.pubkey.data();
}
};
@ -47,4 +48,4 @@ namespace llarp
} // namespace dht
} // namespace llarp
#endif
#endif

@ -1,64 +0,0 @@
#ifndef LLARP_DHT_SEARCH_JOB_HPP
#define LLARP_DHT_SEARCH_JOB_HPP
#include <llarp/dht.h>
#include <llarp/time.h>
#include <functional>
#include <llarp/dht/key.hpp>
#include <llarp/service/IntroSet.hpp>
#include <set>
#include <vector>
namespace llarp
{
namespace dht
{
/// TODO: this should be made into a templated type
struct SearchJob
{
const static uint64_t JobTimeout = 30000;
typedef std::function< bool(
const std::vector< llarp::service::IntroSet >&) >
IntroSetHookFunc;
typedef std::function< void(void) > DoneFunc;
SearchJob();
/// for routers
SearchJob(const Key_t& requester, uint64_t requesterTX,
const Key_t& target, const std::set< Key_t >& excludes,
llarp_router_lookup_job* job);
/// for introsets
SearchJob(const Key_t& requester, uint64_t requesterTX,
const Key_t& target, const std::set< Key_t >& excludes,
IntroSetHookFunc found, DoneFunc done);
// for introsets via tag
SearchJob(const Key_t& requester, uint64_t requseterTX,
IntroSetHookFunc found, DoneFunc done);
void
FoundRouter(const llarp_rc* router) const;
bool
FoundIntros(
const std::vector< llarp::service::IntroSet >& introset) const;
void
Timeout() const;
bool
IsExpired(llarp_time_t now) const;
// only set if looking up router
llarp_router_lookup_job* job = nullptr;
IntroSetHookFunc foundIntroHook;
DoneFunc onDone;
llarp_time_t started;
Key_t requester;
uint64_t requesterTX;
Key_t target;
std::set< Key_t > exclude;
};
} // namespace dht
} // namespace llarp
#endif

@ -0,0 +1,31 @@
#ifndef LLARP_DTLS_HPP
#define LLARP_DTLS_HPP
#include <openssl/ssl.h>
namespace llarp
{
namespace dtls
{
struct Base
{
Base(uint16_t mtu)
{
_ctx = SSL_CTX_new(DTLS_with_buffers_method());
SSL_CTX_set_custom_verify(_ctx, SSL_VERIFY_PEER, []());
}
~Base()
{
if(_ctx)
SSL_CTX_free(_ctx);
}
SSL_CTX* _ctx = nullptr;
};
} // namespace dtls
} // namespace llarp
#endif

@ -5,12 +5,15 @@
#include <llarp/buffer.h>
#include <sodium.h>
#include <vector>
#include <stdexcept>
namespace llarp
{
/// encrypted buffer base type
struct Encrypted
{
static const size_t MAX_SIZE = (1024 * 8);
Encrypted(Encrypted&&) = delete;
Encrypted(const Encrypted& other);
Encrypted();
@ -31,15 +34,13 @@ namespace llarp
}
Encrypted&
operator=(llarp_buffer_t buf)
operator=(const llarp_buffer_t& buf)
{
if(_data)
delete[] _data;
_data = nullptr;
_sz = buf.sz;
if(buf.sz > MAX_SIZE)
return *this;
_sz = buf.sz;
if(_sz)
{
_data = new byte_t[_sz];
memcpy(_data, buf.base, _sz);
}
UpdateBuffer();
@ -57,7 +58,7 @@ namespace llarp
void
Randomize()
{
if(_data && _sz)
if(_sz)
randombytes(_data, _sz);
}
@ -69,10 +70,9 @@ namespace llarp
return false;
if(strbuf.sz == 0)
return false;
if(_data)
delete[] _data;
_sz = strbuf.sz;
_data = new byte_t[_sz];
if(strbuf.sz > MAX_SIZE)
return false;
_sz = strbuf.sz;
memcpy(_data, strbuf.base, _sz);
UpdateBuffer();
return true;
@ -116,10 +116,10 @@ namespace llarp
m_Buffer.cur = data();
m_Buffer.sz = size();
}
byte_t* _data = nullptr;
size_t _sz = 0;
byte_t _data[MAX_SIZE];
size_t _sz = 0;
llarp_buffer_t m_Buffer;
};
} // namespace llarp
#endif
#endif

@ -33,11 +33,11 @@ namespace llarp
EncryptedFrame&
operator=(const EncryptedFrame& other)
{
if(_data)
delete[] _data;
_sz = other._sz;
_data = new byte_t[_sz];
memcpy(_data, other._data, _sz);
if(other._sz <= MAX_SIZE)
{
_sz = other._sz;
memcpy(_data, other._data, _sz);
}
return *this;
}

@ -0,0 +1,33 @@
#ifndef LLARP_ESTABLISH_JOB_HPP
#define LLARP_ESTABLISH_JOB_HPP
namespace llarp
{
struct OutboundLinkEstablishJob
{
RouterContact rc;
OutboundLinkEstablishJob(const RouterContact& remote) : rc(remote)
{
}
virtual ~OutboundLinkEstablishJob(){};
virtual void
Success() = 0;
virtual void
Failed() = 0;
virtual void
AttemptTimedout() = 0;
virtual void
Attempt() = 0;
virtual bool
ShouldRetry() const = 0;
};
} // namespace llarp
#endif

@ -52,6 +52,8 @@ llarp_ev_loop_stop(struct llarp_ev_loop *ev);
/// UDP handling configuration
struct llarp_udp_io
{
/// set after added
int fd;
void *user;
void *impl;
struct llarp_ev_loop *parent;

@ -0,0 +1,62 @@
#ifndef LLARP_XI_HPP
#define LLARP_XI_HPP
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/net.h>
#include <iostream>
#include <llarp/bits.hpp>
/**
* exit_info.h
*
* utilities for handling exits on the llarp network
*/
/// Exit info model
namespace llarp
{
struct ExitInfo : public IBEncodeMessage
{
struct in6_addr address;
struct in6_addr netmask;
PubKey pubkey;
ExitInfo() : IBEncodeMessage()
{
}
ExitInfo(const ExitInfo &other) : IBEncodeMessage()
{
pubkey = other.pubkey;
memcpy(address.s6_addr, other.address.s6_addr, 16);
memcpy(netmask.s6_addr, other.netmask.s6_addr, 16);
version = other.version;
}
~ExitInfo();
bool
BEncode(llarp_buffer_t *buf) const;
bool
DecodeKey(llarp_buffer_t k, llarp_buffer_t *buf);
ExitInfo &
operator=(const ExitInfo &other);
friend std::ostream &
operator<<(std::ostream &out, const ExitInfo &xi)
{
char tmp[128] = {0};
if(inet_ntop(AF_INET6, &xi.address, tmp, sizeof(tmp)))
out << std::string(tmp);
else
return out;
out << std::string("/");
return out << std::to_string(
llarp::bits::count_array_bits(xi.netmask.s6_addr));
}
};
} // namespace llarp
#endif

@ -16,7 +16,7 @@ typedef struct ip_hdr
unsigned char
ip_header_len : 4; // 4-bit header length (in 32-bit words) normally=5
// (Means 20 Bytes may be 24 also)
unsigned char version : 4; // 4-bit IPv4 version
unsigned char ip_version : 4; // 4-bit IPv4 version
unsigned char ip_tos; // IP type of service
unsigned short ip_total_length; // Total length
unsigned short ip_id; // Unique identifier
@ -75,27 +75,27 @@ namespace llarp
struct GetTime
{
llarp_time_t
operator()(const IPv4Packet* pkt) const
operator()(const IPv4Packet& pkt) const
{
return pkt->timestamp;
return pkt.timestamp;
}
};
struct PutTime
{
void
operator()(IPv4Packet* pkt) const
operator()(IPv4Packet& pkt) const
{
pkt->timestamp = llarp_time_now_ms();
pkt.timestamp = llarp_time_now_ms();
}
};
struct CompareOrder
{
bool
operator()(const IPv4Packet* left, const IPv4Packet* right)
operator()(const IPv4Packet& left, const IPv4Packet& right)
{
return left->timestamp < right->timestamp;
return left.timestamp < right.timestamp;
}
};

@ -9,7 +9,7 @@ struct llarp_iwp_args
struct llarp_logic* logic;
struct llarp_threadpool* cryptoworker;
struct llarp_router* router;
std::string keyfile;
bool permitInbound;
};
#endif

@ -1,21 +0,0 @@
#pragma once
#include "llarp/address_info.h"
struct llarp_link;
struct llarp_link_session;
struct llarp_link_establish_job
{
void *user;
void (*result)(struct llarp_link_establish_job *);
struct llarp_ai ai;
uint64_t timeout;
uint16_t retries;
byte_t pubkey[PUBKEYSIZE];
/** set on success by try_establish */
struct llarp_link *link;
/** set on success by try_establish */
struct llarp_link_session *session;
};

@ -1,39 +0,0 @@
#pragma once
#include "llarp/buffer.h"
enum header_flag
{
eSessionInvalidated = (1 << 0),
eHighPacketDrop = (1 << 1),
eHighMTUDetected = (1 << 2),
eProtoUpgrade = (1 << 3)
};
struct frame_header
{
byte_t *ptr;
frame_header(byte_t *buf);
byte_t *
data();
uint8_t &
version();
uint8_t &
msgtype();
uint16_t
size() const;
void
setsize(uint16_t sz);
uint8_t &
flags();
void
setflag(header_flag f);
};

@ -1,121 +0,0 @@
#pragma once
#include <llarp/codel.hpp>
#include <llarp/crypto.hpp>
#include "frame_header.hpp"
#include "inbound_message.hpp"
#include "llarp/logger.hpp"
#include "llarp/time.h"
#include "llarp/types.h"
#include "sendbuf.hpp"
#include "sendqueue.hpp"
#include "transit_message.hpp"
#include <queue>
#include <unordered_map>
enum msgtype
{
eALIV = 0x00,
eXMIT = 0x01,
eACKS = 0x02,
eFRAG = 0x03
};
static inline byte_t *
init_sendbuf(sendbuf_t *buf, msgtype t, uint16_t sz, uint8_t flags)
{
frame_header hdr(buf->data());
hdr.version() = 0;
hdr.msgtype() = t;
hdr.setsize(sz);
buf->data()[4] = 0;
buf->data()[5] = flags;
return hdr.data();
}
struct llarp_router;
struct llarp_link_session;
struct frame_state
{
byte_t rxflags = 0;
byte_t txflags = 0;
uint64_t rxids = 0;
uint64_t txids = 0;
llarp_time_t lastEvent = 0;
std::unordered_map< uint64_t, llarp::ShortHash > rxIDs;
std::unordered_map< llarp::ShortHash, transit_message *,
llarp::ShortHash::Hash >
rx;
std::unordered_map< uint64_t, transit_message * > tx;
// typedef std::queue< sendbuf_t * > sendqueue_t;
typedef llarp::util::CoDelQueue<
InboundMessage, InboundMessage::GetTime, InboundMessage::PutTime,
InboundMessage::OrderCompare, llarp::util::DummyMutex,
llarp::util::DummyLock >
recvqueue_t;
llarp_link_session *parent = nullptr;
sendqueue_t sendqueue;
recvqueue_t recvqueue;
uint64_t nextMsgID = 0;
frame_state(llarp_link_session *session)
: parent(session)
, sendqueue("iwp_outbound_message")
, recvqueue("iwp_inbound_message")
{
}
/// return true if both sides have the same state flags
bool
flags_agree(byte_t flags) const;
bool
process_inbound_queue();
llarp_router *
Router();
void
clear();
bool
inbound_frame_complete(uint64_t id);
void
push_ackfor(uint64_t id, uint32_t bitmask);
bool
got_xmit(frame_header hdr, size_t sz);
void
alive();
bool
got_frag(frame_header hdr, size_t sz);
bool
got_acks(frame_header hdr, size_t sz);
// queue new outbound message
void
queue_tx(uint64_t id, transit_message *msg);
void
retransmit(llarp_time_t now);
// get next frame to encrypt and transmit
bool
next_frame(llarp_buffer_t *buf);
void
pop_next_frame();
bool
process(byte_t *buf, size_t sz);
};

@ -1,59 +0,0 @@
#pragma once
#include "buffer.hpp"
#include "llarp/time.h"
#include "llarp/types.h"
#include <vector>
struct InboundMessage
{
uint64_t msgid;
std::vector< byte_t > msg;
llarp_time_t queued = 0;
InboundMessage(uint64_t id, const std::vector< byte_t > &m)
: msgid(id), msg(m)
{
}
bool
operator<(const InboundMessage &other) const
{
// order in ascending order for codel queue
return msgid < other.msgid;
}
llarp_buffer_t
Buffer()
{
return llarp::Buffer< decltype(msg) >(msg);
}
struct GetTime
{
llarp_time_t
operator()(const InboundMessage *msg)
{
return msg->queued;
}
};
struct OrderCompare
{
bool
operator()(const InboundMessage *left, const InboundMessage *right) const
{
return left->msgid < right->msgid;
}
};
struct PutTime
{
void
operator()(InboundMessage *msg)
{
msg->queued = llarp_time_now_ms();
}
};
};

@ -1,78 +0,0 @@
#pragma once
#include <llarp/buffer.h>
#include <llarp/time.h>
#include <memory>
#include <queue>
struct sendbuf_t
{
sendbuf_t(size_t s) : sz(s)
{
_buf = new byte_t[s];
}
~sendbuf_t()
{
if(_buf)
delete[] _buf;
}
size_t sz;
byte_t priority = 255;
size_t
size() const
{
return sz;
}
byte_t *
data()
{
return _buf;
}
llarp_buffer_t
Buffer()
{
llarp_buffer_t buf;
buf.base = _buf;
buf.sz = sz;
buf.cur = buf.base;
return buf;
}
struct GetTime
{
llarp_time_t
operator()(const sendbuf_t *buf) const
{
return buf->timestamp;
}
};
struct PutTime
{
void
operator()(sendbuf_t *buf) const
{
buf->timestamp = llarp_time_now_ms();
}
};
struct Compare
{
bool
operator()(const sendbuf_t *left, const sendbuf_t *right) const
{
return left->timestamp < right->timestamp;
}
};
llarp_time_t timestamp = 0;
private:
byte_t *_buf = nullptr;
};

@ -1,11 +0,0 @@
#ifndef LLARP_IWP_SENDQUEUE_HPP
#define LLARP_IWP_SENDQUEUE_HPP
#include <llarp/codel.hpp>
#include <llarp/iwp/sendbuf.hpp>
typedef llarp::util::CoDelQueue<
sendbuf_t, sendbuf_t::GetTime, sendbuf_t::PutTime, sendbuf_t::Compare,
llarp::util::DummyMutex, llarp::util::DummyLock >
sendqueue_t;
#endif

@ -1,170 +0,0 @@
#pragma once
#include <llarp/iwp.hpp>
#include <llarp/threading.hpp>
#include "llarp/iwp/establish_job.hpp"
#include "router.hpp"
#include "session.hpp"
#ifndef __linux__
#ifdef saddr
#undef saddr
#endif
#endif
#include <algorithm>
#include <fstream>
struct llarp_link
{
typedef llarp::util::NullMutex mtx_t;
typedef llarp::util::NullLock lock_t;
llarp_router *router;
llarp_crypto *crypto;
llarp_logic *logic;
llarp_ev_loop *netloop;
llarp_async_iwp *iwp;
llarp_threadpool *worker;
llarp_link *parent = nullptr;
llarp_udp_io udp;
llarp::Addr addr;
std::string keyfile;
uint32_t timeout_job_id;
const char *
name() const
{
return m_name;
}
const char *m_name;
typedef std::unordered_map< llarp::Addr, llarp_link_session *,
llarp::Addr::Hash >
LinkMap_t;
LinkMap_t m_sessions;
mtx_t m_sessions_Mutex;
typedef std::unordered_map< llarp::PubKey, llarp::Addr, llarp::PubKey::Hash >
SessionMap_t;
SessionMap_t m_Connected;
mtx_t m_Connected_Mutex;
std::atomic< bool > pumpingLogic;
typedef std::unordered_map< llarp::Addr, llarp_link_session *,
llarp::Addr::Hash >
PendingSessionMap_t;
PendingSessionMap_t m_PendingSessions;
mtx_t m_PendingSessions_Mutex;
llarp::SecretKey seckey;
llarp_link(const llarp_iwp_args &args);
~llarp_link();
bool
has_intro_from(const llarp::Addr &from);
void
put_intro_from(llarp_link_session *s);
void
remove_intro_from(const llarp::Addr &from);
// set that src address has identity pubkey
void
MapAddr(const llarp::Addr &src, const llarp::PubKey &identity);
/// does nothing if we have no session already established
void
KeepAliveSessionTo(const byte_t *pubkey);
/// does nothing if we have no session already established
void
CloseSessionTo(const byte_t *pubkey);
bool
has_session_to(const byte_t *pubkey);
void
TickSessions();
bool
sendto(const byte_t *pubkey, llarp_buffer_t buf);
void
UnmapAddr(const llarp::Addr &src);
llarp_link_session *
create_session(const llarp::Addr &src);
bool
has_session_via(const llarp::Addr &dst);
llarp_link_session *
find_session(const llarp::Addr &addr);
void
put_session(const llarp::Addr &src, llarp_link_session *impl);
void
clear_sessions();
/// safe iterate sessions
void
iterate_sessions(std::function< bool(llarp_link_session *) > visitor);
static void
handle_logic_pump(void *user);
void
PumpLogic();
void
RemoveSession(llarp_link_session *s);
const uint8_t *
pubkey();
bool
ensure_privkey();
bool
keygen(const char *fname);
static void
handle_cleanup_timer(void *l, uint64_t orig, uint64_t left);
// this is called in net threadpool
static void
handle_recvfrom(struct llarp_udp_io *udp, const struct sockaddr *saddr,
const void *buf, ssize_t sz);
void
cancel_timer();
void
issue_cleanup_timer(uint64_t timeout);
void
get_our_address(struct llarp_ai *addr);
static void
after_recv(llarp_udp_io *udp);
bool
configure(struct llarp_ev_loop *netloop, const char *ifname, int af,
uint16_t port);
bool
start_link(struct llarp_logic *pLogic);
bool
stop_link();
bool
try_establish(struct llarp_link_establish_job *job);
};

@ -1,189 +0,0 @@
#pragma once
#include <atomic>
#include <llarp/codel.hpp>
#include "frame_state.hpp"
#include "llarp/buffer.h"
#include "llarp/crypto.hpp"
#include "llarp/crypto_async.h"
#include "llarp/net.hpp"
#include "llarp/router_contact.h"
#include "llarp/time.h"
#include "llarp/types.h"
struct llarp_udp_io;
struct llarp_async_iwp;
struct llarp_logic;
struct llarp_link;
struct transit_message;
struct llarp_link_establish_job;
struct llarp_link_session
{
static constexpr llarp_time_t SESSION_TIMEOUT = 10000;
static constexpr llarp_time_t KEEP_ALIVE_INTERVAL = SESSION_TIMEOUT / 4;
static constexpr size_t MAX_PAD = 128;
llarp_link_session(llarp_link *l, const byte_t *seckey, const llarp::Addr &a);
~llarp_link_session();
void
session_start();
bool sendto(llarp_buffer_t);
bool
has_timed_out();
bool
timedout(llarp_time_t now, llarp_time_t timeout = SESSION_TIMEOUT);
void
close();
void
session_established();
llarp_link *
get_parent();
llarp_rc *
get_remote_router();
bool
CheckRCValid();
bool
IsEstablished();
void
send_LIM();
bool
is_invalidated() const;
void
done();
void
pump();
void
introduce(uint8_t *pub);
void
intro_ack();
void
on_intro_ack(const void *buf, size_t sz);
void
on_intro(const void *buf, size_t sz);
void
on_session_start(const void *buf, size_t sz);
void
encrypt_frame_async_send(const void *buf, size_t sz);
// void send_keepalive(void *user);
bool
Tick(llarp_time_t now);
void
keepalive();
void
PumpCryptoOutbound();
// process inbound and outbound queues (logic thread)
void
TickLogic(llarp_time_t now);
// this is called from net thread
void
recv(const void *buf, size_t sz);
llarp_router *
Router();
llarp_udp_io *udp = nullptr;
llarp_crypto *crypto = nullptr;
llarp_async_iwp *iwp = nullptr;
llarp_link *serv = nullptr;
llarp_rc *our_router = nullptr;
llarp_rc remote_router;
llarp::SecretKey eph_seckey;
llarp::PubKey remote;
llarp::SharedSecret sessionkey;
llarp_link_establish_job *establish_job = nullptr;
llarp_time_t createdAt = 0;
llarp_time_t lastKeepalive = 0;
uint32_t establish_job_id = 0;
uint32_t frames = 0;
std::atomic< bool > working;
llarp::util::CoDelQueue< iwp_async_frame, FrameGetTime, FramePutTime,
FrameCompareTime >
outboundFrames;
llarp::util::CoDelQueue< iwp_async_frame, FrameGetTime, FramePutTime,
FrameCompareTime >
decryptedFrames;
llarp::Addr addr;
iwp_async_intro intro;
iwp_async_introack introack;
iwp_async_session_start start;
/// timestamp last intro packet sent at
llarp_time_t lastIntroSentAt = 0;
uint32_t intro_resend_job_id = 0;
byte_t token[32];
byte_t workbuf[MAX_PAD + 128];
enum State
{
eInitial,
eIntroRecv,
eIntroSent,
eIntroAckSent,
eIntroAckRecv,
eSessionStartSent,
eLIMSent,
eEstablished,
eTimeout
};
State state;
void
EnterState(State st);
void
add_outbound_message(uint64_t id, transit_message *msg);
void
EncryptOutboundFrames();
iwp_async_frame *
alloc_frame(const void *buf, size_t sz);
void
decrypt_frame(const void *buf, size_t sz);
static void
handle_frame_decrypt(iwp_async_frame *f);
static void
handle_introack_timeout(void *user, uint64_t timeout, uint64_t left);
frame_state frame;
};
struct llarp_link_session_iter
{
void *user;
struct llarp_link *link;
bool (*visit)(struct llarp_link_session_iter *, struct llarp_link_session *);
};

@ -1,74 +0,0 @@
#pragma once
#include "llarp/types.h"
#include "sendbuf.hpp"
#include "sendqueue.hpp"
#include "xmit.hpp"
#include <bitset>
#include <unordered_map>
#include <vector>
struct transit_message
{
xmit msginfo;
std::bitset< 32 > status = {};
typedef std::vector< byte_t > fragment_t;
std::unordered_map< byte_t, fragment_t > frags;
fragment_t lastfrag;
llarp_time_t lastAck = 0;
llarp_time_t lastRetransmit = 0;
llarp_time_t started;
void
clear();
// calculate acked bitmask
uint32_t
get_bitmask() const;
// outbound
transit_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id,
uint16_t mtu = 1024);
// inbound
transit_message(const xmit &x);
/// ack packets based off a bitmask
void
ack(uint32_t bitmask);
bool
should_send_ack(llarp_time_t now) const;
bool
should_resend_frags(llarp_time_t now) const;
bool
should_resend_xmit(llarp_time_t now) const;
bool
completed() const;
// template < typename T >
void
generate_xmit(sendqueue_t &queue, byte_t flags = 0);
// template < typename T >
void
retransmit_frags(sendqueue_t &queue, byte_t flags = 0);
bool
reassemble(std::vector< byte_t > &buffer);
void
put_message(llarp_buffer_t buf, const byte_t *hash, uint64_t id,
uint16_t mtu = 1024);
void
put_lastfrag(byte_t *buf, size_t sz);
bool
put_frag(byte_t fragno, byte_t *buf);
};

@ -1,43 +0,0 @@
#pragma once
#include "llarp/buffer.h"
struct xmit
{
byte_t buffer[48];
xmit() = default;
xmit(byte_t *ptr);
xmit(const xmit &other);
void
set_info(const byte_t *hash, uint64_t id, uint16_t fragsz, uint16_t lastsz,
uint8_t numfrags, uint8_t flags = 0x01);
const byte_t *
hash() const;
uint64_t
msgid() const;
// size of each full fragment
uint16_t
fragsize() const;
// number of full fragments
uint8_t
numfrags() const;
// size of the entire message
size_t
totalsize() const;
// size of the last fragment
uint16_t
lastfrag() const;
uint8_t
flags();
};

@ -0,0 +1,15 @@
#ifndef LLARP_LINK_CURVECP_HPP
#define LLARP_LINK_CURVECP_HPP
#include <llarp/link_layer.hpp>
namespace llarp
{
namespace curvecp
{
std::unique_ptr< ILinkLayer >
NewServer(llarp_router* r);
}
} // namespace llarp
#endif

@ -0,0 +1,142 @@
#ifndef LLARP_LINK_SERVER_HPP
#define LLARP_LINK_SERVER_HPP
#include <unordered_map>
#include <llarp/threading.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/crypto.hpp>
#include <llarp/net.hpp>
#include <llarp/ev.h>
#include <llarp/link/session.hpp>
#include <llarp/logic.h>
#include <list>
struct llarp_router;
namespace llarp
{
struct ILinkLayer
{
virtual ~ILinkLayer();
bool
HasSessionTo(const PubKey& pk);
bool
HasSessionVia(const Addr& addr);
static void
udp_tick(llarp_udp_io* udp)
{
static_cast< ILinkLayer* >(udp->user)->Pump();
}
static void
udp_recv_from(llarp_udp_io* udp, const sockaddr* from, const void* buf,
const ssize_t sz)
{
static_cast< ILinkLayer* >(udp->user)->RecvFrom(*from, buf, sz);
}
bool
Configure(llarp_ev_loop* loop, const std::string& ifname, int af,
uint16_t port);
virtual ILinkSession*
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) = 0;
virtual void
Pump();
virtual void
RecvFrom(const Addr& from, const void* buf, size_t sz) = 0;
bool
PickAddress(const RouterContact& rc, AddressInfo& picked) const;
void
TryEstablishTo(const RouterContact& rc);
bool
Start(llarp_logic* l);
void
Stop();
virtual const char*
Name() const = 0;
void
CloseSessionTo(const PubKey& remote);
void
KeepAliveSessionTo(const PubKey& remote);
bool
SendTo(const PubKey& remote, llarp_buffer_t buf);
bool
GetOurAddressInfo(AddressInfo& addr) const;
void
RemoveSessionVia(const Addr& addr);
virtual uint16_t
Rank() const = 0;
virtual bool
KeyGen(SecretKey&) = 0;
const byte_t*
TransportPubKey() const;
const byte_t*
TransportSecretKey() const;
bool
EnsureKeys(const char* fpath);
void
MapAddr(const PubKey& pk, ILinkSession* s);
virtual void
Tick(llarp_time_t now)
{
}
private:
static void
on_timer_tick(void* user, uint64_t orig, uint64_t left)
{
// timer cancelled
if(left)
return;
static_cast< ILinkLayer* >(user)->OnTick(orig, llarp_time_now_ms());
}
void
OnTick(uint64_t interval, llarp_time_t now);
void
ScheduleTick(uint64_t interval);
uint32_t tick_id;
protected:
void
PutSession(const Addr& addr, ILinkSession* s);
llarp_logic* m_Logic = nullptr;
Addr m_ourAddr;
llarp_udp_io m_udp;
SecretKey m_SecretKey;
util::Mutex m_AuthedLinksMutex;
std::unordered_multimap< PubKey, std::unique_ptr< ILinkSession >,
PubKey::Hash >
m_AuthedLinks;
util::Mutex m_PendingMutex;
std::list< std::unique_ptr< ILinkSession > > m_Pending;
};
} // namespace llarp
#endif

@ -0,0 +1,49 @@
#ifndef LLARP_LINK_SESSION_HPP
#define LLARP_LINK_SESSION_HPP
#include <llarp/crypto.hpp>
#include <llarp/net.hpp>
#include <llarp/router_contact.hpp>
#include <functional>
namespace llarp
{
struct LinkIntroMessage;
struct ILinkMessage;
struct ILinkLayer;
struct ILinkSession
{
virtual ~ILinkSession(){};
/// called every event loop tick
std::function< void(void) > Pump;
/// called every timer tick
std::function< void(llarp_time_t) > Tick;
/// send a message buffer to the remote endpoint
std::function< bool(llarp_buffer_t) > SendMessageBuffer;
/// start the connection
std::function< void(void) > Start;
/// send a keepalive to the remote endpoint
std::function< bool(void) > SendKeepAlive;
/// send close message
std::function< void(void) > SendClose;
/// return true if we are established
std::function< bool(void) > IsEstablished;
/// return true if this session has timed out
std::function< bool(llarp_time_t) > TimedOut;
/// get remote public identity key
std::function< const PubKey &(void) > GetPubKey;
/// get remote address
std::function< const Addr &(void) > GetRemoteEndpoint;
};
} // namespace llarp
#endif

@ -0,0 +1,15 @@
#ifndef LLARP_LINK_UTP_HPP
#define LLARP_LINK_UTP_HPP
#include <llarp/link_layer.hpp>
namespace llarp
{
namespace utp
{
std::unique_ptr< ILinkLayer >
NewServer(llarp_router* r);
}
} // namespace llarp
#endif

@ -0,0 +1,6 @@
#ifndef LLARP_LINK_LAYER_HPP
#define LLARP_LINK_LAYER_HPP
#include <llarp/link/server.hpp>
#include <llarp/link/session.hpp>
constexpr size_t MAX_LINK_MSG_SIZE = 8192;
#endif

@ -3,29 +3,36 @@
#include <llarp/bencode.hpp>
#include <llarp/router_id.hpp>
#include <llarp/link/session.hpp>
#include <queue>
#include <vector>
struct llarp_router;
struct llarp_link_session;
struct llarp_link_session_iter;
namespace llarp
{
struct ILinkMessage;
struct ILinkSession;
typedef std::queue< ILinkMessage* > SendQueue;
/// parsed link layer message
struct ILinkMessage : public IBEncodeMessage
{
/// who did this message come from (rc.k)
RouterID remote = {};
/// who did this message come from or is going to
ILinkSession* session;
uint64_t version = 0;
ILinkMessage() = default;
ILinkMessage(const RouterID& id);
ILinkMessage() : ILinkMessage(nullptr)
{
}
ILinkMessage(ILinkSession* from) : session(from)
{
}
virtual ~ILinkMessage()
{
}
virtual bool
HandleMessage(llarp_router* router) const = 0;
@ -41,13 +48,17 @@ namespace llarp
/// start processig message from a link session
bool
ProcessFrom(llarp_link_session* from, llarp_buffer_t buf);
ProcessFrom(ILinkSession* from, llarp_buffer_t buf);
/// called when the message is fully read
/// return true when the message was accepted otherwise returns false
bool
MessageDone();
/// resets internal state
void
Reset();
private:
RouterID
GetCurrentFrom();
@ -55,8 +66,8 @@ namespace llarp
private:
bool firstkey;
llarp_router* router;
llarp_link_session* from;
ILinkMessage* msg = nullptr;
ILinkSession* from = nullptr;
std::unique_ptr< ILinkMessage > msg;
};
} // namespace llarp

@ -26,7 +26,7 @@ namespace llarp
template < typename T, size_t align = 128 >
void
DumpBuffer(const T &buff)
DumpBufferHex(const T &buff)
{
size_t idx = 0;
printf("buffer of size %zu\n", buff.sz);
@ -51,7 +51,7 @@ namespace llarp
template < typename T, size_t align = 128 >
void
DumpBufferHex(const T &buff)
DumpBuffer(const T &buff)
{
size_t idx = 0;
printf("buffer of size %zu\n", buff.sz);
@ -65,6 +65,10 @@ namespace llarp
{
printf("%c", buff.base[idx]);
}
else
{
printf(".");
}
if(buff.base + idx == buff.cur)
{
printf("%c[0;0m", 27);

@ -8,9 +8,8 @@
#include <llarp/messages/dht_immediate.hpp>
#include <llarp/messages/link_intro.hpp>
#include <llarp/messages/relay.hpp>
#include <llarp/messages/relay_ack.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/messages/discard.hpp>
#include <llarp/messages/path_confirm.hpp>
#endif

@ -11,7 +11,7 @@ namespace llarp
{
struct DHTMessage : public IMessage
{
std::vector< llarp::dht::IMessage* > M;
std::vector< std::unique_ptr< llarp::dht::IMessage > > M;
uint64_t V = 0;
~DHTMessage();
@ -28,4 +28,4 @@ namespace llarp
} // namespace routing
} // namespace llarp
#endif
#endif

@ -8,13 +8,17 @@ namespace llarp
{
struct DHTImmeidateMessage : public ILinkMessage
{
DHTImmeidateMessage(const RouterID& from) : ILinkMessage(from)
DHTImmeidateMessage(ILinkSession* parent) : ILinkMessage(parent)
{
}
DHTImmeidateMessage() : ILinkMessage()
{
}
~DHTImmeidateMessage();
std::vector< llarp::dht::IMessage* > msgs;
std::vector< std::unique_ptr< llarp::dht::IMessage > > msgs;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);

@ -0,0 +1,49 @@
#ifndef LLARP_MESSAGES_DISCARD_HPP
#define LLARP_MESSAGES_DISCARD_HPP
#include <llarp/link_message.hpp>
#include <llarp/bencode.hpp>
namespace llarp
{
struct DiscardMessage : public ILinkMessage
{
/// who did this message come from or is going to
DiscardMessage() : ILinkMessage(nullptr)
{
}
DiscardMessage(ILinkSession* from) : ILinkMessage(from)
{
}
~DiscardMessage()
{
}
bool
BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!bencode_write_bytestring(buf, "a", 1))
return false;
if(!bencode_write_bytestring(buf, "x", 1))
return false;
return bencode_end(buf);
}
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf)
{
return false;
}
bool
HandleMessage(llarp_router* router) const
{
return true;
}
};
} // namespace llarp
#endif

@ -1,17 +1,26 @@
#ifndef LLARP_MESSAGES_LINK_INTRO_HPP
#define LLARP_MESSAGES_LINK_INTRO_HPP
#include <llarp/link_message.hpp>
#include <llarp/router_contact.hpp>
namespace llarp
{
struct ILinkSession;
struct LinkIntroMessage : public ILinkMessage
{
LinkIntroMessage(llarp_rc* rc) : ILinkMessage(), RC(rc)
LinkIntroMessage() : ILinkMessage()
{
}
LinkIntroMessage(ILinkSession* s) : ILinkMessage(s)
{
}
~LinkIntroMessage();
llarp_rc* RC;
RouterContact rc;
KeyExchangeNonce N;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);

@ -16,7 +16,7 @@ namespace llarp
TunnelNonce Y;
RelayUpstreamMessage();
RelayUpstreamMessage(const RouterID& from);
RelayUpstreamMessage(ILinkSession* from);
~RelayUpstreamMessage();
bool
@ -35,7 +35,7 @@ namespace llarp
Encrypted X;
TunnelNonce Y;
RelayDownstreamMessage();
RelayDownstreamMessage(const RouterID& from);
RelayDownstreamMessage(ILinkSession* from);
~RelayDownstreamMessage();
bool

@ -1,41 +0,0 @@
#ifndef LLARP_MESSAGES_RELAY_ACK_HPP
#define LLARP_MESSAGES_RELAY_ACK_HPP
#include <llarp/crypto.hpp>
#include <llarp/encrypted_frame.hpp>
#include <llarp/link_message.hpp>
#include <llarp/path_types.hpp>
namespace llarp
{
struct LR_AckRecord
{
uint64_t version = 0;
bool
BEncode(llarp_buffer_t* buf) const;
bool
BDecode(llarp_buffer_t* buf);
};
struct LR_AckMessage : public ILinkMessage
{
std::vector< EncryptedFrame > replies;
uint64_t version = 0;
LR_AckMessage(const RouterID& from);
~LR_AckMessage();
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf);
bool
BEncode(llarp_buffer_t* buf) const;
bool
HandleMessage(llarp_router* router) const;
};
} // namespace llarp
#endif

@ -45,14 +45,13 @@ namespace llarp
struct LR_CommitMessage : public ILinkMessage
{
std::vector< EncryptedFrame > frames;
uint64_t version;
std::array< EncryptedFrame, 8 > frames;
LR_CommitMessage() : ILinkMessage()
{
}
LR_CommitMessage(const RouterID &from) : ILinkMessage(from)
LR_CommitMessage(ILinkSession *from) : ILinkMessage(from)
{
}

@ -1,6 +1,6 @@
#ifndef LLARP_NET_HPP
#define LLARP_NET_HPP
#include <llarp/address_info.h>
#include <llarp/address_info.hpp>
#include <llarp/net.h>
#include <functional>
#include <iostream>
@ -12,12 +12,21 @@
bool
operator==(const sockaddr& a, const sockaddr& b);
bool
operator==(const sockaddr_in& a, const sockaddr_in& b);
bool
operator==(const sockaddr_in6& a, const sockaddr_in6& b);
bool
operator<(const sockaddr_in6& a, const sockaddr_in6& b);
bool
operator<(const in6_addr& a, const in6_addr& b);
bool
operator==(const in6_addr& a, const in6_addr& b);
struct privatesInUse
{
bool ten; // 16m ips
@ -44,6 +53,16 @@ namespace llarp
memcpy(&_addr4, &other._addr4, sizeof(sockaddr_in));
}
void
port(uint16_t port)
{
if(af() == AF_INET)
{
_addr4.sin_port = htons(port);
}
_addr.sin6_port = htons(port);
}
in6_addr*
addr6()
{
@ -87,7 +106,7 @@ namespace llarp
ip[3] = four;
}
Addr(const llarp_ai& other)
Addr(const AddressInfo& other)
{
memcpy(addr6(), other.ip.s6_addr, 16);
_addr.sin6_port = htons(other.port);
@ -106,6 +125,42 @@ namespace llarp
_addr.sin6_family = AF_INET6;
}
Addr(const sockaddr_in& other)
{
llarp::Zero(&_addr, sizeof(sockaddr_in6));
_addr.sin6_family = AF_INET;
uint8_t* addrptr = _addr.sin6_addr.s6_addr;
uint16_t* port = &_addr.sin6_port;
// SIIT
memcpy(12 + addrptr, &((const sockaddr_in*)(&other))->sin_addr,
sizeof(in_addr));
addrptr[11] = 0xff;
addrptr[10] = 0xff;
*port = ((sockaddr_in*)(&other))->sin_port;
_addr4.sin_family = AF_INET;
_addr4.sin_port = *port;
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
}
Addr(const sockaddr_in6& other)
{
memcpy(addr6(), other.sin6_addr.s6_addr, 16);
_addr.sin6_port = htons(other.sin6_port);
auto ptr = &_addr.sin6_addr.s6_addr[0];
// TODO: detect SIIT better
if(ptr[11] == 0xff && ptr[10] == 0xff && ptr[9] == 0 && ptr[8] == 0
&& ptr[7] == 0 && ptr[6] == 0 && ptr[5] == 0 && ptr[4] == 0
&& ptr[3] == 0 && ptr[2] == 0 && ptr[1] == 0 && ptr[0] == 0)
{
_addr4.sin_family = AF_INET;
_addr4.sin_port = htons(other.sin6_port);
_addr.sin6_family = AF_INET;
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
}
else
_addr.sin6_family = AF_INET6;
}
Addr(const sockaddr& other)
{
llarp::Zero(&_addr, sizeof(sockaddr_in6));
@ -240,6 +295,38 @@ namespace llarp
&& port() == other.port();
}
Addr&
operator=(const sockaddr& other)
{
llarp::Zero(&_addr, sizeof(sockaddr_in6));
_addr.sin6_family = other.sa_family;
uint8_t* addrptr = _addr.sin6_addr.s6_addr;
uint16_t* port = &_addr.sin6_port;
switch(other.sa_family)
{
case AF_INET:
// SIIT
memcpy(12 + addrptr, &((const sockaddr_in*)(&other))->sin_addr,
sizeof(in_addr));
addrptr[11] = 0xff;
addrptr[10] = 0xff;
*port = ((sockaddr_in*)(&other))->sin_port;
_addr4.sin_family = AF_INET;
_addr4.sin_port = *port;
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
break;
case AF_INET6:
memcpy(addrptr, &((const sockaddr_in6*)(&other))->sin6_addr.s6_addr,
16);
*port = ((sockaddr_in6*)(&other))->sin6_port;
break;
// TODO : sockaddr_ll
default:
break;
}
return *this;
}
bool
sameAddr(const Addr& other) const
{
@ -283,6 +370,15 @@ namespace llarp
return byte1 == 192 && byte2 == 168;
}
socklen_t
SockLen() const
{
if(af() == AF_INET)
return sizeof(sockaddr_in);
else
return sizeof(sockaddr_in6);
}
bool
isPrivate()
{
@ -306,16 +402,23 @@ namespace llarp
{
return a.port() ^ a.addr4()->s_addr;
}
uint8_t empty[16] = {0};
static const uint8_t empty[16] = {0};
return (a.af() + memcmp(a.addr6(), empty, 16)) ^ a.port();
}
};
};
bool
AllInterfaces(int af, Addr& addr);
/// get first network interface with public address
bool
GetBestNetIF(std::string& ifname, int af = AF_INET);
/// get network interface address for network interface with ifname
bool
GetIFAddr(const std::string& ifname, Addr& addr, int af = AF_INET);
} // namespace llarp
#endif

@ -1,11 +1,12 @@
#ifndef LLARP_NODEDB_H
#define LLARP_NODEDB_H
#ifndef LLARP_NODEDB_HPP
#define LLARP_NODEDB_HPP
#include <llarp/common.h>
#include <llarp/crypto.h>
#include <llarp/router_contact.h>
#include <llarp/router_contact.hpp>
#include <llarp/router_id.hpp>
/**
* nodedb.h
* nodedb.hpp
*
* persistent storage API for router contacts
*/
@ -39,7 +40,7 @@ llarp_nodedb_store_dir(struct llarp_nodedb *n, const char *dir);
struct llarp_nodedb_iter
{
void *user;
struct llarp_rc *rc;
llarp::RouterContact *rc;
size_t index;
bool (*visit)(struct llarp_nodedb_iter *);
};
@ -48,15 +49,6 @@ struct llarp_nodedb_iter
int
llarp_nodedb_iterate_all(struct llarp_nodedb *n, struct llarp_nodedb_iter i);
/// get a random rc that is loaded
void
llarp_nodedb_get_random_rc(struct llarp_nodedb *n, struct llarp_rc *result);
/// select a random rc at hop number N
void
llarp_nodedb_select_random_hop(struct llarp_nodedb *n, struct llarp_rc *prev,
struct llarp_rc *result, size_t N);
/// return number of RC loaded
size_t
llarp_nodedb_num_loaded(struct llarp_nodedb *n);
@ -68,11 +60,11 @@ llarp_nodedb_num_loaded(struct llarp_nodedb *n);
returns true on success and false on error
*/
bool
llarp_nodedb_put_rc(struct llarp_nodedb *n, struct llarp_rc *rc);
llarp_nodedb_put_rc(struct llarp_nodedb *n, const llarp::RouterContact &rc);
/// return a pointer to an already loaded RC or nullptr if it's not there
struct llarp_rc *
llarp_nodedb_get_rc(struct llarp_nodedb *n, const byte_t *pk);
bool
llarp_nodedb_get_rc(struct llarp_nodedb *n, const llarp::RouterID &pk,
llarp::RouterContact &result);
/// struct for async rc verification
struct llarp_async_verify_rc;
@ -94,7 +86,7 @@ struct llarp_async_verify_rc
struct llarp_threadpool *diskworker;
/// router contact
struct llarp_rc rc;
llarp::RouterContact rc;
/// result
bool valid;
/// hook
@ -125,9 +117,9 @@ struct llarp_async_load_rc
/// disk worker threadpool
struct llarp_threadpool *diskworker;
/// target pubkey
byte_t pubkey[PUBKEYSIZE];
llarp::PubKey pubkey;
/// router contact result
struct llarp_rc rc;
llarp::RouterContact result;
/// set to true if we loaded the rc
bool loaded;
/// hook function called in logic thread
@ -138,4 +130,9 @@ struct llarp_async_load_rc
void
llarp_nodedb_async_load_rc(struct llarp_async_load_rc *job);
bool
llarp_nodedb_select_random_hop(struct llarp_nodedb *n,
const llarp::RouterContact &prev,
llarp::RouterContact &result, size_t N);
#endif

@ -1,28 +0,0 @@
#ifndef LLARP_PATH_H
#define LLARP_PATH_H
#include <llarp/router_contact.h>
#define MAXHOPS (8)
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
#define PATH_BUILD_TIMEOUT (10 * 1000)
#define MESSAGE_PAD_SIZE (1024)
struct llarp_path_hop
{
struct llarp_rc router;
byte_t nextHop[PUBKEYSIZE];
byte_t sessionkey[SHAREDKEYSIZE];
byte_t pathid[PATHIDSIZE];
};
struct llarp_path_hops
{
struct llarp_path_hop hops[MAXHOPS];
size_t numHops;
};
void
llarp_path_hops_free(struct llarp_path_hops* hops);
#endif

@ -1,6 +1,5 @@
#ifndef LLARP_PATH_HPP
#define LLARP_PATH_HPP
#include <llarp/path.h>
#include <llarp/router.h>
#include <llarp/time.h>
#include <llarp/aligned.hpp>
@ -10,6 +9,7 @@
#include <llarp/messages/relay_commit.hpp>
#include <llarp/path_types.hpp>
#include <llarp/pathset.hpp>
#include <llarp/pathbuilder.hpp>
#include <llarp/router_id.hpp>
#include <llarp/routing/handler.hpp>
#include <llarp/routing/message.hpp>
@ -22,6 +22,11 @@
#include <unordered_map>
#include <vector>
#define MAXHOPS (8)
#define DEFAULT_PATH_LIFETIME (10 * 60 * 1000)
#define PATH_BUILD_TIMEOUT (10 * 1000)
#define MESSAGE_PAD_SIZE (1024)
namespace llarp
{
namespace path
@ -193,7 +198,7 @@ namespace llarp
/// path id
PathID_t txID, rxID;
// router contact of router
llarp_rc router;
RouterContact rc;
// temp public encryption key
SecretKey commkey;
/// shared secret at this hop
@ -226,7 +231,7 @@ namespace llarp
llarp_time_t buildStarted;
PathStatus status;
Path(llarp_path_hops* path);
Path(const std::vector< RouterContact >& routers);
void
SetBuildResultHook(BuildResultHookFunc func);
@ -338,7 +343,7 @@ namespace llarp
/// track a path builder with this context
void
AddPathBuilder(llarp_pathbuilder_context* set);
AddPathBuilder(Builder* set);
void
AllowTransit();
@ -371,7 +376,7 @@ namespace llarp
bool
ForwardLRCM(const RouterID& nextHop,
std::deque< EncryptedFrame >& frames);
const std::array< EncryptedFrame, 8 >& frames);
bool
HopIsUs(const PubKey& k) const;
@ -386,7 +391,7 @@ namespace llarp
AddOwnPath(PathSet* set, Path* p);
void
RemovePathBuilder(llarp_pathbuilder_context* ctx);
RemovePathBuilder(Builder* ctx);
void
RemovePathSet(PathSet* set);
@ -423,7 +428,7 @@ namespace llarp
SyncTransitMap_t m_TransitPaths;
SyncTransitMap_t m_Paths;
SyncOwnedPathsMap_t m_OurPaths;
std::list< llarp_pathbuilder_context* > m_PathBuilders;
std::list< Builder* > m_PathBuilders;
bool m_AllowTransit;
};
} // namespace path

@ -1,62 +0,0 @@
#ifndef LLARP_PATHFINDER_H_
#define LLARP_PATHFINDER_H_
#include <llarp/buffer.h>
#include <llarp/path.h>
/**
* path_base.h
*
* path api functions
*/
/// forard declare
struct llarp_router;
struct llarp_dht_context;
// fwd declr
struct llarp_pathbuilder_context;
/// alloc
struct llarp_pathbuilder_context*
llarp_pathbuilder_context_new(struct llarp_router* router,
struct llarp_dht_context* dht, size_t numpaths,
size_t defaultNumHops);
/// dealloc
void
llarp_pathbuilder_context_free(struct llarp_pathbuilder_context* ctx);
// fwd declr
struct llarp_pathbuild_job;
/// response callback
typedef void (*llarp_pathbuilder_hook)(struct llarp_pathbuild_job*);
// select hop function (user, nodedb, prevhop, result, hopnnumber) called in
// logic thread
typedef bool (*llarp_pathbuilder_select_hop_func)(void*, struct llarp_nodedb*,
struct llarp_rc*,
struct llarp_rc*, size_t);
// request struct
struct llarp_pathbuild_job
{
// opaque pointer for user data
void* user;
// router context (set by llarp_pathbuilder_build_path)
struct llarp_router* router;
// context
struct llarp_pathbuilder_context* context;
// path hop selection
llarp_pathbuilder_select_hop_func selectHop;
// called when the path build started
llarp_pathbuilder_hook pathBuildStarted;
// path
struct llarp_path_hops hops;
};
/// request func
// or find_path but thought pathfinder_find_path was a bit redundant
void
llarp_pathbuilder_build_path(struct llarp_pathbuild_job* job);
#endif

@ -1,37 +1,41 @@
#ifndef LLARP_PATHBUILDER_HPP_
#define LLARP_PATHBUILDER_HPP_
#include <llarp/pathbuilder.h>
#include <llarp/router.h>
#include <llarp/path.hpp>
#include <llarp/pathset.hpp>
struct llarp_pathbuilder_context : public llarp::path::PathSet
namespace llarp
{
struct llarp_router* router;
struct llarp_dht_context* dht;
llarp::SecretKey enckey;
size_t numHops;
/// construct
llarp_pathbuilder_context(llarp_router* p_router,
struct llarp_dht_context* p_dht, size_t numPaths,
size_t numHops);
virtual ~llarp_pathbuilder_context();
virtual bool
SelectHop(llarp_nodedb* db, llarp_rc* prev, llarp_rc* cur, size_t hop);
virtual bool
ShouldBuildMore() const;
void
BuildOne();
void
ManualRebuild(size_t N);
virtual byte_t*
GetTunnelEncryptionSecretKey();
};
namespace path
{
struct Builder : public PathSet
{
struct llarp_router* router;
struct llarp_dht_context* dht;
llarp::SecretKey enckey;
size_t numHops;
/// construct
Builder(llarp_router* p_router, struct llarp_dht_context* p_dht,
size_t numPaths, size_t numHops);
virtual ~Builder();
virtual bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop);
virtual bool
ShouldBuildMore() const;
void
BuildOne();
void
ManualRebuild(size_t N);
virtual const byte_t*
GetTunnelEncryptionSecretKey() const;
};
} // namespace path
} // namespace llarp
#endif

@ -8,6 +8,7 @@
#include <llarp/routing/message.hpp>
#include <llarp/service/IntroSet.hpp>
#include <llarp/service/lookup.hpp>
#include <llarp/dht/messages/all.hpp>
#include <map>
#include <tuple>
@ -114,17 +115,9 @@ namespace llarp
}
virtual bool
SelectHop(llarp_nodedb* db, llarp_rc* prev, llarp_rc* cur,
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop) = 0;
static bool
SelectHopCallback(void* user, llarp_nodedb* db, llarp_rc* prev,
llarp_rc* cur, size_t hopno)
{
PathSet* self = static_cast< PathSet* >(user);
return self->SelectHop(db, prev, cur, hopno);
}
private:
typedef std::pair< RouterID, PathID_t > PathInfo_t;
typedef std::map< PathInfo_t, Path* > PathMap_t;

@ -3,11 +3,10 @@
#include <llarp/config.h>
#include <llarp/ev.h>
#include <llarp/logic.h>
#include <llarp/nodedb.h>
#include <llarp/pathbuilder.h>
#include <llarp/router_contact.h>
#include <llarp/threadpool.h>
#include <llarp/buffer.h>
struct llarp_nodedb;
struct llarp_router;
bool
@ -19,16 +18,6 @@ llarp_init_router(struct llarp_threadpool *worker,
struct llarp_ev_loop *netloop, struct llarp_logic *logic);
void
llarp_free_router(struct llarp_router **router);
bool
llarp_router_try_connect(struct llarp_router *router, struct llarp_rc *remote,
uint16_t numretries);
/// override default path builder function (FFI)
void
llarp_router_override_path_selection(struct llarp_router *router,
llarp_pathbuilder_select_hop_func func);
bool
llarp_configure_router(struct llarp_router *router, struct llarp_config *conf);
@ -38,15 +27,4 @@ llarp_run_router(struct llarp_router *router, struct llarp_nodedb *nodedb);
void
llarp_stop_router(struct llarp_router *router);
struct llarp_router_link_iter
{
void *user;
bool (*visit)(struct llarp_router_link_iter *, struct llarp_router *,
struct llarp_link *);
};
void
llarp_router_iterate_links(struct llarp_router *router,
struct llarp_router_link_iter iter);
#endif

@ -1,115 +0,0 @@
#ifndef LLARP_RC_H
#define LLARP_RC_H
#include <llarp/address_info.h>
#include <llarp/crypto.h>
#include <llarp/exit_info.h>
#ifdef __cplusplus
#include <string>
#endif
// forward declare
struct llarp_alloc;
struct llarp_rc;
#define MAX_RC_SIZE (1024)
#define NICKLEN (32)
bool
llarp_rc_bdecode(struct llarp_rc *rc, llarp_buffer_t *buf);
bool
llarp_rc_bencode(const struct llarp_rc *rc, llarp_buffer_t *buf);
struct llarp_rc
{
struct llarp_ai_list *addrs;
// public encryption public key
byte_t enckey[PUBKEYSIZE];
// public signing public key
byte_t pubkey[PUBKEYSIZE];
struct llarp_xi_list *exits;
byte_t signature[SIGSIZE];
/// node nickname, yw kee
byte_t nickname[NICKLEN];
uint64_t last_updated;
#ifdef __cplusplus
bool
BEncode(llarp_buffer_t *buf) const
{
return llarp_rc_bencode(this, buf);
}
bool
BDecode(llarp_buffer_t *buf)
{
return llarp_rc_bdecode(this, buf);
}
bool
HasNick() const
{
return nickname[0] != 0;
}
std::string
Nick() const
{
const char *nick = (const char *)nickname;
return std::string(nick, strnlen(nick, sizeof(nickname)));
}
#endif
};
void
llarp_rc_free(struct llarp_rc *rc);
bool
llarp_rc_new(struct llarp_rc *rc);
bool
llarp_rc_verify_sig(struct llarp_crypto *crypto, struct llarp_rc *rc);
void
llarp_rc_copy(struct llarp_rc *dst, const struct llarp_rc *src);
bool
llarp_rc_is_public_router(const struct llarp_rc *const rc);
void
llarp_rc_set_addrs(struct llarp_rc *rc, struct llarp_alloc *mem,
struct llarp_ai_list *addr);
bool
llarp_rc_set_nickname(struct llarp_rc *rc, const char *name);
void
llarp_rc_set_pubenckey(struct llarp_rc *rc, const uint8_t *pubenckey);
void
llarp_rc_set_pubsigkey(struct llarp_rc *rc, const uint8_t *pubkey);
/// combo
void
llarp_rc_set_pubkey(struct llarp_rc *rc, const uint8_t *pubenckey,
const uint8_t *pubsigkey);
void
llarp_rc_sign(struct llarp_crypto *crypto, const byte_t *seckey,
struct llarp_rc *rc);
void
llarp_rc_clear(struct llarp_rc *rc);
bool
llarp_rc_addr_list_iter(struct llarp_ai_list_iter *iter, struct llarp_ai *ai);
bool
llarp_rc_read(const char *fpath, struct llarp_rc *result);
bool
llarp_rc_write(struct llarp_rc *rc, const char *our_rc_file);
#endif

@ -0,0 +1,95 @@
#ifndef LLARP_RC_HPP
#define LLARP_RC_HPP
#include <llarp/address_info.hpp>
#include <llarp/crypto.h>
#include <llarp/bencode.hpp>
#include <llarp/exit_info.hpp>
#include <vector>
#define MAX_RC_SIZE (1024)
#define NICKLEN (32)
namespace llarp
{
struct RouterContact : public IBEncodeMessage
{
RouterContact() : IBEncodeMessage()
{
Clear();
}
RouterContact(const RouterContact &other)
: addrs(other.addrs)
, enckey(other.enckey)
, pubkey(other.pubkey)
, exits(other.exits)
, signature(other.signature)
, nickname(other.nickname)
, last_updated(other.last_updated)
{
version = other.version;
}
// advertised addresses
std::vector< AddressInfo > addrs = {};
// public encryption public key
llarp::PubKey enckey;
// public signing public key
llarp::PubKey pubkey;
// advertised exits
std::vector< ExitInfo > exits = {};
// signature
llarp::Signature signature;
/// node nickname, yw kee
llarp::AlignedBuffer< NICKLEN > nickname;
uint64_t last_updated;
bool
BEncode(llarp_buffer_t *buf) const;
void
Clear();
bool
BDecode(llarp_buffer_t *buf)
{
Clear();
return IBEncodeMessage::BDecode(buf);
}
bool
DecodeKey(llarp_buffer_t k, llarp_buffer_t *buf);
RouterContact &
operator=(const RouterContact &other);
bool
HasNick() const;
std::string
Nick() const;
bool
IsPublicRouter() const;
void
SetNick(const std::string &nick);
bool
VerifySignature(llarp_crypto *crypto) const;
bool
Sign(llarp_crypto *crypto, const llarp::SecretKey &secret);
bool
Read(const char *fname);
bool
Write(const char *fname) const;
};
} // namespace llarp
#endif

@ -18,7 +18,8 @@ namespace llarp
public:
ServiceInfo() = default;
ServiceInfo(const ServiceInfo&& other)
ServiceInfo(ServiceInfo&& other) = delete;
/*
{
enckey = std::move(other.enckey);
signkey = std::move(other.signkey);
@ -26,14 +27,15 @@ namespace llarp
vanity = std::move(other.vanity);
m_CachedAddr = std::move(other.m_CachedAddr);
}
*/
ServiceInfo(const ServiceInfo& other)
: enckey(other.enckey)
, signkey(other.signkey)
, vanity(other.vanity)
, m_CachedAddr(other.m_CachedAddr)
{
enckey = other.enckey;
signkey = other.signkey;
version = other.version;
vanity = other.vanity;
m_CachedAddr = other.m_CachedAddr;
version = other.version;
}
void
@ -137,4 +139,4 @@ namespace llarp
} // namespace service
} // namespace llarp
#endif
#endif

@ -5,12 +5,13 @@
#include <llarp/service/Identity.hpp>
#include <llarp/service/handler.hpp>
#include <llarp/service/protocol.hpp>
#include <llarp/path.hpp>
namespace llarp
{
namespace service
{
struct Endpoint : public llarp_pathbuilder_context,
struct Endpoint : public path::Builder,
public ILookupHolder,
public IDataHandler
{
@ -145,7 +146,7 @@ namespace llarp
typedef std::queue< PendingBuffer > PendingBufferQueue;
/// context needed to initiate an outbound hidden service session
struct OutboundContext : public llarp_pathbuilder_context
struct OutboundContext : public path::Builder
{
OutboundContext(const IntroSet& introSet, Endpoint* parent);
~OutboundContext();
@ -176,7 +177,8 @@ namespace llarp
HandlePathBuilt(path::Path* path);
bool
SelectHop(llarp_nodedb* db, llarp_rc* prev, llarp_rc* cur, size_t hop);
SelectHop(llarp_nodedb* db, const RouterContact& prev,
RouterContact& cur, size_t hop);
bool
HandleHiddenServiceFrame(const ProtocolFrame* frame);

@ -67,4 +67,4 @@ namespace llarp
} // namespace service
} // namespace llarp
#endif
#endif

@ -0,0 +1,227 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __UTP_H__
#define __UTP_H__
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdarg.h>
#include "utp_types.h"
typedef struct UTPSocket utp_socket;
typedef struct struct_utp_context utp_context;
enum
{
UTP_UDP_DONTFRAG = 2, // Used to be a #define as UDP_IP_DONTFRAG
};
enum
{
// socket has reveived syn-ack (notification only for outgoing connection
// completion) this implies writability
UTP_STATE_CONNECT = 1,
// socket is able to send more data
UTP_STATE_WRITABLE = 2,
// connection closed
UTP_STATE_EOF = 3,
// socket is being destroyed, meaning all data has been sent if possible.
// it is not valid to refer to the socket after this state change occurs
UTP_STATE_DESTROYING = 4,
};
extern const char *utp_state_names[];
// Errors codes that can be passed to UTP_ON_ERROR callback
enum
{
UTP_ECONNREFUSED = 0,
UTP_ECONNRESET,
UTP_ETIMEDOUT,
};
extern const char *utp_error_code_names[];
enum
{
// callback names
UTP_ON_FIREWALL = 0,
UTP_ON_ACCEPT,
UTP_ON_CONNECT,
UTP_ON_ERROR,
UTP_ON_READ,
UTP_ON_OVERHEAD_STATISTICS,
UTP_ON_STATE_CHANGE,
UTP_GET_READ_BUFFER_SIZE,
UTP_ON_DELAY_SAMPLE,
UTP_GET_UDP_MTU,
UTP_GET_UDP_OVERHEAD,
UTP_GET_MILLISECONDS,
UTP_GET_MICROSECONDS,
UTP_GET_RANDOM,
UTP_LOG,
UTP_SENDTO,
// context and socket options that may be set/queried
UTP_LOG_NORMAL,
UTP_LOG_MTU,
UTP_LOG_DEBUG,
UTP_SNDBUF,
UTP_RCVBUF,
UTP_TARGET_DELAY,
UTP_ARRAY_SIZE, // must be last
};
extern const char *utp_callback_names[];
typedef struct
{
utp_context *context;
utp_socket *socket;
size_t len;
uint32 flags;
int callback_type;
const byte *buf;
union {
const struct sockaddr *address;
int send;
int sample_ms;
int error_code;
int state;
};
union {
socklen_t address_len;
int type;
};
} utp_callback_arguments;
typedef uint64
utp_callback_t(utp_callback_arguments *);
// Returned by utp_get_context_stats()
typedef struct
{
uint32 _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU
// bytes fpr all connections (context-wide)
uint32 _nraw_send[5]; // total packets sent less than 300/600/1200/MTU
// bytes for all connections (context-wide)
} utp_context_stats;
// Returned by utp_get_stats()
typedef struct
{
uint64 nbytes_recv; // total bytes received
uint64 nbytes_xmit; // total bytes transmitted
uint32 rexmit; // retransmit counter
uint32 fastrexmit; // fast retransmit counter
uint32 nxmit; // transmit counter
uint32 nrecv; // receive counter (total)
uint32 nduprecv; // duplicate receive counter
uint32 mtu_guess; // Best guess at MTU
} utp_socket_stats;
#define UTP_IOV_MAX 1024
// For utp_writev, to writes data from multiple buffers
struct utp_iovec
{
void *iov_base;
size_t iov_len;
};
// Public Functions
utp_context *
utp_init(int version);
void
utp_destroy(utp_context *ctx);
void
utp_set_callback(utp_context *ctx, int callback_name, utp_callback_t *proc);
void *
utp_context_set_userdata(utp_context *ctx, void *userdata);
void *
utp_context_get_userdata(utp_context *ctx);
int
utp_context_set_option(utp_context *ctx, int opt, int val);
int
utp_context_get_option(utp_context *ctx, int opt);
int
utp_process_udp(utp_context *ctx, const byte *buf, size_t len,
const struct sockaddr *to, socklen_t tolen);
int
utp_process_icmp_error(utp_context *ctx, const byte *buffer, size_t len,
const struct sockaddr *to, socklen_t tolen);
int
utp_process_icmp_fragmentation(utp_context *ctx, const byte *buffer,
size_t len, const struct sockaddr *to,
socklen_t tolen, uint16 next_hop_mtu);
void
utp_check_timeouts(utp_context *ctx);
void
utp_issue_deferred_acks(utp_context *ctx);
utp_context_stats *
utp_get_context_stats(utp_context *ctx);
utp_socket *
utp_create_socket(utp_context *ctx);
void *
utp_set_userdata(utp_socket *s, void *userdata);
void *
utp_get_userdata(utp_socket *s);
int
utp_setsockopt(utp_socket *s, int opt, int val);
int
utp_getsockopt(utp_socket *s, int opt);
int
utp_connect(utp_socket *s, const struct sockaddr *to, socklen_t tolen);
ssize_t
utp_write(utp_socket *s, void *buf, size_t count);
ssize_t
utp_writev(utp_socket *s, struct utp_iovec *iovec, size_t num_iovecs);
int
utp_getpeername(utp_socket *s, struct sockaddr *addr, socklen_t *addrlen);
void
utp_read_drained(utp_socket *s);
int
utp_get_delays(utp_socket *s, uint32 *ours, uint32 *theirs, uint32 *age);
utp_socket_stats *
utp_get_stats(utp_socket *s);
utp_context *
utp_get_context(utp_socket *s);
void
utp_shutdown(utp_socket *s, int how);
void
utp_close(utp_socket *s);
#ifdef __cplusplus
}
#endif
#endif //__UTP_H__

@ -0,0 +1,123 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __UTP_TYPES_H__
#define __UTP_TYPES_H__
// Allow libutp consumers or prerequisites to override PACKED_ATTRIBUTE
#ifndef PACKED_ATTRIBUTE
#if defined BROKEN_GCC_STRUCTURE_PACKING && defined __GNUC__
// Used for gcc tool chains accepting but not supporting pragma pack
// See http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
#define PACKED_ATTRIBUTE __attribute__((__packed__))
#else
#define PACKED_ATTRIBUTE
#endif // defined BROKEN_GCC_STRUCTURE_PACKING && defined __GNUC__
#endif // ndef PACKED_ATTRIBUTE
#ifdef __GNUC__
#define ALIGNED_ATTRIBUTE(x) __attribute__((aligned(x)))
#else
#define ALIGNED_ATTRIBUTE(x)
#endif
// hash.cpp needs socket definitions, which is why this networking specific
// code is inclued in utypes.h
#ifdef WIN32
#define _CRT_SECURE_NO_DEPRECATE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
#define SHUT_RD SD_RECEIVE
#define SHUT_WR SD_SEND
#define SHUT_RDWR SD_BOTH
#else
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#ifdef IP_DONTFRAG
#define IP_OPT_DONTFRAG IP_DONTFRAG
#elif defined IP_DONTFRAGMENT
#define IP_OPT_DONTFRAG IP_DONTFRAGMENT
#else
//#warning "I don't know how to set DF bit on this system"
#endif
#endif
#ifdef _MSC_VER
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#ifdef POSIX
typedef struct sockaddr_storage SOCKADDR_STORAGE;
#endif
#ifdef WIN32
#define I64u "%I64u"
#else
#define I64u "%Lu"
#endif
// standard types
typedef unsigned char byte;
typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short uint16;
typedef signed short int16;
typedef unsigned int uint;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef _MSC_VER
typedef unsigned __int64 uint64;
typedef signed __int64 int64;
#else
typedef unsigned long long uint64;
typedef long long int64;
#endif
/* compile-time assert */
#ifndef CASSERT
#define CASSERT(exp, name) typedef int is_not_##name[(exp) ? 1 : -1];
#endif
CASSERT(8 == sizeof(uint64), sizeof_uint64_is_8)
CASSERT(8 == sizeof(int64), sizeof_int64_is_8)
#ifndef INT64_MAX
#define INT64_MAX 0x7fffffffffffffffLL
#endif
// always ANSI
typedef const char* cstr;
typedef char* str;
#ifndef __cplusplus
typedef uint8 bool;
#endif
#endif //__UTP_TYPES_H__

@ -0,0 +1,19 @@
Copyright (c) 2010-2013 BitTorrent, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -0,0 +1,48 @@
OBJS = utp_internal.o utp_utils.o utp_hash.o utp_callbacks.o utp_api.o utp_packedsockaddr.o
CFLAGS = -Wall -DPOSIX -g -fno-exceptions $(OPT)
OPT ?= -O3
CXXFLAGS = $(CFLAGS) -fPIC -fno-rtti
CC = gcc
CXX = g++
CXXFLAGS += -Wno-sign-compare
CXXFLAGS += -fpermissive
# Uncomment to enable utp_get_stats(), and a few extra sanity checks
#CFLAGS += -D_DEBUG
# Uncomment to enable debug logging
#CFLAGS += -DUTP_DEBUG_LOGGING
# Dynamically determine if librt is available. If so, assume we need to link
# against it for clock_gettime(2). This is required for clean builds on OSX;
# see <https://github.com/bittorrent/libutp/issues/1> for more. This should
# probably be ported to CMake at some point, but is suitable for now.
lrt := $(shell echo 'int main() {}' | $(CC) -xc -o /dev/null - -lrt >/dev/null 2>&1; echo $$?)
ifeq ($(strip $(lrt)),0)
LDFLAGS += -lrt
endif
all: libutp.so libutp.a ucat ucat-static
libutp.so: $(OBJS)
$(CXX) $(CXXFLAGS) -o libutp.so -shared $(OBJS)
libutp.a: $(OBJS)
ar rvs libutp.a $(OBJS)
ucat: ucat.o libutp.so
$(CC) $(CFLAGS) -o ucat ucat.o -L. -lutp $(LDFLAGS)
ucat-static: ucat.o libutp.a
$(CXX) $(CXXFLAGS) -o ucat-static ucat.o libutp.a $(LDFLAGS)
clean:
rm -f *.o libutp.so libutp.a ucat ucat-static
tags: $(shell ls *.cpp *.h)
rm -f tags
ctags *.cpp *.h
anyway: clean all
.PHONY: clean all anyway

@ -0,0 +1,68 @@
# libutp - The uTorrent Transport Protocol library.
Copyright (c) 2010 BitTorrent, Inc.
uTP is a TCP-like implementation of [LEDBAT][ledbat] documented as a BitTorrent
extension in [BEP-29][bep29]. uTP provides reliable, ordered delivery
while maintaining minimum extra delay. It is implemented on top of UDP to be
cross-platform and functional today. As a result, uTP is the primary transport
for uTorrent peer-to-peer connections.
uTP is written in C++, but the external interface is strictly C (ANSI C89).
## The Interface
The uTP socket interface is a bit different from the Berkeley socket API to
avoid the need for our own select() implementation, and to make it easier to
write event-based code with minimal buffering.
When you create a uTP socket, you register a set of callbacks. Most notably, the
on_read callback is a reactive callback which occurs when bytes arrive off the
network. The write side of the socket is proactive, and you call UTP_Write to
indicate the number of bytes you wish to write. As packets are created, the
on_write callback is called for each packet, so you can fill the buffers with
data.
The libutp interface is not thread-safe. It was designed for use in a
single-threaded asyncronous context, although with proper synchronization
it may be used from a multi-threaded environment as well.
See utp.h for more details and other API documentation.
## Example
See ucat.c. Build with:
make ucat
## Building
uTP has been known to build on Windows with MSVC and on linux and OS X with gcc.
On Windows, use the MSVC project files (utp.sln, and friends). On other platforms,
building the shared library is as simple as:
make
To build one of the examples, which will statically link in everything it needs
from libutp:
cd utp_test && make
## Packaging and API
The libutp API is considered unstable, and probably always will be. We encourage
you to test with the version of libutp you have, and be mindful when upgrading.
For this reason, it is probably also a good idea to bundle libutp with your
application.
## License
libutp is released under the [MIT][lic] license.
## Related Work
Research and analysis of congestion control mechanisms can be found [here.][survey]
[ledbat]: http://datatracker.ietf.org/wg/ledbat/charter/
[bep29]: http://www.bittorrent.org/beps/bep_0029.html
[lic]: http://www.opensource.org/licenses/mit-license.php
[survey]: http://datatracker.ietf.org/doc/draft-ietf-ledbat-survey/

@ -0,0 +1,108 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include "libutp_inet_ntop.h"
//######################################################################
const char *libutp::inet_ntop(int af, const void *src, char *dest, size_t length)
{
if (af != AF_INET && af != AF_INET6)
{
return NULL;
}
SOCKADDR_STORAGE address;
DWORD address_length;
if (af == AF_INET)
{
address_length = sizeof(sockaddr_in);
sockaddr_in* ipv4_address = (sockaddr_in*)(&address);
ipv4_address->sin_family = AF_INET;
ipv4_address->sin_port = 0;
memcpy(&ipv4_address->sin_addr, src, sizeof(in_addr));
}
else // AF_INET6
{
address_length = sizeof(sockaddr_in6);
sockaddr_in6* ipv6_address = (sockaddr_in6*)(&address);
ipv6_address->sin6_family = AF_INET6;
ipv6_address->sin6_port = 0;
ipv6_address->sin6_flowinfo = 0;
// hmmm
ipv6_address->sin6_scope_id = 0;
memcpy(&ipv6_address->sin6_addr, src, sizeof(in6_addr));
}
DWORD string_length = (DWORD)(length);
int result;
result = WSAAddressToStringA((sockaddr*)(&address),
address_length, 0, dest,
&string_length);
// one common reason for this to fail is that ipv6 is not installed
return result == SOCKET_ERROR ? NULL : dest;
}
//######################################################################
int libutp::inet_pton(int af, const char* src, void* dest)
{
if (af != AF_INET && af != AF_INET6)
{
return -1;
}
SOCKADDR_STORAGE address;
int address_length = sizeof(SOCKADDR_STORAGE);
int result = WSAStringToAddressA((char*)(src), af, 0,
(sockaddr*)(&address),
&address_length);
if (af == AF_INET)
{
if (result != SOCKET_ERROR)
{
sockaddr_in* ipv4_address =(sockaddr_in*)(&address);
memcpy(dest, &ipv4_address->sin_addr, sizeof(in_addr));
}
else if (strcmp(src, "255.255.255.255") == 0)
{
((in_addr*)(dest))->s_addr = INADDR_NONE;
}
}
else // AF_INET6
{
if (result != SOCKET_ERROR)
{
sockaddr_in6* ipv6_address = (sockaddr_in6*)(&address);
memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr));
}
}
return result == SOCKET_ERROR ? -1 : 1;
}

@ -0,0 +1,68 @@
#ifndef LIBUTP_INET_NTOP_H
#define LIBUTP_INET_NTOP_H
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// About us linking the system inet_pton and inet_ntop symbols:
// 1) These symbols are usually defined on POSIX systems
// 2) They are not defined on Windows versions earlier than Vista
// Defined in:
// ut_utils/src/sockaddr.cpp
// libutp/win32_inet_ntop.obj
//
// When we drop support for XP we can just #include <ws2tcpip.h>, and use the system functions
// For now, we will always use our functions on windows, on all builds
// The reason is: we would like the debug build to behave as much as the release build as possible
// It is much better to catch a problem in the debug build, than to link the system version
// in debug, and our version int he wild.
#if defined(_WIN32_WINNT)
#if _WIN32_WINNT >= 0x600 // Win32, post-XP
#include <ws2tcpip.h> // for inet_ntop, inet_pton
#define INET_NTOP inet_ntop
#define INET_PTON inet_pton
#else
#define INET_NTOP libutp::inet_ntop // Win32, pre-XP: Use ours
#define INET_PTON libutp::inet_pton
#endif
#else // not WIN32
#include <arpa/inet.h> // for inet_ntop, inet_pton
#define INET_NTOP inet_ntop
#define INET_PTON inet_pton
#endif
//######################################################################
//######################################################################
namespace libutp {
//######################################################################
const char *inet_ntop(int af, const void *src, char *dest, size_t length);
//######################################################################
int inet_pton(int af, const char* src, void* dest);
} //namespace libutp
#endif // LIBUTP_INET_NTOP_H

@ -0,0 +1,288 @@
import os, sys, time
# usage: parse_log.py log-file [socket-index to focus on]
socket_filter = None
if len(sys.argv) >= 3:
socket_filter = sys.argv[2].strip()
if socket_filter == None:
print "scanning for socket with the most packets"
file = open(sys.argv[1], 'rb')
sockets = {}
for l in file:
if not 'our_delay' in l: continue
try:
a = l.strip().split(" ")
socket_index = a[1][:-1]
except:
continue
# msvc's runtime library doesn't prefix pointers
# with '0x'
# if socket_index[:2] != '0x':
# continue
if socket_index in sockets:
sockets[socket_index] += 1
else:
sockets[socket_index] = 1
items = sockets.items()
items.sort(lambda x, y: y[1] - x[1])
count = 0
for i in items:
print '%s: %d' % (i[0], i[1])
count += 1
if count > 5: break
file.close()
socket_filter = items[0][0]
print '\nfocusing on socket %s' % socket_filter
file = open(sys.argv[1], 'rb')
out_file = 'utp.out%s' % socket_filter;
out = open(out_file, 'wb')
delay_samples = 'dots lc rgb "blue"'
delay_base = 'steps lw 2 lc rgb "purple"'
target_delay = 'steps lw 2 lc rgb "red"'
off_target = 'dots lc rgb "blue"'
cwnd = 'steps lc rgb "green"'
window_size = 'steps lc rgb "sea-green"'
rtt = 'lines lc rgb "light-blue"'
metrics = {
'our_delay':['our delay (ms)', 'x1y2', delay_samples],
'upload_rate':['send rate (B/s)', 'x1y1', 'lines'],
'max_window':['cwnd (B)', 'x1y1', cwnd],
'target_delay':['target delay (ms)', 'x1y2', target_delay],
'cur_window':['bytes in-flight (B)', 'x1y1', window_size],
'cur_window_packets':['number of packets in-flight', 'x1y2', 'steps'],
'packet_size':['current packet size (B)', 'x1y2', 'steps'],
'rtt':['rtt (ms)', 'x1y2', rtt],
'off_target':['off-target (ms)', 'x1y2', off_target],
'delay_sum':['delay sum (ms)', 'x1y2', 'steps'],
'their_delay':['their delay (ms)', 'x1y2', delay_samples],
'get_microseconds':['clock (us)', 'x1y1', 'steps'],
'wnduser':['advertised window size (B)', 'x1y1', 'steps'],
'delay_base':['delay base (us)', 'x1y1', delay_base],
'their_delay_base':['their delay base (us)', 'x1y1', delay_base],
'their_actual_delay':['their actual delay (us)', 'x1y1', delay_samples],
'actual_delay':['actual_delay (us)', 'x1y1', delay_samples]
}
histogram_quantization = 1
socket_index = None
columns = []
begin = None
title = "-"
packet_loss = 0
packet_timeout = 0
delay_histogram = {}
window_size = {'0': 0, '1': 0}
# [35301484] 0x00ec1190: actual_delay:1021583 our_delay:102 their_delay:-1021345 off_target:297 max_window:2687 upload_rate:18942 delay_base:1021481154 delay_sum:-1021242 target_delay:400 acked_bytes:1441 cur_window:2882 scaled_gain:2.432
counter = 0
print "reading log file"
for l in file:
if "UTP_Connect" in l:
title = l[:-2]
if socket_filter != None:
title += ' socket: %s' % socket_filter
else:
title += ' sum of all sockets'
continue
try:
a = l.strip().split(" ")
t = a[0][1:-1]
socket_index = a[1][:-1]
except:
continue
# if socket_index[:2] != '0x':
# continue
if socket_filter != None and socket_index != socket_filter:
continue
counter += 1
if (counter % 300 == 0):
print "\r%d " % counter,
if "lost." in l:
packet_loss = packet_loss + 1
continue
if "Packet timeout" in l:
packet_timeout = packet_timeout + 1
continue
if "our_delay:" not in l:
continue
# used for Logf timestamps
# t, m = t.split(".")
# t = time.strptime(t, "%H:%M:%S")
# t = list(t)
# t[0] += 107
# t = tuple(t)
# m = float(m)
# m /= 1000.0
# t = time.mktime(t) + m
# used for tick count timestamps
t = int(t)
if begin is None:
begin = t
t = t - begin
# print time. Convert from milliseconds to seconds
print >>out, '%f\t' % (float(t)/1000.),
#if t > 200000:
# break
fill_columns = not columns
for i in a[2:]:
try:
n, v = i.split(':')
except:
continue
v = float(v)
if n == "our_delay":
bucket = v / histogram_quantization
delay_histogram[bucket] = 1 + delay_histogram.get(bucket, 0)
if not n in metrics: continue
if fill_columns:
columns.append(n)
if n == "max_window":
window_size[socket_index] = v
print >>out, '%f\t' % int(reduce(lambda a,b: a+b, window_size.values())),
else:
print >>out, '%f\t' % v,
print >>out, float(packet_loss * 8000), float(packet_timeout * 8000)
packet_loss = 0
packet_timeout = 0
out.close()
out = open('%s.histogram' % out_file, 'wb')
for d,f in delay_histogram.iteritems():
print >>out, float(d*histogram_quantization) + histogram_quantization / 2, f
out.close()
plot = [
{
'data': ['upload_rate', 'max_window', 'cur_window', 'wnduser', 'cur_window_packets', 'packet_size', 'rtt'],
'title': 'send-packet-size',
'y1': 'Bytes',
'y2': 'Time (ms)'
},
{
'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'wnduser', 'cur_window_packets'],
'title': 'uploading',
'y1': 'Bytes',
'y2': 'Time (ms)'
},
{
'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'cur_window_packets'],
'title': 'uploading_packets',
'y1': 'Bytes',
'y2': 'Time (ms)'
},
{
'data': ['get_microseconds'],
'title': 'timer',
'y1': 'Time microseconds',
'y2': 'Time (ms)'
},
{
'data': ['their_delay', 'target_delay', 'rtt'],
'title': 'their_delay',
'y1': '',
'y2': 'Time (ms)'
},
{
'data': ['their_actual_delay','their_delay_base'],
'title': 'their_delay_base',
'y1': 'Time (us)',
'y2': ''
},
{
'data': ['our_delay', 'target_delay', 'rtt'],
'title': 'our-delay',
'y1': '',
'y2': 'Time (ms)'
},
{
'data': ['actual_delay', 'delay_base'],
'title': 'our_delay_base',
'y1': 'Time (us)',
'y2': ''
}
]
out = open('utp.gnuplot', 'w+')
files = ''
#print >>out, 'set xtics 0, 20'
print >>out, "set term png size 1280,800"
print >>out, 'set output "%s.delays.png"' % out_file
print >>out, 'set xrange [0:250]'
print >>out, 'set xlabel "delay (ms)"'
print >>out, 'set boxwidth 1'
print >>out, 'set style fill solid'
print >>out, 'set ylabel "number of packets"'
print >>out, 'plot "%s.histogram" using 1:2 with boxes' % out_file
print >>out, "set style data steps"
#print >>out, "set yrange [0:*]"
print >>out, "set y2range [*:*]"
files += out_file + '.delays.png '
#set hidden3d
#set title "Peer bandwidth distribution"
#set xlabel "Ratio"
for p in plot:
print >>out, 'set title "%s %s"' % (p['title'], title)
print >>out, 'set xlabel "time (s)"'
print >>out, 'set ylabel "%s"' % p['y1']
print >>out, "set tics nomirror"
print >>out, 'set y2tics'
print >>out, 'set y2label "%s"' % p['y2']
print >>out, 'set xrange [0:*]'
print >>out, "set key box"
print >>out, "set term png size 1280,800"
print >>out, 'set output "%s-%s.png"' % (out_file, p['title'])
files += '%s-%s.png ' % (out_file, p['title'])
comma = ''
print >>out, "plot",
for c in p['data']:
if not c in metrics: continue
i = columns.index(c)
print >>out, '%s"%s" using 1:%d title "%s-%s" axes %s with %s' % (comma, out_file, i + 2, metrics[c][0], metrics[c][1], metrics[c][1], metrics[c][2]),
comma = ', '
print >>out, ''
out.close()
os.system("gnuplot utp.gnuplot")
os.system("open %s" % files)

@ -0,0 +1,139 @@
// vim:set ts=4 sw=4 ai:
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "utp_internal.h"
#include "utp_utils.h"
extern "C" {
const char * utp_callback_names[] = {
"UTP_ON_FIREWALL",
"UTP_ON_ACCEPT",
"UTP_ON_CONNECT",
"UTP_ON_ERROR",
"UTP_ON_READ",
"UTP_ON_OVERHEAD_STATISTICS",
"UTP_ON_STATE_CHANGE",
"UTP_GET_READ_BUFFER_SIZE",
"UTP_ON_DELAY_SAMPLE",
"UTP_GET_UDP_MTU",
"UTP_GET_UDP_OVERHEAD",
"UTP_GET_MILLISECONDS",
"UTP_GET_MICROSECONDS",
"UTP_GET_RANDOM",
"UTP_LOG",
"UTP_SENDTO",
};
const char * utp_error_code_names[] = {
"UTP_ECONNREFUSED",
"UTP_ECONNRESET",
"UTP_ETIMEDOUT",
};
const char *utp_state_names[] = {
NULL,
"UTP_STATE_CONNECT",
"UTP_STATE_WRITABLE",
"UTP_STATE_EOF",
"UTP_STATE_DESTROYING",
};
struct_utp_context::struct_utp_context()
: userdata(NULL)
, current_ms(0)
, last_utp_socket(NULL)
, log_normal(false)
, log_mtu(false)
, log_debug(false)
{
memset(&context_stats, 0, sizeof(context_stats));
memset(callbacks, 0, sizeof(callbacks));
target_delay = CCONTROL_TARGET;
utp_sockets = new UTPSocketHT;
callbacks[UTP_GET_UDP_MTU] = &utp_default_get_udp_mtu;
callbacks[UTP_GET_UDP_OVERHEAD] = &utp_default_get_udp_overhead;
callbacks[UTP_GET_MILLISECONDS] = &utp_default_get_milliseconds;
callbacks[UTP_GET_MICROSECONDS] = &utp_default_get_microseconds;
callbacks[UTP_GET_RANDOM] = &utp_default_get_random;
// 1 MB of receive buffer (i.e. max bandwidth delay product)
// means that from a peer with 200 ms RTT, we cannot receive
// faster than 5 MB/s
// from a peer with 10 ms RTT, we cannot receive faster than
// 100 MB/s. This is assumed to be good enough, since bandwidth
// often is proportional to RTT anyway
// when setting a download rate limit, all sockets should have
// their receive buffer set much lower, to say 60 kiB or so
opt_rcvbuf = opt_sndbuf = 1024 * 1024;
last_check = 0;
}
struct_utp_context::~struct_utp_context() {
delete this->utp_sockets;
}
utp_context* utp_init (int version)
{
assert(version == 2);
if (version != 2)
return NULL;
utp_context *ctx = new utp_context;
return ctx;
}
void utp_destroy(utp_context *ctx) {
assert(ctx);
if (ctx) delete ctx;
}
void utp_set_callback(utp_context *ctx, int callback_name, utp_callback_t *proc) {
assert(ctx);
if (ctx) ctx->callbacks[callback_name] = proc;
}
void* utp_context_set_userdata(utp_context *ctx, void *userdata) {
assert(ctx);
if (ctx) ctx->userdata = userdata;
return ctx ? ctx->userdata : NULL;
}
void* utp_context_get_userdata(utp_context *ctx) {
assert(ctx);
return ctx ? ctx->userdata : NULL;
}
utp_context_stats* utp_get_context_stats(utp_context *ctx) {
assert(ctx);
return ctx ? &ctx->context_stats : NULL;
}
ssize_t utp_write(utp_socket *socket, void *buf, size_t len) {
struct utp_iovec iovec = { buf, len };
return utp_writev(socket, &iovec, 1);
}
}

@ -0,0 +1,208 @@
// vim:set ts=4 sw=4 ai:
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "utp_callbacks.h"
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_FIREWALL]) return 0;
args.callback_type = UTP_ON_FIREWALL;
args.context = ctx;
args.socket = NULL;
args.address = address;
args.address_len = address_len;
return (int)ctx->callbacks[UTP_ON_FIREWALL](&args);
}
void utp_call_on_accept(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_ACCEPT]) return;
args.callback_type = UTP_ON_ACCEPT;
args.context = ctx;
args.socket = socket;
args.address = address;
args.address_len = address_len;
ctx->callbacks[UTP_ON_ACCEPT](&args);
}
void utp_call_on_connect(utp_context *ctx, utp_socket *socket)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_CONNECT]) return;
args.callback_type = UTP_ON_CONNECT;
args.context = ctx;
args.socket = socket;
ctx->callbacks[UTP_ON_CONNECT](&args);
}
void utp_call_on_error(utp_context *ctx, utp_socket *socket, int error_code)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_ERROR]) return;
args.callback_type = UTP_ON_ERROR;
args.context = ctx;
args.socket = socket;
args.error_code = error_code;
ctx->callbacks[UTP_ON_ERROR](&args);
}
void utp_call_on_read(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_READ]) return;
args.callback_type = UTP_ON_READ;
args.context = ctx;
args.socket = socket;
args.buf = buf;
args.len = len;
ctx->callbacks[UTP_ON_READ](&args);
}
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *socket, int send, size_t len, int type)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS]) return;
args.callback_type = UTP_ON_OVERHEAD_STATISTICS;
args.context = ctx;
args.socket = socket;
args.send = send;
args.len = len;
args.type = type;
ctx->callbacks[UTP_ON_OVERHEAD_STATISTICS](&args);
}
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *socket, int sample_ms)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_DELAY_SAMPLE]) return;
args.callback_type = UTP_ON_DELAY_SAMPLE;
args.context = ctx;
args.socket = socket;
args.sample_ms = sample_ms;
ctx->callbacks[UTP_ON_DELAY_SAMPLE](&args);
}
void utp_call_on_state_change(utp_context *ctx, utp_socket *socket, int state)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_ON_STATE_CHANGE]) return;
args.callback_type = UTP_ON_STATE_CHANGE;
args.context = ctx;
args.socket = socket;
args.state = state;
ctx->callbacks[UTP_ON_STATE_CHANGE](&args);
}
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_GET_UDP_MTU]) return 0;
args.callback_type = UTP_GET_UDP_MTU;
args.context = ctx;
args.socket = socket;
args.address = address;
args.address_len = address_len;
return (uint16)ctx->callbacks[UTP_GET_UDP_MTU](&args);
}
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *socket, const struct sockaddr *address, socklen_t address_len)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_GET_UDP_OVERHEAD]) return 0;
args.callback_type = UTP_GET_UDP_OVERHEAD;
args.context = ctx;
args.socket = socket;
args.address = address;
args.address_len = address_len;
return (uint16)ctx->callbacks[UTP_GET_UDP_OVERHEAD](&args);
}
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *socket)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_GET_MILLISECONDS]) return 0;
args.callback_type = UTP_GET_MILLISECONDS;
args.context = ctx;
args.socket = socket;
return ctx->callbacks[UTP_GET_MILLISECONDS](&args);
}
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *socket)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_GET_MICROSECONDS]) return 0;
args.callback_type = UTP_GET_MICROSECONDS;
args.context = ctx;
args.socket = socket;
return ctx->callbacks[UTP_GET_MICROSECONDS](&args);
}
uint32 utp_call_get_random(utp_context *ctx, utp_socket *socket)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_GET_RANDOM]) return 0;
args.callback_type = UTP_GET_RANDOM;
args.context = ctx;
args.socket = socket;
return (uint32)ctx->callbacks[UTP_GET_RANDOM](&args);
}
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *socket)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_GET_READ_BUFFER_SIZE]) return 0;
args.callback_type = UTP_GET_READ_BUFFER_SIZE;
args.context = ctx;
args.socket = socket;
return (size_t)ctx->callbacks[UTP_GET_READ_BUFFER_SIZE](&args);
}
void utp_call_log(utp_context *ctx, utp_socket *socket, const byte *buf)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_LOG]) return;
args.callback_type = UTP_LOG;
args.context = ctx;
args.socket = socket;
args.buf = buf;
ctx->callbacks[UTP_LOG](&args);
}
void utp_call_sendto(utp_context *ctx, utp_socket *socket, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags)
{
utp_callback_arguments args;
if (!ctx->callbacks[UTP_SENDTO]) return;
args.callback_type = UTP_SENDTO;
args.context = ctx;
args.socket = socket;
args.buf = buf;
args.len = len;
args.address = address;
args.address_len = address_len;
args.flags = flags;
ctx->callbacks[UTP_SENDTO](&args);
}

@ -0,0 +1,47 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __UTP_CALLBACKS_H__
#define __UTP_CALLBACKS_H__
#include "utp.h"
#include "utp_internal.h"
// Generated by running: grep ^[a-z] utp_callbacks.cpp | sed 's/$/;/'
int utp_call_on_firewall(utp_context *ctx, const struct sockaddr *address, socklen_t address_len);
void utp_call_on_accept(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
void utp_call_on_connect(utp_context *ctx, utp_socket *s);
void utp_call_on_error(utp_context *ctx, utp_socket *s, int error_code);
void utp_call_on_read(utp_context *ctx, utp_socket *s, const byte *buf, size_t len);
void utp_call_on_overhead_statistics(utp_context *ctx, utp_socket *s, int send, size_t len, int type);
void utp_call_on_delay_sample(utp_context *ctx, utp_socket *s, int sample_ms);
void utp_call_on_state_change(utp_context *ctx, utp_socket *s, int state);
uint16 utp_call_get_udp_mtu(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
uint16 utp_call_get_udp_overhead(utp_context *ctx, utp_socket *s, const struct sockaddr *address, socklen_t address_len);
uint64 utp_call_get_milliseconds(utp_context *ctx, utp_socket *s);
uint64 utp_call_get_microseconds(utp_context *ctx, utp_socket *s);
uint32 utp_call_get_random(utp_context *ctx, utp_socket *s);
size_t utp_call_get_read_buffer_size(utp_context *ctx, utp_socket *s);
void utp_call_log(utp_context *ctx, utp_socket *s, const byte *buf);
void utp_call_sendto(utp_context *ctx, utp_socket *s, const byte *buf, size_t len, const struct sockaddr *address, socklen_t address_len, uint32 flags);
#endif // __UTP_CALLBACKS_H__

@ -0,0 +1,246 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "utp_hash.h"
#include "utp_types.h"
#define LIBUTP_HASH_UNUSED ((utp_link_t)-1)
#ifdef STRICT_ALIGN
inline uint32 Read32(const void *p)
{
uint32 tmp;
memcpy(&tmp, p, sizeof tmp);
return tmp;
}
#else
inline uint32 Read32(const void *p) { return *(uint32*)p; }
#endif
// Get the amount of memory required for the hash parameters and the bucket set
// Waste a space for an unused bucket in order to ensure the following managed memory have 32-bit aligned addresses
// TODO: make this 64-bit clean
#define BASE_SIZE(bc) (sizeof(utp_hash_t) + sizeof(utp_link_t) * ((bc) + 1))
// Get a pointer to the base of the structure array managed by the hash table
#define get_bep(h) ((byte*)(h)) + BASE_SIZE((h)->N)
// Get the address of the information associated with a specific structure in the array,
// given the address of the base of the structure.
// This assumes a utp_link_t link member is at the end of the structure.
// Given compilers filling out the memory to a 32-bit clean value, this may mean that
// the location named in the structure may not be the location actually used by the hash table,
// since the compiler may have padded the end of the structure with 2 bytes after the utp_link_t member.
// TODO: this macro should not require that the variable pointing at the hash table be named 'hash'
#define ptr_to_link(p) (utp_link_t *) (((byte *) (p)) + hash->E - sizeof(utp_link_t))
// Calculate how much to allocate for a hash table with bucket count, total size, and structure count
// TODO: make this 64-bit clean
#define ALLOCATION_SIZE(bc, ts, sc) (BASE_SIZE((bc)) + (ts) * (sc))
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun, utp_hash_equal_t compfun)
{
// Must have odd number of hash buckets (prime number is best)
assert(N % 2);
// Ensure structures will be at aligned memory addresses
// TODO: make this 64-bit clean
assert(0 == (total_size % 4));
int size = ALLOCATION_SIZE(N, total_size, initial);
utp_hash_t *hash = (utp_hash_t *) malloc( size );
memset( hash, 0, size );
for (int i = 0; i < N + 1; ++i)
hash->inits[i] = LIBUTP_HASH_UNUSED;
hash->N = N;
hash->K = key_size;
hash->E = total_size;
hash->hash_compute = hashfun;
hash->hash_equal = compfun;
hash->allocated = initial;
hash->count = 0;
hash->used = 0;
hash->free = LIBUTP_HASH_UNUSED;
return hash;
}
uint utp_hash_mem(const void *keyp, size_t keysize)
{
uint hash = 0;
uint n = keysize;
while (n >= 4) {
hash ^= Read32(keyp);
keyp = (byte*)keyp + sizeof(uint32);
hash = (hash << 13) | (hash >> 19);
n -= 4;
}
while (n != 0) {
hash ^= *(byte*)keyp;
keyp = (byte*)keyp + sizeof(byte);
hash = (hash << 8) | (hash >> 24);
n--;
}
return hash;
}
uint utp_hash_mkidx(utp_hash_t *hash, const void *keyp)
{
// Generate a key from the hash
return hash->hash_compute(keyp, hash->K) % hash->N;
}
static inline bool compare(byte *a, byte *b,int n)
{
assert(n >= 4);
if (Read32(a) != Read32(b)) return false;
return memcmp(a+4, b+4, n-4) == 0;
}
#define COMPARE(h,k1,k2,ks) (((h)->hash_equal) ? (h)->hash_equal((void*)k1,(void*)k2,ks) : compare(k1,k2,ks))
// Look-up a key in the hash table.
// Returns NULL if not found
void *utp_hash_lookup(utp_hash_t *hash, const void *key)
{
utp_link_t idx = utp_hash_mkidx(hash, key);
// base pointer
byte *bep = get_bep(hash);
utp_link_t cur = hash->inits[idx];
while (cur != LIBUTP_HASH_UNUSED) {
byte *key2 = bep + (cur * hash->E);
if (COMPARE(hash, (byte*)key, key2, hash->K))
return key2;
cur = *ptr_to_link(key2);
}
return NULL;
}
// Add a new element to the hash table.
// Returns a pointer to the new element.
// This assumes the element is not already present!
void *utp_hash_add(utp_hash_t **hashp, const void *key)
{
//Allocate a new entry
byte *elemp;
utp_link_t elem;
utp_hash_t *hash = *hashp;
utp_link_t idx = utp_hash_mkidx(hash, key);
if ((elem=hash->free) == LIBUTP_HASH_UNUSED) {
utp_link_t all = hash->allocated;
if (hash->used == all) {
utp_hash_t *nhash;
if (all <= (LIBUTP_HASH_UNUSED/2)) {
all *= 2;
} else if (all != LIBUTP_HASH_UNUSED) {
all = LIBUTP_HASH_UNUSED;
} else {
// too many items! can't grow!
assert(0);
return NULL;
}
// otherwise need to allocate.
nhash = (utp_hash_t*)realloc(hash, ALLOCATION_SIZE(hash->N, hash->E, all));
if (!nhash) {
// out of memory (or too big to allocate)
assert(nhash);
return NULL;
}
hash = *hashp = nhash;
hash->allocated = all;
}
elem = hash->used++;
elemp = get_bep(hash) + elem * hash->E;
} else {
elemp = get_bep(hash) + elem * hash->E;
hash->free = *ptr_to_link(elemp);
}
*ptr_to_link(elemp) = hash->inits[idx];
hash->inits[idx] = elem;
hash->count++;
// copy key into it
memcpy(elemp, key, hash->K);
return elemp;
}
// Delete an element from the utp_hash_t
// Returns a pointer to the already deleted element.
void *utp_hash_del(utp_hash_t *hash, const void *key)
{
utp_link_t idx = utp_hash_mkidx(hash, key);
// base pointer
byte *bep = get_bep(hash);
utp_link_t *curp = &hash->inits[idx];
utp_link_t cur;
while ((cur=*curp) != LIBUTP_HASH_UNUSED) {
byte *key2 = bep + (cur * hash->E);
if (COMPARE(hash,(byte*)key,(byte*)key2, hash->K )) {
// found an item that matched. unlink it
*curp = *ptr_to_link(key2);
// Insert into freelist
*ptr_to_link(key2) = hash->free;
hash->free = cur;
hash->count--;
return key2;
}
curp = ptr_to_link(key2);
}
return NULL;
}
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter)
{
utp_link_t elem;
if ((elem=iter->elem) == LIBUTP_HASH_UNUSED) {
// Find a bucket with an element
utp_link_t buck = iter->bucket + 1;
for(;;) {
if (buck >= hash->N)
return NULL;
if ((elem = hash->inits[buck]) != LIBUTP_HASH_UNUSED)
break;
buck++;
}
iter->bucket = buck;
}
byte *elemp = get_bep(hash) + (elem * hash->E);
iter->elem = *ptr_to_link(elemp);
return elemp;
}
void utp_hash_free_mem(utp_hash_t* hash)
{
free(hash);
}

@ -0,0 +1,146 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __UTP_HASH_H__
#define __UTP_HASH_H__
#include <string.h> // memset
#include <stdlib.h> // malloc
#include "utp_types.h"
#include "utp_templates.h"
// TODO: make utp_link_t a template parameter to HashTable
typedef uint32 utp_link_t;
#ifdef _MSC_VER
// Silence the warning about the C99-compliant zero-length array at the end of the structure
#pragma warning (disable: 4200)
#endif
typedef uint32 (*utp_hash_compute_t)(const void *keyp, size_t keysize);
typedef uint (*utp_hash_equal_t)(const void *key_a, const void *key_b, size_t keysize);
// In memory the HashTable is laid out as follows:
// ---------------------------- low
// | hash table data members |
// ---------------------------- _
// | indices | ^
// | . | | utp_link_t indices into the key-values.
// | . | .
// ---------------------------- - <----- bep
// | keys and values | each key-value pair has size total_size
// | . |
// | . |
// ---------------------------- high
//
// The code depends on the ability of the compiler to pad the length
// of the hash table data members structure to
// a length divisible by 32-bits with no remainder.
//
// Since the number of hash buckets (indices) should be odd, the code
// asserts this and adds one to the hash bucket count to ensure that the
// following key-value pairs array starts on a 32-bit boundary.
//
// The key-value pairs array should start on a 32-bit boundary, otherwise
// processors like the ARM will silently mangle 32-bit data in these structures
// (e.g., turning 0xABCD into 0XCDAB when moving a value from memory to register
// when the memory address is 16 bits offset from a 32-bit boundary),
// also, the value will be stored at an address two bytes lower than the address
// value would ordinarily indicate.
//
// The key-value pair is of type T. The first field in T must
// be the key, i.e., the first K bytes of T contains the key.
// total_size = sizeof(T) and thus sizeof(T) >= sizeof(K)
//
// N is the number of buckets.
//
struct utp_hash_t {
utp_link_t N;
byte K;
byte E;
size_t count;
utp_hash_compute_t hash_compute;
utp_hash_equal_t hash_equal;
utp_link_t allocated;
utp_link_t used;
utp_link_t free;
utp_link_t inits[0];
};
#ifdef _MSC_VER
#pragma warning (default: 4200)
#endif
struct utp_hash_iterator_t {
utp_link_t bucket;
utp_link_t elem;
utp_hash_iterator_t() : bucket(0xffffffff), elem(0xffffffff) {}
};
uint utp_hash_mem(const void *keyp, size_t keysize);
uint utp_hash_comp(const void *key_a, const void *key_b, size_t keysize);
utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun = utp_hash_mem, utp_hash_equal_t eqfun = NULL);
void *utp_hash_lookup(utp_hash_t *hash, const void *key);
void *utp_hash_add(utp_hash_t **hashp, const void *key);
void *utp_hash_del(utp_hash_t *hash, const void *key);
void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter);
void utp_hash_free_mem(utp_hash_t *hash);
/*
This HashTable requires that T have at least sizeof(K)+sizeof(utp_link_t) bytes.
Usually done like this:
struct K {
int whatever;
};
struct T {
K wtf;
utp_link_t link; // also wtf
};
*/
template<typename K, typename T> class utpHashTable {
utp_hash_t *hash;
public:
static uint compare(const void *k1, const void *k2, size_t ks) {
return *((K*)k1) == *((K*)k2);
}
static uint32 compute_hash(const void *k, size_t ks) {
return ((K*)k)->compute_hash();
}
void Init() { hash = NULL; }
bool Allocated() { return (hash != NULL); }
void Free() { utp_hash_free_mem(hash); hash = NULL; }
void Create(int N, int initial) { hash = utp_hash_create(N, sizeof(K), sizeof(T), initial, &compute_hash, &compare); }
T *Lookup(const K &key) { return (T*)utp_hash_lookup(hash, &key); }
T *Add(const K &key) { return (T*)utp_hash_add(&hash, &key); }
T *Delete(const K &key) { return (T*)utp_hash_del(hash, &key); }
T *Iterate(utp_hash_iterator_t &iterator) { return (T*)utp_hash_iterate(hash, &iterator); }
size_t GetCount() { return hash->count; }
};
#endif //__UTP_HASH_H__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,141 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __UTP_INTERNAL_H__
#define __UTP_INTERNAL_H__
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "utp.h"
#include "utp_callbacks.h"
#include "utp_templates.h"
#include "utp_hash.h"
#include "utp_hash.h"
#include "utp_packedsockaddr.h"
/* These originally lived in utp_config.h */
#define CCONTROL_TARGET (100 * 1000) // us
enum bandwidth_type_t {
payload_bandwidth, connect_overhead,
close_overhead, ack_overhead,
header_overhead, retransmit_overhead
};
#ifdef WIN32
#ifdef _MSC_VER
#include "libutp_inet_ntop.h"
#endif
// newer versions of MSVC define these in errno.h
#ifndef ECONNRESET
#define ECONNRESET WSAECONNRESET
#define EMSGSIZE WSAEMSGSIZE
#define ECONNREFUSED WSAECONNREFUSED
#define ETIMEDOUT WSAETIMEDOUT
#endif
#endif
struct PACKED_ATTRIBUTE RST_Info {
PackedSockAddr addr;
uint32 connid;
uint16 ack_nr;
uint64 timestamp;
};
// It's really important that we don't have duplicate keys in the hash table.
// If we do, we'll eventually crash. if we try to remove the second instance
// of the key, we'll accidentally remove the first instead. then later,
// checkTimeouts will try to access the second one's already freed memory.
void UTP_FreeAll(struct UTPSocketHT *utp_sockets);
struct UTPSocketKey {
PackedSockAddr addr;
uint32 recv_id; // "conn_seed", "conn_id"
UTPSocketKey(const PackedSockAddr& _addr, uint32 _recv_id) {
memset(this, 0, sizeof(*this));
addr = _addr;
recv_id = _recv_id;
}
bool operator == (const UTPSocketKey &other) const {
return recv_id == other.recv_id && addr == other.addr;
}
uint32 compute_hash() const {
return recv_id ^ addr.compute_hash();
}
};
struct UTPSocketKeyData {
UTPSocketKey key;
UTPSocket *socket;
utp_link_t link;
};
#define UTP_SOCKET_BUCKETS 79
#define UTP_SOCKET_INIT 15
struct UTPSocketHT : utpHashTable<UTPSocketKey, UTPSocketKeyData> {
UTPSocketHT() {
const int buckets = UTP_SOCKET_BUCKETS;
const int initial = UTP_SOCKET_INIT;
this->Create(buckets, initial);
}
~UTPSocketHT() {
UTP_FreeAll(this);
this->Free();
}
};
struct struct_utp_context {
void *userdata;
utp_callback_t* callbacks[UTP_ARRAY_SIZE];
uint64 current_ms;
utp_context_stats context_stats;
UTPSocket *last_utp_socket;
Array<UTPSocket*> ack_sockets;
Array<RST_Info> rst_info;
UTPSocketHT *utp_sockets;
size_t target_delay;
size_t opt_sndbuf;
size_t opt_rcvbuf;
uint64 last_check;
struct_utp_context();
~struct_utp_context();
void log(int level, utp_socket *socket, char const *fmt, ...);
void log_unchecked(utp_socket *socket, char const *fmt, ...);
bool would_log(int level);
bool log_normal:1; // log normal events?
bool log_mtu:1; // log MTU related events?
bool log_debug:1; // log debugging events? (Must also compile with UTP_DEBUG_LOGGING defined)
};
#endif //__UTP_INTERNAL_H__

@ -0,0 +1,139 @@
// vim:set ts=4 sw=4 ai:
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "utp_types.h"
#include "utp_hash.h"
#include "utp_packedsockaddr.h"
#include "libutp_inet_ntop.h"
byte PackedSockAddr::get_family() const
{
#if defined(__sh__)
return ((_sin6d[0] == 0) && (_sin6d[1] == 0) && (_sin6d[2] == htonl(0xffff)) != 0) ?
AF_INET : AF_INET6;
#else
return (IN6_IS_ADDR_V4MAPPED(&_in._in6addr) != 0) ? AF_INET : AF_INET6;
#endif // defined(__sh__)
}
bool PackedSockAddr::operator==(const PackedSockAddr& rhs) const
{
if (&rhs == this)
return true;
if (_port != rhs._port)
return false;
return memcmp(_sin6, rhs._sin6, sizeof(_sin6)) == 0;
}
bool PackedSockAddr::operator!=(const PackedSockAddr& rhs) const
{
return !(*this == rhs);
}
uint32 PackedSockAddr::compute_hash() const {
return utp_hash_mem(&_in, sizeof(_in)) ^ _port;
}
void PackedSockAddr::set(const SOCKADDR_STORAGE* sa, socklen_t len)
{
if (sa->ss_family == AF_INET) {
assert(len >= sizeof(sockaddr_in));
const sockaddr_in *sin = (sockaddr_in*)sa;
_sin6w[0] = 0;
_sin6w[1] = 0;
_sin6w[2] = 0;
_sin6w[3] = 0;
_sin6w[4] = 0;
_sin6w[5] = 0xffff;
_sin4 = sin->sin_addr.s_addr;
_port = ntohs(sin->sin_port);
} else {
assert(len >= sizeof(sockaddr_in6));
const sockaddr_in6 *sin6 = (sockaddr_in6*)sa;
_in._in6addr = sin6->sin6_addr;
_port = ntohs(sin6->sin6_port);
}
}
PackedSockAddr::PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len)
{
set(sa, len);
}
PackedSockAddr::PackedSockAddr(void)
{
SOCKADDR_STORAGE sa;
socklen_t len = sizeof(SOCKADDR_STORAGE);
memset(&sa, 0, len);
sa.ss_family = AF_INET;
set(&sa, len);
}
SOCKADDR_STORAGE PackedSockAddr::get_sockaddr_storage(socklen_t *len = NULL) const
{
SOCKADDR_STORAGE sa;
const byte family = get_family();
if (family == AF_INET) {
sockaddr_in *sin = (sockaddr_in*)&sa;
if (len) *len = sizeof(sockaddr_in);
memset(sin, 0, sizeof(sockaddr_in));
sin->sin_family = family;
sin->sin_port = htons(_port);
sin->sin_addr.s_addr = _sin4;
} else {
sockaddr_in6 *sin6 = (sockaddr_in6*)&sa;
memset(sin6, 0, sizeof(sockaddr_in6));
if (len) *len = sizeof(sockaddr_in6);
sin6->sin6_family = family;
sin6->sin6_addr = _in._in6addr;
sin6->sin6_port = htons(_port);
}
return sa;
}
// #define addrfmt(x, s) x.fmt(s, sizeof(s))
cstr PackedSockAddr::fmt(str s, size_t len) const
{
memset(s, 0, len);
const byte family = get_family();
str i;
if (family == AF_INET) {
INET_NTOP(family, (uint32*)&_sin4, s, len);
i = s;
while (*++i) {}
} else {
i = s;
*i++ = '[';
INET_NTOP(family, (in6_addr*)&_in._in6addr, i, len-1);
while (*++i) {}
*i++ = ']';
}
snprintf(i, len - (i-s), ":%u", _port);
return s;
}

@ -0,0 +1,60 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __UTP_PACKEDSOCKADDR_H__
#define __UTP_PACKEDSOCKADDR_H__
#include "utp_types.h"
struct PACKED_ATTRIBUTE PackedSockAddr {
// The values are always stored here in network byte order
union {
byte _in6[16]; // IPv6
uint16 _in6w[8]; // IPv6, word based (for convenience)
uint32 _in6d[4]; // Dword access
in6_addr _in6addr; // For convenience
} _in;
// Host byte order
uint16 _port;
#define _sin4 _in._in6d[3] // IPv4 is stored where it goes if mapped
#define _sin6 _in._in6
#define _sin6w _in._in6w
#define _sin6d _in._in6d
byte get_family() const;
bool operator==(const PackedSockAddr& rhs) const;
bool operator!=(const PackedSockAddr& rhs) const;
void set(const SOCKADDR_STORAGE* sa, socklen_t len);
PackedSockAddr(const SOCKADDR_STORAGE* sa, socklen_t len);
PackedSockAddr(void);
SOCKADDR_STORAGE get_sockaddr_storage(socklen_t *len) const;
cstr fmt(str s, size_t len) const;
uint32 compute_hash() const;
} ALIGNED_ATTRIBUTE(4);
#endif //__UTP_PACKEDSOCKADDR_H__

@ -0,0 +1,195 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef __TEMPLATES_H__
#define __TEMPLATES_H__
#include "utp_types.h"
#include <assert.h>
#if defined(POSIX)
/* Allow over-writing FORCEINLINE from makefile because gcc 3.4.4 for buffalo
doesn't seem to support __attribute__((always_inline)) in -O0 build
(strangely, it works in -Os build) */
#ifndef FORCEINLINE
// The always_inline attribute asks gcc to inline the function even if no optimization is being requested.
// This macro should be used exclusive-or with the inline directive (use one or the other but not both)
// since Microsoft uses __forceinline to also mean inline,
// and this code is following a Microsoft compatibility model.
// Just setting the attribute without also specifying the inline directive apparently won't inline the function,
// as evidenced by multiply-defined symbols found at link time.
#define FORCEINLINE inline __attribute__((always_inline))
#endif
#endif
// Utility templates
#undef min
#undef max
template <typename T> static inline T min(T a, T b) { if (a < b) return a; return b; }
template <typename T> static inline T max(T a, T b) { if (a > b) return a; return b; }
template <typename T> static inline T min(T a, T b, T c) { return min(min(a,b),c); }
template <typename T> static inline T max(T a, T b, T c) { return max(max(a,b),c); }
template <typename T> static inline T clamp(T v, T mi, T ma)
{
if (v > ma) v = ma;
if (v < mi) v = mi;
return v;
}
#if (defined(__SVR4) && defined(__sun))
#pragma pack(1)
#else
#pragma pack(push,1)
#endif
namespace aux
{
FORCEINLINE uint16 host_to_network(uint16 i) { return htons(i); }
FORCEINLINE uint32 host_to_network(uint32 i) { return htonl(i); }
FORCEINLINE int32 host_to_network(int32 i) { return htonl(i); }
FORCEINLINE uint16 network_to_host(uint16 i) { return ntohs(i); }
FORCEINLINE uint32 network_to_host(uint32 i) { return ntohl(i); }
FORCEINLINE int32 network_to_host(int32 i) { return ntohl(i); }
}
template <class T>
struct PACKED_ATTRIBUTE big_endian
{
T operator=(T i) { m_integer = aux::host_to_network(i); return i; }
operator T() const { return aux::network_to_host(m_integer); }
private:
T m_integer;
};
typedef big_endian<int32> int32_big;
typedef big_endian<uint32> uint32_big;
typedef big_endian<uint16> uint16_big;
#if (defined(__SVR4) && defined(__sun))
#pragma pack(0)
#else
#pragma pack(pop)
#endif
template<typename T> static inline void zeromem(T *a, size_t count = 1) { memset(a, 0, count * sizeof(T)); }
typedef int SortCompareProc(const void *, const void *);
template<typename T> static FORCEINLINE void QuickSortT(T *base, size_t num, int (*comp)(const T *, const T *)) { qsort(base, num, sizeof(T), (SortCompareProc*)comp); }
// WARNING: The template parameter MUST be a POD type!
template <typename T, size_t minsize = 16> class Array {
protected:
T *mem;
size_t alloc,count;
public:
Array(size_t init) { Init(init); }
Array() { Init(); }
~Array() { Free(); }
void inline Init() { mem = NULL; alloc = count = 0; }
void inline Init(size_t init) { Init(); if (init) Resize(init); }
size_t inline GetCount() const { return count; }
size_t inline GetAlloc() const { return alloc; }
void inline SetCount(size_t c) { count = c; }
inline T& operator[](size_t offset) { assert(offset ==0 || offset<alloc); return mem[offset]; }
inline const T& operator[](size_t offset) const { assert(offset ==0 || offset<alloc); return mem[offset]; }
void inline Resize(size_t a) {
if (a == 0) { free(mem); Init(); }
else { mem = (T*)realloc(mem, (alloc=a) * sizeof(T)); }
}
void Grow() { Resize(::max<size_t>(minsize, alloc * 2)); }
inline size_t Append(const T &t) {
if (count >= alloc) Grow();
size_t r=count++;
mem[r] = t;
return r;
}
T inline &Append() {
if (count >= alloc) Grow();
return mem[count++];
}
void inline Compact() {
Resize(count);
}
void inline Free() {
free(mem);
Init();
}
void inline Clear() {
count = 0;
}
bool inline MoveUpLast(size_t index) {
assert(index < count);
size_t c = --count;
if (index != c) {
mem[index] = mem[c];
return true;
}
return false;
}
bool inline MoveUpLastExist(const T &v) {
return MoveUpLast(LookupElementExist(v));
}
size_t inline LookupElement(const T &v) const {
for(size_t i = 0; i != count; i++)
if (mem[i] == v)
return i;
return (size_t) -1;
}
bool inline HasElement(const T &v) const {
return LookupElement(v) != -1;
}
typedef int SortCompareProc(const T *a, const T *b);
void Sort(SortCompareProc* proc, size_t start, size_t end) {
QuickSortT(&mem[start], end - start, proc);
}
void Sort(SortCompareProc* proc, size_t start) {
Sort(proc, start, count);
}
void Sort(SortCompareProc* proc) {
Sort(proc, 0, count);
}
};
#endif //__TEMPLATES_H__

@ -0,0 +1,254 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <assert.h>
#include "utp.h"
#include "utp_types.h"
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else //!WIN32
#include <time.h>
#include <sys/time.h> // Linux needs both time.h and sys/time.h
#endif
#if defined(__APPLE__)
#include <mach/mach_time.h>
#endif
#include "utp_utils.h"
#ifdef WIN32
typedef ULONGLONG (WINAPI GetTickCount64Proc)(void);
static GetTickCount64Proc *pt2GetTickCount64;
static GetTickCount64Proc *pt2RealGetTickCount;
static uint64 startPerformanceCounter;
static uint64 startGetTickCount;
// MSVC 6 standard doesn't like division with uint64s
static double counterPerMicrosecond;
static uint64 UTGetTickCount64()
{
if (pt2GetTickCount64) {
return pt2GetTickCount64();
}
if (pt2RealGetTickCount) {
uint64 v = pt2RealGetTickCount();
// fix return value from GetTickCount
return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000);
}
return (uint64)GetTickCount();
}
static void Time_Initialize()
{
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64");
// not a typo. GetTickCount actually returns 64 bits
pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount");
uint64 frequency;
QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter);
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
counterPerMicrosecond = (double)frequency / 1000000.0f;
startGetTickCount = UTGetTickCount64();
}
static int64 abs64(int64 x) { return x < 0 ? -x : x; }
static uint64 __GetMicroseconds()
{
static bool time_init = false;
if (!time_init) {
time_init = true;
Time_Initialize();
}
uint64 counter;
uint64 tick;
QueryPerformanceCounter((LARGE_INTEGER*) &counter);
tick = UTGetTickCount64();
// unfortunately, QueryPerformanceCounter is not guaranteed
// to be monotonic. Make it so.
int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond);
// if the QPC clock leaps more than one second off GetTickCount64()
// something is seriously fishy. Adjust QPC to stay monotonic
int64 tick_diff = tick - startGetTickCount;
if (abs64(ret / 100000 - tick_diff / 100) > 10) {
startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond);
ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond);
}
return ret;
}
static inline uint64 UTP_GetMilliseconds()
{
return GetTickCount();
}
#else //!WIN32
static inline uint64 UTP_GetMicroseconds(void);
static inline uint64 UTP_GetMilliseconds()
{
return UTP_GetMicroseconds() / 1000;
}
#if defined(__APPLE__)
static uint64 __GetMicroseconds()
{
// http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
// http://www.macresearch.org/tutorial_performance_and_time
static mach_timebase_info_data_t sTimebaseInfo;
static uint64_t start_tick = 0;
uint64_t tick;
// Returns a counter in some fraction of a nanoseconds
tick = mach_absolute_time();
if (sTimebaseInfo.denom == 0) {
// Get the timer ratio to convert mach_absolute_time to nanoseconds
mach_timebase_info(&sTimebaseInfo);
start_tick = tick;
}
// Calculate the elapsed time, convert it to microseconds and return it.
return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000);
}
#else // !__APPLE__
#if ! (defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC))
#warning "Using non-monotonic function gettimeofday() in UTP_GetMicroseconds()"
#endif
/* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that
POSIX clocks work -- we could be running a recent libc with an ancient
kernel (think OpenWRT). -- jch */
static uint64_t __GetMicroseconds()
{
struct timeval tv;
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
static int have_posix_clocks = -1;
int rc;
if (have_posix_clocks < 0) {
struct timespec ts;
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
if (rc < 0) {
have_posix_clocks = 0;
} else {
have_posix_clocks = 1;
}
}
if (have_posix_clocks) {
struct timespec ts;
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
return uint64(ts.tv_sec) * 1000000 + uint64(ts.tv_nsec) / 1000;
}
#endif
gettimeofday(&tv, NULL);
return uint64(tv.tv_sec) * 1000000 + tv.tv_usec;
}
#endif //!__APPLE__
#endif //!WIN32
/*
* Whew. Okay. After that #ifdef maze above, we now know we have a working
* __GetMicroseconds() implementation on all platforms.
*
* Because there are a number of assertions in libutp that will cause a crash
* if monotonic time isn't monotonic, now apply some safety checks. While in
* principle we're already protecting ourselves in cases where non-monotonic
* time is likely to happen, this protects all versions.
*/
static inline uint64 UTP_GetMicroseconds()
{
static uint64 offset = 0, previous = 0;
uint64 now = __GetMicroseconds() + offset;
if (previous > now) {
/* Eek! */
offset += previous - now;
now = previous;
}
previous = now;
return now;
}
#define ETHERNET_MTU 1500
#define IPV4_HEADER_SIZE 20
#define IPV6_HEADER_SIZE 40
#define UDP_HEADER_SIZE 8
#define GRE_HEADER_SIZE 24
#define PPPOE_HEADER_SIZE 8
#define MPPE_HEADER_SIZE 2
// packets have been observed in the wild that were fragmented
// with a payload of 1416 for the first fragment
// There are reports of routers that have MTU sizes as small as 1392
#define FUDGE_HEADER_SIZE 36
#define TEREDO_MTU 1280
#define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE)
#define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE)
#define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD)
#define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
#define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
#define UDP_TEREDO_MTU (TEREDO_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE)
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args) {
// Since we don't know the local address of the interface,
// be conservative and assume all IPv6 connections are Teredo.
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_MTU : UDP_IPV4_MTU;
}
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args) {
// Since we don't know the local address of the interface,
// be conservative and assume all IPv6 connections are Teredo.
return (args->address->sa_family == AF_INET6) ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD;
}
uint64 utp_default_get_random(utp_callback_arguments *args) {
return rand();
}
uint64 utp_default_get_milliseconds(utp_callback_arguments *args) {
return UTP_GetMilliseconds();
}
uint64 utp_default_get_microseconds(utp_callback_arguments *args) {
return UTP_GetMicroseconds();
}

@ -0,0 +1,27 @@
/*
* Copyright (c) 2010-2013 BitTorrent, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
uint64 utp_default_get_udp_mtu(utp_callback_arguments *args);
uint64 utp_default_get_udp_overhead(utp_callback_arguments *args);
uint64 utp_default_get_random(utp_callback_arguments *args);
uint64 utp_default_get_milliseconds(utp_callback_arguments *args);
uint64 utp_default_get_microseconds(utp_callback_arguments *args);

@ -1,276 +1,169 @@
#include "address_info.hpp"
#include <llarp/address_info.hpp>
#ifndef _WIN32
#include <arpa/inet.h>
#endif
#include <llarp/bencode.h>
#include <llarp/mem.h>
#include <llarp/string.h>
#include <llarp/net.hpp>
static bool
llarp_ai_decode_key(struct dict_reader *r, llarp_buffer_t *key)
namespace llarp
{
uint64_t i;
char tmp[128] = {0};
llarp_buffer_t strbuf;
llarp_ai *ai = static_cast< llarp_ai * >(r->user);
// done
if(!key)
return true;
// rank
if(llarp_buffer_eq(*key, "c"))
AddressInfo::~AddressInfo()
{
if(!bencode_read_integer(r->buffer, &i))
return false;
if(i > 65536 || i <= 0)
return false;
ai->rank = i;
return true;
}
// dialect
if(llarp_buffer_eq(*key, "d"))
AddressInfo &
AddressInfo::operator=(const AddressInfo &other)
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz >= sizeof(ai->dialect))
return false;
memcpy(ai->dialect, strbuf.base, strbuf.sz);
ai->dialect[strbuf.sz] = 0;
return true;
rank = other.rank;
dialect = other.dialect;
pubkey = other.pubkey;
memcpy(ip.s6_addr, other.ip.s6_addr, 16);
port = other.port;
return *this;
}
// encryption public key
if(llarp_buffer_eq(*key, "e"))
bool
AddressInfo::operator==(const AddressInfo &other) const
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != PUBKEYSIZE)
return false;
memcpy(ai->enc_key, strbuf.base, PUBKEYSIZE);
return true;
// we don't care about rank
return pubkey == other.pubkey && port == other.port
&& dialect == other.dialect && ip == other.ip;
}
// ip address
if(llarp_buffer_eq(*key, "i"))
bool
AddressInfo::operator<(const AddressInfo &other) const
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz >= sizeof(tmp))
return false;
memcpy(tmp, strbuf.base, strbuf.sz);
tmp[strbuf.sz] = 0;
return inet_pton(AF_INET6, tmp, &ai->ip.s6_addr[0]) == 1;
return rank < other.rank || ip < other.ip || port < other.port;
}
// port
if(llarp_buffer_eq(*key, "p"))
bool
AddressInfo::DecodeKey(llarp_buffer_t key, llarp_buffer_t *buf)
{
if(!bencode_read_integer(r->buffer, &i))
return false;
if(i > 65536 || i <= 0)
return false;
ai->port = i;
return true;
}
// version
if(llarp_buffer_eq(*key, "v"))
{
if(!bencode_read_integer(r->buffer, &i))
return false;
return i == LLARP_PROTO_VERSION;
}
// bad key
return false;
}
static bool
llarp_ai_list_bdecode_item(struct list_reader *r, bool more)
{
if(!more)
return true;
llarp_ai_list *l = static_cast< llarp_ai_list * >(r->user);
llarp_ai ai;
if(!llarp_ai_bdecode(&ai, r->buffer))
return false;
llarp_ai_list_pushback(l, &ai);
return true;
}
static bool
llarp_ai_list_iter_bencode(struct llarp_ai_list_iter *iter, struct llarp_ai *ai)
{
return llarp_ai_bencode(ai, static_cast< llarp_buffer_t * >(iter->user));
}
bool
llarp_ai_bdecode(struct llarp_ai *ai, llarp_buffer_t *buff)
{
#ifndef _MSC_VER
struct dict_reader reader = {
.buffer = nullptr, .user = ai, .on_key = &llarp_ai_decode_key};
#else
struct dict_reader reader = {nullptr, ai, &llarp_ai_decode_key};
#endif
return bencode_read_dict(buff, &reader);
}
bool
llarp_ai_bencode(struct llarp_ai *ai, llarp_buffer_t *buff)
{
char ipbuff[128] = {0};
const char *ipstr;
if(!bencode_start_dict(buff))
return false;
/* rank */
if(!bencode_write_bytestring(buff, "c", 1))
return false;
if(!bencode_write_uint64(buff, ai->rank))
return false;
/* dialect */
if(!bencode_write_bytestring(buff, "d", 1))
return false;
if(!bencode_write_bytestring(buff, ai->dialect,
strnlen(ai->dialect, sizeof(ai->dialect))))
return false;
/* encryption key */
if(!bencode_write_bytestring(buff, "e", 1))
return false;
if(!bencode_write_bytestring(buff, ai->enc_key, PUBKEYSIZE))
uint64_t i;
char tmp[128] = {0};
llarp_buffer_t strbuf;
// rank
if(llarp_buffer_eq(key, "c"))
{
if(!bencode_read_integer(buf, &i))
return false;
if(i > 65536 || i <= 0)
return false;
rank = i;
return true;
}
// dialect
if(llarp_buffer_eq(key, "d"))
{
if(!bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz > sizeof(tmp))
return false;
memcpy(tmp, strbuf.base, strbuf.sz);
tmp[strbuf.sz] = 0;
dialect = std::string(tmp);
return true;
}
// encryption public key
if(llarp_buffer_eq(key, "e"))
{
if(!bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz != PUBKEYSIZE)
return false;
pubkey = strbuf.base;
return true;
}
// ip address
if(llarp_buffer_eq(key, "i"))
{
if(!bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz >= sizeof(tmp))
return false;
memcpy(tmp, strbuf.base, strbuf.sz);
tmp[strbuf.sz] = 0;
return inet_pton(AF_INET6, tmp, &ip.s6_addr[0]) == 1;
}
// port
if(llarp_buffer_eq(key, "p"))
{
if(!bencode_read_integer(buf, &i))
return false;
if(i > 65536 || i <= 0)
return false;
port = i;
return true;
}
// version
if(llarp_buffer_eq(key, "v"))
{
if(!bencode_read_integer(buf, &i))
return false;
return i == LLARP_PROTO_VERSION;
}
// bad key
return false;
/** ip */
ipstr = inet_ntop(AF_INET6, &ai->ip, ipbuff, sizeof(ipbuff));
if(!ipstr)
return false;
if(!bencode_write_bytestring(buff, "i", 1))
return false;
if(!bencode_write_bytestring(buff, ipstr, strnlen(ipstr, sizeof(ipbuff))))
return false;
/** port */
if(!bencode_write_bytestring(buff, "p", 1))
return false;
if(!bencode_write_uint64(buff, ai->port))
return false;
/** version */
if(!bencode_write_version_entry(buff))
return false;
/** end */
return bencode_end(buff);
}
bool
llarp_ai_list_bencode(struct llarp_ai_list *l, llarp_buffer_t *buff)
{
if(!bencode_start_list(buff))
return false;
#ifndef _MSC_VER
struct llarp_ai_list_iter ai_itr = {
.user = buff, .list = nullptr, .visit = &llarp_ai_list_iter_bencode};
#else
struct llarp_ai_list_iter ai_itr = {buff, nullptr,
&llarp_ai_list_iter_bencode};
#endif
llarp_ai_list_iterate(l, &ai_itr);
return bencode_end(buff);
}
struct llarp_ai_list *
llarp_ai_list_new()
{
return new llarp_ai_list;
}
void
llarp_ai_list_free(struct llarp_ai_list *l)
{
if(l)
{
l->list.clear();
delete l;
}
}
void
llarp_ai_copy(struct llarp_ai *dst, struct llarp_ai *src)
{
memcpy(dst, src, sizeof(struct llarp_ai));
}
void
llarp_ai_list_copy(struct llarp_ai_list *dst, struct llarp_ai_list *src)
{
dst->list.clear();
for(auto &itr : src->list)
dst->list.emplace_back(itr);
}
void
llarp_ai_list_pushback(struct llarp_ai_list *l, struct llarp_ai *ai)
{
l->list.push_back(*ai);
}
size_t
llarp_ai_list_size(struct llarp_ai_list *l)
{
if(l)
bool
AddressInfo::BEncode(llarp_buffer_t *buff) const
{
return l->list.size();
}
return 0;
}
void
llarp_ai_list_iterate(struct llarp_ai_list *l, struct llarp_ai_list_iter *itr)
{
itr->list = l;
for(auto &ai : l->list)
if(!itr->visit(itr, &ai))
return;
}
bool
llarp_ai_list_index(struct llarp_ai_list *l, ssize_t idx, struct llarp_ai *dst)
{
// TODO: implement negative indexes
if(idx < 0)
return false;
size_t i = idx;
char ipbuff[128] = {0};
const char *ipstr;
if(!bencode_start_dict(buff))
return false;
/* rank */
if(!bencode_write_bytestring(buff, "c", 1))
return false;
if(!bencode_write_uint64(buff, rank))
return false;
/* dialect */
if(!bencode_write_bytestring(buff, "d", 1))
return false;
if(!bencode_write_bytestring(buff, dialect.c_str(), dialect.size()))
return false;
/* encryption key */
if(!bencode_write_bytestring(buff, "e", 1))
return false;
if(!bencode_write_bytestring(buff, pubkey, PUBKEYSIZE))
return false;
/** ip */
ipstr = inet_ntop(AF_INET6, &ip, ipbuff, sizeof(ipbuff));
if(!ipstr)
return false;
if(!bencode_write_bytestring(buff, "i", 1))
return false;
if(!bencode_write_bytestring(buff, ipstr, strnlen(ipstr, sizeof(ipbuff))))
return false;
/** port */
if(!bencode_write_bytestring(buff, "p", 1))
return false;
if(!bencode_write_uint64(buff, port))
return false;
if(l->list.size() > i)
{
llarp_ai_copy(dst, &l->list[i]);
return true;
/** version */
if(!bencode_write_version_entry(buff))
return false;
/** end */
return bencode_end(buff);
}
return false;
}
bool
llarp_ai_list_bdecode(struct llarp_ai_list *l, llarp_buffer_t *buff)
{
#ifndef _MSC_VER
struct list_reader r = {
.buffer = nullptr, .user = l, .on_item = &llarp_ai_list_bdecode_item};
#else
struct list_reader r = {nullptr, l, &llarp_ai_list_bdecode_item};
#endif
return bencode_read_list(buff, &r);
}
} // namespace llarp

@ -1,5 +1,5 @@
#include <llarp/bencode.h>
#include "logger.hpp"
#include <llarp/logger.hpp>
bool
bencode_write_bytestring(llarp_buffer_t* buff, const void* data, size_t sz)
@ -114,10 +114,14 @@ bencode_read_dict(llarp_buffer_t* buff, struct dict_reader* r)
return false;
}
if(*r->buffer->cur != 'e') // make sure we're at dictionary end
if(*r->buffer->cur != 'e')
{
llarp::LogWarn("reading dict not ending on 'e'");
// make sure we're at dictionary end
return false;
}
r->buffer->cur++;
return r->on_key(r, 0);
return r->on_key(r, nullptr);
}
bool

@ -6,6 +6,7 @@
#ifndef ssize_t
#define ssize_t long
#endif
size_t
llarp_buffer_size_left(llarp_buffer_t buff)
{
@ -100,6 +101,7 @@ llarp_buffer_put_uint32(llarp_buffer_t* buf, uint32_t i)
buf->cur += sizeof(uint32_t);
return true;
}
bool
llarp_buffer_read_uint16(llarp_buffer_t* buf, uint16_t* i)
{
@ -110,6 +112,16 @@ llarp_buffer_read_uint16(llarp_buffer_t* buf, uint16_t* i)
return true;
}
bool
llarp_buffer_read_uint32(llarp_buffer_t* buf, uint32_t* i)
{
if(llarp_buffer_size_left(*buf) < sizeof(uint32_t))
return false;
*i = bufbe32toh(buf->cur);
buf->cur += sizeof(uint32_t);
return true;
}
bool
llarp_buffer_put_uint32(llarp_buffer_t* buf, uint32_t* i)
{
@ -118,4 +130,4 @@ llarp_buffer_put_uint32(llarp_buffer_t* buf, uint32_t* i)
*i = bufbe32toh(buf->cur);
buf->cur += sizeof(uint32_t);
return true;
}
}

@ -97,7 +97,7 @@ namespace llarp
int
Context::LoadDatabase()
{
llarp_crypto_libsodium_init(&crypto);
llarp_crypto_init(&crypto);
nodedb = llarp_nodedb_new(&crypto);
if(!nodedb_dir[0])
{
@ -131,15 +131,19 @@ namespace llarp
}
bool
Context::PutDatabase(struct llarp_rc *rc)
Context::PutDatabase(struct llarp::RouterContact *rc)
{
return llarp_nodedb_put_rc(nodedb, rc);
// FIXME
//return llarp_nodedb_put_rc(nodedb, rc);
return false;
}
struct llarp_rc *
llarp::RouterContact *
Context::GetDatabase(const byte_t *pk)
{
return llarp_nodedb_get_rc(nodedb, pk);
// FIXME
//return llarp_nodedb_get_rc(nodedb, pk);
return nullptr;
}
int
@ -349,31 +353,53 @@ extern "C"
llarp_logic_stop_timer(ptr->ctx->router->logic);
}
int
llarp_main_loadDatabase(struct llarp_main *ptr)
{
return ptr->ctx->LoadDatabase();
}
int
llarp_main_iterateDatabase(struct llarp_main *ptr, struct llarp_nodedb_iter i)
void
llarp_main_queryDHT_RC(struct llarp_main *ptr,
struct llarp_router_lookup_job *job)
{
return ptr->ctx->IterateDatabase(i);
llarp_dht_lookup_router(ptr->ctx->router->dht, job);
}
bool
llarp_main_putDatabase(struct llarp_main *ptr, struct llarp_rc *rc)
llarp_main_init_dnsd(struct llarp_main *ptr, struct dnsd_context *dnsd,
uint16_t server_port, const char *upstream_host,
uint16_t upstream_port)
{
return ptr->ctx->PutDatabase(rc);
return llarp_dnsd_init(dnsd, ptr->ctx->mainloop, ptr->ctx->logic, "*",
server_port, upstream_host, upstream_port);
}
struct llarp_rc *
llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk)
void
llarp_main_free(struct llarp_main *ptr)
{
return ptr->ctx->GetDatabase(pk);
delete ptr;
}
struct llarp_rc *
int
llarp_main_loadDatabase(struct llarp_main *ptr)
{
return ptr->ctx->LoadDatabase();
}
int
llarp_main_iterateDatabase(struct llarp_main *ptr, struct llarp_nodedb_iter i)
{
return ptr->ctx->IterateDatabase(i);
}
bool
llarp_main_putDatabase(struct llarp_main *ptr, llarp::RouterContact *rc)
{
return ptr->ctx->PutDatabase(rc);
}
llarp::RouterContact *
llarp_main_getDatabase(struct llarp_main *ptr, byte_t *pk)
{
return ptr->ctx->GetDatabase(pk);
}
llarp::RouterContact *
llarp_main_getLocalRC(struct llarp_main *ptr)
{
//
@ -383,83 +409,65 @@ extern "C"
iter.visit = &iter_config;
llarp_config_iter(ctx->config, &iter);
*/
llarp_rc *rc = new llarp_rc;
llarp_rc_new(rc);
llarp::LogInfo("Loading ", ptr->ctx->conatctFile);
//llarp_rc *rc = new llarp_rc;
llarp::RouterContact *rc = new llarp::RouterContact;
//llarp_rc_new(rc);
llarp::LogInfo("FIXME: Loading ", ptr->ctx->conatctFile);
// FIXME
/*
if(llarp_rc_read(ptr->ctx->conatctFile, rc))
return rc;
else
*/
return nullptr;
}
void
llarp_main_checkOnline(void *u, uint64_t orig, uint64_t left)
{
// llarp::LogInfo("checkOnline - check ", left);
if(left)
return;
struct check_online_request *request =
static_cast< struct check_online_request * >(u);
// llarp::LogDebug("checkOnline - running");
// llarp::LogInfo("checkOnline - DHT nodes ",
// request->ptr->ctx->router->dht->impl.nodes->nodes.size());
request->online = false;
request->nodes = request->ptr->ctx->router->dht->impl.nodes->nodes.size();
if(request->ptr->ctx->router->dht->impl.nodes->nodes.size())
{
// llarp::LogInfo("checkOnline - Going to say we're online");
request->online = true;
}
request->hook(request);
// reschedue our self
llarp_main_queryDHT(request);
}
void
llarp_main_queryDHT_online(struct check_online_request *request)
{
// Info("llarp_main_queryDHT_online: ", request->online ? "online" :
// "offline");
if(request->online && !request->first)
{
request->first = true;
llarp::LogInfo("llarp_main_queryDHT_online - We're online");
llarp::LogInfo("llarp_main_queryDHT_online - Querying DHT");
llarp_dht_lookup_router(request->ptr->ctx->router->dht, request->job);
}
}
void
llarp_main_queryDHT(struct check_online_request *request)
{
// llarp::LogInfo("llarp_main_queryDHT - setting up timer");
request->hook = &llarp_main_queryDHT_online;
llarp_logic_call_later(request->ptr->ctx->router->logic,
{1000, request, &llarp_main_checkOnline});
// llarp_dht_lookup_router(ptr->ctx->router->dht, job);
}
void
llarp_main_queryDHT_RC(struct llarp_main *ptr,
struct llarp_router_lookup_job *job)
void
llarp_main_checkOnline(void *u, uint64_t orig, uint64_t left)
{
// llarp::Info("checkOnline - check ", left);
if(left)
return;
struct check_online_request *request =
static_cast< struct check_online_request * >(u);
// llarp::Debug("checkOnline - running");
// llarp::Info("checkOnline - DHT nodes ",
// request->ptr->ctx->router->dht->impl.nodes->nodes.size());
request->online = false;
request->nodes = request->ptr->ctx->router->dht->impl.nodes->nodes.size();
if(request->ptr->ctx->router->dht->impl.nodes->nodes.size())
{
llarp_dht_lookup_router(ptr->ctx->router->dht, job);
// llarp::Info("checkOnline - Going to say we're online");
request->online = true;
}
request->hook(request);
// reschedue our self
llarp_main_queryDHT(request);
}
bool
llarp_main_init_dnsd(struct llarp_main *ptr, struct dnsd_context *dnsd,
uint16_t server_port, const char *upstream_host,
uint16_t upstream_port)
void
llarp_main_queryDHT_online(struct check_online_request *request)
{
// Info("llarp_main_queryDHT_online: ", request->online ? "online" :
// "offline");
if(request->online && !request->first)
{
return llarp_dnsd_init(dnsd, ptr->ctx->mainloop, ptr->ctx->logic, "*",
server_port, upstream_host, upstream_port);
request->first = true;
llarp::LogInfo("llarp_main_queryDHT_online - We're online");
llarp::LogInfo("llarp_main_queryDHT_online - Querying DHT");
llarp_dht_lookup_router(request->ptr->ctx->router->dht, request->job);
}
}
void
llarp_main_free(struct llarp_main *ptr)
{
delete ptr;
}
void
llarp_main_queryDHT(struct check_online_request *request)
{
// llarp::Info("llarp_main_queryDHT - setting up timer");
request->hook = &llarp_main_queryDHT_online;
llarp_logic_call_later(request->ptr->ctx->router->logic,
{1000, request, &llarp_main_checkOnline});
// llarp_dht_lookup_router(ptr->ctx->router->dht, job);
}
const char *
handleBaseCmdLineArgs(int argc, char *argv[])

@ -1,6 +1,6 @@
#include <llarp/crypto_async.h>
#include <llarp/mem.h>
#include <llarp/router_contact.h>
#include <llarp/router_contact.hpp>
#include <string.h>
#include <llarp/crypto.hpp>
#include <llarp/router_id.hpp>
@ -17,22 +17,6 @@ struct llarp_async_iwp
namespace iwp
{
void
inform_keygen(void *user)
{
iwp_async_keygen *keygen = static_cast< iwp_async_keygen * >(user);
keygen->hook(keygen);
}
void
keygen(void *user)
{
iwp_async_keygen *keygen = static_cast< iwp_async_keygen * >(user);
keygen->iwp->crypto->encryption_keygen(keygen->keybuf);
keygen->hook(keygen);
// llarp_logic_queue_job(keygen->iwp->logic, job);
}
void
inform_intro(void *user)
{
@ -67,7 +51,7 @@ namespace iwp
llarp::SymmNonce n;
// copy nonce
memcpy(n, intro->nonce, 24);
memcpy(n, intro->nonce, 32); // was 24 bytes
char ftmpN[68] = {0};
const char *hexN =
llarp::HexEncode< llarp::SymmNonce, decltype(ftmpN) >(n, ftmpN);
@ -85,6 +69,9 @@ namespace iwp
llarp::HexEncode< llarp::ShortHash, decltype(ftmpEk) >(e_k, ftmpEk);
llarp::LogDebug("gen_intro e_k ", hexEk, " used ", strlen(hexEk));
// put nonce
memcpy(intro->buf + 32, intro->nonce, 32);
// e = SE(a.k, e_k, n[0:24])
memcpy(intro->buf + 64, llarp::seckey_topublic(intro->secretkey), 32);
@ -145,7 +132,10 @@ namespace iwp
buf.base = intro->remote_pubkey;
buf.cur = buf.base;
buf.sz = 32;
memcpy(intro->remote_pubkey, intro->buf + 64, 32);
// was using remote_pubkey directly (use buffer wrapper? directly?)
//memcpy(intro->remote_pubkey, intro->buf + 64, 32);
memcpy(buf.base, intro->buf + 64, 32);
crypto->xchacha20(buf, e_K, intro->nonce);
llarp::LogInfo("handshake from ", llarp::RouterID(intro->remote_pubkey));
@ -174,6 +164,7 @@ namespace iwp
{
llarp::LogWarn("intro HMAC failure");
// hmac fail
delete[] intro->buf;
intro->buf = nullptr;
}
// inform result
@ -197,13 +188,13 @@ namespace iwp
llarp::ShortHash digest;
llarp::SharedSecret sharedkey;
auto hmac = introack->buf;
auto body = introack->buf + 32;
auto pubkey = introack->remote_pubkey;
auto secretkey = introack->secretkey;
auto nonce = introack->buf + 32;
auto token = introack->buf + 64;
size_t bodysz = introack->sz - 32;
auto hmac = introack->buf;
auto body = introack->buf + 32;
const auto pubkey = introack->remote_pubkey;
auto secretkey = introack->secretkey;
auto nonce = introack->buf + 32;
auto token = introack->buf + 64;
size_t bodysz = introack->sz - 32;
llarp_buffer_t buf;
buf.base = body;
buf.cur = body;
@ -238,10 +229,10 @@ namespace iwp
{
iwp_async_introack *introack = static_cast< iwp_async_introack * >(user);
llarp::SharedSecret sharedkey;
auto crypto = introack->iwp->crypto;
auto pubkey = introack->remote_pubkey;
auto secretkey = introack->secretkey;
auto nonce = introack->nonce;
auto crypto = introack->iwp->crypto;
const auto pubkey = introack->remote_pubkey;
auto secretkey = introack->secretkey;
auto nonce = introack->nonce;
// S = TKE(a.k, b.k, n)
crypto->transport_dh_server(sharedkey, pubkey, secretkey, nonce);
@ -284,11 +275,11 @@ namespace iwp
auto encrypt = crypto->xchacha20;
// auto logic = session->iwp->logic;
auto a_sK = session->secretkey;
auto b_K = session->remote_pubkey;
auto N = session->nonce;
auto token = session->token;
auto K = session->sessionkey;
auto a_sK = session->secretkey;
const auto b_K = session->remote_pubkey;
auto N = session->nonce;
auto token = session->token;
auto K = session->sessionkey;
llarp::SharedSecret e_K;
llarp::ShortHash T;
@ -317,7 +308,7 @@ namespace iwp
buf.sz = session->sz - 32;
hmac(session->buf, buf, e_K);
// session->hook(session);
llarp_logic_queue_job(logic, {user, &inform_session_start});
llarp_logic_queue_job(logic, {session, &inform_session_start});
}
void
@ -386,7 +377,7 @@ namespace iwp
else // hmac fail
session->buf = nullptr;
// session->hook(session);
llarp_logic_queue_job(logic, {user, &inform_session_start});
llarp_logic_queue_job(logic, {session, &inform_session_start});
}
void
@ -417,14 +408,6 @@ namespace iwp
}
} // namespace iwp
void
iwp_call_async_keygen(struct llarp_async_iwp *iwp,
struct iwp_async_keygen *keygen)
{
keygen->iwp = iwp;
llarp_threadpool_queue_job(iwp->worker, {keygen, &iwp::keygen});
}
bool
iwp_decrypt_frame(struct iwp_async_frame *frame)
{

@ -193,7 +193,7 @@ namespace llarp
} // namespace llarp
void
llarp_crypto_libsodium_init(struct llarp_crypto *c)
llarp_crypto_init(struct llarp_crypto *c)
{
assert(sodium_init() != -1);
char *avx2 = getenv("AVX2_FORCE_DISABLE");
@ -229,4 +229,4 @@ llarp_randint()
uint64_t i;
randombytes((byte_t *)&i, sizeof(i));
return i;
}
}

@ -19,15 +19,6 @@ llarp_dht_context_free(struct llarp_dht_context *ctx)
delete ctx;
}
void
__llarp_dht_put_peer(struct llarp_dht_context *ctx, struct llarp_rc *rc)
{
llarp::dht::RCNode n(rc);
llarp::LogDebug("Adding ", n.ID, " to DHT");
ctx->impl.nodes->PutNode(n);
}
void
__llarp_dht_remove_peer(struct llarp_dht_context *ctx, const byte_t *id)
{
@ -45,7 +36,7 @@ llarp_dht_allow_transit(llarp_dht_context *ctx)
void
llarp_dht_context_start(struct llarp_dht_context *ctx, const byte_t *key)
{
ctx->impl.Init(key, ctx->parent);
ctx->impl.Init(key, ctx->parent, 20000);
}
void
@ -54,8 +45,11 @@ llarp_dht_lookup_router(struct llarp_dht_context *ctx,
{
job->dht = ctx;
job->found = false;
// TODO: check for reuse
llarp_rc_clear(&job->result);
job->result.Clear();
//llarp_rc_clear(&job->result);
llarp::LogError("implement me llarp_dht_lookup_router");
/*
llarp_logic_queue_job(ctx->parent->logic,
{job, &llarp::dht::Context::queue_router_lookup});
*/
}

File diff suppressed because it is too large Load Diff

@ -8,8 +8,8 @@ namespace llarp
struct MessageDecoder
{
const Key_t &From;
std::unique_ptr< IMessage > msg;
bool firstKey = true;
IMessage *msg = nullptr;
bool relayed = false;
MessageDecoder(const Key_t &from) : From(from)
@ -37,32 +37,33 @@ namespace llarp
return false;
llarp::LogInfo("Handle DHT message ", *strbuf.base,
" relayed=", dec->relayed);
IMessage *msg;
switch(*strbuf.base)
{
case 'F':
dec->msg = new FindIntroMessage(dec->From, dec->relayed);
msg = new FindIntroMessage(dec->From, dec->relayed);
break;
case 'R':
if(dec->relayed)
dec->msg = new RelayedFindRouterMessage(dec->From);
msg = new RelayedFindRouterMessage(dec->From);
else
dec->msg = new FindRouterMessage(dec->From);
msg = new FindRouterMessage(dec->From);
break;
case 'S':
dec->msg = new GotRouterMessage(dec->From, dec->relayed);
msg = new GotRouterMessage(dec->From, dec->relayed);
break;
case 'I':
dec->msg = new PublishIntroMessage();
msg = new PublishIntroMessage();
break;
case 'G':
if(dec->relayed)
{
dec->msg = new RelayedGotIntroMessage();
msg = new RelayedGotIntroMessage();
break;
}
else
{
dec->msg = new GotIntroMessage(dec->From);
msg = new GotIntroMessage(dec->From);
break;
}
default:
@ -70,6 +71,7 @@ namespace llarp
// bad msg type
return false;
}
dec->msg = std::unique_ptr< IMessage >(msg);
dec->firstKey = false;
return dec->msg != nullptr;
}
@ -78,7 +80,7 @@ namespace llarp
}
};
IMessage *
std::unique_ptr< IMessage >
DecodeMesssage(const Key_t &from, llarp_buffer_t *buf, bool relayed)
{
MessageDecoder dec(from);
@ -86,26 +88,20 @@ namespace llarp
dict_reader r;
r.user = &dec;
r.on_key = &MessageDecoder::on_key;
if(bencode_read_dict(buf, &r))
{
return dec.msg;
}
else
{
if(dec.msg)
delete dec.msg;
if(!bencode_read_dict(buf, &r))
return nullptr;
}
return std::unique_ptr< IMessage >(std::move(dec.msg));
}
struct ListDecoder
{
ListDecoder(const Key_t &from, std::vector< IMessage * > &list)
ListDecoder(const Key_t &from,
std::vector< std::unique_ptr< IMessage > > &list)
: From(from), l(list){};
bool relayed = false;
const Key_t &From;
std::vector< IMessage * > &l;
std::vector< std::unique_ptr< IMessage > > &l;
static bool
on_item(list_reader *r, bool has)
@ -116,7 +112,7 @@ namespace llarp
auto msg = DecodeMesssage(dec->From, r->buffer, dec->relayed);
if(msg)
{
dec->l.push_back(msg);
dec->l.emplace_back(std::move(msg));
return true;
}
else
@ -125,8 +121,9 @@ namespace llarp
};
bool
DecodeMesssageList(const Key_t &from, llarp_buffer_t *buf,
std::vector< IMessage * > &list, bool relayed)
DecodeMesssageList(Key_t from, llarp_buffer_t *buf,
std::vector< std::unique_ptr< IMessage > > &list,
bool relayed)
{
ListDecoder dec(from, list);
dec.relayed = relayed;
@ -136,4 +133,4 @@ namespace llarp
return bencode_read_list(buf, &r);
}
} // namespace dht
} // namespace llarp
} // namespace llarp

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

Loading…
Cancel
Save