Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ee2f00224 | |||
| 383a3b8b02 | |||
| 0beca5d801 | |||
| 47bd5bf083 | |||
| 7b5b80cb3a | |||
| b50eecc56f | |||
| 8953173403 | |||
| 2f307c195c | |||
| 8c5024a78a | |||
| 3f823e8583 | |||
| a4bfc6012a | |||
| 136d446157 | |||
| 1966f49ce2 | |||
| a4da39f23c | |||
| 87bfc15712 | |||
| 6353e9d5fa | |||
| 14ce8cc2a7 | |||
| d180b5870c | |||
| 596d4ab55c | |||
| 5af26f186e | |||
| 5530920b25 | |||
| 3ed9a42b3c |
@@ -9,7 +9,7 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
VERSION: "5.1.5"
|
||||
VERSION: "5.2.0"
|
||||
|
||||
jobs:
|
||||
build-windows-qt:
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
# Embedded Tor Integration Guide for Triangles
|
||||
|
||||
This guide explains how to compile Tor as a static library (`libtor.a`) and link
|
||||
it directly into the Triangles wallet binary so that every node automatically
|
||||
runs a Tor hidden service without needing an external Tor installation.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
trianglesd / triangles-qt
|
||||
├── tor_embedded.cpp ← calls tor_run_main() in a background thread
|
||||
├── tor_process.cpp ← fallback: launches external tor binary (already works)
|
||||
├── onion_v3.cpp ← V3 onion address generation / SOCKS5 proxy logic
|
||||
└── libtor.a ← static Tor library (built from official source)
|
||||
```
|
||||
|
||||
When compiled with `ENABLE_TOR_EMBEDDED`, the wallet calls `tor_run_main()` from
|
||||
`tor_api.h` on a dedicated thread. This gives the wallet a SOCKS5 proxy on
|
||||
`127.0.0.1:19099` and a V3 hidden service on port 24112 (the P2P port).
|
||||
|
||||
When compiled **without** the flag, `tor_embedded.cpp` falls back to the external
|
||||
`tor_process.cpp` which searches for and launches a system `tor` binary.
|
||||
|
||||
## Step 1: Add Tor as a Git Submodule
|
||||
|
||||
```bash
|
||||
cd /path/to/triangles
|
||||
git submodule add https://gitlab.torproject.org/tpo/core/tor.git src/tor/tor-src
|
||||
cd src/tor/tor-src
|
||||
git checkout release-0.4.9 # latest stable branch as of 2026
|
||||
```
|
||||
|
||||
This puts the full Tor source at `src/tor/tor-src/`.
|
||||
Current imported checkout in this repo: `release-0.4.9` at commit `1442ca4`.
|
||||
There is also a helper build script at `src/tor/build-libtor.sh`.
|
||||
|
||||
## Step 2: Build libtor.a (Linux)
|
||||
|
||||
Tor uses autotools. Build it as a static library:
|
||||
|
||||
```bash
|
||||
cd src/tor/tor-src
|
||||
|
||||
# Install Tor build dependencies
|
||||
sudo apt install autoconf automake libtool pkg-config \
|
||||
libssl-dev libevent-dev zlib1g-dev
|
||||
|
||||
# Generate configure script
|
||||
./autogen.sh
|
||||
|
||||
# Configure for static library build (disable unneeded modules)
|
||||
./configure \
|
||||
--enable-static-tor \
|
||||
--disable-module-relay \
|
||||
--disable-module-dirauth \
|
||||
--disable-asciidoc \
|
||||
--disable-manpage \
|
||||
--disable-html-manual \
|
||||
--disable-unittests \
|
||||
--disable-tool-name-check \
|
||||
--with-openssl-dir=/usr \
|
||||
--with-libevent-dir=/usr \
|
||||
--with-zlib-dir=/usr \
|
||||
--prefix=/usr/local
|
||||
|
||||
make -j$(nproc)
|
||||
```
|
||||
|
||||
Or from the repo root:
|
||||
```bash
|
||||
./src/tor/build-libtor.sh
|
||||
```
|
||||
|
||||
After building, the static libraries are in `src/tor/tor-src/src/`:
|
||||
- `src/core/libtor-app.a`
|
||||
- `src/lib/libtor-*.a` (multiple component libs)
|
||||
- `src/trunnel/libor-trunnel.a`
|
||||
|
||||
The header `src/feature/api/tor_api.h` provides the public C API:
|
||||
```c
|
||||
tor_main_configuration_t *tor_main_configuration_new(void);
|
||||
int tor_main_configuration_set_command_line(tor_main_configuration_t *cfg,
|
||||
int argc, char *argv[]);
|
||||
int tor_run_main(const tor_main_configuration_t *);
|
||||
void tor_main_configuration_free(tor_main_configuration_t *);
|
||||
```
|
||||
|
||||
## Step 3: Build Triangles with Embedded Tor
|
||||
|
||||
### Linux (makefile.unix)
|
||||
|
||||
```bash
|
||||
cd src
|
||||
|
||||
# Point to Tor's built libraries and headers
|
||||
make -f makefile.unix \
|
||||
USE_TOR_EMBEDDED=1
|
||||
```
|
||||
|
||||
You may need to adjust the `-l` flags in the makefile depending on the exact
|
||||
library names Tor produces. Check `src/tor/tor-src/src/` after building:
|
||||
|
||||
```bash
|
||||
find tor/tor-src/src -name '*.a' | sort
|
||||
```
|
||||
|
||||
Common libraries to link (order matters):
|
||||
```
|
||||
-ltor-app -lor -lor-ctime -lor-evloop -lor-event -lor-compress
|
||||
-lor-container -lor-crypt-ops -lor-encoding -lor-err -lor-fs
|
||||
-lor-intmath -lor-lock -lor-log -lor-malloc -lor-math -lor-memarea
|
||||
-lor-meminfo -lor-net -lor-osinfo -lor-process -lor-sandbox
|
||||
-lor-smartlist-core -lor-string -lor-term -lor-thread -lor-time
|
||||
-lor-tls -lor-trace -lor-version -lor-wallclock
|
||||
-lor-trunnel
|
||||
```
|
||||
|
||||
### Windows (triangles-qt.pro)
|
||||
|
||||
Add to `triangles-qt.pro`:
|
||||
```qmake
|
||||
qmake "USE_TOR_EMBEDDED=1" \
|
||||
"TOR_SOURCE_ROOT=src/tor/tor-src"
|
||||
```
|
||||
|
||||
Both build systems now default to:
|
||||
- source root: `src/tor/tor-src`
|
||||
- include path: `src/tor/tor-src/src/feature/api`
|
||||
- library paths: `src/tor/tor-src/src/core`, `src/tor/tor-src/src/lib`, `src/tor/tor-src/src/trunnel`
|
||||
|
||||
Override `TOR_EMBEDDED_LIBS` if the actual Tor static library names differ on your platform/build.
|
||||
|
||||
## Step 4: Wire into init.cpp
|
||||
|
||||
The global hooks `StartEmbeddedTor()` and `StopEmbeddedTor()` need to be called
|
||||
from `init.cpp`. Add these calls:
|
||||
|
||||
### In AppInit2() (after network init, before starting node):
|
||||
```cpp
|
||||
#include "tor/tor_embedded.h"
|
||||
|
||||
// Near the end of AppInit2, after network initialization:
|
||||
if (!StartEmbeddedTor()) {
|
||||
printf("WARNING: Embedded Tor failed to start. .onion connectivity unavailable.\n");
|
||||
// Non-fatal: wallet works without Tor, just no .onion
|
||||
}
|
||||
```
|
||||
|
||||
### In Shutdown():
|
||||
```cpp
|
||||
StopEmbeddedTor();
|
||||
```
|
||||
|
||||
## Step 5: Configure SOCKS Proxy for Outbound Connections
|
||||
|
||||
After Tor starts, the wallet needs to route `.onion` connections through the
|
||||
SOCKS5 proxy. In `net.cpp`, after Tor is initialized:
|
||||
|
||||
```cpp
|
||||
// If embedded Tor is running, use its SOCKS proxy for .onion addresses
|
||||
CTorEmbedded* tor = CTorEmbedded::GetInstance();
|
||||
if (tor->IsRunning()) {
|
||||
// Set proxy for .onion connections
|
||||
proxyType addrProxy(CService("127.0.0.1", tor->GetSocksPort()), 5);
|
||||
SetNameProxy(addrProxy);
|
||||
}
|
||||
```
|
||||
|
||||
## Runtime Flags
|
||||
|
||||
The embedded Tor respects these command-line flags:
|
||||
|
||||
| Flag | Default | Description |
|
||||
|------|---------|-------------|
|
||||
| `-notor` | false | Disable Tor entirely |
|
||||
| `-torsocks=PORT` | 19099 | SOCKS5 proxy port |
|
||||
| `-torhsport=PORT` | 24112 | Hidden service virtual port |
|
||||
|
||||
## File Layout After Integration
|
||||
|
||||
```
|
||||
src/tor/
|
||||
├── tor-src/ ← git submodule (official Tor repo)
|
||||
│ └── src/
|
||||
│ ├── core/libtor-app.a
|
||||
│ ├── lib/libor-*.a
|
||||
│ ├── trunnel/libor-trunnel.a
|
||||
│ └── feature/api/tor_api.h
|
||||
├── tor_embedded.h ← CTorEmbedded class header
|
||||
├── tor_embedded.cpp ← implementation (calls tor_run_main)
|
||||
├── tor_process.h ← external Tor process manager (fallback)
|
||||
├── tor_process.cpp
|
||||
├── onion_v3.h ← V3 onion address utilities
|
||||
├── onion_v3.cpp
|
||||
├── anonymize.h ← data dir helpers
|
||||
├── anonymize.cpp
|
||||
└── LICENSE
|
||||
```
|
||||
|
||||
## Reference: How VERGE (XVG) Does It
|
||||
|
||||
VERGE uses the same pattern. Their implementation is at:
|
||||
- `src/torcontroller.cpp` (~100 lines)
|
||||
- They use `tor_main()` (older API, pre-0.4.5)
|
||||
- Git submodule at `src/tor/` pointing to `release-0.4.8` branch
|
||||
- Build Tor as part of their `depends/` system
|
||||
|
||||
Key difference: modern Tor (0.4.5+) uses `tor_run_main()` with a configuration
|
||||
object instead of raw `tor_main(int argc, char** argv)`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Tor fails to bootstrap**: Check firewall rules. Tor needs outbound TCP to the
|
||||
Tor network (ports 80, 443, 9001, 9030).
|
||||
|
||||
**Link errors with libtor**: The Tor static libraries must be linked in
|
||||
dependency order. If you get undefined symbols, reorder the `-l` flags or use
|
||||
`-Wl,--start-group ... -Wl,--end-group` to resolve circular deps:
|
||||
```
|
||||
LIBS += -Wl,--start-group -ltor-app -lor -lor-ctime ... -Wl,--end-group
|
||||
```
|
||||
|
||||
**OpenSSL version mismatch**: Both Tor and Triangles must link against the same
|
||||
OpenSSL version (3.x). If Tor was built against a different OpenSSL, rebuild it
|
||||
with the same `--with-openssl-dir`.
|
||||
@@ -3,7 +3,7 @@
|
||||
# Generated by qmake (3.1) (Qt 5.15.18)
|
||||
# Project: triangles-qt.pro
|
||||
# Template: app
|
||||
# Command: C:/msys64/mingw64/bin/qmake-qt5.exe -o Makefile triangles-qt.pro
|
||||
# Command: C:/msys64/mingw64/bin/qmake-qt5.exe -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
|
||||
#############################################################################
|
||||
|
||||
MAKEFILE = Makefile
|
||||
@@ -156,7 +156,7 @@ Makefile: triangles-qt.pro C:/msys64/mingw64/share/qt5/mkspecs/win32-g++/qmake.c
|
||||
C:/msys64/mingw64/lib/qtmain.prl \
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/build_pass.prf \
|
||||
src/qt/triangles.qrc
|
||||
$(QMAKE) -o Makefile triangles-qt.pro
|
||||
$(QMAKE) -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/spec_pre.prf:
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/qdevice.pri:
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/device_config.prf:
|
||||
@@ -244,7 +244,7 @@ C:/msys64/mingw64/lib/qtmain.prl:
|
||||
C:/msys64/mingw64/share/qt5/mkspecs/features/build_pass.prf:
|
||||
src/qt/triangles.qrc:
|
||||
qmake: FORCE
|
||||
@$(QMAKE) -o Makefile triangles-qt.pro
|
||||
@$(QMAKE) -o Makefile triangles-qt.pro USE_QRCODE=1 USE_UPNP=-
|
||||
|
||||
qmake_all: FORCE
|
||||
|
||||
@@ -261,7 +261,7 @@ distclean: release-distclean debug-distclean FORCE
|
||||
-$(DEL_FILE) .qmake.stash
|
||||
|
||||
E:/repos/triangles/src/leveldb/libleveldb.a: FORCE
|
||||
cd E:/repos/triangles/src/leveldb && CC=gcc CXX=g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) OPT="-fpermissive -O2" libleveldb.a libmemenv.a && ranlib E:/repos/triangles/src/leveldb/libleveldb.a && ranlib E:/repos/triangles/src/leveldb/libmemenv.a
|
||||
cd E:/repos/triangles/src/leveldb && CC=gcc CXX=g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) OPT="-fno-keep-inline-dllexport -march=nocona -msahf -mtune=generic -Wa,-mbig-obj -O2" libleveldb.a libmemenv.a && ranlib E:/repos/triangles/src/leveldb/libleveldb.a && ranlib E:/repos/triangles/src/leveldb/libmemenv.a
|
||||
|
||||
release-mocclean:
|
||||
$(MAKE) -f $(MAKEFILE).Release mocclean
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Embedded Tor Rebase Notes
|
||||
|
||||
This repository currently contains a legacy Tor source snapshot under
|
||||
`src/tor/`, but the wallet target does not build most of that tree.
|
||||
|
||||
## Current state
|
||||
|
||||
- The vendored Tor headers report `0.2.5.1-alpha-dev` in:
|
||||
- `src/tor/orconfig_linux.h`
|
||||
- `src/tor/orconfig_apple.h`
|
||||
- `src/tor/orconfig_win32.h`
|
||||
- The Qt wallet target currently builds only these Tor-related sources:
|
||||
- `src/tor_embed_hooks.cpp`
|
||||
- `src/tor/onion_v3.cpp`
|
||||
- `src/tor/tor_process.cpp`
|
||||
- This means the large legacy `src/tor/` tree is mostly dormant from the
|
||||
wallet build's perspective.
|
||||
|
||||
## Rebase target
|
||||
|
||||
- Target upstream Tor line: `0.4.9.x`
|
||||
- Imported source tree: `src/tor/tor-src`
|
||||
- Imported branch: `release-0.4.9`
|
||||
- Imported commit: `1442ca4`
|
||||
|
||||
## Why this matters
|
||||
|
||||
Attempting to "upgrade embedded Tor" by rebasing the entire old source tree in
|
||||
place is unnecessarily expensive if the wallet is only relying on:
|
||||
|
||||
- process management for a bundled Tor executable
|
||||
- Tor v3 onion address/key handling
|
||||
- a few local embedding hooks
|
||||
|
||||
The migration should preserve the embedded product experience while reducing
|
||||
coupling to legacy upstream Tor internals.
|
||||
|
||||
## Strategy
|
||||
|
||||
1. Keep the product-level embedding model.
|
||||
- The wallet can still ship with Tor and launch it automatically.
|
||||
2. Separate Triangles-owned glue from vendored Tor code.
|
||||
- `src/tor_embed_hooks.*` now holds local process/bootstrap helpers that
|
||||
previously lived under `src/tor/anonymize.*`.
|
||||
3. Treat `src/tor/onion_v3.cpp` and `src/tor/tor_process.cpp` as the active
|
||||
compatibility boundary.
|
||||
4. Re-vendor a newer upstream Tor snapshot only after deciding whether the
|
||||
product truly needs upstream Tor source in-tree or only a bundled Tor
|
||||
runtime plus the wallet's own v3/onion management code.
|
||||
|
||||
## Immediate next tasks
|
||||
|
||||
1. Audit whether any live build target still includes legacy `src/tor/*.c`
|
||||
sources beyond the current wallet target.
|
||||
2. Decide whether `onion_v3.cpp` should remain wallet-owned code or be reduced
|
||||
further in favor of runtime Tor control/provisioning.
|
||||
3. Add build metadata recording the intended upstream Tor version and source.
|
||||
4. If full upstream vendoring is still required, import a fresh `0.4.8.19`
|
||||
tree side-by-side instead of trying to patch the legacy `0.2.5.1` tree.
|
||||
+3
-4
@@ -5,7 +5,6 @@
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <map>
|
||||
|
||||
#include "alert.h"
|
||||
@@ -46,10 +45,10 @@ void CUnsignedAlert::SetNull()
|
||||
std::string CUnsignedAlert::ToString() const
|
||||
{
|
||||
std::string strSetCancel;
|
||||
BOOST_FOREACH(int n, setCancel)
|
||||
for (int n : setCancel)
|
||||
strSetCancel += strprintf("%d ", n);
|
||||
std::string strSetSubVer;
|
||||
BOOST_FOREACH(std::string str, setSubVer)
|
||||
for (std::string str : setSubVer)
|
||||
strSetSubVer += "\"" + str + "\" ";
|
||||
return strprintf(
|
||||
"CAlert(\n"
|
||||
@@ -228,7 +227,7 @@ bool CAlert::ProcessAlert(bool fThread)
|
||||
}
|
||||
|
||||
// Check if this alert has been cancelled
|
||||
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
|
||||
for (auto& item : mapAlerts)
|
||||
{
|
||||
const CAlert& alert = item.second;
|
||||
if (alert.Cancels(*this))
|
||||
|
||||
+42
-67
@@ -2,9 +2,6 @@
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "checkpoints.h"
|
||||
|
||||
#include "txdb.h"
|
||||
@@ -22,39 +19,37 @@ namespace Checkpoints
|
||||
// timestamp before)
|
||||
// + Contains no strange transactions
|
||||
//
|
||||
static MapCheckpoints mapCheckpoints =
|
||||
boost::assign::map_list_of
|
||||
( 0, hashGenesisBlockOfficial )
|
||||
( 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467"))
|
||||
( 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059"))
|
||||
( 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e"))
|
||||
( 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51"))
|
||||
( 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6"))
|
||||
( 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b"))
|
||||
( 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db"))
|
||||
( 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007"))
|
||||
( 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249"))
|
||||
( 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6"))
|
||||
( 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47"))
|
||||
(2186940, uint256("0xbd952e8d4a612e336d840ad924a7e09395e36bcd9d929b302e47e60b5c3098c0"))
|
||||
;
|
||||
static MapCheckpoints mapCheckpoints = {
|
||||
{ 0, hashGenesisBlockOfficial },
|
||||
{ 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")},
|
||||
{ 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")},
|
||||
{ 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")},
|
||||
{ 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")},
|
||||
{ 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")},
|
||||
{ 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")},
|
||||
{ 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")},
|
||||
{ 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")},
|
||||
{ 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")},
|
||||
{ 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")},
|
||||
{ 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47")},
|
||||
{2186940, uint256("0xbd952e8d4a612e336d840ad924a7e09395e36bcd9d929b302e47e60b5c3098c0")},
|
||||
};
|
||||
|
||||
static MapCheckpoints mapCheckpointsTestnet =
|
||||
boost::assign::map_list_of
|
||||
( 0, hashGenesisBlockTestNet )
|
||||
( 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467"))
|
||||
( 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059"))
|
||||
( 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e"))
|
||||
( 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51"))
|
||||
( 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6"))
|
||||
( 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b"))
|
||||
( 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db"))
|
||||
( 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007"))
|
||||
( 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249"))
|
||||
( 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6"))
|
||||
( 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47"))
|
||||
(2186940, uint256("0xbd952e8d4a612e336d840ad924a7e09395e36bcd9d929b302e47e60b5c3098c0"))
|
||||
;
|
||||
static MapCheckpoints mapCheckpointsTestnet = {
|
||||
{ 0, hashGenesisBlockTestNet },
|
||||
{ 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")},
|
||||
{ 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")},
|
||||
{ 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")},
|
||||
{ 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")},
|
||||
{ 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")},
|
||||
{ 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")},
|
||||
{ 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")},
|
||||
{ 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")},
|
||||
{ 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")},
|
||||
{ 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")},
|
||||
{ 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47")},
|
||||
{2186940, uint256("0xbd952e8d4a612e336d840ad924a7e09395e36bcd9d929b302e47e60b5c3098c0")},
|
||||
};
|
||||
|
||||
bool CheckHardened(int nHeight, const uint256& hash)
|
||||
{
|
||||
@@ -76,9 +71,9 @@ namespace Checkpoints
|
||||
{
|
||||
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
|
||||
|
||||
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
|
||||
for (auto it = checkpoints.rbegin(); it != checkpoints.rend(); ++it)
|
||||
{
|
||||
const uint256& hash = i.second;
|
||||
const uint256& hash = it->second;
|
||||
std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
|
||||
if (t != mapBlockIndex.end())
|
||||
return t->second;
|
||||
@@ -87,8 +82,8 @@ namespace Checkpoints
|
||||
}
|
||||
|
||||
// triangles: synchronized checkpoint (centrally broadcasted)
|
||||
uint256 hashSyncCheckpoint = uint256("0xbd952e8d4a612e336d840ad924a7e09395e36bcd9d929b302e47e60b5c3098c0");
|
||||
uint256 hashPendingCheckpoint = uint256("0xbd952e8d4a612e336d840ad924a7e09395e36bcd9d929b302e47e60b5c3098c0");
|
||||
uint256 hashSyncCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
||||
uint256 hashPendingCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
|
||||
CSyncCheckpoint checkpointMessage;
|
||||
CSyncCheckpoint checkpointMessagePending;
|
||||
uint256 hashInvalidCheckpoint = 0;
|
||||
@@ -199,7 +194,7 @@ namespace Checkpoints
|
||||
// relay the checkpoint
|
||||
if (!checkpointMessage.IsNull())
|
||||
{
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
checkpointMessage.RelayTo(pnode);
|
||||
}
|
||||
return true;
|
||||
@@ -218,30 +213,10 @@ namespace Checkpoints
|
||||
}
|
||||
|
||||
// Check against synchronized checkpoint
|
||||
// Disabled: master key removed in V5, no new sync checkpoints possible.
|
||||
// Always returns true to prevent stale DB-persisted checkpoints from blocking IBD.
|
||||
bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
|
||||
{
|
||||
if (fTestNet) return true; // Testnet has no checkpoints
|
||||
int nHeight = pindexPrev->nHeight + 1;
|
||||
|
||||
LOCK(cs_hashSyncCheckpoint);
|
||||
// sync-checkpoint should always be accepted block
|
||||
assert(mapBlockIndex.count(hashSyncCheckpoint));
|
||||
const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
|
||||
|
||||
if (nHeight > pindexSync->nHeight)
|
||||
{
|
||||
// trace back to same height as sync-checkpoint
|
||||
const CBlockIndex* pindex = pindexPrev;
|
||||
while (pindex->nHeight > pindexSync->nHeight)
|
||||
if (!(pindex = pindex->pprev))
|
||||
return error("CheckSync: pprev null - block index structure failure");
|
||||
if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
|
||||
return false; // only descendant of sync-checkpoint can pass check
|
||||
}
|
||||
if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
|
||||
return false; // same height with sync-checkpoint
|
||||
if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
|
||||
return false; // lower height than sync-checkpoint
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -284,9 +259,9 @@ namespace Checkpoints
|
||||
printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
|
||||
}
|
||||
|
||||
BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
|
||||
for (auto it = mapCheckpoints.rbegin(); it != mapCheckpoints.rend(); ++it)
|
||||
{
|
||||
const uint256& hash = i.second;
|
||||
const uint256& hash = it->second;
|
||||
if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
|
||||
{
|
||||
if (!WriteSyncCheckpoint(hash))
|
||||
@@ -351,7 +326,7 @@ namespace Checkpoints
|
||||
// Relay checkpoint
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
checkpoint.RelayTo(pnode);
|
||||
}
|
||||
return true;
|
||||
@@ -361,8 +336,8 @@ namespace Checkpoints
|
||||
bool IsMatureSyncCheckpoint()
|
||||
{
|
||||
LOCK(cs_hashSyncCheckpoint);
|
||||
// sync-checkpoint should always be accepted block
|
||||
assert(mapBlockIndex.count(hashSyncCheckpoint));
|
||||
if (!mapBlockIndex.count(hashSyncCheckpoint))
|
||||
return true; // no valid sync checkpoint, treat as mature
|
||||
const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
|
||||
return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity ||
|
||||
pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime());
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@
|
||||
|
||||
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 5
|
||||
#define CLIENT_VERSION_MINOR 1
|
||||
#define CLIENT_VERSION_REVISION 5
|
||||
#define CLIENT_VERSION_MINOR 3
|
||||
#define CLIENT_VERSION_REVISION 0
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
|
||||
// Converts the parameter X to a string after macro replacement on X has been performed.
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ bool CDBEnv::Open(fs::path pathEnv_)
|
||||
if (GetBoolArg("-privdb", true))
|
||||
nEnvFlags |= DB_PRIVATE;
|
||||
|
||||
int nDbCache = GetArg("-dbcache", 128);
|
||||
int nDbCache = GetArg("-dbcache", 2048);
|
||||
dbenv.set_lg_dir(pathLogDir.string().c_str());
|
||||
dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1);
|
||||
dbenv.set_lg_bsize(1048576);
|
||||
|
||||
+72
-23
@@ -11,7 +11,10 @@
|
||||
#include "ui_interface.h"
|
||||
#include "checkpoints.h"
|
||||
#include "smessage.h"
|
||||
#include "openssl_compat.h"
|
||||
#include "tor/tor_embedded.h"
|
||||
#include "tor/onion_v3.h"
|
||||
#include "tor/tor_process.h"
|
||||
#ifdef ENABLE_ZMQ
|
||||
#include "zmqpublishnotifier.h"
|
||||
#endif
|
||||
@@ -139,6 +142,7 @@ void Shutdown(void* parg)
|
||||
if (fFirstThread)
|
||||
{
|
||||
fShutdown = true;
|
||||
|
||||
int64_t nDeferredWaitStart = GetTimeMillis();
|
||||
while (true)
|
||||
{
|
||||
@@ -154,6 +158,7 @@ void Shutdown(void* parg)
|
||||
|
||||
SecureMsgShutdown();
|
||||
ShutdownTorV3();
|
||||
StopEmbeddedTor();
|
||||
|
||||
#ifdef ENABLE_ZMQ
|
||||
if (pzmqNotifier)
|
||||
@@ -178,6 +183,7 @@ void Shutdown(void* parg)
|
||||
fs::remove(GetPidFile());
|
||||
UnregisterWallet(pwalletMain);
|
||||
delete pwalletMain;
|
||||
// DB is flushed and wallet saved - safe to force-exit if something hangs
|
||||
NewThread(ExitTimeout, NULL);
|
||||
MilliSleep(50);
|
||||
printf("Triangles exited\n\n");
|
||||
@@ -328,6 +334,9 @@ std::string HelpMessage()
|
||||
//" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
|
||||
//" -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
|
||||
" -tor=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"
|
||||
" -notor " + _("Disable Tor startup and .onion connectivity") + "\n" +
|
||||
" -torsocks=<port> " + _("Set embedded or managed Tor SOCKS proxy port (default: 19099)") + "\n" +
|
||||
" -torhsport=<port> " + _("Set embedded or managed Tor hidden service port (default: wallet listen port)") + "\n" +
|
||||
//" -dns " + _("Allow DNS lookups for -addnode, -seednode and -connect") + "\n" +
|
||||
" -port=<port> " + _("Listen for connections on <port> (default: 24112 or testnet: 24111)") + "\n" +
|
||||
" -maxconnections=<n> " + _("Maintain at most <n> connections to peers (default: 125)") + "\n" +
|
||||
@@ -403,6 +412,12 @@ std::string HelpMessage()
|
||||
" -rpcsslprivatekeyfile=<file.pem> " + _("Server private key (default: server.pem)") + "\n" +
|
||||
" -rpcsslciphers=<ciphers> " + _("Acceptable ciphers (default: TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!AH:!3DES:@STRENGTH)") + "\n" +
|
||||
|
||||
"\n" + _("REST API options:") + "\n" +
|
||||
" -rest " + _("Enable public REST API on RPC port (default: 0)") + "\n" +
|
||||
" -restcorsorigin=<origin> " + _("CORS Access-Control-Allow-Origin header (default: *)") + "\n" +
|
||||
" -restapikey=<key> " + _("Bearer token for authenticated wallet endpoints") + "\n" +
|
||||
" -restratelimit=<n> " + _("Max requests/sec per IP for public endpoints (default: 30, 0=disabled)") + "\n" +
|
||||
|
||||
"\n" + _("Secure messaging options:") + "\n" +
|
||||
" -nosmsg " + _("Disable secure messaging.") + "\n" +
|
||||
" -debugsmsg " + _("Log extra debug messages.") + "\n" +
|
||||
@@ -641,7 +656,7 @@ bool AppInit2()
|
||||
ShrinkDebugFile();
|
||||
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||
printf("Triangles version %s (%s)\n", FormatFullVersion().c_str(), CLIENT_DATE.c_str());
|
||||
printf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
|
||||
printf("Using OpenSSL version %s\n", TrianglesOpenSSLVersionString());
|
||||
if (!fLogTimestamps)
|
||||
printf("Startup time: %s\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
|
||||
printf("Default data directory %s\n", GetDefaultDataDir().string().c_str());
|
||||
@@ -694,24 +709,26 @@ bool AppInit2()
|
||||
//if (nSocksVersion != 4 && nSocksVersion != 5)
|
||||
// return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
|
||||
|
||||
do {
|
||||
// Network selection: enable all networks (IPv4, IPv6, Tor)
|
||||
// Tor is always enabled; clearnet is also allowed for seed node discovery
|
||||
// Users can restrict to Tor-only with -onlynet=tor
|
||||
if (mapArgs.count("-onlynet")) {
|
||||
std::set<enum Network> nets;
|
||||
|
||||
|
||||
|
||||
|
||||
nets.insert(NET_TOR);
|
||||
|
||||
for (std::string snet : mapMultiArgs["-onlynet"]) {
|
||||
enum Network net = ParseNetwork(snet);
|
||||
if (net == NET_UNROUTABLE)
|
||||
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet.c_str()));
|
||||
nets.insert(net);
|
||||
}
|
||||
for (int n = 0; n < NET_MAX; n++) {
|
||||
enum Network net = (enum Network)n;
|
||||
if (!nets.count(net))
|
||||
SetLimited(net);
|
||||
}
|
||||
} while (false);
|
||||
}
|
||||
|
||||
|
||||
CService addrOnion;
|
||||
// need to move onion_port to a header
|
||||
// Tor proxy: always configured for .onion connectivity
|
||||
CService addrOnion;
|
||||
unsigned short const onion_port = 19099;
|
||||
|
||||
if (mapArgs.count("-tor") && mapArgs["-tor"] != "0") {
|
||||
@@ -722,10 +739,8 @@ bool AppInit2()
|
||||
addrOnion = CService("127.0.0.1", onion_port);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
SetProxy(NET_TOR, addrOnion, 5);
|
||||
SetReachable(NET_TOR);
|
||||
}
|
||||
SetProxy(NET_TOR, addrOnion, 5);
|
||||
SetReachable(NET_TOR);
|
||||
|
||||
// see Step 2: parameter interactions for more information about these
|
||||
fNoListen = !GetBoolArg("-listen", true);
|
||||
@@ -751,11 +766,11 @@ bool AppInit2()
|
||||
|
||||
|
||||
// Release the old Tor initialization mutex (no longer blocking on embedded Tor)
|
||||
set_initialized();
|
||||
triangles_tor_set_initialized();
|
||||
|
||||
if (mapArgs.count("-externalip"))
|
||||
{
|
||||
BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
|
||||
for (string strAddr : mapMultiArgs["-externalip"]) {
|
||||
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
|
||||
if (!addrLocal.IsValid())
|
||||
return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr.c_str()));
|
||||
@@ -779,7 +794,7 @@ bool AppInit2()
|
||||
InitError(_("Unable to sign checkpoint, wrong checkpointkey?\n"));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
|
||||
for (string strDest : mapMultiArgs["-seednode"])
|
||||
AddOneShot(strDest);
|
||||
|
||||
// ********************************************************* Step 7: load blockchain
|
||||
@@ -956,18 +971,34 @@ bool AppInit2()
|
||||
printf(" rescan %15"PRId64"ms\n", GetTimeMillis() - nStart);
|
||||
}
|
||||
|
||||
// ********************************************************* Step 8.5: initialize Tor V3 identity
|
||||
// ********************************************************* Step 8.5: start Tor and initialize V3 identity
|
||||
{
|
||||
uiInterface.InitMessage(_("Starting Tor..."));
|
||||
printf("Starting Tor process...\n");
|
||||
|
||||
bool torStarted = StartEmbeddedTor();
|
||||
std::string torDataPath = CTorEmbedded::GetInstance()->GetDataDir();
|
||||
if (torDataPath.empty())
|
||||
torDataPath = (GetDataDir() / "tor_data").string();
|
||||
|
||||
if (torStarted) {
|
||||
printf("Tor process running, SOCKS proxy at %s\n",
|
||||
CTorEmbedded::GetInstance()->GetSocksProxy().c_str());
|
||||
} else {
|
||||
printf("WARNING: Tor not available. .onion peers will not be reachable.\n");
|
||||
printf(" Clearnet connections will still work normally.\n");
|
||||
}
|
||||
|
||||
// Initialize Tor V3 identity (Ed25519 keys, onion address)
|
||||
uiInterface.InitMessage(_("Initializing Tor V3 identity..."));
|
||||
printf("Initializing Tor V3 onion identity...\n");
|
||||
|
||||
// Tor V3 identity is innate to Triangles — always enabled
|
||||
LoadTorV3Config();
|
||||
TorV3Config& torConfig = GetTorV3Config();
|
||||
torConfig.enableTor = true;
|
||||
torConfig.enableHiddenService = true;
|
||||
torConfig.hiddenServicePort = GetListenPort();
|
||||
torConfig.torDataDirectory = (GetDataDir() / "tor_data").string();
|
||||
torConfig.torDataDirectory = torDataPath;
|
||||
|
||||
if (InitTorV3()) {
|
||||
string onionAddr = CTorV3Manager::GetInstance()->GetWalletOnionAddress();
|
||||
@@ -990,6 +1021,24 @@ bool AppInit2()
|
||||
} else {
|
||||
printf("WARNING: Failed to initialize Tor V3 identity\n");
|
||||
}
|
||||
|
||||
// Also check if Tor gave us a hidden service hostname
|
||||
if (torStarted) {
|
||||
fs::path torHsHostname = fs::path(torDataPath) / "hidden_service" / "hostname";
|
||||
if (fs::exists(torHsHostname)) {
|
||||
ifstream f(torHsHostname.string().c_str());
|
||||
string torOnion;
|
||||
if (f.is_open() && getline(f, torOnion)) {
|
||||
// Trim whitespace
|
||||
while (!torOnion.empty() && (torOnion.back() == '\n' || torOnion.back() == '\r' || torOnion.back() == ' '))
|
||||
torOnion.pop_back();
|
||||
if (!torOnion.empty()) {
|
||||
AddLocal(CService(torOnion, GetListenPort(), fNameLookup), LOCAL_MANUAL);
|
||||
printf("Tor hidden service (from Tor process): %s\n", torOnion.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ********************************************************* Step 9: import blocks
|
||||
@@ -998,7 +1047,7 @@ bool AppInit2()
|
||||
{
|
||||
uiInterface.InitMessage(_("Importing blockchain data file."));
|
||||
|
||||
BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
|
||||
for (string strFile : mapMultiArgs["-loadblock"])
|
||||
{
|
||||
FILE *file = fopen(strFile.c_str(), "rb");
|
||||
if (file)
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
#define TRIANGLES_INIT_H
|
||||
|
||||
#include "wallet.h"
|
||||
#include <tor/anonymize.h>
|
||||
#include "tor_embed_hooks.h"
|
||||
|
||||
extern CWallet* pwalletMain;
|
||||
extern std::string strWalletFileName;
|
||||
|
||||
+5
-8
@@ -2,8 +2,6 @@
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
|
||||
#include "kernel.h"
|
||||
#include "txdb.h"
|
||||
|
||||
@@ -19,10 +17,9 @@ extern unsigned int nTargetSpacing;
|
||||
typedef std::map<int, unsigned int> MapModifierCheckpoints;
|
||||
|
||||
// Hard checkpoints of stake modifiers to ensure they are deterministic
|
||||
static std::map<int, unsigned int> mapStakeModifierCheckpoints =
|
||||
boost::assign::map_list_of
|
||||
( 0, 0x000000000e00670b )
|
||||
;
|
||||
static std::map<int, unsigned int> mapStakeModifierCheckpoints = {
|
||||
{ 0, 0x000000000e00670b },
|
||||
};
|
||||
|
||||
// Get time weight
|
||||
int64_t GetWeight(int64_t nIntervalBeginning, int64_t nIntervalEnd)
|
||||
@@ -80,7 +77,7 @@ static bool SelectBlockFromCandidates(vector<pair<int64_t, uint256> >& vSortedBy
|
||||
bool fSelected = false;
|
||||
uint256 hashBest = 0;
|
||||
*pindexSelected = (const CBlockIndex*) 0;
|
||||
BOOST_FOREACH(const PAIRTYPE(int64_t, uint256)& item, vSortedByTimestamp)
|
||||
for (const auto& item : vSortedByTimestamp)
|
||||
{
|
||||
if (!mapBlockIndex.count(item.second))
|
||||
return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString().c_str());
|
||||
@@ -199,7 +196,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64_t& nStakeMod
|
||||
strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "=");
|
||||
pindex = pindex->pprev;
|
||||
}
|
||||
BOOST_FOREACH(const PAIRTYPE(uint256, const CBlockIndex*)& item, mapSelectedBlocks)
|
||||
for (const auto& item : mapSelectedBlocks)
|
||||
{
|
||||
// 'S' indicates selected proof-of-stake blocks
|
||||
// 'W' indicates selected proof-of-work blocks
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
|
||||
return false;
|
||||
|
||||
fUseCrypto = true;
|
||||
BOOST_FOREACH(KeyMap::value_type& mKey, mapKeys)
|
||||
for (KeyMap::value_type& mKey : mapKeys)
|
||||
{
|
||||
CKey key;
|
||||
if (!key.SetSecret(mKey.second.first, mKey.second.second))
|
||||
|
||||
+292
-149
@@ -120,7 +120,7 @@ void UnregisterWallet(CWallet* pwalletIn)
|
||||
// check whether the passed transaction is from us
|
||||
bool static IsFromMe(CTransaction& tx)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
if (pwallet->IsFromMe(tx))
|
||||
return true;
|
||||
return false;
|
||||
@@ -129,7 +129,7 @@ bool static IsFromMe(CTransaction& tx)
|
||||
// get the wallet transaction with the given hash (if it exists)
|
||||
bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
if (pwallet->GetTransaction(hashTx,wtx))
|
||||
return true;
|
||||
return false;
|
||||
@@ -138,7 +138,7 @@ bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx)
|
||||
// erases transaction with the given hash from all wallets
|
||||
void static EraseFromWallets(uint256 hash)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
pwallet->EraseFromWallet(hash);
|
||||
}
|
||||
|
||||
@@ -150,21 +150,21 @@ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate,
|
||||
// triangles: wallets need to refund inputs when disconnecting coinstake
|
||||
if (tx.IsCoinStake())
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
if (pwallet->IsFromMe(tx))
|
||||
pwallet->DisableTransaction(tx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
|
||||
}
|
||||
|
||||
// notify wallets about a new best chain
|
||||
void static SetBestChain(const CBlockLocator& loc)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
pwallet->SetBestChain(loc);
|
||||
}
|
||||
|
||||
@@ -186,28 +186,28 @@ static bool UpdateAddressIndexSyncState(CTxDB& txdb, const CBlockIndex* pindexNe
|
||||
// notify wallets about an updated transaction
|
||||
void static UpdatedTransaction(const uint256& hashTx)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
pwallet->UpdatedTransaction(hashTx);
|
||||
}
|
||||
|
||||
// dump all wallets
|
||||
void static PrintWallets(const CBlock& block)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
pwallet->PrintWallet(block);
|
||||
}
|
||||
|
||||
// notify wallets about an incoming inventory (for request counts)
|
||||
void static Inventory(const uint256& hash)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
pwallet->Inventory(hash);
|
||||
}
|
||||
|
||||
// ask wallets to resend their transactions
|
||||
void ResendWalletTransactions(bool fForce)
|
||||
{
|
||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||
for (CWallet* pwallet : setpwalletRegistered)
|
||||
pwallet->ResendWalletTransactions(fForce);
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ bool AddOrphanTx(const CTransaction& tx)
|
||||
}
|
||||
|
||||
mapOrphanTransactions[hash] = tx;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
for (const CTxIn& txin : tx.vin)
|
||||
mapOrphanTransactionsByPrev[txin.prevout.hash].insert(hash);
|
||||
|
||||
printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().substr(0,10).c_str(),
|
||||
@@ -258,7 +258,7 @@ void static EraseOrphanTx(uint256 hash)
|
||||
if (!mapOrphanTransactions.count(hash))
|
||||
return;
|
||||
const CTransaction& tx = mapOrphanTransactions[hash];
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
for (const CTxIn& txin : tx.vin)
|
||||
{
|
||||
mapOrphanTransactionsByPrev[txin.prevout.hash].erase(hash);
|
||||
if (mapOrphanTransactionsByPrev[txin.prevout.hash].empty())
|
||||
@@ -327,7 +327,7 @@ bool CTransaction::IsStandard() const
|
||||
if (nVersion > CTransaction::CURRENT_VERSION)
|
||||
return false;
|
||||
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
for (const CTxIn& txin : vin)
|
||||
{
|
||||
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
|
||||
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
|
||||
@@ -340,7 +340,7 @@ bool CTransaction::IsStandard() const
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const CTxOut& txout, vout) {
|
||||
for (const CTxOut& txout : vout) {
|
||||
if (!::IsStandard(txout.scriptPubKey))
|
||||
return false;
|
||||
if (txout.nValue == 0)
|
||||
@@ -421,11 +421,11 @@ unsigned int
|
||||
CTransaction::GetLegacySigOpCount() const
|
||||
{
|
||||
unsigned int nSigOps = 0;
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
for (const CTxIn& txin : vin)
|
||||
{
|
||||
nSigOps += txin.scriptSig.GetSigOpCount(false);
|
||||
}
|
||||
BOOST_FOREACH(const CTxOut& txout, vout)
|
||||
for (const CTxOut& txout : vout)
|
||||
{
|
||||
nSigOps += txout.scriptPubKey.GetSigOpCount(false);
|
||||
}
|
||||
@@ -519,7 +519,7 @@ bool CTransaction::CheckTransaction() const
|
||||
|
||||
// Check for duplicate inputs
|
||||
set<COutPoint> vInOutPoints;
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
for (const CTxIn& txin : vin)
|
||||
{
|
||||
if (vInOutPoints.count(txin.prevout))
|
||||
return false;
|
||||
@@ -533,7 +533,7 @@ bool CTransaction::CheckTransaction() const
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
for (const CTxIn& txin : vin)
|
||||
if (txin.prevout.IsNull())
|
||||
return DoS(10, error("CTransaction::CheckTransaction() : prevout is null"));
|
||||
}
|
||||
@@ -552,7 +552,7 @@ int64_t CTransaction::GetMinFee(unsigned int nBlockSize, enum GetMinFee_mode mod
|
||||
// To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01
|
||||
if (nMinFee < nBaseFee)
|
||||
{
|
||||
BOOST_FOREACH(const CTxOut& txout, vout)
|
||||
for (const CTxOut& txout : vout)
|
||||
if (txout.nValue < CENT)
|
||||
nMinFee = nBaseFee;
|
||||
}
|
||||
@@ -767,7 +767,7 @@ bool CTxMemPool::remove(const CTransaction &tx, bool fRecursive)
|
||||
remove(*it->second.ptx, true);
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
for (const CTxIn& txin : tx.vin)
|
||||
mapNextTx.erase(txin.prevout);
|
||||
mapTx.erase(hash);
|
||||
nTransactionsUpdated++;
|
||||
@@ -780,7 +780,7 @@ bool CTxMemPool::removeConflicts(const CTransaction &tx)
|
||||
{
|
||||
// Remove transactions which depend on inputs of tx, recursively
|
||||
LOCK(cs);
|
||||
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
|
||||
for (const CTxIn &txin : tx.vin) {
|
||||
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(txin.prevout);
|
||||
if (it != mapNextTx.end()) {
|
||||
const CTransaction &txConflict = *it->second.ptx;
|
||||
@@ -882,7 +882,7 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
// Add previous supporting transactions first
|
||||
BOOST_FOREACH(CMerkleTx& tx, vtxPrev)
|
||||
for (CMerkleTx& tx : vtxPrev)
|
||||
{
|
||||
if (!(tx.IsCoinBase() || tx.IsCoinStake()))
|
||||
{
|
||||
@@ -1220,7 +1220,7 @@ bool CTransaction::DisconnectInputs(CTxDB& txdb)
|
||||
// Relinquish previous transactions' spent pointers
|
||||
if (!IsCoinBase())
|
||||
{
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
for (const CTxIn& txin : vin)
|
||||
{
|
||||
COutPoint prevout = txin.prevout;
|
||||
|
||||
@@ -1627,7 +1627,7 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex)
|
||||
}
|
||||
|
||||
// triangles: clean up wallet after disconnecting coinstake
|
||||
BOOST_FOREACH(CTransaction& tx, vtx)
|
||||
for (CTransaction& tx : vtx)
|
||||
SyncWithWallets(tx, this, false, false);
|
||||
|
||||
return true;
|
||||
@@ -1639,6 +1639,12 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
if (!CheckBlock(!fJustCheck, !fJustCheck, false))
|
||||
return false;
|
||||
|
||||
// Determine if this block is covered by the hardcoded checkpoint.
|
||||
// Below checkpoint: skip all input validation, FetchInputs, ConnectInputs,
|
||||
// and wallet sync. The checkpoint hash guarantees chain integrity for these blocks.
|
||||
bool fAssumeValid = (pindex->nHeight <= Checkpoints::GetTotalBlocksEstimate());
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
|
||||
//// issue here: it doesn't know the version
|
||||
unsigned int nTxPos;
|
||||
if (fJustCheck)
|
||||
@@ -1654,10 +1660,24 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
int64_t nValueOut = 0;
|
||||
int64_t nStakeReward = 0;
|
||||
unsigned int nSigOps = 0;
|
||||
BOOST_FOREACH(CTransaction& tx, vtx)
|
||||
for (CTransaction& tx : vtx)
|
||||
{
|
||||
uint256 hashTx = tx.GetHash();
|
||||
|
||||
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
|
||||
if (!fJustCheck)
|
||||
nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
||||
|
||||
// Fast path: below checkpoint, skip all input validation and spent-tracking.
|
||||
// Just record where each transaction lives on disk (txindex).
|
||||
if (fAssumeValid)
|
||||
{
|
||||
mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Full validation path (above checkpoint)
|
||||
|
||||
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
|
||||
// unless those are already completely spent.
|
||||
// If such overwrites are allowed, coinbases and transactions depending upon those
|
||||
@@ -1672,7 +1692,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
// initial block download.
|
||||
CTxIndex txindexOld;
|
||||
if (txdb.ReadTxIndex(hashTx, txindexOld)) {
|
||||
BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent)
|
||||
for (CDiskTxPos &pos : txindexOld.vSpent)
|
||||
if (pos.IsNull())
|
||||
return false;
|
||||
}
|
||||
@@ -1681,10 +1701,6 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
if (nSigOps > MAX_BLOCK_SIGOPS)
|
||||
return DoS(100, error("ConnectBlock() : too many sigops"));
|
||||
|
||||
CDiskTxPos posThisTx(pindex->nFile, pindex->nBlockPos, nTxPos);
|
||||
if (!fJustCheck)
|
||||
nTxPos += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION);
|
||||
|
||||
MapPrevTx mapInputs;
|
||||
if (tx.IsCoinBase())
|
||||
nValueOut += tx.GetValueOut();
|
||||
@@ -1717,20 +1733,18 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
mapQueuedChanges[hashTx] = CTxIndex(posThisTx, tx.vout.size());
|
||||
}
|
||||
|
||||
if (IsProofOfWork() && pindex->nHeight > Checkpoints::GetTotalBlocksEstimate())
|
||||
if (!fAssumeValid)
|
||||
{
|
||||
int64_t nReward = GetProofOfWorkReward(nFees);
|
||||
// Check coinbase reward
|
||||
if (vtx[0].GetValueOut() > nReward)
|
||||
return DoS(50, error("ConnectBlock() : coinbase reward exceeded (actual=%"PRId64" vs calculated=%"PRId64")",
|
||||
vtx[0].GetValueOut(),
|
||||
nReward));
|
||||
}
|
||||
if (IsProofOfStake())
|
||||
if (IsProofOfWork())
|
||||
{
|
||||
// Skip expensive coin age calculation and reward validation for blocks
|
||||
// covered by the hardcoded checkpoint. The checkpoint guarantees chain integrity.
|
||||
if (pindex->nHeight > Checkpoints::GetTotalBlocksEstimate())
|
||||
int64_t nReward = GetProofOfWorkReward(nFees);
|
||||
// Check coinbase reward
|
||||
if (vtx[0].GetValueOut() > nReward)
|
||||
return DoS(50, error("ConnectBlock() : coinbase reward exceeded (actual=%"PRId64" vs calculated=%"PRId64")",
|
||||
vtx[0].GetValueOut(),
|
||||
nReward));
|
||||
}
|
||||
if (IsProofOfStake())
|
||||
{
|
||||
// triangles: coin stake tx earns reward instead of paying fee
|
||||
uint64_t nCoinAge;
|
||||
@@ -1760,8 +1774,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
return error("ConnectBlock() : UpdateTxIndex failed");
|
||||
}
|
||||
|
||||
// Update address index
|
||||
if (fAddressIndex)
|
||||
// Update address index (skip during IBD - will be rebuilt on next start with -reindex)
|
||||
if (fAddressIndex && !fIsInitialDownload)
|
||||
{
|
||||
for (unsigned int i = 0; i < vtx.size(); i++)
|
||||
{
|
||||
@@ -1834,11 +1848,11 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck)
|
||||
return error("ConnectBlock() : WriteBlockIndex failed");
|
||||
}
|
||||
|
||||
// Watch for transactions paying to me
|
||||
// Skip during initial block download - wallet will rescan on next normal startup
|
||||
if (!IsInitialBlockDownload())
|
||||
// Skip wallet sync during IBD - a full wallet rescan runs when IBD completes.
|
||||
// This eliminates millions of per-transaction wallet lookups during sync.
|
||||
if (!fIsInitialDownload)
|
||||
{
|
||||
BOOST_FOREACH(CTransaction& tx, vtx)
|
||||
for (CTransaction& tx : vtx)
|
||||
SyncWithWallets(tx, this, true);
|
||||
}
|
||||
|
||||
@@ -1879,7 +1893,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
|
||||
// Disconnect shorter branch
|
||||
vector<CTransaction> vResurrect;
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
|
||||
for (CBlockIndex* pindex : vDisconnect)
|
||||
{
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
@@ -1888,7 +1902,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
return error("Reorganize() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str());
|
||||
|
||||
// Queue memory transactions to resurrect
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
for (const CTransaction& tx : block.vtx)
|
||||
if (!(tx.IsCoinBase() || tx.IsCoinStake()))
|
||||
vResurrect.push_back(tx);
|
||||
}
|
||||
@@ -1908,7 +1922,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
}
|
||||
|
||||
// Queue memory transactions to delete
|
||||
BOOST_FOREACH(const CTransaction& tx, block.vtx)
|
||||
for (const CTransaction& tx : block.vtx)
|
||||
vDelete.push_back(tx);
|
||||
}
|
||||
if (!txdb.WriteHashBestChain(pindexNew->GetBlockHash()))
|
||||
@@ -1921,21 +1935,21 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
return error("Reorganize() : TxnCommit failed");
|
||||
|
||||
// Disconnect shorter branch
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vDisconnect)
|
||||
for (CBlockIndex* pindex : vDisconnect)
|
||||
if (pindex->pprev)
|
||||
pindex->pprev->pnext = NULL;
|
||||
|
||||
// Connect longer branch
|
||||
BOOST_FOREACH(CBlockIndex* pindex, vConnect)
|
||||
for (CBlockIndex* pindex : vConnect)
|
||||
if (pindex->pprev)
|
||||
pindex->pprev->pnext = pindex;
|
||||
|
||||
// Resurrect memory transactions that were in the disconnected branch
|
||||
BOOST_FOREACH(CTransaction& tx, vResurrect)
|
||||
for (CTransaction& tx : vResurrect)
|
||||
tx.AcceptToMemoryPool(txdb, false);
|
||||
|
||||
// Delete redundant memory transactions that are in the connected branch
|
||||
BOOST_FOREACH(CTransaction& tx, vDelete) {
|
||||
for (CTransaction& tx : vDelete) {
|
||||
mempool.remove(tx);
|
||||
mempool.removeConflicts(tx);
|
||||
}
|
||||
@@ -1965,7 +1979,7 @@ bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew)
|
||||
pindexNew->pprev->pnext = pindexNew;
|
||||
|
||||
// Delete redundant memory transactions
|
||||
BOOST_FOREACH(CTransaction& tx, vtx)
|
||||
for (CTransaction& tx : vtx)
|
||||
mempool.remove(tx);
|
||||
|
||||
return true;
|
||||
@@ -2020,8 +2034,9 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
}
|
||||
|
||||
// Connect further blocks
|
||||
BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary)
|
||||
for (auto rit = vpindexSecondary.rbegin(); rit != vpindexSecondary.rend(); ++rit)
|
||||
{
|
||||
CBlockIndex *pindex = *rit;
|
||||
CBlock block;
|
||||
if (!block.ReadFromDisk(pindex))
|
||||
{
|
||||
@@ -2038,7 +2053,8 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
}
|
||||
}
|
||||
|
||||
// Update best block in wallet (so we can detect restored wallets)
|
||||
// Update best block in wallet (so we can detect restored wallets).
|
||||
// During IBD, skip this so the wallet knows it needs rescanning on restart.
|
||||
bool fIsInitialDownload = IsInitialBlockDownload();
|
||||
if (!fIsInitialDownload)
|
||||
{
|
||||
@@ -2057,7 +2073,8 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
|
||||
uint256 nBestBlockTrust = pindexBest->nHeight != 0 ? (pindexBest->nChainTrust - pindexBest->pprev->nChainTrust) : pindexBest->nChainTrust;
|
||||
|
||||
if (nBestHeight % 10000 == 0 || nBestHeight > 2186900)
|
||||
// Log every 5000 blocks during sync, every block once caught up
|
||||
if (nBestHeight % 5000 == 0 || !IsInitialBlockDownload())
|
||||
printf("SetBestChain: new best=%s height=%d trust=%s blocktrust=%"PRId64" date=%s\n",
|
||||
hashBestChain.ToString().substr(0,20).c_str(), nBestHeight,
|
||||
CBigNum(nBestChainTrust).ToString().c_str(),
|
||||
@@ -2108,6 +2125,40 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
|
||||
pNotificationQueue->Push(strBlockEvent);
|
||||
}
|
||||
|
||||
// Detect IBD-to-synced transition and trigger deferred work:
|
||||
// wallet rescan (since SyncWithWallets was skipped) and smsg chain scan.
|
||||
{
|
||||
static bool fWasInitialDownload = true;
|
||||
if (fWasInitialDownload && !fIsInitialDownload)
|
||||
{
|
||||
printf("*** Initial block download complete at height %d ***\n", nBestHeight);
|
||||
|
||||
// Update wallet best chain locator now that IBD is done
|
||||
const CBlockLocator locator(pindexBest);
|
||||
::SetBestChain(locator);
|
||||
|
||||
// Wallet rescan: SyncWithWallets was skipped during IBD, so scan
|
||||
// the entire chain to pick up all wallet transactions.
|
||||
if (pwalletMain)
|
||||
{
|
||||
printf("Starting post-IBD wallet rescan from genesis...\n");
|
||||
uiInterface.InitMessage(_("Rescanning wallet..."));
|
||||
int nFound = pwalletMain->ScanForWalletTransactions(pindexGenesisBlock, true);
|
||||
printf("Post-IBD wallet rescan complete: %d transactions found\n", nFound);
|
||||
}
|
||||
|
||||
// Secure messaging: scan chain for public keys needed to decrypt messages
|
||||
if (fSecMsgEnabled)
|
||||
{
|
||||
printf("Starting post-IBD secure message chain scan...\n");
|
||||
uiInterface.InitMessage(_("Scanning for secure messages..."));
|
||||
SecureMsgScanBlockChain();
|
||||
printf("Post-IBD secure message chain scan complete\n");
|
||||
}
|
||||
}
|
||||
fWasInitialDownload = fIsInitialDownload;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2126,7 +2177,7 @@ bool CTransaction::GetCoinAge(CTxDB& txdb, uint64_t& nCoinAge) const
|
||||
if (IsCoinBase())
|
||||
return true;
|
||||
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
for (const CTxIn& txin : vin)
|
||||
{
|
||||
// First try finding the previous transaction in database
|
||||
CTransaction txPrev;
|
||||
@@ -2163,7 +2214,7 @@ bool CBlock::GetCoinAge(uint64_t& nCoinAge) const
|
||||
nCoinAge = 0;
|
||||
|
||||
CTxDB txdb("r");
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
for (const CTransaction& tx : vtx)
|
||||
{
|
||||
uint64_t nTxCoinAge;
|
||||
if (tx.GetCoinAge(txdb, nTxCoinAge))
|
||||
@@ -2319,7 +2370,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c
|
||||
}
|
||||
|
||||
// Check transactions
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
for (const CTransaction& tx : vtx)
|
||||
{
|
||||
if (!tx.CheckTransaction())
|
||||
return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed"));
|
||||
@@ -2332,7 +2383,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c
|
||||
// Check for duplicate txids. This is caught by ConnectInputs(),
|
||||
// but catching it earlier avoids a potential DoS attack:
|
||||
set<uint256> uniqueTx;
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
for (const CTransaction& tx : vtx)
|
||||
{
|
||||
uniqueTx.insert(tx.GetHash());
|
||||
}
|
||||
@@ -2340,7 +2391,7 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c
|
||||
return DoS(100, error("CheckBlock() : duplicate transaction"));
|
||||
|
||||
unsigned int nSigOps = 0;
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
for (const CTransaction& tx : vtx)
|
||||
{
|
||||
nSigOps += tx.GetLegacySigOpCount();
|
||||
}
|
||||
@@ -2397,7 +2448,7 @@ bool CBlock::AcceptBlock()
|
||||
return error("AcceptBlock() : block's timestamp is too early");
|
||||
|
||||
// Check that all transactions are finalized
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
for (const CTransaction& tx : vtx)
|
||||
if (!tx.IsFinal(nHeight, GetBlockTime()))
|
||||
return DoS(10, error("AcceptBlock() : contains a non-final transaction"));
|
||||
|
||||
@@ -2421,18 +2472,10 @@ bool CBlock::AcceptBlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Before fork: enforce sync checkpoints for historical chain integrity
|
||||
// After fork: no sync checkpoint enforcement (decentralized)
|
||||
if (nHeight < FORK_HEIGHT_V5)
|
||||
{
|
||||
bool cpSatisfies = Checkpoints::CheckSync(hash, pindexPrev);
|
||||
|
||||
if (CheckpointsMode == Checkpoints::STRICT && !cpSatisfies)
|
||||
return error("AcceptBlock() : rejected by synchronized checkpoint");
|
||||
|
||||
if (CheckpointsMode == Checkpoints::ADVISORY && !cpSatisfies)
|
||||
strMiscWarning = _("WARNING: syncronized checkpoint violation detected, but skipped!");
|
||||
}
|
||||
// Sync checkpoint enforcement is disabled:
|
||||
// - Master key was removed in V5 fork, no new sync checkpoints will be broadcast
|
||||
// - Hardcoded checkpoints already guarantee chain integrity
|
||||
// - The persisted hashSyncCheckpoint in LevelDB blocks IBD from progressing
|
||||
|
||||
// Enforce rule that the coinbase starts with serialized block height
|
||||
CScript expect = CScript() << nHeight;
|
||||
@@ -2455,7 +2498,7 @@ bool CBlock::AcceptBlock()
|
||||
if (hashBestChain == hash)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
|
||||
pnode->PushInventory(CInv(MSG_BLOCK, hash));
|
||||
}
|
||||
@@ -2508,37 +2551,40 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
|
||||
// Skip block signature verification during initial block download (below checkpoint).
|
||||
// The hardcoded checkpoint guarantees historical chain integrity.
|
||||
if (!pblock->CheckBlock(true, true, !IsInitialBlockDownload()))
|
||||
return error("ProcessBlock() : CheckBlock FAILED");
|
||||
|
||||
CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
|
||||
|
||||
if(pcheckpoint && fDebug)
|
||||
{
|
||||
const CBlockIndex* pindexLastPos = GetLastBlockIndex(pcheckpoint, true);
|
||||
if(pindexLastPos)
|
||||
{
|
||||
printf("ProcessBlock(): Last POS Block Height: %d \n", pindexLastPos->nHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ProcessBlock(): Previous POS block not found.\n");
|
||||
}
|
||||
printf("IBD-DIAG: CheckBlock FAILED for %s (PoS=%d, IBD=%d)\n",
|
||||
hash.ToString().substr(0,20).c_str(), pblock->IsProofOfStake(), IsInitialBlockDownload());
|
||||
return error("ProcessBlock() : CheckBlock FAILED");
|
||||
}
|
||||
|
||||
// Anti-spam: reject blocks with insufficient difficulty to prevent memory flooding.
|
||||
// Use sync checkpoint as reference; fall back to chain tip if checkpoint is genesis.
|
||||
CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
|
||||
if (!pcheckpoint || pcheckpoint->nHeight == 0)
|
||||
pcheckpoint = pindexBest;
|
||||
|
||||
if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash))
|
||||
{
|
||||
// Extra checks to prevent "fill up memory by spamming with bogus blocks"
|
||||
int64_t deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime;
|
||||
CBigNum bnNewBlock;
|
||||
bnNewBlock.SetCompact(pblock->nBits);
|
||||
CBigNum bnRequired;
|
||||
|
||||
if (pblock->IsProofOfStake())
|
||||
bnRequired.SetCompact(ComputeMinStake(GetLastBlockIndex(pcheckpoint, true)->nBits, deltaTime, pblock->nTime));
|
||||
{
|
||||
const CBlockIndex* pindexLastPos = GetLastBlockIndex(pcheckpoint, true);
|
||||
if (pindexLastPos)
|
||||
bnRequired.SetCompact(ComputeMinStake(pindexLastPos->nBits, deltaTime, pblock->nTime));
|
||||
// else: no PoS history yet (below block 9001), skip — AcceptBlock rejects PoS below MODIFIER_INTERVAL_SWITCH
|
||||
}
|
||||
else
|
||||
bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, false)->nBits, deltaTime));
|
||||
{
|
||||
const CBlockIndex* pindexLastPow = GetLastBlockIndex(pcheckpoint, false);
|
||||
if (pindexLastPow)
|
||||
bnRequired.SetCompact(ComputeMinWork(pindexLastPow->nBits, deltaTime));
|
||||
}
|
||||
|
||||
if (bnNewBlock > bnRequired)
|
||||
if (bnRequired != 0 && bnNewBlock > bnRequired)
|
||||
{
|
||||
if (pfrom)
|
||||
pfrom->Misbehaving(100);
|
||||
@@ -2568,6 +2614,31 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
|
||||
mapOrphanBlocks.insert(make_pair(hash, pblock2));
|
||||
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
|
||||
|
||||
// Limit orphan blocks to prevent memory exhaustion
|
||||
if (mapOrphanBlocks.size() > MAX_ORPHAN_BLOCKS)
|
||||
{
|
||||
// Evict a random orphan
|
||||
uint256 randomhash = GetRandHash();
|
||||
auto it = mapOrphanBlocks.lower_bound(randomhash);
|
||||
if (it == mapOrphanBlocks.end())
|
||||
it = mapOrphanBlocks.begin();
|
||||
CBlock* pblockEvict = it->second;
|
||||
uint256 evictHash = it->first;
|
||||
// Remove from by-prev index
|
||||
for (auto range = mapOrphanBlocksByPrev.equal_range(pblockEvict->hashPrevBlock);
|
||||
range.first != range.second; ++range.first)
|
||||
{
|
||||
if (range.first->second == pblockEvict) {
|
||||
mapOrphanBlocksByPrev.erase(range.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
setStakeSeenOrphan.erase(pblockEvict->GetProofOfStake());
|
||||
delete pblockEvict;
|
||||
mapOrphanBlocks.erase(evictHash);
|
||||
printf("ProcessBlock: orphan eviction, %u orphans remain\n", (unsigned int)mapOrphanBlocks.size());
|
||||
}
|
||||
|
||||
// Ask this guy to fill in what we're missing
|
||||
if (pfrom)
|
||||
{
|
||||
@@ -2604,8 +2675,8 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
|
||||
mapOrphanBlocksByPrev.erase(hashPrev);
|
||||
}
|
||||
|
||||
if (nBestHeight % 10000 == 0 || nBestHeight > 2186900)
|
||||
printf("ProcessBlock: ACCEPTED\n");
|
||||
if (nBestHeight % 5000 == 0 || !IsInitialBlockDownload())
|
||||
printf("ProcessBlock: ACCEPTED block %d\n", nBestHeight);
|
||||
|
||||
// triangles: if responsible for sync-checkpoint send it
|
||||
if (pfrom && !CSyncCheckpoint::strMasterPrivKey.empty())
|
||||
@@ -3048,7 +3119,7 @@ string GetWarnings(string strFor)
|
||||
// Alerts
|
||||
{
|
||||
LOCK(cs_mapAlerts);
|
||||
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
|
||||
for (auto& item : mapAlerts)
|
||||
{
|
||||
const CAlert& alert = item.second;
|
||||
if (alert.AppliesToMe() && alert.nPriority > nPriority)
|
||||
@@ -3217,31 +3288,33 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
}
|
||||
}
|
||||
|
||||
// Ask the first connected node for block updates
|
||||
// Ask connected nodes for block updates
|
||||
// During IBD, always request blocks from any valid peer (critical for reconnection)
|
||||
static int nAskedForBlocks = 0;
|
||||
if (!pfrom->fClient && !pfrom->fOneShot &&
|
||||
bool fShouldAsk = !pfrom->fClient && !pfrom->fOneShot &&
|
||||
(pfrom->nStartingHeight > (nBestHeight - 144)) &&
|
||||
(pfrom->nVersion < NOBLKS_VERSION_START ||
|
||||
pfrom->nVersion >= NOBLKS_VERSION_END) &&
|
||||
(nAskedForBlocks < 1 || vNodes.size() <= 1))
|
||||
(IsInitialBlockDownload() || nAskedForBlocks < 1 || vNodes.size() <= 1);
|
||||
printf("IBD-DIAG: version handler: peer=%s height=%d ourHeight=%d fClient=%d fOneShot=%d shouldAsk=%d nAskedForBlocks=%d IBD=%d\n",
|
||||
pfrom->addr.ToString().c_str(), pfrom->nStartingHeight, nBestHeight,
|
||||
pfrom->fClient, pfrom->fOneShot, fShouldAsk, nAskedForBlocks, IsInitialBlockDownload());
|
||||
if (fShouldAsk)
|
||||
{
|
||||
nAskedForBlocks++;
|
||||
pfrom->PushGetHeaders(pindexBest, uint256(0));
|
||||
pfrom->PushGetBlocks(pindexBest, uint256(0));
|
||||
printf("IBD-DIAG: sent getblocks from height %d to peer %s\n", nBestHeight, pfrom->addr.ToString().c_str());
|
||||
}
|
||||
|
||||
// Relay alerts
|
||||
{
|
||||
LOCK(cs_mapAlerts);
|
||||
BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
|
||||
for (auto& item : mapAlerts)
|
||||
item.second.RelayTo(pfrom);
|
||||
}
|
||||
|
||||
// triangles: relay sync-checkpoint
|
||||
{
|
||||
LOCK(Checkpoints::cs_hashSyncCheckpoint);
|
||||
if (!Checkpoints::checkpointMessage.IsNull())
|
||||
Checkpoints::checkpointMessage.RelayTo(pfrom);
|
||||
}
|
||||
// Sync checkpoint relay disabled (master key removed in V5 fork).
|
||||
// Relaying stale checkpoints causes IBD nodes to request far-future blocks.
|
||||
|
||||
pfrom->fSuccessfullyConnected = true;
|
||||
|
||||
@@ -3287,7 +3360,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
vector<CAddress> vAddrOk;
|
||||
int64_t nNow = GetAdjustedTime();
|
||||
int64_t nSince = nNow - 10 * 60;
|
||||
BOOST_FOREACH(CAddress& addr, vAddr)
|
||||
for (CAddress& addr : vAddr)
|
||||
{
|
||||
if (fShutdown)
|
||||
return true;
|
||||
@@ -3309,7 +3382,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
|
||||
hashRand = Hash(BEGIN(hashRand), END(hashRand));
|
||||
multimap<uint256, CNode*> mapMix;
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
if (pnode->nVersion < CADDR_TIME_VERSION)
|
||||
continue;
|
||||
@@ -3347,13 +3420,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
|
||||
// find last block in inv vector
|
||||
unsigned int nLastBlock = (unsigned int)(-1);
|
||||
int nBlockInv = 0, nTxInv = 0;
|
||||
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
|
||||
if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) {
|
||||
if (vInv[nInv].type == MSG_BLOCK) nBlockInv++;
|
||||
else nTxInv++;
|
||||
if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK && nLastBlock == (unsigned int)(-1)) {
|
||||
nLastBlock = vInv.size() - 1 - nInv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("IBD-DIAG: inv received: %d blocks, %d tx from %s (our height=%d)\n",
|
||||
nBlockInv, nTxInv, pfrom->addr.ToString().c_str(), nBestHeight);
|
||||
|
||||
CTxDB txdb("r");
|
||||
int nNew = 0, nAlready = 0;
|
||||
for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
|
||||
{
|
||||
const CInv &inv = vInv[nInv];
|
||||
@@ -3363,25 +3442,24 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
pfrom->AddInventoryKnown(inv);
|
||||
|
||||
bool fAlreadyHave = AlreadyHave(txdb, inv);
|
||||
if (fDebug)
|
||||
printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");
|
||||
if (inv.type == MSG_BLOCK) {
|
||||
if (fAlreadyHave) nAlready++; else nNew++;
|
||||
}
|
||||
|
||||
if (!fAlreadyHave)
|
||||
pfrom->AskFor(inv);
|
||||
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
|
||||
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
|
||||
} else if (nInv == nLastBlock) {
|
||||
// In case we are on a very long side-chain, it is possible that we already have
|
||||
// the last block in an inv bundle sent in response to getblocks. Try to detect
|
||||
// this situation and push another getblocks to continue.
|
||||
pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
|
||||
if (fDebug)
|
||||
printf("force request: %s\n", inv.ToString().c_str());
|
||||
printf("IBD-DIAG: inv last block already known, pushing getblocks from %d\n",
|
||||
mapBlockIndex[inv.hash]->nHeight);
|
||||
}
|
||||
|
||||
// Track requests for our stuff
|
||||
Inventory(inv.hash);
|
||||
}
|
||||
if (nBlockInv > 0)
|
||||
printf("IBD-DIAG: inv result: %d new blocks requested, %d already have\n", nNew, nAlready);
|
||||
}
|
||||
|
||||
|
||||
@@ -3398,7 +3476,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
if (fDebugNet || (vInv.size() != 1))
|
||||
printf("received getdata (%"PRIszu" invsz)\n", vInv.size());
|
||||
|
||||
BOOST_FOREACH(const CInv& inv, vInv)
|
||||
for (const CInv& inv : vInv)
|
||||
{
|
||||
if (fShutdown)
|
||||
return true;
|
||||
@@ -3470,8 +3548,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
// Send the rest of the chain
|
||||
if (pindex)
|
||||
pindex = pindex->pnext;
|
||||
int nLimit = 500;
|
||||
printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
|
||||
int nLimit = IsInitialBlockDownload() ? 20000 : 500;
|
||||
printf("IBD-DIAG: getblocks request from peer %s: start=%d stop=%s limit=%d\n",
|
||||
pfrom->addr.ToString().c_str(), (pindex ? pindex->nHeight : -1),
|
||||
hashStop.ToString().substr(0,20).c_str(), nLimit);
|
||||
for (; pindex; pindex = pindex->pnext)
|
||||
{
|
||||
if (pindex->GetBlockHash() == hashStop)
|
||||
@@ -3496,17 +3576,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
}
|
||||
else if (strCommand == "checkpoint")
|
||||
{
|
||||
CSyncCheckpoint checkpoint;
|
||||
vRecv >> checkpoint;
|
||||
|
||||
if (checkpoint.ProcessSyncCheckpoint(pfrom))
|
||||
{
|
||||
// Relay
|
||||
pfrom->hashCheckpointKnown = checkpoint.hashCheckpoint;
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
checkpoint.RelayTo(pnode);
|
||||
}
|
||||
// Sync checkpoint system disabled (master key removed in V5 fork).
|
||||
// Ignore checkpoint messages — processing them during IBD causes the
|
||||
// node to request a single far-future block instead of syncing sequentially.
|
||||
}
|
||||
|
||||
else if (strCommand == "getheaders")
|
||||
@@ -3557,7 +3629,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
CTxDB txdb("r");
|
||||
uint256 hashChainTip = 0;
|
||||
int nRequested = 0;
|
||||
BOOST_FOREACH(const CBlock& header, vHeaders)
|
||||
for (const CBlock& header : vHeaders)
|
||||
{
|
||||
if (!header.vtx.empty())
|
||||
{
|
||||
@@ -3599,6 +3671,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
|
||||
if (nRequested > 0 && fDebug)
|
||||
printf("requested %d blocks from headers announcement\n", nRequested);
|
||||
|
||||
// If we received a full batch, continue sync via getblocks
|
||||
// (the getblocks/inv/orphan cycle handles chain continuation)
|
||||
if (vHeaders.size() >= 2000)
|
||||
pfrom->PushGetBlocks(pindexBest, uint256(0));
|
||||
}
|
||||
|
||||
|
||||
@@ -3653,7 +3730,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_FOREACH(uint256 hash, vEraseQueue)
|
||||
for (uint256 hash : vEraseQueue)
|
||||
EraseOrphanTx(hash);
|
||||
}
|
||||
else if (fMissingInputs)
|
||||
@@ -3675,19 +3752,50 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
vRecv >> block;
|
||||
uint256 hashBlock = block.GetHash();
|
||||
|
||||
printf("received block %s\n", hashBlock.ToString().substr(0,20).c_str());
|
||||
// block.print();
|
||||
// Log every block during IBD (with throttling after first 100)
|
||||
static int64_t nLastBlockLog = 0;
|
||||
static int nBlocksReceived = 0;
|
||||
nBlocksReceived++;
|
||||
bool fLogThis = (nBlocksReceived <= 20) || (nBestHeight % 500 == 0) || !IsInitialBlockDownload() || (GetTime() - nLastBlockLog >= 5);
|
||||
if (fLogThis) {
|
||||
printf("IBD-DIAG: block received #%d hash=%s from=%s ourHeight=%d\n",
|
||||
nBlocksReceived, hashBlock.ToString().substr(0,20).c_str(),
|
||||
pfrom->addr.ToString().c_str(), nBestHeight);
|
||||
nLastBlockLog = GetTime();
|
||||
}
|
||||
|
||||
CInv inv(MSG_BLOCK, hashBlock);
|
||||
pfrom->AddInventoryKnown(inv);
|
||||
|
||||
if (ProcessBlock(pfrom, &block))
|
||||
{
|
||||
mapAlreadyAskedFor.erase(inv);
|
||||
|
||||
if (block.nDoS)
|
||||
|
||||
if (IsInitialBlockDownload())
|
||||
{
|
||||
static int nBlocksSinceRequest = 0;
|
||||
if (++nBlocksSinceRequest >= 1000)
|
||||
{
|
||||
nBlocksSinceRequest = 0;
|
||||
pfrom->pindexLastGetBlocksBegin = NULL;
|
||||
pfrom->PushGetBlocks(pindexBest, uint256(0));
|
||||
printf("IBD-DIAG: pipeline refill at height %d\n", nBestHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("IBD-DIAG: ProcessBlock FAILED for block %s (height after prev=%d, DoS=%d)\n",
|
||||
hashBlock.ToString().substr(0,20).c_str(), nBestHeight, block.nDoS);
|
||||
}
|
||||
|
||||
if (block.nDoS) {
|
||||
printf("IBD-DIAG: Misbehaving peer %s by %d\n",
|
||||
pfrom->addr.ToString().c_str(), block.nDoS);
|
||||
pfrom->Misbehaving(block.nDoS);
|
||||
|
||||
if (fSecMsgEnabled)
|
||||
}
|
||||
|
||||
if (fSecMsgEnabled && !IsInitialBlockDownload())
|
||||
SecureMsgScanBlock(block);
|
||||
}
|
||||
|
||||
@@ -3698,7 +3806,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
int64_t nCutOff = GetTime() - (nNodeLifespan * 24 * 60 * 60);
|
||||
pfrom->vAddrToSend.clear();
|
||||
vector<CAddress> vAddr = addrman.GetAddr();
|
||||
BOOST_FOREACH(const CAddress &addr, vAddr)
|
||||
for (const CAddress &addr : vAddr)
|
||||
if(addr.nTime > nCutOff)
|
||||
pfrom->PushAddress(addr);
|
||||
}
|
||||
@@ -3803,7 +3911,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
||||
pfrom->setKnown.insert(alertHash);
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
alert.RelayTo(pnode);
|
||||
}
|
||||
}
|
||||
@@ -4018,7 +4126,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
{
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
// Periodically clear setAddrKnown to allow refresh broadcasts
|
||||
if (nLastRebroadcast)
|
||||
@@ -4043,7 +4151,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
{
|
||||
vector<CAddress> vAddr;
|
||||
vAddr.reserve(pto->vAddrToSend.size());
|
||||
BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
|
||||
for (const CAddress& addr : pto->vAddrToSend)
|
||||
{
|
||||
// returns true if wasn't already contained in the set
|
||||
if (pto->setAddrKnown.insert(addr).second)
|
||||
@@ -4072,7 +4180,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
LOCK(pto->cs_inventory);
|
||||
vInv.reserve(pto->vInventoryToSend.size());
|
||||
vInvWait.reserve(pto->vInventoryToSend.size());
|
||||
BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
|
||||
for (const CInv& inv : pto->vInventoryToSend)
|
||||
{
|
||||
if (pto->setInventoryKnown.count(inv))
|
||||
continue;
|
||||
@@ -4121,9 +4229,44 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
||||
pto->PushMessage("inv", vInv);
|
||||
|
||||
|
||||
//
|
||||
// Stall detection: if IBD and no new blocks for 5 seconds, re-request
|
||||
//
|
||||
if (IsInitialBlockDownload() && !pto->fClient)
|
||||
{
|
||||
static int64_t nLastBlockReceived = 0;
|
||||
static int nLastHeight = 0;
|
||||
static int64_t nLastStallLog = 0;
|
||||
if (nBestHeight > nLastHeight) {
|
||||
nLastHeight = nBestHeight;
|
||||
nLastBlockReceived = GetTime();
|
||||
} else if (nLastBlockReceived > 0 && GetTime() - nLastBlockReceived > 2) {
|
||||
if (GetTime() - nLastStallLog >= 10) { // log every 10s max
|
||||
printf("IBD-DIAG: STALL at height %d for %ds, peer=%s askfor_queue=%d send_size=%d\n",
|
||||
nBestHeight, (int)(GetTime() - nLastBlockReceived),
|
||||
pto->addr.ToString().c_str(),
|
||||
(int)pto->mapAskFor.size(), (int)pto->nSendSize);
|
||||
nLastStallLog = GetTime();
|
||||
}
|
||||
pto->pindexLastGetBlocksBegin = NULL;
|
||||
pto->PushGetBlocks(pindexBest, uint256(0));
|
||||
nLastBlockReceived = GetTime();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Message: getdata
|
||||
//
|
||||
// Periodic IBD status
|
||||
if (IsInitialBlockDownload()) {
|
||||
static int64_t nLastStatus = 0;
|
||||
if (GetTime() - nLastStatus >= 15) {
|
||||
printf("IBD-DIAG: STATUS height=%d peers=%d askfor_queued=%d orphans=%d\n",
|
||||
nBestHeight, (int)vNodes.size(), (int)pto->mapAskFor.size(), (int)mapOrphanBlocks.size());
|
||||
nLastStatus = GetTime();
|
||||
}
|
||||
}
|
||||
|
||||
vector<CInv> vGetData;
|
||||
int64_t nNow = GetTime() * 1000000;
|
||||
CTxDB txdb("r");
|
||||
|
||||
+9
-8
@@ -34,6 +34,7 @@ static const unsigned int MAX_BLOCK_SIZE = 1000000;
|
||||
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
|
||||
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
|
||||
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
|
||||
static const unsigned int MAX_ORPHAN_BLOCKS = 750;
|
||||
static const unsigned int MAX_INV_SZ = 50000;
|
||||
static const int64_t MIN_TX_FEE = (1 * CENT) / 100;
|
||||
static const int64_t MIN_RELAY_TX_FEE = (1 * CENT) / 100;
|
||||
@@ -489,7 +490,7 @@ public:
|
||||
nBlockTime = GetAdjustedTime();
|
||||
if ((int64_t)nLockTime < ((int64_t)nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
|
||||
return true;
|
||||
BOOST_FOREACH(const CTxIn& txin, vin)
|
||||
for (const CTxIn& txin : vin)
|
||||
if (!txin.IsFinal())
|
||||
return false;
|
||||
return true;
|
||||
@@ -567,7 +568,7 @@ public:
|
||||
int64_t GetValueOut() const
|
||||
{
|
||||
int64_t nValueOut = 0;
|
||||
BOOST_FOREACH(const CTxOut& txout, vout)
|
||||
for (const CTxOut& txout : vout)
|
||||
{
|
||||
nValueOut += txout.nValue;
|
||||
if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut))
|
||||
@@ -955,7 +956,7 @@ public:
|
||||
int64_t GetMaxTransactionTime() const
|
||||
{
|
||||
int64_t maxTransactionTime = 0;
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
for (const CTransaction& tx : vtx)
|
||||
maxTransactionTime = std::max(maxTransactionTime, (int64_t)tx.nTime);
|
||||
return maxTransactionTime;
|
||||
}
|
||||
@@ -963,7 +964,7 @@ public:
|
||||
uint256 BuildMerkleTree() const
|
||||
{
|
||||
vMerkleTree.clear();
|
||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
||||
for (const CTransaction& tx : vtx)
|
||||
vMerkleTree.push_back(tx.GetHash());
|
||||
int j = 0;
|
||||
for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2)
|
||||
@@ -999,7 +1000,7 @@ public:
|
||||
{
|
||||
if (nIndex == -1)
|
||||
return 0;
|
||||
BOOST_FOREACH(const uint256& otherside, vMerkleBranch)
|
||||
for (const uint256& otherside : vMerkleBranch)
|
||||
{
|
||||
if (nIndex & 1)
|
||||
hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash));
|
||||
@@ -1518,7 +1519,7 @@ public:
|
||||
// Retrace how far back it was in the sender's branch
|
||||
int nDistance = 0;
|
||||
int nStep = 1;
|
||||
BOOST_FOREACH(const uint256& hash, vHave)
|
||||
for (const uint256& hash : vHave)
|
||||
{
|
||||
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
|
||||
if (mi != mapBlockIndex.end())
|
||||
@@ -1537,7 +1538,7 @@ public:
|
||||
CBlockIndex* GetBlockIndex()
|
||||
{
|
||||
// Find the first block the caller has in the main chain
|
||||
BOOST_FOREACH(const uint256& hash, vHave)
|
||||
for (const uint256& hash : vHave)
|
||||
{
|
||||
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
|
||||
if (mi != mapBlockIndex.end())
|
||||
@@ -1553,7 +1554,7 @@ public:
|
||||
uint256 GetBlockHash()
|
||||
{
|
||||
// Find the first block the caller has in the main chain
|
||||
BOOST_FOREACH(const uint256& hash, vHave)
|
||||
for (const uint256& hash : vHave)
|
||||
{
|
||||
std::map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hash);
|
||||
if (mi != mapBlockIndex.end())
|
||||
|
||||
+10
-1
@@ -114,6 +114,7 @@ OBJS= \
|
||||
obj/net_bootstrap.o \
|
||||
obj/protocol.o \
|
||||
obj/trianglesrpc.o \
|
||||
obj/rest.o \
|
||||
obj/rpcdump.o \
|
||||
obj/rpcnet.o \
|
||||
obj/rpcmining.o \
|
||||
@@ -134,7 +135,8 @@ OBJS= \
|
||||
obj/scrypt-x86.o \
|
||||
obj/scrypt-x86_64.o \
|
||||
obj/smessage.o \
|
||||
obj/onion_v3.o
|
||||
obj/onion_v3.o \
|
||||
obj/tor_process.o
|
||||
|
||||
all: trianglesd.exe
|
||||
|
||||
@@ -199,6 +201,13 @@ obj/onion_v3.o: tor/onion_v3.cpp
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/tor_process.o: tor/tor_process.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/net_bootstrap.o: net_bootstrap.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
|
||||
+37
-11
@@ -107,7 +107,7 @@ endif
|
||||
|
||||
# CXXFLAGS can be specified on the make command line, so we use xCXXFLAGS that only
|
||||
# adds some defaults in front. Unfortunately, CXXFLAGS=... $(CXXFLAGS) does not work.
|
||||
xCXXFLAGS=-O2 $(EXT_OPTIONS) -pthread -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter \
|
||||
xCXXFLAGS=-O2 -std=c++17 $(EXT_OPTIONS) -pthread -Wall -Wextra -Wno-ignored-qualifiers -Wformat -Wformat-security -Wno-unused-parameter \
|
||||
$(DEBUGFLAGS) $(DEFS) $(HARDENING) $(CXXFLAGS)
|
||||
|
||||
# LDFLAGS can be specified on the make command line, so we use xLDFLAGS that only
|
||||
@@ -149,6 +149,7 @@ OBJS= \
|
||||
obj/net_bootstrap.o \
|
||||
obj/protocol.o \
|
||||
obj/trianglesrpc.o \
|
||||
obj/rest.o \
|
||||
obj/rpcdump.o \
|
||||
obj/rpcnet.o \
|
||||
obj/rpcmining.o \
|
||||
@@ -169,7 +170,25 @@ OBJS= \
|
||||
obj/scrypt-x86.o \
|
||||
obj/scrypt-x86_64.o \
|
||||
obj/smessage.o \
|
||||
obj/onion_v3.o
|
||||
obj/onion_v3.o \
|
||||
obj/tor_process.o \
|
||||
obj/tor_embed_hooks.o \
|
||||
obj/tor_embedded.o
|
||||
|
||||
# Embedded Tor support (optional)
|
||||
# Build with: make -f makefile.unix USE_TOR_EMBEDDED=1 TOR_LIB_PATH=/path/to/libtor
|
||||
# Requires libtor.a built from official Tor source (see CODEX-TOR-GUIDE.md)
|
||||
TOR_SOURCE_ROOT ?= tor/tor-src
|
||||
TOR_INCLUDE_PATH ?= $(TOR_SOURCE_ROOT)/src/feature/api
|
||||
TOR_LIB_PATH ?= $(TOR_SOURCE_ROOT)/src/core $(TOR_SOURCE_ROOT)/src/lib $(TOR_SOURCE_ROOT)/src/trunnel
|
||||
TOR_EMBEDDED_LIBS ?= -ltor-app -lor -lor-ctime -lor-event -lor-trunnel
|
||||
ifdef USE_TOR_EMBEDDED
|
||||
DEFS += -DENABLE_TOR_EMBEDDED
|
||||
DEFS += $(addprefix -I,$(TOR_INCLUDE_PATH))
|
||||
LIBS += $(addprefix -L,$(TOR_LIB_PATH))
|
||||
LIBS += -Wl,--start-group $(TOR_EMBEDDED_LIBS) -Wl,--end-group
|
||||
LIBS += -levent -levent_pthreads -lssl -lcrypto -lz -lm -lpthread
|
||||
endif
|
||||
|
||||
# ZMQ support (optional)
|
||||
# Build with: make -f makefile.unix USE_ZMQ=1
|
||||
@@ -224,14 +243,7 @@ obj/%.o: %.c
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/%.o: tor/%.c
|
||||
$(CC) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/anonymize.o: tor/anonymize.cpp
|
||||
obj/tor_embed_hooks.o: tor_embed_hooks.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
@@ -245,6 +257,20 @@ obj/onion_v3.o: tor/onion_v3.cpp
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/tor_process.o: tor/tor_process.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/tor_embedded.o: tor/tor_embedded.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
obj/net_bootstrap.o: net_bootstrap.cpp
|
||||
$(CXX) -c $(xCXXFLAGS) -MMD -MF $(@:%.o=%.d) -o $@ $<
|
||||
@cp $(@:%.o=%.d) $(@:%.o=%.P); \
|
||||
@@ -252,7 +278,7 @@ obj/net_bootstrap.o: net_bootstrap.cpp
|
||||
-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
|
||||
rm -f $(@:%.o=%.d)
|
||||
|
||||
trianglesd: $(OBJS:obj/%=obj/%) obj/anonymize.o
|
||||
trianglesd: $(OBJS:obj/%=obj/%)
|
||||
$(LINK) $(xCXXFLAGS) -o $@ $^ $(xLDFLAGS) $(LIBS)
|
||||
|
||||
TESTOBJS := $(patsubst test/%.cpp,obj-test/%.o,$(wildcard test/*.cpp))
|
||||
|
||||
+3
-3
@@ -72,7 +72,7 @@ public:
|
||||
{
|
||||
printf("COrphan(hash=%s, dPriority=%.1f, dFeePerKb=%.1f)\n",
|
||||
ptx->GetHash().ToString().substr(0,10).c_str(), dPriority, dFeePerKb);
|
||||
BOOST_FOREACH(uint256 hash, setDependsOn)
|
||||
for (uint256 hash : setDependsOn)
|
||||
printf(" setDependsOn %s\n", hash.ToString().substr(0,10).c_str());
|
||||
}
|
||||
};
|
||||
@@ -188,7 +188,7 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake, int64_t* pFees)
|
||||
double dPriority = 0;
|
||||
int64_t nTotalIn = 0;
|
||||
bool fMissingInputs = false;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
for (const CTxIn& txin : tx.vin)
|
||||
{
|
||||
// Read prev transaction
|
||||
CTransaction txPrev;
|
||||
@@ -335,7 +335,7 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake, int64_t* pFees)
|
||||
uint256 hash = tx.GetHash();
|
||||
if (mapDependers.count(hash))
|
||||
{
|
||||
BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
|
||||
for (COrphan* porphan : mapDependers[hash])
|
||||
{
|
||||
if (!porphan->setDependsOn.empty())
|
||||
{
|
||||
|
||||
+135
-54
@@ -6,6 +6,7 @@
|
||||
#include "irc.h"
|
||||
#include "db.h"
|
||||
#include "net.h"
|
||||
#include "main.h"
|
||||
#include "init.h"
|
||||
#include "strlcpy.h"
|
||||
#include "addrman.h"
|
||||
@@ -40,6 +41,7 @@ void ThreadOpenAddedConnections2(void* parg);
|
||||
#ifdef USE_UPNP
|
||||
void ThreadMapPort2(void* parg);
|
||||
#endif
|
||||
void ThreadDNSAddressSeed(void* parg);
|
||||
void ThreadDNSAddressSeed2(void* parg);
|
||||
bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOutbound = NULL, const char *strDest = NULL, bool fOneShot = false);
|
||||
|
||||
@@ -211,7 +213,7 @@ bool RecvLine(SOCKET hSocket, string& strLine)
|
||||
void static AdvertizeLocal()
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
if (pnode->fSuccessfullyConnected)
|
||||
{
|
||||
@@ -456,7 +458,7 @@ CNode* FindNode(const CNetAddr& ip)
|
||||
{
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
if ((CNetAddr)pnode->addr == ip)
|
||||
return (pnode);
|
||||
}
|
||||
@@ -466,7 +468,7 @@ CNode* FindNode(const CNetAddr& ip)
|
||||
CNode* FindNode(std::string addrName)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
if (pnode->addrName == addrName)
|
||||
return (pnode);
|
||||
return NULL;
|
||||
@@ -476,7 +478,7 @@ CNode* FindNode(const CService& addr)
|
||||
{
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
if ((CService)pnode->addr == addr)
|
||||
return (pnode);
|
||||
}
|
||||
@@ -821,7 +823,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
LOCK(cs_vNodes);
|
||||
// Disconnect unused nodes
|
||||
vector<CNode*> vNodesCopy = vNodes;
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||
for (CNode* pnode : vNodesCopy)
|
||||
{
|
||||
if (pnode->fDisconnect ||
|
||||
(pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty()))
|
||||
@@ -845,7 +847,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
|
||||
// Delete disconnected nodes
|
||||
list<CNode*> vNodesDisconnectedCopy = vNodesDisconnected;
|
||||
BOOST_FOREACH(CNode* pnode, vNodesDisconnectedCopy)
|
||||
for (CNode* pnode : vNodesDisconnectedCopy)
|
||||
{
|
||||
// wait until threads are done using it
|
||||
if (pnode->GetRefCount() <= 0)
|
||||
@@ -888,7 +890,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
//
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 50000; // frequency to poll pnode->vSend
|
||||
timeout.tv_usec = IsInitialBlockDownload() ? 1000 : 50000; // 1ms during IBD, 50ms normal
|
||||
|
||||
fd_set fdsetRecv;
|
||||
fd_set fdsetSend;
|
||||
@@ -899,14 +901,14 @@ void ThreadSocketHandler2(void* parg)
|
||||
SOCKET hSocketMax = 0;
|
||||
bool have_fds = false;
|
||||
|
||||
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket) {
|
||||
for (SOCKET hListenSocket : vhListenSocket) {
|
||||
FD_SET(hListenSocket, &fdsetRecv);
|
||||
hSocketMax = max(hSocketMax, hListenSocket);
|
||||
have_fds = true;
|
||||
}
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
if (pnode->hSocket == INVALID_SOCKET)
|
||||
continue;
|
||||
@@ -946,7 +948,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
//
|
||||
// Accept new connections
|
||||
//
|
||||
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
|
||||
for (SOCKET hListenSocket : vhListenSocket)
|
||||
if (hListenSocket != INVALID_SOCKET && FD_ISSET(hListenSocket, &fdsetRecv))
|
||||
{
|
||||
#ifdef USE_IPV6
|
||||
@@ -965,7 +967,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
if (pnode->fInbound)
|
||||
nInbound++;
|
||||
}
|
||||
@@ -1005,10 +1007,10 @@ void ThreadSocketHandler2(void* parg)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
vNodesCopy = vNodes;
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||
for (CNode* pnode : vNodesCopy)
|
||||
pnode->AddRef();
|
||||
}
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||
for (CNode* pnode : vNodesCopy)
|
||||
{
|
||||
if (fShutdown)
|
||||
return;
|
||||
@@ -1098,7 +1100,7 @@ void ThreadSocketHandler2(void* parg)
|
||||
}
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||
for (CNode* pnode : vNodesCopy)
|
||||
pnode->Release();
|
||||
}
|
||||
|
||||
@@ -1375,6 +1377,7 @@ void ThreadOnionSeed(void* parg)
|
||||
|
||||
unsigned int pnSeed[] = {
|
||||
0xCE58E9C2, // DNS2-OpenClaw: 194.233.88.206
|
||||
0x13A7D04A, // DNS3-Sami: 74.208.167.19
|
||||
};
|
||||
|
||||
void DumpAddresses()
|
||||
@@ -1416,6 +1419,58 @@ void ThreadDumpAddress(void* parg)
|
||||
printf("ThreadDumpAddress exited\n");
|
||||
}
|
||||
|
||||
void ThreadDNSAddressSeed2(void* parg)
|
||||
{
|
||||
static const char* strDNSSeed[] = {
|
||||
"seed1.cryptographic-triangles.org",
|
||||
"seed2.cryptographic-triangles.org",
|
||||
"seed3.cryptographic-triangles.org",
|
||||
"backup-seed.cryptographic-triangles.org",
|
||||
};
|
||||
|
||||
printf("Loading addresses from DNS seeds...\n");
|
||||
int found = 0;
|
||||
|
||||
for (unsigned int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++)
|
||||
{
|
||||
if (fShutdown)
|
||||
return;
|
||||
|
||||
vector<CNetAddr> vaddr;
|
||||
if (LookupHost(strDNSSeed[seed_idx], vaddr))
|
||||
{
|
||||
for (CNetAddr& ip : vaddr)
|
||||
{
|
||||
CAddress addr(CService(ip, GetDefaultPort()));
|
||||
addr.nTime = GetTime() - 3*24*60*60; // 3 days ago
|
||||
addrman.Add(addr, CNetAddr(strDNSSeed[seed_idx], true));
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%d addresses found from DNS seeds\n", found);
|
||||
}
|
||||
|
||||
void ThreadDNSAddressSeed(void* parg)
|
||||
{
|
||||
RenameThread("Triangles-dnsseed");
|
||||
try
|
||||
{
|
||||
vnThreadsRunning[THREAD_DNSSEED]++;
|
||||
ThreadDNSAddressSeed2(parg);
|
||||
vnThreadsRunning[THREAD_DNSSEED]--;
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
vnThreadsRunning[THREAD_DNSSEED]--;
|
||||
PrintException(&e, "ThreadDNSAddressSeed()");
|
||||
} catch (...) {
|
||||
vnThreadsRunning[THREAD_DNSSEED]--;
|
||||
PrintException(NULL, "ThreadDNSAddressSeed()");
|
||||
}
|
||||
printf("ThreadDNSAddressSeed exited\n");
|
||||
}
|
||||
|
||||
void ThreadOpenConnections(void* parg)
|
||||
{
|
||||
// Make this thread recognisable as the connection opening thread
|
||||
@@ -1486,7 +1541,7 @@ void ThreadOpenConnections2(void* parg)
|
||||
for (int64_t nLoop = 0;; nLoop++)
|
||||
{
|
||||
ProcessOneShot();
|
||||
BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
|
||||
for (string strAddr : mapMultiArgs["-connect"])
|
||||
{
|
||||
CAddress addr;
|
||||
OpenNetworkConnection(addr, NULL, strAddr.c_str());
|
||||
@@ -1520,24 +1575,29 @@ void ThreadOpenConnections2(void* parg)
|
||||
if (fShutdown)
|
||||
return;
|
||||
|
||||
// Add seed nodes if IRC isn't working
|
||||
if (addrman.size()==0 && (GetTime() - nStart > 60) && !fTestNet)
|
||||
// Add hardcoded seed nodes when we have no connections.
|
||||
// Original check (addrman.size()==0) was too conservative - stale entries
|
||||
// in peers.dat would prevent fallback to working hardcoded IPs forever.
|
||||
{
|
||||
std::vector<CAddress> vAdd;
|
||||
for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
|
||||
{
|
||||
// It'll only connect to one or two seed nodes because once it connects,
|
||||
// it'll get a pile of addresses with newer timestamps.
|
||||
// Seed nodes are given a random 'last seen time' of between one and two
|
||||
// weeks ago.
|
||||
const int64_t nOneWeek = 7*24*60*60;
|
||||
struct in_addr ip;
|
||||
memcpy(&ip, &pnSeed[i], sizeof(ip));
|
||||
CAddress addr(CService(ip, GetDefaultPort()));
|
||||
addr.nTime = GetTime()-GetRand(nOneWeek)-nOneWeek;
|
||||
vAdd.push_back(addr);
|
||||
LOCK(cs_vNodes);
|
||||
bool fNoOutbound = true;
|
||||
for (CNode* pnode : vNodes) {
|
||||
if (!pnode->fInbound) { fNoOutbound = false; break; }
|
||||
}
|
||||
if (fNoOutbound && (GetTime() - nStart > 30) && !fTestNet)
|
||||
{
|
||||
std::vector<CAddress> vAdd;
|
||||
for (unsigned int i = 0; i < ARRAYLEN(pnSeed); i++)
|
||||
{
|
||||
struct in_addr ip;
|
||||
memcpy(&ip, &pnSeed[i], sizeof(ip));
|
||||
CAddress addr(CService(ip, GetDefaultPort()));
|
||||
addr.nTime = GetTime() - GetRand(60*60); // seen recently
|
||||
vAdd.push_back(addr);
|
||||
}
|
||||
addrman.Add(vAdd, CNetAddr("127.0.0.1"));
|
||||
printf("No outbound connections after 30s, added %d hardcoded seeds\n", (int)vAdd.size());
|
||||
}
|
||||
addrman.Add(vAdd, CNetAddr("127.0.0.1"));
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1551,7 +1611,7 @@ void ThreadOpenConnections2(void* parg)
|
||||
set<vector<unsigned char> > setConnected;
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes) {
|
||||
for (CNode* pnode : vNodes) {
|
||||
if (!pnode->fInbound) {
|
||||
setConnected.insert(pnode->addr.GetGroup());
|
||||
nOutbound++;
|
||||
@@ -1628,7 +1688,7 @@ void ThreadOpenAddedConnections2(void* parg)
|
||||
|
||||
if (HaveNameProxy()) {
|
||||
while(!fShutdown) {
|
||||
BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"]) {
|
||||
for (string& strAddNode : mapMultiArgs["-addnode"]) {
|
||||
CAddress addr;
|
||||
CSemaphoreGrant grant(*semOutbound);
|
||||
OpenNetworkConnection(addr, &grant, strAddNode.c_str());
|
||||
@@ -1642,7 +1702,7 @@ void ThreadOpenAddedConnections2(void* parg)
|
||||
}
|
||||
|
||||
vector<vector<CService> > vservAddressesToAdd(0);
|
||||
BOOST_FOREACH(string& strAddNode, mapMultiArgs["-addnode"])
|
||||
for (string& strAddNode : mapMultiArgs["-addnode"])
|
||||
{
|
||||
vector<CService> vservNode(0);
|
||||
if(Lookup(strAddNode.c_str(), vservNode, GetDefaultPort(), fNameLookup, 0))
|
||||
@@ -1650,7 +1710,7 @@ void ThreadOpenAddedConnections2(void* parg)
|
||||
vservAddressesToAdd.push_back(vservNode);
|
||||
{
|
||||
LOCK(cs_setservAddNodeAddresses);
|
||||
BOOST_FOREACH(CService& serv, vservNode)
|
||||
for (CService& serv : vservNode)
|
||||
setservAddNodeAddresses.insert(serv);
|
||||
}
|
||||
}
|
||||
@@ -1662,9 +1722,9 @@ void ThreadOpenAddedConnections2(void* parg)
|
||||
// (keeping in mind that addnode entries can have many IPs if fNameLookup)
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
for (vector<vector<CService> >::iterator it = vservConnectAddresses.begin(); it != vservConnectAddresses.end(); it++)
|
||||
BOOST_FOREACH(CService& addrNode, *(it))
|
||||
for (CService& addrNode : *(it))
|
||||
if (pnode->addr == addrNode)
|
||||
{
|
||||
it = vservConnectAddresses.erase(it);
|
||||
@@ -1672,7 +1732,7 @@ void ThreadOpenAddedConnections2(void* parg)
|
||||
break;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(vector<CService>& vserv, vservConnectAddresses)
|
||||
for (vector<CService>& vserv : vservConnectAddresses)
|
||||
{
|
||||
CSemaphoreGrant grant(*semOutbound);
|
||||
OpenNetworkConnection(CAddress(*(vserv.begin())), &grant);
|
||||
@@ -1755,13 +1815,14 @@ void ThreadMessageHandler2(void* parg)
|
||||
{
|
||||
printf("ThreadMessageHandler started\n");
|
||||
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
|
||||
bool fWasBoosted = false;
|
||||
while (!fShutdown)
|
||||
{
|
||||
vector<CNode*> vNodesCopy;
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
vNodesCopy = vNodes;
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||
for (CNode* pnode : vNodesCopy)
|
||||
pnode->AddRef();
|
||||
}
|
||||
|
||||
@@ -1769,7 +1830,7 @@ void ThreadMessageHandler2(void* parg)
|
||||
CNode* pnodeTrickle = NULL;
|
||||
if (!vNodesCopy.empty())
|
||||
pnodeTrickle = vNodesCopy[GetRand(vNodesCopy.size())];
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||
for (CNode* pnode : vNodesCopy)
|
||||
{
|
||||
// Receive messages
|
||||
{
|
||||
@@ -1793,15 +1854,25 @@ void ThreadMessageHandler2(void* parg)
|
||||
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
||||
for (CNode* pnode : vNodesCopy)
|
||||
pnode->Release();
|
||||
}
|
||||
|
||||
// Boost thread priority during IBD, restore when caught up
|
||||
if (IsInitialBlockDownload() && !fWasBoosted) {
|
||||
SetThreadPriority(THREAD_PRIORITY_NORMAL);
|
||||
fWasBoosted = true;
|
||||
} else if (!IsInitialBlockDownload() && fWasBoosted) {
|
||||
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
|
||||
fWasBoosted = false;
|
||||
}
|
||||
|
||||
// Wait and allow messages to bunch up.
|
||||
// During IBD, use a shorter sleep to maximize block processing throughput.
|
||||
// Reduce vnThreadsRunning so StopNode has permission to exit while
|
||||
// we're sleeping, but we must always check fShutdown after doing this.
|
||||
vnThreadsRunning[THREAD_MESSAGEHANDLER]--;
|
||||
MilliSleep(100);
|
||||
MilliSleep(IsInitialBlockDownload() ? 1 : 100);
|
||||
if (fRequestShutdown)
|
||||
StartShutdown();
|
||||
vnThreadsRunning[THREAD_MESSAGEHANDLER]++;
|
||||
@@ -1952,10 +2023,11 @@ void static Discover()
|
||||
}
|
||||
|
||||
static void run_tor() {
|
||||
// Old embedded Tor v2 client removed - incompatible with OpenSSL 3.x.
|
||||
// Tor v3 onion services are handled by onion_v3.cpp via external Tor/SOCKS5.
|
||||
printf("Tor v3 mode: using external Tor process via SOCKS5 proxy.\n");
|
||||
set_initialized();
|
||||
// Tor process is now managed by CTorProcess (tor_process.cpp)
|
||||
// which starts an external Tor binary with SOCKS5 proxy and v3 hidden service.
|
||||
// The old embedded Tor v2 code was removed (incompatible with OpenSSL 3.x).
|
||||
printf("Tor v3 mode: using managed Tor process via SOCKS5 proxy.\n");
|
||||
triangles_tor_set_initialized();
|
||||
}
|
||||
|
||||
|
||||
@@ -2030,9 +2102,9 @@ void StartNode(void* parg)
|
||||
if (fUseUPnP)
|
||||
MapPort();
|
||||
|
||||
// Get addresses from IRC and advertise ours
|
||||
//if (!NewThread(ThreadIRCSeed, NULL))
|
||||
// printf("Error: NewThread(ThreadIRCSeed) failed\n");
|
||||
// DNS seed lookup
|
||||
if (!NewThread(ThreadDNSAddressSeed, NULL))
|
||||
printf("Error: NewThread(ThreadDNSAddressSeed) failed\n");
|
||||
|
||||
// Send and receive from sockets, accept connections
|
||||
if (!NewThread(ThreadSocketHandler, NULL))
|
||||
@@ -2094,8 +2166,18 @@ bool StopNode()
|
||||
if (vnThreadsRunning[THREAD_ADDEDCONNECTIONS] > 0) printf("ThreadOpenAddedConnections still running\n");
|
||||
if (vnThreadsRunning[THREAD_DUMPADDRESS] > 0) printf("ThreadDumpAddresses still running\n");
|
||||
if (vnThreadsRunning[THREAD_STAKE_MINER] > 0) printf("ThreadStakeMiner still running\n");
|
||||
while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0)
|
||||
MilliSleep(20);
|
||||
{
|
||||
int64_t nWaitStart = GetTime();
|
||||
while (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0 || vnThreadsRunning[THREAD_RPCHANDLER] > 0)
|
||||
{
|
||||
if (GetTime() - nWaitStart > 10)
|
||||
{
|
||||
printf("Timed out waiting for message/RPC threads to stop\n");
|
||||
break;
|
||||
}
|
||||
MilliSleep(20);
|
||||
}
|
||||
}
|
||||
MilliSleep(50);
|
||||
DumpAddresses();
|
||||
return true;
|
||||
@@ -2110,10 +2192,10 @@ public:
|
||||
~CNetCleanup()
|
||||
{
|
||||
// Close sockets
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
if (pnode->hSocket != INVALID_SOCKET)
|
||||
closesocket(pnode->hSocket);
|
||||
BOOST_FOREACH(SOCKET hListenSocket, vhListenSocket)
|
||||
for (SOCKET hListenSocket : vhListenSocket)
|
||||
if (hListenSocket != INVALID_SOCKET)
|
||||
if (closesocket(hListenSocket) == SOCKET_ERROR)
|
||||
printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());
|
||||
@@ -2153,4 +2235,3 @@ void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataSt
|
||||
|
||||
RelayInventory(inv);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <deque>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#ifndef WIN32
|
||||
@@ -22,12 +21,13 @@
|
||||
class CRequestTracker;
|
||||
class CNode;
|
||||
class CBlockIndex;
|
||||
bool IsInitialBlockDownload();
|
||||
extern int nBestHeight;
|
||||
|
||||
|
||||
|
||||
inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
|
||||
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
|
||||
inline unsigned int ReceiveFloodSize() { return 100 * 1024 * 1024; } // 100 MB
|
||||
inline unsigned int SendBufferSize() { return 32 * 1024 * 1024; } // 32 MB
|
||||
|
||||
void AddOneShot(std::string strDest);
|
||||
bool RecvLine(SOCKET hSocket, std::string& strLine);
|
||||
@@ -324,8 +324,10 @@ public:
|
||||
|
||||
// Be shy and don't send version until we hear
|
||||
if (hSocket != INVALID_SOCKET && !fInbound)
|
||||
{
|
||||
printf("CNode(): pfrom-addr %s\n", addrName.c_str());
|
||||
PushVersion();
|
||||
}
|
||||
}
|
||||
|
||||
~CNode()
|
||||
@@ -353,7 +355,7 @@ public:
|
||||
unsigned int GetTotalRecvSize()
|
||||
{
|
||||
unsigned int total = 0;
|
||||
BOOST_FOREACH(const CNetMessage &msg, vRecvMsg)
|
||||
for (const CNetMessage &msg : vRecvMsg)
|
||||
total += msg.vRecv.size() + 24;
|
||||
return total;
|
||||
}
|
||||
@@ -365,7 +367,7 @@ public:
|
||||
void SetRecvVersion(int nVersionIn)
|
||||
{
|
||||
nRecvVersion = nVersionIn;
|
||||
BOOST_FOREACH(CNetMessage &msg, vRecvMsg)
|
||||
for (CNetMessage &msg : vRecvMsg)
|
||||
msg.SetVersion(nVersionIn);
|
||||
}
|
||||
|
||||
@@ -429,8 +431,12 @@ public:
|
||||
nNow = std::max(nNow, nLastTime);
|
||||
nLastTime = nNow;
|
||||
|
||||
// Each retry is 2 minutes after the last
|
||||
nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
|
||||
// During IBD, request immediately (no 2-minute retry delay)
|
||||
// Normal operation: each retry is 2 minutes after the last
|
||||
if (nRequestTime > 0 && IsInitialBlockDownload())
|
||||
nRequestTime = nNow;
|
||||
else
|
||||
nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
|
||||
mapAskFor.insert(std::make_pair(nRequestTime, inv));
|
||||
}
|
||||
|
||||
@@ -735,7 +741,7 @@ inline void RelayInventory(const CInv& inv)
|
||||
// Put on lists to offer to the other nodes
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
pnode->PushInventory(inv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef TRIANGLES_OPENSSL_COMPAT_H
|
||||
#define TRIANGLES_OPENSSL_COMPAT_H
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/crypto.h>
|
||||
|
||||
static inline const char* TrianglesOpenSSLVersionString()
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
return OpenSSL_version(OPENSSL_VERSION);
|
||||
#else
|
||||
return SSLeay_version(SSLEAY_VERSION);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // TRIANGLES_OPENSSL_COMPAT_H
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "aboutdialog.h"
|
||||
#include "ui_aboutdialog.h"
|
||||
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "clientmodel.h"
|
||||
#include "dialog_move_handler.h"
|
||||
#include "version.h"
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
cachedAddressTable.clear();
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& item, wallet->mapAddressBook)
|
||||
for (const auto& item : wallet->mapAddressBook)
|
||||
{
|
||||
const CTrianglesAddress& address = item.first;
|
||||
const std::string& strName = item.second;
|
||||
|
||||
@@ -63,7 +63,9 @@ void ClientModel::updateTimer()
|
||||
int newNumBlocks = getNumBlocks();
|
||||
int newNumBlocksOfPeers = getNumBlocksOfPeers();
|
||||
|
||||
if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers)
|
||||
// Always emit during IBD so the speed/ETA display stays live
|
||||
if(cachedNumBlocks != newNumBlocks || cachedNumBlocksOfPeers != newNumBlocksOfPeers
|
||||
|| newNumBlocks < newNumBlocksOfPeers)
|
||||
{
|
||||
cachedNumBlocks = newNumBlocks;
|
||||
cachedNumBlocksOfPeers = newNumBlocksOfPeers;
|
||||
|
||||
@@ -506,7 +506,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||
coinControl->ListSelected(vCoinControl);
|
||||
model->getOutputs(vCoinControl, vOutputs);
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vOutputs)
|
||||
for (const COutput& out : vOutputs)
|
||||
{
|
||||
// Quantity
|
||||
nQuantity++;
|
||||
@@ -647,7 +647,7 @@ void CoinControlDialog::updateView()
|
||||
map<QString, vector<COutput> > mapCoins;
|
||||
model->listCoins(mapCoins);
|
||||
|
||||
BOOST_FOREACH(PAIRTYPE(QString, vector<COutput>) coins, mapCoins)
|
||||
for (auto coins : mapCoins)
|
||||
{
|
||||
QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
|
||||
QString sWalletAddress = coins.first;
|
||||
@@ -679,7 +679,7 @@ void CoinControlDialog::updateView()
|
||||
double dPrioritySum = 0;
|
||||
int nChildren = 0;
|
||||
int nInputSum = 0;
|
||||
BOOST_FOREACH(const COutput& out, coins.second)
|
||||
for (const COutput& out : coins.second)
|
||||
{
|
||||
int nInputSize = 148; // 180 if uncompressed public key
|
||||
nSum += out.tx->vout[out.i].nValue;
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
#include "introdialog.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QFileDialog>
|
||||
#include <QDir>
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
IntroDialog::IntroDialog(QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setWindowTitle("Triangles");
|
||||
setMinimumWidth(520);
|
||||
|
||||
// Match existing Triangles dark theme
|
||||
setStyleSheet(
|
||||
"QDialog { background-color: #000; color: #f26522; }"
|
||||
"QLabel { color: #f26522; }"
|
||||
"QRadioButton { color: #f26522; }"
|
||||
"QRadioButton::indicator { border: 1px solid #f26522; background-color: #000; width: 12px; height: 12px; border-radius: 7px; }"
|
||||
"QRadioButton::indicator:checked { background-color: #f26522; }"
|
||||
"QLineEdit { background-color: #1c1c1c; border: 1px solid #f26522; color: #f26522; padding: 4px; }"
|
||||
"QPushButton { background-color: #000; color: #f26522; border: 1px solid #f26522; padding: 4px 16px; min-height: 20px; }"
|
||||
"QPushButton:hover { background-color: #61280E; }"
|
||||
);
|
||||
|
||||
defaultDataDir = QString::fromStdString(GetDefaultDataDir().string());
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setContentsMargins(20, 20, 20, 20);
|
||||
mainLayout->setSpacing(12);
|
||||
|
||||
// Welcome header
|
||||
QLabel *welcomeLabel = new QLabel(tr("Welcome to Triangles!"));
|
||||
welcomeLabel->setStyleSheet("font-size: 16px; font-weight: bold; color: #f26522;");
|
||||
mainLayout->addWidget(welcomeLabel);
|
||||
|
||||
// Description
|
||||
QLabel *descLabel = new QLabel(tr(
|
||||
"Triangles will store its blockchain data, wallet, and configuration in a data directory. "
|
||||
"You can use the default directory or choose a custom location. "
|
||||
"The data directory requires several hundred MB of free space."
|
||||
));
|
||||
descLabel->setWordWrap(true);
|
||||
mainLayout->addWidget(descLabel);
|
||||
|
||||
mainLayout->addSpacing(8);
|
||||
|
||||
// Default directory radio
|
||||
defaultRadio = new QRadioButton(tr("Use the default data directory"));
|
||||
defaultRadio->setChecked(true);
|
||||
mainLayout->addWidget(defaultRadio);
|
||||
|
||||
// Show default path
|
||||
QLabel *defaultPathLabel = new QLabel(defaultDataDir);
|
||||
defaultPathLabel->setStyleSheet("color: #999; margin-left: 24px; font-size: 11px;");
|
||||
mainLayout->addWidget(defaultPathLabel);
|
||||
|
||||
mainLayout->addSpacing(4);
|
||||
|
||||
// Custom directory radio
|
||||
customRadio = new QRadioButton(tr("Use a custom data directory:"));
|
||||
mainLayout->addWidget(customRadio);
|
||||
|
||||
// Path input + browse button
|
||||
QHBoxLayout *pathLayout = new QHBoxLayout();
|
||||
pathLayout->setContentsMargins(24, 0, 0, 0);
|
||||
|
||||
pathEdit = new QLineEdit(defaultDataDir);
|
||||
pathEdit->setEnabled(false);
|
||||
pathLayout->addWidget(pathEdit);
|
||||
|
||||
browseButton = new QPushButton(tr("Browse..."));
|
||||
browseButton->setEnabled(false);
|
||||
pathLayout->addWidget(browseButton);
|
||||
|
||||
mainLayout->addLayout(pathLayout);
|
||||
|
||||
// Free space label
|
||||
freeSpaceLabel = new QLabel();
|
||||
freeSpaceLabel->setStyleSheet("color: #999; margin-left: 24px; font-size: 11px;");
|
||||
mainLayout->addWidget(freeSpaceLabel);
|
||||
|
||||
mainLayout->addStretch(1);
|
||||
|
||||
// OK / Cancel buttons
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout();
|
||||
buttonLayout->addStretch(1);
|
||||
|
||||
QPushButton *okButton = new QPushButton(tr("OK"));
|
||||
QPushButton *cancelButton = new QPushButton(tr("Cancel"));
|
||||
|
||||
buttonLayout->addWidget(okButton);
|
||||
buttonLayout->addWidget(cancelButton);
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
|
||||
// Connections
|
||||
connect(defaultRadio, SIGNAL(toggled(bool)), this, SLOT(on_defaultRadio_toggled(bool)));
|
||||
connect(browseButton, SIGNAL(clicked()), this, SLOT(on_browseButton_clicked()));
|
||||
connect(pathEdit, SIGNAL(textChanged(QString)), this, SLOT(updateFreeSpace()));
|
||||
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
||||
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
|
||||
|
||||
updateFreeSpace();
|
||||
}
|
||||
|
||||
QString IntroDialog::getDataDirectory() const
|
||||
{
|
||||
if (defaultRadio->isChecked())
|
||||
return defaultDataDir;
|
||||
return pathEdit->text();
|
||||
}
|
||||
|
||||
void IntroDialog::setDataDirectory(const QString &dir)
|
||||
{
|
||||
pathEdit->setText(dir);
|
||||
if (dir == defaultDataDir) {
|
||||
defaultRadio->setChecked(true);
|
||||
} else {
|
||||
customRadio->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
void IntroDialog::on_browseButton_clicked()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Choose data directory"), pathEdit->text());
|
||||
if (!dir.isEmpty())
|
||||
pathEdit->setText(dir);
|
||||
}
|
||||
|
||||
void IntroDialog::on_defaultRadio_toggled(bool checked)
|
||||
{
|
||||
pathEdit->setEnabled(!checked);
|
||||
browseButton->setEnabled(!checked);
|
||||
if (checked)
|
||||
pathEdit->setText(defaultDataDir);
|
||||
updateFreeSpace();
|
||||
}
|
||||
|
||||
void IntroDialog::updateFreeSpace()
|
||||
{
|
||||
QString path = getDataDirectory();
|
||||
boost::filesystem::path fsPath(path.toStdString());
|
||||
|
||||
// Walk up to find an existing parent
|
||||
try {
|
||||
while (!fsPath.empty() && !boost::filesystem::exists(fsPath))
|
||||
fsPath = fsPath.parent_path();
|
||||
|
||||
if (!fsPath.empty()) {
|
||||
boost::filesystem::space_info si = boost::filesystem::space(fsPath);
|
||||
double freeGB = (double)si.available / (1024.0 * 1024.0 * 1024.0);
|
||||
freeSpaceLabel->setText(tr("Free space: %1 GB").arg(QString::number(freeGB, 'f', 2)));
|
||||
} else {
|
||||
freeSpaceLabel->setText(tr("Cannot determine free space"));
|
||||
}
|
||||
} catch (const boost::filesystem::filesystem_error &) {
|
||||
freeSpaceLabel->setText(tr("Cannot determine free space"));
|
||||
}
|
||||
}
|
||||
|
||||
bool IntroDialog::pickDataDirectory()
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
QSettings settings;
|
||||
// If -datadir was passed on the command line, skip the dialog entirely
|
||||
if (mapArgs.count("-datadir"))
|
||||
return true;
|
||||
|
||||
QString dataDir = settings.value("strDataDir", "").toString();
|
||||
|
||||
if (dataDir.isEmpty()) {
|
||||
// First run - show the dialog
|
||||
IntroDialog dlg;
|
||||
if (dlg.exec() != QDialog::Accepted)
|
||||
return false;
|
||||
|
||||
dataDir = dlg.getDataDirectory();
|
||||
settings.setValue("strDataDir", dataDir);
|
||||
}
|
||||
|
||||
// If the saved path is the default, don't set -datadir (let normal defaults work)
|
||||
QString defaultDir = QString::fromStdString(GetDefaultDataDir().string());
|
||||
if (dataDir != defaultDir) {
|
||||
mapArgs["-datadir"] = dataDir.toStdString();
|
||||
}
|
||||
|
||||
// Ensure the directory exists
|
||||
try {
|
||||
fs::create_directories(fs::path(dataDir.toStdString()));
|
||||
} catch (const fs::filesystem_error &) {
|
||||
QMessageBox::critical(0, "Triangles",
|
||||
QString("Error: Could not create data directory \"%1\".").arg(dataDir));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef INTRODIALOG_H
|
||||
#define INTRODIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QRadioButton>
|
||||
#include <QPushButton>
|
||||
|
||||
/** Data directory selection dialog shown on first run. */
|
||||
class IntroDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit IntroDialog(QWidget *parent = 0);
|
||||
|
||||
QString getDataDirectory() const;
|
||||
void setDataDirectory(const QString &dir);
|
||||
|
||||
/**
|
||||
* Check settings or show the dialog to choose data directory.
|
||||
* Returns true if a directory was selected, false if the user cancelled.
|
||||
* Sets mapArgs["-datadir"] if a non-default directory was chosen.
|
||||
*/
|
||||
static bool pickDataDirectory();
|
||||
|
||||
private slots:
|
||||
void on_browseButton_clicked();
|
||||
void on_defaultRadio_toggled(bool checked);
|
||||
void updateFreeSpace();
|
||||
|
||||
private:
|
||||
QRadioButton *defaultRadio;
|
||||
QRadioButton *customRadio;
|
||||
QLineEdit *pathEdit;
|
||||
QPushButton *browseButton;
|
||||
QLabel *freeSpaceLabel;
|
||||
QString defaultDataDir;
|
||||
};
|
||||
|
||||
#endif // INTRODIALOG_H
|
||||
@@ -31,7 +31,7 @@ protected:
|
||||
|
||||
void MessageViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
QStyleOptionViewItemV4 optionV4 = option;
|
||||
QStyleOptionViewItem optionV4 = option;
|
||||
initStyleOption(&optionV4, index);
|
||||
|
||||
QStyle *style = optionV4.widget? optionV4.widget->style() : QApplication::style();
|
||||
@@ -62,7 +62,7 @@ void MessageViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o
|
||||
|
||||
QSize MessageViewDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
|
||||
{
|
||||
QStyleOptionViewItemV4 options = option;
|
||||
QStyleOptionViewItem options = option;
|
||||
initStyleOption(&options, index);
|
||||
|
||||
QTextDocument doc;
|
||||
@@ -159,7 +159,7 @@ void MessagePage::setModel(MessageModel *model)
|
||||
// Set column widths
|
||||
ui->tableView->horizontalHeader()->resizeSection(MessageModel::Type, 100);
|
||||
ui->tableView->horizontalHeader()->resizeSection(MessageModel::Label, 100);
|
||||
ui->tableView->horizontalHeader()->setResizeMode(MessageModel::Label, QHeaderView::Stretch);
|
||||
ui->tableView->horizontalHeader()->setSectionResizeMode(MessageModel::Label, QHeaderView::Stretch);
|
||||
ui->tableView->horizontalHeader()->resizeSection(MessageModel::FromAddress, 320);
|
||||
ui->tableView->horizontalHeader()->resizeSection(MessageModel::ToAddress, 320);
|
||||
ui->tableView->horizontalHeader()->resizeSection(MessageModel::SentDateTime, 170);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "trianglesrpc.h"
|
||||
#include "guiutil.h"
|
||||
#include "dialog_move_handler.h"
|
||||
#include "openssl_compat.h"
|
||||
|
||||
#include <QTime>
|
||||
#include <QTimer>
|
||||
@@ -207,7 +208,7 @@ RPCConsole::RPCConsole(QWidget *parent) :
|
||||
connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));
|
||||
|
||||
// set OpenSSL version label
|
||||
ui->openSSLVersion->setText(SSLeay_version(SSLEAY_VERSION));
|
||||
ui->openSSLVersion->setText(TrianglesOpenSSLVersionString());
|
||||
|
||||
startExecutor();
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
SignMessagePage::SignMessagePage(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::SignMessagePage),
|
||||
|
||||
+10
-10
@@ -77,7 +77,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||
if (nNet > 0)
|
||||
{
|
||||
// Credit
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
{
|
||||
if (wallet->IsMine(txout))
|
||||
{
|
||||
@@ -125,7 +125,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||
// Coinbase
|
||||
//
|
||||
int64_t nUnmatured = 0;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
nUnmatured += wallet->GetCredit(txout);
|
||||
strHTML += "<b>" + tr("Credit") + ":</b> ";
|
||||
if (wtx.IsInMainChain())
|
||||
@@ -144,11 +144,11 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||
else
|
||||
{
|
||||
bool fAllFromMe = true;
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
for (const CTxIn& txin : wtx.vin)
|
||||
fAllFromMe = fAllFromMe && wallet->IsMine(txin);
|
||||
|
||||
bool fAllToMe = true;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
fAllToMe = fAllToMe && wallet->IsMine(txout);
|
||||
|
||||
if (fAllFromMe)
|
||||
@@ -156,7 +156,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||
//
|
||||
// Debit
|
||||
//
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
{
|
||||
if (wallet->IsMine(txout))
|
||||
continue;
|
||||
@@ -196,10 +196,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||
//
|
||||
// Mixed debit transaction
|
||||
//
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
for (const CTxIn& txin : wtx.vin)
|
||||
if (wallet->IsMine(txin))
|
||||
strHTML += "<b>" + tr("Debit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, -wallet->GetDebit(txin)) + "<br>";
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
if (wallet->IsMine(txout))
|
||||
strHTML += "<b>" + tr("Credit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, wallet->GetCredit(txout)) + "<br>";
|
||||
}
|
||||
@@ -234,10 +234,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||
if (fDebug)
|
||||
{
|
||||
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
for (const CTxIn& txin : wtx.vin)
|
||||
if(wallet->IsMine(txin))
|
||||
strHTML += "<b>" + tr("Debit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, -wallet->GetDebit(txin)) + "<br>";
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
if(wallet->IsMine(txout))
|
||||
strHTML += "<b>" + tr("Credit") + ":</b> " + TrianglesUnits::formatWithUnit(TrianglesUnits::TRI, wallet->GetCredit(txout)) + "<br>";
|
||||
|
||||
@@ -251,7 +251,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx)
|
||||
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
for (const CTxIn& txin : wtx.vin)
|
||||
{
|
||||
COutPoint prevout = txin.prevout;
|
||||
|
||||
|
||||
@@ -87,11 +87,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
||||
else
|
||||
{
|
||||
bool fAllFromMe = true;
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
for (const CTxIn& txin : wtx.vin)
|
||||
fAllFromMe = fAllFromMe && wallet->IsMine(txin);
|
||||
|
||||
bool fAllToMe = true;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
fAllToMe = fAllToMe && wallet->IsMine(txout);
|
||||
|
||||
if (fAllFromMe && fAllToMe)
|
||||
|
||||
+14
-9
@@ -8,6 +8,7 @@
|
||||
#include "guiutil.h"
|
||||
#include "guiconstants.h"
|
||||
|
||||
#include "introdialog.h"
|
||||
#include "init.h"
|
||||
#include "ui_interface.h"
|
||||
#include "qtipcserver.h"
|
||||
@@ -131,6 +132,18 @@ int main(int argc, char *argv[])
|
||||
// Command-line options take precedence:
|
||||
ParseParameters(argc, argv);
|
||||
|
||||
// Application identification (must be set before IntroDialog uses QSettings)
|
||||
app.setOrganizationName("Triangles");
|
||||
//XXX app.setOrganizationDomain("");
|
||||
if(GetBoolArg("-testnet")) // Separate UI settings for testnet
|
||||
app.setApplicationName("Triangles-Qt-testnet");
|
||||
else
|
||||
app.setApplicationName("Triangles-Qt");
|
||||
|
||||
// Show data directory selection dialog on first run (unless -datadir was passed)
|
||||
if (!IntroDialog::pickDataDirectory())
|
||||
return 0;
|
||||
|
||||
// ... then triangles.conf:
|
||||
if (!boost::filesystem::is_directory(GetDataDir(false)))
|
||||
{
|
||||
@@ -142,15 +155,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
ReadConfigFile(mapArgs, mapMultiArgs);
|
||||
|
||||
// Application identification (must be set before OptionsModel is initialized,
|
||||
// as it is used to locate QSettings)
|
||||
app.setOrganizationName("Triangles");
|
||||
//XXX app.setOrganizationDomain("");
|
||||
if(GetBoolArg("-testnet")) // Separate UI settings for testnet
|
||||
app.setApplicationName("Triangles-Qt-testnet");
|
||||
else
|
||||
app.setApplicationName("Triangles-Qt");
|
||||
|
||||
// ... then GUI settings:
|
||||
OptionsModel optionsModel;
|
||||
|
||||
@@ -215,6 +219,7 @@ int main(int argc, char *argv[])
|
||||
if (GUIUtil::GetStartOnSystemStartup())
|
||||
GUIUtil::SetStartOnSystemStartup(true);
|
||||
|
||||
InitMessage(_("Preparing interface..."));
|
||||
TrianglesGUI window;
|
||||
guiref = &window;
|
||||
if(AppInit2())
|
||||
|
||||
+157
-31
@@ -76,9 +76,10 @@
|
||||
#include <QTextStream>
|
||||
#include <QTextDocument>
|
||||
#include <QSettings>
|
||||
#include <QDesktopWidget>
|
||||
#include <QGuiApplication>
|
||||
#include <QListWidget>
|
||||
#include <QPainter>
|
||||
#include <QScreen>
|
||||
//#include <QSound>
|
||||
#include <QSizeGrip>
|
||||
|
||||
@@ -297,19 +298,15 @@ TrianglesGUI::TrianglesGUI(bool fIsTestnet, QWidget *parent):
|
||||
|
||||
receiveCoinsPage = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab);
|
||||
|
||||
sendCoinsPage = new SendCoinsDialog(this);
|
||||
messagePage = new MessagePage(this);
|
||||
signMessagePage = new SignMessagePage(this);
|
||||
verifyMessagePage = new VerifyMessagePage(this);
|
||||
sendCoinsPage = 0;
|
||||
messagePage = 0;
|
||||
signMessagePage = 0;
|
||||
verifyMessagePage = 0;
|
||||
centralWidget = ui->stackedWidget;
|
||||
centralWidget->addWidget(overviewPage);
|
||||
centralWidget->addWidget(transactionsPage);
|
||||
centralWidget->addWidget(addressBookPage);
|
||||
centralWidget->addWidget(receiveCoinsPage);
|
||||
centralWidget->addWidget(sendCoinsPage);
|
||||
centralWidget->addWidget(messagePage);
|
||||
centralWidget->addWidget(signMessagePage);
|
||||
centralWidget->addWidget(verifyMessagePage);
|
||||
|
||||
QSizeGrip* grip = new QSizeGrip(this);
|
||||
grip->setStyleSheet("width: 6px; height: 6px; image: url(:/res/icons/handle.png);");
|
||||
@@ -337,6 +334,10 @@ TrianglesGUI::TrianglesGUI(bool fIsTestnet, QWidget *parent):
|
||||
updateStakingIcon();
|
||||
}
|
||||
|
||||
QTimer *timerShutdown = new QTimer(this);
|
||||
connect(timerShutdown, SIGNAL(timeout()), this, SLOT(detectShutdown()));
|
||||
timerShutdown->start(200);
|
||||
|
||||
// Progress bar and label for blocks download
|
||||
progressBarLabel = ui->label_synchronization;
|
||||
progressBarLabel->setVisible(false);
|
||||
@@ -359,8 +360,7 @@ TrianglesGUI::TrianglesGUI(bool fIsTestnet, QWidget *parent):
|
||||
// Double-clicking on a transaction on the transaction history page shows details
|
||||
connect(transactionView, SIGNAL(doubleClicked(QModelIndex)), transactionView, SLOT(showDetails()));
|
||||
|
||||
rpcConsole = new RPCConsole(this);
|
||||
connect(openRPCConsoleAction, SIGNAL(triggered()), rpcConsole, SLOT(show()));
|
||||
connect(openRPCConsoleAction, SIGNAL(triggered()), this, SLOT(openRPCConsole()));
|
||||
|
||||
// Clicking on "Verify Message" in the address book sends you to the verify message tab
|
||||
connect(addressBookPage, SIGNAL(verifyMessage(QString)), this, SLOT(gotoVerifyMessageTab(QString)));
|
||||
@@ -479,7 +479,7 @@ void TrianglesGUI::createActions(bool fIsTestnet)
|
||||
openRPCConsoleAction = new QAction(QIcon(":/menu_16/debug"), tr("&Debug window"), this);
|
||||
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
|
||||
|
||||
connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||
connect(quitAction, SIGNAL(triggered()), this, SLOT(requestShutdown()));
|
||||
connect(aboutAction, SIGNAL(triggered()), this, SLOT(aboutClicked()));
|
||||
connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
|
||||
connect(optionsAction, SIGNAL(triggered()), this, SLOT(optionsClicked()));
|
||||
@@ -563,7 +563,8 @@ void TrianglesGUI::setClientModel(ClientModel *clientModel)
|
||||
// Receive and report messages from network/worker thread
|
||||
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
|
||||
|
||||
rpcConsole->setClientModel(clientModel);
|
||||
if (rpcConsole)
|
||||
rpcConsole->setClientModel(clientModel);
|
||||
addressBookPage->setOptionsModel(clientModel->getOptionsModel());
|
||||
receiveCoinsPage->setOptionsModel(clientModel->getOptionsModel());
|
||||
}
|
||||
@@ -582,9 +583,12 @@ void TrianglesGUI::setWalletModel(WalletModel *walletModel)
|
||||
overviewPage->setModel(walletModel);
|
||||
addressBookPage->setModel(walletModel->getAddressTableModel());
|
||||
receiveCoinsPage->setModel(walletModel->getAddressTableModel());
|
||||
sendCoinsPage->setModel(walletModel);
|
||||
signMessagePage->setModel(walletModel);
|
||||
verifyMessagePage->setModel(walletModel);
|
||||
if (sendCoinsPage)
|
||||
sendCoinsPage->setModel(walletModel);
|
||||
if (signMessagePage)
|
||||
signMessagePage->setModel(walletModel);
|
||||
if (verifyMessagePage)
|
||||
verifyMessagePage->setModel(walletModel);
|
||||
|
||||
setEncryptionStatus(walletModel->getEncryptionStatus());
|
||||
connect(walletModel, SIGNAL(encryptionStatusChanged(int)), this, SLOT(setEncryptionStatus(int)));
|
||||
@@ -610,7 +614,8 @@ void TrianglesGUI::setMessageModel(MessageModel *messageModel)
|
||||
connect(messageModel, SIGNAL(error(QString,QString,bool)), this, SLOT(error(QString,QString,bool)));
|
||||
|
||||
// Put transaction list in tabs
|
||||
messagePage->setModel(messageModel);
|
||||
if (messagePage)
|
||||
messagePage->setModel(messageModel);
|
||||
|
||||
// Balloon pop-up for new message
|
||||
connect(messageModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||||
@@ -626,6 +631,60 @@ void TrianglesGUI::ensureMessageModel()
|
||||
setMessageModel(new MessageModel(pwalletMain, walletModel, this));
|
||||
}
|
||||
|
||||
void TrianglesGUI::ensureSendCoinsPage()
|
||||
{
|
||||
if (sendCoinsPage)
|
||||
return;
|
||||
|
||||
sendCoinsPage = new SendCoinsDialog(this);
|
||||
if (walletModel)
|
||||
sendCoinsPage->setModel(walletModel);
|
||||
centralWidget->addWidget(sendCoinsPage);
|
||||
}
|
||||
|
||||
void TrianglesGUI::ensureMessagePage()
|
||||
{
|
||||
if (messagePage)
|
||||
return;
|
||||
|
||||
messagePage = new MessagePage(this);
|
||||
if (messageModel)
|
||||
messagePage->setModel(messageModel);
|
||||
centralWidget->addWidget(messagePage);
|
||||
}
|
||||
|
||||
void TrianglesGUI::ensureSignMessagePage()
|
||||
{
|
||||
if (signMessagePage)
|
||||
return;
|
||||
|
||||
signMessagePage = new SignMessagePage(this);
|
||||
if (walletModel)
|
||||
signMessagePage->setModel(walletModel);
|
||||
centralWidget->addWidget(signMessagePage);
|
||||
}
|
||||
|
||||
void TrianglesGUI::ensureVerifyMessagePage()
|
||||
{
|
||||
if (verifyMessagePage)
|
||||
return;
|
||||
|
||||
verifyMessagePage = new VerifyMessagePage(this);
|
||||
if (walletModel)
|
||||
verifyMessagePage->setModel(walletModel);
|
||||
centralWidget->addWidget(verifyMessagePage);
|
||||
}
|
||||
|
||||
void TrianglesGUI::ensureRPCConsole()
|
||||
{
|
||||
if (rpcConsole)
|
||||
return;
|
||||
|
||||
rpcConsole = new RPCConsole(this);
|
||||
if (clientModel)
|
||||
rpcConsole->setClientModel(clientModel);
|
||||
}
|
||||
|
||||
void TrianglesGUI::createTrayIcon()
|
||||
{
|
||||
#ifndef Q_OS_MAC
|
||||
@@ -698,7 +757,8 @@ void TrianglesGUI::restoreWindowGeometry()
|
||||
QSize size = settings.value("nWindowSize", QSize(850, 550)).toSize();
|
||||
if (!pos.x() && !pos.y())
|
||||
{
|
||||
QRect screen = QApplication::desktop()->screenGeometry();
|
||||
QScreen *screenObject = QGuiApplication::primaryScreen();
|
||||
QRect screen = screenObject ? screenObject->availableGeometry() : QRect(QPoint(0, 0), size);
|
||||
pos.setX((screen.width()-size.width())/2);
|
||||
pos.setY((screen.height()-size.height())/2);
|
||||
}
|
||||
@@ -751,24 +811,57 @@ void TrianglesGUI::setNumBlocks(int count, int nTotalBlocks)
|
||||
|
||||
QString tooltip;
|
||||
|
||||
QString importText;
|
||||
importText = tr("Synchronizing with network...");
|
||||
|
||||
if(count < nTotalBlocks)
|
||||
{
|
||||
// Calculate blocks/sec - only update rate when new blocks arrive
|
||||
static int lastCount = 0;
|
||||
static qint64 lastRateTime = 0;
|
||||
static float blocksPerSec = 0.0f;
|
||||
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
if (count > lastCount) {
|
||||
// New blocks arrived - recalculate speed
|
||||
if (lastRateTime > 0) {
|
||||
float elapsed = (now - lastRateTime) / 1000.0f;
|
||||
if (elapsed > 0.1f) {
|
||||
float instantRate = (count - lastCount) / elapsed;
|
||||
blocksPerSec = (blocksPerSec < 0.1f) ? instantRate : (blocksPerSec * 0.7f + instantRate * 0.3f);
|
||||
}
|
||||
}
|
||||
lastCount = count;
|
||||
lastRateTime = now;
|
||||
} else if (lastRateTime > 0 && (now - lastRateTime) > 10000) {
|
||||
// No blocks for 10+ seconds - show 0
|
||||
blocksPerSec = 0.0f;
|
||||
}
|
||||
|
||||
int nRemainingBlocks = nTotalBlocks - count;
|
||||
float nPercentageDone = count / (nTotalBlocks * 0.01f);
|
||||
|
||||
progressBarLabel->setText(importText);
|
||||
// Build informative status text
|
||||
QString speedText;
|
||||
if (blocksPerSec >= 1.0f) {
|
||||
int etaSeconds = (int)(nRemainingBlocks / blocksPerSec);
|
||||
QString etaStr;
|
||||
if (etaSeconds < 60)
|
||||
etaStr = tr("%n sec", "", etaSeconds);
|
||||
else if (etaSeconds < 3600)
|
||||
etaStr = tr("%n min", "", etaSeconds / 60);
|
||||
else
|
||||
etaStr = tr("%1h %2m").arg(etaSeconds / 3600).arg((etaSeconds % 3600) / 60);
|
||||
speedText = tr("Syncing: %1 blk/s ~%2 remaining").arg(blocksPerSec, 0, 'f', 1).arg(etaStr);
|
||||
} else {
|
||||
speedText = tr("Synchronizing with network...");
|
||||
}
|
||||
|
||||
progressBarLabel->setText(speedText);
|
||||
progressBarLabel->setVisible(true);
|
||||
progressBar->setFormat(tr("~%n block(s) remaining", "", nRemainingBlocks));
|
||||
progressBar->setFormat(tr("Block %1 / %2 (%3%)").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2));
|
||||
progressBar->setMaximum(nTotalBlocks);
|
||||
progressBar->setValue(count);
|
||||
progressBar->setVisible(true);
|
||||
ui->label_blocks->setText(tr("%n blocks", "", count));
|
||||
ui->label_blocks->setVisible(true);
|
||||
ui->label_blocks->setVisible(false);
|
||||
|
||||
tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
|
||||
tooltip = tr("Downloaded %1 of %2 blocks of transaction history (%3% done).").arg(count).arg(nTotalBlocks).arg(nPercentageDone, 0, 'f', 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -871,19 +964,36 @@ void TrianglesGUI::changeEvent(QEvent *e)
|
||||
|
||||
void TrianglesGUI::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
#ifndef Q_OS_MAC // Ignored on Mac
|
||||
if(clientModel)
|
||||
{
|
||||
#ifndef Q_OS_MAC // Ignored on Mac
|
||||
if(!clientModel->getOptionsModel()->getMinimizeToTray() &&
|
||||
!clientModel->getOptionsModel()->getMinimizeOnClose())
|
||||
if(clientModel->getOptionsModel()->getMinimizeOnClose())
|
||||
{
|
||||
QApplication::quit();
|
||||
// Minimize to taskbar instead of closing
|
||||
QMainWindow::showMinimized();
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
if(clientModel->getOptionsModel()->getMinimizeToTray() && trayIcon)
|
||||
{
|
||||
// Hide to system tray instead of closing
|
||||
hide();
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
// Actually closing - request a full core shutdown before leaving the UI loop.
|
||||
StartShutdown();
|
||||
event->accept();
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void TrianglesGUI::requestShutdown()
|
||||
{
|
||||
StartShutdown();
|
||||
}
|
||||
|
||||
void TrianglesGUI::askFee(qint64 nFeeRequired, bool *payFee)
|
||||
{
|
||||
QString strMessage = tr("<font color='#f26522'>This transaction is over the size limit. You can still send it for a fee of %1, "
|
||||
@@ -1026,6 +1136,8 @@ void TrianglesGUI::gotoReceiveCoinsPage()
|
||||
|
||||
void TrianglesGUI::gotoSendCoinsPage()
|
||||
{
|
||||
ensureSendCoinsPage();
|
||||
|
||||
sendCoinsAction->setChecked(true);
|
||||
centralWidget->setCurrentWidget(sendCoinsPage);
|
||||
|
||||
@@ -1035,6 +1147,7 @@ void TrianglesGUI::gotoSendCoinsPage()
|
||||
|
||||
void TrianglesGUI::gotoMessagePage()
|
||||
{
|
||||
ensureMessagePage();
|
||||
ensureMessageModel();
|
||||
|
||||
messageAction->setChecked(true);
|
||||
@@ -1047,6 +1160,8 @@ void TrianglesGUI::gotoMessagePage()
|
||||
|
||||
void TrianglesGUI::gotoSignMessageTab(QString addr)
|
||||
{
|
||||
ensureSignMessagePage();
|
||||
|
||||
centralWidget->setCurrentWidget(signMessagePage);
|
||||
|
||||
exportAction->setEnabled(false);
|
||||
@@ -1061,6 +1176,8 @@ void TrianglesGUI::gotoSignMessageTab(QString addr)
|
||||
|
||||
void TrianglesGUI::gotoVerifyMessageTab(QString addr)
|
||||
{
|
||||
ensureVerifyMessagePage();
|
||||
|
||||
centralWidget->setCurrentWidget(verifyMessagePage);
|
||||
|
||||
exportAction->setEnabled(false);
|
||||
@@ -1084,6 +1201,7 @@ void TrianglesGUI::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if(event->mimeData()->hasUrls())
|
||||
{
|
||||
ensureSendCoinsPage();
|
||||
int nValidUrisFound = 0;
|
||||
QList<QUrl> uris = event->mimeData()->urls();
|
||||
foreach(const QUrl &uri, uris)
|
||||
@@ -1165,6 +1283,7 @@ void TrianglesGUI::updateMask()
|
||||
void TrianglesGUI::handleURI(QString strURI)
|
||||
{
|
||||
// URI has to be valid
|
||||
ensureSendCoinsPage();
|
||||
if (sendCoinsPage->handleURI(strURI))
|
||||
{
|
||||
showNormalIfMinimized();
|
||||
@@ -1221,6 +1340,12 @@ void TrianglesGUI::menuFileRequested()
|
||||
}
|
||||
}
|
||||
|
||||
void TrianglesGUI::openRPCConsole()
|
||||
{
|
||||
ensureRPCConsole();
|
||||
rpcConsole->show();
|
||||
}
|
||||
|
||||
void TrianglesGUI::menuOperationsRequested()
|
||||
{
|
||||
QMenu menu(this);
|
||||
@@ -1520,5 +1645,6 @@ void TrianglesGUI::detectShutdown()
|
||||
|
||||
void TrianglesGUI::on_bHelp_clicked()
|
||||
{
|
||||
ensureRPCConsole();
|
||||
rpcConsole->show();
|
||||
}
|
||||
|
||||
@@ -79,6 +79,11 @@ protected:
|
||||
|
||||
private:
|
||||
void updateMask();
|
||||
void ensureSendCoinsPage();
|
||||
void ensureMessagePage();
|
||||
void ensureSignMessagePage();
|
||||
void ensureVerifyMessagePage();
|
||||
void ensureRPCConsole();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
@@ -181,6 +186,8 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void ensureMessageModel();
|
||||
void openRPCConsole();
|
||||
void requestShutdown();
|
||||
|
||||
void menuFileRequested();
|
||||
void menuOperationsRequested();
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
VerifyMessagePage::VerifyMessagePage(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::VerifyMessagePage),
|
||||
|
||||
@@ -168,7 +168,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QList<SendCoinsRecipie
|
||||
std::vector<COutput> vCoins;
|
||||
wallet->AvailableCoins(vCoins, true, coinControl);
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
for (const COutput& out : vCoins)
|
||||
nBalance += out.tx->vout[out.i].nValue;
|
||||
|
||||
if(total > nBalance)
|
||||
@@ -451,7 +451,7 @@ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
|
||||
// returns a list of COutputs from COutPoints
|
||||
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
|
||||
{
|
||||
BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
|
||||
for (const COutPoint& outpoint : vOutpoints)
|
||||
{
|
||||
if (!wallet->mapWallet.count(outpoint.hash)) continue;
|
||||
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
|
||||
@@ -469,7 +469,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
|
||||
std::vector<COutPoint> vLockedCoins;
|
||||
|
||||
// add locked coins
|
||||
BOOST_FOREACH(const COutPoint& outpoint, vLockedCoins)
|
||||
for (const COutPoint& outpoint : vLockedCoins)
|
||||
{
|
||||
if (!wallet->mapWallet.count(outpoint.hash)) continue;
|
||||
int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain();
|
||||
@@ -478,7 +478,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
|
||||
vCoins.push_back(out);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
for (const COutput& out : vCoins)
|
||||
{
|
||||
COutput cout = out;
|
||||
|
||||
|
||||
+925
@@ -0,0 +1,925 @@
|
||||
// Copyright (c) 2024 The Triangles developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "rest.h"
|
||||
#include "trianglesrpc.h"
|
||||
#include "main.h"
|
||||
#include "sync.h"
|
||||
#include "util.h"
|
||||
#include "base58.h"
|
||||
#include "addressindex.h"
|
||||
#include "wallet.h"
|
||||
#include "init.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace json_spirit;
|
||||
|
||||
// Forward declarations from rpcblockchain.cpp
|
||||
extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail);
|
||||
extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
|
||||
|
||||
// Forward declaration from trianglesrpc.cpp
|
||||
extern bool HTTPAuthorized(map<string, string>& mapHeaders);
|
||||
extern string rfc1123Time();
|
||||
|
||||
// ============================================================================
|
||||
// Rate limiter
|
||||
// ============================================================================
|
||||
|
||||
struct IPRateLimiter
|
||||
{
|
||||
int64_t nTokens;
|
||||
int64_t nLastRefill;
|
||||
|
||||
IPRateLimiter() : nTokens(0), nLastRefill(0) {}
|
||||
|
||||
bool Allow(int64_t nMaxTokens, int64_t nRefillRate)
|
||||
{
|
||||
int64_t nNow = GetTime();
|
||||
if (nLastRefill == 0) {
|
||||
nLastRefill = nNow;
|
||||
nTokens = nMaxTokens;
|
||||
}
|
||||
// Refill tokens
|
||||
int64_t nElapsed = nNow - nLastRefill;
|
||||
if (nElapsed > 0) {
|
||||
nTokens += nElapsed * nRefillRate;
|
||||
if (nTokens > nMaxTokens)
|
||||
nTokens = nMaxTokens;
|
||||
nLastRefill = nNow;
|
||||
}
|
||||
if (nTokens > 0) {
|
||||
nTokens--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static CCriticalSection cs_rateLimiter;
|
||||
static map<string, IPRateLimiter> mapRateLimiters;
|
||||
static int64_t nLastCleanup = 0;
|
||||
|
||||
bool CheckRESTRateLimit(const string& strIP)
|
||||
{
|
||||
int64_t nLimit = GetArg("-restratelimit", 30);
|
||||
int64_t nBurst = nLimit * 2; // burst = 2x sustained rate
|
||||
|
||||
if (nLimit <= 0)
|
||||
return true; // rate limiting disabled
|
||||
|
||||
LOCK(cs_rateLimiter);
|
||||
|
||||
// Periodic cleanup of stale entries (every 60s)
|
||||
int64_t nNow = GetTime();
|
||||
if (nNow - nLastCleanup > 60) {
|
||||
map<string, IPRateLimiter>::iterator it = mapRateLimiters.begin();
|
||||
while (it != mapRateLimiters.end()) {
|
||||
if (nNow - it->second.nLastRefill > 300) // 5 min stale
|
||||
mapRateLimiters.erase(it++);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
nLastCleanup = nNow;
|
||||
}
|
||||
|
||||
return mapRateLimiters[strIP].Allow(nBurst, nLimit);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// HTTP response helpers
|
||||
// ============================================================================
|
||||
|
||||
string HTTPReplyREST(int nStatus, const string& strMsg, const string& contentType)
|
||||
{
|
||||
string strCorsOrigin = GetArg("-restcorsorigin", "*");
|
||||
|
||||
const char *cStatus;
|
||||
if (nStatus == 200) cStatus = "OK";
|
||||
else if (nStatus == 204) cStatus = "No Content";
|
||||
else if (nStatus == 400) cStatus = "Bad Request";
|
||||
else if (nStatus == 401) cStatus = "Unauthorized";
|
||||
else if (nStatus == 403) cStatus = "Forbidden";
|
||||
else if (nStatus == 404) cStatus = "Not Found";
|
||||
else if (nStatus == 429) cStatus = "Too Many Requests";
|
||||
else if (nStatus == 500) cStatus = "Internal Server Error";
|
||||
else if (nStatus == 503) cStatus = "Service Unavailable";
|
||||
else cStatus = "";
|
||||
|
||||
return strprintf(
|
||||
"HTTP/1.1 %d %s\r\n"
|
||||
"Date: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: %" PRIszu "\r\n"
|
||||
"Content-Type: %s\r\n"
|
||||
"Access-Control-Allow-Origin: %s\r\n"
|
||||
"Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n"
|
||||
"Access-Control-Allow-Headers: Content-Type, Authorization\r\n"
|
||||
"Access-Control-Max-Age: 86400\r\n"
|
||||
"Server: Triangles/%s\r\n"
|
||||
"\r\n"
|
||||
"%s",
|
||||
nStatus,
|
||||
cStatus,
|
||||
rfc1123Time().c_str(),
|
||||
strMsg.size(),
|
||||
contentType.c_str(),
|
||||
strCorsOrigin.c_str(),
|
||||
FormatFullVersion().c_str(),
|
||||
strMsg.c_str());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// URL parsing
|
||||
// ============================================================================
|
||||
|
||||
static void ParseRESTPath(const string& strURI, vector<string>& parts, map<string, string>& queryParams)
|
||||
{
|
||||
string path = strURI;
|
||||
|
||||
// Split query string
|
||||
size_t qpos = path.find('?');
|
||||
string queryString;
|
||||
if (qpos != string::npos) {
|
||||
queryString = path.substr(qpos + 1);
|
||||
path = path.substr(0, qpos);
|
||||
}
|
||||
|
||||
// Split path into parts
|
||||
boost::split(parts, path, boost::is_any_of("/"));
|
||||
|
||||
// Parse query parameters
|
||||
if (!queryString.empty()) {
|
||||
vector<string> pairs;
|
||||
boost::split(pairs, queryString, boost::is_any_of("&"));
|
||||
for (size_t i = 0; i < pairs.size(); i++) {
|
||||
size_t eq = pairs[i].find('=');
|
||||
if (eq != string::npos)
|
||||
queryParams[pairs[i].substr(0, eq)] = pairs[i].substr(eq + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRESTPath(const string& strURI)
|
||||
{
|
||||
return strURI.size() >= 6 && strURI.substr(0, 6) == "/rest/";
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Auth helpers
|
||||
// ============================================================================
|
||||
|
||||
static bool RESTAuthorized(map<string, string>& mapHeaders)
|
||||
{
|
||||
// Check Bearer token first (if -restapikey is set)
|
||||
string strApiKey = GetArg("-restapikey", "");
|
||||
if (!strApiKey.empty()) {
|
||||
string strAuth = mapHeaders.count("authorization") ? mapHeaders["authorization"] : "";
|
||||
if (strAuth.substr(0, 7) == "Bearer ") {
|
||||
string strToken = strAuth.substr(7);
|
||||
boost::trim(strToken);
|
||||
if (TimingResistantEqual(strToken, strApiKey))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to Basic Auth (same as RPC)
|
||||
if (mapHeaders.count("authorization"))
|
||||
return HTTPAuthorized(mapHeaders);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// JSON error helper
|
||||
// ============================================================================
|
||||
|
||||
static string RESTError(const string& message, int code = -1)
|
||||
{
|
||||
Object obj;
|
||||
obj.push_back(Pair("error", message));
|
||||
if (code != -1)
|
||||
obj.push_back(Pair("code", code));
|
||||
return write_string(Value(obj), false) + "\n";
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Helper: call an RPC method and return JSON string
|
||||
// ============================================================================
|
||||
|
||||
static bool CallRPCMethod(const string& method, const Array& params,
|
||||
string& strReply, int& nStatus)
|
||||
{
|
||||
try {
|
||||
Value result = tableRPC.execute(method, params);
|
||||
strReply = write_string(result, false) + "\n";
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
catch (Object& objError) {
|
||||
int code = find_value(objError, "code").get_int();
|
||||
string msg = find_value(objError, "message").get_str();
|
||||
if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
|
||||
else if (code == RPC_WALLET_UNLOCK_NEEDED) nStatus = HTTP_FORBIDDEN;
|
||||
else if (code == RPC_INVALID_PARAMETER || code == RPC_INVALID_ADDRESS_OR_KEY) nStatus = HTTP_BAD_REQUEST;
|
||||
else nStatus = HTTP_INTERNAL_SERVER_ERROR;
|
||||
strReply = RESTError(msg, code);
|
||||
return true;
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
nStatus = HTTP_INTERNAL_SERVER_ERROR;
|
||||
strReply = RESTError(e.what());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Public endpoint handlers
|
||||
// ============================================================================
|
||||
|
||||
// GET /rest/chaininfo
|
||||
static bool HandleChainInfo(string& strReply, int& nStatus)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
Object obj, diff;
|
||||
obj.push_back(Pair("chain", fTestNet ? string("test") : string("main")));
|
||||
obj.push_back(Pair("blocks", (int)nBestHeight));
|
||||
obj.push_back(Pair("bestblockhash", hashBestChain.GetHex()));
|
||||
diff.push_back(Pair("proof-of-work", GetDifficulty()));
|
||||
diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
|
||||
obj.push_back(Pair("difficulty", diff));
|
||||
obj.push_back(Pair("moneysupply", ValueFromAmount(pindexBest->nMoneySupply)));
|
||||
strReply = write_string(Value(obj), false) + "\n";
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GET /rest/block/{hash_or_param}[.hex]
|
||||
static bool HandleBlock(const string& param, const string& format, string& strReply, int& nStatus)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
uint256 hash(param);
|
||||
if (mapBlockIndex.count(hash) == 0) {
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Block not found");
|
||||
return true;
|
||||
}
|
||||
CBlock block;
|
||||
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||
block.ReadFromDisk(pblockindex, true);
|
||||
|
||||
if (format == "hex") {
|
||||
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssBlock << block;
|
||||
strReply = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
|
||||
} else {
|
||||
Object obj = blockToJSON(block, pblockindex, false);
|
||||
strReply = write_string(Value(obj), false) + "\n";
|
||||
}
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GET /rest/blockheader/{hash}
|
||||
static bool HandleBlockHeader(const string& param, string& strReply, int& nStatus)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
uint256 hash(param);
|
||||
if (mapBlockIndex.count(hash) == 0) {
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Block not found");
|
||||
return true;
|
||||
}
|
||||
CBlockIndex* pblockindex = mapBlockIndex[hash];
|
||||
Object result;
|
||||
result.push_back(Pair("hash", pblockindex->GetBlockHash().GetHex()));
|
||||
result.push_back(Pair("confirmations", pindexBest->nHeight - pblockindex->nHeight + 1));
|
||||
result.push_back(Pair("height", pblockindex->nHeight));
|
||||
result.push_back(Pair("version", pblockindex->nVersion));
|
||||
result.push_back(Pair("merkleroot", pblockindex->hashMerkleRoot.GetHex()));
|
||||
result.push_back(Pair("time", (boost::int64_t)pblockindex->GetBlockTime()));
|
||||
result.push_back(Pair("nonce", (boost::uint64_t)pblockindex->nNonce));
|
||||
result.push_back(Pair("bits", HexBits(pblockindex->nBits)));
|
||||
result.push_back(Pair("difficulty", GetDifficulty(pblockindex)));
|
||||
result.push_back(Pair("flags", strprintf("%s%s",
|
||||
pblockindex->IsProofOfStake() ? "proof-of-stake" : "proof-of-work",
|
||||
pblockindex->GeneratedStakeModifier() ? " stake-modifier" : "")));
|
||||
if (pblockindex->pprev)
|
||||
result.push_back(Pair("previousblockhash", pblockindex->pprev->GetBlockHash().GetHex()));
|
||||
if (pblockindex->pnext)
|
||||
result.push_back(Pair("nextblockhash", pblockindex->pnext->GetBlockHash().GetHex()));
|
||||
strReply = write_string(Value(result), false) + "\n";
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GET /rest/tx/{txid}[.hex]
|
||||
static bool HandleTx(const string& param, const string& format, string& strReply, int& nStatus)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
uint256 hash(param);
|
||||
CTransaction tx;
|
||||
uint256 hashBlock = 0;
|
||||
if (!GetTransaction(hash, tx, hashBlock)) {
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Transaction not found");
|
||||
return true;
|
||||
}
|
||||
if (format == "hex") {
|
||||
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssTx << tx;
|
||||
strReply = HexStr(ssTx.begin(), ssTx.end()) + "\n";
|
||||
} else {
|
||||
Object obj;
|
||||
obj.push_back(Pair("txid", tx.GetHash().GetHex()));
|
||||
TxToJSON(tx, hashBlock, obj);
|
||||
strReply = write_string(Value(obj), false) + "\n";
|
||||
}
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GET /rest/blockhashbyheight/{n}
|
||||
static bool HandleBlockHashByHeight(const string& param, string& strReply, int& nStatus)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
int nHeight = atoi(param.c_str());
|
||||
if (nHeight < 0 || nHeight > nBestHeight) {
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Block height out of range");
|
||||
return true;
|
||||
}
|
||||
CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
|
||||
Object obj;
|
||||
obj.push_back(Pair("blockhash", pblockindex->phashBlock->GetHex()));
|
||||
strReply = write_string(Value(obj), false) + "\n";
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GET /rest/blockbyheight/{n}
|
||||
static bool HandleBlockByHeight(const string& param, const string& format, string& strReply, int& nStatus)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
int nHeight = atoi(param.c_str());
|
||||
if (nHeight < 0 || nHeight > nBestHeight) {
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Block height out of range");
|
||||
return true;
|
||||
}
|
||||
CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
|
||||
CBlock block;
|
||||
block.ReadFromDisk(pblockindex, true);
|
||||
|
||||
if (format == "hex") {
|
||||
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
|
||||
ssBlock << block;
|
||||
strReply = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
|
||||
} else {
|
||||
Object obj = blockToJSON(block, pblockindex, false);
|
||||
strReply = write_string(Value(obj), false) + "\n";
|
||||
}
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GET /rest/mempool
|
||||
static bool HandleMempool(string& strReply, int& nStatus)
|
||||
{
|
||||
vector<uint256> vtxid;
|
||||
mempool.queryHashes(vtxid);
|
||||
Array a;
|
||||
for (const uint256& hash : vtxid)
|
||||
a.push_back(hash.ToString());
|
||||
strReply = write_string(Value(a), false) + "\n";
|
||||
nStatus = HTTP_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GET /rest/difficulty
|
||||
static bool HandleDifficulty(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getdifficulty", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/supply
|
||||
static bool HandleSupply(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("gettxoutsetinfo", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/staking
|
||||
static bool HandleStaking(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getstakinginfo", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/mining
|
||||
static bool HandleMining(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getmininginfo", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/subsidy
|
||||
static bool HandleSubsidy(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getsubsidy", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/estimatefee
|
||||
static bool HandleEstimateFee(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
params.push_back(6); // default 6 blocks
|
||||
return CallRPCMethod("estimatefee", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/checkpoint
|
||||
static bool HandleCheckpoint(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getcheckpoint", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/network
|
||||
static bool HandleNetwork(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getnetworkinfo", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/peers
|
||||
static bool HandlePeers(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getpeerinfo", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/validate/{address}
|
||||
static bool HandleValidate(const string& addr, string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
params.push_back(addr);
|
||||
return CallRPCMethod("validateaddress", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/address/{addr}/balance
|
||||
static bool HandleAddressBalance(const string& addr, string& strReply, int& nStatus)
|
||||
{
|
||||
if (!fAddressIndex) {
|
||||
nStatus = 503;
|
||||
strReply = RESTError("Address index not enabled. Start daemon with -addressindex=1");
|
||||
return true;
|
||||
}
|
||||
Object addrObj;
|
||||
Array addrArray;
|
||||
addrArray.push_back(addr);
|
||||
addrObj.push_back(Pair("addresses", addrArray));
|
||||
Array params;
|
||||
params.push_back(addrObj);
|
||||
return CallRPCMethod("getaddressbalance", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/address/{addr}/utxos
|
||||
static bool HandleAddressUtxos(const string& addr, string& strReply, int& nStatus)
|
||||
{
|
||||
if (!fAddressIndex) {
|
||||
nStatus = 503;
|
||||
strReply = RESTError("Address index not enabled. Start daemon with -addressindex=1");
|
||||
return true;
|
||||
}
|
||||
Object addrObj;
|
||||
Array addrArray;
|
||||
addrArray.push_back(addr);
|
||||
addrObj.push_back(Pair("addresses", addrArray));
|
||||
Array params;
|
||||
params.push_back(addrObj);
|
||||
return CallRPCMethod("getaddressutxos", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/address/{addr}/txids[?start=N&end=N]
|
||||
static bool HandleAddressTxids(const string& addr, const map<string, string>& queryParams,
|
||||
string& strReply, int& nStatus)
|
||||
{
|
||||
if (!fAddressIndex) {
|
||||
nStatus = 503;
|
||||
strReply = RESTError("Address index not enabled. Start daemon with -addressindex=1");
|
||||
return true;
|
||||
}
|
||||
Object addrObj;
|
||||
Array addrArray;
|
||||
addrArray.push_back(addr);
|
||||
addrObj.push_back(Pair("addresses", addrArray));
|
||||
|
||||
map<string, string>::const_iterator itStart = queryParams.find("start");
|
||||
map<string, string>::const_iterator itEnd = queryParams.find("end");
|
||||
if (itStart != queryParams.end())
|
||||
addrObj.push_back(Pair("start", atoi(itStart->second.c_str())));
|
||||
if (itEnd != queryParams.end())
|
||||
addrObj.push_back(Pair("end", atoi(itEnd->second.c_str())));
|
||||
|
||||
Array params;
|
||||
params.push_back(addrObj);
|
||||
return CallRPCMethod("getaddresstxids", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// POST /rest/tx/decode body: {"hex":"..."}
|
||||
static bool HandleTxDecode(const string& strBody, string& strReply, int& nStatus)
|
||||
{
|
||||
Value valBody;
|
||||
if (!read_string(strBody, valBody) || valBody.type() != obj_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Invalid JSON body. Expected: {\"hex\":\"...\"}");
|
||||
return true;
|
||||
}
|
||||
Object bodyObj = valBody.get_obj();
|
||||
Value hexVal = find_value(bodyObj, "hex");
|
||||
if (hexVal.type() != str_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Missing 'hex' field in request body");
|
||||
return true;
|
||||
}
|
||||
Array params;
|
||||
params.push_back(hexVal.get_str());
|
||||
return CallRPCMethod("decoderawtransaction", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// POST /rest/tx/send body: {"hex":"..."}
|
||||
static bool HandleTxSend(const string& strBody, string& strReply, int& nStatus)
|
||||
{
|
||||
Value valBody;
|
||||
if (!read_string(strBody, valBody) || valBody.type() != obj_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Invalid JSON body. Expected: {\"hex\":\"...\"}");
|
||||
return true;
|
||||
}
|
||||
Object bodyObj = valBody.get_obj();
|
||||
Value hexVal = find_value(bodyObj, "hex");
|
||||
if (hexVal.type() != str_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Missing 'hex' field in request body");
|
||||
return true;
|
||||
}
|
||||
Array params;
|
||||
params.push_back(hexVal.get_str());
|
||||
return CallRPCMethod("sendrawtransaction", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Wallet endpoint handlers (authenticated)
|
||||
// ============================================================================
|
||||
|
||||
// GET /rest/wallet/info
|
||||
static bool HandleWalletInfo(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getwalletinfo", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/wallet/balance
|
||||
static bool HandleWalletBalance(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getbalance", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/wallet/transactions[?count=N&skip=N]
|
||||
static bool HandleWalletTransactions(const map<string, string>& queryParams,
|
||||
string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
params.push_back("*"); // all accounts
|
||||
|
||||
map<string, string>::const_iterator itCount = queryParams.find("count");
|
||||
map<string, string>::const_iterator itSkip = queryParams.find("skip");
|
||||
|
||||
int nCount = 10;
|
||||
int nSkip = 0;
|
||||
if (itCount != queryParams.end())
|
||||
nCount = atoi(itCount->second.c_str());
|
||||
if (itSkip != queryParams.end())
|
||||
nSkip = atoi(itSkip->second.c_str());
|
||||
|
||||
params.push_back(nCount);
|
||||
params.push_back(nSkip);
|
||||
return CallRPCMethod("listtransactions", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/wallet/transaction/{txid}
|
||||
static bool HandleWalletTransaction(const string& txid, string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
params.push_back(txid);
|
||||
return CallRPCMethod("gettransaction", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/wallet/unspent[?minconf=N&maxconf=N]
|
||||
static bool HandleWalletUnspent(const map<string, string>& queryParams,
|
||||
string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
map<string, string>::const_iterator itMin = queryParams.find("minconf");
|
||||
map<string, string>::const_iterator itMax = queryParams.find("maxconf");
|
||||
|
||||
params.push_back(itMin != queryParams.end() ? atoi(itMin->second.c_str()) : 1);
|
||||
params.push_back(itMax != queryParams.end() ? atoi(itMax->second.c_str()) : 9999999);
|
||||
return CallRPCMethod("listunspent", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/wallet/addresses
|
||||
static bool HandleWalletAddresses(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("listaddressgroupings", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// GET /rest/wallet/staking
|
||||
static bool HandleWalletStaking(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("getstakinginfo", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// POST /rest/wallet/address/new body: {} or {"account":"..."}
|
||||
static bool HandleWalletNewAddress(const string& strBody, string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
if (!strBody.empty()) {
|
||||
Value valBody;
|
||||
if (read_string(strBody, valBody) && valBody.type() == obj_type) {
|
||||
Value acctVal = find_value(valBody.get_obj(), "account");
|
||||
if (acctVal.type() == str_type)
|
||||
params.push_back(acctVal.get_str());
|
||||
}
|
||||
}
|
||||
return CallRPCMethod("getnewaddress", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// POST /rest/wallet/send body: {"address":"...", "amount":N}
|
||||
static bool HandleWalletSend(const string& strBody, string& strReply, int& nStatus)
|
||||
{
|
||||
Value valBody;
|
||||
if (!read_string(strBody, valBody) || valBody.type() != obj_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Invalid JSON body. Expected: {\"address\":\"...\", \"amount\":N}");
|
||||
return true;
|
||||
}
|
||||
Object bodyObj = valBody.get_obj();
|
||||
Value addrVal = find_value(bodyObj, "address");
|
||||
Value amtVal = find_value(bodyObj, "amount");
|
||||
if (addrVal.type() != str_type || (amtVal.type() != real_type && amtVal.type() != int_type)) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Missing 'address' (string) or 'amount' (number) in request body");
|
||||
return true;
|
||||
}
|
||||
Array params;
|
||||
params.push_back(addrVal.get_str());
|
||||
params.push_back(amtVal);
|
||||
|
||||
// Optional comment fields
|
||||
Value commentVal = find_value(bodyObj, "comment");
|
||||
Value commentToVal = find_value(bodyObj, "comment_to");
|
||||
if (commentVal.type() == str_type)
|
||||
params.push_back(commentVal.get_str());
|
||||
else
|
||||
params.push_back("");
|
||||
if (commentToVal.type() == str_type)
|
||||
params.push_back(commentToVal.get_str());
|
||||
|
||||
return CallRPCMethod("sendtoaddress", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// POST /rest/wallet/sendmany body: {"recipients":{"addr":amount,...}}
|
||||
static bool HandleWalletSendMany(const string& strBody, string& strReply, int& nStatus)
|
||||
{
|
||||
Value valBody;
|
||||
if (!read_string(strBody, valBody) || valBody.type() != obj_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Invalid JSON body. Expected: {\"recipients\":{\"addr\":amount,...}}");
|
||||
return true;
|
||||
}
|
||||
Object bodyObj = valBody.get_obj();
|
||||
Value recipVal = find_value(bodyObj, "recipients");
|
||||
if (recipVal.type() != obj_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Missing 'recipients' object in request body");
|
||||
return true;
|
||||
}
|
||||
Array params;
|
||||
params.push_back(""); // fromaccount (default)
|
||||
params.push_back(recipVal); // {addr: amount, ...}
|
||||
return CallRPCMethod("sendmany", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// POST /rest/wallet/unlock body: {"passphrase":"...", "timeout":N, "staking_only":bool}
|
||||
static bool HandleWalletUnlock(const string& strBody, string& strReply, int& nStatus)
|
||||
{
|
||||
Value valBody;
|
||||
if (!read_string(strBody, valBody) || valBody.type() != obj_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Invalid JSON body. Expected: {\"passphrase\":\"...\", \"timeout\":N}");
|
||||
return true;
|
||||
}
|
||||
Object bodyObj = valBody.get_obj();
|
||||
Value passVal = find_value(bodyObj, "passphrase");
|
||||
Value timeVal = find_value(bodyObj, "timeout");
|
||||
if (passVal.type() != str_type || timeVal.type() != int_type) {
|
||||
nStatus = HTTP_BAD_REQUEST;
|
||||
strReply = RESTError("Missing 'passphrase' (string) or 'timeout' (integer) in request body");
|
||||
return true;
|
||||
}
|
||||
Array params;
|
||||
params.push_back(passVal.get_str());
|
||||
params.push_back(timeVal.get_int());
|
||||
|
||||
Value stakingVal = find_value(bodyObj, "staking_only");
|
||||
if (stakingVal.type() == bool_type)
|
||||
params.push_back(stakingVal.get_bool());
|
||||
|
||||
return CallRPCMethod("walletpassphrase", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// POST /rest/wallet/lock
|
||||
static bool HandleWalletLock(string& strReply, int& nStatus)
|
||||
{
|
||||
Array params;
|
||||
return CallRPCMethod("walletlock", params, strReply, nStatus);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Main router
|
||||
// ============================================================================
|
||||
|
||||
bool HandleRESTRequest(const string& strMethod,
|
||||
const string& strURI,
|
||||
const string& strBody,
|
||||
map<string, string>& mapHeaders,
|
||||
string& strReply,
|
||||
string& strContentType,
|
||||
int& nStatus)
|
||||
{
|
||||
strContentType = "application/json";
|
||||
|
||||
// OPTIONS: CORS preflight
|
||||
if (strMethod == "OPTIONS") {
|
||||
nStatus = 204;
|
||||
strReply = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse path
|
||||
vector<string> parts;
|
||||
map<string, string> queryParams;
|
||||
ParseRESTPath(strURI, parts, queryParams);
|
||||
// parts: ["", "rest", "resource", "param", ...]
|
||||
|
||||
if (parts.size() < 3) {
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Not found");
|
||||
return true;
|
||||
}
|
||||
|
||||
string resource = parts[2];
|
||||
|
||||
// Detect format suffix (.hex, .json)
|
||||
string format = "json";
|
||||
string lastPart = parts.size() > 3 ? parts[parts.size() - 1] : "";
|
||||
size_t dotPos = lastPart.rfind('.');
|
||||
string param;
|
||||
if (dotPos != string::npos) {
|
||||
param = lastPart.substr(0, dotPos);
|
||||
format = lastPart.substr(dotPos + 1);
|
||||
} else {
|
||||
param = lastPart;
|
||||
}
|
||||
|
||||
if (format == "hex")
|
||||
strContentType = "text/plain";
|
||||
|
||||
// ---- Wallet endpoints (authenticated) ----
|
||||
if (resource == "wallet") {
|
||||
if (!RESTAuthorized(mapHeaders)) {
|
||||
nStatus = HTTP_UNAUTHORIZED;
|
||||
strReply = RESTError("Authentication required for wallet endpoints");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parts.size() < 4) {
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Unknown wallet endpoint");
|
||||
return true;
|
||||
}
|
||||
|
||||
string walletResource = parts[3];
|
||||
|
||||
if (strMethod == "GET") {
|
||||
if (walletResource == "info")
|
||||
return HandleWalletInfo(strReply, nStatus);
|
||||
if (walletResource == "balance")
|
||||
return HandleWalletBalance(strReply, nStatus);
|
||||
if (walletResource == "transactions")
|
||||
return HandleWalletTransactions(queryParams, strReply, nStatus);
|
||||
if (walletResource == "transaction" && parts.size() > 4)
|
||||
return HandleWalletTransaction(parts[4], strReply, nStatus);
|
||||
if (walletResource == "unspent")
|
||||
return HandleWalletUnspent(queryParams, strReply, nStatus);
|
||||
if (walletResource == "addresses")
|
||||
return HandleWalletAddresses(strReply, nStatus);
|
||||
if (walletResource == "staking")
|
||||
return HandleWalletStaking(strReply, nStatus);
|
||||
}
|
||||
else if (strMethod == "POST") {
|
||||
if (walletResource == "address" && parts.size() > 4 && parts[4] == "new")
|
||||
return HandleWalletNewAddress(strBody, strReply, nStatus);
|
||||
if (walletResource == "send")
|
||||
return HandleWalletSend(strBody, strReply, nStatus);
|
||||
if (walletResource == "sendmany")
|
||||
return HandleWalletSendMany(strBody, strReply, nStatus);
|
||||
if (walletResource == "unlock")
|
||||
return HandleWalletUnlock(strBody, strReply, nStatus);
|
||||
if (walletResource == "lock")
|
||||
return HandleWalletLock(strReply, nStatus);
|
||||
}
|
||||
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Unknown wallet endpoint");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ---- Public GET endpoints ----
|
||||
if (strMethod == "GET") {
|
||||
if (resource == "chaininfo")
|
||||
return HandleChainInfo(strReply, nStatus);
|
||||
if (resource == "block" && !param.empty())
|
||||
return HandleBlock(param, format, strReply, nStatus);
|
||||
if (resource == "blockheader" && !param.empty())
|
||||
return HandleBlockHeader(param, strReply, nStatus);
|
||||
if (resource == "tx") {
|
||||
// /rest/tx/decode and /rest/tx/send are POST-only
|
||||
if (!param.empty())
|
||||
return HandleTx(param, format, strReply, nStatus);
|
||||
}
|
||||
if (resource == "blockhashbyheight" && !param.empty())
|
||||
return HandleBlockHashByHeight(param, strReply, nStatus);
|
||||
if (resource == "blockbyheight" && !param.empty())
|
||||
return HandleBlockByHeight(param, format, strReply, nStatus);
|
||||
if (resource == "mempool")
|
||||
return HandleMempool(strReply, nStatus);
|
||||
if (resource == "difficulty")
|
||||
return HandleDifficulty(strReply, nStatus);
|
||||
if (resource == "supply")
|
||||
return HandleSupply(strReply, nStatus);
|
||||
if (resource == "staking")
|
||||
return HandleStaking(strReply, nStatus);
|
||||
if (resource == "mining")
|
||||
return HandleMining(strReply, nStatus);
|
||||
if (resource == "subsidy")
|
||||
return HandleSubsidy(strReply, nStatus);
|
||||
if (resource == "estimatefee")
|
||||
return HandleEstimateFee(strReply, nStatus);
|
||||
if (resource == "checkpoint")
|
||||
return HandleCheckpoint(strReply, nStatus);
|
||||
if (resource == "network")
|
||||
return HandleNetwork(strReply, nStatus);
|
||||
if (resource == "peers")
|
||||
return HandlePeers(strReply, nStatus);
|
||||
if (resource == "validate" && !param.empty())
|
||||
return HandleValidate(param, strReply, nStatus);
|
||||
|
||||
// Address endpoints: /rest/address/{addr}/balance etc.
|
||||
if (resource == "address" && parts.size() >= 5) {
|
||||
string addr = parts[3];
|
||||
string addrAction = parts[4];
|
||||
if (addrAction == "balance")
|
||||
return HandleAddressBalance(addr, strReply, nStatus);
|
||||
if (addrAction == "utxos")
|
||||
return HandleAddressUtxos(addr, strReply, nStatus);
|
||||
if (addrAction == "txids")
|
||||
return HandleAddressTxids(addr, queryParams, strReply, nStatus);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Public POST endpoints ----
|
||||
if (strMethod == "POST") {
|
||||
if (resource == "tx" && parts.size() >= 4) {
|
||||
string txAction = parts[3];
|
||||
if (txAction == "decode")
|
||||
return HandleTxDecode(strBody, strReply, nStatus);
|
||||
if (txAction == "send")
|
||||
return HandleTxSend(strBody, strReply, nStatus);
|
||||
}
|
||||
}
|
||||
|
||||
nStatus = HTTP_NOT_FOUND;
|
||||
strReply = RESTError("Unknown REST endpoint");
|
||||
return true;
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2024 The Triangles developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef TRIANGLES_REST_H
|
||||
#define TRIANGLES_REST_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
class CBlock;
|
||||
class CBlockIndex;
|
||||
class CTransaction;
|
||||
|
||||
// REST API response builder with CORS headers
|
||||
std::string HTTPReplyREST(int nStatus, const std::string& strMsg,
|
||||
const std::string& contentType = "application/json");
|
||||
|
||||
// Main REST request router
|
||||
// Returns true if the URI was handled as a REST request, false if it should fall through to RPC
|
||||
bool HandleRESTRequest(const std::string& strMethod,
|
||||
const std::string& strURI,
|
||||
const std::string& strBody,
|
||||
std::map<std::string, std::string>& mapHeaders,
|
||||
std::string& strReply,
|
||||
std::string& strContentType,
|
||||
int& nStatus);
|
||||
|
||||
// Check if a URI is a REST API path
|
||||
bool IsRESTPath(const std::string& strURI);
|
||||
|
||||
// Check rate limit for an IP address. Returns true if allowed.
|
||||
bool CheckRESTRateLimit(const std::string& strIP);
|
||||
|
||||
#endif // TRIANGLES_REST_H
|
||||
@@ -128,7 +128,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPri
|
||||
result.push_back(Pair("modifier", strprintf("%016"PRIx64, blockindex->nStakeModifier)));
|
||||
result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
|
||||
Array txinfo;
|
||||
BOOST_FOREACH (const CTransaction& tx, block.vtx)
|
||||
for (const CTransaction& tx : block.vtx)
|
||||
{
|
||||
if (fPrintTransactionDetail)
|
||||
{
|
||||
@@ -211,7 +211,7 @@ Value getrawmempool(const Array& params, bool fHelp)
|
||||
mempool.queryHashes(vtxid);
|
||||
|
||||
Array a;
|
||||
BOOST_FOREACH(const uint256& hash, vtxid)
|
||||
for (const uint256& hash : vtxid)
|
||||
a.push_back(hash.ToString());
|
||||
|
||||
return a;
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ std::string static EncodeDumpTime(int64_t nTime) {
|
||||
|
||||
std::string static EncodeDumpString(const std::string &str) {
|
||||
std::stringstream ret;
|
||||
BOOST_FOREACH(unsigned char c, str) {
|
||||
for (unsigned char c : str) {
|
||||
if (c <= 32 || c >= 128 || c == '%') {
|
||||
ret << '%' << HexStr(&c, &c + 1);
|
||||
} else {
|
||||
|
||||
+5
-5
@@ -144,7 +144,7 @@ Value getworkex(const Array& params, bool fHelp)
|
||||
{
|
||||
// Deallocate old blocks since they're obsolete now
|
||||
mapNewBlock.clear();
|
||||
BOOST_FOREACH(CBlock* pblock, vNewBlock)
|
||||
for (CBlock* pblock : vNewBlock)
|
||||
delete pblock;
|
||||
vNewBlock.clear();
|
||||
}
|
||||
@@ -191,7 +191,7 @@ Value getworkex(const Array& params, bool fHelp)
|
||||
|
||||
Array merkle_arr;
|
||||
|
||||
BOOST_FOREACH(uint256 merkleh, merkle) {
|
||||
for (uint256 merkleh : merkle) {
|
||||
merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ Value getwork(const Array& params, bool fHelp)
|
||||
{
|
||||
// Deallocate old blocks since they're obsolete now
|
||||
mapNewBlock.clear();
|
||||
BOOST_FOREACH(CBlock* pblock, vNewBlock)
|
||||
for (CBlock* pblock : vNewBlock)
|
||||
delete pblock;
|
||||
vNewBlock.clear();
|
||||
}
|
||||
@@ -442,7 +442,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
||||
map<uint256, int64_t> setTxIndex;
|
||||
int i = 0;
|
||||
CTxDB txdb("r");
|
||||
BOOST_FOREACH (CTransaction& tx, pblock->vtx)
|
||||
for (CTransaction& tx : pblock->vtx)
|
||||
{
|
||||
uint256 txHash = tx.GetHash();
|
||||
setTxIndex[txHash] = i++;
|
||||
@@ -466,7 +466,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
|
||||
entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
|
||||
|
||||
Array deps;
|
||||
BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
|
||||
for (MapPrevTx::value_type& inp : mapInputs)
|
||||
{
|
||||
if (setTxIndex.count(inp.first))
|
||||
deps.push_back(setTxIndex[inp.first]);
|
||||
|
||||
+3
-3
@@ -51,7 +51,7 @@ static void CopyNodeStats(std::vector<CNodeStats>& vstats)
|
||||
|
||||
LOCK(cs_vNodes);
|
||||
vstats.reserve(vNodes.size());
|
||||
BOOST_FOREACH(CNode* pnode, vNodes) {
|
||||
for (CNode* pnode : vNodes) {
|
||||
CNodeStats stats;
|
||||
pnode->copyStats(stats);
|
||||
vstats.push_back(stats);
|
||||
@@ -70,7 +70,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
|
||||
|
||||
Array ret;
|
||||
|
||||
BOOST_FOREACH(const CNodeStats& stats, vstats) {
|
||||
for (const CNodeStats& stats : vstats) {
|
||||
Object obj;
|
||||
|
||||
obj.push_back(Pair("addr", stats.addrName));
|
||||
@@ -140,7 +140,7 @@ Value sendalert(const Array& params, bool fHelp)
|
||||
// Relay alert
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
alert.RelayTo(pnode);
|
||||
}
|
||||
|
||||
|
||||
+18
-22
@@ -3,8 +3,6 @@
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/assign/list_of.hpp>
|
||||
|
||||
#include "base58.h"
|
||||
#include "trianglesrpc.h"
|
||||
#include "txdb.h"
|
||||
@@ -15,7 +13,6 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
using namespace boost::assign;
|
||||
using namespace json_spirit;
|
||||
|
||||
void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
|
||||
@@ -39,7 +36,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH
|
||||
out.push_back(Pair("type", GetTxnOutputType(type)));
|
||||
|
||||
Array a;
|
||||
BOOST_FOREACH(const CTxDestination& addr, addresses)
|
||||
for (const CTxDestination& addr : addresses)
|
||||
a.push_back(CTrianglesAddress(addr).ToString());
|
||||
out.push_back(Pair("addresses", a));
|
||||
}
|
||||
@@ -51,7 +48,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
|
||||
entry.push_back(Pair("time", (boost::int64_t)tx.nTime));
|
||||
entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
|
||||
Array vin;
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
for (const CTxIn& txin : tx.vin)
|
||||
{
|
||||
Object in;
|
||||
if (tx.IsCoinBase())
|
||||
@@ -162,7 +159,7 @@ Value listunspent(const Array& params, bool fHelp)
|
||||
if (params.size() > 2)
|
||||
{
|
||||
Array inputs = params[2].get_array();
|
||||
BOOST_FOREACH(Value& input, inputs)
|
||||
for (Value& input : inputs)
|
||||
{
|
||||
CTrianglesAddress address(input.get_str());
|
||||
if (!address.IsValid())
|
||||
@@ -176,7 +173,7 @@ Value listunspent(const Array& params, bool fHelp)
|
||||
Array results;
|
||||
vector<COutput> vecOutputs;
|
||||
pwalletMain->AvailableCoins(vecOutputs, false);
|
||||
BOOST_FOREACH(const COutput& out, vecOutputs)
|
||||
for (const COutput& out : vecOutputs)
|
||||
{
|
||||
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
|
||||
continue;
|
||||
@@ -231,7 +228,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
|
||||
|
||||
CTransaction rawTx;
|
||||
|
||||
BOOST_FOREACH(Value& input, inputs)
|
||||
for (Value& input : inputs)
|
||||
{
|
||||
const Object& o = input.get_obj();
|
||||
|
||||
@@ -254,7 +251,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
|
||||
}
|
||||
|
||||
set<CTrianglesAddress> setAddress;
|
||||
BOOST_FOREACH(const Pair& s, sendTo)
|
||||
for (const Pair& s : sendTo)
|
||||
{
|
||||
CTrianglesAddress address(s.name_);
|
||||
if (!address.IsValid())
|
||||
@@ -382,7 +379,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||
tempTx.FetchInputs(txdb, unused, false, false, mapPrevTx, fInvalid);
|
||||
|
||||
// Copy results into mapPrevOut:
|
||||
BOOST_FOREACH(const CTxIn& txin, tempTx.vin)
|
||||
for (const CTxIn& txin : tempTx.vin)
|
||||
{
|
||||
const uint256& prevHash = txin.prevout.hash;
|
||||
if (mapPrevTx.count(prevHash) && mapPrevTx[prevHash].second.vout.size()>txin.prevout.n)
|
||||
@@ -394,7 +391,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||
if (params.size() > 1 && params[1].type() != null_type)
|
||||
{
|
||||
Array prevTxs = params[1].get_array();
|
||||
BOOST_FOREACH(Value& p, prevTxs)
|
||||
for (Value& p : prevTxs)
|
||||
{
|
||||
if (p.type() != obj_type)
|
||||
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
|
||||
@@ -442,7 +439,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||
{
|
||||
fGivenKeys = true;
|
||||
Array keys = params[2].get_array();
|
||||
BOOST_FOREACH(Value k, keys)
|
||||
for (Value k : keys)
|
||||
{
|
||||
CTrianglesSecret vchSecret;
|
||||
bool fGood = vchSecret.SetString(k.get_str());
|
||||
@@ -463,15 +460,14 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||
int nHashType = SIGHASH_ALL;
|
||||
if (params.size() > 3 && params[3].type() != null_type)
|
||||
{
|
||||
static map<string, int> mapSigHashValues =
|
||||
boost::assign::map_list_of
|
||||
(string("ALL"), int(SIGHASH_ALL))
|
||||
(string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
|
||||
(string("NONE"), int(SIGHASH_NONE))
|
||||
(string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
|
||||
(string("SINGLE"), int(SIGHASH_SINGLE))
|
||||
(string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
|
||||
;
|
||||
static map<string, int> mapSigHashValues = {
|
||||
{"ALL", int(SIGHASH_ALL)},
|
||||
{"ALL|ANYONECANPAY", int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
|
||||
{"NONE", int(SIGHASH_NONE)},
|
||||
{"NONE|ANYONECANPAY", int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
|
||||
{"SINGLE", int(SIGHASH_SINGLE)},
|
||||
{"SINGLE|ANYONECANPAY", int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
|
||||
};
|
||||
string strHashType = params[3].get_str();
|
||||
if (mapSigHashValues.count(strHashType))
|
||||
nHashType = mapSigHashValues[strHashType];
|
||||
@@ -498,7 +494,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
|
||||
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
|
||||
|
||||
// ... and merge in other signatures:
|
||||
BOOST_FOREACH(const CTransaction& txv, txVariants)
|
||||
for (const CTransaction& txv : txVariants)
|
||||
{
|
||||
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
|
||||
}
|
||||
|
||||
+1
-1
@@ -301,7 +301,7 @@ Value smsglocalkeys(const Array& params, bool fHelp)
|
||||
if (mode == "wallet")
|
||||
{
|
||||
uint32_t nKeys = 0;
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& entry, pwalletMain->mapAddressBook)
|
||||
for (const auto& entry : pwalletMain->mapAddressBook)
|
||||
{
|
||||
if (!IsMine(*pwalletMain, entry.first))
|
||||
continue;
|
||||
|
||||
+21
-21
@@ -60,7 +60,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
|
||||
entry.push_back(Pair("txid", wtx.GetHash().GetHex()));
|
||||
entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime()));
|
||||
entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived));
|
||||
BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue)
|
||||
for (const auto& item : wtx.mapValue)
|
||||
entry.push_back(Pair(item.first, item.second));
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ CTrianglesAddress GetAccountAddress(string strAccount, bool bForceNew=false)
|
||||
++it)
|
||||
{
|
||||
const CWalletTx& wtx = (*it).second;
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
if (txout.scriptPubKey == scriptPubKey)
|
||||
bKeyUsed = true;
|
||||
}
|
||||
@@ -309,7 +309,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
|
||||
|
||||
// Find all addresses that have the given account
|
||||
Array ret;
|
||||
BOOST_FOREACH(const PAIRTYPE(CTrianglesAddress, string)& item, pwalletMain->mapAddressBook)
|
||||
for (const auto& item : pwalletMain->mapAddressBook)
|
||||
{
|
||||
const CTrianglesAddress& address = item.first;
|
||||
const string& strName = item.second;
|
||||
@@ -366,10 +366,10 @@ Value listaddressgroupings(const Array& params, bool fHelp)
|
||||
|
||||
Array jsonGroupings;
|
||||
map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances();
|
||||
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
|
||||
for (set<CTxDestination> grouping : pwalletMain->GetAddressGroupings())
|
||||
{
|
||||
Array jsonGrouping;
|
||||
BOOST_FOREACH(CTxDestination address, grouping)
|
||||
for (CTxDestination address : grouping)
|
||||
{
|
||||
Array addressInfo;
|
||||
addressInfo.push_back(CTrianglesAddress(address).ToString());
|
||||
@@ -487,7 +487,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
|
||||
if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
|
||||
continue;
|
||||
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
if (txout.scriptPubKey == scriptPubKey)
|
||||
if (wtx.GetDepthInMainChain() >= nMinDepth)
|
||||
nAmount += txout.nValue;
|
||||
@@ -499,7 +499,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
|
||||
|
||||
void GetAccountAddresses(string strAccount, set<CTxDestination>& setAddress)
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& item, pwalletMain->mapAddressBook)
|
||||
for (const auto& item : pwalletMain->mapAddressBook)
|
||||
{
|
||||
const CTxDestination& address = item.first;
|
||||
const string& strName = item.second;
|
||||
@@ -535,7 +535,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
|
||||
if (wtx.IsCoinBase() || wtx.IsCoinStake() || !wtx.IsFinal())
|
||||
continue;
|
||||
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
{
|
||||
CTxDestination address;
|
||||
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*pwalletMain, address) && setAddress.count(address))
|
||||
@@ -613,10 +613,10 @@ Value getbalance(const Array& params, bool fHelp)
|
||||
wtx.GetAmounts(listReceived, listSent, allFee, strSentAccount);
|
||||
if (wtx.GetDepthInMainChain() >= nMinDepth && wtx.GetBlocksToMaturity() == 0)
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listReceived)
|
||||
for (const auto& r : listReceived)
|
||||
nBalance += r.second;
|
||||
}
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination,int64_t)& r, listSent)
|
||||
for (const auto& r : listSent)
|
||||
nBalance -= r.second;
|
||||
nBalance -= allFee;
|
||||
}
|
||||
@@ -754,7 +754,7 @@ Value sendmany(const Array& params, bool fHelp)
|
||||
vector<pair<CScript, int64_t> > vecSend;
|
||||
|
||||
int64_t totalAmount = 0;
|
||||
BOOST_FOREACH(const Pair& s, sendTo)
|
||||
for (const Pair& s : sendTo)
|
||||
{
|
||||
CTrianglesAddress address(s.name_);
|
||||
if (!address.IsValid())
|
||||
@@ -925,7 +925,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
||||
if (nDepth < nMinDepth)
|
||||
continue;
|
||||
|
||||
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
|
||||
for (const CTxOut& txout : wtx.vout)
|
||||
{
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(txout.scriptPubKey, address) || !IsMine(*pwalletMain, address))
|
||||
@@ -940,7 +940,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
|
||||
// Reply
|
||||
Array ret;
|
||||
map<string, tallyitem> mapAccountTally;
|
||||
BOOST_FOREACH(const PAIRTYPE(CTrianglesAddress, string)& item, pwalletMain->mapAddressBook)
|
||||
for (const auto& item : pwalletMain->mapAddressBook)
|
||||
{
|
||||
const CTrianglesAddress& address = item.first;
|
||||
const string& strAccount = item.second;
|
||||
@@ -1044,7 +1044,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
|
||||
// Sent
|
||||
if ((!wtx.IsCoinStake()) && (!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
|
||||
for (const auto& s : listSent)
|
||||
{
|
||||
Object entry;
|
||||
entry.push_back(Pair("account", strSentAccount));
|
||||
@@ -1062,7 +1062,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
|
||||
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
|
||||
{
|
||||
bool stop = false;
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
|
||||
for (const auto& r : listReceived)
|
||||
{
|
||||
string account;
|
||||
if (pwalletMain->mapAddressBook.count(r.first))
|
||||
@@ -1191,7 +1191,7 @@ Value listaccounts(const Array& params, bool fHelp)
|
||||
nMinDepth = params[0].get_int();
|
||||
|
||||
map<string, int64_t> mapAccountBalances;
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) {
|
||||
for (const auto& entry : pwalletMain->mapAddressBook) {
|
||||
if (IsMine(*pwalletMain, entry.first)) // This address belongs to me
|
||||
mapAccountBalances[entry.second] = 0;
|
||||
}
|
||||
@@ -1208,11 +1208,11 @@ Value listaccounts(const Array& params, bool fHelp)
|
||||
continue;
|
||||
wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount);
|
||||
mapAccountBalances[strSentAccount] -= nFee;
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& s, listSent)
|
||||
for (const auto& s : listSent)
|
||||
mapAccountBalances[strSentAccount] -= s.second;
|
||||
if (nDepth >= nMinDepth && wtx.GetBlocksToMaturity() == 0)
|
||||
{
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64_t)& r, listReceived)
|
||||
for (const auto& r : listReceived)
|
||||
if (pwalletMain->mapAddressBook.count(r.first))
|
||||
mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
|
||||
else
|
||||
@@ -1222,11 +1222,11 @@ Value listaccounts(const Array& params, bool fHelp)
|
||||
|
||||
list<CAccountingEntry> acentries;
|
||||
CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
|
||||
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
|
||||
for (const CAccountingEntry& entry : acentries)
|
||||
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
|
||||
|
||||
Object ret;
|
||||
BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) {
|
||||
for (const auto& accountBalance : mapAccountBalances) {
|
||||
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
|
||||
}
|
||||
return ret;
|
||||
@@ -1614,7 +1614,7 @@ public:
|
||||
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
|
||||
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
|
||||
Array a;
|
||||
BOOST_FOREACH(const CTxDestination& addr, addresses)
|
||||
for (const CTxDestination& addr : addresses)
|
||||
a.push_back(CTrianglesAddress(addr).ToString());
|
||||
obj.push_back(Pair("addresses", a));
|
||||
if (whichType == TX_MULTISIG)
|
||||
|
||||
+8
-9
@@ -3,7 +3,6 @@
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/tuple/tuple_comparison.hpp>
|
||||
|
||||
@@ -1331,7 +1330,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||
|
||||
// Scan templates
|
||||
const CScript& script1 = scriptPubKey;
|
||||
BOOST_FOREACH(const PAIRTYPE(txnouttype, CScript)& tplate, mTemplates)
|
||||
for (const auto& tplate : mTemplates)
|
||||
{
|
||||
const CScript& script2 = tplate.second;
|
||||
vSolutionsRet.clear();
|
||||
@@ -1533,7 +1532,7 @@ bool IsStandard(const CScript& scriptPubKey)
|
||||
unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
|
||||
{
|
||||
unsigned int nResult = 0;
|
||||
BOOST_FOREACH(const valtype& pubkey, pubkeys)
|
||||
for (const valtype& pubkey : pubkeys)
|
||||
{
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (keystore.HaveKey(keyID))
|
||||
@@ -1637,7 +1636,7 @@ public:
|
||||
std::vector<CTxDestination> vDest;
|
||||
int nRequired;
|
||||
if (ExtractDestinations(script, type, vDest, nRequired)) {
|
||||
BOOST_FOREACH(const CTxDestination &dest, vDest)
|
||||
for (const CTxDestination &dest : vDest)
|
||||
boost::apply_visitor(*this, dest);
|
||||
}
|
||||
}
|
||||
@@ -1792,7 +1791,7 @@ bool VerifySignature(const CTransaction& txFrom, const CTransaction& txTo, unsig
|
||||
static CScript PushAll(const vector<valtype>& values)
|
||||
{
|
||||
CScript result;
|
||||
BOOST_FOREACH(const valtype& v, values)
|
||||
for (const valtype& v : values)
|
||||
result << v;
|
||||
return result;
|
||||
}
|
||||
@@ -1803,12 +1802,12 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u
|
||||
{
|
||||
// Combine all the signatures we've got:
|
||||
set<valtype> allsigs;
|
||||
BOOST_FOREACH(const valtype& v, sigs1)
|
||||
for (const valtype& v : sigs1)
|
||||
{
|
||||
if (!v.empty())
|
||||
allsigs.insert(v);
|
||||
}
|
||||
BOOST_FOREACH(const valtype& v, sigs2)
|
||||
for (const valtype& v : sigs2)
|
||||
{
|
||||
if (!v.empty())
|
||||
allsigs.insert(v);
|
||||
@@ -1819,7 +1818,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CTransaction& txTo, u
|
||||
unsigned int nSigsRequired = vSolutions.front()[0];
|
||||
unsigned int nPubKeys = vSolutions.size()-2;
|
||||
map<valtype, valtype> sigs;
|
||||
BOOST_FOREACH(const valtype& sig, allsigs)
|
||||
for (const valtype& sig : allsigs)
|
||||
{
|
||||
for (unsigned int i = 0; i < nPubKeys; i++)
|
||||
{
|
||||
@@ -2031,7 +2030,7 @@ void CScript::SetMultisig(int nRequired, const std::vector<CKey>& keys)
|
||||
this->clear();
|
||||
|
||||
*this << EncodeOP_N(nRequired);
|
||||
BOOST_FOREACH(const CKey& key, keys)
|
||||
for (const CKey& key : keys)
|
||||
*this << key.GetPubKey();
|
||||
*this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
||||
}
|
||||
|
||||
+1
-2
@@ -11,7 +11,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include "keystore.h"
|
||||
@@ -218,7 +217,7 @@ inline std::string ValueString(const std::vector<unsigned char>& vch)
|
||||
inline std::string StackString(const std::vector<std::vector<unsigned char> >& vStack)
|
||||
{
|
||||
std::string str;
|
||||
BOOST_FOREACH(const std::vector<unsigned char>& vch, vStack)
|
||||
for (const std::vector<unsigned char>& vch : vStack)
|
||||
{
|
||||
if (!str.empty())
|
||||
str += " ";
|
||||
|
||||
+6
-6
@@ -670,7 +670,7 @@ void ThreadSecureMsg(void* parg)
|
||||
printf("Lock on bucket %"PRId64" for peer %u timed out.\n", it->first, nPeerId);
|
||||
// -- look through the nodes for the peer that locked this bucket
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
if (pnode->smsgData.nPeerId != nPeerId)
|
||||
continue;
|
||||
@@ -961,7 +961,7 @@ int SecureMsgAddWalletAddresses()
|
||||
printf("SecureMsgAddWalletAddresses()\n");
|
||||
|
||||
uint32_t nAdded = 0;
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& entry, pwalletMain->mapAddressBook)
|
||||
for (const auto& entry : pwalletMain->mapAddressBook)
|
||||
{
|
||||
if (!IsMine(*pwalletMain, entry.first))
|
||||
continue;
|
||||
@@ -1255,7 +1255,7 @@ bool SecureMsgEnable()
|
||||
// -- ping each peer, don't know which have messaging enabled
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
pnode->PushMessage("smsgPing");
|
||||
pnode->PushMessage("smsgPong"); // Send pong as have missed initial ping sent by peer when it connected
|
||||
@@ -1291,7 +1291,7 @@ bool SecureMsgDisable()
|
||||
// -- tell each smsg enabled peer that this node is disabling
|
||||
{
|
||||
LOCK(cs_vNodes);
|
||||
BOOST_FOREACH(CNode* pnode, vNodes)
|
||||
for (CNode* pnode : vNodes)
|
||||
{
|
||||
if (!pnode->smsgData.fEnabled)
|
||||
continue;
|
||||
@@ -1947,7 +1947,7 @@ static bool ScanBlock(CBlock& block, CTxDB& txdb, SecMsgDB& addrpkdb,
|
||||
uint32_t& nTransactions, uint32_t& nInputs, uint32_t& nPubkeys, uint32_t& nDuplicates)
|
||||
{
|
||||
// -- should have LOCK(cs_smsg) where db is opened
|
||||
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
||||
for (CTransaction& tx : block.vtx)
|
||||
{
|
||||
if (!tx.IsStandard())
|
||||
continue; // leave out coinbase and others
|
||||
@@ -3674,7 +3674,7 @@ int SecureMsgSend(std::string& addressFrom, std::string& addressTo, std::string&
|
||||
std::string addressOutbox = "None";
|
||||
CTrianglesAddress coinAddrOutbox;
|
||||
|
||||
BOOST_FOREACH(const PAIRTYPE(CTxDestination, std::string)& entry, pwalletMain->mapAddressBook)
|
||||
for (const auto& entry : pwalletMain->mapAddressBook)
|
||||
{
|
||||
// -- get first owned address
|
||||
if (!IsMine(*pwalletMain, entry.first))
|
||||
|
||||
+3
-4
@@ -5,7 +5,6 @@
|
||||
#include "sync.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
|
||||
@@ -58,14 +57,14 @@ static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch,
|
||||
{
|
||||
printf("POTENTIAL DEADLOCK DETECTED\n");
|
||||
printf("Previous lock order was:\n");
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2)
|
||||
for (const auto& i : s2)
|
||||
{
|
||||
if (i.first == mismatch.first) printf(" (1)");
|
||||
if (i.first == mismatch.second) printf(" (2)");
|
||||
printf(" %s\n", i.second.ToString().c_str());
|
||||
}
|
||||
printf("Current lock order is:\n");
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1)
|
||||
for (const auto& i : s1)
|
||||
{
|
||||
if (i.first == mismatch.first) printf(" (1)");
|
||||
if (i.first == mismatch.second) printf(" (2)");
|
||||
@@ -84,7 +83,7 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
|
||||
(*lockstack).push_back(std::make_pair(c, locklocation));
|
||||
|
||||
if (!fTry) {
|
||||
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) {
|
||||
for (const auto& i : (*lockstack)) {
|
||||
if (i.first == c) break;
|
||||
|
||||
std::pair<void*, void*> p1 = std::make_pair(i.first, c);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
//
|
||||
// Unit tests for block-chain checkpoints
|
||||
//
|
||||
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "../checkpoints.h"
|
||||
#include "../util.h"
|
||||
|
||||
+8
-11
@@ -3,10 +3,8 @@
|
||||
//
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
@@ -97,22 +95,21 @@ static bool CheckNBits(unsigned int nbits1, int64 time1, unsigned int nbits2, in
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DoS_checknbits)
|
||||
{
|
||||
using namespace boost::assign; // for 'map_list_of()'
|
||||
|
||||
// Timestamps,nBits from the Triangles blockchain.
|
||||
// These are the block-chain checkpoint blocks
|
||||
typedef std::map<int64, unsigned int> BlockData;
|
||||
BlockData chainData =
|
||||
map_list_of(1239852051,486604799)(1262749024,486594666)
|
||||
(1279305360,469854461)(1280200847,469830746)(1281678674,469809688)
|
||||
(1296207707,453179945)(1302624061,453036989)(1309640330,437004818)
|
||||
(1313172719,436789733);
|
||||
BlockData chainData = {
|
||||
{1239852051,486604799},{1262749024,486594666},
|
||||
{1279305360,469854461},{1280200847,469830746},{1281678674,469809688},
|
||||
{1296207707,453179945},{1302624061,453036989},{1309640330,437004818},
|
||||
{1313172719,436789733},
|
||||
};
|
||||
|
||||
// Make sure CheckNBits considers every combination of block-chain-lock-in-points
|
||||
// "sane":
|
||||
BOOST_FOREACH(const BlockData::value_type& i, chainData)
|
||||
for (const BlockData::value_type& i : chainData)
|
||||
{
|
||||
BOOST_FOREACH(const BlockData::value_type& j, chainData)
|
||||
for (const BlockData::value_type& j : chainData)
|
||||
{
|
||||
BOOST_CHECK(CheckNBits(i.second, i.first, j.second, j.first));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "init.h"
|
||||
#include "wallet.h"
|
||||
@@ -16,7 +15,7 @@ GetResults(CWalletDB& walletdb, std::map<int64, CAccountingEntry>& results)
|
||||
results.clear();
|
||||
BOOST_CHECK(walletdb.ReorderTransactions(pwalletMain) == DB_LOAD_OK);
|
||||
walletdb.ListAccountCreditDebit("", aes);
|
||||
BOOST_FOREACH(CAccountingEntry& ae, aes)
|
||||
for (CAccountingEntry& ae : aes)
|
||||
{
|
||||
results[ae.nOrderPos] = ae;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
|
||||
{
|
||||
Array tests = read_json("base58_encode_decode.json");
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
std::string strTest = write_string(tv, false);
|
||||
@@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
|
||||
Array tests = read_json("base58_encode_decode.json");
|
||||
std::vector<unsigned char> result;
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
std::string strTest = write_string(tv, false);
|
||||
@@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
|
||||
// Save global state
|
||||
bool fTestNet_stored = fTestNet;
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
std::string strTest = write_string(tv, false);
|
||||
@@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
|
||||
// Save global state
|
||||
bool fTestNet_stored = fTestNet;
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
std::string strTest = write_string(tv, false);
|
||||
@@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
|
||||
CTrianglesSecret secret;
|
||||
CTrianglesAddress addr;
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
std::string strTest = write_string(tv, false);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include "util.h"
|
||||
@@ -17,7 +16,7 @@ ResetArgs(const std::string& strArg)
|
||||
|
||||
// Convert to char*:
|
||||
std::vector<const char*> vecChar;
|
||||
BOOST_FOREACH(std::string& s, vecArg)
|
||||
for (std::string& s : vecArg)
|
||||
vecChar.push_back(s.c_str());
|
||||
|
||||
ParseParameters(vecChar.size(), &vecChar[0]);
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/assign/list_inserter.hpp>
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <openssl/ec.h>
|
||||
@@ -15,7 +11,6 @@
|
||||
#include "wallet.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::assign;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
@@ -32,7 +27,7 @@ sign_multisig(CScript scriptPubKey, vector<CKey> keys, CTransaction transaction,
|
||||
|
||||
CScript result;
|
||||
result << OP_0; // CHECKMULTISIG bug workaround
|
||||
BOOST_FOREACH(CKey key, keys)
|
||||
for (CKey key : keys)
|
||||
{
|
||||
vector<unsigned char> vchSig;
|
||||
BOOST_CHECK(key.Sign(hash, vchSig));
|
||||
@@ -78,19 +73,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
|
||||
// Test a AND b:
|
||||
keys.clear();
|
||||
keys += key[0],key[1]; // magic operator+= from boost.assign
|
||||
keys.push_back(key[0]); keys.push_back(key[1]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, true, 0));
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keys.clear();
|
||||
keys += key[i];
|
||||
keys.push_back(key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 1: %d", i));
|
||||
|
||||
keys.clear();
|
||||
keys += key[1],key[i];
|
||||
keys.push_back(key[1]); keys.push_back(key[i]);
|
||||
s = sign_multisig(a_and_b, keys, txTo[0], 0);
|
||||
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, true, 0), strprintf("a&b 2: %d", i));
|
||||
}
|
||||
@@ -99,7 +94,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
keys.clear();
|
||||
keys += key[i];
|
||||
keys.push_back(key[i]);
|
||||
s = sign_multisig(a_or_b, keys, txTo[1], 0);
|
||||
if (i == 0 || i == 1)
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, true, 0), strprintf("a|b: %d", i));
|
||||
@@ -118,7 +113,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
keys.clear();
|
||||
keys += key[i],key[j];
|
||||
keys.push_back(key[i]); keys.push_back(key[j]);
|
||||
s = sign_multisig(escrow, keys, txTo[2], 0);
|
||||
if (i < j && i < 3 && j < 3)
|
||||
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, true, 0), strprintf("escrow 1: %d %d", i, j));
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "base58.h"
|
||||
#include "util.h"
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include <boost/assign/list_inserter.hpp>
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "../main.h"
|
||||
#include "../script.h"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "json/json_spirit_reader_template.h"
|
||||
@@ -48,7 +47,7 @@ ParseScript(string s)
|
||||
vector<string> words;
|
||||
split(words, s, is_any_of(" \t\n"), token_compress_on);
|
||||
|
||||
BOOST_FOREACH(string w, words)
|
||||
for (string w : words)
|
||||
{
|
||||
if (all(w, is_digit()) ||
|
||||
(starts_with(w, "-") && all(string(w.begin()+1, w.end()), is_digit())))
|
||||
@@ -128,7 +127,7 @@ BOOST_AUTO_TEST_CASE(script_valid)
|
||||
// scripts.
|
||||
Array tests = read_json("script_valid.json");
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
@@ -152,7 +151,7 @@ BOOST_AUTO_TEST_CASE(script_invalid)
|
||||
// Scripts that should evaluate as invalid
|
||||
Array tests = read_json("script_invalid.json");
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
@@ -211,7 +210,7 @@ sign_multisig(CScript scriptPubKey, std::vector<CKey> keys, CTransaction transac
|
||||
// and vice-versa)
|
||||
//
|
||||
result << OP_0;
|
||||
BOOST_FOREACH(CKey key, keys)
|
||||
for (CKey key : keys)
|
||||
{
|
||||
vector<unsigned char> vchSig;
|
||||
BOOST_CHECK(key.Sign(hash, vchSig));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <vector>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "script.h"
|
||||
#include "key.h"
|
||||
|
||||
@@ -24,7 +24,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
// ... where all scripts are stringified scripts.
|
||||
Array tests = read_json("tx_valid.json");
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
@@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
||||
map<COutPoint, CScript> mapprevOutScriptPubKeys;
|
||||
Array inputs = test[0].get_array();
|
||||
bool fValid = true;
|
||||
BOOST_FOREACH(Value& input, inputs)
|
||||
for (Value& input : inputs)
|
||||
{
|
||||
if (input.type() != array_type)
|
||||
{
|
||||
@@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
// ... where all scripts are stringified scripts.
|
||||
Array tests = read_json("tx_invalid.json");
|
||||
|
||||
BOOST_FOREACH(Value& tv, tests)
|
||||
for (Value& tv : tests)
|
||||
{
|
||||
Array test = tv.get_array();
|
||||
string strTest = write_string(tv, false);
|
||||
@@ -106,7 +106,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
||||
map<COutPoint, CScript> mapprevOutScriptPubKeys;
|
||||
Array inputs = test[0].get_array();
|
||||
bool fValid = true;
|
||||
BOOST_FOREACH(Value& input, inputs)
|
||||
for (Value& input : inputs)
|
||||
{
|
||||
if (input.type() != array_type)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include <vector>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "main.h"
|
||||
#include "wallet.h"
|
||||
|
||||
@@ -42,7 +42,7 @@ static void add_coin(int64 nValue, int nAge = 6*24, bool fIsFromMe = false, int
|
||||
|
||||
static void empty_wallet(void)
|
||||
{
|
||||
BOOST_FOREACH(COutput output, vCoins)
|
||||
for (COutput output : vCoins)
|
||||
delete output.tx;
|
||||
vCoins.clear();
|
||||
}
|
||||
|
||||
-1692
File diff suppressed because it is too large
Load Diff
@@ -1,232 +0,0 @@
|
||||
/* Copyright (c) 2003-2004, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file address.h
|
||||
* \brief Headers for address.h
|
||||
**/
|
||||
|
||||
#ifndef TOR_ADDRESS_H
|
||||
#define TOR_ADDRESS_H
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "torint.h"
|
||||
#include "tor_compat.h"
|
||||
|
||||
/** The number of bits from an address to consider while doing a masked
|
||||
* comparison. */
|
||||
typedef uint8_t maskbits_t;
|
||||
|
||||
struct in_addr;
|
||||
/** Holds an IPv4 or IPv6 address. (Uses less memory than struct
|
||||
* sockaddr_storage.) */
|
||||
typedef struct tor_addr_t
|
||||
{
|
||||
sa_family_t family;
|
||||
union {
|
||||
uint32_t dummy_; /* This field is here so we have something to initialize
|
||||
* with a reliable cross-platform type. */
|
||||
struct in_addr in_addr;
|
||||
struct in6_addr in6_addr;
|
||||
} addr;
|
||||
} tor_addr_t;
|
||||
|
||||
/** Holds an IP address and a TCP/UDP port. */
|
||||
typedef struct tor_addr_port_t
|
||||
{
|
||||
tor_addr_t addr;
|
||||
uint16_t port;
|
||||
} tor_addr_port_t;
|
||||
|
||||
#define TOR_ADDR_NULL {AF_UNSPEC, {0}}
|
||||
|
||||
static INLINE const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a);
|
||||
static INLINE uint32_t tor_addr_to_ipv4n(const tor_addr_t *a);
|
||||
static INLINE uint32_t tor_addr_to_ipv4h(const tor_addr_t *a);
|
||||
static INLINE uint32_t tor_addr_to_mapped_ipv4h(const tor_addr_t *a);
|
||||
static INLINE sa_family_t tor_addr_family(const tor_addr_t *a);
|
||||
static INLINE const struct in_addr *tor_addr_to_in(const tor_addr_t *a);
|
||||
static INLINE int tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u);
|
||||
|
||||
socklen_t tor_addr_to_sockaddr(const tor_addr_t *a, uint16_t port,
|
||||
struct sockaddr *sa_out, socklen_t len);
|
||||
int tor_addr_from_sockaddr(tor_addr_t *a, const struct sockaddr *sa,
|
||||
uint16_t *port_out);
|
||||
void tor_addr_make_unspec(tor_addr_t *a);
|
||||
void tor_addr_make_null(tor_addr_t *a, sa_family_t family);
|
||||
char *tor_sockaddr_to_str(const struct sockaddr *sa);
|
||||
|
||||
/** Return an in6_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
|
||||
* an IPv6 address. */
|
||||
static INLINE const struct in6_addr *
|
||||
tor_addr_to_in6(const tor_addr_t *a)
|
||||
{
|
||||
return a->family == AF_INET6 ? &a->addr.in6_addr : NULL;
|
||||
}
|
||||
|
||||
/** Given an IPv6 address <b>x</b>, yield it as an array of uint8_t.
|
||||
*
|
||||
* Requires that <b>x</b> is actually an IPv6 address.
|
||||
*/
|
||||
#define tor_addr_to_in6_addr8(x) tor_addr_to_in6(x)->s6_addr
|
||||
/** Given an IPv6 address <b>x</b>, yield it as an array of uint16_t.
|
||||
*
|
||||
* Requires that <b>x</b> is actually an IPv6 address.
|
||||
*/
|
||||
#define tor_addr_to_in6_addr16(x) S6_ADDR16(*tor_addr_to_in6(x))
|
||||
/** Given an IPv6 address <b>x</b>, yield it as an array of uint32_t.
|
||||
*
|
||||
* Requires that <b>x</b> is actually an IPv6 address.
|
||||
*/
|
||||
#define tor_addr_to_in6_addr32(x) S6_ADDR32(*tor_addr_to_in6(x))
|
||||
|
||||
/** Return an IPv4 address in network order for <b>a</b>, or 0 if
|
||||
* <b>a</b> is not an IPv4 address. */
|
||||
static INLINE uint32_t
|
||||
tor_addr_to_ipv4n(const tor_addr_t *a)
|
||||
{
|
||||
return a->family == AF_INET ? a->addr.in_addr.s_addr : 0;
|
||||
}
|
||||
/** Return an IPv4 address in host order for <b>a</b>, or 0 if
|
||||
* <b>a</b> is not an IPv4 address. */
|
||||
static INLINE uint32_t
|
||||
tor_addr_to_ipv4h(const tor_addr_t *a)
|
||||
{
|
||||
return ntohl(tor_addr_to_ipv4n(a));
|
||||
}
|
||||
/** Given an IPv6 address, return its mapped IPv4 address in host order, or
|
||||
* 0 if <b>a</b> is not an IPv6 address.
|
||||
*
|
||||
* (Does not check whether the address is really a mapped address */
|
||||
static INLINE uint32_t
|
||||
tor_addr_to_mapped_ipv4h(const tor_addr_t *a)
|
||||
{
|
||||
return a->family == AF_INET6 ? ntohl(tor_addr_to_in6_addr32(a)[3]) : 0;
|
||||
}
|
||||
/** Return the address family of <b>a</b>. Possible values are:
|
||||
* AF_INET6, AF_INET, AF_UNSPEC. */
|
||||
static INLINE sa_family_t
|
||||
tor_addr_family(const tor_addr_t *a)
|
||||
{
|
||||
return a->family;
|
||||
}
|
||||
/** Return an in_addr* equivalent to <b>a</b>, or NULL if <b>a</b> is not
|
||||
* an IPv4 address. */
|
||||
static INLINE const struct in_addr *
|
||||
tor_addr_to_in(const tor_addr_t *a)
|
||||
{
|
||||
return a->family == AF_INET ? &a->addr.in_addr : NULL;
|
||||
}
|
||||
/** Return true iff <b>a</b> is an IPv4 address equal to the host-ordered
|
||||
* address in <b>u</b>. */
|
||||
static INLINE int
|
||||
tor_addr_eq_ipv4h(const tor_addr_t *a, uint32_t u)
|
||||
{
|
||||
return a->family == AF_INET ? (tor_addr_to_ipv4h(a) == u) : 0;
|
||||
}
|
||||
|
||||
/** Length of a buffer that you need to allocate to be sure you can encode
|
||||
* any tor_addr_t.
|
||||
*
|
||||
* This allows enough space for
|
||||
* "[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]",
|
||||
* plus a terminating NUL.
|
||||
*/
|
||||
#define TOR_ADDR_BUF_LEN 48
|
||||
|
||||
int tor_addr_lookup(const char *name, uint16_t family, tor_addr_t *addr_out);
|
||||
char *tor_dup_addr(const tor_addr_t *addr) ATTR_MALLOC;
|
||||
|
||||
/** Wrapper function of fmt_addr_impl(). It does not decorate IPv6
|
||||
* addresses. */
|
||||
#define fmt_addr(a) fmt_addr_impl((a), 0)
|
||||
/** Wrapper function of fmt_addr_impl(). It decorates IPv6
|
||||
* addresses. */
|
||||
#define fmt_and_decorate_addr(a) fmt_addr_impl((a), 1)
|
||||
const char *fmt_addr_impl(const tor_addr_t *addr, int decorate);
|
||||
const char *fmt_addrport(const tor_addr_t *addr, uint16_t port);
|
||||
const char * fmt_addr32(uint32_t addr);
|
||||
int get_interface_address6(int severity, sa_family_t family, tor_addr_t *addr);
|
||||
|
||||
/** Flag to specify how to do a comparison between addresses. In an "exact"
|
||||
* comparison, addresses are equivalent only if they are in the same family
|
||||
* with the same value. In a "semantic" comparison, IPv4 addresses match all
|
||||
* IPv6 encodings of those addresses. */
|
||||
typedef enum {
|
||||
CMP_EXACT,
|
||||
CMP_SEMANTIC,
|
||||
} tor_addr_comparison_t;
|
||||
|
||||
int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2,
|
||||
tor_addr_comparison_t how);
|
||||
int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
|
||||
maskbits_t mask, tor_addr_comparison_t how);
|
||||
/** Return true iff a and b are the same address. The comparison is done
|
||||
* "exactly". */
|
||||
#define tor_addr_eq(a,b) (0==tor_addr_compare((a),(b),CMP_EXACT))
|
||||
|
||||
unsigned int tor_addr_hash(const tor_addr_t *addr);
|
||||
int tor_addr_is_v4(const tor_addr_t *addr);
|
||||
int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
|
||||
const char *filename, int lineno);
|
||||
#define tor_addr_is_internal(addr, for_listening) \
|
||||
tor_addr_is_internal_((addr), (for_listening), SHORT_FILE__, __LINE__)
|
||||
|
||||
/** Longest length that can be required for a reverse lookup name. */
|
||||
/* 32 nybbles, 32 dots, 8 characters of "ip6.arpa", 1 NUL: 73 characters. */
|
||||
#define REVERSE_LOOKUP_NAME_BUF_LEN 73
|
||||
int tor_addr_to_PTR_name(char *out, size_t outlen,
|
||||
const tor_addr_t *addr);
|
||||
int tor_addr_parse_PTR_name(tor_addr_t *result, const char *address,
|
||||
int family, int accept_regular);
|
||||
|
||||
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out,
|
||||
uint16_t *port_out);
|
||||
#define TAPMP_EXTENDED_STAR 1
|
||||
int tor_addr_parse_mask_ports(const char *s, unsigned flags,
|
||||
tor_addr_t *addr_out, maskbits_t *mask_out,
|
||||
uint16_t *port_min_out, uint16_t *port_max_out);
|
||||
const char * tor_addr_to_str(char *dest, const tor_addr_t *addr, size_t len,
|
||||
int decorate);
|
||||
int tor_addr_parse(tor_addr_t *addr, const char *src);
|
||||
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src);
|
||||
void tor_addr_from_ipv4n(tor_addr_t *dest, uint32_t v4addr);
|
||||
/** Set <b>dest</b> to the IPv4 address encoded in <b>v4addr</b> in host
|
||||
* order. */
|
||||
#define tor_addr_from_ipv4h(dest, v4addr) \
|
||||
tor_addr_from_ipv4n((dest), htonl(v4addr))
|
||||
void tor_addr_from_ipv6_bytes(tor_addr_t *dest, const char *bytes);
|
||||
/** Set <b>dest</b> to the IPv4 address incoded in <b>in</b>. */
|
||||
#define tor_addr_from_in(dest, in) \
|
||||
tor_addr_from_ipv4n((dest), (in)->s_addr);
|
||||
void tor_addr_from_in6(tor_addr_t *dest, const struct in6_addr *in6);
|
||||
int tor_addr_is_null(const tor_addr_t *addr);
|
||||
int tor_addr_is_loopback(const tor_addr_t *addr);
|
||||
|
||||
int tor_addr_port_split(int severity, const char *addrport,
|
||||
char **address_out, uint16_t *port_out);
|
||||
|
||||
int tor_addr_port_parse(int severity, const char *addrport,
|
||||
tor_addr_t *address_out, uint16_t *port_out);
|
||||
|
||||
int tor_addr_hostname_is_local(const char *name);
|
||||
|
||||
/* IPv4 helpers */
|
||||
int is_internal_IP(uint32_t ip, int for_listening);
|
||||
int addr_port_lookup(int severity, const char *addrport, char **address,
|
||||
uint32_t *addr, uint16_t *port_out);
|
||||
int parse_port_range(const char *port, uint16_t *port_min_out,
|
||||
uint16_t *port_max_out);
|
||||
int addr_mask_get_bits(uint32_t mask);
|
||||
/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/
|
||||
#define INET_NTOA_BUF_LEN 16
|
||||
int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len);
|
||||
char *tor_dup_ip(uint32_t addr) ATTR_MALLOC;
|
||||
int get_interface_address(int severity, uint32_t *addr);
|
||||
|
||||
tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,62 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_ADDRESSMAP_H
|
||||
#define TOR_ADDRESSMAP_H
|
||||
|
||||
#include "testsupport.h"
|
||||
|
||||
void addressmap_init(void);
|
||||
void addressmap_clear_excluded_trackexithosts(const or_options_t *options);
|
||||
void addressmap_clear_invalid_automaps(const or_options_t *options);
|
||||
void addressmap_clean(time_t now);
|
||||
void addressmap_clear_configured(void);
|
||||
void addressmap_clear_transient(void);
|
||||
void addressmap_free_all(void);
|
||||
#define AMR_FLAG_USE_IPV4_DNS (1u<<0)
|
||||
#define AMR_FLAG_USE_IPV6_DNS (1u<<1)
|
||||
int addressmap_rewrite(char *address, size_t maxlen, unsigned flags,
|
||||
time_t *expires_out,
|
||||
addressmap_entry_source_t *exit_source_out);
|
||||
int addressmap_rewrite_reverse(char *address, size_t maxlen, unsigned flags,
|
||||
time_t *expires_out);
|
||||
int addressmap_have_mapping(const char *address, int update_timeout);
|
||||
|
||||
void addressmap_register(const char *address, char *new_address,
|
||||
time_t expires, addressmap_entry_source_t source,
|
||||
const int address_wildcard,
|
||||
const int new_address_wildcard);
|
||||
int parse_virtual_addr_network(const char *val,
|
||||
sa_family_t family, int validate_only,
|
||||
char **msg);
|
||||
int client_dns_incr_failures(const char *address);
|
||||
void client_dns_clear_failures(const char *address);
|
||||
void client_dns_set_addressmap(entry_connection_t *for_conn,
|
||||
const char *address, const tor_addr_t *val,
|
||||
const char *exitname, int ttl);
|
||||
const char *addressmap_register_virtual_address(int type, char *new_address);
|
||||
void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
|
||||
time_t max_expires, int want_expiry);
|
||||
int address_is_in_virtual_range(const char *addr);
|
||||
void clear_trackexithost_mappings(const char *exitname);
|
||||
void client_dns_set_reverse_addressmap(entry_connection_t *for_conn,
|
||||
const char *address, const char *v,
|
||||
const char *exitname, int ttl);
|
||||
int addressmap_address_should_automap(const char *address,
|
||||
const or_options_t *options);
|
||||
|
||||
#ifdef ADDRESSMAP_PRIVATE
|
||||
typedef struct virtual_addr_conf_t {
|
||||
tor_addr_t addr;
|
||||
maskbits_t bits;
|
||||
} virtual_addr_conf_t;
|
||||
|
||||
STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf,
|
||||
tor_addr_t *addr_out);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
-523
@@ -1,523 +0,0 @@
|
||||
/* Copyright (c) 2001, Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file aes.c
|
||||
* \brief Implements a counter-mode stream cipher on top of AES.
|
||||
**/
|
||||
|
||||
#include "orconfig.h"
|
||||
|
||||
#ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1300)
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/engine.h>
|
||||
#include "crypto.h"
|
||||
#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,0)
|
||||
/* See comments about which counter mode implementation to use below. */
|
||||
#include <openssl/modes.h>
|
||||
#define CAN_USE_OPENSSL_CTR
|
||||
#endif
|
||||
#include "tor_compat.h"
|
||||
#include "aes.h"
|
||||
#include "tor_util.h"
|
||||
#include "torlog.h"
|
||||
#include "di_ops.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
/* Android's OpenSSL seems to have removed all of its Engine support. */
|
||||
#define DISABLE_ENGINES
|
||||
#endif
|
||||
|
||||
/* We have five strategies for implementing AES counter mode.
|
||||
*
|
||||
* Best with x86 and x86_64: Use EVP_aes_ctr128() and EVP_EncryptUpdate().
|
||||
* This is possible with OpenSSL 1.0.1, where the counter-mode implementation
|
||||
* can use bit-sliced or vectorized AES or AESNI as appropriate.
|
||||
*
|
||||
* Otherwise: Pick the best possible AES block implementation that OpenSSL
|
||||
* gives us, and the best possible counter-mode implementation, and combine
|
||||
* them.
|
||||
*/
|
||||
#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_NOPATCH(1,0,1) && \
|
||||
(defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
|
||||
defined(__x86_64) || defined(__x86_64__) || \
|
||||
defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__)) \
|
||||
|
||||
#define USE_EVP_AES_CTR
|
||||
|
||||
#endif
|
||||
|
||||
/* We have 2 strategies for getting the AES block cipher: Via OpenSSL's
|
||||
* AES_encrypt function, or via OpenSSL's EVP_EncryptUpdate function.
|
||||
*
|
||||
* If there's any hardware acceleration in play, we want to be using EVP_* so
|
||||
* we can get it. Otherwise, we'll want AES_*, which seems to be about 5%
|
||||
* faster than indirecting through the EVP layer.
|
||||
*/
|
||||
|
||||
/* We have 2 strategies for getting a plug-in counter mode: use our own, or
|
||||
* use OpenSSL's.
|
||||
*
|
||||
* Here we have a counter mode that's faster than the one shipping with
|
||||
* OpenSSL pre-1.0 (by about 10%!). But OpenSSL 1.0.0 added a counter mode
|
||||
* implementation faster than the one here (by about 7%). So we pick which
|
||||
* one to used based on the Openssl version above. (OpenSSL 1.0.0a fixed a
|
||||
* critical bug in that counter mode implementation, so we need to test to
|
||||
* make sure that we have a fixed version.)
|
||||
*/
|
||||
|
||||
#ifdef USE_EVP_AES_CTR
|
||||
|
||||
struct aes_cnt_cipher {
|
||||
EVP_CIPHER_CTX *evp;
|
||||
};
|
||||
|
||||
aes_cnt_cipher_t *
|
||||
aes_new_cipher(const char *key, const char *iv)
|
||||
{
|
||||
aes_cnt_cipher_t *cipher;
|
||||
cipher = tor_malloc_zero(sizeof(aes_cnt_cipher_t));
|
||||
cipher->evp = EVP_CIPHER_CTX_new();
|
||||
EVP_EncryptInit(cipher->evp, EVP_aes_128_ctr(),
|
||||
(const unsigned char*)key, (const unsigned char *)iv);
|
||||
return cipher;
|
||||
}
|
||||
void
|
||||
aes_cipher_free(aes_cnt_cipher_t *cipher)
|
||||
{
|
||||
if (!cipher)
|
||||
return;
|
||||
EVP_CIPHER_CTX_free(cipher->evp);
|
||||
memwipe(cipher, 0, sizeof(aes_cnt_cipher_t));
|
||||
tor_free(cipher);
|
||||
}
|
||||
void
|
||||
aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
|
||||
char *output)
|
||||
{
|
||||
int outl;
|
||||
|
||||
tor_assert(len < INT_MAX);
|
||||
|
||||
EVP_EncryptUpdate(cipher->evp, (unsigned char*)output,
|
||||
&outl, (const unsigned char *)input, (int)len);
|
||||
}
|
||||
void
|
||||
aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
|
||||
{
|
||||
int outl;
|
||||
|
||||
tor_assert(len < INT_MAX);
|
||||
|
||||
EVP_EncryptUpdate(cipher->evp, (unsigned char*)data,
|
||||
&outl, (unsigned char*)data, (int)len);
|
||||
}
|
||||
int
|
||||
evaluate_evp_for_aes(int force_val)
|
||||
{
|
||||
(void) force_val;
|
||||
log_info(LD_CRYPTO, "This version of OpenSSL has a known-good EVP "
|
||||
"counter-mode implementation. Using it.");
|
||||
return 0;
|
||||
}
|
||||
int
|
||||
evaluate_ctr_for_aes(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
/*======================================================================*/
|
||||
/* Interface to AES code, and counter implementation */
|
||||
|
||||
/** Implements an AES counter-mode cipher. */
|
||||
struct aes_cnt_cipher {
|
||||
/** This next element (however it's defined) is the AES key. */
|
||||
union {
|
||||
EVP_CIPHER_CTX evp;
|
||||
AES_KEY aes;
|
||||
} key;
|
||||
|
||||
#if !defined(WORDS_BIGENDIAN)
|
||||
#define USING_COUNTER_VARS
|
||||
/** These four values, together, implement a 128-bit counter, with
|
||||
* counter0 as the low-order word and counter3 as the high-order word. */
|
||||
uint32_t counter3;
|
||||
uint32_t counter2;
|
||||
uint32_t counter1;
|
||||
uint32_t counter0;
|
||||
#endif
|
||||
|
||||
union {
|
||||
/** The counter, in big-endian order, as bytes. */
|
||||
uint8_t buf[16];
|
||||
/** The counter, in big-endian order, as big-endian words. Note that
|
||||
* on big-endian platforms, this is redundant with counter3...0,
|
||||
* so we just use these values instead. */
|
||||
uint32_t buf32[4];
|
||||
} ctr_buf;
|
||||
|
||||
/** The encrypted value of ctr_buf. */
|
||||
uint8_t buf[16];
|
||||
/** Our current stream position within buf. */
|
||||
unsigned int pos;
|
||||
|
||||
/** True iff we're using the evp implementation of this cipher. */
|
||||
uint8_t using_evp;
|
||||
};
|
||||
|
||||
/** True iff we should prefer the EVP implementation for AES, either because
|
||||
* we're testing it or because we have hardware acceleration configured */
|
||||
static int should_use_EVP = 0;
|
||||
|
||||
#ifdef CAN_USE_OPENSSL_CTR
|
||||
/** True iff we have tested the counter-mode implementation and found that it
|
||||
* doesn't have the counter-mode bug from OpenSSL 1.0.0. */
|
||||
static int should_use_openssl_CTR = 0;
|
||||
#endif
|
||||
|
||||
/** Check whether we should use the EVP interface for AES. If <b>force_val</b>
|
||||
* is nonnegative, we use use EVP iff it is true. Otherwise, we use EVP
|
||||
* if there is an engine enabled for aes-ecb. */
|
||||
int
|
||||
evaluate_evp_for_aes(int force_val)
|
||||
{
|
||||
ENGINE *e;
|
||||
|
||||
if (force_val >= 0) {
|
||||
should_use_EVP = force_val;
|
||||
return 0;
|
||||
}
|
||||
#ifdef DISABLE_ENGINES
|
||||
should_use_EVP = 0;
|
||||
#else
|
||||
e = ENGINE_get_cipher_engine(NID_aes_128_ecb);
|
||||
|
||||
if (e) {
|
||||
log_info(LD_CRYPTO, "AES engine \"%s\" found; using EVP_* functions.",
|
||||
ENGINE_get_name(e));
|
||||
should_use_EVP = 1;
|
||||
} else {
|
||||
log_info(LD_CRYPTO, "No AES engine found; using AES_* functions.");
|
||||
should_use_EVP = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Test the OpenSSL counter mode implementation to see whether it has the
|
||||
* counter-mode bug from OpenSSL 1.0.0. If the implementation works, then
|
||||
* we will use it for future encryption/decryption operations.
|
||||
*
|
||||
* We can't just look at the OpenSSL version, since some distributions update
|
||||
* their OpenSSL packages without changing the version number.
|
||||
**/
|
||||
int
|
||||
evaluate_ctr_for_aes(void)
|
||||
{
|
||||
#ifdef CAN_USE_OPENSSL_CTR
|
||||
/* Result of encrypting an all-zero block with an all-zero 128-bit AES key.
|
||||
* This should be the same as encrypting an all-zero block with an all-zero
|
||||
* 128-bit AES key in counter mode, starting at position 0 of the stream.
|
||||
*/
|
||||
static const unsigned char encrypt_zero[] =
|
||||
"\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e";
|
||||
unsigned char zero[16];
|
||||
unsigned char output[16];
|
||||
unsigned char ivec[16];
|
||||
unsigned char ivec_tmp[16];
|
||||
unsigned int pos, i;
|
||||
AES_KEY key;
|
||||
memset(zero, 0, sizeof(zero));
|
||||
memset(ivec, 0, sizeof(ivec));
|
||||
AES_set_encrypt_key(zero, 128, &key);
|
||||
|
||||
pos = 0;
|
||||
/* Encrypting a block one byte at a time should make the error manifest
|
||||
* itself for known bogus openssl versions. */
|
||||
for (i=0; i<16; ++i)
|
||||
AES_ctr128_encrypt(&zero[i], &output[i], 1, &key, ivec, ivec_tmp, &pos);
|
||||
|
||||
if (fast_memneq(output, encrypt_zero, 16)) {
|
||||
/* Counter mode is buggy */
|
||||
log_notice(LD_CRYPTO, "This OpenSSL has a buggy version of counter mode; "
|
||||
"not using it.");
|
||||
} else {
|
||||
/* Counter mode is okay */
|
||||
log_info(LD_CRYPTO, "This OpenSSL has a good implementation of counter "
|
||||
"mode; using it.");
|
||||
should_use_openssl_CTR = 1;
|
||||
}
|
||||
#else
|
||||
log_info(LD_CRYPTO, "This version of OpenSSL has a slow implementation of "
|
||||
"counter mode; not using it.");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(USING_COUNTER_VARS)
|
||||
#define COUNTER(c, n) ((c)->ctr_buf.buf32[3-(n)])
|
||||
#else
|
||||
#define COUNTER(c, n) ((c)->counter ## n)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper function: set <b>cipher</b>'s internal buffer to the encrypted
|
||||
* value of the current counter.
|
||||
*/
|
||||
static INLINE void
|
||||
aes_fill_buf_(aes_cnt_cipher_t *cipher)
|
||||
{
|
||||
/* We don't currently use OpenSSL's counter mode implementation because:
|
||||
* 1) some versions have known bugs
|
||||
* 2) its attitude towards IVs is not our own
|
||||
* 3) changing the counter position was not trivial, last time I looked.
|
||||
* None of these issues are insurmountable in principle.
|
||||
*/
|
||||
|
||||
if (cipher->using_evp) {
|
||||
int outl=16, inl=16;
|
||||
EVP_EncryptUpdate(&cipher->key.evp, cipher->buf, &outl,
|
||||
cipher->ctr_buf.buf, inl);
|
||||
} else {
|
||||
AES_encrypt(cipher->ctr_buf.buf, cipher->buf, &cipher->key.aes);
|
||||
}
|
||||
}
|
||||
|
||||
static void aes_set_key(aes_cnt_cipher_t *cipher, const char *key,
|
||||
int key_bits);
|
||||
static void aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv);
|
||||
|
||||
/**
|
||||
* Return a newly allocated counter-mode AES128 cipher implementation,
|
||||
* using the 128-bit key <b>key</b> and the 128-bit IV <b>iv</b>.
|
||||
*/
|
||||
aes_cnt_cipher_t*
|
||||
aes_new_cipher(const char *key, const char *iv)
|
||||
{
|
||||
aes_cnt_cipher_t* result = tor_malloc_zero(sizeof(aes_cnt_cipher_t));
|
||||
|
||||
aes_set_key(result, key, 128);
|
||||
aes_set_iv(result, iv);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Set the key of <b>cipher</b> to <b>key</b>, which is
|
||||
* <b>key_bits</b> bits long (must be 128, 192, or 256). Also resets
|
||||
* the counter to 0.
|
||||
*/
|
||||
static void
|
||||
aes_set_key(aes_cnt_cipher_t *cipher, const char *key, int key_bits)
|
||||
{
|
||||
if (should_use_EVP) {
|
||||
const EVP_CIPHER *c;
|
||||
switch (key_bits) {
|
||||
case 128: c = EVP_aes_128_ecb(); break;
|
||||
case 192: c = EVP_aes_192_ecb(); break;
|
||||
case 256: c = EVP_aes_256_ecb(); break;
|
||||
default: tor_assert(0);
|
||||
}
|
||||
EVP_EncryptInit(&cipher->key.evp, c, (const unsigned char*)key, NULL);
|
||||
cipher->using_evp = 1;
|
||||
} else {
|
||||
AES_set_encrypt_key((const unsigned char *)key, key_bits,&cipher->key.aes);
|
||||
cipher->using_evp = 0;
|
||||
}
|
||||
|
||||
#ifdef USING_COUNTER_VARS
|
||||
cipher->counter0 = 0;
|
||||
cipher->counter1 = 0;
|
||||
cipher->counter2 = 0;
|
||||
cipher->counter3 = 0;
|
||||
#endif
|
||||
|
||||
memset(cipher->ctr_buf.buf, 0, sizeof(cipher->ctr_buf.buf));
|
||||
|
||||
cipher->pos = 0;
|
||||
|
||||
#ifdef CAN_USE_OPENSSL_CTR
|
||||
if (should_use_openssl_CTR)
|
||||
memset(cipher->buf, 0, sizeof(cipher->buf));
|
||||
else
|
||||
#endif
|
||||
aes_fill_buf_(cipher);
|
||||
}
|
||||
|
||||
/** Release storage held by <b>cipher</b>
|
||||
*/
|
||||
void
|
||||
aes_cipher_free(aes_cnt_cipher_t *cipher)
|
||||
{
|
||||
if (!cipher)
|
||||
return;
|
||||
if (cipher->using_evp) {
|
||||
EVP_CIPHER_CTX_cleanup(&cipher->key.evp);
|
||||
}
|
||||
memwipe(cipher, 0, sizeof(aes_cnt_cipher_t));
|
||||
tor_free(cipher);
|
||||
}
|
||||
|
||||
#if defined(USING_COUNTER_VARS)
|
||||
#define UPDATE_CTR_BUF(c, n) STMT_BEGIN \
|
||||
(c)->ctr_buf.buf32[3-(n)] = htonl((c)->counter ## n); \
|
||||
STMT_END
|
||||
#else
|
||||
#define UPDATE_CTR_BUF(c, n)
|
||||
#endif
|
||||
|
||||
#ifdef CAN_USE_OPENSSL_CTR
|
||||
/* Helper function to use EVP with openssl's counter-mode wrapper. */
|
||||
static void
|
||||
evp_block128_fn(const uint8_t in[16],
|
||||
uint8_t out[16],
|
||||
const void *key)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx = (void*)key;
|
||||
int inl=16, outl=16;
|
||||
EVP_EncryptUpdate(ctx, out, &outl, in, inl);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Encrypt <b>len</b> bytes from <b>input</b>, storing the result in
|
||||
* <b>output</b>. Uses the key in <b>cipher</b>, and advances the counter
|
||||
* by <b>len</b> bytes as it encrypts.
|
||||
*/
|
||||
void
|
||||
aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
|
||||
char *output)
|
||||
{
|
||||
#ifdef CAN_USE_OPENSSL_CTR
|
||||
if (should_use_openssl_CTR) {
|
||||
if (cipher->using_evp) {
|
||||
/* In openssl 1.0.0, there's an if'd out EVP_aes_128_ctr in evp.h. If
|
||||
* it weren't disabled, it might be better just to use that.
|
||||
*/
|
||||
CRYPTO_ctr128_encrypt((const unsigned char *)input,
|
||||
(unsigned char *)output,
|
||||
len,
|
||||
&cipher->key.evp,
|
||||
cipher->ctr_buf.buf,
|
||||
cipher->buf,
|
||||
&cipher->pos,
|
||||
evp_block128_fn);
|
||||
} else {
|
||||
AES_ctr128_encrypt((const unsigned char *)input,
|
||||
(unsigned char *)output,
|
||||
len,
|
||||
&cipher->key.aes,
|
||||
cipher->ctr_buf.buf,
|
||||
cipher->buf,
|
||||
&cipher->pos);
|
||||
}
|
||||
return;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int c = cipher->pos;
|
||||
if (PREDICT_UNLIKELY(!len)) return;
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
if (len-- == 0) { cipher->pos = c; return; }
|
||||
*(output++) = *(input++) ^ cipher->buf[c];
|
||||
} while (++c != 16);
|
||||
cipher->pos = c = 0;
|
||||
if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) {
|
||||
if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) {
|
||||
if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) {
|
||||
++COUNTER(cipher, 3);
|
||||
UPDATE_CTR_BUF(cipher, 3);
|
||||
}
|
||||
UPDATE_CTR_BUF(cipher, 2);
|
||||
}
|
||||
UPDATE_CTR_BUF(cipher, 1);
|
||||
}
|
||||
UPDATE_CTR_BUF(cipher, 0);
|
||||
aes_fill_buf_(cipher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Encrypt <b>len</b> bytes from <b>input</b>, storing the results in place.
|
||||
* Uses the key in <b>cipher</b>, and advances the counter by <b>len</b> bytes
|
||||
* as it encrypts.
|
||||
*/
|
||||
void
|
||||
aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len)
|
||||
{
|
||||
#ifdef CAN_USE_OPENSSL_CTR
|
||||
if (should_use_openssl_CTR) {
|
||||
aes_crypt(cipher, data, len, data);
|
||||
return;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int c = cipher->pos;
|
||||
if (PREDICT_UNLIKELY(!len)) return;
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
if (len-- == 0) { cipher->pos = c; return; }
|
||||
*(data++) ^= cipher->buf[c];
|
||||
} while (++c != 16);
|
||||
cipher->pos = c = 0;
|
||||
if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 0))) {
|
||||
if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 1))) {
|
||||
if (PREDICT_UNLIKELY(! ++COUNTER(cipher, 2))) {
|
||||
++COUNTER(cipher, 3);
|
||||
UPDATE_CTR_BUF(cipher, 3);
|
||||
}
|
||||
UPDATE_CTR_BUF(cipher, 2);
|
||||
}
|
||||
UPDATE_CTR_BUF(cipher, 1);
|
||||
}
|
||||
UPDATE_CTR_BUF(cipher, 0);
|
||||
aes_fill_buf_(cipher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Reset the 128-bit counter of <b>cipher</b> to the 16-bit big-endian value
|
||||
* in <b>iv</b>. */
|
||||
static void
|
||||
aes_set_iv(aes_cnt_cipher_t *cipher, const char *iv)
|
||||
{
|
||||
#ifdef USING_COUNTER_VARS
|
||||
cipher->counter3 = ntohl(get_uint32(iv));
|
||||
cipher->counter2 = ntohl(get_uint32(iv+4));
|
||||
cipher->counter1 = ntohl(get_uint32(iv+8));
|
||||
cipher->counter0 = ntohl(get_uint32(iv+12));
|
||||
#endif
|
||||
cipher->pos = 0;
|
||||
memcpy(cipher->ctr_buf.buf, iv, 16);
|
||||
|
||||
#ifdef CAN_USE_OPENSSL_CTR
|
||||
if (!should_use_openssl_CTR)
|
||||
#endif
|
||||
aes_fill_buf_(cipher);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/* Copyright (c) 2003, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/* Implements a minimal interface to counter-mode AES. */
|
||||
|
||||
#ifndef TOR_AES_H
|
||||
#define TOR_AES_H
|
||||
|
||||
/**
|
||||
* \file aes.h
|
||||
* \brief Headers for aes.c
|
||||
*/
|
||||
|
||||
struct aes_cnt_cipher;
|
||||
typedef struct aes_cnt_cipher aes_cnt_cipher_t;
|
||||
|
||||
aes_cnt_cipher_t* aes_new_cipher(const char *key, const char *iv);
|
||||
void aes_cipher_free(aes_cnt_cipher_t *cipher);
|
||||
void aes_crypt(aes_cnt_cipher_t *cipher, const char *input, size_t len,
|
||||
char *output);
|
||||
void aes_crypt_inplace(aes_cnt_cipher_t *cipher, char *data, size_t len);
|
||||
|
||||
int evaluate_evp_for_aes(int force_value);
|
||||
int evaluate_ctr_for_aes(void);
|
||||
|
||||
#endif
|
||||
|
||||
-1072
File diff suppressed because it is too large
Load Diff
@@ -1,205 +0,0 @@
|
||||
/* Copyright (c) 2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define __USE_GNU
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "backtrace.h"
|
||||
#include "tor_compat.h"
|
||||
#include "tor_util.h"
|
||||
#include "torlog.h"
|
||||
|
||||
#ifdef HAVE_EXECINFO_H
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CYGWIN_SIGNAL_H
|
||||
#include <cygwin/signal.h>
|
||||
#elif defined(HAVE_SYS_UCONTEXT_H)
|
||||
#include <sys/ucontext.h>
|
||||
#elif defined(HAVE_UCONTEXT_H)
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \
|
||||
defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION)
|
||||
#define USE_BACKTRACE
|
||||
#endif
|
||||
|
||||
#if !defined(USE_BACKTRACE)
|
||||
#define NO_BACKTRACE_IMPL
|
||||
#endif
|
||||
|
||||
/** Version of Tor to report in backtrace messages. */
|
||||
static char *bt_version = NULL;
|
||||
|
||||
#ifdef USE_BACKTRACE
|
||||
/** Largest stack depth to try to dump. */
|
||||
#define MAX_DEPTH 256
|
||||
/** Static allocation of stack to dump. This is static so we avoid stack
|
||||
* pressure. */
|
||||
static void *cb_buf[MAX_DEPTH];
|
||||
|
||||
/** Change a stacktrace in <b>stack</b> of depth <b>depth</b> so that it will
|
||||
* log the correct function from which a signal was received with context
|
||||
* <b>ctx</b>. (When we get a signal, the current function will not have
|
||||
* called any other function, and will therefore have not pushed its address
|
||||
* onto the stack. Fortunately, we usually have the program counter in the
|
||||
* ucontext_t structure.
|
||||
*/
|
||||
static void
|
||||
clean_backtrace(void **stack, int depth, const ucontext_t *ctx)
|
||||
{
|
||||
#ifdef PC_FROM_UCONTEXT
|
||||
#if defined(__linux__)
|
||||
const int n = 1;
|
||||
#elif defined(__darwin__) || defined(__APPLE__) || defined(__OpenBSD__) \
|
||||
|| defined(__FreeBSD__)
|
||||
const int n = 2;
|
||||
#else
|
||||
const int n = 1;
|
||||
#endif
|
||||
if (depth <= n)
|
||||
return;
|
||||
|
||||
stack[n] = (void*) ctx->PC_FROM_UCONTEXT;
|
||||
#else
|
||||
(void) depth;
|
||||
(void) ctx;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow
|
||||
* that with a backtrace log. */
|
||||
void
|
||||
log_backtrace(int severity, int domain, const char *msg)
|
||||
{
|
||||
int depth = backtrace(cb_buf, MAX_DEPTH);
|
||||
char **symbols = backtrace_symbols(cb_buf, depth);
|
||||
int i;
|
||||
tor_log(severity, domain, "%s. Stack trace:", msg);
|
||||
if (!symbols) {
|
||||
tor_log(severity, domain, " Unable to generate backtrace.");
|
||||
return;
|
||||
}
|
||||
for (i=0; i < depth; ++i) {
|
||||
tor_log(severity, domain, " %s", symbols[i]);
|
||||
}
|
||||
free(symbols);
|
||||
}
|
||||
|
||||
static void crash_handler(int sig, siginfo_t *si, void *ctx_)
|
||||
__attribute__((noreturn));
|
||||
|
||||
/** Signal handler: write a crash message with a stack trace, and die. */
|
||||
static void
|
||||
crash_handler(int sig, siginfo_t *si, void *ctx_)
|
||||
{
|
||||
char buf[40];
|
||||
int depth;
|
||||
ucontext_t *ctx = (ucontext_t *) ctx_;
|
||||
int n_fds, i;
|
||||
const int *fds = NULL;
|
||||
|
||||
(void) si;
|
||||
|
||||
depth = backtrace(cb_buf, MAX_DEPTH);
|
||||
/* Clean up the top stack frame so we get the real function
|
||||
* name for the most recently failing function. */
|
||||
clean_backtrace(cb_buf, depth, ctx);
|
||||
|
||||
format_dec_number_sigsafe((unsigned)sig, buf, sizeof(buf));
|
||||
|
||||
tor_log_err_sigsafe(bt_version, " died: Caught signal ", buf, "\n",
|
||||
NULL);
|
||||
|
||||
n_fds = tor_log_get_sigsafe_err_fds(&fds);
|
||||
for (i=0; i < n_fds; ++i)
|
||||
backtrace_symbols_fd(cb_buf, depth, fds[i]);
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
/** Install signal handlers as needed so that when we crash, we produce a
|
||||
* useful stack trace. Return 0 on success, -1 on failure. */
|
||||
static int
|
||||
install_bt_handler(void)
|
||||
{
|
||||
int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS,
|
||||
SIGIO, -1 };
|
||||
int i, rv=0;
|
||||
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = crash_handler;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigfillset(&sa.sa_mask);
|
||||
|
||||
for (i = 0; trap_signals[i] >= 0; ++i) {
|
||||
if (sigaction(trap_signals[i], &sa, NULL) == -1) {
|
||||
log_warn(LD_BUG, "Sigaction failed: %s", strerror(errno));
|
||||
rv = -1;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** Uninstall crash handlers. */
|
||||
static void
|
||||
remove_bt_handler(void)
|
||||
{
|
||||
/* We don't need to actually free anything at exit here. */
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NO_BACKTRACE_IMPL
|
||||
void
|
||||
log_backtrace(int severity, int domain, const char *msg)
|
||||
{
|
||||
tor_log(severity, domain, "%s. (Stack trace not available)", msg);
|
||||
}
|
||||
|
||||
static int
|
||||
install_bt_handler(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_bt_handler(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Set up code to handle generating error messages on crashes. */
|
||||
int
|
||||
configure_backtrace_handler(const char *tor_version)
|
||||
{
|
||||
tor_free(bt_version);
|
||||
if (!tor_version)
|
||||
tor_version = "";
|
||||
tor_asprintf(&bt_version, "Tor %s", tor_version);
|
||||
|
||||
return install_bt_handler();
|
||||
}
|
||||
|
||||
/** Perform end-of-process cleanup for code that generates error messages on
|
||||
* crashes. */
|
||||
void
|
||||
clean_up_backtrace_handler(void)
|
||||
{
|
||||
remove_bt_handler();
|
||||
|
||||
tor_free(bt_version);
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/* Copyright (c) 2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_BACKTRACE_H
|
||||
#define TOR_BACKTRACE_H
|
||||
|
||||
void log_backtrace(int severity, int domain, const char *msg);
|
||||
int configure_backtrace_handler(const char *tor_version);
|
||||
void clean_up_backtrace_handler(void);
|
||||
|
||||
#endif
|
||||
|
||||
-2584
File diff suppressed because it is too large
Load Diff
@@ -1,106 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file buffers.h
|
||||
* \brief Header file for buffers.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_BUFFERS_H
|
||||
#define TOR_BUFFERS_H
|
||||
|
||||
#include "testsupport.h"
|
||||
|
||||
buf_t *buf_new(void);
|
||||
buf_t *buf_new_with_capacity(size_t size);
|
||||
void buf_free(buf_t *buf);
|
||||
void buf_clear(buf_t *buf);
|
||||
buf_t *buf_copy(const buf_t *buf);
|
||||
void buf_shrink(buf_t *buf);
|
||||
void buf_shrink_freelists(int free_all);
|
||||
void buf_dump_freelist_sizes(int severity);
|
||||
|
||||
size_t buf_datalen(const buf_t *buf);
|
||||
size_t buf_allocation(const buf_t *buf);
|
||||
size_t buf_slack(const buf_t *buf);
|
||||
|
||||
int read_to_buf(tor_socket_t s, size_t at_most, buf_t *buf, int *reached_eof,
|
||||
int *socket_error);
|
||||
int read_to_buf_tls(tor_tls_t *tls, size_t at_most, buf_t *buf);
|
||||
|
||||
int flush_buf(tor_socket_t s, buf_t *buf, size_t sz, size_t *buf_flushlen);
|
||||
int flush_buf_tls(tor_tls_t *tls, buf_t *buf, size_t sz, size_t *buf_flushlen);
|
||||
|
||||
int write_to_buf(const char *string, size_t string_len, buf_t *buf);
|
||||
int write_to_buf_zlib(buf_t *buf, tor_zlib_state_t *state,
|
||||
const char *data, size_t data_len, int done);
|
||||
int move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen);
|
||||
int fetch_from_buf(char *string, size_t string_len, buf_t *buf);
|
||||
int fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto);
|
||||
int fetch_from_buf_http(buf_t *buf,
|
||||
char **headers_out, size_t max_headerlen,
|
||||
char **body_out, size_t *body_used, size_t max_bodylen,
|
||||
int force_complete);
|
||||
socks_request_t *socks_request_new(void);
|
||||
void socks_request_free(socks_request_t *req);
|
||||
int fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
|
||||
int log_sockstype, int safe_socks);
|
||||
int fetch_from_buf_socks_client(buf_t *buf, int state, char **reason);
|
||||
int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len);
|
||||
|
||||
int peek_buf_has_control0_command(buf_t *buf);
|
||||
|
||||
int fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out);
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
|
||||
int linkproto);
|
||||
int fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
|
||||
int log_sockstype, int safe_socks);
|
||||
int fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state,
|
||||
char **reason);
|
||||
int fetch_from_evbuffer_http(struct evbuffer *buf,
|
||||
char **headers_out, size_t max_headerlen,
|
||||
char **body_out, size_t *body_used, size_t max_bodylen,
|
||||
int force_complete);
|
||||
int peek_evbuffer_has_control0_command(struct evbuffer *buf);
|
||||
int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
|
||||
const char *data, size_t data_len,
|
||||
int done);
|
||||
int fetch_ext_or_command_from_evbuffer(struct evbuffer *buf,
|
||||
ext_or_cmd_t **out);
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
#define generic_buffer_new() evbuffer_new()
|
||||
#define generic_buffer_len(b) evbuffer_get_length((b))
|
||||
#define generic_buffer_add(b,dat,len) evbuffer_add((b),(dat),(len))
|
||||
#define generic_buffer_get(b,buf,buflen) evbuffer_remove((b),(buf),(buflen))
|
||||
#define generic_buffer_clear(b) evbuffer_drain((b), evbuffer_get_length((b)))
|
||||
#define generic_buffer_free(b) evbuffer_free((b))
|
||||
#define generic_buffer_fetch_ext_or_cmd(b, out) \
|
||||
fetch_ext_or_command_from_evbuffer((b), (out))
|
||||
#else
|
||||
#define generic_buffer_new() buf_new()
|
||||
#define generic_buffer_len(b) buf_datalen((b))
|
||||
#define generic_buffer_add(b,dat,len) write_to_buf((dat),(len),(b))
|
||||
#define generic_buffer_get(b,buf,buflen) fetch_from_buf((buf),(buflen),(b))
|
||||
#define generic_buffer_clear(b) buf_clear((b))
|
||||
#define generic_buffer_free(b) buf_free((b))
|
||||
#define generic_buffer_fetch_ext_or_cmd(b, out) \
|
||||
fetch_ext_or_command_from_buf((b), (out))
|
||||
#endif
|
||||
int generic_buffer_set_to_copy(generic_buffer_t **output,
|
||||
const generic_buffer_t *input);
|
||||
|
||||
void assert_buf_ok(buf_t *buf);
|
||||
|
||||
#ifdef BUFFERS_PRIVATE
|
||||
STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TOR_SRC_DIR="${TOR_SRC_DIR:-$ROOT_DIR/tor-src}"
|
||||
|
||||
if [[ ! -d "$TOR_SRC_DIR" ]]; then
|
||||
echo "Tor source tree not found at: $TOR_SRC_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$TOR_SRC_DIR"
|
||||
|
||||
if [[ ! -x "./configure" ]]; then
|
||||
echo "Running autogen.sh"
|
||||
./autogen.sh
|
||||
fi
|
||||
|
||||
echo "Configuring Tor static library build from: $TOR_SRC_DIR"
|
||||
./configure \
|
||||
--enable-static-tor \
|
||||
--disable-module-relay \
|
||||
--disable-module-dirauth \
|
||||
--disable-asciidoc \
|
||||
--disable-manpage \
|
||||
--disable-html-manual \
|
||||
--disable-unittests \
|
||||
--disable-tool-name-check
|
||||
|
||||
echo "Building Tor"
|
||||
make -j"${NPROC:-$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)}"
|
||||
|
||||
echo
|
||||
echo "Build finished. Inspect these locations for static libraries:"
|
||||
echo " $TOR_SRC_DIR/src/core"
|
||||
echo " $TOR_SRC_DIR/src/lib"
|
||||
echo " $TOR_SRC_DIR/src/trunnel"
|
||||
echo
|
||||
echo "Suggested next step for Triangles:"
|
||||
echo ' make -f src/makefile.unix USE_TOR_EMBEDDED=1'
|
||||
-4191
File diff suppressed because it is too large
Load Diff
@@ -1,489 +0,0 @@
|
||||
/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file channel.h
|
||||
* \brief Header file for channel.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_CHANNEL_H
|
||||
#define TOR_CHANNEL_H
|
||||
|
||||
#include "or.h"
|
||||
#include "circuitmux.h"
|
||||
|
||||
/* Channel handler function pointer typedefs */
|
||||
typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *);
|
||||
typedef void (*channel_cell_handler_fn_ptr)(channel_t *, cell_t *);
|
||||
typedef void (*channel_var_cell_handler_fn_ptr)(channel_t *, var_cell_t *);
|
||||
|
||||
struct cell_queue_entry_s;
|
||||
TOR_SIMPLEQ_HEAD(chan_cell_queue, cell_queue_entry_s) incoming_queue;
|
||||
typedef struct chan_cell_queue chan_cell_queue_t;
|
||||
|
||||
/*
|
||||
* Channel struct; see the channel_t typedef in or.h. A channel is an
|
||||
* abstract interface for the OR-to-OR connection, similar to connection_or_t,
|
||||
* but without the strong coupling to the underlying TLS implementation. They
|
||||
* are constructed by calling a protocol-specific function to open a channel
|
||||
* to a particular node, and once constructed support the abstract operations
|
||||
* defined below.
|
||||
*/
|
||||
|
||||
struct channel_s {
|
||||
/* Magic number for type-checking cast macros */
|
||||
uint32_t magic;
|
||||
|
||||
/* Current channel state */
|
||||
channel_state_t state;
|
||||
|
||||
/* Globally unique ID number for a channel over the lifetime of a Tor
|
||||
* process.
|
||||
*/
|
||||
uint64_t global_identifier;
|
||||
|
||||
/* Should we expect to see this channel in the channel lists? */
|
||||
unsigned char registered:1;
|
||||
|
||||
/** has this channel ever been open? */
|
||||
unsigned int has_been_open:1;
|
||||
|
||||
/** Why did we close?
|
||||
*/
|
||||
enum {
|
||||
CHANNEL_NOT_CLOSING = 0,
|
||||
CHANNEL_CLOSE_REQUESTED,
|
||||
CHANNEL_CLOSE_FROM_BELOW,
|
||||
CHANNEL_CLOSE_FOR_ERROR
|
||||
} reason_for_closing;
|
||||
|
||||
/* Timestamps for both cell channels and listeners */
|
||||
time_t timestamp_created; /* Channel created */
|
||||
time_t timestamp_active; /* Any activity */
|
||||
|
||||
/* Methods implemented by the lower layer */
|
||||
|
||||
/* Free a channel */
|
||||
void (*free)(channel_t *);
|
||||
/* Close an open channel */
|
||||
void (*close)(channel_t *);
|
||||
/* Describe the transport subclass for this channel */
|
||||
const char * (*describe_transport)(channel_t *);
|
||||
/* Optional method to dump transport-specific statistics on the channel */
|
||||
void (*dumpstats)(channel_t *, int);
|
||||
|
||||
/* Registered handlers for incoming cells */
|
||||
channel_cell_handler_fn_ptr cell_handler;
|
||||
channel_var_cell_handler_fn_ptr var_cell_handler;
|
||||
|
||||
/* Methods implemented by the lower layer */
|
||||
|
||||
/*
|
||||
* Ask the underlying transport what the remote endpoint address is, in
|
||||
* a tor_addr_t. This is optional and subclasses may leave this NULL.
|
||||
* If they implement it, they should write the address out to the
|
||||
* provided tor_addr_t *, and return 1 if successful or 0 if no address
|
||||
* available.
|
||||
*/
|
||||
int (*get_remote_addr)(channel_t *, tor_addr_t *);
|
||||
int (*get_transport_name)(channel_t *chan, char **transport_out);
|
||||
|
||||
#define GRD_FLAG_ORIGINAL 1
|
||||
#define GRD_FLAG_ADDR_ONLY 2
|
||||
/*
|
||||
* Get a text description of the remote endpoint; canonicalized if the flag
|
||||
* GRD_FLAG_ORIGINAL is not set, or the one we originally connected
|
||||
* to/received from if it is. If GRD_FLAG_ADDR_ONLY is set, we return only
|
||||
* the original address.
|
||||
*/
|
||||
const char * (*get_remote_descr)(channel_t *, int);
|
||||
/* Check if the lower layer has queued writes */
|
||||
int (*has_queued_writes)(channel_t *);
|
||||
/*
|
||||
* If the second param is zero, ask the lower layer if this is
|
||||
* 'canonical', for a transport-specific definition of canonical; if
|
||||
* it is 1, ask if the answer to the preceding query is safe to rely
|
||||
* on.
|
||||
*/
|
||||
int (*is_canonical)(channel_t *, int);
|
||||
/* Check if this channel matches a specified extend_info_t */
|
||||
int (*matches_extend_info)(channel_t *, extend_info_t *);
|
||||
/* Check if this channel matches a target address when extending */
|
||||
int (*matches_target)(channel_t *, const tor_addr_t *);
|
||||
/* Write a cell to an open channel */
|
||||
int (*write_cell)(channel_t *, cell_t *);
|
||||
/* Write a packed cell to an open channel */
|
||||
int (*write_packed_cell)(channel_t *, packed_cell_t *);
|
||||
/* Write a variable-length cell to an open channel */
|
||||
int (*write_var_cell)(channel_t *, var_cell_t *);
|
||||
|
||||
/*
|
||||
* Hash of the public RSA key for the other side's identity key, or
|
||||
* zeroes if the other side hasn't shown us a valid identity key.
|
||||
*/
|
||||
char identity_digest[DIGEST_LEN];
|
||||
/* Nickname of the OR on the other side, or NULL if none. */
|
||||
char *nickname;
|
||||
|
||||
/*
|
||||
* Linked list of channels with the same identity digest, for the
|
||||
* digest->channel map
|
||||
*/
|
||||
TOR_LIST_ENTRY(channel_s) next_with_same_id;
|
||||
|
||||
/* List of incoming cells to handle */
|
||||
chan_cell_queue_t incoming_queue;
|
||||
|
||||
/* List of queued outgoing cells */
|
||||
chan_cell_queue_t outgoing_queue;
|
||||
|
||||
/* Circuit mux for circuits sending on this channel */
|
||||
circuitmux_t *cmux;
|
||||
|
||||
/* Circuit ID generation stuff for use by circuitbuild.c */
|
||||
|
||||
/*
|
||||
* When we send CREATE cells along this connection, which half of the
|
||||
* space should we use?
|
||||
*/
|
||||
ENUM_BF(circ_id_type_t) circ_id_type:2;
|
||||
/** DOCDOC*/
|
||||
unsigned wide_circ_ids:1;
|
||||
/*
|
||||
* Which circ_id do we try to use next on this connection? This is
|
||||
* always in the range 0..1<<15-1.
|
||||
*/
|
||||
circid_t next_circ_id;
|
||||
|
||||
/* For how many circuits are we n_chan? What about p_chan? */
|
||||
unsigned int num_n_circuits, num_p_circuits;
|
||||
|
||||
/*
|
||||
* True iff this channel shouldn't get any new circs attached to it,
|
||||
* because the connection is too old, or because there's a better one.
|
||||
* More generally, this flag is used to note an unhealthy connection;
|
||||
* for example, if a bad connection fails we shouldn't assume that the
|
||||
* router itself has a problem.
|
||||
*/
|
||||
unsigned int is_bad_for_new_circs:1;
|
||||
|
||||
/** True iff we have decided that the other end of this connection
|
||||
* is a client. Channels with this flag set should never be used
|
||||
* to satisfy an EXTEND request. */
|
||||
unsigned int is_client:1;
|
||||
|
||||
/** Set if the channel was initiated remotely (came from a listener) */
|
||||
unsigned int is_incoming:1;
|
||||
|
||||
/** Set by lower layer if this is local; i.e., everything it communicates
|
||||
* with for this channel returns true for is_local_addr(). This is used
|
||||
* to decide whether to declare reachability when we receive something on
|
||||
* this channel in circuitbuild.c
|
||||
*/
|
||||
unsigned int is_local:1;
|
||||
|
||||
/** Channel timestamps for cell channels */
|
||||
time_t timestamp_client; /* Client used this, according to relay.c */
|
||||
time_t timestamp_drained; /* Output queue empty */
|
||||
time_t timestamp_recv; /* Cell received from lower layer */
|
||||
time_t timestamp_xmit; /* Cell sent to lower layer */
|
||||
|
||||
/* Timestamp for relay.c */
|
||||
time_t timestamp_last_added_nonpadding;
|
||||
|
||||
/** Unique ID for measuring direct network status requests;vtunneled ones
|
||||
* come over a circuit_t, which has a dirreq_id field as well, but is a
|
||||
* distinct namespace. */
|
||||
uint64_t dirreq_id;
|
||||
|
||||
/** Channel counters for cell channels */
|
||||
uint64_t n_cells_recved;
|
||||
uint64_t n_cells_xmitted;
|
||||
};
|
||||
|
||||
struct channel_listener_s {
|
||||
/* Current channel listener state */
|
||||
channel_listener_state_t state;
|
||||
|
||||
/* Globally unique ID number for a channel over the lifetime of a Tor
|
||||
* process.
|
||||
*/
|
||||
uint64_t global_identifier;
|
||||
|
||||
/* Should we expect to see this channel in the channel lists? */
|
||||
unsigned char registered:1;
|
||||
|
||||
/** Why did we close?
|
||||
*/
|
||||
enum {
|
||||
CHANNEL_LISTENER_NOT_CLOSING = 0,
|
||||
CHANNEL_LISTENER_CLOSE_REQUESTED,
|
||||
CHANNEL_LISTENER_CLOSE_FROM_BELOW,
|
||||
CHANNEL_LISTENER_CLOSE_FOR_ERROR
|
||||
} reason_for_closing;
|
||||
|
||||
/* Timestamps for both cell channels and listeners */
|
||||
time_t timestamp_created; /* Channel created */
|
||||
time_t timestamp_active; /* Any activity */
|
||||
|
||||
/* Methods implemented by the lower layer */
|
||||
|
||||
/* Free a channel */
|
||||
void (*free)(channel_listener_t *);
|
||||
/* Close an open channel */
|
||||
void (*close)(channel_listener_t *);
|
||||
/* Describe the transport subclass for this channel */
|
||||
const char * (*describe_transport)(channel_listener_t *);
|
||||
/* Optional method to dump transport-specific statistics on the channel */
|
||||
void (*dumpstats)(channel_listener_t *, int);
|
||||
|
||||
/* Registered listen handler to call on incoming connection */
|
||||
channel_listener_fn_ptr listener;
|
||||
|
||||
/* List of pending incoming connections */
|
||||
smartlist_t *incoming_list;
|
||||
|
||||
/* Timestamps for listeners */
|
||||
time_t timestamp_accepted;
|
||||
|
||||
/* Counters for listeners */
|
||||
uint64_t n_accepted;
|
||||
};
|
||||
|
||||
/* Channel state manipulations */
|
||||
|
||||
int channel_state_is_valid(channel_state_t state);
|
||||
int channel_listener_state_is_valid(channel_listener_state_t state);
|
||||
|
||||
int channel_state_can_transition(channel_state_t from, channel_state_t to);
|
||||
int channel_listener_state_can_transition(channel_listener_state_t from,
|
||||
channel_listener_state_t to);
|
||||
|
||||
const char * channel_state_to_string(channel_state_t state);
|
||||
const char *
|
||||
channel_listener_state_to_string(channel_listener_state_t state);
|
||||
|
||||
/* Abstract channel operations */
|
||||
|
||||
void channel_mark_for_close(channel_t *chan);
|
||||
void channel_write_cell(channel_t *chan, cell_t *cell);
|
||||
void channel_write_packed_cell(channel_t *chan, packed_cell_t *cell);
|
||||
void channel_write_var_cell(channel_t *chan, var_cell_t *cell);
|
||||
|
||||
void channel_listener_mark_for_close(channel_listener_t *chan_l);
|
||||
|
||||
/* Channel callback registrations */
|
||||
|
||||
/* Listener callback */
|
||||
channel_listener_fn_ptr
|
||||
channel_listener_get_listener_fn(channel_listener_t *chan);
|
||||
|
||||
void channel_listener_set_listener_fn(channel_listener_t *chan,
|
||||
channel_listener_fn_ptr listener);
|
||||
|
||||
/* Incoming cell callbacks */
|
||||
channel_cell_handler_fn_ptr channel_get_cell_handler(channel_t *chan);
|
||||
|
||||
channel_var_cell_handler_fn_ptr
|
||||
channel_get_var_cell_handler(channel_t *chan);
|
||||
|
||||
void channel_set_cell_handlers(channel_t *chan,
|
||||
channel_cell_handler_fn_ptr cell_handler,
|
||||
channel_var_cell_handler_fn_ptr
|
||||
var_cell_handler);
|
||||
|
||||
/* Clean up closed channels and channel listeners periodically; these are
|
||||
* called from run_scheduled_events() in onion_main.c.
|
||||
*/
|
||||
void channel_run_cleanup(void);
|
||||
void channel_listener_run_cleanup(void);
|
||||
|
||||
/* Close all channels and deallocate everything */
|
||||
void channel_free_all(void);
|
||||
|
||||
/* Dump some statistics in the log */
|
||||
void channel_dumpstats(int severity);
|
||||
void channel_listener_dumpstats(int severity);
|
||||
|
||||
/* Set the cmux policy on all active channels */
|
||||
void channel_set_cmux_policy_everywhere(circuitmux_policy_t *pol);
|
||||
|
||||
#ifdef TOR_CHANNEL_INTERNAL_
|
||||
|
||||
/* Channel operations for subclasses and internal use only */
|
||||
|
||||
/* Initialize a newly allocated channel - do this first in subclass
|
||||
* constructors.
|
||||
*/
|
||||
|
||||
void channel_init(channel_t *chan);
|
||||
void channel_init_listener(channel_listener_t *chan);
|
||||
|
||||
/* Channel registration/unregistration */
|
||||
void channel_register(channel_t *chan);
|
||||
void channel_unregister(channel_t *chan);
|
||||
|
||||
/* Channel listener registration/unregistration */
|
||||
void channel_listener_register(channel_listener_t *chan_l);
|
||||
void channel_listener_unregister(channel_listener_t *chan_l);
|
||||
|
||||
/* Close from below */
|
||||
void channel_close_from_lower_layer(channel_t *chan);
|
||||
void channel_close_for_error(channel_t *chan);
|
||||
void channel_closed(channel_t *chan);
|
||||
|
||||
void channel_listener_close_from_lower_layer(channel_listener_t *chan_l);
|
||||
void channel_listener_close_for_error(channel_listener_t *chan_l);
|
||||
void channel_listener_closed(channel_listener_t *chan_l);
|
||||
|
||||
/* Free a channel */
|
||||
void channel_free(channel_t *chan);
|
||||
void channel_listener_free(channel_listener_t *chan_l);
|
||||
|
||||
/* State/metadata setters */
|
||||
|
||||
void channel_change_state(channel_t *chan, channel_state_t to_state);
|
||||
void channel_clear_identity_digest(channel_t *chan);
|
||||
void channel_clear_remote_end(channel_t *chan);
|
||||
void channel_mark_local(channel_t *chan);
|
||||
void channel_mark_incoming(channel_t *chan);
|
||||
void channel_mark_outgoing(channel_t *chan);
|
||||
void channel_set_identity_digest(channel_t *chan,
|
||||
const char *identity_digest);
|
||||
void channel_set_remote_end(channel_t *chan,
|
||||
const char *identity_digest,
|
||||
const char *nickname);
|
||||
|
||||
void channel_listener_change_state(channel_listener_t *chan_l,
|
||||
channel_listener_state_t to_state);
|
||||
|
||||
/* Timestamp updates */
|
||||
void channel_timestamp_created(channel_t *chan);
|
||||
void channel_timestamp_active(channel_t *chan);
|
||||
void channel_timestamp_drained(channel_t *chan);
|
||||
void channel_timestamp_recv(channel_t *chan);
|
||||
void channel_timestamp_xmit(channel_t *chan);
|
||||
|
||||
void channel_listener_timestamp_created(channel_listener_t *chan_l);
|
||||
void channel_listener_timestamp_active(channel_listener_t *chan_l);
|
||||
void channel_listener_timestamp_accepted(channel_listener_t *chan_l);
|
||||
|
||||
/* Incoming channel handling */
|
||||
void channel_listener_process_incoming(channel_listener_t *listener);
|
||||
void channel_listener_queue_incoming(channel_listener_t *listener,
|
||||
channel_t *incoming);
|
||||
|
||||
/* Incoming cell handling */
|
||||
void channel_process_cells(channel_t *chan);
|
||||
void channel_queue_cell(channel_t *chan, cell_t *cell);
|
||||
void channel_queue_var_cell(channel_t *chan, var_cell_t *var_cell);
|
||||
|
||||
/* Outgoing cell handling */
|
||||
void channel_flush_cells(channel_t *chan);
|
||||
|
||||
/* Request from lower layer for more cells if available */
|
||||
ssize_t channel_flush_some_cells(channel_t *chan, ssize_t num_cells);
|
||||
|
||||
/* Query if data available on this channel */
|
||||
int channel_more_to_flush(channel_t *chan);
|
||||
|
||||
/* Notify flushed outgoing for dirreq handling */
|
||||
void channel_notify_flushed(channel_t *chan);
|
||||
|
||||
/* Handle stuff we need to do on open like notifying circuits */
|
||||
void channel_do_open_actions(channel_t *chan);
|
||||
|
||||
#endif
|
||||
|
||||
/* Helper functions to perform operations on channels */
|
||||
|
||||
int channel_send_destroy(circid_t circ_id, channel_t *chan,
|
||||
int reason);
|
||||
|
||||
/*
|
||||
* Outside abstract interfaces that should eventually get turned into
|
||||
* something transport/address format independent.
|
||||
*/
|
||||
|
||||
channel_t * channel_connect(const tor_addr_t *addr, uint16_t port,
|
||||
const char *id_digest);
|
||||
|
||||
channel_t * channel_get_for_extend(const char *digest,
|
||||
const tor_addr_t *target_addr,
|
||||
const char **msg_out,
|
||||
int *launch_out);
|
||||
|
||||
/* Ask which of two channels is better for circuit-extension purposes */
|
||||
int channel_is_better(time_t now,
|
||||
channel_t *a, channel_t *b,
|
||||
int forgive_new_connections);
|
||||
|
||||
/** Channel lookups
|
||||
*/
|
||||
|
||||
channel_t * channel_find_by_global_id(uint64_t global_identifier);
|
||||
channel_t * channel_find_by_remote_digest(const char *identity_digest);
|
||||
|
||||
/** For things returned by channel_find_by_remote_digest(), walk the list.
|
||||
*/
|
||||
channel_t * channel_next_with_digest(channel_t *chan);
|
||||
|
||||
/*
|
||||
* Metadata queries/updates
|
||||
*/
|
||||
|
||||
const char * channel_describe_transport(channel_t *chan);
|
||||
void channel_dump_statistics(channel_t *chan, int severity);
|
||||
void channel_dump_transport_statistics(channel_t *chan, int severity);
|
||||
const char * channel_get_actual_remote_descr(channel_t *chan);
|
||||
const char * channel_get_actual_remote_address(channel_t *chan);
|
||||
int channel_get_addr_if_possible(channel_t *chan, tor_addr_t *addr_out);
|
||||
const char * channel_get_canonical_remote_descr(channel_t *chan);
|
||||
int channel_has_queued_writes(channel_t *chan);
|
||||
int channel_is_bad_for_new_circs(channel_t *chan);
|
||||
void channel_mark_bad_for_new_circs(channel_t *chan);
|
||||
int channel_is_canonical(channel_t *chan);
|
||||
int channel_is_canonical_is_reliable(channel_t *chan);
|
||||
int channel_is_client(channel_t *chan);
|
||||
int channel_is_local(channel_t *chan);
|
||||
int channel_is_incoming(channel_t *chan);
|
||||
int channel_is_outgoing(channel_t *chan);
|
||||
void channel_mark_client(channel_t *chan);
|
||||
int channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info);
|
||||
int channel_matches_target_addr_for_extend(channel_t *chan,
|
||||
const tor_addr_t *target);
|
||||
unsigned int channel_num_circuits(channel_t *chan);
|
||||
void channel_set_circid_type(channel_t *chan, crypto_pk_t *identity_rcvd,
|
||||
int consider_identity);
|
||||
void channel_timestamp_client(channel_t *chan);
|
||||
|
||||
const char * channel_listener_describe_transport(channel_listener_t *chan_l);
|
||||
void channel_listener_dump_statistics(channel_listener_t *chan_l,
|
||||
int severity);
|
||||
void channel_listener_dump_transport_statistics(channel_listener_t *chan_l,
|
||||
int severity);
|
||||
|
||||
/* Timestamp queries */
|
||||
time_t channel_when_created(channel_t *chan);
|
||||
time_t channel_when_last_active(channel_t *chan);
|
||||
time_t channel_when_last_client(channel_t *chan);
|
||||
time_t channel_when_last_drained(channel_t *chan);
|
||||
time_t channel_when_last_recv(channel_t *chan);
|
||||
time_t channel_when_last_xmit(channel_t *chan);
|
||||
|
||||
time_t channel_listener_when_created(channel_listener_t *chan_l);
|
||||
time_t channel_listener_when_last_active(channel_listener_t *chan_l);
|
||||
time_t channel_listener_when_last_accepted(channel_listener_t *chan_l);
|
||||
|
||||
/* Counter queries */
|
||||
uint64_t channel_count_recved(channel_t *chan);
|
||||
uint64_t channel_count_xmitted(channel_t *chan);
|
||||
|
||||
uint64_t channel_listener_count_accepted(channel_listener_t *chan_l);
|
||||
|
||||
int packed_cell_is_destroy(channel_t *chan,
|
||||
const packed_cell_t *packed_cell,
|
||||
circid_t *circid_out);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,57 +0,0 @@
|
||||
/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file channeltls.h
|
||||
* \brief Header file for channeltls.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_CHANNELTLS_H
|
||||
#define TOR_CHANNELTLS_H
|
||||
|
||||
#include "or.h"
|
||||
#include "channel.h"
|
||||
|
||||
#define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c)))
|
||||
#define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c)))
|
||||
|
||||
#define TLS_CHAN_MAGIC 0x8a192427U
|
||||
|
||||
#ifdef TOR_CHANNEL_INTERNAL_
|
||||
|
||||
struct channel_tls_s {
|
||||
/* Base channel_t struct */
|
||||
channel_t base_;
|
||||
/* or_connection_t pointer */
|
||||
or_connection_t *conn;
|
||||
};
|
||||
|
||||
#endif /* TOR_CHANNEL_INTERNAL_ */
|
||||
|
||||
channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port,
|
||||
const char *id_digest);
|
||||
channel_listener_t * channel_tls_get_listener(void);
|
||||
channel_listener_t * channel_tls_start_listener(void);
|
||||
channel_t * channel_tls_handle_incoming(or_connection_t *orconn);
|
||||
|
||||
/* Casts */
|
||||
|
||||
channel_t * channel_tls_to_base(channel_tls_t *tlschan);
|
||||
channel_tls_t * channel_tls_from_base(channel_t *chan);
|
||||
|
||||
/* Things for connection_or.c to call back into */
|
||||
ssize_t channel_tls_flush_some_cells(channel_tls_t *chan, ssize_t num_cells);
|
||||
int channel_tls_more_to_flush(channel_tls_t *chan);
|
||||
void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn);
|
||||
void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
|
||||
or_connection_t *conn,
|
||||
uint8_t old_state,
|
||||
uint8_t state);
|
||||
void channel_tls_handle_var_cell(var_cell_t *var_cell,
|
||||
or_connection_t *conn);
|
||||
|
||||
/* Cleanup at shutdown */
|
||||
void channel_tls_free_all(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
/* This is an include file used to define the list of ciphers clients should
|
||||
* advertise. Before including it, you should define the CIPHER and XCIPHER
|
||||
* macros.
|
||||
*
|
||||
* This file was automatically generated by get_mozilla_ciphers.py.
|
||||
*/
|
||||
#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
|
||||
CIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc00a, TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA
|
||||
CIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc014, TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
|
||||
CIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0x0088, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
|
||||
CIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0x0087, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_RSA_WITH_AES_256_SHA
|
||||
CIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA)
|
||||
#else
|
||||
XCIPHER(0x0039, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_DSS_WITH_AES_256_SHA
|
||||
CIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA)
|
||||
#else
|
||||
XCIPHER(0x0038, TLS1_TXT_DHE_DSS_WITH_AES_256_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA
|
||||
CIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc00f, TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA
|
||||
CIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc005, TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA
|
||||
CIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0x0084, TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_RSA_WITH_AES_256_SHA
|
||||
CIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA)
|
||||
#else
|
||||
XCIPHER(0x0035, TLS1_TXT_RSA_WITH_AES_256_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA
|
||||
CIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA)
|
||||
#else
|
||||
XCIPHER(0xc007, TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
|
||||
CIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc009, TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA
|
||||
CIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA)
|
||||
#else
|
||||
XCIPHER(0xc011, TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
||||
CIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc013, TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
|
||||
CIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0x0045, TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
|
||||
CIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0x0044, TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_RSA_WITH_AES_128_SHA
|
||||
CIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA)
|
||||
#else
|
||||
XCIPHER(0x0033, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_DHE_DSS_WITH_AES_128_SHA
|
||||
CIPHER(0x0032, TLS1_TXT_DHE_DSS_WITH_AES_128_SHA)
|
||||
#else
|
||||
XCIPHER(0x0032, TLS1_TXT_DHE_DSS_WITH_AES_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA
|
||||
CIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA)
|
||||
#else
|
||||
XCIPHER(0xc00c, TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA
|
||||
CIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc00e, TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA
|
||||
CIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA)
|
||||
#else
|
||||
XCIPHER(0xc002, TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA
|
||||
CIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xc004, TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_RSA_WITH_SEED_SHA
|
||||
CIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA)
|
||||
#else
|
||||
XCIPHER(0x0096, TLS1_TXT_RSA_WITH_SEED_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA
|
||||
CIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0x0041, TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA)
|
||||
#endif
|
||||
#ifdef SSL3_TXT_RSA_RC4_128_MD5
|
||||
CIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5)
|
||||
#else
|
||||
XCIPHER(0x0004, SSL3_TXT_RSA_RC4_128_MD5)
|
||||
#endif
|
||||
#ifdef SSL3_TXT_RSA_RC4_128_SHA
|
||||
CIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA)
|
||||
#else
|
||||
XCIPHER(0x0005, SSL3_TXT_RSA_RC4_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_RSA_WITH_AES_128_SHA
|
||||
CIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA)
|
||||
#else
|
||||
XCIPHER(0x002f, TLS1_TXT_RSA_WITH_AES_128_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA
|
||||
CIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA)
|
||||
#else
|
||||
XCIPHER(0xc008, TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA
|
||||
CIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA)
|
||||
#else
|
||||
XCIPHER(0xc012, TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA)
|
||||
#endif
|
||||
#ifdef SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA
|
||||
CIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
|
||||
#else
|
||||
XCIPHER(0x0016, SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA)
|
||||
#endif
|
||||
#ifdef SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA
|
||||
CIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA)
|
||||
#else
|
||||
XCIPHER(0x0013, SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA
|
||||
CIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA)
|
||||
#else
|
||||
XCIPHER(0xc00d, TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA)
|
||||
#endif
|
||||
#ifdef TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA
|
||||
CIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA)
|
||||
#else
|
||||
XCIPHER(0xc003, TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA)
|
||||
#endif
|
||||
/* No openssl macro found for 0xfeff */
|
||||
#ifdef SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA
|
||||
CIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
|
||||
#else
|
||||
XCIPHER(0xfeff, SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA)
|
||||
#endif
|
||||
#ifdef SSL3_TXT_RSA_DES_192_CBC3_SHA
|
||||
CIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA)
|
||||
#else
|
||||
XCIPHER(0x000a, SSL3_TXT_RSA_DES_192_CBC3_SHA)
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,29 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitbuild.h
|
||||
* \brief Header file for circuitbuild.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCPATHBIAS_H
|
||||
#define TOR_CIRCPATHBIAS_H
|
||||
|
||||
double pathbias_get_extreme_rate(const or_options_t *options);
|
||||
double pathbias_get_extreme_use_rate(const or_options_t *options);
|
||||
int pathbias_get_dropguards(const or_options_t *options);
|
||||
void pathbias_count_timeout(origin_circuit_t *circ);
|
||||
void pathbias_count_build_success(origin_circuit_t *circ);
|
||||
int pathbias_count_build_attempt(origin_circuit_t *circ);
|
||||
int pathbias_check_close(origin_circuit_t *circ, int reason);
|
||||
int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell);
|
||||
void pathbias_count_use_attempt(origin_circuit_t *circ);
|
||||
void pathbias_mark_use_success(origin_circuit_t *circ);
|
||||
void pathbias_mark_use_rollback(origin_circuit_t *circ);
|
||||
const char *pathbias_state_to_string(path_state_t state);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,62 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitbuild.h
|
||||
* \brief Header file for circuitbuild.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCUITBUILD_H
|
||||
#define TOR_CIRCUITBUILD_H
|
||||
|
||||
char *circuit_list_path(origin_circuit_t *circ, int verbose);
|
||||
char *circuit_list_path_for_controller(origin_circuit_t *circ);
|
||||
void circuit_log_path(int severity, unsigned int domain,
|
||||
origin_circuit_t *circ);
|
||||
void circuit_rep_hist_note_result(origin_circuit_t *circ);
|
||||
origin_circuit_t *origin_circuit_init(uint8_t purpose, int flags);
|
||||
origin_circuit_t *circuit_establish_circuit(uint8_t purpose,
|
||||
extend_info_t *exit,
|
||||
int flags);
|
||||
int circuit_handle_first_hop(origin_circuit_t *circ);
|
||||
void circuit_n_chan_done(channel_t *chan, int status);
|
||||
int inform_testing_reachability(void);
|
||||
int circuit_timeout_want_to_count_circ(origin_circuit_t *circ);
|
||||
int circuit_send_next_onion_skin(origin_circuit_t *circ);
|
||||
void circuit_note_clock_jumped(int seconds_elapsed);
|
||||
int circuit_extend(cell_t *cell, circuit_t *circ);
|
||||
int circuit_init_cpath_crypto(crypt_path_t *cpath, const char *key_data,
|
||||
int reverse);
|
||||
struct created_cell_t;
|
||||
int circuit_finish_handshake(origin_circuit_t *circ,
|
||||
const struct created_cell_t *created_cell);
|
||||
int circuit_truncated(origin_circuit_t *circ, crypt_path_t *layer,
|
||||
int reason);
|
||||
int onionskin_answer(or_circuit_t *circ,
|
||||
const struct created_cell_t *created_cell,
|
||||
const char *keys,
|
||||
const uint8_t *rend_circ_nonce);
|
||||
int circuit_all_predicted_ports_handled(time_t now, int *need_uptime,
|
||||
int *need_capacity);
|
||||
|
||||
int circuit_append_new_exit(origin_circuit_t *circ, extend_info_t *info);
|
||||
int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info);
|
||||
void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop);
|
||||
extend_info_t *extend_info_new(const char *nickname, const char *digest,
|
||||
crypto_pk_t *onion_key,
|
||||
const curve25519_public_key_t *curve25519_key,
|
||||
const tor_addr_t *addr, uint16_t port);
|
||||
extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect);
|
||||
extend_info_t *extend_info_dup(extend_info_t *info);
|
||||
void extend_info_free(extend_info_t *info);
|
||||
const node_t *build_state_get_exit_node(cpath_build_state_t *state);
|
||||
const char *build_state_get_exit_nickname(cpath_build_state_t *state);
|
||||
|
||||
const node_t *choose_good_entry_server(uint8_t purpose,
|
||||
cpath_build_state_t *state);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitlist.h
|
||||
* \brief Header file for circuitlist.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCUITLIST_H
|
||||
#define TOR_CIRCUITLIST_H
|
||||
|
||||
#include "testsupport.h"
|
||||
|
||||
TOR_LIST_HEAD(global_circuitlist_s, circuit_t);
|
||||
|
||||
struct global_circuitlist_s* circuit_get_global_list(void);
|
||||
const char *circuit_state_to_string(int state);
|
||||
const char *circuit_purpose_to_controller_string(uint8_t purpose);
|
||||
const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);
|
||||
const char *circuit_purpose_to_string(uint8_t purpose);
|
||||
void circuit_dump_by_conn(connection_t *conn, int severity);
|
||||
void circuit_dump_by_chan(channel_t *chan, int severity);
|
||||
void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id,
|
||||
channel_t *chan);
|
||||
void circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
|
||||
channel_t *chan);
|
||||
void channel_mark_circid_unusable(channel_t *chan, circid_t id);
|
||||
void channel_mark_circid_usable(channel_t *chan, circid_t id);
|
||||
void circuit_set_state(circuit_t *circ, uint8_t state);
|
||||
void circuit_close_all_marked(void);
|
||||
int32_t circuit_initial_package_window(void);
|
||||
origin_circuit_t *origin_circuit_new(void);
|
||||
or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan);
|
||||
circuit_t *circuit_get_by_circid_channel(circid_t circ_id,
|
||||
channel_t *chan);
|
||||
circuit_t *
|
||||
circuit_get_by_circid_channel_even_if_marked(circid_t circ_id,
|
||||
channel_t *chan);
|
||||
int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan);
|
||||
circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn);
|
||||
void circuit_unlink_all_from_channel(channel_t *chan, int reason);
|
||||
origin_circuit_t *circuit_get_by_global_id(uint32_t id);
|
||||
origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data(
|
||||
const rend_data_t *rend_data);
|
||||
origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
|
||||
const char *digest, uint8_t purpose);
|
||||
or_circuit_t *circuit_get_rendezvous(const char *cookie);
|
||||
or_circuit_t *circuit_get_intro_point(const char *digest);
|
||||
origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose,
|
||||
extend_info_t *info, int flags);
|
||||
void circuit_mark_all_unused_circs(void);
|
||||
void circuit_mark_all_dirty_circs_as_unusable(void);
|
||||
void circuit_mark_for_close_(circuit_t *circ, int reason,
|
||||
int line, const char *file);
|
||||
int circuit_get_cpath_len(origin_circuit_t *circ);
|
||||
void circuit_clear_cpath(origin_circuit_t *circ);
|
||||
crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum);
|
||||
void circuit_get_all_pending_on_channel(smartlist_t *out,
|
||||
channel_t *chan);
|
||||
int circuit_count_pending_on_channel(channel_t *chan);
|
||||
|
||||
#define circuit_mark_for_close(c, reason) \
|
||||
circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__)
|
||||
|
||||
void assert_cpath_layer_ok(const crypt_path_t *cp);
|
||||
void assert_circuit_ok(const circuit_t *c);
|
||||
void circuit_free_all(void);
|
||||
void circuits_handle_oom(size_t current_allocation);
|
||||
|
||||
void channel_note_destroy_pending(channel_t *chan, circid_t id);
|
||||
void channel_note_destroy_not_pending(channel_t *chan, circid_t id);
|
||||
|
||||
#ifdef CIRCUITLIST_PRIVATE
|
||||
STATIC void circuit_free(circuit_t *circ);
|
||||
STATIC size_t n_cells_in_circ_queues(const circuit_t *c);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,147 +0,0 @@
|
||||
/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitmux.h
|
||||
* \brief Header file for circuitmux.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCUITMUX_H
|
||||
#define TOR_CIRCUITMUX_H
|
||||
|
||||
#include "or.h"
|
||||
#include "testsupport.h"
|
||||
|
||||
typedef struct circuitmux_policy_s circuitmux_policy_t;
|
||||
typedef struct circuitmux_policy_data_s circuitmux_policy_data_t;
|
||||
typedef struct circuitmux_policy_circ_data_s circuitmux_policy_circ_data_t;
|
||||
|
||||
struct circuitmux_policy_s {
|
||||
/* Allocate cmux-wide policy-specific data */
|
||||
circuitmux_policy_data_t * (*alloc_cmux_data)(circuitmux_t *cmux);
|
||||
/* Free cmux-wide policy-specific data */
|
||||
void (*free_cmux_data)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data);
|
||||
/* Allocate circuit policy-specific data for a newly attached circuit */
|
||||
circuitmux_policy_circ_data_t *
|
||||
(*alloc_circ_data)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
cell_direction_t direction,
|
||||
unsigned int cell_count);
|
||||
/* Free circuit policy-specific data */
|
||||
void (*free_circ_data)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data);
|
||||
/* Notify that a circuit has become active/inactive */
|
||||
void (*notify_circ_active)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data);
|
||||
void (*notify_circ_inactive)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data);
|
||||
/* Notify of arriving/transmitted cells on a circuit */
|
||||
void (*notify_set_n_cells)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data,
|
||||
unsigned int n_cells);
|
||||
void (*notify_xmit_cells)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data,
|
||||
unsigned int n_cells);
|
||||
/* Choose a circuit */
|
||||
circuit_t * (*pick_active_circuit)(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data);
|
||||
};
|
||||
|
||||
/*
|
||||
* Circuitmux policy implementations can subclass this to store circuitmux-
|
||||
* wide data; it just has the magic number in the base struct.
|
||||
*/
|
||||
|
||||
struct circuitmux_policy_data_s {
|
||||
uint32_t magic;
|
||||
};
|
||||
|
||||
/*
|
||||
* Circuitmux policy implementations can subclass this to store circuit-
|
||||
* specific data; it just has the magic number in the base struct.
|
||||
*/
|
||||
|
||||
struct circuitmux_policy_circ_data_s {
|
||||
uint32_t magic;
|
||||
};
|
||||
|
||||
/*
|
||||
* Upcast #defines for the above types
|
||||
*/
|
||||
|
||||
/**
|
||||
* Convert a circuitmux_policy_data_t subtype to a circuitmux_policy_data_t.
|
||||
*/
|
||||
|
||||
#define TO_CMUX_POL_DATA(x) (&((x)->base_))
|
||||
|
||||
/**
|
||||
* Convert a circuitmux_policy_circ_data_t subtype to a
|
||||
* circuitmux_policy_circ_data_t.
|
||||
*/
|
||||
|
||||
#define TO_CMUX_POL_CIRC_DATA(x) (&((x)->base_))
|
||||
|
||||
/* Consistency check */
|
||||
void circuitmux_assert_okay(circuitmux_t *cmux);
|
||||
|
||||
/* Create/destroy */
|
||||
circuitmux_t * circuitmux_alloc(void);
|
||||
void circuitmux_detach_all_circuits(circuitmux_t *cmux);
|
||||
void circuitmux_free(circuitmux_t *cmux);
|
||||
|
||||
/* Policy control */
|
||||
void circuitmux_clear_policy(circuitmux_t *cmux);
|
||||
const circuitmux_policy_t * circuitmux_get_policy(circuitmux_t *cmux);
|
||||
void circuitmux_set_policy(circuitmux_t *cmux,
|
||||
const circuitmux_policy_t *pol);
|
||||
|
||||
/* Status inquiries */
|
||||
cell_direction_t circuitmux_attached_circuit_direction(
|
||||
circuitmux_t *cmux,
|
||||
circuit_t *circ);
|
||||
int circuitmux_is_circuit_attached(circuitmux_t *cmux, circuit_t *circ);
|
||||
int circuitmux_is_circuit_active(circuitmux_t *cmux, circuit_t *circ);
|
||||
unsigned int circuitmux_num_cells_for_circuit(circuitmux_t *cmux,
|
||||
circuit_t *circ);
|
||||
unsigned int circuitmux_num_cells(circuitmux_t *cmux);
|
||||
unsigned int circuitmux_num_circuits(circuitmux_t *cmux);
|
||||
unsigned int circuitmux_num_active_circuits(circuitmux_t *cmux);
|
||||
|
||||
/* Channel interface */
|
||||
circuit_t * circuitmux_get_first_active_circuit(circuitmux_t *cmux,
|
||||
cell_queue_t **destroy_queue_out);
|
||||
void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
|
||||
unsigned int n_cells);
|
||||
void circuitmux_notify_xmit_destroy(circuitmux_t *cmux);
|
||||
|
||||
/* Circuit interface */
|
||||
MOCK_DECL(void, circuitmux_attach_circuit, (circuitmux_t *cmux,
|
||||
circuit_t *circ,
|
||||
cell_direction_t direction));
|
||||
MOCK_DECL(void, circuitmux_detach_circuit,
|
||||
(circuitmux_t *cmux, circuit_t *circ));
|
||||
void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ);
|
||||
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
|
||||
unsigned int n_cells);
|
||||
|
||||
void circuitmux_append_destroy_cell(channel_t *chan,
|
||||
circuitmux_t *cmux, circid_t circ_id,
|
||||
uint8_t reason);
|
||||
void circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux,
|
||||
channel_t *chan);
|
||||
|
||||
#endif /* TOR_CIRCUITMUX_H */
|
||||
|
||||
@@ -1,684 +0,0 @@
|
||||
/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitmux_ewma.c
|
||||
* \brief EWMA circuit selection as a circuitmux_t policy
|
||||
**/
|
||||
|
||||
#define TOR_CIRCUITMUX_EWMA_C_
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "or.h"
|
||||
#include "circuitmux.h"
|
||||
#include "circuitmux_ewma.h"
|
||||
#include "networkstatus.h"
|
||||
|
||||
/*** EWMA parameter #defines ***/
|
||||
|
||||
/** How long does a tick last (seconds)? */
|
||||
#define EWMA_TICK_LEN 10
|
||||
|
||||
/** The default per-tick scale factor, if it hasn't been overridden by a
|
||||
* consensus or a configuration setting. zero means "disabled". */
|
||||
#define EWMA_DEFAULT_HALFLIFE 0.0
|
||||
|
||||
/*** Some useful constant #defines ***/
|
||||
|
||||
/*DOCDOC*/
|
||||
#define EPSILON 0.00001
|
||||
/*DOCDOC*/
|
||||
#define LOG_ONEHALF -0.69314718055994529
|
||||
|
||||
/*** EWMA structures ***/
|
||||
|
||||
typedef struct cell_ewma_s cell_ewma_t;
|
||||
typedef struct ewma_policy_data_s ewma_policy_data_t;
|
||||
typedef struct ewma_policy_circ_data_s ewma_policy_circ_data_t;
|
||||
|
||||
/**
|
||||
* The cell_ewma_t structure keeps track of how many cells a circuit has
|
||||
* transferred recently. It keeps an EWMA (exponentially weighted moving
|
||||
* average) of the number of cells flushed from the circuit queue onto a
|
||||
* connection in channel_flush_from_first_active_circuit().
|
||||
*/
|
||||
|
||||
struct cell_ewma_s {
|
||||
/** The last 'tick' at which we recalibrated cell_count.
|
||||
*
|
||||
* A cell sent at exactly the start of this tick has weight 1.0. Cells sent
|
||||
* since the start of this tick have weight greater than 1.0; ones sent
|
||||
* earlier have less weight. */
|
||||
unsigned int last_adjusted_tick;
|
||||
/** The EWMA of the cell count. */
|
||||
double cell_count;
|
||||
/** True iff this is the cell count for a circuit's previous
|
||||
* channel. */
|
||||
unsigned int is_for_p_chan : 1;
|
||||
/** The position of the circuit within the OR connection's priority
|
||||
* queue. */
|
||||
int heap_index;
|
||||
};
|
||||
|
||||
struct ewma_policy_data_s {
|
||||
circuitmux_policy_data_t base_;
|
||||
|
||||
/**
|
||||
* Priority queue of cell_ewma_t for circuits with queued cells waiting
|
||||
* for room to free up on the channel that owns this circuitmux. Kept
|
||||
* in heap order according to EWMA. This was formerly in channel_t, and
|
||||
* in or_connection_t before that.
|
||||
*/
|
||||
smartlist_t *active_circuit_pqueue;
|
||||
|
||||
/**
|
||||
* The tick on which the cell_ewma_ts in active_circuit_pqueue last had
|
||||
* their ewma values rescaled. This was formerly in channel_t, and in
|
||||
* or_connection_t before that.
|
||||
*/
|
||||
unsigned int active_circuit_pqueue_last_recalibrated;
|
||||
};
|
||||
|
||||
struct ewma_policy_circ_data_s {
|
||||
circuitmux_policy_circ_data_t base_;
|
||||
|
||||
/**
|
||||
* The EWMA count for the number of cells flushed from this circuit
|
||||
* onto this circuitmux. Used to determine which circuit to flush
|
||||
* from next. This was formerly in circuit_t and or_circuit_t.
|
||||
*/
|
||||
cell_ewma_t cell_ewma;
|
||||
|
||||
/**
|
||||
* Pointer back to the circuit_t this is for; since we're separating
|
||||
* out circuit selection policy like this, we can't attach cell_ewma_t
|
||||
* to the circuit_t any more, so we can't use SUBTYPE_P directly to a
|
||||
* circuit_t like before; instead get it here.
|
||||
*/
|
||||
circuit_t *circ;
|
||||
};
|
||||
|
||||
#define EWMA_POL_DATA_MAGIC 0x2fd8b16aU
|
||||
#define EWMA_POL_CIRC_DATA_MAGIC 0x761e7747U
|
||||
|
||||
/*** Downcasts for the above types ***/
|
||||
|
||||
static ewma_policy_data_t *
|
||||
TO_EWMA_POL_DATA(circuitmux_policy_data_t *);
|
||||
|
||||
static ewma_policy_circ_data_t *
|
||||
TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *);
|
||||
|
||||
/**
|
||||
* Downcast a circuitmux_policy_data_t to an ewma_policy_data_t and assert
|
||||
* if the cast is impossible.
|
||||
*/
|
||||
|
||||
static INLINE ewma_policy_data_t *
|
||||
TO_EWMA_POL_DATA(circuitmux_policy_data_t *pol)
|
||||
{
|
||||
if (!pol) return NULL;
|
||||
else {
|
||||
tor_assert(pol->magic == EWMA_POL_DATA_MAGIC);
|
||||
return DOWNCAST(ewma_policy_data_t, pol);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downcast a circuitmux_policy_circ_data_t to an ewma_policy_circ_data_t
|
||||
* and assert if the cast is impossible.
|
||||
*/
|
||||
|
||||
static INLINE ewma_policy_circ_data_t *
|
||||
TO_EWMA_POL_CIRC_DATA(circuitmux_policy_circ_data_t *pol)
|
||||
{
|
||||
if (!pol) return NULL;
|
||||
else {
|
||||
tor_assert(pol->magic == EWMA_POL_CIRC_DATA_MAGIC);
|
||||
return DOWNCAST(ewma_policy_circ_data_t, pol);
|
||||
}
|
||||
}
|
||||
|
||||
/*** Static declarations for circuitmux_ewma.c ***/
|
||||
|
||||
static void add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
|
||||
static int compare_cell_ewma_counts(const void *p1, const void *p2);
|
||||
static unsigned cell_ewma_tick_from_timeval(const struct timeval *now,
|
||||
double *remainder_out);
|
||||
static circuit_t * cell_ewma_to_circuit(cell_ewma_t *ewma);
|
||||
static INLINE double get_scale_factor(unsigned from_tick, unsigned to_tick);
|
||||
static cell_ewma_t * pop_first_cell_ewma(ewma_policy_data_t *pol);
|
||||
static void remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma);
|
||||
static void scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick);
|
||||
static void scale_active_circuits(ewma_policy_data_t *pol,
|
||||
unsigned cur_tick);
|
||||
|
||||
/*** Circuitmux policy methods ***/
|
||||
|
||||
static circuitmux_policy_data_t * ewma_alloc_cmux_data(circuitmux_t *cmux);
|
||||
static void ewma_free_cmux_data(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data);
|
||||
static circuitmux_policy_circ_data_t *
|
||||
ewma_alloc_circ_data(circuitmux_t *cmux, circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ, cell_direction_t direction,
|
||||
unsigned int cell_count);
|
||||
static void
|
||||
ewma_free_circ_data(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data);
|
||||
static void
|
||||
ewma_notify_circ_active(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data);
|
||||
static void
|
||||
ewma_notify_circ_inactive(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data);
|
||||
static void
|
||||
ewma_notify_xmit_cells(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data,
|
||||
unsigned int n_cells);
|
||||
static circuit_t *
|
||||
ewma_pick_active_circuit(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data);
|
||||
|
||||
/*** EWMA global variables ***/
|
||||
|
||||
/** The per-tick scale factor to be used when computing cell-count EWMA
|
||||
* values. (A cell sent N ticks before the start of the current tick
|
||||
* has value ewma_scale_factor ** N.)
|
||||
*/
|
||||
static double ewma_scale_factor = 0.1;
|
||||
/* DOCDOC ewma_enabled */
|
||||
static int ewma_enabled = 0;
|
||||
|
||||
/*** EWMA circuitmux_policy_t method table ***/
|
||||
|
||||
circuitmux_policy_t ewma_policy = {
|
||||
/*.alloc_cmux_data =*/ ewma_alloc_cmux_data,
|
||||
/*.free_cmux_data =*/ ewma_free_cmux_data,
|
||||
/*.alloc_circ_data =*/ ewma_alloc_circ_data,
|
||||
/*.free_circ_data =*/ ewma_free_circ_data,
|
||||
/*.notify_circ_active =*/ ewma_notify_circ_active,
|
||||
/*.notify_circ_inactive =*/ ewma_notify_circ_inactive,
|
||||
/*.notify_set_n_cells =*/ NULL, /* EWMA doesn't need this */
|
||||
/*.notify_xmit_cells =*/ ewma_notify_xmit_cells,
|
||||
/*.pick_active_circuit =*/ ewma_pick_active_circuit
|
||||
};
|
||||
|
||||
/*** EWMA method implementations using the below EWMA helper functions ***/
|
||||
|
||||
/**
|
||||
* Allocate an ewma_policy_data_t and upcast it to a circuitmux_policy_data_t;
|
||||
* this is called when setting the policy on a circuitmux_t to ewma_policy.
|
||||
*/
|
||||
|
||||
static circuitmux_policy_data_t *
|
||||
ewma_alloc_cmux_data(circuitmux_t *cmux)
|
||||
{
|
||||
ewma_policy_data_t *pol = NULL;
|
||||
|
||||
tor_assert(cmux);
|
||||
|
||||
pol = tor_malloc_zero(sizeof(*pol));
|
||||
pol->base_.magic = EWMA_POL_DATA_MAGIC;
|
||||
pol->active_circuit_pqueue = smartlist_new();
|
||||
pol->active_circuit_pqueue_last_recalibrated = cell_ewma_get_tick();
|
||||
|
||||
return TO_CMUX_POL_DATA(pol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an ewma_policy_data_t allocated with ewma_alloc_cmux_data()
|
||||
*/
|
||||
|
||||
static void
|
||||
ewma_free_cmux_data(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data)
|
||||
{
|
||||
ewma_policy_data_t *pol = NULL;
|
||||
|
||||
tor_assert(cmux);
|
||||
if (!pol_data) return;
|
||||
|
||||
pol = TO_EWMA_POL_DATA(pol_data);
|
||||
|
||||
smartlist_free(pol->active_circuit_pqueue);
|
||||
tor_free(pol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate an ewma_policy_circ_data_t and upcast it to a
|
||||
* circuitmux_policy_data_t; this is called when attaching a circuit to a
|
||||
* circuitmux_t with ewma_policy.
|
||||
*/
|
||||
|
||||
static circuitmux_policy_circ_data_t *
|
||||
ewma_alloc_circ_data(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
cell_direction_t direction,
|
||||
unsigned int cell_count)
|
||||
{
|
||||
ewma_policy_circ_data_t *cdata = NULL;
|
||||
|
||||
tor_assert(cmux);
|
||||
tor_assert(pol_data);
|
||||
tor_assert(circ);
|
||||
tor_assert(direction == CELL_DIRECTION_OUT ||
|
||||
direction == CELL_DIRECTION_IN);
|
||||
/* Shut the compiler up */
|
||||
tor_assert(cell_count == cell_count);
|
||||
|
||||
cdata = tor_malloc_zero(sizeof(*cdata));
|
||||
cdata->base_.magic = EWMA_POL_CIRC_DATA_MAGIC;
|
||||
cdata->circ = circ;
|
||||
|
||||
/*
|
||||
* Initialize the cell_ewma_t structure (formerly in
|
||||
* init_circuit_base())
|
||||
*/
|
||||
cdata->cell_ewma.last_adjusted_tick = cell_ewma_get_tick();
|
||||
cdata->cell_ewma.cell_count = 0.0;
|
||||
cdata->cell_ewma.heap_index = -1;
|
||||
if (direction == CELL_DIRECTION_IN) {
|
||||
cdata->cell_ewma.is_for_p_chan = 1;
|
||||
} else {
|
||||
cdata->cell_ewma.is_for_p_chan = 0;
|
||||
}
|
||||
|
||||
return TO_CMUX_POL_CIRC_DATA(cdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free an ewma_policy_circ_data_t allocated with ewma_alloc_circ_data()
|
||||
*/
|
||||
|
||||
static void
|
||||
ewma_free_circ_data(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data)
|
||||
|
||||
{
|
||||
ewma_policy_circ_data_t *cdata = NULL;
|
||||
|
||||
tor_assert(cmux);
|
||||
tor_assert(circ);
|
||||
tor_assert(pol_data);
|
||||
|
||||
if (!pol_circ_data) return;
|
||||
|
||||
cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
|
||||
|
||||
tor_free(cdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle circuit activation; this inserts the circuit's cell_ewma into
|
||||
* the active_circuits_pqueue.
|
||||
*/
|
||||
|
||||
static void
|
||||
ewma_notify_circ_active(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data)
|
||||
{
|
||||
ewma_policy_data_t *pol = NULL;
|
||||
ewma_policy_circ_data_t *cdata = NULL;
|
||||
|
||||
tor_assert(cmux);
|
||||
tor_assert(pol_data);
|
||||
tor_assert(circ);
|
||||
tor_assert(pol_circ_data);
|
||||
|
||||
pol = TO_EWMA_POL_DATA(pol_data);
|
||||
cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
|
||||
|
||||
add_cell_ewma(pol, &(cdata->cell_ewma));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle circuit deactivation; this removes the circuit's cell_ewma from
|
||||
* the active_circuits_pqueue.
|
||||
*/
|
||||
|
||||
static void
|
||||
ewma_notify_circ_inactive(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data)
|
||||
{
|
||||
ewma_policy_data_t *pol = NULL;
|
||||
ewma_policy_circ_data_t *cdata = NULL;
|
||||
|
||||
tor_assert(cmux);
|
||||
tor_assert(pol_data);
|
||||
tor_assert(circ);
|
||||
tor_assert(pol_circ_data);
|
||||
|
||||
pol = TO_EWMA_POL_DATA(pol_data);
|
||||
cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
|
||||
|
||||
remove_cell_ewma(pol, &(cdata->cell_ewma));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cell_ewma for this circuit after we've sent some cells, and
|
||||
* remove/reinsert it in the queue. This used to be done (brokenly,
|
||||
* see bug 6816) in channel_flush_from_first_active_circuit().
|
||||
*/
|
||||
|
||||
static void
|
||||
ewma_notify_xmit_cells(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data,
|
||||
circuit_t *circ,
|
||||
circuitmux_policy_circ_data_t *pol_circ_data,
|
||||
unsigned int n_cells)
|
||||
{
|
||||
ewma_policy_data_t *pol = NULL;
|
||||
ewma_policy_circ_data_t *cdata = NULL;
|
||||
unsigned int tick;
|
||||
double fractional_tick, ewma_increment;
|
||||
/* The current (hi-res) time */
|
||||
struct timeval now_hires;
|
||||
cell_ewma_t *cell_ewma, *tmp;
|
||||
|
||||
tor_assert(cmux);
|
||||
tor_assert(pol_data);
|
||||
tor_assert(circ);
|
||||
tor_assert(pol_circ_data);
|
||||
tor_assert(n_cells > 0);
|
||||
|
||||
pol = TO_EWMA_POL_DATA(pol_data);
|
||||
cdata = TO_EWMA_POL_CIRC_DATA(pol_circ_data);
|
||||
|
||||
/* Rescale the EWMAs if needed */
|
||||
tor_gettimeofday_cached(&now_hires);
|
||||
tick = cell_ewma_tick_from_timeval(&now_hires, &fractional_tick);
|
||||
|
||||
if (tick != pol->active_circuit_pqueue_last_recalibrated) {
|
||||
scale_active_circuits(pol, tick);
|
||||
}
|
||||
|
||||
/* How much do we adjust the cell count in cell_ewma by? */
|
||||
ewma_increment =
|
||||
((double)(n_cells)) * pow(ewma_scale_factor, -fractional_tick);
|
||||
|
||||
/* Do the adjustment */
|
||||
cell_ewma = &(cdata->cell_ewma);
|
||||
cell_ewma->cell_count += ewma_increment;
|
||||
|
||||
/*
|
||||
* Since we just sent on this circuit, it should be at the head of
|
||||
* the queue. Pop the head, assert that it matches, then re-add.
|
||||
*/
|
||||
tmp = pop_first_cell_ewma(pol);
|
||||
tor_assert(tmp == cell_ewma);
|
||||
add_cell_ewma(pol, cell_ewma);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick the preferred circuit to send from; this will be the one with
|
||||
* the lowest EWMA value in the priority queue. This used to be done
|
||||
* in channel_flush_from_first_active_circuit().
|
||||
*/
|
||||
|
||||
static circuit_t *
|
||||
ewma_pick_active_circuit(circuitmux_t *cmux,
|
||||
circuitmux_policy_data_t *pol_data)
|
||||
{
|
||||
ewma_policy_data_t *pol = NULL;
|
||||
circuit_t *circ = NULL;
|
||||
cell_ewma_t *cell_ewma = NULL;
|
||||
|
||||
tor_assert(cmux);
|
||||
tor_assert(pol_data);
|
||||
|
||||
pol = TO_EWMA_POL_DATA(pol_data);
|
||||
|
||||
if (smartlist_len(pol->active_circuit_pqueue) > 0) {
|
||||
/* Get the head of the queue */
|
||||
cell_ewma = smartlist_get(pol->active_circuit_pqueue, 0);
|
||||
circ = cell_ewma_to_circuit(cell_ewma);
|
||||
}
|
||||
|
||||
return circ;
|
||||
}
|
||||
|
||||
/** Helper for sorting cell_ewma_t values in their priority queue. */
|
||||
static int
|
||||
compare_cell_ewma_counts(const void *p1, const void *p2)
|
||||
{
|
||||
const cell_ewma_t *e1 = p1, *e2 = p2;
|
||||
|
||||
if (e1->cell_count < e2->cell_count)
|
||||
return -1;
|
||||
else if (e1->cell_count > e2->cell_count)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Given a cell_ewma_t, return a pointer to the circuit containing it. */
|
||||
static circuit_t *
|
||||
cell_ewma_to_circuit(cell_ewma_t *ewma)
|
||||
{
|
||||
ewma_policy_circ_data_t *cdata = NULL;
|
||||
|
||||
tor_assert(ewma);
|
||||
cdata = SUBTYPE_P(ewma, ewma_policy_circ_data_t, cell_ewma);
|
||||
tor_assert(cdata);
|
||||
|
||||
return cdata->circ;
|
||||
}
|
||||
|
||||
/* ==== Functions for scaling cell_ewma_t ====
|
||||
|
||||
When choosing which cells to relay first, we favor circuits that have been
|
||||
quiet recently. This gives better latency on connections that aren't
|
||||
pushing lots of data, and makes the network feel more interactive.
|
||||
|
||||
Conceptually, we take an exponentially weighted mean average of the number
|
||||
of cells a circuit has sent, and allow active circuits (those with cells to
|
||||
relay) to send cells in reverse order of their exponentially-weighted mean
|
||||
average (EWMA) cell count. [That is, a cell sent N seconds ago 'counts'
|
||||
F^N times as much as a cell sent now, for 0<F<1.0, and we favor the
|
||||
circuit that has sent the fewest cells]
|
||||
|
||||
If 'double' had infinite precision, we could do this simply by counting a
|
||||
cell sent at startup as having weight 1.0, and a cell sent N seconds later
|
||||
as having weight F^-N. This way, we would never need to re-scale
|
||||
any already-sent cells.
|
||||
|
||||
To prevent double from overflowing, we could count a cell sent now as
|
||||
having weight 1.0 and a cell sent N seconds ago as having weight F^N.
|
||||
This, however, would mean we'd need to re-scale *ALL* old circuits every
|
||||
time we wanted to send a cell.
|
||||
|
||||
So as a compromise, we divide time into 'ticks' (currently, 10-second
|
||||
increments) and say that a cell sent at the start of a current tick is
|
||||
worth 1.0, a cell sent N seconds before the start of the current tick is
|
||||
worth F^N, and a cell sent N seconds after the start of the current tick is
|
||||
worth F^-N. This way we don't overflow, and we don't need to constantly
|
||||
rescale.
|
||||
*/
|
||||
|
||||
/** Given a timeval <b>now</b>, compute the cell_ewma tick in which it occurs
|
||||
* and the fraction of the tick that has elapsed between the start of the tick
|
||||
* and <b>now</b>. Return the former and store the latter in
|
||||
* *<b>remainder_out</b>.
|
||||
*
|
||||
* These tick values are not meant to be shared between Tor instances, or used
|
||||
* for other purposes. */
|
||||
|
||||
static unsigned
|
||||
cell_ewma_tick_from_timeval(const struct timeval *now,
|
||||
double *remainder_out)
|
||||
{
|
||||
unsigned res = (unsigned) (now->tv_sec / EWMA_TICK_LEN);
|
||||
/* rem */
|
||||
double rem = (now->tv_sec % EWMA_TICK_LEN) +
|
||||
((double)(now->tv_usec)) / 1.0e6;
|
||||
*remainder_out = rem / EWMA_TICK_LEN;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** Tell the caller whether ewma_enabled is set */
|
||||
int
|
||||
cell_ewma_enabled(void)
|
||||
{
|
||||
return ewma_enabled;
|
||||
}
|
||||
|
||||
/** Compute and return the current cell_ewma tick. */
|
||||
unsigned int
|
||||
cell_ewma_get_tick(void)
|
||||
{
|
||||
return ((unsigned)approx_time() / EWMA_TICK_LEN);
|
||||
}
|
||||
|
||||
/** Adjust the global cell scale factor based on <b>options</b> */
|
||||
void
|
||||
cell_ewma_set_scale_factor(const or_options_t *options,
|
||||
const networkstatus_t *consensus)
|
||||
{
|
||||
int32_t halflife_ms;
|
||||
double halflife;
|
||||
const char *source;
|
||||
if (options && options->CircuitPriorityHalflife >= -EPSILON) {
|
||||
halflife = options->CircuitPriorityHalflife;
|
||||
source = "CircuitPriorityHalflife in configuration";
|
||||
} else if (consensus && (halflife_ms = networkstatus_get_param(
|
||||
consensus, "CircuitPriorityHalflifeMsec",
|
||||
-1, -1, INT32_MAX)) >= 0) {
|
||||
halflife = ((double)halflife_ms)/1000.0;
|
||||
source = "CircuitPriorityHalflifeMsec in consensus";
|
||||
} else {
|
||||
halflife = EWMA_DEFAULT_HALFLIFE;
|
||||
source = "Default value";
|
||||
}
|
||||
|
||||
if (halflife <= EPSILON) {
|
||||
/* The cell EWMA algorithm is disabled. */
|
||||
ewma_scale_factor = 0.1;
|
||||
ewma_enabled = 0;
|
||||
log_info(LD_OR,
|
||||
"Disabled cell_ewma algorithm because of value in %s",
|
||||
source);
|
||||
} else {
|
||||
/* convert halflife into halflife-per-tick. */
|
||||
halflife /= EWMA_TICK_LEN;
|
||||
/* compute per-tick scale factor. */
|
||||
ewma_scale_factor = exp( LOG_ONEHALF / halflife );
|
||||
ewma_enabled = 1;
|
||||
log_info(LD_OR,
|
||||
"Enabled cell_ewma algorithm because of value in %s; "
|
||||
"scale factor is %f per %d seconds",
|
||||
source, ewma_scale_factor, EWMA_TICK_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
/** Return the multiplier necessary to convert the value of a cell sent in
|
||||
* 'from_tick' to one sent in 'to_tick'. */
|
||||
static INLINE double
|
||||
get_scale_factor(unsigned from_tick, unsigned to_tick)
|
||||
{
|
||||
/* This math can wrap around, but that's okay: unsigned overflow is
|
||||
well-defined */
|
||||
int diff = (int)(to_tick - from_tick);
|
||||
return pow(ewma_scale_factor, diff);
|
||||
}
|
||||
|
||||
/** Adjust the cell count of <b>ewma</b> so that it is scaled with respect to
|
||||
* <b>cur_tick</b> */
|
||||
static void
|
||||
scale_single_cell_ewma(cell_ewma_t *ewma, unsigned cur_tick)
|
||||
{
|
||||
double factor = get_scale_factor(ewma->last_adjusted_tick, cur_tick);
|
||||
ewma->cell_count *= factor;
|
||||
ewma->last_adjusted_tick = cur_tick;
|
||||
}
|
||||
|
||||
/** Adjust the cell count of every active circuit on <b>chan</b> so
|
||||
* that they are scaled with respect to <b>cur_tick</b> */
|
||||
static void
|
||||
scale_active_circuits(ewma_policy_data_t *pol, unsigned cur_tick)
|
||||
{
|
||||
double factor;
|
||||
|
||||
tor_assert(pol);
|
||||
tor_assert(pol->active_circuit_pqueue);
|
||||
|
||||
factor =
|
||||
get_scale_factor(
|
||||
pol->active_circuit_pqueue_last_recalibrated,
|
||||
cur_tick);
|
||||
/** Ordinarily it isn't okay to change the value of an element in a heap,
|
||||
* but it's okay here, since we are preserving the order. */
|
||||
SMARTLIST_FOREACH_BEGIN(
|
||||
pol->active_circuit_pqueue,
|
||||
cell_ewma_t *, e) {
|
||||
tor_assert(e->last_adjusted_tick ==
|
||||
pol->active_circuit_pqueue_last_recalibrated);
|
||||
e->cell_count *= factor;
|
||||
e->last_adjusted_tick = cur_tick;
|
||||
} SMARTLIST_FOREACH_END(e);
|
||||
pol->active_circuit_pqueue_last_recalibrated = cur_tick;
|
||||
}
|
||||
|
||||
/** Rescale <b>ewma</b> to the same scale as <b>pol</b>, and add it to
|
||||
* <b>pol</b>'s priority queue of active circuits */
|
||||
static void
|
||||
add_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
|
||||
{
|
||||
tor_assert(pol);
|
||||
tor_assert(pol->active_circuit_pqueue);
|
||||
tor_assert(ewma);
|
||||
tor_assert(ewma->heap_index == -1);
|
||||
|
||||
scale_single_cell_ewma(
|
||||
ewma,
|
||||
pol->active_circuit_pqueue_last_recalibrated);
|
||||
|
||||
smartlist_pqueue_add(pol->active_circuit_pqueue,
|
||||
compare_cell_ewma_counts,
|
||||
STRUCT_OFFSET(cell_ewma_t, heap_index),
|
||||
ewma);
|
||||
}
|
||||
|
||||
/** Remove <b>ewma</b> from <b>pol</b>'s priority queue of active circuits */
|
||||
static void
|
||||
remove_cell_ewma(ewma_policy_data_t *pol, cell_ewma_t *ewma)
|
||||
{
|
||||
tor_assert(pol);
|
||||
tor_assert(pol->active_circuit_pqueue);
|
||||
tor_assert(ewma);
|
||||
tor_assert(ewma->heap_index != -1);
|
||||
|
||||
smartlist_pqueue_remove(pol->active_circuit_pqueue,
|
||||
compare_cell_ewma_counts,
|
||||
STRUCT_OFFSET(cell_ewma_t, heap_index),
|
||||
ewma);
|
||||
}
|
||||
|
||||
/** Remove and return the first cell_ewma_t from pol's priority queue of
|
||||
* active circuits. Requires that the priority queue is nonempty. */
|
||||
static cell_ewma_t *
|
||||
pop_first_cell_ewma(ewma_policy_data_t *pol)
|
||||
{
|
||||
tor_assert(pol);
|
||||
tor_assert(pol->active_circuit_pqueue);
|
||||
|
||||
return smartlist_pqueue_pop(pol->active_circuit_pqueue,
|
||||
compare_cell_ewma_counts,
|
||||
STRUCT_OFFSET(cell_ewma_t, heap_index));
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/* * Copyright (c) 2012-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitmux_ewma.h
|
||||
* \brief Header file for circuitmux_ewma.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCUITMUX_EWMA_H
|
||||
#define TOR_CIRCUITMUX_EWMA_H
|
||||
|
||||
#include "or.h"
|
||||
#include "circuitmux.h"
|
||||
|
||||
/* Everything but circuitmux_ewma.c should see this extern */
|
||||
#ifndef TOR_CIRCUITMUX_EWMA_C_
|
||||
|
||||
extern circuitmux_policy_t ewma_policy;
|
||||
|
||||
#endif /* !(TOR_CIRCUITMUX_EWMA_C_) */
|
||||
|
||||
/* Externally visible EWMA functions */
|
||||
int cell_ewma_enabled(void);
|
||||
unsigned int cell_ewma_get_tick(void);
|
||||
void cell_ewma_set_scale_factor(const or_options_t *options,
|
||||
const networkstatus_t *consensus);
|
||||
|
||||
#endif /* TOR_CIRCUITMUX_EWMA_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,98 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuitstats.h
|
||||
* \brief Header file for circuitstats.c
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCUITSTATS_H
|
||||
#define TOR_CIRCUITSTATS_H
|
||||
|
||||
const circuit_build_times_t *get_circuit_build_times(void);
|
||||
circuit_build_times_t *get_circuit_build_times_mutable(void);
|
||||
double get_circuit_build_close_time_ms(void);
|
||||
double get_circuit_build_timeout_ms(void);
|
||||
|
||||
int circuit_build_times_disabled(void);
|
||||
int circuit_build_times_enough_to_compute(const circuit_build_times_t *cbt);
|
||||
void circuit_build_times_update_state(const circuit_build_times_t *cbt,
|
||||
or_state_t *state);
|
||||
int circuit_build_times_parse_state(circuit_build_times_t *cbt,
|
||||
or_state_t *state);
|
||||
void circuit_build_times_count_timeout(circuit_build_times_t *cbt,
|
||||
int did_onehop);
|
||||
int circuit_build_times_count_close(circuit_build_times_t *cbt,
|
||||
int did_onehop, time_t start_time);
|
||||
void circuit_build_times_set_timeout(circuit_build_times_t *cbt);
|
||||
int circuit_build_times_add_time(circuit_build_times_t *cbt,
|
||||
build_time_t time);
|
||||
int circuit_build_times_needs_circuits(const circuit_build_times_t *cbt);
|
||||
|
||||
int circuit_build_times_needs_circuits_now(const circuit_build_times_t *cbt);
|
||||
void circuit_build_times_init(circuit_build_times_t *cbt);
|
||||
void circuit_build_times_free_timeouts(circuit_build_times_t *cbt);
|
||||
void circuit_build_times_new_consensus_params(circuit_build_times_t *cbt,
|
||||
networkstatus_t *ns);
|
||||
double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
|
||||
double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
|
||||
|
||||
void circuit_build_times_update_last_circ(circuit_build_times_t *cbt);
|
||||
|
||||
#ifdef CIRCUITSTATS_PRIVATE
|
||||
STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
|
||||
double quantile);
|
||||
STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
|
||||
STATIC void circuit_build_times_reset(circuit_build_times_t *cbt);
|
||||
|
||||
/* Network liveness functions */
|
||||
STATIC int circuit_build_times_network_check_changed(
|
||||
circuit_build_times_t *cbt);
|
||||
#endif
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
|
||||
double q_lo, double q_hi);
|
||||
double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
|
||||
void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
|
||||
double quantile, double time_ms);
|
||||
void circuitbuild_running_unit_tests(void);
|
||||
#endif
|
||||
|
||||
/* Network liveness functions */
|
||||
void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
|
||||
int circuit_build_times_network_check_live(const circuit_build_times_t *cbt);
|
||||
void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
|
||||
|
||||
#ifdef CIRCUITSTATS_PRIVATE
|
||||
/** Structure for circuit build times history */
|
||||
struct circuit_build_times_s {
|
||||
/** The circular array of recorded build times in milliseconds */
|
||||
build_time_t circuit_build_times[CBT_NCIRCUITS_TO_OBSERVE];
|
||||
/** Current index in the circuit_build_times circular array */
|
||||
int build_times_idx;
|
||||
/** Total number of build times accumulated. Max CBT_NCIRCUITS_TO_OBSERVE */
|
||||
int total_build_times;
|
||||
/** Information about the state of our local network connection */
|
||||
network_liveness_t liveness;
|
||||
/** Last time we built a circuit. Used to decide to build new test circs */
|
||||
time_t last_circ_at;
|
||||
/** "Minimum" value of our pareto distribution (actually mode) */
|
||||
build_time_t Xm;
|
||||
/** alpha exponent for pareto dist. */
|
||||
double alpha;
|
||||
/** Have we computed a timeout? */
|
||||
int have_computed_timeout;
|
||||
/** The exact value for that timeout in milliseconds. Stored as a double
|
||||
* to maintain precision from calculations to and from quantile value. */
|
||||
double timeout_ms;
|
||||
/** How long we wait before actually closing the circuit. */
|
||||
double close_ms;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,61 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file circuituse.h
|
||||
* \brief Header file for circuituse.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_CIRCUITUSE_H
|
||||
#define TOR_CIRCUITUSE_H
|
||||
|
||||
void circuit_expire_building(void);
|
||||
void circuit_remove_handled_ports(smartlist_t *needed_ports);
|
||||
int circuit_stream_is_being_handled(entry_connection_t *conn, uint16_t port,
|
||||
int min);
|
||||
#if 0
|
||||
int circuit_conforms_to_options(const origin_circuit_t *circ,
|
||||
const or_options_t *options);
|
||||
#endif
|
||||
void circuit_build_needed_circs(time_t now);
|
||||
void circuit_detach_stream(circuit_t *circ, edge_connection_t *conn);
|
||||
|
||||
void circuit_expire_old_circuits_serverside(time_t now);
|
||||
|
||||
void reset_bandwidth_test(void);
|
||||
int circuit_enough_testing_circs(void);
|
||||
|
||||
void circuit_has_opened(origin_circuit_t *circ);
|
||||
void circuit_try_attaching_streams(origin_circuit_t *circ);
|
||||
void circuit_build_failed(origin_circuit_t *circ);
|
||||
|
||||
/** Flag to set when a circuit should have only a single hop. */
|
||||
#define CIRCLAUNCH_ONEHOP_TUNNEL (1<<0)
|
||||
/** Flag to set when a circuit needs to be built of high-uptime nodes */
|
||||
#define CIRCLAUNCH_NEED_UPTIME (1<<1)
|
||||
/** Flag to set when a circuit needs to be built of high-capacity nodes */
|
||||
#define CIRCLAUNCH_NEED_CAPACITY (1<<2)
|
||||
/** Flag to set when the last hop of a circuit doesn't need to be an
|
||||
* exit node. */
|
||||
#define CIRCLAUNCH_IS_INTERNAL (1<<3)
|
||||
origin_circuit_t *circuit_launch_by_extend_info(uint8_t purpose,
|
||||
extend_info_t *info,
|
||||
int flags);
|
||||
origin_circuit_t *circuit_launch(uint8_t purpose, int flags);
|
||||
void circuit_reset_failure_count(int timeout);
|
||||
int connection_ap_handshake_attach_chosen_circuit(entry_connection_t *conn,
|
||||
origin_circuit_t *circ,
|
||||
crypt_path_t *cpath);
|
||||
int connection_ap_handshake_attach_circuit(entry_connection_t *conn);
|
||||
|
||||
void circuit_change_purpose(circuit_t *circ, uint8_t new_purpose);
|
||||
|
||||
int hostname_in_track_host_exits(const or_options_t *options,
|
||||
const char *address);
|
||||
void mark_circuit_unusable_for_new_conns(origin_circuit_t *circ);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,589 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file command.c
|
||||
* \brief Functions for processing incoming cells.
|
||||
**/
|
||||
|
||||
/* In-points to command.c:
|
||||
*
|
||||
* - command_process_cell(), called from
|
||||
* incoming cell handlers of channel_t instances;
|
||||
* callbacks registered in command_setup_channel(),
|
||||
* called when channels are created in circuitbuild.c
|
||||
*/
|
||||
#include "or.h"
|
||||
#include "channel.h"
|
||||
#include "circuitbuild.h"
|
||||
#include "circuitlist.h"
|
||||
#include "command.h"
|
||||
#include "connection.h"
|
||||
#include "connection_or.h"
|
||||
#include "config.h"
|
||||
#include "control.h"
|
||||
#include "cpuworker.h"
|
||||
#include "hibernate.h"
|
||||
#include "nodelist.h"
|
||||
#include "onion.h"
|
||||
#include "rephist.h"
|
||||
#include "relay.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
|
||||
/** How many CELL_CREATE cells have we received, ever? */
|
||||
uint64_t stats_n_create_cells_processed = 0;
|
||||
/** How many CELL_CREATED cells have we received, ever? */
|
||||
uint64_t stats_n_created_cells_processed = 0;
|
||||
/** How many CELL_RELAY cells have we received, ever? */
|
||||
uint64_t stats_n_relay_cells_processed = 0;
|
||||
/** How many CELL_DESTROY cells have we received, ever? */
|
||||
uint64_t stats_n_destroy_cells_processed = 0;
|
||||
|
||||
/* Handle an incoming channel */
|
||||
static void command_handle_incoming_channel(channel_listener_t *listener,
|
||||
channel_t *chan);
|
||||
|
||||
/* These are the main functions for processing cells */
|
||||
static void command_process_create_cell(cell_t *cell, channel_t *chan);
|
||||
static void command_process_created_cell(cell_t *cell, channel_t *chan);
|
||||
static void command_process_relay_cell(cell_t *cell, channel_t *chan);
|
||||
static void command_process_destroy_cell(cell_t *cell, channel_t *chan);
|
||||
|
||||
/** Convert the cell <b>command</b> into a lower-case, human-readable
|
||||
* string. */
|
||||
const char *
|
||||
cell_command_to_string(uint8_t command)
|
||||
{
|
||||
switch (command) {
|
||||
case CELL_PADDING: return "padding";
|
||||
case CELL_CREATE: return "create";
|
||||
case CELL_CREATED: return "created";
|
||||
case CELL_RELAY: return "relay";
|
||||
case CELL_DESTROY: return "destroy";
|
||||
case CELL_CREATE_FAST: return "create_fast";
|
||||
case CELL_CREATED_FAST: return "created_fast";
|
||||
case CELL_VERSIONS: return "versions";
|
||||
case CELL_NETINFO: return "netinfo";
|
||||
case CELL_RELAY_EARLY: return "relay_early";
|
||||
case CELL_CREATE2: return "create2";
|
||||
case CELL_CREATED2: return "created2";
|
||||
case CELL_VPADDING: return "vpadding";
|
||||
case CELL_CERTS: return "certs";
|
||||
case CELL_AUTH_CHALLENGE: return "auth_challenge";
|
||||
case CELL_AUTHENTICATE: return "authenticate";
|
||||
case CELL_AUTHORIZE: return "authorize";
|
||||
default: return "unrecognized";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef KEEP_TIMING_STATS
|
||||
/** This is a wrapper function around the actual function that processes the
|
||||
* <b>cell</b> that just arrived on <b>conn</b>. Increment <b>*time</b>
|
||||
* by the number of microseconds used by the call to <b>*func(cell, conn)</b>.
|
||||
*/
|
||||
static void
|
||||
command_time_process_cell(cell_t *cell, channel_t *chan, int *time,
|
||||
void (*func)(cell_t *, channel_t *))
|
||||
{
|
||||
struct timeval start, end;
|
||||
long time_passed;
|
||||
|
||||
tor_gettimeofday(&start);
|
||||
|
||||
(*func)(cell, chan);
|
||||
|
||||
tor_gettimeofday(&end);
|
||||
time_passed = tv_udiff(&start, &end) ;
|
||||
|
||||
if (time_passed > 10000) { /* more than 10ms */
|
||||
log_debug(LD_OR,"That call just took %ld ms.",time_passed/1000);
|
||||
}
|
||||
if (time_passed < 0) {
|
||||
log_info(LD_GENERAL,"That call took us back in time!");
|
||||
time_passed = 0;
|
||||
}
|
||||
*time += time_passed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Process a <b>cell</b> that was just received on <b>chan</b>. Keep internal
|
||||
* statistics about how many of each cell we've processed so far
|
||||
* this second, and the total number of microseconds it took to
|
||||
* process each type of cell.
|
||||
*/
|
||||
void
|
||||
command_process_cell(channel_t *chan, cell_t *cell)
|
||||
{
|
||||
#ifdef KEEP_TIMING_STATS
|
||||
/* how many of each cell have we seen so far this second? needs better
|
||||
* name. */
|
||||
static int num_create=0, num_created=0, num_relay=0, num_destroy=0;
|
||||
/* how long has it taken to process each type of cell? */
|
||||
static int create_time=0, created_time=0, relay_time=0, destroy_time=0;
|
||||
static time_t current_second = 0; /* from previous calls to time */
|
||||
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (now > current_second) { /* the second has rolled over */
|
||||
/* print stats */
|
||||
log_info(LD_OR,
|
||||
"At end of second: %d creates (%d ms), %d createds (%d ms), "
|
||||
"%d relays (%d ms), %d destroys (%d ms)",
|
||||
num_create, create_time/1000,
|
||||
num_created, created_time/1000,
|
||||
num_relay, relay_time/1000,
|
||||
num_destroy, destroy_time/1000);
|
||||
|
||||
/* zero out stats */
|
||||
num_create = num_created = num_relay = num_destroy = 0;
|
||||
create_time = created_time = relay_time = destroy_time = 0;
|
||||
|
||||
/* remember which second it is, for next time */
|
||||
current_second = now;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef KEEP_TIMING_STATS
|
||||
#define PROCESS_CELL(tp, cl, cn) STMT_BEGIN { \
|
||||
++num ## tp; \
|
||||
command_time_process_cell(cl, cn, & tp ## time , \
|
||||
command_process_ ## tp ## _cell); \
|
||||
} STMT_END
|
||||
#else
|
||||
#define PROCESS_CELL(tp, cl, cn) command_process_ ## tp ## _cell(cl, cn)
|
||||
#endif
|
||||
|
||||
switch (cell->command) {
|
||||
case CELL_CREATE:
|
||||
case CELL_CREATE_FAST:
|
||||
case CELL_CREATE2:
|
||||
++stats_n_create_cells_processed;
|
||||
PROCESS_CELL(create, cell, chan);
|
||||
break;
|
||||
case CELL_CREATED:
|
||||
case CELL_CREATED_FAST:
|
||||
case CELL_CREATED2:
|
||||
++stats_n_created_cells_processed;
|
||||
PROCESS_CELL(created, cell, chan);
|
||||
break;
|
||||
case CELL_RELAY:
|
||||
case CELL_RELAY_EARLY:
|
||||
++stats_n_relay_cells_processed;
|
||||
PROCESS_CELL(relay, cell, chan);
|
||||
break;
|
||||
case CELL_DESTROY:
|
||||
++stats_n_destroy_cells_processed;
|
||||
PROCESS_CELL(destroy, cell, chan);
|
||||
break;
|
||||
default:
|
||||
log_fn(LOG_INFO, LD_PROTOCOL,
|
||||
"Cell of unknown or unexpected type (%d) received. "
|
||||
"Dropping.",
|
||||
cell->command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Process an incoming var_cell from a channel; in the current protocol all
|
||||
* the var_cells are handshake-related and handled below the channel layer,
|
||||
* so this just logs a warning and drops the cell.
|
||||
*/
|
||||
|
||||
void
|
||||
command_process_var_cell(channel_t *chan, var_cell_t *var_cell)
|
||||
{
|
||||
tor_assert(chan);
|
||||
tor_assert(var_cell);
|
||||
|
||||
log_info(LD_PROTOCOL,
|
||||
"Received unexpected var_cell above the channel layer of type %d"
|
||||
"; dropping it.",
|
||||
var_cell->command);
|
||||
}
|
||||
|
||||
/** Process a 'create' <b>cell</b> that just arrived from <b>chan</b>. Make a
|
||||
* new circuit with the p_circ_id specified in cell. Put the circuit in state
|
||||
* onionskin_pending, and pass the onionskin to the cpuworker. Circ will get
|
||||
* picked up again when the cpuworker finishes decrypting it.
|
||||
*/
|
||||
static void
|
||||
command_process_create_cell(cell_t *cell, channel_t *chan)
|
||||
{
|
||||
or_circuit_t *circ;
|
||||
const or_options_t *options = get_options();
|
||||
int id_is_high;
|
||||
create_cell_t *create_cell;
|
||||
|
||||
tor_assert(cell);
|
||||
tor_assert(chan);
|
||||
|
||||
log_debug(LD_OR,
|
||||
"Got a CREATE cell for circ_id %u on channel " U64_FORMAT
|
||||
" (%p)",
|
||||
(unsigned)cell->circ_id,
|
||||
U64_PRINTF_ARG(chan->global_identifier), chan);
|
||||
|
||||
if (we_are_hibernating()) {
|
||||
log_info(LD_OR,
|
||||
"Received create cell but we're shutting down. Sending back "
|
||||
"destroy.");
|
||||
channel_send_destroy(cell->circ_id, chan,
|
||||
END_CIRC_REASON_HIBERNATING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server_mode(options) ||
|
||||
(!public_server_mode(options) && channel_is_outgoing(chan))) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received create cell (type %d) from %s, but we're connected "
|
||||
"to it as a client. "
|
||||
"Sending back a destroy.",
|
||||
(int)cell->command, channel_get_canonical_remote_descr(chan));
|
||||
channel_send_destroy(cell->circ_id, chan,
|
||||
END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cell->circ_id == 0) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received a create cell (type %d) from %s with zero circID; "
|
||||
" ignoring.", (int)cell->command,
|
||||
channel_get_actual_remote_descr(chan));
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the high bit of the circuit ID is not as expected, close the
|
||||
* circ. */
|
||||
if (chan->wide_circ_ids)
|
||||
id_is_high = cell->circ_id & (1u<<31);
|
||||
else
|
||||
id_is_high = cell->circ_id & (1u<<15);
|
||||
if ((id_is_high &&
|
||||
chan->circ_id_type == CIRC_ID_TYPE_HIGHER) ||
|
||||
(!id_is_high &&
|
||||
chan->circ_id_type == CIRC_ID_TYPE_LOWER)) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received create cell with unexpected circ_id %u. Closing.",
|
||||
(unsigned)cell->circ_id);
|
||||
channel_send_destroy(cell->circ_id, chan,
|
||||
END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (circuit_id_in_use_on_channel(cell->circ_id, chan)) {
|
||||
const node_t *node = node_get_by_id(chan->identity_digest);
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received CREATE cell (circID %u) for known circ. "
|
||||
"Dropping (age %d).",
|
||||
(unsigned)cell->circ_id,
|
||||
(int)(time(NULL) - channel_when_created(chan)));
|
||||
if (node) {
|
||||
char *p = esc_for_log(node_get_platform(node));
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Details: router %s, platform %s.",
|
||||
node_describe(node), p);
|
||||
tor_free(p);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
circ = or_circuit_new(cell->circ_id, chan);
|
||||
circ->base_.purpose = CIRCUIT_PURPOSE_OR;
|
||||
circuit_set_state(TO_CIRCUIT(circ), CIRCUIT_STATE_ONIONSKIN_PENDING);
|
||||
create_cell = tor_malloc_zero(sizeof(create_cell_t));
|
||||
if (create_cell_parse(create_cell, cell) < 0) {
|
||||
tor_free(create_cell);
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_OR,
|
||||
"Bogus/unrecognized create cell; closing.");
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (create_cell->handshake_type != ONION_HANDSHAKE_TYPE_FAST) {
|
||||
/* hand it off to the cpuworkers, and then return. */
|
||||
if (connection_or_digest_is_known_relay(chan->identity_digest))
|
||||
rep_hist_note_circuit_handshake_requested(create_cell->handshake_type);
|
||||
if (assign_onionskin_to_cpuworker(NULL, circ, create_cell) < 0) {
|
||||
log_debug(LD_GENERAL,"Failed to hand off onionskin. Closing.");
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_RESOURCELIMIT);
|
||||
return;
|
||||
}
|
||||
log_debug(LD_OR,"success: handed off onionskin.");
|
||||
} else {
|
||||
/* This is a CREATE_FAST cell; we can handle it immediately without using
|
||||
* a CPU worker. */
|
||||
uint8_t keys[CPATH_KEY_MATERIAL_LEN];
|
||||
uint8_t rend_circ_nonce[DIGEST_LEN];
|
||||
int len;
|
||||
created_cell_t created_cell;
|
||||
|
||||
/* Make sure we never try to use the OR connection on which we
|
||||
* received this cell to satisfy an EXTEND request, */
|
||||
channel_mark_client(chan);
|
||||
|
||||
memset(&created_cell, 0, sizeof(created_cell));
|
||||
len = onion_skin_server_handshake(ONION_HANDSHAKE_TYPE_FAST,
|
||||
create_cell->onionskin,
|
||||
create_cell->handshake_len,
|
||||
NULL,
|
||||
created_cell.reply,
|
||||
keys, CPATH_KEY_MATERIAL_LEN,
|
||||
rend_circ_nonce);
|
||||
tor_free(create_cell);
|
||||
if (len < 0) {
|
||||
log_warn(LD_OR,"Failed to generate key material. Closing.");
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
|
||||
tor_free(create_cell);
|
||||
return;
|
||||
}
|
||||
created_cell.cell_type = CELL_CREATED_FAST;
|
||||
created_cell.handshake_len = len;
|
||||
|
||||
if (onionskin_answer(circ, &created_cell,
|
||||
(const char *)keys, rend_circ_nonce)<0) {
|
||||
log_warn(LD_OR,"Failed to reply to CREATE_FAST cell. Closing.");
|
||||
circuit_mark_for_close(TO_CIRCUIT(circ), END_CIRC_REASON_INTERNAL);
|
||||
return;
|
||||
}
|
||||
memwipe(keys, 0, sizeof(keys));
|
||||
}
|
||||
}
|
||||
|
||||
/** Process a 'created' <b>cell</b> that just arrived from <b>chan</b>.
|
||||
* Find the circuit
|
||||
* that it's intended for. If we're not the origin of the circuit, package
|
||||
* the 'created' cell in an 'extended' relay cell and pass it back. If we
|
||||
* are the origin of the circuit, send it to circuit_finish_handshake() to
|
||||
* finish processing keys, and then call circuit_send_next_onion_skin() to
|
||||
* extend to the next hop in the circuit if necessary.
|
||||
*/
|
||||
static void
|
||||
command_process_created_cell(cell_t *cell, channel_t *chan)
|
||||
{
|
||||
circuit_t *circ;
|
||||
extended_cell_t extended_cell;
|
||||
|
||||
circ = circuit_get_by_circid_channel(cell->circ_id, chan);
|
||||
|
||||
if (!circ) {
|
||||
log_info(LD_OR,
|
||||
"(circID %u) unknown circ (probably got a destroy earlier). "
|
||||
"Dropping.", (unsigned)cell->circ_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (circ->n_circ_id != cell->circ_id) {
|
||||
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,
|
||||
"got created cell from Tor client? Closing.");
|
||||
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (created_cell_parse(&extended_cell.created_cell, cell) < 0) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_OR, "Unparseable created cell.");
|
||||
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) { /* we're the OP. Handshake this. */
|
||||
origin_circuit_t *origin_circ = TO_ORIGIN_CIRCUIT(circ);
|
||||
int err_reason = 0;
|
||||
log_debug(LD_OR,"at OP. Finishing handshake.");
|
||||
if ((err_reason = circuit_finish_handshake(origin_circ,
|
||||
&extended_cell.created_cell)) < 0) {
|
||||
log_warn(LD_OR,"circuit_finish_handshake failed.");
|
||||
circuit_mark_for_close(circ, -err_reason);
|
||||
return;
|
||||
}
|
||||
log_debug(LD_OR,"Moving to next skin.");
|
||||
if ((err_reason = circuit_send_next_onion_skin(origin_circ)) < 0) {
|
||||
log_info(LD_OR,"circuit_send_next_onion_skin failed.");
|
||||
/* XXX push this circuit_close lower */
|
||||
circuit_mark_for_close(circ, -err_reason);
|
||||
return;
|
||||
}
|
||||
} else { /* pack it into an extended relay cell, and send it. */
|
||||
uint8_t command=0;
|
||||
uint16_t len=0;
|
||||
uint8_t payload[RELAY_PAYLOAD_SIZE];
|
||||
log_debug(LD_OR,
|
||||
"Converting created cell to extended relay cell, sending.");
|
||||
memset(payload, 0, sizeof(payload));
|
||||
if (extended_cell.created_cell.cell_type == CELL_CREATED2)
|
||||
extended_cell.cell_type = RELAY_COMMAND_EXTENDED2;
|
||||
else
|
||||
extended_cell.cell_type = RELAY_COMMAND_EXTENDED;
|
||||
if (extended_cell_format(&command, &len, payload, &extended_cell) < 0) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_OR, "Can't format extended cell.");
|
||||
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
relay_send_command_from_edge(0, circ, command,
|
||||
(const char*)payload, len, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/** Process a 'relay' or 'relay_early' <b>cell</b> that just arrived from
|
||||
* <b>conn</b>. Make sure it came in with a recognized circ_id. Pass it on to
|
||||
* circuit_receive_relay_cell() for actual processing.
|
||||
*/
|
||||
static void
|
||||
command_process_relay_cell(cell_t *cell, channel_t *chan)
|
||||
{
|
||||
circuit_t *circ;
|
||||
int reason, direction;
|
||||
|
||||
circ = circuit_get_by_circid_channel(cell->circ_id, chan);
|
||||
|
||||
if (!circ) {
|
||||
log_debug(LD_OR,
|
||||
"unknown circuit %u on connection from %s. Dropping.",
|
||||
(unsigned)cell->circ_id,
|
||||
channel_get_canonical_remote_descr(chan));
|
||||
return;
|
||||
}
|
||||
|
||||
if (circ->state == CIRCUIT_STATE_ONIONSKIN_PENDING) {
|
||||
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit in create_wait. Closing.");
|
||||
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||
/* if we're a relay and treating connections with recent local
|
||||
* traffic better, then this is one of them. */
|
||||
channel_timestamp_client(chan);
|
||||
}
|
||||
|
||||
if (!CIRCUIT_IS_ORIGIN(circ) &&
|
||||
cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id)
|
||||
direction = CELL_DIRECTION_OUT;
|
||||
else
|
||||
direction = CELL_DIRECTION_IN;
|
||||
|
||||
/* If we have a relay_early cell, make sure that it's outbound, and we've
|
||||
* gotten no more than MAX_RELAY_EARLY_CELLS_PER_CIRCUIT of them. */
|
||||
if (cell->command == CELL_RELAY_EARLY) {
|
||||
if (direction == CELL_DIRECTION_IN) {
|
||||
/* Allow an unlimited number of inbound relay_early cells,
|
||||
* for hidden service compatibility. There isn't any way to make
|
||||
* a long circuit through inbound relay_early cells anyway. See
|
||||
* bug 1038. -RD */
|
||||
} else {
|
||||
or_circuit_t *or_circ = TO_OR_CIRCUIT(circ);
|
||||
if (or_circ->remaining_relay_early_cells == 0) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_OR,
|
||||
"Received too many RELAY_EARLY cells on circ %u from %s."
|
||||
" Closing circuit.",
|
||||
(unsigned)cell->circ_id,
|
||||
safe_str(channel_get_canonical_remote_descr(chan)));
|
||||
circuit_mark_for_close(circ, END_CIRC_REASON_TORPROTOCOL);
|
||||
return;
|
||||
}
|
||||
--or_circ->remaining_relay_early_cells;
|
||||
}
|
||||
}
|
||||
|
||||
if ((reason = circuit_receive_relay_cell(cell, circ, direction)) < 0) {
|
||||
log_fn(LOG_PROTOCOL_WARN,LD_PROTOCOL,"circuit_receive_relay_cell "
|
||||
"(%s) failed. Closing.",
|
||||
direction==CELL_DIRECTION_OUT?"forward":"backward");
|
||||
circuit_mark_for_close(circ, -reason);
|
||||
}
|
||||
}
|
||||
|
||||
/** Process a 'destroy' <b>cell</b> that just arrived from
|
||||
* <b>chan</b>. Find the circ that it refers to (if any).
|
||||
*
|
||||
* If the circ is in state
|
||||
* onionskin_pending, then call onion_pending_remove() to remove it
|
||||
* from the pending onion list (note that if it's already being
|
||||
* processed by the cpuworker, it won't be in the list anymore; but
|
||||
* when the cpuworker returns it, the circuit will be gone, and the
|
||||
* cpuworker response will be dropped).
|
||||
*
|
||||
* Then mark the circuit for close (which marks all edges for close,
|
||||
* and passes the destroy cell onward if necessary).
|
||||
*/
|
||||
static void
|
||||
command_process_destroy_cell(cell_t *cell, channel_t *chan)
|
||||
{
|
||||
circuit_t *circ;
|
||||
int reason;
|
||||
|
||||
circ = circuit_get_by_circid_channel(cell->circ_id, chan);
|
||||
if (!circ) {
|
||||
log_info(LD_OR,"unknown circuit %u on connection from %s. Dropping.",
|
||||
(unsigned)cell->circ_id,
|
||||
channel_get_canonical_remote_descr(chan));
|
||||
return;
|
||||
}
|
||||
log_debug(LD_OR,"Received for circID %u.",(unsigned)cell->circ_id);
|
||||
|
||||
reason = (uint8_t)cell->payload[0];
|
||||
circ->received_destroy = 1;
|
||||
|
||||
if (!CIRCUIT_IS_ORIGIN(circ) &&
|
||||
cell->circ_id == TO_OR_CIRCUIT(circ)->p_circ_id) {
|
||||
/* the destroy came from behind */
|
||||
circuit_set_p_circid_chan(TO_OR_CIRCUIT(circ), 0, NULL);
|
||||
circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE);
|
||||
} else { /* the destroy came from ahead */
|
||||
circuit_set_n_circid_chan(circ, 0, NULL);
|
||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||
circuit_mark_for_close(circ, reason|END_CIRC_REASON_FLAG_REMOTE);
|
||||
} else {
|
||||
char payload[1];
|
||||
log_debug(LD_OR, "Delivering 'truncated' back.");
|
||||
payload[0] = (char)reason;
|
||||
relay_send_command_from_edge(0, circ, RELAY_COMMAND_TRUNCATED,
|
||||
payload, sizeof(payload), NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback to handle a new channel; call command_setup_channel() to give
|
||||
* it the right cell handlers.
|
||||
*/
|
||||
|
||||
static void
|
||||
command_handle_incoming_channel(channel_listener_t *listener, channel_t *chan)
|
||||
{
|
||||
tor_assert(listener);
|
||||
tor_assert(chan);
|
||||
|
||||
command_setup_channel(chan);
|
||||
}
|
||||
|
||||
/** Given a channel, install the right handlers to process incoming
|
||||
* cells on it.
|
||||
*/
|
||||
|
||||
void
|
||||
command_setup_channel(channel_t *chan)
|
||||
{
|
||||
tor_assert(chan);
|
||||
|
||||
channel_set_cell_handlers(chan,
|
||||
command_process_cell,
|
||||
command_process_var_cell);
|
||||
}
|
||||
|
||||
/** Given a listener, install the right handler to process incoming
|
||||
* channels on it.
|
||||
*/
|
||||
|
||||
void
|
||||
command_setup_listener(channel_listener_t *listener)
|
||||
{
|
||||
tor_assert(listener);
|
||||
tor_assert(listener->state == CHANNEL_LISTENER_STATE_LISTENING);
|
||||
|
||||
channel_listener_set_listener_fn(listener, command_handle_incoming_channel);
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/* Copyright (c) 2001 Matej Pfajfar.
|
||||
* Copyright (c) 2001-2004, Roger Dingledine.
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
||||
* Copyright (c) 2007-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file command.h
|
||||
* \brief Header file for command.c.
|
||||
**/
|
||||
|
||||
#ifndef TOR_COMMAND_H
|
||||
#define TOR_COMMAND_H
|
||||
|
||||
#include "channel.h"
|
||||
|
||||
void command_process_cell(channel_t *chan, cell_t *cell);
|
||||
void command_process_var_cell(channel_t *chan, var_cell_t *cell);
|
||||
void command_setup_channel(channel_t *chan);
|
||||
void command_setup_listener(channel_listener_t *chan_l);
|
||||
|
||||
const char *cell_command_to_string(uint8_t command);
|
||||
|
||||
extern uint64_t stats_n_padding_cells_processed;
|
||||
extern uint64_t stats_n_create_cells_processed;
|
||||
extern uint64_t stats_n_created_cells_processed;
|
||||
extern uint64_t stats_n_relay_cells_processed;
|
||||
extern uint64_t stats_n_destroy_cells_processed;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
"10e0ec8ee3318e6a5ebbedc35d45ad4ec2fe5bb2 src/common/aes.c\n"
|
||||
"7fdacbf7fc104d4e118ce06cf823b2f3cb145291 src/common/crypto.c\n"
|
||||
"401d6c1243b8d99ad8f64dba232e234e60a59eb7 src/common/crypto_format.c\n"
|
||||
"64a20b8425300b0bf2373a4fe4eb74b47c4baf50 src/common/torgzip.c\n"
|
||||
"f0e8fd88f7198ad4adbd5c28e4af909b2d553b5a src/common/tortls.c\n"
|
||||
"05dc726d9d47888cc75a1c3bd31c8214dc2cb581 src/common/crypto_curve25519.c\n"
|
||||
"d233965a57506745525c7a78ff2911d59f5e3743 src/common/address.h\n"
|
||||
"ac6a50ceb318ed6907b5804034b98172ffc5ff83 src/common/backtrace.h\n"
|
||||
"947ef902f15f556f176b1115f09d9966e377347d src/common/aes.h\n"
|
||||
"6fb51902eea04b5c33a99a754845958fec43d912 src/common/ciphers.inc\n"
|
||||
"4618a9860688c2cb12d37d8172317324c10f0a92 src/common/tor_compat.h\n"
|
||||
"e427c754391f1282a98cbbb387bae2ae403cbde7 src/common/compat_libevent.h\n"
|
||||
"faaa0bcfcc0cbc61f6d092b9b36e56cb89b090b7 src/common/container.h\n"
|
||||
"7196fde86ec70bd579e8fcd546817d285d936b18 src/common/crypto.h\n"
|
||||
"1260154e3b65f2586a54986deffec6963a4c7204 src/common/crypto_curve25519.h\n"
|
||||
"9ed1bb165e8d0532cae5bfd17e27d037d2a05bf4 src/common/di_ops.h\n"
|
||||
"697be45dc2e1ae6537b34dc72abf6394952a1b87 src/common/memarea.h\n"
|
||||
"0b594bada47b6e23358fa924cffbf24e01180d60 src/common/mempool.h\n"
|
||||
"2cd7af59a82d4e1ca2873d2801c44176605a545a src/common/procmon.h\n"
|
||||
"ed8b5d4225ceaf11e29fe635a091e2b2f3fe3ae8 src/common/sandbox.h\n"
|
||||
"ddfdca2f5d52acc27214a3c91c0ca73c81b526eb src/common/testsupport.h\n"
|
||||
"13108dc9184a7ece65685e0724e7e8770acd576f src/common/torgzip.h\n"
|
||||
"8d71f0488728c324a5aabfd92d209350973b490a src/common/torint.h\n"
|
||||
"b86f76bfdfdc3bd841233c662761e857cb830c88 src/common/torlog.h\n"
|
||||
"27209a8a0e9b8c61bbbb2d50241a2a4b4595ce19 src/common/tortls.h\n"
|
||||
"e5cb074466d9f59f1988e8964fed1476c238ff14 src/common/tor_util.h\n"
|
||||
-3254
File diff suppressed because it is too large
Load Diff
@@ -1,663 +0,0 @@
|
||||
/* Copyright (c) 2009-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file compat_libevent.c
|
||||
* \brief Wrappers to handle porting between different versions of libevent.
|
||||
*
|
||||
* In an ideal world, we'd just use Libevent 2.0 from now on. But as of June
|
||||
* 2012, Libevent 1.4 is still all over, and some poor souls are stuck on
|
||||
* Libevent 1.3e. */
|
||||
|
||||
#include "orconfig.h"
|
||||
#include "tor_compat.h"
|
||||
#include "compat_libevent.h"
|
||||
|
||||
#include "tor_util.h"
|
||||
#include "torlog.h"
|
||||
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
#include <event2/event.h>
|
||||
#include <event2/thread.h>
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
#include <event2/bufferevent.h>
|
||||
#endif
|
||||
#else
|
||||
#include <event.h>
|
||||
#endif
|
||||
|
||||
/** A number representing a version of Libevent.
|
||||
|
||||
This is a 4-byte number, with the first three bytes representing the
|
||||
major, minor, and patchlevel respectively of the library. The fourth
|
||||
byte is unused.
|
||||
|
||||
This is equivalent to the format of LIBEVENT_VERSION_NUMBER on Libevent
|
||||
2.0.1 or later. For versions of Libevent before 1.4.0, which followed the
|
||||
format of "1.0, 1.0a, 1.0b", we define 1.0 to be equivalent to 1.0.0, 1.0a
|
||||
to be equivalent to 1.0.1, and so on.
|
||||
*/
|
||||
typedef uint32_t le_version_t;
|
||||
|
||||
/** @{ */
|
||||
/** Macros: returns the number of a libevent version as a le_version_t */
|
||||
#define V(major, minor, patch) \
|
||||
(((major) << 24) | ((minor) << 16) | ((patch) << 8))
|
||||
#define V_OLD(major, minor, patch) \
|
||||
V((major), (minor), (patch)-'a'+1)
|
||||
/** @} */
|
||||
|
||||
/** Represetns a version of libevent so old we can't figure out what version
|
||||
* it is. */
|
||||
#define LE_OLD V(0,0,0)
|
||||
/** Represents a version of libevent so weird we can't figure out what version
|
||||
* it is. */
|
||||
#define LE_OTHER V(0,0,99)
|
||||
|
||||
#if 0
|
||||
static le_version_t tor_get_libevent_version(const char **v_out);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_EVENT_SET_LOG_CALLBACK) || defined(RUNNING_DOXYGEN)
|
||||
/** A string which, if it appears in a libevent log, should be ignored. */
|
||||
static const char *suppress_msg = NULL;
|
||||
/** Callback function passed to event_set_log() so we can intercept
|
||||
* log messages from libevent. */
|
||||
static void
|
||||
libevent_logging_callback(int severity, const char *msg)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t n;
|
||||
if (suppress_msg && strstr(msg, suppress_msg))
|
||||
return;
|
||||
n = strlcpy(buf, msg, sizeof(buf));
|
||||
if (n && n < sizeof(buf) && buf[n-1] == '\n') {
|
||||
buf[n-1] = '\0';
|
||||
}
|
||||
switch (severity) {
|
||||
case _EVENT_LOG_DEBUG:
|
||||
log_debug(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
|
||||
break;
|
||||
case _EVENT_LOG_MSG:
|
||||
log_info(LD_NOCB|LD_NET, "Message from libevent: %s", buf);
|
||||
break;
|
||||
case _EVENT_LOG_WARN:
|
||||
log_warn(LD_NOCB|LD_GENERAL, "Warning from libevent: %s", buf);
|
||||
break;
|
||||
case _EVENT_LOG_ERR:
|
||||
log_err(LD_NOCB|LD_GENERAL, "Error from libevent: %s", buf);
|
||||
break;
|
||||
default:
|
||||
log_warn(LD_NOCB|LD_GENERAL, "Message [%d] from libevent: %s",
|
||||
severity, buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/** Set hook to intercept log messages from libevent. */
|
||||
void
|
||||
configure_libevent_logging(void)
|
||||
{
|
||||
event_set_log_callback(libevent_logging_callback);
|
||||
}
|
||||
/** Ignore any libevent log message that contains <b>msg</b>. */
|
||||
void
|
||||
suppress_libevent_log_msg(const char *msg)
|
||||
{
|
||||
suppress_msg = msg;
|
||||
}
|
||||
#else
|
||||
void
|
||||
configure_libevent_logging(void)
|
||||
{
|
||||
}
|
||||
void
|
||||
suppress_libevent_log_msg(const char *msg)
|
||||
{
|
||||
(void)msg;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_EVENT2_EVENT_H
|
||||
/** Work-alike replacement for event_new() on pre-Libevent-2.0 systems. */
|
||||
struct event *
|
||||
tor_event_new(struct event_base *base, int sock, short what,
|
||||
void (*cb)(int, short, void *), void *arg)
|
||||
{
|
||||
struct event *e = tor_malloc_zero(sizeof(struct event));
|
||||
event_set(e, sock, what, cb, arg);
|
||||
if (! base)
|
||||
base = tor_libevent_get_base();
|
||||
event_base_set(base, e);
|
||||
return e;
|
||||
}
|
||||
/** Work-alike replacement for evtimer_new() on pre-Libevent-2.0 systems. */
|
||||
struct event *
|
||||
tor_evtimer_new(struct event_base *base,
|
||||
void (*cb)(int, short, void *), void *arg)
|
||||
{
|
||||
return tor_event_new(base, -1, 0, cb, arg);
|
||||
}
|
||||
/** Work-alike replacement for evsignal_new() on pre-Libevent-2.0 systems. */
|
||||
struct event *
|
||||
tor_evsignal_new(struct event_base * base, int sig,
|
||||
void (*cb)(int, short, void *), void *arg)
|
||||
{
|
||||
return tor_event_new(base, sig, EV_SIGNAL|EV_PERSIST, cb, arg);
|
||||
}
|
||||
/** Work-alike replacement for event_free() on pre-Libevent-2.0 systems. */
|
||||
void
|
||||
tor_event_free(struct event *ev)
|
||||
{
|
||||
event_del(ev);
|
||||
tor_free(ev);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Global event base for use by the main thread. */
|
||||
struct event_base *the_event_base = NULL;
|
||||
|
||||
/* This is what passes for version detection on OSX. We set
|
||||
* MACOSX_KQUEUE_IS_BROKEN to true iff we're on a version of OSX before
|
||||
* 10.4.0 (aka 1040). */
|
||||
#ifdef __APPLE__
|
||||
#ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
|
||||
#define MACOSX_KQUEUE_IS_BROKEN \
|
||||
(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1040)
|
||||
#else
|
||||
#define MACOSX_KQUEUE_IS_BROKEN 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
static int using_iocp_bufferevents = 0;
|
||||
static void tor_libevent_set_tick_timeout(int msec_per_tick);
|
||||
|
||||
int
|
||||
tor_libevent_using_iocp_bufferevents(void)
|
||||
{
|
||||
return using_iocp_bufferevents;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Initialize the Libevent library and set up the event base. */
|
||||
void
|
||||
tor_libevent_initialize(tor_libevent_cfg *torcfg)
|
||||
{
|
||||
tor_assert(the_event_base == NULL);
|
||||
/* some paths below don't use torcfg, so avoid unused variable warnings */
|
||||
(void)torcfg;
|
||||
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
{
|
||||
int attempts = 0;
|
||||
int using_threads;
|
||||
struct event_config *cfg;
|
||||
|
||||
retry:
|
||||
++attempts;
|
||||
using_threads = 0;
|
||||
cfg = event_config_new();
|
||||
tor_assert(cfg);
|
||||
|
||||
#if defined(_WIN32) && defined(USE_BUFFEREVENTS)
|
||||
if (! torcfg->disable_iocp) {
|
||||
evthread_use_windows_threads();
|
||||
event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
|
||||
using_iocp_bufferevents = 1;
|
||||
using_threads = 1;
|
||||
} else {
|
||||
using_iocp_bufferevents = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!using_threads) {
|
||||
/* Telling Libevent not to try to turn locking on can avoid a needless
|
||||
* socketpair() attempt. */
|
||||
event_config_set_flag(cfg, EVENT_BASE_FLAG_NOLOCK);
|
||||
}
|
||||
|
||||
#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
|
||||
if (torcfg->num_cpus > 0)
|
||||
event_config_set_num_cpus_hint(cfg, torcfg->num_cpus);
|
||||
#endif
|
||||
|
||||
#if LIBEVENT_VERSION_NUMBER >= V(2,0,9)
|
||||
/* We can enable changelist support with epoll, since we don't give
|
||||
* Libevent any dup'd fds. This lets us avoid some syscalls. */
|
||||
event_config_set_flag(cfg, EVENT_BASE_FLAG_EPOLL_USE_CHANGELIST);
|
||||
#endif
|
||||
|
||||
the_event_base = event_base_new_with_config(cfg);
|
||||
|
||||
event_config_free(cfg);
|
||||
|
||||
if (using_threads && the_event_base == NULL && attempts < 2) {
|
||||
/* This could be a socketpair() failure, which can happen sometimes on
|
||||
* windows boxes with obnoxious firewall rules. Downgrade and try
|
||||
* again. */
|
||||
#if defined(_WIN32) && defined(USE_BUFFEREVENTS)
|
||||
if (torcfg->disable_iocp == 0) {
|
||||
log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again "
|
||||
"with IOCP disabled.");
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
log_warn(LD_GENERAL, "Unable to initialize Libevent. Trying again.");
|
||||
}
|
||||
|
||||
torcfg->disable_iocp = 1;
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
#else
|
||||
the_event_base = event_init();
|
||||
#endif
|
||||
|
||||
if (!the_event_base) {
|
||||
log_err(LD_GENERAL, "Unable to initialize Libevent: cannot continue.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#if defined(HAVE_EVENT_GET_VERSION) && defined(HAVE_EVENT_GET_METHOD)
|
||||
/* Making this a NOTICE for now so we can link bugs to a libevent versions
|
||||
* or methods better. */
|
||||
log_info(LD_GENERAL,
|
||||
"Initialized libevent version %s using method %s. Good.",
|
||||
event_get_version(), tor_libevent_get_method());
|
||||
#else
|
||||
log_notice(LD_GENERAL,
|
||||
"Initialized old libevent (version 1.0b or earlier).");
|
||||
log_warn(LD_GENERAL,
|
||||
"You have a *VERY* old version of libevent. It is likely to be buggy; "
|
||||
"please build Tor with a more recent version.");
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
tor_libevent_set_tick_timeout(torcfg->msec_per_tick);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Return the current Libevent event base that we're set up to use. */
|
||||
struct event_base *
|
||||
tor_libevent_get_base(void)
|
||||
{
|
||||
return the_event_base;
|
||||
}
|
||||
|
||||
#ifndef HAVE_EVENT_BASE_LOOPEXIT
|
||||
/** Replacement for event_base_loopexit on some very old versions of Libevent
|
||||
* that we are not yet brave enough to deprecate. */
|
||||
int
|
||||
tor_event_base_loopexit(struct event_base *base, struct timeval *tv)
|
||||
{
|
||||
tor_assert(base == the_event_base);
|
||||
return event_loopexit(tv);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Return the name of the Libevent backend we're using. */
|
||||
const char *
|
||||
tor_libevent_get_method(void)
|
||||
{
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
return event_base_get_method(the_event_base);
|
||||
#elif defined(HAVE_EVENT_GET_METHOD)
|
||||
return event_get_method();
|
||||
#else
|
||||
return "<unknown>";
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Return the le_version_t for the version of libevent specified in the
|
||||
* string <b>v</b>. If the version is very new or uses an unrecognized
|
||||
* version, format, return LE_OTHER. */
|
||||
static le_version_t
|
||||
tor_decode_libevent_version(const char *v)
|
||||
{
|
||||
unsigned major, minor, patchlevel;
|
||||
char c, e, extra;
|
||||
int fields;
|
||||
|
||||
/* Try the new preferred "1.4.11-stable" format.
|
||||
* Also accept "1.4.14b-stable". */
|
||||
fields = tor_sscanf(v, "%u.%u.%u%c%c", &major, &minor, &patchlevel, &c, &e);
|
||||
if (fields == 3 ||
|
||||
((fields == 4 || fields == 5 ) && (c == '-' || c == '_')) ||
|
||||
(fields == 5 && TOR_ISALPHA(c) && (e == '-' || e == '_'))) {
|
||||
return V(major,minor,patchlevel);
|
||||
}
|
||||
|
||||
/* Try the old "1.3e" format. */
|
||||
fields = tor_sscanf(v, "%u.%u%c%c", &major, &minor, &c, &extra);
|
||||
if (fields == 3 && TOR_ISALPHA(c)) {
|
||||
return V_OLD(major, minor, c);
|
||||
} else if (fields == 2) {
|
||||
return V(major, minor, 0);
|
||||
}
|
||||
|
||||
return LE_OTHER;
|
||||
}
|
||||
|
||||
/** Return an integer representing the binary interface of a Libevent library.
|
||||
* Two different versions with different numbers are sure not to be binary
|
||||
* compatible. Two different versions with the same numbers have a decent
|
||||
* chance of binary compatibility.*/
|
||||
static int
|
||||
le_versions_compatibility(le_version_t v)
|
||||
{
|
||||
if (v == LE_OTHER)
|
||||
return 0;
|
||||
if (v < V_OLD(1,0,'c'))
|
||||
return 1;
|
||||
else if (v < V(1,4,0))
|
||||
return 2;
|
||||
else if (v < V(1,4,99))
|
||||
return 3;
|
||||
else if (v < V(2,0,1))
|
||||
return 4;
|
||||
else /* Everything 2.0 and later should be compatible. */
|
||||
return 5;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** Return the version number of the currently running version of Libevent.
|
||||
* See le_version_t for info on the format.
|
||||
*/
|
||||
static le_version_t
|
||||
tor_get_libevent_version(const char **v_out)
|
||||
{
|
||||
const char *v;
|
||||
le_version_t r;
|
||||
#if defined(HAVE_EVENT_GET_VERSION_NUMBER)
|
||||
v = event_get_version();
|
||||
r = event_get_version_number();
|
||||
#elif defined (HAVE_EVENT_GET_VERSION)
|
||||
v = event_get_version();
|
||||
r = tor_decode_libevent_version(v);
|
||||
#else
|
||||
v = "pre-1.0c";
|
||||
r = LE_OLD;
|
||||
#endif
|
||||
if (v_out)
|
||||
*v_out = v;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Return a string representation of the version of the currently running
|
||||
* version of Libevent. */
|
||||
const char *
|
||||
tor_libevent_get_version_str(void)
|
||||
{
|
||||
#ifdef HAVE_EVENT_GET_VERSION
|
||||
return event_get_version();
|
||||
#else
|
||||
return "pre-1.0c";
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the current Libevent method and version to a list of versions
|
||||
* which are known not to work. Warn the user as appropriate.
|
||||
*/
|
||||
void
|
||||
tor_check_libevent_version(const char *m, int server,
|
||||
const char **badness_out)
|
||||
{
|
||||
(void) m;
|
||||
(void) server;
|
||||
*badness_out = NULL;
|
||||
}
|
||||
|
||||
#if defined(LIBEVENT_VERSION)
|
||||
#define HEADER_VERSION LIBEVENT_VERSION
|
||||
#elif defined(_EVENT_VERSION)
|
||||
#define HEADER_VERSION _EVENT_VERSION
|
||||
#endif
|
||||
|
||||
/** Return a string representation of the version of Libevent that was used
|
||||
* at compilation time. */
|
||||
const char *
|
||||
tor_libevent_get_header_version_str(void)
|
||||
{
|
||||
return HEADER_VERSION;
|
||||
}
|
||||
|
||||
/** See whether the headers we were built against differ from the library we
|
||||
* linked against so much that we're likely to crash. If so, warn the
|
||||
* user. */
|
||||
void
|
||||
tor_check_libevent_header_compatibility(void)
|
||||
{
|
||||
(void) le_versions_compatibility;
|
||||
(void) tor_decode_libevent_version;
|
||||
|
||||
/* In libevent versions before 2.0, it's hard to keep binary compatibility
|
||||
* between upgrades, and unpleasant to detect when the version we compiled
|
||||
* against is unlike the version we have linked against. Here's how. */
|
||||
#if defined(HEADER_VERSION) && defined(HAVE_EVENT_GET_VERSION)
|
||||
/* We have a header-file version and a function-call version. Easy. */
|
||||
if (strcmp(HEADER_VERSION, event_get_version())) {
|
||||
le_version_t v1, v2;
|
||||
int compat1 = -1, compat2 = -1;
|
||||
int verybad;
|
||||
v1 = tor_decode_libevent_version(HEADER_VERSION);
|
||||
v2 = tor_decode_libevent_version(event_get_version());
|
||||
compat1 = le_versions_compatibility(v1);
|
||||
compat2 = le_versions_compatibility(v2);
|
||||
|
||||
verybad = compat1 != compat2;
|
||||
|
||||
tor_log(verybad ? LOG_WARN : LOG_NOTICE,
|
||||
LD_GENERAL, "We were compiled with headers from version %s "
|
||||
"of Libevent, but we're using a Libevent library that says it's "
|
||||
"version %s.", HEADER_VERSION, event_get_version());
|
||||
if (verybad)
|
||||
log_warn(LD_GENERAL, "This will almost certainly make Tor crash.");
|
||||
else
|
||||
log_info(LD_GENERAL, "I think these versions are binary-compatible.");
|
||||
}
|
||||
#elif defined(HAVE_EVENT_GET_VERSION)
|
||||
/* event_get_version but no _EVENT_VERSION. We might be in 1.4.0-beta or
|
||||
earlier, where that's normal. To see whether we were compiled with an
|
||||
earlier version, let's see whether the struct event defines MIN_HEAP_IDX.
|
||||
*/
|
||||
#ifdef HAVE_STRUCT_EVENT_MIN_HEAP_IDX
|
||||
/* The header files are 1.4.0-beta or later. If the version is not
|
||||
* 1.4.0-beta, we are incompatible. */
|
||||
{
|
||||
if (strcmp(event_get_version(), "1.4.0-beta")) {
|
||||
log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
|
||||
"Libevent 1.4.0-beta header files, whereas you have linked "
|
||||
"against Libevent %s. This will probably make Tor crash.",
|
||||
event_get_version());
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Our headers are 1.3e or earlier. If the library version is not 1.4.x or
|
||||
later, we're probably fine. */
|
||||
{
|
||||
const char *v = event_get_version();
|
||||
if ((v[0] == '1' && v[2] == '.' && v[3] > '3') || v[0] > '1') {
|
||||
log_warn(LD_GENERAL, "It's a little hard to tell, but you seem to have "
|
||||
"Libevent header file from 1.3e or earlier, whereas you have "
|
||||
"linked against Libevent %s. This will probably make Tor "
|
||||
"crash.", event_get_version());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(HEADER_VERSION)
|
||||
#warn "_EVENT_VERSION is defined but not get_event_version(): Libevent is odd."
|
||||
#else
|
||||
/* Your libevent is ancient. */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
If possible, we're going to try to use Libevent's periodic timer support,
|
||||
since it does a pretty good job of making sure that periodic events get
|
||||
called exactly M seconds apart, rather than starting each one exactly M
|
||||
seconds after the time that the last one was run.
|
||||
*/
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
#define HAVE_PERIODIC
|
||||
#define PERIODIC_FLAGS EV_PERSIST
|
||||
#else
|
||||
#define PERIODIC_FLAGS 0
|
||||
#endif
|
||||
|
||||
/** Represents a timer that's run every N microseconds by Libevent. */
|
||||
struct periodic_timer_t {
|
||||
/** Underlying event used to implement this periodic event. */
|
||||
struct event *ev;
|
||||
/** The callback we'll be invoking whenever the event triggers */
|
||||
void (*cb)(struct periodic_timer_t *, void *);
|
||||
/** User-supplied data for the callback */
|
||||
void *data;
|
||||
#ifndef HAVE_PERIODIC
|
||||
/** If Libevent doesn't know how to invoke events every N microseconds,
|
||||
* we'll need to remember the timeout interval here. */
|
||||
struct timeval tv;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Libevent callback to implement a periodic event. */
|
||||
static void
|
||||
periodic_timer_cb(evutil_socket_t fd, short what, void *arg)
|
||||
{
|
||||
periodic_timer_t *timer = arg;
|
||||
(void) what;
|
||||
(void) fd;
|
||||
#ifndef HAVE_PERIODIC
|
||||
/** reschedule the event as needed. */
|
||||
event_add(timer->ev, &timer->tv);
|
||||
#endif
|
||||
timer->cb(timer, timer->data);
|
||||
}
|
||||
|
||||
/** Create and schedule a new timer that will run every <b>tv</b> in
|
||||
* the event loop of <b>base</b>. When the timer fires, it will
|
||||
* run the timer in <b>cb</b> with the user-supplied data in <b>data</b>. */
|
||||
periodic_timer_t *
|
||||
periodic_timer_new(struct event_base *base,
|
||||
const struct timeval *tv,
|
||||
void (*cb)(periodic_timer_t *timer, void *data),
|
||||
void *data)
|
||||
{
|
||||
periodic_timer_t *timer;
|
||||
tor_assert(base);
|
||||
tor_assert(tv);
|
||||
tor_assert(cb);
|
||||
timer = tor_malloc_zero(sizeof(periodic_timer_t));
|
||||
if (!(timer->ev = tor_event_new(base, -1, PERIODIC_FLAGS,
|
||||
periodic_timer_cb, timer))) {
|
||||
tor_free(timer);
|
||||
return NULL;
|
||||
}
|
||||
timer->cb = cb;
|
||||
timer->data = data;
|
||||
#ifndef HAVE_PERIODIC
|
||||
memcpy(&timer->tv, tv, sizeof(struct timeval));
|
||||
#endif
|
||||
event_add(timer->ev, (struct timeval *)tv); /*drop const for old libevent*/
|
||||
return timer;
|
||||
}
|
||||
|
||||
/** Stop and free a periodic timer */
|
||||
void
|
||||
periodic_timer_free(periodic_timer_t *timer)
|
||||
{
|
||||
if (!timer)
|
||||
return;
|
||||
tor_event_free(timer->ev);
|
||||
tor_free(timer);
|
||||
}
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
static const struct timeval *one_tick = NULL;
|
||||
/**
|
||||
* Return a special timeout to be passed whenever libevent's O(1) timeout
|
||||
* implementation should be used. Only use this when the timer is supposed
|
||||
* to fire after msec_per_tick ticks have elapsed.
|
||||
*/
|
||||
const struct timeval *
|
||||
tor_libevent_get_one_tick_timeout(void)
|
||||
{
|
||||
tor_assert(one_tick);
|
||||
return one_tick;
|
||||
}
|
||||
|
||||
/** Initialize the common timeout that we'll use to refill the buckets every
|
||||
* time a tick elapses. */
|
||||
static void
|
||||
tor_libevent_set_tick_timeout(int msec_per_tick)
|
||||
{
|
||||
struct event_base *base = tor_libevent_get_base();
|
||||
struct timeval tv;
|
||||
|
||||
tor_assert(! one_tick);
|
||||
tv.tv_sec = msec_per_tick / 1000;
|
||||
tv.tv_usec = (msec_per_tick % 1000) * 1000;
|
||||
one_tick = event_base_init_common_timeout(base, &tv);
|
||||
}
|
||||
|
||||
static struct bufferevent *
|
||||
tor_get_root_bufferevent(struct bufferevent *bev)
|
||||
{
|
||||
struct bufferevent *u;
|
||||
while ((u = bufferevent_get_underlying(bev)) != NULL)
|
||||
bev = u;
|
||||
return bev;
|
||||
}
|
||||
|
||||
int
|
||||
tor_set_bufferevent_rate_limit(struct bufferevent *bev,
|
||||
struct ev_token_bucket_cfg *cfg)
|
||||
{
|
||||
return bufferevent_set_rate_limit(tor_get_root_bufferevent(bev), cfg);
|
||||
}
|
||||
|
||||
int
|
||||
tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
|
||||
struct bufferevent_rate_limit_group *g)
|
||||
{
|
||||
return bufferevent_add_to_rate_limit_group(tor_get_root_bufferevent(bev), g);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,1,1)
|
||||
void
|
||||
tor_gettimeofday_cached(struct timeval *tv)
|
||||
{
|
||||
event_base_gettimeofday_cached(the_event_base, tv);
|
||||
}
|
||||
void
|
||||
tor_gettimeofday_cache_clear(void)
|
||||
{
|
||||
event_base_update_cache_time(the_event_base);
|
||||
}
|
||||
#else
|
||||
/** Cache the current hi-res time; the cache gets reset when libevent
|
||||
* calls us. */
|
||||
static struct timeval cached_time_hires = {0, 0};
|
||||
|
||||
/** Return a fairly recent view of the current time. */
|
||||
void
|
||||
tor_gettimeofday_cached(struct timeval *tv)
|
||||
{
|
||||
if (cached_time_hires.tv_sec == 0) {
|
||||
tor_gettimeofday(&cached_time_hires);
|
||||
}
|
||||
*tv = cached_time_hires;
|
||||
}
|
||||
|
||||
/** Reset the cached view of the current time, so that the next time we try
|
||||
* to learn it, we will get an up-to-date value. */
|
||||
void
|
||||
tor_gettimeofday_cache_clear(void)
|
||||
{
|
||||
cached_time_hires.tv_sec = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
/* Copyright (c) 2009-2013, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_COMPAT_LIBEVENT_H
|
||||
#define TOR_COMPAT_LIBEVENT_H
|
||||
|
||||
#include "orconfig.h"
|
||||
|
||||
struct event;
|
||||
struct event_base;
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
struct bufferevent;
|
||||
struct ev_token_bucket_cfg;
|
||||
struct bufferevent_rate_limit_group;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
#include <event2/util.h>
|
||||
#elif !defined(EVUTIL_SOCKET_DEFINED)
|
||||
#define EVUTIL_SOCKET_DEFINED
|
||||
#define evutil_socket_t int
|
||||
#endif
|
||||
|
||||
void configure_libevent_logging(void);
|
||||
void suppress_libevent_log_msg(const char *msg);
|
||||
|
||||
#ifdef HAVE_EVENT2_EVENT_H
|
||||
#define tor_event_new event_new
|
||||
#define tor_evtimer_new evtimer_new
|
||||
#define tor_evsignal_new evsignal_new
|
||||
#define tor_event_free event_free
|
||||
#define tor_evdns_add_server_port(sock, tcp, cb, data) \
|
||||
evdns_add_server_port_with_base(tor_libevent_get_base(), \
|
||||
(sock),(tcp),(cb),(data));
|
||||
|
||||
#else
|
||||
struct event *tor_event_new(struct event_base * base, evutil_socket_t sock,
|
||||
short what, void (*cb)(evutil_socket_t, short, void *), void *arg);
|
||||
struct event *tor_evtimer_new(struct event_base * base,
|
||||
void (*cb)(evutil_socket_t, short, void *), void *arg);
|
||||
struct event *tor_evsignal_new(struct event_base * base, int sig,
|
||||
void (*cb)(evutil_socket_t, short, void *), void *arg);
|
||||
void tor_event_free(struct event *ev);
|
||||
#define tor_evdns_add_server_port evdns_add_server_port
|
||||
#endif
|
||||
|
||||
typedef struct periodic_timer_t periodic_timer_t;
|
||||
|
||||
periodic_timer_t *periodic_timer_new(struct event_base *base,
|
||||
const struct timeval *tv,
|
||||
void (*cb)(periodic_timer_t *timer, void *data),
|
||||
void *data);
|
||||
void periodic_timer_free(periodic_timer_t *);
|
||||
|
||||
#ifdef HAVE_EVENT_BASE_LOOPEXIT
|
||||
#define tor_event_base_loopexit event_base_loopexit
|
||||
#else
|
||||
struct timeval;
|
||||
int tor_event_base_loopexit(struct event_base *base, struct timeval *tv);
|
||||
#endif
|
||||
|
||||
/** Defines a configuration for using libevent with Tor: passed as an argument
|
||||
* to tor_libevent_initialize() to describe how we want to set up. */
|
||||
typedef struct tor_libevent_cfg {
|
||||
/** Flag: if true, disable IOCP (assuming that it could be enabled). */
|
||||
int disable_iocp;
|
||||
/** How many CPUs should we use (relevant only with IOCP). */
|
||||
int num_cpus;
|
||||
/** How many milliseconds should we allow between updating bandwidth limits?
|
||||
* (relevant only with bufferevents). */
|
||||
int msec_per_tick;
|
||||
} tor_libevent_cfg;
|
||||
|
||||
void tor_libevent_initialize(tor_libevent_cfg *cfg);
|
||||
struct event_base *tor_libevent_get_base(void);
|
||||
const char *tor_libevent_get_method(void);
|
||||
void tor_check_libevent_version(const char *m, int server,
|
||||
const char **badness_out);
|
||||
void tor_check_libevent_header_compatibility(void);
|
||||
const char *tor_libevent_get_version_str(void);
|
||||
const char *tor_libevent_get_header_version_str(void);
|
||||
|
||||
#ifdef USE_BUFFEREVENTS
|
||||
const struct timeval *tor_libevent_get_one_tick_timeout(void);
|
||||
int tor_libevent_using_iocp_bufferevents(void);
|
||||
int tor_set_bufferevent_rate_limit(struct bufferevent *bev,
|
||||
struct ev_token_bucket_cfg *cfg);
|
||||
int tor_add_bufferevent_to_rate_limit_group(struct bufferevent *bev,
|
||||
struct bufferevent_rate_limit_group *g);
|
||||
#endif
|
||||
|
||||
void tor_gettimeofday_cached(struct timeval *tv);
|
||||
void tor_gettimeofday_cache_clear(void);
|
||||
|
||||
#endif
|
||||
|
||||
-6704
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user