forked from I2P_Developers/i2p.i2p
Compare commits
272 Commits
i2p_0_3_0_
...
i2p_0_3_1_
Author | SHA1 | Date | |
---|---|---|---|
a8ad8644c8 | |||
4e91bb88a5 | |||
f60a90e2da | |||
784dc0f6a7 | |||
e80e627fba | |||
d5987c51c9 | |||
5ced441b17 | |||
57801202fd | |||
a019399c3c | |||
e6f610a86c | |||
7ef528bbde | |||
a351a29bf3 | |||
983d258bce | |||
f6d38dd5e0 | |||
d51245aada | |||
56cf51f0f9 | |||
eb40fb9c5d | |||
085da0cea7 | |||
5539b19938 | |||
94feb762ca | |||
40b59d5a5a | |||
9ffd147470 | |||
3fea4ad2ba | |||
1ab5536879 | |||
9690a89a6d | |||
8f895f4349 | |||
980c0aa1d7 | |||
52fd6ca513 | |||
eb5dd2ff2e | |||
7ca35452eb | |||
dd781e256c | |||
551a7ab82f | |||
2901287d9e | |||
2b714967aa | |||
e8734ef1e7 | |||
14b9f9509f | |||
b1f973d304 | |||
2f17bfd71c | |||
b6670ee23a | |||
f1036df1f6 | |||
5c3e815757 | |||
55e780d885 | |||
d502df7d56 | |||
beb6cc8c0f | |||
c99db5e75c | |||
65cd70a85b | |||
5166eab5ee | |||
232f6f158d | |||
2a07ceba62 | |||
3e4b8c7dd4 | |||
26138e213f | |||
d82796e3ad | |||
cdcb81c867 | |||
5669e8f060 | |||
d84a40b4dc | |||
591be43763 | |||
97d0686354 | |||
e2da05b197 | |||
4f0052043d | |||
cfc1d1a2db | |||
9957e6ef17 | |||
6a02c8383c | |||
bc0a4ee68d | |||
1ca615da77 | |||
7da0cee29a | |||
f25bccd19f | |||
4e5a2e012c | |||
c9ee2a92a3 | |||
95a7938328 | |||
baedcdb2c1 | |||
bc06b3671a | |||
a9172811ca | |||
91b1fd6d07 | |||
bab7b8b9ed | |||
1b7fb96ca8 | |||
6d84b8c02f | |||
3e3749f011 | |||
52384fb3a5 | |||
e401670087 | |||
ae0b4c59cc | |||
0a8dc8afcc | |||
d59b94df66 | |||
e28502454b | |||
bbf73f0937 | |||
592519c45c | |||
cc904ba9dc | |||
1679ba6719 | |||
07fadd4a6c | |||
57e1ff39e0 | |||
51e259c198 | |||
de334b003d | |||
a61ff12390 | |||
f4697be159 | |||
3835fe3960 | |||
76c374ef06 | |||
57d24bd948 | |||
deff14dfd8 | |||
0a479be370 | |||
ba6a2e3fd2 | |||
c3a395a41e | |||
a3136a19e9 | |||
b631568003 | |||
1d0c03eca4 | |||
eb30525a26 | |||
3e66ea3f56 | |||
9f1189e606 | |||
698927bed4 | |||
8fd02ee8dd | |||
f3154e8f5e | |||
878af163a9 | |||
da8341d014 | |||
95c33e88ed | |||
fed8369a5f | |||
d85806e3d5 | |||
097660ce53 | |||
b08cfbbb35 | |||
97ee3c47a0 | |||
05918de6ab | |||
8d7abd8298 | |||
727f4c3bb5 | |||
7372ad0cc4 | |||
ca6884dbca | |||
1ebb0ac5fb | |||
bf0e53f13b | |||
8888a960c0 | |||
04be41aac5 | |||
fd1313d49f | |||
3599dba5c3 | |||
67edc437d2 | |||
7a39d9240c | |||
6d2d9aed7e | |||
3c2e5f22b6 | |||
ddb6348bfd | |||
d70c5df5a0 | |||
b2799d198c | |||
f2fa2038b1 | |||
bfd59e64ea | |||
60e05e270a | |||
242b9a6af9 | |||
e7e8ad9bdc | |||
0e5d164a8a | |||
7293a8d3c0 | |||
097a4647a8 | |||
0942a7f3ff | |||
2df4370477 | |||
7243963106 | |||
9f17654052 | |||
1a65d7061d | |||
292363eb65 | |||
07e79ce61a | |||
1cf7dac82b | |||
6003b2902f | |||
ff0023a889 | |||
8c6bf5a1cc | |||
61c97ab940 | |||
b0a1b3b5ca | |||
4c7af01edc | |||
0d431213cd | |||
ad9dd9a2e2 | |||
c7895ed905 | |||
57d7979d51 | |||
61f6871cd1 | |||
406048f7b9 | |||
6dd5b0fe45 | |||
fd4bc5e3cf | |||
3bab2d8957 | |||
af2f5cd2e1 | |||
d4bb32da82 | |||
08aca6ca61 | |||
697b3c6772 | |||
878525ced8 | |||
418531736b | |||
6c175440c6 | |||
723a2f2008 | |||
ea9b9fbf17 | |||
303e257841 | |||
07b6a8ba92 | |||
e216e18368 | |||
e57c5b4bc2 | |||
f772d6ddeb | |||
cd37c301d9 | |||
f5fa26639e | |||
45ec73c115 | |||
13952ebd8b | |||
2df0007a10 | |||
89bc5db3e1 | |||
4021deec7f | |||
a3977f37f7 | |||
766c12242e | |||
a82b951aff | |||
997a94eecc | |||
635535aac2 | |||
25314fd91a | |||
9a06a5758d | |||
e5a2a9644f | |||
e0e7211852 | |||
cdaeb4d176 | |||
07aa2e280d | |||
6c4bc67ff3 | |||
d9f0cc27ef | |||
59aec9d289 | |||
451f4c503d | |||
cd82089d4d | |||
3db8b63cde | |||
6edf5d1e4f | |||
a23fa6fadd | |||
51eb77e409 | |||
691326cea8 | |||
3cac1238ed | |||
b04512a4f6 | |||
3a4d0549aa | |||
d7467f5dc3 | |||
141902b86d | |||
5aa680fc93 | |||
a790117f5a | |||
2a5a52c810 | |||
2156f4c2f3 | |||
2585460286 | |||
1b4af66986 | |||
0324bac044 | |||
2bfbe1ca27 | |||
60584228d9 | |||
44e34f7b11 | |||
7912050647 | |||
2231abd407 | |||
8d17ba4d66 | |||
8244bdb440 | |||
bc3b7ffd86 | |||
e22cb62493 | |||
e923aa1f72 | |||
68a21f1fbb | |||
74209e2607 | |||
1a38271104 | |||
e5ab5d6a5a | |||
2745ff727f | |||
24ea383937 | |||
9cb11d4d5f | |||
7202ea3340 | |||
d234ea01d0 | |||
e246cd37dd | |||
0a4ddedac9 | |||
0e4b80b002 | |||
a460a0dc44 | |||
f7212112b8 | |||
86d55b32a6 | |||
4b0d1aac15 | |||
fb7c06aa01 | |||
5c41be3470 | |||
a78df1a152 | |||
34e8db0fe3 | |||
70faecb8b5 | |||
237f278479 | |||
e766a00a12 | |||
ea03637ec1 | |||
d0f6d47b14 | |||
5bf1658d9a | |||
4ce9fb5b5a | |||
f80f02da73 | |||
52ece833a7 | |||
1ad6dde146 | |||
64bcfd23bd | |||
d659447879 | |||
e73eb55d75 | |||
a52cea29f4 | |||
3d91e59386 | |||
393b1d7674 | |||
c29a6b95ae | |||
567a4e8361 | |||
4d3e4c1a15 | |||
afeecdf4af | |||
4fe7105e2f | |||
d7c3a53f2d |
27
apps/enclave/LICENSE
Normal file
27
apps/enclave/LICENSE
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of any contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
79
apps/enclave/Makefile
Normal file
79
apps/enclave/Makefile
Normal file
@ -0,0 +1,79 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and should work on Linux
|
||||
# (Tested on Debian 3.0)
|
||||
#
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
BINDIR = bin
|
||||
LOGDIR = log
|
||||
OBJDIR = obj
|
||||
SRCDIR = src
|
||||
|
||||
SAMINCDIR = ../sam/c/inc
|
||||
SAMLIBDIR = ../sam/c/lib
|
||||
TOMCRYPTDIR = $(HOME)/libtomcrypt-0.96
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
CC = g++
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -march=i486 -pipe -Wall
|
||||
|
||||
#
|
||||
# Libraries
|
||||
#
|
||||
|
||||
CFLAGS += -I$(SAMINCDIR) -I$(TOMCRYPTDIR)
|
||||
LDFLAGS = -L$(SAMLIBDIR) -L$(TOMCRYPTDIR)
|
||||
LIBS = -lsam -ltomcrypt
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
|
||||
OBJS = $(OBJDIR)/bigint.o \
|
||||
$(OBJDIR)/chk.o \
|
||||
$(OBJDIR)/config.o \
|
||||
$(OBJDIR)/logger.o \
|
||||
$(OBJDIR)/main.o \
|
||||
$(OBJDIR)/peers.o \
|
||||
$(OBJDIR)/random.o \
|
||||
$(OBJDIR)/rpc.o \
|
||||
$(OBJDIR)/sam.o \
|
||||
$(OBJDIR)/sha1.o
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: depend enclave
|
||||
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCDIR)/*.cpp > .depend
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
enclave: $(OBJS)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $(BINDIR)/enclave $(OBJS) $(LIBS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f $(BINDIR)/* $(OBJDIR)/* .depend
|
||||
|
||||
clean-logs:
|
||||
-rm -f $(LOGDIR)/*
|
||||
|
||||
tidy: clean clean-logs
|
32
apps/enclave/cfg/enclave.cfg
Normal file
32
apps/enclave/cfg/enclave.cfg
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# This is the Enclave configuration file. Lines starting with # and blank lines
|
||||
# are ignored.
|
||||
#
|
||||
|
||||
# The DNS name or IP address of the SAM server you will be using
|
||||
samhost=localhost
|
||||
|
||||
# The TCP port the SAM server is listening on
|
||||
samport=7656
|
||||
|
||||
# The destination name of this program. This can be anything. If you run
|
||||
# multiple copies of Enclave off the same SAM server then each one has to have a
|
||||
# unique name.
|
||||
samname=enclave
|
||||
|
||||
# The depth used for incoming and outgoing I2P tunnels. Using a depth of 2 is
|
||||
# the default and a good choice. You can set it to 0 if you don't care about
|
||||
# anonymity and just want speed.
|
||||
tunneldepth=0
|
||||
|
||||
# The location of the peer references file. You can use an absolute or relative
|
||||
# path, but absolute paths are safer.
|
||||
references=cfg/peers.ref
|
||||
|
||||
# Record every log message at or above this priority level
|
||||
# debug = 0, minor = 1, info = 2, warn = 3, error = 4
|
||||
loglevel=0
|
||||
|
||||
# The location of the Enclave log file. You can use an absolute or relative
|
||||
# path, but absolute paths are safer.
|
||||
logfile=log/enclave.log
|
2
apps/enclave/cfg/peers.ref
Normal file
2
apps/enclave/cfg/peers.ref
Normal file
@ -0,0 +1,2 @@
|
||||
4KpEG0uUvTM~IZKuWZZifdmh5UU6evIPG0tE3ppoqy37AY2NJrsM8BU0EkT1SG-g18qSW9UHDp7qs7m~WzeWTXyYggEb6k6-e0GYC2Cj8ED8JV58-2~cFZumVNJ2d1hns-MGX7RZv2lz3Cz2ZVhfZxSIw9UnpV-kwVn7sQ7PBCvJYE4INbp5OlRQH1-3lXiUheoJfeZpegGTUSHUwIRWglX7w87YF~LCbJMYXDgMyA3SaxsZaun7Wc8ku4bqtbmG9u15XlmqimLUUmDG0cw77HJzqxnR1C1hx0wf-9zgH6u4jwTWk92w5tZJZSv1SHKejlPkIbRNAhZv5wroyZsn6T0koV~kTVCvbUEwILho-rHn4A6C2jLQifwE9aucziBTVq3YLK2urf1wI1jLh98iFNav40S~B2w-4xZFAQ49bOdWzY4KmVIjocVhfGi~RLl5bHD1TEJS7nOaDhI8qCSe7mR0XzZgQ~iROR~XowlwKXBzNPjKED7yN8GgV2pWRGNYAAAA
|
||||
WiotuvEjGpSz7q14eZGYFpD0xNt3V~nxZdDDgKc~whkW-pardZyz~wZipHXLIOvniThDL2rxJ~OW7RxgUycCph4x--NL51kEJhMWZ~bgxPioxw-T4JGQ9LSNndt9xNOf6yhEqyokqyEOEeJjw6m2e7RX7mTRffmTlCdu6uH6rVEk22o4Uu5S26p6-LS2k9lRyMWitFd~t9cnOgLTZTE~h4d-UlAd1BGxpCTlGWcaynOQzKKtljZknZMF9Qv19MxT83t18~3IURb6aOLlC4oih9pMt1pHouZuOaStKA7cGLsXUAhSB31BvK8l4R7VhgcudwJ9EQZkZQee51hcng7K1Yqmd4lnjHHuf1mDk0YXBAWDZOM0-oEwkJWumGuYl0NUtLhNlFrBjenbjACx88qhfy6mkXfo8c-c2QqEXuD2xt4OVqrWxBTIrr1pR-E1NdIxzIvOlCbrRXaqxqu-wnrrG2vCO-1zu9NHacCVjXD7AR7p3T628wPdCUzj2~rZRcCkAAAA
|
169
apps/enclave/src/bigint.cpp
Normal file
169
apps/enclave/src/bigint.cpp
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "bigint.hpp"
|
||||
|
||||
/******************************************************************************/
|
||||
// Note: All the const_casts below are necessary because libtomcrypt doesn't //
|
||||
// have its arguments as const, even when they are not changed //
|
||||
/******************************************************************************/
|
||||
|
||||
Bigint::Bigint(const Bigint& bigint)
|
||||
{
|
||||
init();
|
||||
copyover_mp_int(bigint.mpi);
|
||||
}
|
||||
|
||||
Bigint::Bigint(const uchar_t* data, size_t size)
|
||||
{
|
||||
init();
|
||||
import_uraw(data, size);
|
||||
}
|
||||
|
||||
Bigint::Bigint(uint16_t i)
|
||||
{
|
||||
init();
|
||||
i = htons(i);
|
||||
import_uraw(reinterpret_cast<uchar_t*>(&i), 2);
|
||||
}
|
||||
|
||||
Bigint::Bigint(uint32_t i)
|
||||
{
|
||||
init();
|
||||
i = htonl(i);
|
||||
import_uraw(reinterpret_cast<uchar_t*>(&i), 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Replaces our current mp_int with another one
|
||||
* (just a wrapper for mp_copy)
|
||||
*/
|
||||
void Bigint::copyover_mp_int(const mp_int& i)
|
||||
{
|
||||
int rc = mp_copy(const_cast<mp_int*>(&i), &mpi);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Saves a Bigint to a raw unsigned big-endian integer
|
||||
* Note that the result must be freed with delete[]
|
||||
*
|
||||
* size - filled with the size of the output
|
||||
*
|
||||
* Returns: binary data
|
||||
*/
|
||||
uchar_t* Bigint::export_uraw(size_t& size) const
|
||||
{
|
||||
uchar_t* out;
|
||||
size = mp_unsigned_bin_size(const_cast<mp_int*>(&mpi));
|
||||
if (size != 0) {
|
||||
out = new uchar_t[size];
|
||||
int rc = mp_to_unsigned_bin(const_cast<mp_int*>(&mpi), out);
|
||||
assert(rc == MP_OKAY);
|
||||
} else { // size == 0
|
||||
size = 1;
|
||||
out = new uchar_t[1];
|
||||
out[0] = 0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads a raw unsigned big-endian integer into Bigint
|
||||
*
|
||||
* data - binary data
|
||||
* size - size of data
|
||||
*/
|
||||
void Bigint::import_uraw(const uchar_t* data, size_t size)
|
||||
{
|
||||
uchar_t tmp[size]; // mp_read_unsigned_bin() arg 2 is not const
|
||||
memcpy(tmp, data, sizeof tmp); // I'm not taking any chances
|
||||
int rc = mp_read_unsigned_bin(&mpi, tmp, sizeof tmp);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialises the object
|
||||
*/
|
||||
void Bigint::init(void)
|
||||
{
|
||||
int rc = mp_init(&mpi);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
||||
|
||||
bool Bigint::operator<(const Bigint& rhs) const
|
||||
{
|
||||
int rc = mp_cmp(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi));
|
||||
if (rc == MP_LT)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
Bigint& Bigint::operator=(const Bigint& rhs)
|
||||
{
|
||||
if (this != &rhs) // check for self-assignment: a = a
|
||||
copyover_mp_int(rhs.mpi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Bigint::operator==(const Bigint& rhs) const
|
||||
{
|
||||
int rc = mp_cmp(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi));
|
||||
if (rc == MP_EQ)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Bigint::operator>(const Bigint& rhs) const
|
||||
{
|
||||
int rc = mp_cmp(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi));
|
||||
if (rc == MP_GT)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Xors another Bigint with this Bigint and puts the result in Bigint `result'.
|
||||
* We can't name it "xor" because that word is reserved in C++ (see Appendex C,
|
||||
* section 3.1 in TC++PL).
|
||||
*
|
||||
* rhs - the bigint to xor with
|
||||
* result - will be filled with the result of the xor
|
||||
*/
|
||||
void Bigint::x_or(const Bigint& rhs, Bigint& result) const
|
||||
{
|
||||
int rc = mp_xor(const_cast<mp_int*>(&mpi), const_cast<mp_int*>(&rhs.mpi),
|
||||
&result.mpi);
|
||||
assert(rc == MP_OKAY);
|
||||
}
|
60
apps/enclave/src/bigint.hpp
Normal file
60
apps/enclave/src/bigint.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef BIGINT_HPP
|
||||
#define BIGINT_HPP
|
||||
|
||||
class Bigint {
|
||||
public:
|
||||
Bigint(void) { init(); }
|
||||
Bigint(const Bigint& bigint);
|
||||
Bigint(const uchar_t* data, size_t size);
|
||||
Bigint(uint16_t i);
|
||||
Bigint(uint32_t i);
|
||||
~Bigint(void) { mp_clear(&mpi); }
|
||||
|
||||
uchar_t* export_uraw(size_t& size) const;
|
||||
const mp_int& get_mp_int(void) const { return mpi; }
|
||||
void import_uraw(const uchar_t* data, size_t size);
|
||||
bool operator<(const Bigint& rhs) const;
|
||||
Bigint& operator=(const Bigint& rhs);
|
||||
bool operator==(const Bigint& rhs) const;
|
||||
bool operator>(const Bigint& rhs) const;
|
||||
void x_or(const Bigint& rhs, Bigint& result) const;
|
||||
|
||||
protected:
|
||||
mp_int mpi;
|
||||
|
||||
private:
|
||||
void copyover_mp_int(const mp_int& i);
|
||||
void init(void);
|
||||
};
|
||||
|
||||
#endif // BIGINT_HPP
|
56
apps/enclave/src/chk.cpp
Normal file
56
apps/enclave/src/chk.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "chk.hpp"
|
||||
|
||||
Chk::Chk(const uchar_t* plaintext, size_t size, const string& mime_type)
|
||||
: data_size(size), mime_type(mime_type)
|
||||
{
|
||||
encrypt(plaintext);
|
||||
}
|
||||
|
||||
void Chk::encrypt(const uchar_t *pt)
|
||||
{
|
||||
int rc = register_cipher(&twofish_desc);
|
||||
assert(rc != -1);
|
||||
|
||||
uchar_t key[CRYPT_KEY_SIZE], iv[CRYPT_BLOCK_SIZE];
|
||||
prng->get_bytes(key, CRYPT_KEY_SIZE);
|
||||
prng->get_bytes(iv, CRYPT_BLOCK_SIZE);
|
||||
|
||||
symmetric_CTR ctr;
|
||||
rc = ctr_start(find_cipher("twofish"), iv, key, CRYPT_KEY_SIZE, 0, &ctr);
|
||||
assert(rc == CRYPT_OK);
|
||||
|
||||
ct = new uchar_t[data_size];
|
||||
rc = ctr_encrypt(pt, ct, data_size, &ctr);
|
||||
assert(rc == CRYPT_OK);
|
||||
}
|
51
apps/enclave/src/chk.hpp
Normal file
51
apps/enclave/src/chk.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CHK_HPP
|
||||
#define CHK_HPP
|
||||
|
||||
class Chk {
|
||||
public:
|
||||
//Chk(const uchar_t* cypertext, size_t size);
|
||||
Chk(const uchar_t* plaintext, size_t size, const string& mime_type);
|
||||
~Chk(void) { delete[] ct; }
|
||||
|
||||
private:
|
||||
static const size_t CRYPT_BLOCK_SIZE = 16;
|
||||
static const size_t CRYPT_KEY_SIZE = 32;
|
||||
|
||||
void encrypt(const uchar_t *pt);
|
||||
|
||||
uchar_t* ct; // cyphertext
|
||||
const size_t data_size;
|
||||
const string& mime_type; // I hate mimes.
|
||||
};
|
||||
|
||||
#endif // CHK_HPP
|
148
apps/enclave/src/config.cpp
Normal file
148
apps/enclave/src/config.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "bigint.hpp"
|
||||
|
||||
Config::Config(const string& file)
|
||||
: file(file)
|
||||
{
|
||||
set_defaults();
|
||||
parse();
|
||||
configf.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up a configuration option in the table and returns a constant value.
|
||||
* This is the same as get_property() except the value returned is a constant.
|
||||
*
|
||||
* key - key to lookup
|
||||
*
|
||||
* Returns the value associated with the key
|
||||
*/
|
||||
const string& Config::get_cproperty(const string& key) const
|
||||
{
|
||||
for (cfgmap_ci i = cfgmap.begin(); i != cfgmap.end(); i++) {
|
||||
const string s = i->first;
|
||||
if (s == key)
|
||||
return i->second;
|
||||
}
|
||||
LERROR << "Tried to lookup an invalid property: " << key << '\n';
|
||||
assert(false);
|
||||
// this should never occur, it's just to silence a compiler warning
|
||||
string* s = new string;
|
||||
return *s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets a property as an integer (they are all stored as strings)
|
||||
*
|
||||
* key - key to lookup
|
||||
*
|
||||
* Returns an integer of the value associated with the key
|
||||
*/
|
||||
int Config::get_iproperty(const string& key) const
|
||||
{
|
||||
for (cfgmap_ci i = cfgmap.begin(); i != cfgmap.end(); i++) {
|
||||
const string s = i->first;
|
||||
if (s == key)
|
||||
return atoi(i->second.c_str());
|
||||
}
|
||||
LERROR << "Tried to lookup an invalid property: " << key << '\n';
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Looks up a configuration option in the table and returns the value
|
||||
*
|
||||
* key - key to lookup
|
||||
*
|
||||
* Returns the value associated with the key
|
||||
*/
|
||||
string& Config::get_property(const string& key)
|
||||
{
|
||||
for (cfgmap_i i = cfgmap.begin(); i != cfgmap.end(); i++) {
|
||||
const string s = i->first;
|
||||
if (s == key)
|
||||
return i->second;
|
||||
}
|
||||
LERROR << "Tried to lookup an invalid property: " << key << '\n';
|
||||
assert(false);
|
||||
// this should never occur, it's just to silence a compiler warning
|
||||
string* s = new string;
|
||||
return *s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the configuration file, replacing default values with user defined
|
||||
* values
|
||||
*/
|
||||
void Config::parse(void)
|
||||
{
|
||||
configf.open(file.c_str());
|
||||
if (!configf) {
|
||||
cerr << "Error opening configuration file (" << file.c_str() << ")\n";
|
||||
throw runtime_error("Error opening configuration file");
|
||||
}
|
||||
size_t line = 0;
|
||||
string s;
|
||||
for (getline(configf, s); configf; getline(configf, s)) {
|
||||
line++;
|
||||
if (s.size() == 0 || s[0] == '#') // blank line or comment
|
||||
continue;
|
||||
size_t eqpos = s.find("=");
|
||||
if (eqpos == string::npos) {
|
||||
cerr << "Error parsing line #" << line << " in " << file << ": "
|
||||
<< s << '\n';
|
||||
continue;
|
||||
}
|
||||
string key = s.substr(0, eqpos);
|
||||
string value = s.substr(eqpos + 1);
|
||||
//cout << "Inserting key = " << key << " value = " << value << '\n';
|
||||
cfgmap.erase(key); // erase the default value created by set_defaults()
|
||||
cfgmap.insert(make_pair(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If you (the programmer) add something to the config file you should also add
|
||||
* it here, and vice versa
|
||||
*/
|
||||
void Config::set_defaults(void)
|
||||
{
|
||||
cfgmap.insert(make_pair("samhost", "localhost"));
|
||||
cfgmap.insert(make_pair("samport", "7656"));
|
||||
cfgmap.insert(make_pair("samname", "enclave"));
|
||||
cfgmap.insert(make_pair("tunneldepth", "2"));
|
||||
cfgmap.insert(make_pair("references", "cfg/peers.ref"));
|
||||
cfgmap.insert(make_pair("loglevel", "1"));
|
||||
cfgmap.insert(make_pair("logfile", "log/enclave.log"));
|
||||
}
|
54
apps/enclave/src/config.hpp
Normal file
54
apps/enclave/src/config.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_HPP
|
||||
#define CONFIG_HPP
|
||||
|
||||
class Config {
|
||||
public:
|
||||
Config(const string& file);
|
||||
|
||||
const string& get_cproperty(const string& key) const;
|
||||
int get_iproperty(const string& key) const;
|
||||
string& get_property(const string& key);
|
||||
|
||||
private:
|
||||
typedef map<const string, string>::const_iterator cfgmap_ci;
|
||||
typedef map<const string, string>::iterator cfgmap_i;
|
||||
|
||||
void parse(void);
|
||||
void set_defaults(void);
|
||||
|
||||
ifstream configf;
|
||||
const string file;
|
||||
map<const string, string> cfgmap;
|
||||
};
|
||||
|
||||
#endif // CONFIG_HPP
|
44
apps/enclave/src/logger.cpp
Normal file
44
apps/enclave/src/logger.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "logger.hpp"
|
||||
|
||||
Logger::Logger(const string& file)
|
||||
: file(file)
|
||||
{
|
||||
set_pri(debug);
|
||||
set_loglevel(static_cast<priority_t>(config->get_iproperty("loglevel")));
|
||||
logf.open(file.c_str(), ios::app);
|
||||
if (!logf) {
|
||||
cerr << "Error opening log file (" << file.c_str() << ")\n";
|
||||
throw runtime_error("Error opening log file");
|
||||
}
|
||||
}
|
84
apps/enclave/src/logger.hpp
Normal file
84
apps/enclave/src/logger.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LOGGER_HPP
|
||||
#define LOGGER_HPP
|
||||
|
||||
/*
|
||||
* LDEBUG - debugging messages
|
||||
* LMINOR - unimportant messages
|
||||
* LINFO - informational messages
|
||||
* LWARN - errors we automatically recover from
|
||||
* LERROR - major, important errors
|
||||
*/
|
||||
#if VERBOSE_LOGS
|
||||
#define LDEBUG logger->set_pri(Logger::debug); (*logger) << "(D)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LMINOR logger->set_pri(Logger::minor); (*logger) << "(M)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LINFO logger->set_pri(Logger::info); (*logger) << "(I)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LWARN logger->set_pri(Logger::warn); (*logger) << "(W)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#define LERROR logger->set_pri(Logger::error); (*logger) << "(E)" << __FILE__ << ':' << __LINE__ << ':' << __func__ << ": "
|
||||
#else
|
||||
#define LDEBUG logger->set_pri(Logger::debug); (*logger) << "(D)"
|
||||
#define LMINOR logger->set_pri(Logger::minor); (*logger) << "(M)"
|
||||
#define LINFO logger->set_pri(Logger::info); (*logger) << "(I)"
|
||||
#define LWARN logger->set_pri(Logger::warn); (*logger) << "(W)"
|
||||
#define LERROR logger->set_pri(Logger::error); (*logger) << "(E)"
|
||||
#endif
|
||||
|
||||
class Logger {
|
||||
public:
|
||||
typedef enum {debug = 0, minor = 1, info = 2, warn = 3, error = 4}
|
||||
priority_t;
|
||||
|
||||
Logger(const string& file);
|
||||
|
||||
void flush(void) { logf.flush(); }
|
||||
priority_t get_loglevel(void) const { return loglevel; }
|
||||
void set_loglevel(priority_t priority) { loglevel = priority; }
|
||||
Logger& operator<<(char c)
|
||||
{ if (priority >= loglevel) { logf << c; flush(); } return *this; }
|
||||
Logger& operator<<(const char* c)
|
||||
{ if (priority >= loglevel) { logf << c; flush(); } return *this; }
|
||||
Logger& operator<<(int i)
|
||||
{ if (priority >= loglevel) { logf << i; flush(); } return *this; }
|
||||
Logger& operator<<(const string& s)
|
||||
{ if (priority >= loglevel) { logf << s; flush(); } return *this; }
|
||||
Logger& operator<<(unsigned int i)
|
||||
{ if (priority >= loglevel) { logf << i; flush(); } return *this; }
|
||||
void set_pri(priority_t priority) { this->priority = priority; }
|
||||
|
||||
private:
|
||||
priority_t priority; // importance of the following log message(s)
|
||||
string file;
|
||||
priority_t loglevel; // write log messsages at or above this priority
|
||||
ofstream logf;
|
||||
};
|
||||
|
||||
#endif // LOGGER_HPP
|
84
apps/enclave/src/main.cpp
Normal file
84
apps/enclave/src/main.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "main.hpp"
|
||||
|
||||
Config *config; // Configuration options
|
||||
Logger *logger; // Logging mechanism
|
||||
Random *prng; // Random number generator
|
||||
Sam *sam; // SAM connection
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 2) { // put some getopts stuff in here later
|
||||
cerr << "Please specify the configuration file location.\n" \
|
||||
"e.g. 'bin/enclave cfg/enclave.cfg'\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
config = new Config(argv[1]);
|
||||
} catch (const runtime_error& x) {
|
||||
return 0;
|
||||
}
|
||||
logger = new Logger(config->get_cproperty("logfile"));
|
||||
LINFO << "Enclave DHT - Built on " << __DATE__ << ' ' << __TIME__ << '\n';
|
||||
prng = new Random;
|
||||
try {
|
||||
sam = new Sam(config->get_cproperty("samhost"),
|
||||
config->get_iproperty("samport"), config->get_cproperty("samname"),
|
||||
config->get_iproperty("tunneldepth"));
|
||||
} catch (const Sam_error& x) {
|
||||
LERROR << "SAM error: " << x.what() << '\n';
|
||||
cerr << "SAM error: " << x.what() << '\n';
|
||||
if (x.code() == SAM_SOCKET_ERROR) {
|
||||
LERROR << "Check whether you have specified the correct SAM host " \
|
||||
"and port number, and that I2P is running.\n";
|
||||
cerr << "Check whether you have specified the correct SAM host " \
|
||||
"and port number, and that\nI2P is running.\n";
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
sam->naming_lookup();
|
||||
while (sam->get_my_dest() == "")
|
||||
sam->read_buffer(); // wait until we get our own dest back from lookup
|
||||
|
||||
sam->peers->advertise_self();
|
||||
|
||||
while (true)
|
||||
sam->read_buffer();
|
||||
|
||||
delete sam;
|
||||
delete prng;
|
||||
delete logger;
|
||||
delete config;
|
||||
return 0;
|
||||
}
|
36
apps/enclave/src/main.hpp
Normal file
36
apps/enclave/src/main.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef MAIN_HPP
|
||||
#define MAIN_HPP
|
||||
|
||||
// intentionally left blank
|
||||
|
||||
#endif // MAIN_HPP
|
54
apps/enclave/src/near_peer.hpp
Normal file
54
apps/enclave/src/near_peer.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef NEAR_PEER_HPP
|
||||
#define NEAR_PEER_HPP
|
||||
|
||||
//
|
||||
// Used for finding the closest peers to a sha1
|
||||
//
|
||||
|
||||
class Near_peer {
|
||||
public:
|
||||
Near_peer(const Bigint& distance, Peer* peer)
|
||||
: distance(distance), peer(peer) {}
|
||||
|
||||
Peer* get_peer(void) const { return peer; }
|
||||
bool operator<(const Near_peer& rhs) const
|
||||
{ if (distance < rhs.distance) return true; else return false; }
|
||||
|
||||
protected:
|
||||
const Bigint distance;
|
||||
|
||||
private:
|
||||
Peer* peer;
|
||||
};
|
||||
|
||||
#endif // NEAR_PEER_HPP
|
52
apps/enclave/src/peer.hpp
Normal file
52
apps/enclave/src/peer.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PEER_HPP
|
||||
#define PEER_HPP
|
||||
|
||||
class Peer {
|
||||
public:
|
||||
Peer(const string& dest, const Sha1& kaddr)
|
||||
: dest(dest), kaddr(kaddr), lag(-1) {}
|
||||
|
||||
const string& get_b64kaddr(void) const { return kaddr.b64hash(); }
|
||||
const uchar_t* get_binkaddr(void) const { return kaddr.binhash(); }
|
||||
const string& get_dest(void) const { return dest; }
|
||||
int get_lag(void) const { return lag; }
|
||||
const string get_sdest(void) const { return dest.substr(0, 8); }
|
||||
void set_lag(int lag) { this->lag = lag; }
|
||||
|
||||
private:
|
||||
const string dest;
|
||||
const Sha1 kaddr;
|
||||
int lag; // if -1, then it is unknown
|
||||
};
|
||||
|
||||
#endif // PEER_HPP
|
220
apps/enclave/src/peers.cpp
Normal file
220
apps/enclave/src/peers.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "near_peer.hpp"
|
||||
#include "rpc.hpp"
|
||||
#include "sha1.hpp"
|
||||
#include "peers.hpp"
|
||||
|
||||
/*
|
||||
* Inform other peers of our existence and collect the destination addresses of
|
||||
* nearby peers
|
||||
*/
|
||||
void Peers::advertise_self(void)
|
||||
{
|
||||
list<Near_peer> near_peers;
|
||||
get_nearest(sam->get_my_sha1(), PAR_RPCS, near_peers);
|
||||
for (list<Near_peer>::const_iterator i = near_peers.begin();
|
||||
i != near_peers.end(); i++) {
|
||||
Rpc rpc(i->get_peer());
|
||||
rpc.find_peers(sam->get_my_sha1());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the `n' nearest peers by xoring a sha1 with a kaddr
|
||||
*
|
||||
* sha1 - sha1 to find nearness to
|
||||
* n - number of peers to find
|
||||
* near_peers - a list to put the found peers in
|
||||
*/
|
||||
void Peers::get_nearest(const Sha1& sha1, size_t n, list<Near_peer>& near_peers)
|
||||
{
|
||||
near_peers.clear(); // prevents duplicate peers in the list
|
||||
for (peersmap_i i = peersmap.begin(); i != peersmap.end(); i++) {
|
||||
const Sha1& kaddr = i->first;
|
||||
Bigint distance;
|
||||
sha1.x_or(kaddr, distance);
|
||||
Near_peer np(distance, &(i->second));
|
||||
near_peers.insert(near_peers.end(), np);
|
||||
}
|
||||
near_peers.sort();
|
||||
while (near_peers.size() > n)
|
||||
near_peers.pop_back();
|
||||
}
|
||||
|
||||
Peer* Peers::get_peer_by_dest(const sam_pubkey_t dest)
|
||||
{
|
||||
const string s = dest;
|
||||
return get_peer_by_dest(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets a peer by its base 64 destination address
|
||||
*
|
||||
* dest - destination
|
||||
*
|
||||
* Returns: pointer to peer, or 0 if the peer wasn't found
|
||||
*/
|
||||
Peer* Peers::get_peer_by_dest(const string& dest)
|
||||
{
|
||||
for (peersmap_i i = peersmap.begin(); i != peersmap.end(); i++) {
|
||||
Peer& tmp = i->second;
|
||||
if (tmp.get_dest() == dest)
|
||||
return &(i->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets a peer by its Kademlia address
|
||||
*
|
||||
* kaddr - Kademlia adddress
|
||||
*
|
||||
* Returns: pointer to peer, or 0 if the peer wasn't found
|
||||
*/
|
||||
Peer* Peers::get_peer_by_kaddr(const Sha1& kaddr)
|
||||
{
|
||||
peersmap_i i = peersmap.find(kaddr);
|
||||
if (i != peersmap.end())
|
||||
return &(i->second);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads peer addresses from a file
|
||||
*/
|
||||
void Peers::load(void)
|
||||
{
|
||||
string dest;
|
||||
|
||||
ifstream peersf(file.c_str());
|
||||
if (!peersf) {
|
||||
LERROR << "Couldn't load peers reference file (" << file.c_str()
|
||||
<< ")\n";
|
||||
if (peersmap.size() > 0)
|
||||
return;
|
||||
else
|
||||
throw runtime_error("No peer references in memory");
|
||||
}
|
||||
|
||||
for (getline(peersf, dest); peersf; getline(peersf, dest))
|
||||
new_peer(dest);
|
||||
|
||||
if (peersmap.size() > 0) {
|
||||
LMINOR << peersmap.size() << " peer references in memory\n";
|
||||
} else
|
||||
throw runtime_error("No peer references in memory");
|
||||
}
|
||||
|
||||
Peer* Peers::new_peer(const sam_pubkey_t dest)
|
||||
{
|
||||
const string s = dest;
|
||||
return new_peer(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adds a newly discovered peer to the peers map
|
||||
*
|
||||
* dest - destination address of the peer
|
||||
*
|
||||
* Returns: pointer to the peer
|
||||
*/
|
||||
Peer* Peers::new_peer(const string& dest)
|
||||
{
|
||||
// Check the destination address
|
||||
if (!sam->valid_dest(dest)) {
|
||||
LWARN << "Bad format in peer reference: " << dest.substr(0, 8) << '\n';
|
||||
return 0;
|
||||
}
|
||||
// Never add our own peer to the peers we can connect to
|
||||
if (dest == sam->get_my_dest()) {
|
||||
LDEBUG << "Not adding my own peer reference: " << dest.substr(0, 8)
|
||||
<< '\n';
|
||||
return 0;
|
||||
}
|
||||
// Be sure that the peer is not already known to us
|
||||
Peer *peer = get_peer_by_dest(dest);
|
||||
if (peer != 0) {
|
||||
LDEBUG << "Redundant peer reference: " << dest.substr(0, 8) << '\n';
|
||||
return peer;
|
||||
}
|
||||
|
||||
// Tests passed, add it
|
||||
Sha1 sha1(dest);
|
||||
pair<peersmap_i, bool> p = peersmap.insert(
|
||||
make_pair(sha1, Peer(dest, sha1)));
|
||||
assert(p.second);
|
||||
LMINOR << "New peer reference: " << dest.substr(0, 8)
|
||||
<< " (Kaddr: " << sha1.b64hash() << ")\n";
|
||||
peer = &(p.first->second);
|
||||
return peer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Saves peer destinations to a file
|
||||
*
|
||||
* file - the file to save to
|
||||
*/
|
||||
void Peers::save(void)
|
||||
{
|
||||
ofstream peersf(file.c_str());
|
||||
if (!peersf) {
|
||||
LERROR << "Error opening peers reference file (" << file.c_str()
|
||||
<< ")\n";
|
||||
return;
|
||||
}
|
||||
|
||||
LDEBUG << "Saving " << peersmap.size() + 1 << " peer references\n";
|
||||
peersf << sam->get_my_dest() << '\n';
|
||||
for (peersmap_ci i = peersmap.begin(); i != peersmap.end(); i++) {
|
||||
const Peer& tmp = i->second;
|
||||
peersf << tmp.get_dest() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Stores data on some peers
|
||||
*
|
||||
* sha1 - the sha1 value for the data
|
||||
* data - the data
|
||||
*/
|
||||
void Peers::store(const Sha1& sha1)
|
||||
{
|
||||
list<Near_peer> near_peers;
|
||||
get_nearest(sam->get_my_sha1(), PAR_RPCS, near_peers);
|
||||
for (list<Near_peer>::const_iterator i = near_peers.begin();
|
||||
i != near_peers.end(); i++) {
|
||||
Rpc rpc(i->get_peer());
|
||||
rpc.store(sha1);
|
||||
}
|
||||
}
|
65
apps/enclave/src/peers.hpp
Normal file
65
apps/enclave/src/peers.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PEERS_HPP
|
||||
#define PEERS_HPP
|
||||
|
||||
class Peers {
|
||||
public:
|
||||
static const int PAR_RPCS = 3; // The number of parallel RPCs to send
|
||||
static const int RET_REFS = 20; // The number of peer refs to return on
|
||||
// failed requests
|
||||
Peers(const string& file)
|
||||
: file(file)
|
||||
{ load(); }
|
||||
~Peers(void) { save(); }
|
||||
|
||||
void advertise_self(void);
|
||||
void get_nearest(const Sha1& sha1, size_t n,
|
||||
list<Near_peer>& near_peers);
|
||||
Peer* get_peer_by_dest(const sam_pubkey_t dest);
|
||||
Peer* get_peer_by_dest(const string& dest);
|
||||
Peer* get_peer_by_kaddr(const Sha1& kaddr);
|
||||
Peer* new_peer(const sam_pubkey_t dest);
|
||||
Peer* new_peer(const string& dest);
|
||||
void store(const Sha1& sha1);
|
||||
|
||||
private:
|
||||
typedef map<const Sha1, Peer>::const_iterator peersmap_ci;
|
||||
typedef map<const Sha1, Peer>::iterator peersmap_i;
|
||||
|
||||
void load(void);
|
||||
void save(void);
|
||||
|
||||
const string file;
|
||||
map<const Sha1, Peer> peersmap;
|
||||
};
|
||||
|
||||
#endif // PEERS_HPP
|
93
apps/enclave/src/platform.hpp
Normal file
93
apps/enclave/src/platform.hpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_HPP
|
||||
#define PLATFORM_HPP
|
||||
|
||||
/*
|
||||
* Operating system
|
||||
*/
|
||||
#define FREEBSD 0 // FreeBSD (untested)
|
||||
#define MINGW 1 // Windows native (Mingw)
|
||||
#define LINUX 2 // Linux
|
||||
#define CYGWIN 3 // Cygwin
|
||||
|
||||
/*
|
||||
* System includes
|
||||
*/
|
||||
#include <arpa/inet.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* Define this to '1' to cause the printing of source code file and line number
|
||||
* information with each log message. Set it to '0' for simple logging.
|
||||
*/
|
||||
#define VERBOSE_LOGS 0
|
||||
|
||||
/*
|
||||
* Library includes
|
||||
*/
|
||||
#include "mycrypt.h" // LibTomCrypt
|
||||
#include "sam.h" // LibSAM
|
||||
|
||||
/*
|
||||
* Local includes
|
||||
*/
|
||||
#include "logger.hpp" // Logger
|
||||
#include "config.hpp" // Config
|
||||
#include "sam_error.hpp" // for sam.hpp
|
||||
#include "bigint.hpp" // for sha1.hpp
|
||||
#include "sha1.hpp" // for peers.hpp
|
||||
#include "peer.hpp" // for peers.hpp
|
||||
#include "near_peer.hpp" // for peers.hpp
|
||||
#include "peers.hpp" // for sam.hpp
|
||||
#include "sam.hpp" // SAM
|
||||
#include "random.hpp" // Random
|
||||
|
||||
/*
|
||||
* Global variables
|
||||
*/
|
||||
extern Config *config; // Configuration options
|
||||
extern Logger *logger; // Logging mechanism
|
||||
extern Random *prng; // Random number generator
|
||||
extern Sam *sam; // Sam connection
|
||||
|
||||
#endif // PLATFORM_HPP
|
65
apps/enclave/src/random.cpp
Normal file
65
apps/enclave/src/random.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "random.hpp"
|
||||
|
||||
/*
|
||||
* Prepares the Yarrow PRNG for use
|
||||
*/
|
||||
Random::Random(void)
|
||||
{
|
||||
LMINOR << "Initalising PRNG\n";
|
||||
|
||||
int rc = yarrow_start(&prng);
|
||||
assert(rc == CRYPT_OK);
|
||||
|
||||
uchar_t entropy[ENTROPY_SIZE];
|
||||
size_t sz = rng_get_bytes(entropy, ENTROPY_SIZE, NULL);
|
||||
assert(sz == ENTROPY_SIZE);
|
||||
|
||||
rc = yarrow_add_entropy(entropy, ENTROPY_SIZE, &prng);
|
||||
assert(rc == CRYPT_OK);
|
||||
|
||||
rc = yarrow_ready(&prng);
|
||||
assert(rc == CRYPT_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets `size' random bytes from the PRNG
|
||||
*
|
||||
* random - space to fill with random bytes
|
||||
* size - size of `random'
|
||||
*/
|
||||
void Random::get_bytes(uchar_t* random, size_t size)
|
||||
{
|
||||
size_t sz = yarrow_read(random, size, &prng);
|
||||
assert(sz == size);
|
||||
}
|
45
apps/enclave/src/random.hpp
Normal file
45
apps/enclave/src/random.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RANDOM_HPP
|
||||
#define RANDOM_HPP
|
||||
|
||||
class Random {
|
||||
public:
|
||||
Random(void);
|
||||
|
||||
void get_bytes(uchar_t* random, size_t size);
|
||||
|
||||
private:
|
||||
static const size_t ENTROPY_SIZE = 32;
|
||||
prng_state prng;
|
||||
};
|
||||
|
||||
#endif // RNG_HPP
|
233
apps/enclave/src/rpc.cpp
Normal file
233
apps/enclave/src/rpc.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "rpc.hpp"
|
||||
|
||||
// These can't be 'const' because I have to make them big-endian first
|
||||
uint16_t Rpc::VERSION = htons(1);
|
||||
uint16_t Rpc::OLDEST_GOOD_VERSION = htons(1);
|
||||
|
||||
/*
|
||||
* Requests a peer to find the addresses of the closest peers to the specified
|
||||
* sha1 and return them
|
||||
*
|
||||
* sha1 - closeness to this sha1
|
||||
*/
|
||||
void Rpc::find_peers(const Sha1& sha1)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FIND_PEERS\n";
|
||||
|
||||
// VERSION + command + bin sha1
|
||||
const size_t len = sizeof VERSION + 1 + Sha1::SHA1BIN_LEN;
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = FIND_PEERS;
|
||||
p++;
|
||||
memcpy(p, sha1.binhash(), Sha1::SHA1BIN_LEN);
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the closest peer references to a Sha1
|
||||
*
|
||||
* sha1 - sha1 to test nearness to
|
||||
*/
|
||||
void Rpc::found_peers(const Sha1& sha1)
|
||||
{
|
||||
list<Near_peer> near_peers;
|
||||
sam->peers->get_nearest(sha1, Peers::RET_REFS, near_peers);
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FOUND_PEERS (" << near_peers.size() << " peers)\n";
|
||||
|
||||
// VERSION + command + number of sha1s (0-255) + bin sha1s
|
||||
const size_t len = sizeof VERSION + 1 + 1 +
|
||||
(near_peers.size() * (SAM_PUBKEY_LEN - 1));
|
||||
assert(near_peers.size() <= 255);
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = FOUND_PEERS;
|
||||
p++;
|
||||
*p = near_peers.size();
|
||||
p++;
|
||||
for (list<Near_peer>::const_iterator i = near_peers.begin();
|
||||
i != near_peers.end(); i++) {
|
||||
const Peer* peer = i->get_peer();
|
||||
memcpy(p, peer->get_dest().c_str(), (SAM_PUBKEY_LEN - 1));
|
||||
p += SAM_PUBKEY_LEN - 1;
|
||||
}
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse incoming data and invoke the appropriate RPC
|
||||
*
|
||||
* data - the data
|
||||
* size - the size of `data'
|
||||
*/
|
||||
void Rpc::parse(const void* data, size_t size)
|
||||
{
|
||||
uint16_t his_ver;
|
||||
|
||||
memcpy(&his_ver, data, sizeof VERSION);
|
||||
if (ntohs(his_ver) < ntohs(VERSION)) {
|
||||
LMINOR << "Ignored RPC from " << peer->get_sdest() << " ["
|
||||
<< peer->get_b64kaddr() << "] using obsolete protocol version "
|
||||
<< ntohs(his_ver) << '\n';
|
||||
return;
|
||||
} else if (size <= 4) {
|
||||
LWARN << "RPC too small from " << peer->get_sdest() << " ["
|
||||
<< peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
const uchar_t* p = static_cast<const uchar_t*>(data);
|
||||
|
||||
if (p[2] == PING) { //-----------------------------------------------------
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PING\n";
|
||||
uint32_t ptime;
|
||||
if (size != sizeof VERSION + 1 + sizeof ptime) {
|
||||
LWARN << "Malformed PING RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
p += sizeof VERSION + 1;
|
||||
memcpy(&ptime, p, sizeof ptime);
|
||||
pong(ptime); // no need to ntohl() it here because we're just copying it
|
||||
return;
|
||||
|
||||
} else if (p[2] == PONG) { //----------------------------------------------
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PONG\n";
|
||||
uint32_t ptime;
|
||||
if (size != sizeof VERSION + 1 + sizeof ptime) {
|
||||
LWARN << "Malformed PONG RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
p += sizeof VERSION + 1;
|
||||
memcpy(&ptime, p, sizeof ptime);
|
||||
ptime = ntohl(ptime);
|
||||
uint32_t now = time(NULL);
|
||||
peer->set_lag(now - ptime);
|
||||
LDEBUG << "Lag is " << peer->get_lag() << " seconds\n";
|
||||
return;
|
||||
|
||||
} else if (p[2] == FIND_PEERS) { //----------------------------------------
|
||||
if (size != sizeof VERSION + 1 + Sha1::SHA1BIN_LEN) {
|
||||
LWARN << "Malformed FIND_PEERS RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FIND_PEERS\n";
|
||||
found_peers(Sha1(p + 4));
|
||||
return;
|
||||
|
||||
} else if (p[2] == FOUND_PEERS) { //---------------------------------------
|
||||
const size_t refs = p[3];
|
||||
if (size != sizeof VERSION + 1 + 1 + (refs * (SAM_PUBKEY_LEN - 1))) {
|
||||
LWARN << "Malformed FOUND_PEERS RPC from " << peer->get_sdest()
|
||||
<< " [" << peer->get_b64kaddr() << "]\n";
|
||||
return;
|
||||
}
|
||||
LDEBUG << "From: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: FOUND_PEERS (" << refs << " peers)\n";
|
||||
p += sizeof VERSION + 1 + 1;
|
||||
for (size_t i = 1; i <= refs; i++) {
|
||||
sam_pubkey_t dest;
|
||||
memcpy(dest, p, SAM_PUBKEY_LEN - 1); // - 1 == no NUL in RPC
|
||||
dest[SAM_PUBKEY_LEN - 1] = '\0';
|
||||
//LDEBUG << "Message had: " << dest << '\n';
|
||||
sam->peers->new_peer(dest);
|
||||
p += SAM_PUBKEY_LEN - 1;
|
||||
}
|
||||
return;
|
||||
|
||||
} else //------------------------------------------------------------------
|
||||
LWARN << "Unknown RPC #" << static_cast<int>(p[2]) << " from "
|
||||
<< peer->get_sdest() << " [" << peer->get_b64kaddr() << "]\n";
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a ping to someone
|
||||
*/
|
||||
void Rpc::ping(void)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PING\n";
|
||||
|
||||
uint32_t now = htonl(time(NULL));
|
||||
// VERSION + command + seconds since 1970
|
||||
const size_t len = sizeof VERSION + 1 + sizeof now;
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = PING;
|
||||
p++;
|
||||
memcpy(p, &now, sizeof now);
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a ping reply to someone
|
||||
*
|
||||
* ptime - the time the peer sent us (we echo the same time back)
|
||||
*/
|
||||
void Rpc::pong(uint32_t ptime)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: PONG\n";
|
||||
|
||||
// VERSION + command + pinger's seconds since 1970 echoed back
|
||||
const size_t len = sizeof VERSION + 1 + sizeof ptime;
|
||||
uchar_t buf[len];
|
||||
uchar_t* p = static_cast<uchar_t*>(memcpy(buf, &VERSION, sizeof VERSION));
|
||||
p += sizeof VERSION;
|
||||
*p = PONG;
|
||||
p++;
|
||||
memcpy(p, &ptime, sizeof ptime);
|
||||
sam->send_dgram(peer->get_dest(), buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tells a peer to store some data
|
||||
*
|
||||
* sha1 - sha1 value for the data
|
||||
* data - the data
|
||||
*/
|
||||
void Rpc::store(const Sha1& sha1)
|
||||
{
|
||||
LDEBUG << "To: " << peer->get_sdest() << " [" << peer->get_b64kaddr()
|
||||
<< "] Msg: STORE\n";
|
||||
}
|
65
apps/enclave/src/rpc.hpp
Normal file
65
apps/enclave/src/rpc.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RPC_HPP
|
||||
#define RPC_HPP
|
||||
|
||||
class Rpc {
|
||||
public:
|
||||
// The PROTOCOL version we are using
|
||||
static uint16_t VERSION;
|
||||
// The oldest version we will talk to
|
||||
static uint16_t OLDEST_GOOD_VERSION;
|
||||
// RPC identifiers (0-255)
|
||||
typedef enum {
|
||||
PING = 0,
|
||||
PONG = 1,
|
||||
FIND_PEERS = 2,
|
||||
FOUND_PEERS = 3,
|
||||
STORE = 4
|
||||
} rpc_t;
|
||||
|
||||
Rpc(Peer* peer)
|
||||
: peer(peer) {};
|
||||
|
||||
void find_peers(const Sha1& sha1);
|
||||
void parse(const void* data, size_t size);
|
||||
void ping(void);
|
||||
void store(const Sha1& sha1);
|
||||
|
||||
private:
|
||||
void found_peers(const Sha1& sha1);
|
||||
void pong(uint32_t ptime);
|
||||
|
||||
Peer* peer;
|
||||
basic_string<uchar_t> data;
|
||||
};
|
||||
|
||||
#endif // RPC_HPP
|
248
apps/enclave/src/sam.cpp
Normal file
248
apps/enclave/src/sam.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "rpc.hpp"
|
||||
#include "sam.hpp"
|
||||
|
||||
extern "C" {
|
||||
/*
|
||||
* Assorted callbacks required by LibSAM - ugly, but it works
|
||||
*/
|
||||
static void dgramback(sam_pubkey_t dest, void* data, size_t size);
|
||||
static void diedback(void);
|
||||
static void logback(char* str);
|
||||
static void namingback(char* name, sam_pubkey_t pubkey, samerr_t result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prevents more than one Sam object from existing in the program at a time
|
||||
* (LibSAM limitation)
|
||||
*/
|
||||
bool Sam::exists = false;
|
||||
|
||||
Sam::Sam(const string& samhost, uint16_t samport, const string& destname,
|
||||
uint_t tunneldepth)
|
||||
{
|
||||
// Only allow one Sam object to exist at a time
|
||||
assert(!exists);
|
||||
exists = true;
|
||||
|
||||
// hook up callbacks
|
||||
sam_dgramback = &dgramback;
|
||||
sam_diedback = &diedback;
|
||||
sam_logback = &logback;
|
||||
sam_namingback = &namingback;
|
||||
|
||||
// we haven't connected to SAM yet
|
||||
set_connected(false);
|
||||
|
||||
// now try to connect to SAM
|
||||
connect(samhost.c_str(), samport, destname.c_str(), tunneldepth);
|
||||
}
|
||||
|
||||
Sam::~Sam(void)
|
||||
{
|
||||
delete peers; // this must be before set_connected(false)!
|
||||
if (get_connected()) {
|
||||
sam_close();
|
||||
set_connected(false);
|
||||
}
|
||||
exists = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connects to the SAM host
|
||||
*
|
||||
* samhost - host that SAM is running on (hostname or IP address)
|
||||
* samport - port number that SAM is running own
|
||||
* destname - the destination name of this program
|
||||
* tunneldepth - how long the tunnels should be
|
||||
*/
|
||||
void Sam::connect(const char* samhost, uint16_t samport, const char* destname,
|
||||
uint_t tunneldepth)
|
||||
{
|
||||
assert(!get_connected());
|
||||
LMINOR << "Connecting to SAM as '" << destname << "'\n";
|
||||
samerr_t rc = sam_connect(samhost, samport, destname, SAM_DGRAM, tunneldepth);
|
||||
if (rc == SAM_OK)
|
||||
set_connected(true);
|
||||
else
|
||||
throw Sam_error(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loads peer references from disk
|
||||
* Note: this can only be called after my_dest has been set
|
||||
*/
|
||||
void Sam::load_peers(void)
|
||||
{
|
||||
peers = new Peers(config->get_cproperty("references"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts `name' to a base 64 destination
|
||||
*
|
||||
* name - name to lookup
|
||||
*/
|
||||
void Sam::naming_lookup(const string& name) const
|
||||
{
|
||||
assert(get_connected());
|
||||
sam_naming_lookup(name.c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses an incoming datagram
|
||||
*
|
||||
* dest - source destination address
|
||||
* data - datagram payload
|
||||
* size - size of `data'
|
||||
*/
|
||||
void Sam::parse_dgram(const string& dest, void* data, size_t size)
|
||||
{
|
||||
assert(get_connected());
|
||||
Peer* peer = peers->new_peer(dest);
|
||||
Rpc rpc(peer);
|
||||
rpc.parse(data, size);
|
||||
rpc.ping();
|
||||
free(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks the SAM connection for incoming commands and invokes callbacks
|
||||
*/
|
||||
void Sam::read_buffer(void)
|
||||
{
|
||||
assert(get_connected());
|
||||
sam_read_buffer();
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends a datagram to a destination
|
||||
*
|
||||
* dest - destination to send to
|
||||
* data - data to send
|
||||
* size - size of `data'
|
||||
*/
|
||||
void Sam::send_dgram(const string& dest, uchar_t *data, size_t size)
|
||||
{
|
||||
samerr_t rc = sam_dgram_send(dest.c_str(), data, size);
|
||||
assert(rc == SAM_OK); // i.e. not SAM_TOO_BIG
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets the connection status
|
||||
*
|
||||
* connected - true for connected, false for disconnected
|
||||
*/
|
||||
void Sam::set_connected(bool connected)
|
||||
{
|
||||
if (!connected)
|
||||
my_dest = "";
|
||||
this->connected = connected;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets my destination address
|
||||
*
|
||||
* pubkey - the base 64 destination
|
||||
*/
|
||||
void Sam::set_my_dest(const sam_pubkey_t pubkey)
|
||||
{
|
||||
my_dest = pubkey;
|
||||
my_sha1 = Sha1(my_dest);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the destination specified is of a valid base 64 syntax
|
||||
*
|
||||
* Returns: true if it is valid, false if it isn't
|
||||
*/
|
||||
bool Sam::valid_dest(const string& dest)
|
||||
{
|
||||
if (dest.size() != 516)
|
||||
return false;
|
||||
if (dest.substr(512, 4) == "AAAA") // note this AAAA signifies a null
|
||||
return true; // certificate - may not be true in the
|
||||
else // future
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * Callbacks * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Unfortunately these aren't part of the "Sam" object because they are function
|
||||
* pointers to _C_ functions. As a hack, we just have them call the global Sam
|
||||
* object.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Callback: A datagram was received
|
||||
*/
|
||||
static void dgramback(sam_pubkey_t dest, void* data, size_t size)
|
||||
{
|
||||
sam->parse_dgram(dest, data, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback: The connection to SAM has failed
|
||||
*/
|
||||
static void diedback(void)
|
||||
{
|
||||
LERROR << "Connection to SAM lost!\n";
|
||||
sam->set_connected(false);
|
||||
throw Sam_error(SAM_SOCKET_ERROR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback: A log message has been sent from LibSAM
|
||||
*/
|
||||
static void logback(char* str)
|
||||
{
|
||||
LINFO << "LibSAM: " << str << '\n';
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback: A naming lookup has completed
|
||||
*/
|
||||
static void namingback(char* name, sam_pubkey_t pubkey, samerr_t result)
|
||||
{
|
||||
Sam_error res(result);
|
||||
if (res.code() == SAM_OK) {
|
||||
if (strcmp(name, "ME") == 0) {
|
||||
sam->set_my_dest(pubkey);
|
||||
sam->load_peers();
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
} else {
|
||||
LERROR << "Naming look failed for '" << name << "': " << res.what()
|
||||
<< '\n';
|
||||
}
|
||||
}
|
66
apps/enclave/src/sam.hpp
Normal file
66
apps/enclave/src/sam.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SAM_HPP
|
||||
#define SAM_HPP
|
||||
|
||||
class Sam {
|
||||
public:
|
||||
Sam(const string& samhost, uint16_t samport, const string& destname,
|
||||
uint_t tunneldepth);
|
||||
~Sam(void);
|
||||
|
||||
const string& get_my_dest(void) const { return my_dest; }
|
||||
const Sha1& get_my_sha1(void) const { return my_sha1; }
|
||||
void naming_lookup(const string& name = "ME") const;
|
||||
void read_buffer(void);
|
||||
void send_dgram(const string& dest, uchar_t *data, size_t size);
|
||||
bool valid_dest(const string& dest);
|
||||
|
||||
Peers* peers;
|
||||
|
||||
//callback-private:
|
||||
void load_peers(void);
|
||||
void parse_dgram(const string& dest, void* data, size_t size);
|
||||
void set_connected(bool connected);
|
||||
void set_my_dest(const sam_pubkey_t pubkey);
|
||||
|
||||
private:
|
||||
void connect(const char* samhost, uint16_t samport,
|
||||
const char* destname, uint_t tunneldepth);
|
||||
bool get_connected(void) const { return connected; }
|
||||
|
||||
bool connected;
|
||||
static bool exists;
|
||||
string my_dest;
|
||||
Sha1 my_sha1;
|
||||
};
|
||||
|
||||
#endif // SAM_HPP
|
46
apps/enclave/src/sam_error.hpp
Normal file
46
apps/enclave/src/sam_error.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SAM_ERROR_HPP
|
||||
#define SAM_ERROR_HPP
|
||||
|
||||
class Sam_error {
|
||||
public:
|
||||
Sam_error(samerr_t error)
|
||||
: errcode(error) {}
|
||||
|
||||
samerr_t code(void) const { return errcode; }
|
||||
const char* what(void) const { return sam_strerror(errcode); }
|
||||
|
||||
private:
|
||||
const samerr_t errcode;
|
||||
};
|
||||
|
||||
#endif // SAM_ERROR_HPP
|
122
apps/enclave/src/sha1.cpp
Normal file
122
apps/enclave/src/sha1.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform.hpp"
|
||||
#include "sha1.hpp"
|
||||
|
||||
Sha1::Sha1(void)
|
||||
{
|
||||
b64hashed = "No value!";
|
||||
memset(binhashed, 0, sizeof binhashed);
|
||||
}
|
||||
|
||||
Sha1::Sha1(const string& data)
|
||||
{
|
||||
/* Hash it */
|
||||
hash_state md;
|
||||
sha1_init(&md);
|
||||
int rc = sha1_process(&md, reinterpret_cast<const uchar_t*>(data.c_str()),
|
||||
data.size());
|
||||
assert(rc == CRYPT_OK);
|
||||
rc = sha1_done(&md, binhashed);
|
||||
assert(rc == CRYPT_OK);
|
||||
b64();
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialises the Sha1 object from a binary hash
|
||||
*/
|
||||
Sha1::Sha1(const uchar_t binary[SHA1BIN_LEN])
|
||||
{
|
||||
memcpy(binhashed, binary, sizeof binhashed);
|
||||
b64();
|
||||
}
|
||||
|
||||
/*
|
||||
* Base 64 the binary hash
|
||||
*/
|
||||
void Sha1::b64(void)
|
||||
{
|
||||
ulong_t outlen = 29;
|
||||
char tmp[outlen];
|
||||
// b64 FIXME: replace + with ~, and / with - to be like freenet
|
||||
int rc = base64_encode(binhashed, sizeof binhashed, reinterpret_cast<uchar_t*>(tmp), &outlen);
|
||||
assert(rc == CRYPT_OK);
|
||||
b64hashed = tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two Sha1s, returning true if the this one is less than the right one
|
||||
*/
|
||||
bool Sha1::operator<(const Sha1& rhs) const
|
||||
{
|
||||
Bigint lhsnum(binhashed, SHA1BIN_LEN);
|
||||
Bigint rhsnum(rhs.binhash(), SHA1BIN_LEN);
|
||||
if (lhsnum < rhsnum)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assigns a value from another Sha1 to this one
|
||||
*/
|
||||
Sha1& Sha1::operator=(const Sha1& rhs)
|
||||
{
|
||||
if (this != &rhs) { // check for self-assignment: a = a
|
||||
b64hashed = rhs.b64hash();
|
||||
memcpy(binhashed, rhs.binhash(), sizeof binhashed);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares Sha1s for equality
|
||||
*/
|
||||
bool Sha1::operator==(const Sha1& rhs) const
|
||||
{
|
||||
if (memcmp(binhashed, rhs.binhash(), sizeof binhashed) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Xors this Sha1 with another, and stores the result in a Bigint
|
||||
*
|
||||
* rhs - sha1 to xor this one with
|
||||
* result - will be filled with the result
|
||||
*/
|
||||
void Sha1::x_or(const Sha1& rhs, Bigint& result) const
|
||||
{
|
||||
Bigint lhsnum(binhashed, SHA1BIN_LEN);
|
||||
Bigint rhsnum(rhs.binhash(), SHA1BIN_LEN);
|
||||
lhsnum.x_or(rhsnum, result);
|
||||
}
|
56
apps/enclave/src/sha1.hpp
Normal file
56
apps/enclave/src/sha1.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SHA1_HPP
|
||||
#define SHA1_HPP
|
||||
|
||||
class Sha1 {
|
||||
public:
|
||||
static const size_t SHA1BIN_LEN = 20;
|
||||
|
||||
Sha1(void);
|
||||
Sha1(const string& data);
|
||||
Sha1(const uchar_t binary[SHA1BIN_LEN]);
|
||||
|
||||
const string& b64hash(void) const { return b64hashed; }
|
||||
const uchar_t* binhash(void) const { return binhashed; }
|
||||
bool operator<(const Sha1& rhs) const;
|
||||
Sha1& operator=(const Sha1& rhs);
|
||||
bool operator==(const Sha1& rhs) const;
|
||||
void x_or(const Sha1& rhs, Bigint& result) const;
|
||||
|
||||
private:
|
||||
void b64(void);
|
||||
|
||||
string b64hashed; // base 64 of the hash
|
||||
uchar_t binhashed[SHA1BIN_LEN]; // non-NUL terminated binary hash
|
||||
};
|
||||
|
||||
#endif // SHA1_HPP
|
@ -4,7 +4,6 @@ import net.i2p.data.Destination;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.Clock;
|
||||
|
||||
/**
|
||||
* Responsible for actually conducting the tests, coordinating the storing of the
|
||||
@ -84,8 +83,8 @@ class ClientEngine {
|
||||
/** fire off a new ping */
|
||||
private void doSend() {
|
||||
long now = Clock.getInstance().now();
|
||||
_heartbeat.sendPing(_data.getConfig().getPeer(), _id, now, _data.getConfig().getSendSize());
|
||||
_data.addPing(now);
|
||||
_heartbeat.sendPing(_data.getConfig().getPeer(), _id, now, _data.getConfig().getSendSize());
|
||||
}
|
||||
|
||||
/** our actual heartbeat pumper - this drives the test */
|
||||
|
@ -11,6 +11,7 @@ import java.util.Date;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.I2PSession;
|
||||
@ -219,7 +220,8 @@ class I2PAdapter {
|
||||
DataHelper.writeDate(baos, new Date(now));
|
||||
int padding = size - baos.size();
|
||||
byte paddingData[] = new byte[padding];
|
||||
Arrays.fill(paddingData, (byte) 0x2A);
|
||||
I2PAppContext.getGlobalContext().random().nextBytes(paddingData);
|
||||
//Arrays.fill(paddingData, (byte) 0x2A);
|
||||
DataHelper.writeLong(baos, 2, padding);
|
||||
baos.write(paddingData);
|
||||
boolean sent = _session.sendMessage(peer, baos.toByteArray());
|
||||
@ -600,4 +602,4 @@ class I2PAdapter {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ package net.i2p.heartbeat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.stat.Rate;
|
||||
|
@ -59,7 +59,7 @@ public class PeerDataWriter {
|
||||
String header = getHeader(data);
|
||||
|
||||
out.write(header.getBytes());
|
||||
out.write("#action\tstatus\tdate and time sent \tsendMs\treplyMs\n".getBytes());
|
||||
out.write("#action\tstatus\tdate and time sent \tsendMs\treplyMs\troundTrip\n".getBytes());
|
||||
for (Iterator iter = data.getDataPoints().iterator(); iter.hasNext();) {
|
||||
PeerData.EventDataPoint point = (PeerData.EventDataPoint) iter.next();
|
||||
String line = getEvent(point);
|
||||
@ -84,12 +84,15 @@ public class PeerDataWriter {
|
||||
buf.append("lifetimeSent \t").append(data.getLifetimeSent()).append('\n');
|
||||
buf.append("lifetimeRecv \t").append(data.getLifetimeReceived()).append('\n');
|
||||
int periods[] = data.getAveragePeriods();
|
||||
buf.append("#averages\tminutes\tsendMs\trecvMs\tnumLost\n");
|
||||
buf.append("#averages\tminutes\tsendMs\trecvMs\tnumLost\troundTrip\n");
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
buf.append("periodAverage\t").append(periods[i]).append('\t');
|
||||
buf.append(getNum(data.getAverageSendTime(periods[i]))).append('\t');
|
||||
buf.append(getNum(data.getAverageReceiveTime(periods[i]))).append('\t');
|
||||
buf.append(getNum(data.getLostMessages(periods[i]))).append('\n');
|
||||
buf.append(getNum(data.getLostMessages(periods[i]))).append('\t');
|
||||
double rtt = data.getAverageSendTime(periods[i])
|
||||
+ data.getAverageReceiveTime(periods[i]);
|
||||
buf.append(getNum(rtt)).append('\n');
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
@ -105,6 +108,7 @@ public class PeerDataWriter {
|
||||
if (point.getWasPonged()) {
|
||||
buf.append(point.getPongSent() - point.getPingSent()).append('\t');
|
||||
buf.append(point.getPongReceived() - point.getPongSent()).append('\t');
|
||||
buf.append(point.getPongReceived() - point.getPingSent()).append('\t');
|
||||
}
|
||||
buf.append('\n');
|
||||
return buf.toString();
|
||||
|
@ -10,7 +10,6 @@ import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
|
||||
class HeartbeatMonitorGUI extends JFrame {
|
||||
private HeartbeatMonitor _monitor;
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -1,26 +1,23 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.util.List;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.XYItemRenderer;
|
||||
import org.jfree.chart.renderer.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.XYSeries;
|
||||
import org.jfree.data.XYSeriesCollection;
|
||||
|
||||
import net.i2p.heartbeat.PeerData;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import org.jfree.data.XYSeries;
|
||||
import org.jfree.data.XYSeriesCollection;
|
||||
import org.jfree.data.MovingAverage;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.renderer.XYLineAndShapeRenderer;
|
||||
import org.jfree.chart.renderer.XYItemRenderer;
|
||||
import org.jfree.chart.renderer.XYDotRenderer;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.Font;
|
||||
import java.awt.Color;
|
||||
|
||||
class JFreeChartAdapter {
|
||||
private final static Log _log = new Log(JFreeChartAdapter.class);
|
||||
private final static Color WHITE = new Color(255, 255, 255);
|
||||
|
@ -1,21 +1,14 @@
|
||||
package net.i2p.heartbeat.gui;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.i2p.heartbeat.PeerDataWriter;
|
||||
import net.i2p.util.Log;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the graph and legend
|
||||
*
|
||||
|
@ -11,8 +11,8 @@ import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.heartbeat.ClientConfig;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Configure how we want to render a particular clientConfig in the GUI
|
||||
|
@ -53,7 +53,7 @@ public class HTTPListener extends Thread {
|
||||
private boolean proxyUsed = false;
|
||||
|
||||
/**
|
||||
* Query whether this is the first use of the proxy or not . . .
|
||||
* Query whether this is the first use of the proxy or not
|
||||
* @return Whether this is the first proxy use, no doubt.
|
||||
*/
|
||||
public boolean firstProxyUse() {
|
||||
|
@ -7,8 +7,8 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.SocketException;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
@ -26,6 +26,7 @@ import net.i2p.util.Log;
|
||||
public class EepHandler {
|
||||
|
||||
private static final Log _log = new Log(EepHandler.class);
|
||||
private static I2PAppContext _context = new I2PAppContext();
|
||||
|
||||
protected ErrorHandler errorHandler;
|
||||
|
||||
@ -44,7 +45,7 @@ public class EepHandler {
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out,
|
||||
/* boolean fromProxy, */String destination) throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = NamingService.getInstance().lookup(destination);
|
||||
Destination dest = _context.namingService().lookup(destination);
|
||||
if (dest == null) {
|
||||
errorHandler.handle(req, httpl, out, "Could not lookup host: " + destination);
|
||||
return;
|
||||
@ -66,8 +67,8 @@ public class EepHandler {
|
||||
* @return boolean, true if something was written, false otherwise.
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean handle(Request req, Filter f, OutputStream out, Destination dest, I2PSocketManager sm)
|
||||
throws IOException {
|
||||
public boolean handle(Request req, Filter f, OutputStream out, Destination dest,
|
||||
I2PSocketManager sm) throws IOException {
|
||||
I2PSocket s = null;
|
||||
boolean written = false;
|
||||
try {
|
||||
|
@ -3,7 +3,7 @@ package net.i2p.httptunnel.handler;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.httptunnel.HTTPListener;
|
||||
@ -19,6 +19,7 @@ import net.i2p.util.Log;
|
||||
public class ProxyHandler extends EepHandler {
|
||||
|
||||
private static final Log _log = new Log(ErrorHandler.class);
|
||||
private static I2PAppContext _context = new I2PAppContext();
|
||||
|
||||
/* package private */ProxyHandler(ErrorHandler eh) {
|
||||
super(eh);
|
||||
@ -31,7 +32,7 @@ public class ProxyHandler extends EepHandler {
|
||||
* @throws IOException
|
||||
*/
|
||||
public void handle(Request req, HTTPListener httpl, OutputStream out
|
||||
/*, boolean fromProxy */) throws IOException {
|
||||
/*, boolean fromProxy */) throws IOException {
|
||||
SocketManagerProducer smp = httpl.getSMP();
|
||||
Destination dest = findProxy();
|
||||
if (dest == null) {
|
||||
@ -48,6 +49,6 @@ public class ProxyHandler extends EepHandler {
|
||||
|
||||
private Destination findProxy() {
|
||||
//FIXME!
|
||||
return NamingService.getInstance().lookup("squid.i2p");
|
||||
return _context.namingService().lookup("squid.i2p");
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ public class RootHandler {
|
||||
private static RootHandler instance;
|
||||
|
||||
/**
|
||||
* Singleton stuff . . .
|
||||
* Singleton stuff
|
||||
* @return the one and only instance, yay!
|
||||
*/
|
||||
public static synchronized RootHandler getInstance() {
|
||||
|
@ -49,6 +49,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
@ -63,8 +64,11 @@ import net.i2p.util.EventDispatcherImpl;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnel implements Logging, EventDispatcher {
|
||||
private final static Log _log = new Log(I2PTunnel.class);
|
||||
private final EventDispatcherImpl _event = new EventDispatcherImpl();
|
||||
private Log _log;
|
||||
private EventDispatcherImpl _event;
|
||||
private I2PAppContext _context;
|
||||
private static long __tunnelId = 0;
|
||||
private long _tunnelId;
|
||||
|
||||
public static final int PACKET_DELAY = 100;
|
||||
|
||||
@ -74,6 +78,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
public static String host = System.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
|
||||
public static String listenHost = host;
|
||||
|
||||
public static long readTimeout = -1;
|
||||
|
||||
private static final String nocli_args[] = { "-nocli", "-die"};
|
||||
|
||||
private List tasks = new ArrayList();
|
||||
@ -94,6 +100,10 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
}
|
||||
|
||||
public I2PTunnel(String[] args, ConnectionEventListener lsnr) {
|
||||
_context = I2PAppContext.getGlobalContext(); // new I2PAppContext();
|
||||
_tunnelId = ++__tunnelId;
|
||||
_log = _context.logManager().getLog(I2PTunnel.class);
|
||||
_event = new EventDispatcherImpl();
|
||||
addConnectionEventListener(lsnr);
|
||||
boolean gui = true;
|
||||
boolean checkRunByE = true;
|
||||
@ -107,7 +117,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
checkRunByE = false;
|
||||
} else if (args[i].equals("-nogui")) {
|
||||
gui = false;
|
||||
_log.warn("The `-nogui' option of I2PTunnel is deprecated.\n"
|
||||
_log.warn(getPrefix() + "The `-nogui' option of I2PTunnel is deprecated.\n"
|
||||
+ "Use `-cli', `-nocli' (aka `-wait') or `-die' instead.");
|
||||
} else if (args[i].equals("-cli")) {
|
||||
gui = false;
|
||||
@ -201,6 +211,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
runConfig(args, l);
|
||||
} else if ("listen_on".equals(cmdname)) {
|
||||
runListenOn(args, l);
|
||||
} else if ("read_timeout".equals(cmdname)) {
|
||||
runReadTimeout(args, l);
|
||||
} else if ("genkeys".equals(cmdname)) {
|
||||
runGenKeys(args, l);
|
||||
} else if ("gentextkeys".equals(cmdname)) {
|
||||
@ -235,6 +247,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
l.log("Command list:");
|
||||
l.log("config <i2phost> <i2pport>");
|
||||
l.log("listen_on <ip>");
|
||||
l.log("read_timeout <msecs>");
|
||||
l.log("owndest yes|no");
|
||||
l.log("ping <args>");
|
||||
l.log("server <host> <port> <privkeyfile>");
|
||||
@ -270,7 +283,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
serverHost = InetAddress.getByName(args[0]);
|
||||
} catch (UnknownHostException uhe) {
|
||||
l.log("unknown host");
|
||||
_log.error("Error resolving " + args[0], uhe);
|
||||
_log.error(getPrefix() + "Error resolving " + args[0], uhe);
|
||||
notifyEvent("serverTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
@ -279,7 +292,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
portNum = Integer.parseInt(args[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error("Port specified is not valid: " + args[1], nfe);
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe);
|
||||
notifyEvent("serverTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
@ -287,14 +300,15 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
privKeyFile = new File(args[2]);
|
||||
if (!privKeyFile.canRead()) {
|
||||
l.log("private key file does not exist");
|
||||
_log.error("Private key file does not exist or is not readable: " + args[2]);
|
||||
_log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]);
|
||||
notifyEvent("serverTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
I2PTunnelTask task;
|
||||
task = new I2PTunnelServer(serverHost, portNum, privKeyFile, args[2], l, (EventDispatcher) this);
|
||||
addtask(task);
|
||||
notifyEvent("serverTaskId", new Integer(task.getId()));
|
||||
I2PTunnelServer serv = new I2PTunnelServer(serverHost, portNum, privKeyFile, args[2], l, (EventDispatcher) this);
|
||||
serv.setReadTimeout(readTimeout);
|
||||
serv.startRunning();
|
||||
addtask(serv);
|
||||
notifyEvent("serverTaskId", new Integer(serv.getId()));
|
||||
return;
|
||||
} else {
|
||||
l.log("server <host> <port> <privkeyfile>");
|
||||
@ -322,7 +336,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
serverHost = InetAddress.getByName(args[0]);
|
||||
} catch (UnknownHostException uhe) {
|
||||
l.log("unknown host");
|
||||
_log.error("Error resolving " + args[0], uhe);
|
||||
_log.error(getPrefix() + "Error resolving " + args[0], uhe);
|
||||
notifyEvent("serverTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
@ -331,15 +345,16 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
portNum = Integer.parseInt(args[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error("Port specified is not valid: " + args[1], nfe);
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe);
|
||||
notifyEvent("serverTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
I2PTunnelTask task;
|
||||
task = new I2PTunnelServer(serverHost, portNum, args[2], l, (EventDispatcher) this);
|
||||
addtask(task);
|
||||
notifyEvent("serverTaskId", new Integer(task.getId()));
|
||||
I2PTunnelServer serv = new I2PTunnelServer(serverHost, portNum, args[2], l, (EventDispatcher) this);
|
||||
serv.setReadTimeout(readTimeout);
|
||||
serv.startRunning();
|
||||
addtask(serv);
|
||||
notifyEvent("serverTaskId", new Integer(serv.getId()));
|
||||
} else {
|
||||
l.log("textserver <host> <port> <privkey>");
|
||||
l.log(" creates a server that sends all incoming data\n" + " of its destination to host:port.");
|
||||
@ -366,7 +381,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
port = Integer.parseInt(args[0]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error("Port specified is not valid: " + args[0], nfe);
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe);
|
||||
notifyEvent("clientTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
@ -398,7 +413,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
port = Integer.parseInt(args[0]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error("Port specified is not valid: " + args[0], nfe);
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe);
|
||||
notifyEvent("httpclientTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
@ -439,7 +454,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
port = Integer.parseInt(args[0]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error("Port specified is not valid: " + args[0], nfe);
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe);
|
||||
notifyEvent("sockstunnelTaskId", new Integer(-1));
|
||||
return;
|
||||
}
|
||||
@ -510,7 +525,31 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
} else {
|
||||
l.log("listen_on <ip>");
|
||||
l.log(" sets the interface to listen for the I2PClient.");
|
||||
notifyEvent("listen_onResult", "ok");
|
||||
notifyEvent("listen_onResult", "error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the read timeout going to be used for newly-created I2PSockets
|
||||
*
|
||||
* Sets the event "read_timeoutResult" = "ok" or "error" after the interface has been specified
|
||||
*
|
||||
* @param args {hostname}
|
||||
* @param l logger to receive events and output
|
||||
*/
|
||||
public void runReadTimeout(String args[], Logging l) {
|
||||
if (args.length == 1) {
|
||||
try {
|
||||
readTimeout = Long.parseLong(args[0]);
|
||||
} catch (NumberFormatException e) {
|
||||
notifyEvent("read_timeoutResult", "error");
|
||||
}
|
||||
notifyEvent("read_timeoutResult", "ok");
|
||||
} else {
|
||||
l.log("read_timeout <msecs>");
|
||||
l.log(" sets the read timeout (in milliseconds) for I2P connections\n"
|
||||
+" Negative values will make the connections wait forever");
|
||||
notifyEvent("read_timeoutResult", "error");
|
||||
}
|
||||
}
|
||||
|
||||
@ -529,7 +568,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
pubdest = new FileOutputStream(args[1]);
|
||||
} catch (IOException ioe) {
|
||||
l.log("Error opening output stream");
|
||||
_log.error("Error generating keys to out", ioe);
|
||||
_log.error(getPrefix() + "Error generating keys to out", ioe);
|
||||
notifyEvent("genkeysResult", "error");
|
||||
return;
|
||||
}
|
||||
@ -552,7 +591,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
} catch (IOException ioe) {
|
||||
l.log("Error generating keys - " + ioe.getMessage());
|
||||
notifyEvent("genkeysResult", "error");
|
||||
_log.error("Error generating keys", ioe);
|
||||
_log.error(getPrefix() + "Error generating keys", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@ -686,7 +725,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
notifyEvent("runResult", "ok");
|
||||
} catch (IOException ioe) {
|
||||
l.log("IO error running the file");
|
||||
_log.error("Error running the file", ioe);
|
||||
_log.error(getPrefix() + "Error running the file", ioe);
|
||||
notifyEvent("runResult", "error");
|
||||
}
|
||||
} else {
|
||||
@ -760,12 +799,12 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
private boolean closetask(int num, boolean forced, Logging l) {
|
||||
boolean closed = false;
|
||||
|
||||
_log.debug("closetask(): looking for task " + num);
|
||||
_log.debug(getPrefix() + "closetask(): looking for task " + num);
|
||||
synchronized (tasks) {
|
||||
for (Iterator it = tasks.iterator(); it.hasNext();) {
|
||||
I2PTunnelTask t = (I2PTunnelTask) it.next();
|
||||
int id = t.getId();
|
||||
_log.debug("closetask(): parsing task " + id + " (" + t.toString() + ")");
|
||||
_log.debug(getPrefix() + "closetask(): parsing task " + id + " (" + t.toString() + ")");
|
||||
if (id == num) {
|
||||
closed = closetask(t, forced, l);
|
||||
break;
|
||||
@ -800,7 +839,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
for (Iterator it = tasks.iterator(); it.hasNext();) {
|
||||
I2PTunnelTask t = (I2PTunnelTask) it.next();
|
||||
if (!t.isOpen()) {
|
||||
_log.debug("Purging inactive tunnel: [" + t.getId() + "] " + t.toString());
|
||||
_log.debug(getPrefix() + "Purging inactive tunnel: [" + t.getId() + "] " + t.toString());
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
@ -813,7 +852,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
*/
|
||||
public void log(String s) {
|
||||
System.out.println(s);
|
||||
_log.info("Display: " + s);
|
||||
_log.info(getPrefix() + "Display: " + s);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -888,6 +927,9 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
|
||||
if ((name == null) || (name.trim().length() <= 0)) throw new DataFormatException("Empty destination provided");
|
||||
|
||||
I2PAppContext ctx = I2PAppContext.getGlobalContext();
|
||||
Log log = ctx.logManager().getLog(I2PTunnel.class);
|
||||
|
||||
if (name.startsWith("file:")) {
|
||||
Destination result = new Destination();
|
||||
byte content[] = null;
|
||||
@ -911,19 +953,21 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
result.fromByteArray(content);
|
||||
return result;
|
||||
} catch (Exception ex) {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("File is not a binary destination - trying base64");
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("File is not a binary destination - trying base64");
|
||||
try {
|
||||
byte decoded[] = Base64.decode(new String(content));
|
||||
result.fromByteArray(decoded);
|
||||
return result;
|
||||
} catch (DataFormatException dfe) {
|
||||
if (_log.shouldLog(Log.WARN)) _log.warn("File is not a base64 destination either - failing!");
|
||||
if (log.shouldLog(Log.WARN))
|
||||
log.warn("File is not a base64 destination either - failing!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ask naming service
|
||||
NamingService inst = NamingService.getInstance();
|
||||
NamingService inst = ctx.namingService();
|
||||
return inst.lookup(name);
|
||||
}
|
||||
}
|
||||
@ -941,6 +985,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
listeners.remove(lsnr);
|
||||
}
|
||||
}
|
||||
|
||||
private String getPrefix() { return '[' + _tunnelId + "]: "; }
|
||||
|
||||
/**
|
||||
* Call this whenever we lose touch with the router involuntarily (aka the router
|
||||
@ -948,7 +994,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
*
|
||||
*/
|
||||
void routerDisconnected() {
|
||||
_log.error("Router disconnected - firing notification events");
|
||||
_log.error(getPrefix() + "Router disconnected - firing notification events");
|
||||
synchronized (listeners) {
|
||||
for (Iterator iter = listeners.iterator(); iter.hasNext();) {
|
||||
ConnectionEventListener lsnr = (ConnectionEventListener) iter.next();
|
||||
@ -1000,4 +1046,4 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
public Object waitEventValue(String n) {
|
||||
return _event.waitEventValue(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ package net.i2p.i2ptunnel;
|
||||
|
||||
import java.net.Socket;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
@ -17,6 +16,8 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
|
||||
private static final Log _log = new Log(I2PTunnelClient.class);
|
||||
|
||||
protected Destination dest;
|
||||
private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1
|
||||
protected long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||
|
||||
public I2PTunnelClient(int localPort, String destination, Logging l, boolean ownDest, EventDispatcher notifyThis) {
|
||||
super(localPort, ownDest, l, notifyThis, "SynSender");
|
||||
@ -45,9 +46,13 @@ public class I2PTunnelClient extends I2PTunnelClientBase {
|
||||
notifyEvent("openClientResult", "ok");
|
||||
}
|
||||
|
||||
public void setReadTimeout(long ms) { readTimeout = ms; }
|
||||
public long getReadTimeout() { return readTimeout; }
|
||||
|
||||
protected void clientConnectionRun(Socket s) {
|
||||
try {
|
||||
I2PSocket i2ps = createI2PSocket(dest);
|
||||
i2ps.setReadTimeout(readTimeout);
|
||||
new I2PTunnelRunner(s, i2ps, sockLock, null);
|
||||
} catch (Exception ex) {
|
||||
_log.info("Error connecting", ex);
|
||||
|
@ -33,6 +33,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
|
||||
private static final long DEFAULT_CONNECT_TIMEOUT = 60 * 1000;
|
||||
|
||||
private static volatile long __clientId = 0;
|
||||
protected long _clientId;
|
||||
protected Object sockLock = new Object(); // Guards sockMgr and mySockets
|
||||
private I2PSocketManager sockMgr;
|
||||
private List mySockets = new ArrayList();
|
||||
@ -60,9 +62,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
|
||||
public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l, EventDispatcher notifyThis, String handlerName) {
|
||||
super(localPort + " (uninitialized)", notifyThis);
|
||||
_clientId = ++__clientId;
|
||||
this.localPort = localPort;
|
||||
this.l = l;
|
||||
this.handlerName = handlerName;
|
||||
this.handlerName = handlerName + _clientId;
|
||||
|
||||
synchronized (sockLock) {
|
||||
if (ownDest) {
|
||||
@ -75,7 +78,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
l.log("I2P session created");
|
||||
|
||||
Thread t = new I2PThread(this);
|
||||
t.setName("Client");
|
||||
t.setName("Client " + _clientId);
|
||||
listenerReady = false;
|
||||
t.start();
|
||||
open = true;
|
||||
@ -179,8 +182,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
public I2PSocket createI2PSocket(Destination dest, I2PSocketOptions opt) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
|
||||
I2PSocket i2ps;
|
||||
|
||||
i2ps = sockMgr.connect(dest, opt);
|
||||
synchronized (sockLock) {
|
||||
i2ps = sockMgr.connect(dest, opt);
|
||||
mySockets.add(i2ps);
|
||||
}
|
||||
|
||||
@ -272,12 +275,14 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
}
|
||||
|
||||
private static volatile long __runnerId = 0;
|
||||
|
||||
public class ClientConnectionRunner extends I2PThread {
|
||||
private Socket s;
|
||||
|
||||
public ClientConnectionRunner(Socket s, String name) {
|
||||
this.s = s;
|
||||
setName(name);
|
||||
setName(name + '.' + (++__runnerId));
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -20,13 +20,32 @@ import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Act as a mini HTTP proxy, handling various different types of requests,
|
||||
* forwarding them through I2P appropriately, and displaying the reply. Supported
|
||||
* request formats are: <pre>
|
||||
* $method http://$site[$port]/$path $protocolVersion
|
||||
* or
|
||||
* $method $path $protocolVersion\nHost: $site
|
||||
* or
|
||||
* $method http://i2p/$site/$path $protocolVersion
|
||||
* or
|
||||
* $method /$site/$path $protocolVersion
|
||||
* </pre>
|
||||
*
|
||||
* If the $site resolves with the I2P naming service, then it is directed towards
|
||||
* that eepsite, otherwise it is directed towards this client's outproxy (typically
|
||||
* "squid.i2p"). Only HTTP is supported (no HTTPS, ftp, mailto, etc). Both GET
|
||||
* and POST have been tested, though other $methods should work.
|
||||
*
|
||||
*/
|
||||
public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelHTTPClient.class);
|
||||
|
||||
private String wwwProxy;
|
||||
|
||||
private final static byte[] ERR_REQUEST_DENIED =
|
||||
("HTTP/1.1 404 Not Found\r\n"+
|
||||
("HTTP/1.1 403 Access Denied\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"\r\n"+
|
||||
@ -35,37 +54,35 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
.getBytes();
|
||||
|
||||
private final static byte[] ERR_DESTINATION_UNKNOWN =
|
||||
("HTTP/1.1 404 Not Found\r\n"+
|
||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n"+
|
||||
"\r\n"+
|
||||
"<html><body><H1>I2P ERROR: NOT FOUND</H1>"+
|
||||
"That Desitination was not found. Perhaps you pasted in the wrong "+
|
||||
"BASE64 I2P Destination or the link you are following is bad. "+
|
||||
"The host (or the WWW proxy, if you're using one) could also be "+
|
||||
"temporarily offline. "+
|
||||
"<html><body><H1>I2P ERROR: DESTINATION NOT FOUND</H1>"+
|
||||
"That I2P Desitination was not found. Perhaps you pasted in the "+
|
||||
"wrong BASE64 I2P Destination or the link you are following is "+
|
||||
"bad. The host (or the WWW proxy, if you're using one) could also "+
|
||||
"be temporarily offline. You may want to <b>retry</b>. "+
|
||||
"Could not find the following Destination:<BR><BR>")
|
||||
.getBytes();
|
||||
|
||||
private final static byte[] ERR_TIMEOUT =
|
||||
("HTTP/1.1 404 Not Found\r\n"+
|
||||
("HTTP/1.1 504 Gateway Timeout\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
"Cache-control: no-cache\r\n\r\n"+
|
||||
"<html><body><H1>I2P ERROR: TIMEOUT</H1>"+
|
||||
"That Desitination was reachable, but timed out getting a "+
|
||||
"response. This may be a temporary error, so you should simply "+
|
||||
"response. This is likely a temporary error, so you should simply "+
|
||||
"try to refresh, though if the problem persists, the remote "+
|
||||
"destination may have issues. Could not get a response from "+
|
||||
"the following Destination:<BR><BR>")
|
||||
.getBytes();
|
||||
|
||||
// public I2PTunnelHTTPClient(int localPort, Logging l,
|
||||
// boolean ownDest, String wwwProxy) {
|
||||
// this(localPort, l, ownDest, wwwProxy, (EventDispatcher)null);
|
||||
// }
|
||||
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
public I2PTunnelHTTPClient(int localPort, Logging l, boolean ownDest, String wwwProxy, EventDispatcher notifyThis) {
|
||||
super(localPort, ownDest, l, notifyThis, "HTTPHandler");
|
||||
super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId));
|
||||
|
||||
if (waitEventValue("openBaseClientResult").equals("error")) {
|
||||
notifyEvent("openHTTPClientResult", "error");
|
||||
@ -81,6 +98,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
notifyEvent("openHTTPClientResult", "ok");
|
||||
}
|
||||
|
||||
private String getPrefix() { return "Client[" + _clientId + "]: "; }
|
||||
|
||||
protected void clientConnectionRun(Socket s) {
|
||||
OutputStream out = null;
|
||||
String targetRequest = null;
|
||||
@ -92,7 +111,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
String line, method = null, protocol = null, host = null, destination = null;
|
||||
StringBuffer newRequest = new StringBuffer();
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Line=[" + line + "]");
|
||||
|
||||
if (line.startsWith("Connection: ") ||
|
||||
line.startsWith("Keep-Alive: ") ||
|
||||
line.startsWith("Proxy-Connection: "))
|
||||
continue;
|
||||
|
||||
if (method == null) { // first line (GET /base64/realaddr)
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Method is null for [" + line + "]");
|
||||
|
||||
int pos = line.indexOf(" ");
|
||||
if (pos == -1) break;
|
||||
method = line.substring(0, pos);
|
||||
@ -126,6 +156,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
// The request must be forwarded to a WWW proxy
|
||||
destination = wwwProxy;
|
||||
usingWWWProxy = true;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!");
|
||||
} else {
|
||||
request = request.substring(pos + 1);
|
||||
pos = request.indexOf("/");
|
||||
@ -135,29 +167,40 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
|
||||
boolean isValid = usingWWWProxy || isSupportedAddress(host, protocol);
|
||||
if (!isValid) {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("notValid(" + host + ")");
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "notValid(" + host + ")");
|
||||
method = null;
|
||||
destination = null;
|
||||
break;
|
||||
} else if (!usingWWWProxy) {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("host=getHostName(" + destination + ")");
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "host=getHostName(" + destination + ")");
|
||||
host = getHostName(destination); // hide original host
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("METHOD:" + method + ":");
|
||||
_log.debug("PROTOC:" + protocol + ":");
|
||||
_log.debug("HOST :" + host + ":");
|
||||
_log.debug("DEST :" + destination + ":");
|
||||
_log.debug(getPrefix() + "METHOD:" + method + ":");
|
||||
_log.debug(getPrefix() + "PROTOC:" + protocol + ":");
|
||||
_log.debug(getPrefix() + "HOST :" + host + ":");
|
||||
_log.debug(getPrefix() + "DEST :" + destination + ":");
|
||||
}
|
||||
|
||||
} else {
|
||||
if (line.startsWith("Host: ") && !usingWWWProxy) {
|
||||
line = "Host: " + host;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix() + "Setting host = " + host);
|
||||
}
|
||||
|
||||
} else if (line.startsWith("Host: ") && !usingWWWProxy) {
|
||||
line = "Host: " + host;
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("Setting host = " + host);
|
||||
}
|
||||
newRequest.append(line).append("\r\n"); // HTTP spec
|
||||
if (line.length() == 0) break;
|
||||
|
||||
if (line.length() == 0) {
|
||||
newRequest.append("Connection: close\r\n\r\n");
|
||||
break;
|
||||
} else {
|
||||
newRequest.append(line).append("\r\n"); // HTTP spec
|
||||
}
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "NewRequest header: [" + newRequest.toString() + "]");
|
||||
|
||||
while (br.ready()) { // empty the buffer (POST requests)
|
||||
int i = br.read();
|
||||
if (i != -1) {
|
||||
@ -176,6 +219,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Destination: " + destination);
|
||||
|
||||
Destination dest = I2PTunnel.destFromName(destination);
|
||||
if (dest == null) {
|
||||
l.log("Could not resolve " + destination + ".");
|
||||
@ -191,19 +238,19 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
timeoutThread.start();
|
||||
} catch (SocketException ex) {
|
||||
if (timeoutThread != null) timeoutThread.disable();
|
||||
_log.info("Error trying to connect", ex);
|
||||
_log.info(getPrefix() + "Error trying to connect", ex);
|
||||
l.log(ex.getMessage());
|
||||
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, wwwProxy);
|
||||
closeSocket(s);
|
||||
} catch (IOException ex) {
|
||||
if (timeoutThread != null) timeoutThread.disable();
|
||||
_log.info("Error trying to connect", ex);
|
||||
_log.info(getPrefix() + "Error trying to connect", ex);
|
||||
l.log(ex.getMessage());
|
||||
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, wwwProxy);
|
||||
closeSocket(s);
|
||||
} catch (I2PException ex) {
|
||||
if (timeoutThread != null) timeoutThread.disable();
|
||||
_log.info("Error trying to connect", ex);
|
||||
_log.info("getPrefix() + Error trying to connect", ex);
|
||||
l.log(ex.getMessage());
|
||||
handleHTTPClientException(ex, out, targetRequest, usingWWWProxy, wwwProxy);
|
||||
closeSocket(s);
|
||||
@ -211,6 +258,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
private static final long INACTIVITY_TIMEOUT = 120 * 1000;
|
||||
private static volatile long __timeoutId = 0;
|
||||
|
||||
private class InactivityTimeoutThread extends I2PThread {
|
||||
|
||||
@ -230,7 +278,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
_targetRequest = targetRequest;
|
||||
_useWWWProxy = useWWWProxy;
|
||||
_disabled = false;
|
||||
setName("InactivityThread");
|
||||
long timeoutId = ++__timeoutId;
|
||||
setName("InactivityThread " + getPrefix() + timeoutId);
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
@ -243,15 +292,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
public void run() {
|
||||
while (!_disabled) {
|
||||
if (_runner.isFinished()) {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info("HTTP client request completed prior to timeout");
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix() + "HTTP client request completed prior to timeout");
|
||||
return;
|
||||
}
|
||||
if (_runner.getLastActivityOn() < Clock.getInstance().now() - INACTIVITY_TIMEOUT) {
|
||||
if (_runner.getStartedOn() < Clock.getInstance().now() - INACTIVITY_TIMEOUT) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("HTTP client request timed out (lastActivity: "
|
||||
_log.warn(getPrefix() + "HTTP client request timed out (lastActivity: "
|
||||
+ new Date(_runner.getLastActivityOn()) + ", startedOn: "
|
||||
+ new Date(_runner.getLastActivityOn()) + ")");
|
||||
+ new Date(_runner.getStartedOn()) + ")");
|
||||
timeout();
|
||||
return;
|
||||
} else {
|
||||
@ -270,7 +319,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
private void timeout() {
|
||||
_log.info("Inactivity timeout reached");
|
||||
_log.info(getPrefix() + "Inactivity timeout reached");
|
||||
l.log("Inactivity timeout reached");
|
||||
if (_out != null) {
|
||||
try {
|
||||
@ -280,10 +329,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
writeErrorMessage(ERR_TIMEOUT, _out, _targetRequest, _useWWWProxy, wwwProxy);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.warn("Error writing out the 'timeout' message", ioe);
|
||||
_log.warn(getPrefix() + "Error writing out the 'timeout' message", ioe);
|
||||
}
|
||||
} else {
|
||||
_log.warn("Client disconnected before we could say we timed out");
|
||||
_log.warn(getPrefix() + "Client disconnected before we could say we timed out");
|
||||
}
|
||||
closeSocket(s);
|
||||
}
|
||||
@ -314,16 +363,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleHTTPClientException(Exception ex, OutputStream out, String targetRequest,
|
||||
private void handleHTTPClientException(Exception ex, OutputStream out, String targetRequest,
|
||||
boolean usingWWWProxy, String wwwProxy) {
|
||||
if (out != null) {
|
||||
try {
|
||||
writeErrorMessage(ERR_DESTINATION_UNKNOWN, out, targetRequest, usingWWWProxy, wwwProxy);
|
||||
} catch (IOException ioe) {
|
||||
_log.warn("Error writing out the 'destination was unknown' " + "message", ioe);
|
||||
_log.warn(getPrefix() + "Error writing out the 'destination was unknown' " + "message", ioe);
|
||||
}
|
||||
} else {
|
||||
_log.warn("Client disconnected before we could say that destination " + "was unknown", ex);
|
||||
_log.warn(getPrefix() + "Client disconnected before we could say that destination " + "was unknown", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ package net.i2p.i2ptunnel;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
@ -17,9 +18,11 @@ import net.i2p.util.Clock;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelRunner extends I2PThread {
|
||||
public class I2PTunnelRunner extends I2PThread implements I2PSocket.SocketErrorListener {
|
||||
private final static Log _log = new Log(I2PTunnelRunner.class);
|
||||
|
||||
private static volatile long __runnerId;
|
||||
private long _runnerId;
|
||||
/**
|
||||
* max bytes streamed in a packet - smaller ones might be filled
|
||||
* up to this size. Larger ones are not split (at least not on
|
||||
@ -48,9 +51,11 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
this.slock = slock;
|
||||
this.initialData = initialData;
|
||||
lastActivityOn = -1;
|
||||
startedOn = -1;
|
||||
_log.info("I2PTunnelRunner started");
|
||||
setName("I2PTunnelRunner");
|
||||
startedOn = Clock.getInstance().now();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("I2PTunnelRunner started");
|
||||
_runnerId = ++__runnerId;
|
||||
setName("I2PTunnelRunner " + _runnerId);
|
||||
start();
|
||||
}
|
||||
|
||||
@ -86,10 +91,10 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
startedOn = Clock.getInstance().now();
|
||||
try {
|
||||
InputStream in = s.getInputStream();
|
||||
OutputStream out = new BufferedOutputStream(s.getOutputStream(), NETWORK_BUFFER_SIZE);
|
||||
i2ps.setSocketErrorListener(this);
|
||||
InputStream i2pin = i2ps.getInputStream();
|
||||
OutputStream i2pout = new BufferedOutputStream(i2ps.getOutputStream(), MAX_PACKET_SIZE);
|
||||
if (initialData != null) {
|
||||
@ -116,7 +121,9 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
_log.error("Interrupted", ex);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
_log.error("Error forwarding", ex);
|
||||
_log.debug("Error forwarding", ex);
|
||||
} catch (Exception e) {
|
||||
_log.error("Internal error", e);
|
||||
} finally {
|
||||
try {
|
||||
if (s != null) s.close();
|
||||
@ -128,6 +135,15 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
}
|
||||
}
|
||||
|
||||
public void errorOccurred() {
|
||||
synchronized (finishLock) {
|
||||
finished = true;
|
||||
finishLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
private volatile long __forwarderId = 0;
|
||||
|
||||
private class StreamForwarder extends I2PThread {
|
||||
|
||||
InputStream in;
|
||||
@ -136,7 +152,7 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
private StreamForwarder(InputStream in, OutputStream out) {
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
setName("StreamForwarder");
|
||||
setName("StreamForwarder " + _runnerId + "." + (++__forwarderId));
|
||||
start();
|
||||
}
|
||||
|
||||
@ -163,11 +179,14 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
} catch (SocketException ex) {
|
||||
// this *will* occur when the other threads closes the socket
|
||||
synchronized (finishLock) {
|
||||
if (!finished)
|
||||
_log.error("Error reading and writing", ex);
|
||||
else
|
||||
_log.warn("You may ignore this", ex);
|
||||
if (!finished) {
|
||||
_log.debug("Socket closed - error reading and writing",
|
||||
ex);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedIOException ex) {
|
||||
_log.warn("Closing connection due to timeout (error: \""
|
||||
+ ex.getMessage() + "\")");
|
||||
} catch (IOException ex) {
|
||||
if (!finished)
|
||||
_log.error("Error forwarding", ex);
|
||||
@ -178,7 +197,8 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
out.close();
|
||||
in.close();
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error closing streams", ex);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error closing streams", ex);
|
||||
}
|
||||
synchronized (finishLock) {
|
||||
finished = true;
|
||||
@ -188,4 +208,4 @@ public class I2PTunnelRunner extends I2PThread {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import java.net.SocketException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
@ -40,6 +41,10 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
|
||||
private Logging l;
|
||||
|
||||
private static final long DEFAULT_READ_TIMEOUT = -1; // 3*60*1000;
|
||||
/** default timeout to 3 minutes - override if desired */
|
||||
private long readTimeout = DEFAULT_READ_TIMEOUT;
|
||||
|
||||
public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis) {
|
||||
super(host + ":" + port + " <- " + privData, notifyThis);
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData));
|
||||
@ -57,8 +62,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l,
|
||||
EventDispatcher notifyThis) {
|
||||
public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis) {
|
||||
super(host + ":" + port + " <- " + privkeyname, notifyThis);
|
||||
init(host, port, privData, privkeyname, l);
|
||||
}
|
||||
@ -78,11 +82,40 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
l.log("Ready!");
|
||||
notifyEvent("openServerResult", "ok");
|
||||
open = true;
|
||||
}
|
||||
|
||||
|
||||
private static volatile long __serverId = 0;
|
||||
|
||||
/**
|
||||
* Start running the I2PTunnelServer.
|
||||
*
|
||||
*/
|
||||
public void startRunning() {
|
||||
Thread t = new I2PThread(this);
|
||||
t.setName("Server");
|
||||
t.setName("Server " + (++__serverId));
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the read idle timeout for newly-created connections (in
|
||||
* milliseconds). After this time expires without data being reached from
|
||||
* the I2P network, the connection itself will be closed.
|
||||
*/
|
||||
public void setReadTimeout(long ms) {
|
||||
readTimeout = ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the read idle timeout for newly-created connections (in
|
||||
* milliseconds).
|
||||
*
|
||||
* @return The read timeout used for connections
|
||||
*/
|
||||
public long getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
public boolean close(boolean forced) {
|
||||
if (!open) return true;
|
||||
synchronized (lock) {
|
||||
@ -112,14 +145,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
I2PServerSocket i2pss = sockMgr.getServerSocket();
|
||||
while (true) {
|
||||
I2PSocket i2ps = i2pss.accept();
|
||||
//local is fast, so synchronously. Does not need that many
|
||||
//threads.
|
||||
try {
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
new I2PTunnelRunner(s, i2ps, slock, null);
|
||||
} catch (SocketException ex) {
|
||||
i2ps.close();
|
||||
}
|
||||
I2PThread t = new I2PThread(new Handler(i2ps));
|
||||
t.start();
|
||||
}
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
@ -127,5 +154,43 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Async handler to keep .accept() from blocking too long.
|
||||
* todo: replace with a thread pool so we dont get overrun by threads if/when
|
||||
* receiving a lot of connection requests concurrently.
|
||||
*
|
||||
*/
|
||||
private class Handler implements Runnable {
|
||||
private I2PSocket _handleSocket;
|
||||
public Handler(I2PSocket socket) {
|
||||
_handleSocket = socket;
|
||||
}
|
||||
public void run() {
|
||||
long afterAccept = I2PAppContext.getGlobalContext().clock().now();
|
||||
long afterSocket = -1;
|
||||
//local is fast, so synchronously. Does not need that many
|
||||
//threads.
|
||||
try {
|
||||
_handleSocket.setReadTimeout(readTimeout);
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
afterSocket = I2PAppContext.getGlobalContext().clock().now();
|
||||
new I2PTunnelRunner(s, _handleSocket, slock, null);
|
||||
} catch (SocketException ex) {
|
||||
try {
|
||||
_handleSocket.close();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error while closing the received i2p con", ex);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error while waiting for I2PConnections", ex);
|
||||
}
|
||||
|
||||
long afterHandle = I2PAppContext.getGlobalContext().clock().now();
|
||||
long timeToHandle = afterHandle - afterAccept;
|
||||
if (timeToHandle > 1000)
|
||||
_log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ public class ByteCollector {
|
||||
int size;
|
||||
|
||||
public ByteCollector() {
|
||||
contents = new byte[80];
|
||||
contents = new byte[1024];
|
||||
size = 0;
|
||||
}
|
||||
|
||||
|
@ -1,74 +1,150 @@
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Initial stub implementation for the server socket
|
||||
* Server socket implementation, allowing multiple threads to accept I2PSockets
|
||||
* and pull from a queue populated by various threads (each of whom have their own
|
||||
* timeout)
|
||||
*
|
||||
*/
|
||||
class I2PServerSocketImpl implements I2PServerSocket {
|
||||
private final static Log _log = new Log(I2PServerSocketImpl.class);
|
||||
private I2PSocketManager mgr;
|
||||
private I2PSocket cached = null; // buffer one socket here
|
||||
|
||||
private boolean closing = false; // Are we being closed?
|
||||
|
||||
private Object acceptLock = new Object();
|
||||
|
||||
/** list of sockets waiting for the client to accept them */
|
||||
private List pendingSockets = Collections.synchronizedList(new ArrayList(4));
|
||||
|
||||
/** have we been closed */
|
||||
private volatile boolean closing = false;
|
||||
|
||||
/** lock on this when accepting a pending socket, and wait on it for notification of acceptance */
|
||||
private Object socketAcceptedLock = new Object();
|
||||
/** lock on this when adding a new socket to the pending list, and wait on it accordingly */
|
||||
private Object socketAddedLock = new Object();
|
||||
|
||||
public I2PServerSocketImpl(I2PSocketManager mgr) {
|
||||
this.mgr = mgr;
|
||||
}
|
||||
|
||||
public synchronized I2PSocket accept() throws I2PException, ConnectException {
|
||||
I2PSocket ret;
|
||||
|
||||
synchronized (acceptLock) {
|
||||
while ((cached == null) && !closing) {
|
||||
myWait();
|
||||
}
|
||||
|
||||
if (closing) {
|
||||
throw new ConnectException("I2PServerSocket closed");
|
||||
}
|
||||
|
||||
ret = cached;
|
||||
cached = null;
|
||||
acceptLock.notifyAll();
|
||||
}
|
||||
|
||||
_log.debug("TIMING: handed out accept result " + ret.hashCode());
|
||||
|
||||
/**
|
||||
* Waits for the next socket connecting. If a remote user tried to make a
|
||||
* connection and the local application wasn't .accept()ing new connections,
|
||||
* they should get refused (if .accept() doesnt occur in some small period -
|
||||
* currently 5 seconds)
|
||||
*
|
||||
* @return a connected I2PSocket
|
||||
*
|
||||
* @throws I2PException if there is a problem with reading a new socket
|
||||
* from the data available (aka the I2PSession closed, etc)
|
||||
* @throws ConnectException if the I2PServerSocket is closed
|
||||
*/
|
||||
public I2PSocket accept() throws I2PException, ConnectException {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("accept() called, pending: " + pendingSockets.size());
|
||||
|
||||
I2PSocket ret = null;
|
||||
|
||||
while ( (ret == null) && (!closing) ){
|
||||
while (pendingSockets.size() <= 0) {
|
||||
if (closing) throw new ConnectException("I2PServerSocket closed");
|
||||
try {
|
||||
synchronized(socketAddedLock) {
|
||||
socketAddedLock.wait();
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
synchronized (pendingSockets) {
|
||||
if (pendingSockets.size() > 0) {
|
||||
ret = (I2PSocket)pendingSockets.remove(0);
|
||||
}
|
||||
}
|
||||
if (ret != null) {
|
||||
synchronized (socketAcceptedLock) {
|
||||
socketAcceptedLock.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("TIMING: handed out accept result " + ret.hashCode());
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean getNewSocket(I2PSocket s) {
|
||||
synchronized (acceptLock) {
|
||||
while (cached != null) {
|
||||
myWait();
|
||||
}
|
||||
cached = s;
|
||||
acceptLock.notifyAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make the socket available and wait until the client app accepts it, or until
|
||||
* the given timeout elapses. This doesn't have any limits on the queue size -
|
||||
* perhaps it should add some choking (e.g. after 5 waiting for accept, refuse)
|
||||
*
|
||||
* @param timeoutMs how long to wait until accept
|
||||
* @return true if the socket was accepted, false if the timeout expired
|
||||
* or the socket was closed
|
||||
*/
|
||||
public boolean addWaitForAccept(I2PSocket s, long timeoutMs) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("addWaitForAccept [new socket arrived [" + s.toString() + "], pending: " + pendingSockets.size());
|
||||
|
||||
if (closing) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Already closing the socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
Clock clock = I2PAppContext.getGlobalContext().clock();
|
||||
long start = clock.now();
|
||||
long end = start + timeoutMs;
|
||||
pendingSockets.add(s);
|
||||
synchronized (socketAddedLock) {
|
||||
socketAddedLock.notifyAll();
|
||||
}
|
||||
|
||||
// keep looping until the socket has been grabbed by the accept()
|
||||
// (or the expiration passes, or the socket is closed)
|
||||
while (pendingSockets.contains(s)) {
|
||||
long now = clock.now();
|
||||
if (now >= end) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Expired while waiting for accept (time elapsed =" + (now - start) + "ms) for socket " + s.toString());
|
||||
pendingSockets.remove(s);
|
||||
return false;
|
||||
}
|
||||
if (closing) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Server socket closed while waiting for accept");
|
||||
pendingSockets.remove(s);
|
||||
return false;
|
||||
}
|
||||
long remaining = end - now;
|
||||
try {
|
||||
synchronized (socketAcceptedLock) {
|
||||
socketAcceptedLock.wait(remaining);
|
||||
}
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
long now = clock.now();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.info("Socket accepted after " + (now-start) + "ms for socket " + s.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
public void close() throws I2PException {
|
||||
synchronized (acceptLock) {
|
||||
closing = true;
|
||||
acceptLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public I2PSocketManager getManager() {
|
||||
return mgr;
|
||||
}
|
||||
|
||||
private void myWait() {
|
||||
try {
|
||||
acceptLock.wait();
|
||||
} catch (InterruptedException ex) {}
|
||||
|
||||
public void close() {
|
||||
closing = true;
|
||||
// let anyone .accept()ing know to fsck off
|
||||
synchronized (socketAddedLock) {
|
||||
socketAddedLock.notifyAll();
|
||||
}
|
||||
// let anyone addWaitForAccept()ing know to fsck off
|
||||
synchronized (socketAcceptedLock) {
|
||||
socketAcceptedLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public I2PSocketManager getManager() { return mgr; }
|
||||
}
|
||||
|
@ -32,8 +32,39 @@ public interface I2PSocket {
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* How long we will wait blocked on a read() operation.
|
||||
*
|
||||
* @return milliseconds to wait, or -1 if we will wait indefinitely
|
||||
*/
|
||||
public long getReadTimeout();
|
||||
|
||||
/**
|
||||
* Define how long we will wait blocked on a read() operation (-1 will make
|
||||
* the socket wait forever).
|
||||
*
|
||||
*/
|
||||
public void setReadTimeout(long ms);
|
||||
|
||||
/**
|
||||
* Closes the socket if not closed yet
|
||||
*/
|
||||
public void close() throws IOException;
|
||||
}
|
||||
|
||||
public void setSocketErrorListener(SocketErrorListener lsnr);
|
||||
/**
|
||||
* Allow notification of underlying errors communicating across I2P without
|
||||
* waiting for any sort of cleanup process. For example, if some data could
|
||||
* not be sent, this listener is notified immediately, and while the input/output
|
||||
* streams are notified through IOExceptions, they are told only after the
|
||||
* TCP-like stream is closed (which may be a minute later, if the close message
|
||||
* times out as well). This is not fired on normal close() activity.
|
||||
*
|
||||
*/
|
||||
public interface SocketErrorListener {
|
||||
/**
|
||||
* An error occurred communicating with the peer.
|
||||
*/
|
||||
void errorOccurred();
|
||||
}
|
||||
}
|
||||
|
@ -29,14 +29,44 @@ class I2PSocketImpl implements I2PSocket {
|
||||
private Object remoteIDWaiter = new Object();
|
||||
private I2PInputStream in;
|
||||
private I2POutputStream out;
|
||||
private SocketErrorListener _socketErrorListener;
|
||||
private boolean outgoing;
|
||||
private long _socketId;
|
||||
private static long __socketId = 0;
|
||||
private long _bytesRead = 0;
|
||||
private long _bytesWritten = 0;
|
||||
private Object flagLock = new Object();
|
||||
private boolean closed = false, sendClose = true, closed2 = false;
|
||||
|
||||
/**
|
||||
* Whether the I2P socket has already been closed.
|
||||
*/
|
||||
private boolean closed = false;
|
||||
|
||||
/**
|
||||
* Whether to send out a close packet when the socket is
|
||||
* closed. (If the socket is closed because of an incoming close
|
||||
* packet, we need not send one.)
|
||||
*/
|
||||
private boolean sendClose = true;
|
||||
|
||||
/**
|
||||
* Whether the I2P socket has already been closed and all data
|
||||
* (from I2P to the app, dunno whether to call this incoming or
|
||||
* outgoing) has been processed.
|
||||
*/
|
||||
private boolean closed2 = false;
|
||||
|
||||
/**
|
||||
* @param peer who this socket is (or should be) connected to
|
||||
* @param mgr how we talk to the network
|
||||
* @param outgoing did we initiate the connection (true) or did we receive it (false)?
|
||||
* @param localID what is our half of the socket ID?
|
||||
*/
|
||||
public I2PSocketImpl(Destination peer, I2PSocketManager mgr, boolean outgoing, String localID) {
|
||||
this.outgoing = outgoing;
|
||||
manager = mgr;
|
||||
remote = peer;
|
||||
_socketId = ++__socketId;
|
||||
local = mgr.getSession().getMyDestination();
|
||||
in = new I2PInputStream();
|
||||
I2PInputStream pin = new I2PInputStream();
|
||||
@ -45,10 +75,17 @@ class I2PSocketImpl implements I2PSocket {
|
||||
this.localID = localID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Our half of the socket's unique ID
|
||||
*
|
||||
*/
|
||||
public String getLocalID() {
|
||||
return localID;
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received the other side's half of the socket's unique ID
|
||||
*/
|
||||
public void setRemoteID(String id) {
|
||||
synchronized (remoteIDWaiter) {
|
||||
remoteID = id;
|
||||
@ -56,37 +93,73 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
}
|
||||
|
||||
public String getRemoteID(boolean wait) throws InterruptedIOException {
|
||||
return getRemoteID(wait, -1);
|
||||
/**
|
||||
* Retrieve the other side's half of the socket's unique ID, or null if it
|
||||
* isn't known yet
|
||||
*
|
||||
* @param wait if true, we should wait until we receive it from the peer, otherwise
|
||||
* return what we know immediately (which may be null)
|
||||
*/
|
||||
public String getRemoteID(boolean wait) {
|
||||
try {
|
||||
return getRemoteID(wait, -1);
|
||||
} catch (InterruptedIOException iie) {
|
||||
_log.error("wtf, we said we didn't want it to time out! you smell", iie);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the other side's half of the socket's unique ID, or null if it isn't
|
||||
* known yet and we were instructed not to wait
|
||||
*
|
||||
* @param wait should we wait for the peer to send us their half of the ID, or
|
||||
* just return immediately?
|
||||
* @param maxWait if we're going to wait, after how long should we timeout and fail?
|
||||
* (if this value is < 0, we wait indefinitely)
|
||||
* @throws InterruptedIOException when the max waiting period has been exceeded
|
||||
*/
|
||||
public String getRemoteID(boolean wait, long maxWait) throws InterruptedIOException {
|
||||
long dieAfter = System.currentTimeMillis() + maxWait;
|
||||
synchronized (remoteIDWaiter) {
|
||||
if (wait) {
|
||||
try {
|
||||
if (maxWait > 0)
|
||||
if (maxWait >= 0)
|
||||
remoteIDWaiter.wait(maxWait);
|
||||
else
|
||||
remoteIDWaiter.wait();
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
|
||||
if ((maxWait > 0) && (System.currentTimeMillis() > dieAfter))
|
||||
if ((maxWait >= 0) && (System.currentTimeMillis() >= dieAfter))
|
||||
throw new InterruptedIOException("Timed out waiting for remote ID");
|
||||
|
||||
_log.debug("TIMING: RemoteID set to " + I2PSocketManager.getReadableForm(remoteID) + " for "
|
||||
+ this.hashCode());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("TIMING: RemoteID set to "
|
||||
+ I2PSocketManager.getReadableForm(remoteID) + " for "
|
||||
+ this.hashCode());
|
||||
}
|
||||
return remoteID;
|
||||
}
|
||||
}
|
||||
|
||||
public String getRemoteID() throws InterruptedIOException {
|
||||
/**
|
||||
* Retrieve the other side's half of the socket's unique ID, or null if it
|
||||
* isn't known yet. This does not wait
|
||||
*
|
||||
*/
|
||||
public String getRemoteID() {
|
||||
return getRemoteID(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The other side has given us some data, so inject it into our socket's
|
||||
* inputStream
|
||||
*
|
||||
* @param data the data to inject into our local inputStream
|
||||
*/
|
||||
public void queueData(byte[] data) {
|
||||
_bytesRead += data.length;
|
||||
in.queueData(data);
|
||||
}
|
||||
|
||||
@ -121,7 +194,8 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the socket if not closed yet
|
||||
* Closes the socket if not closed yet (from the Application
|
||||
* side).
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
synchronized (flagLock) {
|
||||
@ -132,7 +206,10 @@ class I2PSocketImpl implements I2PSocket {
|
||||
in.notifyClosed();
|
||||
}
|
||||
|
||||
public void internalClose() {
|
||||
/**
|
||||
* Close the socket from the I2P side, e. g. by a close packet.
|
||||
*/
|
||||
protected void internalClose() {
|
||||
synchronized (flagLock) {
|
||||
closed = true;
|
||||
closed2 = true;
|
||||
@ -143,14 +220,51 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
|
||||
private byte getMask(int add) {
|
||||
return (byte) ((outgoing ? (byte) 0xA0 : (byte) 0x50) + (byte) add);
|
||||
if (outgoing)
|
||||
return (byte)(I2PSocketManager.DATA_IN + (byte)add);
|
||||
else
|
||||
return (byte)(I2PSocketManager.DATA_OUT + (byte)add);
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the longest we'll block on the input stream while waiting
|
||||
* for more data? If this value is exceeded, the read() throws
|
||||
* InterruptedIOException
|
||||
*/
|
||||
public long getReadTimeout() {
|
||||
return in.getReadTimeout();
|
||||
}
|
||||
|
||||
public void setReadTimeout(long ms) {
|
||||
in.setReadTimeout(ms);
|
||||
}
|
||||
|
||||
public void setSocketErrorListener(SocketErrorListener lsnr) {
|
||||
_socketErrorListener = lsnr;
|
||||
}
|
||||
|
||||
void errorOccurred() {
|
||||
if (_socketErrorListener != null)
|
||||
_socketErrorListener.errorOccurred();
|
||||
}
|
||||
|
||||
private String getPrefix() { return "[" + _socketId + "]: "; }
|
||||
|
||||
//--------------------------------------------------
|
||||
public class I2PInputStream extends InputStream {
|
||||
private class I2PInputStream extends InputStream {
|
||||
|
||||
private ByteCollector bc = new ByteCollector();
|
||||
|
||||
private long readTimeout = -1;
|
||||
|
||||
public long getReadTimeout() {
|
||||
return readTimeout;
|
||||
}
|
||||
|
||||
public void setReadTimeout(long ms) {
|
||||
readTimeout = ms;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] b = new byte[1];
|
||||
int res = read(b);
|
||||
@ -160,32 +274,47 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
|
||||
public synchronized int read(byte[] b, int off, int len) throws IOException {
|
||||
_log.debug("Read called: " + this.hashCode());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Read called: " + this.hashCode());
|
||||
if (len == 0) return 0;
|
||||
long dieAfter = System.currentTimeMillis() + readTimeout;
|
||||
byte[] read = bc.startToByteArray(len);
|
||||
boolean timedOut = false;
|
||||
|
||||
while (read.length == 0) {
|
||||
synchronized (flagLock) {
|
||||
if (closed) {
|
||||
_log.debug("Closed is set, so closing stream: " + this.hashCode());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Closed is set after reading " + _bytesRead + " and writing " + _bytesWritten + ", so closing stream: " + hashCode());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ex) {
|
||||
if (readTimeout >= 0) {
|
||||
wait(readTimeout);
|
||||
} else {
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException ex) {}
|
||||
|
||||
if ((readTimeout >= 0)
|
||||
&& (System.currentTimeMillis() >= dieAfter)) {
|
||||
throw new InterruptedIOException(getPrefix() + "Timeout reading from I2PSocket (" + readTimeout + " msecs)");
|
||||
}
|
||||
|
||||
read = bc.startToByteArray(len);
|
||||
}
|
||||
if (read.length > len) throw new RuntimeException("BUG");
|
||||
System.arraycopy(read, 0, b, off, read.length);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("Read from I2PInputStream " + this.hashCode() + " returned " + read.length + " bytes");
|
||||
_log.debug(getPrefix() + "Read from I2PInputStream " + hashCode() + " returned "
|
||||
+ read.length + " bytes");
|
||||
}
|
||||
//if (_log.shouldLog(Log.DEBUG)) {
|
||||
// _log.debug("Read from I2PInputStream " + this.hashCode()
|
||||
// + " returned "+read.length+" bytes:\n"
|
||||
// + HexDump.dump(read));
|
||||
// + " returned "+read.length+" bytes:\n"
|
||||
// + HexDump.dump(read));
|
||||
//}
|
||||
return read.length;
|
||||
}
|
||||
@ -199,18 +328,24 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
|
||||
public synchronized void queueData(byte[] data, int off, int len) {
|
||||
_log.debug("Insert " + len + " bytes into queue: " + this.hashCode());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Insert " + len + " bytes into queue: " + hashCode());
|
||||
bc.append(data, off, len);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
public synchronized void notifyClosed() {
|
||||
notifyAll();
|
||||
I2PInputStream.this.notifyAll();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
notifyClosed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class I2POutputStream extends OutputStream {
|
||||
private class I2POutputStream extends OutputStream {
|
||||
|
||||
public I2PInputStream sendTo;
|
||||
|
||||
@ -223,6 +358,7 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
_bytesWritten += len;
|
||||
sendTo.queueData(b, off, len);
|
||||
}
|
||||
|
||||
@ -231,94 +367,114 @@ class I2PSocketImpl implements I2PSocket {
|
||||
}
|
||||
}
|
||||
|
||||
public class I2PSocketRunner extends I2PThread {
|
||||
private static volatile long __runnerId = 0;
|
||||
private class I2PSocketRunner extends I2PThread {
|
||||
|
||||
public InputStream in;
|
||||
|
||||
public I2PSocketRunner(InputStream in) {
|
||||
_log.debug("Runner's input stream is: " + in.hashCode());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Runner's input stream is: " + in.hashCode());
|
||||
this.in = in;
|
||||
setName("SocketRunner from " + I2PSocketImpl.this.remote.calculateHash().toBase64().substring(0, 4));
|
||||
String peer = I2PSocketImpl.this.remote.calculateHash().toBase64();
|
||||
setName("SocketRunner " + (++__runnerId) + "/" + _socketId + " " + peer.substring(0, 4));
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pump some more data
|
||||
*
|
||||
* @return true if we should keep on handling, false otherwise
|
||||
*/
|
||||
private boolean handleNextPacket(ByteCollector bc, byte buffer[])
|
||||
throws IOException, I2PSessionException {
|
||||
int len = in.read(buffer);
|
||||
int bcsize = bc.getCurrentSize();
|
||||
if (len != -1) {
|
||||
bc.append(buffer, len);
|
||||
} else if (bcsize == 0) {
|
||||
// nothing left in the buffer, and read(..) got EOF (-1).
|
||||
// the bart the
|
||||
return false;
|
||||
}
|
||||
if ((bcsize < MAX_PACKET_SIZE) && (in.available() == 0)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Runner Point d: " + hashCode());
|
||||
|
||||
try {
|
||||
Thread.sleep(PACKET_DELAY);
|
||||
} catch (InterruptedException e) {
|
||||
_log.warn("wtf", e);
|
||||
}
|
||||
}
|
||||
if ((bcsize >= MAX_PACKET_SIZE) || (in.available() == 0)) {
|
||||
byte[] data = bc.startToByteArray(MAX_PACKET_SIZE);
|
||||
if (data.length > 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Message size is: " + data.length);
|
||||
boolean sent = sendBlock(data);
|
||||
if (!sent) {
|
||||
_log.error(getPrefix() + "Error sending message to peer. Killing socket runner");
|
||||
errorOccurred();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
byte[] buffer = new byte[MAX_PACKET_SIZE];
|
||||
ByteCollector bc = new ByteCollector();
|
||||
boolean sent = true;
|
||||
boolean keepHandling = true;
|
||||
int packetsHandled = 0;
|
||||
try {
|
||||
int len, bcsize;
|
||||
// try {
|
||||
while (true) {
|
||||
len = in.read(buffer);
|
||||
bcsize = bc.getCurrentSize();
|
||||
if (len != -1) {
|
||||
bc.append(buffer, len);
|
||||
} else if (bcsize == 0) {
|
||||
break;
|
||||
}
|
||||
if ((bcsize < MAX_PACKET_SIZE) && (in.available() == 0)) {
|
||||
_log.debug("Runner Point d: " + this.hashCode());
|
||||
|
||||
try {
|
||||
Thread.sleep(PACKET_DELAY);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if ((bcsize >= MAX_PACKET_SIZE) || (in.available() == 0)) {
|
||||
byte[] data = bc.startToByteArray(MAX_PACKET_SIZE);
|
||||
if (data.length > 0) {
|
||||
_log.debug("Message size is: " + data.length);
|
||||
sent = sendBlock(data);
|
||||
if (!sent) {
|
||||
_log.error("Error sending message to peer. Killing socket runner");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// try {
|
||||
while (keepHandling) {
|
||||
keepHandling = handleNextPacket(bc, buffer);
|
||||
packetsHandled++;
|
||||
}
|
||||
if ((bc.getCurrentSize() > 0) && sent) {
|
||||
_log.error("A SCARY MONSTER HAS EATEN SOME DATA! " + "(input stream: " + in.hashCode() + "; "
|
||||
if ((bc.getCurrentSize() > 0) && (packetsHandled > 1)) {
|
||||
_log.error(getPrefix() + "A SCARY MONSTER HAS EATEN SOME DATA! " + "(input stream: "
|
||||
+ in.hashCode() + "; "
|
||||
+ "queue size: " + bc.getCurrentSize() + ")");
|
||||
}
|
||||
synchronized (flagLock) {
|
||||
closed2 = true;
|
||||
}
|
||||
// } catch (IOException ex) {
|
||||
// if (_log.shouldLog(Log.INFO))
|
||||
// _log.info("Error reading and writing", ex);
|
||||
// }
|
||||
boolean sc;
|
||||
synchronized (flagLock) {
|
||||
sc = sendClose;
|
||||
} // FIXME: Race here?
|
||||
if (sc) {
|
||||
_log.info("Sending close packet: " + outgoing);
|
||||
byte[] packet = I2PSocketManager.makePacket((byte) (getMask(0x02)), remoteID, new byte[0]);
|
||||
synchronized (manager.getSession()) {
|
||||
sent = manager.getSession().sendMessage(remote, packet);
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix() + "Sending close packet: (we started? " + outgoing + ") after reading " + _bytesRead + " and writing " + _bytesWritten);
|
||||
byte[] packet = I2PSocketManager.makePacket(getMask(0x02), remoteID, new byte[0]);
|
||||
boolean sent = manager.getSession().sendMessage(remote, packet);
|
||||
if (!sent) {
|
||||
_log.error("Error sending close packet to peer");
|
||||
_log.error(getPrefix() + "Error sending close packet to peer");
|
||||
errorOccurred();
|
||||
}
|
||||
}
|
||||
manager.removeSocket(I2PSocketImpl.this);
|
||||
} catch (InterruptedIOException ex) {
|
||||
_log.error(getPrefix() + "BUG! read() operations should not timeout!", ex);
|
||||
} catch (IOException ex) {
|
||||
// WHOEVER removes this event on inconsistent
|
||||
// state before fixing the inconsistent state (a
|
||||
// reference on the socket in the socket manager
|
||||
// etc.) will get hanged by me personally -- mihi
|
||||
_log.error("Error running - **INCONSISTENT STATE!!!**", ex);
|
||||
_log.error(getPrefix() + "Error running - **INCONSISTENT STATE!!!**", ex);
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error running - **INCONSISTENT STATE!!!**", ex);
|
||||
_log.error(getPrefix() + "Error running - **INCONSISTENT STATE!!!**", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean sendBlock(byte data[]) throws I2PSessionException {
|
||||
_log.debug("TIMING: Block to send for " + I2PSocketImpl.this.hashCode());
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "TIMING: Block to send for " + I2PSocketImpl.this.hashCode());
|
||||
if (remoteID == null) {
|
||||
_log.error("NULL REMOTEID");
|
||||
_log.error(getPrefix() + "NULL REMOTEID");
|
||||
return false;
|
||||
}
|
||||
byte[] packet = I2PSocketManager.makePacket(getMask(0x00), remoteID, data);
|
||||
@ -326,10 +482,10 @@ class I2PSocketImpl implements I2PSocket {
|
||||
synchronized (flagLock) {
|
||||
if (closed2) return false;
|
||||
}
|
||||
synchronized (manager.getSession()) {
|
||||
sent = manager.getSession().sendMessage(remote, packet);
|
||||
}
|
||||
sent = manager.getSession().sendMessage(remote, packet);
|
||||
return sent;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() { return "" + hashCode(); }
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
*/
|
||||
package net.i2p.client.streaming;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
@ -21,6 +20,7 @@ import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSessionListener;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@ -40,11 +40,27 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
private HashMap _outSockets;
|
||||
private HashMap _inSockets;
|
||||
private I2PSocketOptions _defaultOptions;
|
||||
private long _acceptTimeout;
|
||||
|
||||
public static final short ACK = 0x51;
|
||||
public static final short CLOSE_OUT = 0x52;
|
||||
public static final short DATA_OUT = 0x50;
|
||||
public static final short SYN = 0xA1;
|
||||
public static final short CLOSE_IN = 0xA2;
|
||||
public static final short DATA_IN = 0xA0;
|
||||
public static final short CHAFF = 0xFF;
|
||||
|
||||
/**
|
||||
* How long to wait for the client app to accept() before sending back CLOSE?
|
||||
* This includes the time waiting in the queue. Currently set to 5 seconds.
|
||||
*/
|
||||
private static final long ACCEPT_TIMEOUT_DEFAULT = 5*1000;
|
||||
|
||||
public I2PSocketManager() {
|
||||
_session = null;
|
||||
_inSockets = new HashMap(16);
|
||||
_outSockets = new HashMap(16);
|
||||
_acceptTimeout = ACCEPT_TIMEOUT_DEFAULT;
|
||||
}
|
||||
|
||||
public I2PSession getSession() {
|
||||
@ -55,15 +71,25 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
_session = session;
|
||||
if (session != null) session.setSessionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* How long should we wait for the client to .accept() a socket before
|
||||
* sending back a NACK/Close?
|
||||
*
|
||||
* @param ms milliseconds to wait, maximum
|
||||
*/
|
||||
public void setAcceptTimeout(long ms) { _acceptTimeout = ms; }
|
||||
public long getAcceptTimeout() { return _acceptTimeout; }
|
||||
|
||||
public void disconnected(I2PSession session) {
|
||||
_log.error("Disconnected from the session");
|
||||
_log.info("Disconnected from the session");
|
||||
destroySocketManager();
|
||||
}
|
||||
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
_log.error("Error occurred: [" + message + "]", error);
|
||||
}
|
||||
|
||||
|
||||
public void messageAvailable(I2PSession session, int msgId, long size) {
|
||||
try {
|
||||
I2PSocketImpl s;
|
||||
@ -77,157 +103,278 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
return;
|
||||
}
|
||||
int type = msg[0] & 0xff;
|
||||
String id = new String(new byte[] { msg[1], msg[2], msg[3]}, "ISO-8859-1");
|
||||
String id = toString(new byte[] { msg[1], msg[2], msg[3]});
|
||||
byte[] payload = new byte[msg.length - 4];
|
||||
System.arraycopy(msg, 4, payload, 0, payload.length);
|
||||
_log.debug("Message read: type = [" + Integer.toHexString(type) + "] id = [" + getReadableForm(id)
|
||||
+ "] payload length: " + payload.length + "]");
|
||||
synchronized (lock) {
|
||||
switch (type) {
|
||||
case 0x51:
|
||||
// ACK outgoing
|
||||
s = (I2PSocketImpl) _outSockets.get(id);
|
||||
if (s == null) {
|
||||
_log.warn("No socket responsible for ACK packet");
|
||||
return;
|
||||
}
|
||||
if (payload.length == 3 && s.getRemoteID(false) == null) {
|
||||
String newID = new String(payload, "ISO-8859-1");
|
||||
s.setRemoteID(newID);
|
||||
return;
|
||||
} else {
|
||||
if (payload.length != 3)
|
||||
_log.warn("Ack packet had " + payload.length + " bytes");
|
||||
else
|
||||
_log.warn("Remote ID already exists? " + s.getRemoteID());
|
||||
return;
|
||||
}
|
||||
case 0x52:
|
||||
// disconnect outgoing
|
||||
_log.debug("*Disconnect outgoing!");
|
||||
try {
|
||||
s = (I2PSocketImpl) _outSockets.get(id);
|
||||
if (s != null) {
|
||||
if (payload.length > 0) {
|
||||
_log.debug("Disconnect packet had "
|
||||
+ payload.length + " bytes");
|
||||
}
|
||||
if (s.getRemoteID(false) == null) {
|
||||
s.setRemoteID(null); // Just to wake up socket
|
||||
return;
|
||||
}
|
||||
s.internalClose();
|
||||
_outSockets.remove(id);
|
||||
}
|
||||
return;
|
||||
} catch (Exception t) {
|
||||
_log.error("Ignoring error on disconnect", t);
|
||||
}
|
||||
case 0x50:
|
||||
// packet send outgoing
|
||||
_log.debug("*Packet send outgoing [" + payload.length + "]");
|
||||
s = (I2PSocketImpl) _outSockets.get(id);
|
||||
if (s != null) {
|
||||
s.queueData(payload);
|
||||
return;
|
||||
} else {
|
||||
_log.error("Null socket with data available");
|
||||
throw new IllegalStateException("Null socket with data available");
|
||||
}
|
||||
case 0xA1:
|
||||
// SYN incoming
|
||||
_log.debug("*Syn!");
|
||||
String newLocalID = makeID(_inSockets);
|
||||
Destination d = new Destination();
|
||||
d.readBytes(new ByteArrayInputStream(payload));
|
||||
|
||||
if (_serverSocket == null) {
|
||||
// The app did not instantiate an I2PServerSocket
|
||||
byte[] packet = makePacket((byte) 0x52, id, newLocalID.getBytes("ISO-8859-1"));
|
||||
boolean replySentOk = false;
|
||||
synchronized (_session) {
|
||||
replySentOk = _session.sendMessage(d, packet);
|
||||
}
|
||||
if (!replySentOk) {
|
||||
_log.error("Error sending close to " + d.calculateHash().toBase64()
|
||||
+ " in response to a new con message", new Exception("Failed creation"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
s = new I2PSocketImpl(d, this, false, newLocalID);
|
||||
s.setRemoteID(id);
|
||||
if (_serverSocket.getNewSocket(s)) {
|
||||
_inSockets.put(newLocalID, s);
|
||||
byte[] packet = makePacket((byte) 0x51, id, newLocalID.getBytes("ISO-8859-1"));
|
||||
boolean replySentOk = false;
|
||||
synchronized (_session) {
|
||||
replySentOk = _session.sendMessage(d, packet);
|
||||
}
|
||||
if (!replySentOk) {
|
||||
_log.error("Error sending reply to " + d.calculateHash().toBase64()
|
||||
+ " in response to a new con message", new Exception("Failed creation"));
|
||||
s.internalClose();
|
||||
}
|
||||
} else {
|
||||
byte[] packet = (" " + id).getBytes("ISO-8859-1");
|
||||
packet[0] = 0x52;
|
||||
boolean nackSent = session.sendMessage(d, packet);
|
||||
if (!nackSent) {
|
||||
_log.error("Error sending NACK for session creation");
|
||||
}
|
||||
s.internalClose();
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Message read: type = [" + Integer.toHexString(type)
|
||||
+ "] id = [" + getReadableForm(id)
|
||||
+ "] payload length: [" + payload.length + "]");
|
||||
switch (type) {
|
||||
case ACK:
|
||||
ackAvailable(id, payload);
|
||||
return;
|
||||
case 0xA2:
|
||||
// disconnect incoming
|
||||
_log.debug("*Disconnect incoming!");
|
||||
try {
|
||||
s = (I2PSocketImpl) _inSockets.get(id);
|
||||
if (payload.length == 0 && s != null) {
|
||||
s.internalClose();
|
||||
_inSockets.remove(id);
|
||||
return;
|
||||
} else {
|
||||
if (payload.length > 0) _log.warn("Disconnect packet had " + payload.length + " bytes");
|
||||
return;
|
||||
}
|
||||
} catch (Exception t) {
|
||||
_log.error("Ignoring error on disconnect", t);
|
||||
return;
|
||||
}
|
||||
case 0xA0:
|
||||
// packet send incoming
|
||||
_log.debug("*Packet send incoming [" + payload.length + "]");
|
||||
s = (I2PSocketImpl) _inSockets.get(id);
|
||||
if (s != null) {
|
||||
s.queueData(payload);
|
||||
return;
|
||||
} else {
|
||||
_log.error("Null socket with data available");
|
||||
throw new IllegalStateException("Null socket with data available");
|
||||
}
|
||||
case 0xFF:
|
||||
case CLOSE_OUT:
|
||||
disconnectAvailable(id, payload);
|
||||
return;
|
||||
case DATA_OUT:
|
||||
sendOutgoingAvailable(id, payload);
|
||||
return;
|
||||
case SYN:
|
||||
synIncomingAvailable(id, payload, session);
|
||||
return;
|
||||
case CLOSE_IN:
|
||||
disconnectIncoming(id, payload);
|
||||
return;
|
||||
case DATA_IN:
|
||||
sendIncoming(id, payload);
|
||||
case CHAFF:
|
||||
// ignore
|
||||
return;
|
||||
}
|
||||
_log.error("\n\n=============== Unknown packet! " + "============" + "\nType: " + (int) type
|
||||
+ "\nID: " + getReadableForm(id) + "\nBase64'ed Data: " + Base64.encode(payload)
|
||||
+ "\n\n\n");
|
||||
if (id != null) {
|
||||
_inSockets.remove(id);
|
||||
_outSockets.remove(id);
|
||||
}
|
||||
default:
|
||||
handleUnknown(type, id, payload);
|
||||
return;
|
||||
}
|
||||
} catch (I2PException ise) {
|
||||
_log.error("Error processing", ise);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error processing", ioe);
|
||||
} catch (IllegalStateException ise) {
|
||||
_log.debug("Error processing", ise);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received an ACK packet (hopefully, in response to a SYN that we
|
||||
* recently sent out). Notify the associated I2PSocket that we now have
|
||||
* the remote stream ID (which should get things going, since the handshake
|
||||
* is complete).
|
||||
*
|
||||
*/
|
||||
private void ackAvailable(String id, byte payload[]) {
|
||||
I2PSocketImpl s = null;
|
||||
synchronized (lock) {
|
||||
s = (I2PSocketImpl) _outSockets.get(id);
|
||||
}
|
||||
|
||||
if (s == null) {
|
||||
_log.warn("No socket responsible for ACK packet");
|
||||
return;
|
||||
}
|
||||
|
||||
String remoteId = null;
|
||||
remoteId = s.getRemoteID(false);
|
||||
|
||||
if ( (payload.length == 3) && (remoteId == null) ) {
|
||||
String newID = toString(payload);
|
||||
s.setRemoteID(newID);
|
||||
return;
|
||||
} else {
|
||||
// (payload.length != 3 || getRemoteId != null)
|
||||
if (_log.shouldLog(Log.WARN)) {
|
||||
if (payload.length != 3)
|
||||
_log.warn("Ack packet had " + payload.length + " bytes");
|
||||
else
|
||||
_log.warn("Remote ID already exists? " + remoteId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We received a disconnect packet, telling us to tear down the specified
|
||||
* stream.
|
||||
*/
|
||||
private void disconnectAvailable(String id, byte payload[]) {
|
||||
I2PSocketImpl s = null;
|
||||
synchronized (lock) {
|
||||
s = (I2PSocketImpl) _outSockets.get(id);
|
||||
}
|
||||
|
||||
_log.debug("*Disconnect outgoing for socket " + s);
|
||||
try {
|
||||
if (s != null) {
|
||||
if (payload.length > 0) {
|
||||
_log.debug("Disconnect packet had "
|
||||
+ payload.length + " bytes");
|
||||
}
|
||||
if (s.getRemoteID(false) == null) {
|
||||
s.setRemoteID(null); // Just to wake up socket
|
||||
return;
|
||||
}
|
||||
s.internalClose();
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(id);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} catch (Exception t) {
|
||||
_log.error("Ignoring error on disconnect for socket " + s, t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received data on a stream we created - toss the data onto
|
||||
* the socket for handling.
|
||||
*
|
||||
* @throws IllegalStateException if the socket isn't open or isn't known
|
||||
*/
|
||||
private void sendOutgoingAvailable(String id, byte payload[]) throws IllegalStateException {
|
||||
I2PSocketImpl s = null;
|
||||
synchronized (lock) {
|
||||
s = (I2PSocketImpl) _outSockets.get(id);
|
||||
}
|
||||
|
||||
// packet send outgoing
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("*Packet send outgoing [" + payload.length + "] for socket " + s);
|
||||
if (s != null) {
|
||||
s.queueData(payload);
|
||||
return;
|
||||
} else {
|
||||
_log.error("Null socket with data available");
|
||||
throw new IllegalStateException("Null socket with data available");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received a SYN packet (a request for a new stream). If the client has
|
||||
* said they want incoming sockets (by retrieving the serverSocket), the stream
|
||||
* will be ACKed, but if they have not, they'll be NACKed)
|
||||
*
|
||||
* @throws DataFormatException if the destination in the SYN was invalid
|
||||
* @throws I2PSessionException if there was an I2P error sending the ACK or NACK
|
||||
*/
|
||||
private void synIncomingAvailable(String id, byte payload[], I2PSession session)
|
||||
throws DataFormatException, I2PSessionException {
|
||||
Destination d = new Destination();
|
||||
d.fromByteArray(payload);
|
||||
|
||||
I2PSocketImpl s = null;
|
||||
boolean acceptConnections = (_serverSocket != null);
|
||||
String newLocalID = null;
|
||||
synchronized (lock) {
|
||||
newLocalID = makeID(_inSockets);
|
||||
if (acceptConnections) {
|
||||
s = new I2PSocketImpl(d, this, false, newLocalID);
|
||||
s.setRemoteID(id);
|
||||
}
|
||||
}
|
||||
_log.debug("*Syn! for socket " + s);
|
||||
|
||||
if (!acceptConnections) {
|
||||
// The app did not instantiate an I2PServerSocket
|
||||
byte[] packet = makePacket((byte) CLOSE_OUT, id, toBytes(newLocalID));
|
||||
boolean replySentOk = false;
|
||||
synchronized (_session) {
|
||||
replySentOk = _session.sendMessage(d, packet);
|
||||
}
|
||||
if (!replySentOk) {
|
||||
_log.error("Error sending close to " + d.calculateHash().toBase64()
|
||||
+ " in response to a new con message",
|
||||
new Exception("Failed creation"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_serverSocket.addWaitForAccept(s, _acceptTimeout)) {
|
||||
_inSockets.put(newLocalID, s);
|
||||
byte[] packet = makePacket((byte) ACK, id, toBytes(newLocalID));
|
||||
boolean replySentOk = false;
|
||||
replySentOk = _session.sendMessage(d, packet);
|
||||
if (!replySentOk) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Error sending reply to " + d.calculateHash().toBase64()
|
||||
+ " in response to a new con message for socket " + s,
|
||||
new Exception("Failed creation"));
|
||||
s.internalClose();
|
||||
}
|
||||
} else {
|
||||
// timed out or serverSocket closed
|
||||
byte[] packet = toBytes(" " + id);
|
||||
packet[0] = CLOSE_OUT;
|
||||
boolean nackSent = session.sendMessage(d, packet);
|
||||
if (!nackSent) {
|
||||
_log.warn("Error sending NACK for session creation for socket " + s);
|
||||
}
|
||||
s.internalClose();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received a disconnect for a socket we didn't initiate, so kill
|
||||
* the socket.
|
||||
*
|
||||
*/
|
||||
private void disconnectIncoming(String id, byte payload[]) {
|
||||
I2PSocketImpl s = null;
|
||||
synchronized (lock) {
|
||||
s = (I2PSocketImpl) _inSockets.get(id);
|
||||
if (payload.length == 0 && s != null) {
|
||||
_inSockets.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
_log.debug("*Disconnect incoming for socket " + s);
|
||||
|
||||
try {
|
||||
if (payload.length == 0 && s != null) {
|
||||
s.internalClose();
|
||||
return;
|
||||
} else {
|
||||
if ( (payload.length > 0) && (_log.shouldLog(Log.ERROR)) )
|
||||
_log.error("Disconnect packet had " + payload.length + " bytes");
|
||||
if (s != null)
|
||||
s.internalClose();
|
||||
return;
|
||||
}
|
||||
} catch (Exception t) {
|
||||
_log.error("Ignoring error on disconnect", t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We've received data on a stream we received - toss the data onto
|
||||
* the socket for handling.
|
||||
*
|
||||
* @throws IllegalStateException if the socket isn't open or isn't known
|
||||
*/
|
||||
private void sendIncoming(String id, byte payload[]) {
|
||||
I2PSocketImpl s = null;
|
||||
synchronized (lock) {
|
||||
s = (I2PSocketImpl) _inSockets.get(id);
|
||||
}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("*Packet send incoming [" + payload.length + "] for socket " + s);
|
||||
|
||||
if (s != null) {
|
||||
s.queueData(payload);
|
||||
return;
|
||||
} else {
|
||||
_log.info("Null socket with data available");
|
||||
throw new IllegalStateException("Null socket with data available");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unknown packet. moo.
|
||||
*
|
||||
*/
|
||||
private void handleUnknown(int type, String id, byte payload[]) {
|
||||
_log.error("\n\n=============== Unknown packet! " + "============"
|
||||
+ "\nType: " + (int) type
|
||||
+ "\nID: " + getReadableForm(id)
|
||||
+ "\nBase64'ed Data: " + Base64.encode(payload)
|
||||
+ "\n\n\n");
|
||||
if (id != null) {
|
||||
synchronized (lock) {
|
||||
_inSockets.remove(id);
|
||||
_outSockets.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void reportAbuse(I2PSession session, int severity) {
|
||||
_log.error("Abuse reported [" + severity + "]");
|
||||
}
|
||||
@ -258,59 +405,77 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
* @throws InterruptedIOException if the connection timeouts
|
||||
* @throws I2PException if there is some other I2P-related problem
|
||||
*/
|
||||
public I2PSocket connect(Destination peer, I2PSocketOptions options) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
|
||||
|
||||
public I2PSocket connect(Destination peer, I2PSocketOptions options)
|
||||
throws I2PException, ConnectException,
|
||||
NoRouteToHostException, InterruptedIOException {
|
||||
String localID, lcID;
|
||||
I2PSocketImpl s;
|
||||
synchronized (lock) {
|
||||
localID = makeID(_outSockets);
|
||||
lcID = getReadableForm(localID);
|
||||
s = new I2PSocketImpl(peer, this, true, localID);
|
||||
_outSockets.put(s.getLocalID(), s);
|
||||
_outSockets.put(localID, s);
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream pubkey = new ByteArrayOutputStream();
|
||||
_session.getMyDestination().writeBytes(pubkey);
|
||||
String remoteID;
|
||||
byte[] packet = makePacket((byte) 0xA1, localID, pubkey.toByteArray());
|
||||
byte[] packet = makePacket((byte) SYN, localID, pubkey.toByteArray());
|
||||
boolean sent = false;
|
||||
synchronized (_session) {
|
||||
sent = _session.sendMessage(peer, packet);
|
||||
}
|
||||
sent = _session.sendMessage(peer, packet);
|
||||
if (!sent) {
|
||||
_log.info("Unable to send & receive ack for SYN packet");
|
||||
_log.info("Unable to send & receive ack for SYN packet for socket " + s);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
throw new I2PException("Error sending through I2P network");
|
||||
}
|
||||
remoteID = s.getRemoteID(true, options.getConnectTimeout());
|
||||
if (remoteID == null) { throw new ConnectException("Connection refused by peer"); }
|
||||
if ("".equals(remoteID)) { throw new NoRouteToHostException("Unable to reach peer"); }
|
||||
_log.debug("TIMING: s given out for remoteID " + getReadableForm(remoteID));
|
||||
|
||||
if (remoteID == null)
|
||||
throw new ConnectException("Connection refused by peer for socket " + s);
|
||||
if ("".equals(remoteID))
|
||||
throw new NoRouteToHostException("Unable to reach peer for socket " + s);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("TIMING: s given out for remoteID "
|
||||
+ getReadableForm(remoteID) + " for socket " + s);
|
||||
|
||||
return s;
|
||||
} catch (InterruptedIOException ioe) {
|
||||
_log.error("Timeout waiting for ack from syn for id " + getReadableForm(lcID), ioe);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Timeout waiting for ack from syn for id "
|
||||
+ getReadableForm(lcID) + " for socket " + s, ioe);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
s.internalClose();
|
||||
throw new InterruptedIOException("Timeout waiting for ack");
|
||||
} catch (ConnectException ex) {
|
||||
s.internalClose();
|
||||
throw ex;
|
||||
} catch (NoRouteToHostException ex) {
|
||||
s.internalClose();
|
||||
throw ex;
|
||||
} catch (IOException ex) {
|
||||
_log.error("Error sending syn on id " + getReadableForm(lcID), ex);
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("Error sending syn on id " + getReadableForm(lcID) + " for socket " + s, ex);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
s.internalClose();
|
||||
throw new I2PException("Unhandled IOException occurred");
|
||||
} catch (I2PException ex) {
|
||||
_log.info("Error sending syn on id " + getReadableForm(lcID), ex);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Error sending syn on id " + getReadableForm(lcID) + " for socket " + s, ex);
|
||||
synchronized (lock) {
|
||||
_outSockets.remove(s.getLocalID());
|
||||
}
|
||||
s.internalClose();
|
||||
throw ex;
|
||||
} catch (Exception e) {
|
||||
s.internalClose();
|
||||
_log.error("Unhandled error connecting", e);
|
||||
throw new ConnectException("Unhandled error connecting: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,7 +489,8 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
* @throws InterruptedIOException if the connection timeouts
|
||||
* @throws I2PException if there is some other I2P-related problem
|
||||
*/
|
||||
public I2PSocket connect(Destination peer) throws I2PException, ConnectException, NoRouteToHostException, InterruptedIOException {
|
||||
public I2PSocket connect(Destination peer) throws I2PException, ConnectException,
|
||||
NoRouteToHostException, InterruptedIOException {
|
||||
return connect(peer, null);
|
||||
}
|
||||
|
||||
@ -334,14 +500,9 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
*
|
||||
*/
|
||||
public void destroySocketManager() {
|
||||
|
||||
try {
|
||||
if (_serverSocket != null) {
|
||||
_serverSocket.close();
|
||||
_serverSocket = null;
|
||||
}
|
||||
} catch (I2PException ex) {
|
||||
_log.error("Error closing I2PServerSocket", ex);
|
||||
if (_serverSocket != null) {
|
||||
_serverSocket.close();
|
||||
_serverSocket = null;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
@ -353,8 +514,9 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
while (iter.hasNext()) {
|
||||
id = (String)iter.next();
|
||||
sock = (I2PSocketImpl)_inSockets.get(id);
|
||||
_log.debug("Closing inSocket \""
|
||||
+ getReadableForm(sock.getLocalID()) + "\"");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Closing inSocket \""
|
||||
+ getReadableForm(sock.getLocalID()) + "\"");
|
||||
sock.internalClose();
|
||||
}
|
||||
|
||||
@ -362,8 +524,9 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
while (iter.hasNext()) {
|
||||
id = (String)iter.next();
|
||||
sock = (I2PSocketImpl)_outSockets.get(id);
|
||||
_log.debug("Closing outSocket \""
|
||||
+ getReadableForm(sock.getLocalID()) + "\"");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Closing outSocket \""
|
||||
+ getReadableForm(sock.getLocalID()) + "\"");
|
||||
sock.internalClose();
|
||||
}
|
||||
}
|
||||
@ -406,7 +569,7 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
*/
|
||||
public boolean ping(Destination peer, long timeoutMs) {
|
||||
try {
|
||||
return _session.sendMessage(peer, new byte[] { (byte) 0xFF});
|
||||
return _session.sendMessage(peer, new byte[] { (byte) CHAFF});
|
||||
} catch (I2PException ex) {
|
||||
_log.error("I2PException:", ex);
|
||||
return false;
|
||||
@ -415,8 +578,8 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
|
||||
public void removeSocket(I2PSocketImpl sock) {
|
||||
synchronized (lock) {
|
||||
_log.debug("Removing socket \""
|
||||
+ getReadableForm(sock.getLocalID()) + "\"");
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Removing socket \"" + getReadableForm(sock.getLocalID()) + "\" [" + sock + "]");
|
||||
_inSockets.remove(sock.getLocalID());
|
||||
_outSockets.remove(sock.getLocalID());
|
||||
lock.notify();
|
||||
@ -424,14 +587,9 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
}
|
||||
|
||||
public static String getReadableForm(String id) {
|
||||
try {
|
||||
if (id == null) return "(null)";
|
||||
if (id.length() != 3) return "Bogus";
|
||||
return Base64.encode(id.getBytes("ISO-8859-1"));
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
if (id == null) return "(null)";
|
||||
if (id.length() != 3) return "Bogus";
|
||||
return Base64.encode(toBytes(id));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -439,22 +597,17 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
*
|
||||
* @param uniqueIn map of already known local IDs so we don't collide. WARNING - NOT THREADSAFE!
|
||||
*/
|
||||
public static String makeID(HashMap uniqueIn) {
|
||||
private static String makeID(HashMap uniqueIn) {
|
||||
String newID;
|
||||
try {
|
||||
do {
|
||||
int id = (int) (Math.random() * 16777215 + 1);
|
||||
byte[] nid = new byte[3];
|
||||
nid[0] = (byte) (id / 65536);
|
||||
nid[1] = (byte) ((id / 256) % 256);
|
||||
nid[2] = (byte) (id % 256);
|
||||
newID = new String(nid, "ISO-8859-1");
|
||||
} while (uniqueIn.get(newID) != null);
|
||||
return newID;
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
do {
|
||||
int id = (int) (Math.random() * 16777215 + 1);
|
||||
byte[] nid = new byte[3];
|
||||
nid[0] = (byte) (id / 65536);
|
||||
nid[1] = (byte) ((id / 256) % 256);
|
||||
nid[2] = (byte) (id % 256);
|
||||
newID = toString(nid);
|
||||
} while (uniqueIn.get(newID) != null);
|
||||
return newID;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -462,17 +615,28 @@ public class I2PSocketManager implements I2PSessionListener {
|
||||
* the given payload
|
||||
*/
|
||||
public static byte[] makePacket(byte type, String id, byte[] payload) {
|
||||
byte[] packet = new byte[payload.length + 4];
|
||||
packet[0] = type;
|
||||
byte[] temp = toBytes(id);
|
||||
if (temp.length != 3) throw new RuntimeException("Incorrect ID length: " + temp.length);
|
||||
System.arraycopy(temp, 0, packet, 1, 3);
|
||||
System.arraycopy(payload, 0, packet, 4, payload.length);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static final String toString(byte data[]) {
|
||||
try {
|
||||
byte[] packet = new byte[payload.length + 4];
|
||||
packet[0] = type;
|
||||
byte[] temp = id.getBytes("ISO-8859-1");
|
||||
if (temp.length != 3) throw new RuntimeException("Incorrect ID length: " + temp.length);
|
||||
System.arraycopy(temp, 0, packet, 1, 3);
|
||||
System.arraycopy(payload, 0, packet, 4, payload.length);
|
||||
return packet;
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
if (_log.shouldLog(Log.ERROR)) _log.error("Error building the packet", ex);
|
||||
return new byte[0];
|
||||
return new String(data, "ISO-8859-1");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new RuntimeException("WTF! iso-8859-1 isn't supported?");
|
||||
}
|
||||
}
|
||||
|
||||
private static final byte[] toBytes(String str) {
|
||||
try {
|
||||
return str.getBytes("ISO-8859-1");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new RuntimeException("WTF! iso-8859-1 isn't supported?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package net.i2p.client.streaming;
|
||||
|
||||
/**
|
||||
* Define the configuration for streaming and verifying data on the socket.
|
||||
* No options available...
|
||||
*
|
||||
*/
|
||||
public class I2PSocketOptions {
|
||||
@ -21,7 +20,11 @@ public class I2PSocketOptions {
|
||||
return _connectTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define how long we will wait for the ACK from a SYN, in milliseconds.
|
||||
*
|
||||
*/
|
||||
public void setConnectTimeout(long ms) {
|
||||
_connectTimeout = ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
package net.i2p.netmonitor;
|
||||
|
||||
import net.i2p.data.RouterInfo;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.Clock;
|
||||
import java.util.Properties;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Locale;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.data.RouterInfo;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Pull out important data from the published routerInfo and stash it away
|
||||
|
@ -1,24 +1,24 @@
|
||||
package net.i2p.netmonitor;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PThread;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Main driver for the app that harvests data about the performance of the network,
|
||||
* building summaries for each peer that change over time. <p />
|
||||
*
|
||||
* Usage: <code>NetMonitor [configFilename]</code> <p />
|
||||
* Usage: <code>NetMonitor [configFilename] [--routers filename[,filename]*]</code> <p />
|
||||
*
|
||||
*
|
||||
*
|
||||
@ -41,15 +41,20 @@ public class NetMonitor {
|
||||
private int _exportDelay;
|
||||
private String _exportDir;
|
||||
private String _netDbDir;
|
||||
private String _explicitRouters;
|
||||
private int _summaryDurationHours;
|
||||
private boolean _isRunning;
|
||||
private Map _peerSummaries;
|
||||
|
||||
public NetMonitor() {
|
||||
this(CONFIG_LOCATION_DEFAULT);
|
||||
this(CONFIG_LOCATION_DEFAULT, null);
|
||||
}
|
||||
public NetMonitor(String configLocation) {
|
||||
this(configLocation, null);
|
||||
}
|
||||
public NetMonitor(String configLocation, String explicitFilenames) {
|
||||
_configLocation = configLocation;
|
||||
_explicitRouters = explicitFilenames;
|
||||
_peerSummaries = new HashMap(32);
|
||||
loadConfig();
|
||||
}
|
||||
@ -120,6 +125,8 @@ public class NetMonitor {
|
||||
public int getSummaryDurationHours() { return _summaryDurationHours; }
|
||||
/** where should we read the data from? */
|
||||
public String getNetDbDir() { return _netDbDir; }
|
||||
/** if specified, contains a set of filenames we want to harvest routerInfo data from */
|
||||
public String getExplicitRouters() { return _explicitRouters; }
|
||||
/**
|
||||
* what peers are we keeping track of?
|
||||
*
|
||||
@ -203,10 +210,30 @@ public class NetMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* main driver for the netMonitor. the usage is:
|
||||
* <code>NetMonitor [configFilename] [--routers filename[,filename]*]</code>
|
||||
*/
|
||||
public static final void main(String args[]) {
|
||||
if (args.length == 1)
|
||||
new NetMonitor(args[0]).startMonitor();
|
||||
else
|
||||
new NetMonitor(CONFIG_LOCATION_DEFAULT).startMonitor();
|
||||
String cfgLocation = CONFIG_LOCATION_DEFAULT;
|
||||
String explicitFilenames = null;
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
cfgLocation = args[0];
|
||||
break;
|
||||
case 2:
|
||||
explicitFilenames = args[1];
|
||||
break;
|
||||
case 3:
|
||||
cfgLocation = args[0];
|
||||
explicitFilenames = args[2];
|
||||
break;
|
||||
default:
|
||||
System.err.println("Usage: NetMonitor [configFilename] [--routers filename[,filename]*]");
|
||||
return;
|
||||
}
|
||||
new NetMonitor(cfgLocation, explicitFilenames).startMonitor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
package net.i2p.netmonitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.RouterInfo;
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Active process that drives the monitoring by periodically rading the
|
||||
@ -130,12 +129,35 @@ class NetMonitorRunner implements Runnable {
|
||||
* @return list of File objects pointing at the routers around
|
||||
*/
|
||||
private File[] listRouters() {
|
||||
File dbDir = new File(_monitor.getNetDbDir());
|
||||
File files[] = dbDir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File f, String name) {
|
||||
return name.startsWith("routerInfo-");
|
||||
}
|
||||
});
|
||||
if (_monitor.getExplicitRouters() != null) {
|
||||
return listRoutersExplicit();
|
||||
} else {
|
||||
File dbDir = new File(_monitor.getNetDbDir());
|
||||
File files[] = dbDir.listFiles(new FilenameFilter() {
|
||||
public boolean accept(File f, String name) {
|
||||
return name.startsWith("routerInfo-");
|
||||
}
|
||||
});
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of router files that were explicitly specified by the netMonitor
|
||||
*
|
||||
*/
|
||||
private File[] listRoutersExplicit() {
|
||||
StringTokenizer tok = new StringTokenizer(_monitor.getExplicitRouters().trim(), ",");
|
||||
List rv = new ArrayList();
|
||||
while (tok.hasMoreTokens()) {
|
||||
String name = tok.nextToken();
|
||||
File cur = new File(name);
|
||||
if (cur.exists())
|
||||
rv.add(cur);
|
||||
}
|
||||
File files[] = new File[rv.size()];
|
||||
for (int i = 0; i < rv.size(); i++)
|
||||
files[i] = (File)rv.get(i);
|
||||
return files;
|
||||
}
|
||||
|
||||
@ -148,4 +170,4 @@ class NetMonitorRunner implements Runnable {
|
||||
Thread.sleep(_monitor.getHarvestDelay());
|
||||
} catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package net.i2p.netmonitor;
|
||||
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.i2p.util.Clock;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* coordinate the data points summarizing the performance of a particular peer
|
||||
|
@ -1,20 +1,17 @@
|
||||
package net.i2p.netmonitor;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Set;
|
||||
import java.util.Locale;
|
||||
import java.util.Date;
|
||||
import java.util.StringTokenizer;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Load up the peer summary
|
||||
@ -33,57 +30,61 @@ class PeerSummaryReader {
|
||||
PeerSummary summary = null;
|
||||
String curDescription = null;
|
||||
List curArgs = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("peer\t")) {
|
||||
String name = line.substring("peer\t".length()).trim();
|
||||
summary = monitor.getSummary(name);
|
||||
if (summary == null)
|
||||
summary = new PeerSummary(name);
|
||||
} else if (line.startsWith("## ")) {
|
||||
curDescription = line.substring("## ".length()).trim();
|
||||
curArgs = new ArrayList(4);
|
||||
} else if (line.startsWith("# param ")) {
|
||||
int start = line.indexOf(':');
|
||||
String arg = line.substring(start+1).trim();
|
||||
curArgs.add(arg);
|
||||
} else {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
String name = tok.nextToken();
|
||||
try {
|
||||
long when = getTime(tok.nextToken());
|
||||
boolean isDouble = false;
|
||||
List argVals = new ArrayList(curArgs.size());
|
||||
while (tok.hasMoreTokens()) {
|
||||
String val = (String)tok.nextToken();
|
||||
if (val.indexOf('.') >= 0) {
|
||||
argVals.add(new Double(val));
|
||||
isDouble = true;
|
||||
} else {
|
||||
argVals.add(new Long(val));
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("peer\t")) {
|
||||
String name = line.substring("peer\t".length()).trim();
|
||||
summary = monitor.getSummary(name);
|
||||
if (summary == null)
|
||||
summary = new PeerSummary(name);
|
||||
} else if (line.startsWith("## ")) {
|
||||
curDescription = line.substring("## ".length()).trim();
|
||||
curArgs = new ArrayList(4);
|
||||
} else if (line.startsWith("# param ")) {
|
||||
int start = line.indexOf(':');
|
||||
String arg = line.substring(start+1).trim();
|
||||
curArgs.add(arg);
|
||||
} else {
|
||||
StringTokenizer tok = new StringTokenizer(line);
|
||||
String name = tok.nextToken();
|
||||
try {
|
||||
long when = getTime(tok.nextToken());
|
||||
boolean isDouble = false;
|
||||
List argVals = new ArrayList(curArgs.size());
|
||||
while (tok.hasMoreTokens()) {
|
||||
String val = (String)tok.nextToken();
|
||||
if (val.indexOf('.') >= 0) {
|
||||
argVals.add(new Double(val));
|
||||
isDouble = true;
|
||||
} else {
|
||||
argVals.add(new Long(val));
|
||||
}
|
||||
}
|
||||
String valDescriptions[] = new String[curArgs.size()];
|
||||
for (int i = 0; i < curArgs.size(); i++)
|
||||
valDescriptions[i] = (String)curArgs.get(i);
|
||||
if (isDouble) {
|
||||
double values[] = new double[argVals.size()];
|
||||
for (int i = 0; i < argVals.size(); i++)
|
||||
values[i] = ((Double)argVals.get(i)).doubleValue();
|
||||
summary.addData(name, curDescription, valDescriptions, when, values);
|
||||
} else {
|
||||
long values[] = new long[argVals.size()];
|
||||
for (int i = 0; i < argVals.size(); i++)
|
||||
values[i] = ((Long)argVals.get(i)).longValue();
|
||||
summary.addData(name, curDescription, valDescriptions, when, values);
|
||||
}
|
||||
} catch (ParseException pe) {
|
||||
_log.error("Error parsing the data line [" + line + "]", pe);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Error parsing the data line [" + line + "]", nfe);
|
||||
}
|
||||
String valDescriptions[] = new String[curArgs.size()];
|
||||
for (int i = 0; i < curArgs.size(); i++)
|
||||
valDescriptions[i] = (String)curArgs.get(i);
|
||||
if (isDouble) {
|
||||
double values[] = new double[argVals.size()];
|
||||
for (int i = 0; i < argVals.size(); i++)
|
||||
values[i] = ((Double)argVals.get(i)).doubleValue();
|
||||
summary.addData(name, curDescription, valDescriptions, when, values);
|
||||
} else {
|
||||
long values[] = new long[argVals.size()];
|
||||
for (int i = 0; i < argVals.size(); i++)
|
||||
values[i] = ((Long)argVals.get(i)).longValue();
|
||||
summary.addData(name, curDescription, valDescriptions, when, values);
|
||||
}
|
||||
} catch (ParseException pe) {
|
||||
_log.error("Error parsing the data line [" + line + "]", pe);
|
||||
} catch (NumberFormatException nfe) {
|
||||
_log.error("Error parsing the data line [" + line + "]", nfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
_log.error("Error handling the data", e);
|
||||
throw new IOException("Error parsing the data");
|
||||
}
|
||||
if (summary == null)
|
||||
return;
|
||||
summary.coallesceData(monitor.getSummaryDurationHours() * 60*60*1000);
|
||||
|
@ -1,15 +1,15 @@
|
||||
package net.i2p.netmonitor;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.TreeSet;
|
||||
import java.util.Set;
|
||||
import java.util.Locale;
|
||||
import java.util.Date;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Dump various peer summaries to disk (so external apps (or good ol' vi) can
|
||||
|
@ -1,14 +1,15 @@
|
||||
package net.i2p.netmonitor;
|
||||
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import java.io.IOException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Load up the StatGroups from the location specified to configure the data harvester.
|
||||
* The stat groups are formatted in a simple properties file style, e.g.: <pre>
|
||||
|
@ -1,28 +1,24 @@
|
||||
package net.i2p.netmonitor.gui;
|
||||
|
||||
import net.i2p.netmonitor.PeerSummary;
|
||||
import net.i2p.netmonitor.PeerStat;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import org.jfree.data.XYSeries;
|
||||
import org.jfree.data.XYSeriesCollection;
|
||||
import org.jfree.data.MovingAverage;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.renderer.XYLineAndShapeRenderer;
|
||||
import org.jfree.chart.renderer.XYItemRenderer;
|
||||
import org.jfree.chart.renderer.XYDotRenderer;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.Font;
|
||||
import java.awt.Color;
|
||||
import org.jfree.chart.ChartPanel;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.axis.DateAxis;
|
||||
import org.jfree.chart.axis.NumberAxis;
|
||||
import org.jfree.chart.plot.Plot;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.jfree.chart.renderer.XYItemRenderer;
|
||||
import org.jfree.chart.renderer.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.XYSeries;
|
||||
import org.jfree.data.XYSeriesCollection;
|
||||
|
||||
import net.i2p.netmonitor.PeerStat;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class JFreeChartAdapter {
|
||||
private final static Log _log = new Log(JFreeChartAdapter.class);
|
||||
|
@ -1,20 +1,15 @@
|
||||
package net.i2p.netmonitor.gui;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import org.jfree.chart.ChartPanel;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Render the graph and legend
|
||||
*
|
||||
|
@ -1,14 +1,13 @@
|
||||
package net.i2p.netmonitor.gui;
|
||||
|
||||
import net.i2p.netmonitor.NetMonitor;
|
||||
import net.i2p.netmonitor.PeerSummary;
|
||||
import net.i2p.netmonitor.PeerStat;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.I2PThread;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.i2p.netmonitor.NetMonitor;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Coordinate the visualization of the network monitor. <p />
|
||||
|
@ -5,7 +5,6 @@ import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
|
@ -1,9 +1,5 @@
|
||||
package net.i2p.netmonitor.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextArea;
|
||||
|
||||
|
@ -1,20 +1,15 @@
|
||||
package net.i2p.netmonitor.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.netmonitor.PeerSummary;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Configure how we want to render a particular peerSummary in the GUI
|
||||
|
@ -5,25 +5,21 @@ import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.TreeMap;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.netmonitor.PeerStat;
|
||||
import net.i2p.netmonitor.PeerSummary;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
class PeerPlotConfigPane extends JPanel implements PeerPlotConfig.UpdateListener {
|
||||
private final static Log _log = new Log(PeerPlotConfigPane.class);
|
||||
|
27
apps/sam/c/LICENSE
Normal file
27
apps/sam/c/LICENSE
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of any contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
65
apps/sam/c/Makefile.cygwin
Normal file
65
apps/sam/c/Makefile.cygwin
Normal file
@ -0,0 +1,65 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and should work on Cygwin
|
||||
#
|
||||
|
||||
#
|
||||
# Your operating system
|
||||
#
|
||||
|
||||
OS = CYGWIN
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
INCDIR = inc
|
||||
LIBDIR = lib
|
||||
OBJDIR = obj
|
||||
SRCDIR = src
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
AR = ar
|
||||
CC = gcc
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -march=i486 -O2 -pipe -std=c99 -Wall
|
||||
CFLAGS += -DOS=$(OS)
|
||||
CFLAGS += -I$(INCDIR)
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
|
||||
OBJS = $(OBJDIR)/sam.o \
|
||||
$(OBJDIR)/snprintf.o \
|
||||
$(OBJDIR)/strl.o
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: depend libsam
|
||||
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCDIR)/*.c > .depend
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
libsam: $(OBJS)
|
||||
$(AR) rcs $(LIBDIR)/libsam.a $(OBJS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f $(LIBDIR)/libsam.a $(OBJDIR)/* .depend
|
||||
|
||||
tidy: clean
|
64
apps/sam/c/Makefile.linux
Normal file
64
apps/sam/c/Makefile.linux
Normal file
@ -0,0 +1,64 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and should work on Linux (generic)
|
||||
#
|
||||
|
||||
#
|
||||
# Your operating system
|
||||
#
|
||||
|
||||
OS = LINUX
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
INCDIR = inc
|
||||
LIBDIR = lib
|
||||
OBJDIR = obj
|
||||
SRCDIR = src
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
AR = ar
|
||||
CC = gcc
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -O2 -pipe -std=c99 -Wall
|
||||
CFLAGS += -DOS=$(OS)
|
||||
CFLAGS += -I$(INCDIR)
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
|
||||
OBJS = $(OBJDIR)/sam.o \
|
||||
$(OBJDIR)/strl.o
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: depend libsam
|
||||
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCDIR)/*.c > .depend
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
libsam: $(OBJS)
|
||||
$(AR) rcs $(LIBDIR)/libsam.a $(OBJS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f $(LIBDIR)/libsam.a $(OBJDIR)/* .depend
|
||||
|
||||
tidy: clean
|
64
apps/sam/c/Makefile.mingw
Normal file
64
apps/sam/c/Makefile.mingw
Normal file
@ -0,0 +1,64 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and should work on Windows (MingW)
|
||||
#
|
||||
|
||||
#
|
||||
# Your operating system
|
||||
#
|
||||
|
||||
OS = MINGW
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
|
||||
INCDIR = inc
|
||||
LIBDIR = lib
|
||||
OBJDIR = obj
|
||||
SRCDIR = src
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
AR = C:\Dev-Cpp\bin\ar
|
||||
CC = C:\Dev-Cpp\bin\gcc
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -march=i486 -O2 -pipe -std=c99 -Wall
|
||||
CFLAGS += -DOS=$(OS)
|
||||
CFLAGS += -I$(INCDIR)
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
|
||||
OBJS = $(OBJDIR)/sam.o \
|
||||
$(OBJDIR)/strl.o
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: depend libsam
|
||||
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCDIR)/*.c > .depend
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
libsam: $(OBJS)
|
||||
$(AR) rcs $(LIBDIR)/libsam.a $(OBJS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f $(LIBDIR)/libsam.a $(OBJDIR)/* .depend
|
||||
|
||||
tidy: clean
|
7
apps/sam/c/doc/donate.txt
Normal file
7
apps/sam/c/doc/donate.txt
Normal file
@ -0,0 +1,7 @@
|
||||
If you would like to make a donation to the author of this library, you can use
|
||||
the following methods:
|
||||
|
||||
* E-Gold account number 1043280
|
||||
* Paypal email mpc@innographx.com
|
||||
|
||||
If you want to use some other method, just ask.
|
27
apps/sam/c/doc/license.txt
Normal file
27
apps/sam/c/doc/license.txt
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of any contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
9
apps/sam/c/doc/todo.txt
Normal file
9
apps/sam/c/doc/todo.txt
Normal file
@ -0,0 +1,9 @@
|
||||
I need to do these things:
|
||||
|
||||
* SAM raw support
|
||||
* Write an instruction manual
|
||||
|
||||
Anyone can help with these things:
|
||||
|
||||
* Fix the example dgram-client.c
|
||||
* Compile on as many platforms as possible
|
27
apps/sam/c/doc/whatsnew.txt
Normal file
27
apps/sam/c/doc/whatsnew.txt
Normal file
@ -0,0 +1,27 @@
|
||||
v1.15 2004-06-23
|
||||
* Added a new example program, warhammer-dgram (use with caution)
|
||||
* Fixed some fatal bugs in datagram handling
|
||||
* Added another error return type named SAM_TOO_BIG - some functions now
|
||||
return samerr_t instead of bool
|
||||
|
||||
v1.10 2004-06-16
|
||||
* Changed sam_strerror() to work the same as the standard library strerror()
|
||||
* Ported to native MS Windows (uses the Mingw development environment)
|
||||
* Fixed a probable bug in the Cygwin port
|
||||
|
||||
v1.05 2004-06-09
|
||||
* Added an example datagram client/server program in the examples directory
|
||||
* sam_read_buffer() now returns bool true if it read anything
|
||||
* Added repliable datagram support - sam_connect() now has another argument
|
||||
* Replaced strstr() with the more appropriate strncmp() in many places
|
||||
* Fixed a parsing error for STREAM CLOSED
|
||||
* Removed the old sam_naming_lookup() and renamed sam_naming_lookup_async()
|
||||
to sam_naming_lookup() to replace it
|
||||
* Fixed a bug in sam_stream_close() where a '\n' was not being sent after
|
||||
the SAM command
|
||||
* Fixed a bug where the stream ID was being improperly incremented in
|
||||
sam_stream_connect()
|
||||
* Added generic Linux Makefile for non-Debian distributions
|
||||
|
||||
v1.00 2004-06-02
|
||||
* First public release
|
42
apps/sam/c/examples/Makefile
Normal file
42
apps/sam/c/examples/Makefile
Normal file
@ -0,0 +1,42 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make
|
||||
#
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
CC = gcc
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -O2 -pipe -std=c99 -Wall
|
||||
CFLAGS += -I../inc -L../lib
|
||||
LIBS = -lsam
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: dgram-client dgram-server warhammer-dgram
|
||||
|
||||
dgram-client:
|
||||
$(CC) $(CFLAGS) -o dgram-client.o -c dgram-client.c
|
||||
$(CC) $(CFLAGS) -o dgram-client dgram-client.o $(LIBS)
|
||||
|
||||
dgram-server:
|
||||
$(CC) $(CFLAGS) -o dgram-server.o -c dgram-server.c
|
||||
$(CC) $(CFLAGS) -o dgram-server dgram-server.o $(LIBS)
|
||||
|
||||
warhammer-dgram:
|
||||
$(CC) $(CFLAGS) -o warhammer-dgram.o -c warhammer-dgram.c
|
||||
$(CC) $(CFLAGS) -o warhammer-dgram warhammer-dgram.o $(LIBS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f *.o *.exe dgram-client dgram-server warhammer-dgram
|
42
apps/sam/c/examples/Makefile.mingw
Normal file
42
apps/sam/c/examples/Makefile.mingw
Normal file
@ -0,0 +1,42 @@
|
||||
#
|
||||
# This Makefile is compatible with GNU Make and has Winsock linking
|
||||
#
|
||||
|
||||
#
|
||||
# Programs
|
||||
#
|
||||
|
||||
CC = C:\Dev-Cpp\bin\gcc
|
||||
|
||||
#
|
||||
# Flags
|
||||
#
|
||||
|
||||
CFLAGS = -g -O2 -pipe -std=c99 -Wall
|
||||
CFLAGS += -I../inc -L../lib
|
||||
LIBS = -lsam -lwsock32
|
||||
|
||||
#
|
||||
# Build rules
|
||||
#
|
||||
|
||||
all: dgram-client dgram-server warhammer-dgram
|
||||
|
||||
dgram-client:
|
||||
$(CC) $(CFLAGS) -o dgram-client.o -c dgram-client.c
|
||||
$(CC) $(CFLAGS) -o dgram-client dgram-client.o $(LIBS)
|
||||
|
||||
dgram-server:
|
||||
$(CC) $(CFLAGS) -o dgram-server.o -c dgram-server.c
|
||||
$(CC) $(CFLAGS) -o dgram-server dgram-server.o $(LIBS)
|
||||
|
||||
warhammer-dgram:
|
||||
$(CC) $(CFLAGS) -o warhammer-dgram.o -c warhammer-dgram.c
|
||||
$(CC) $(CFLAGS) -o warhammer-dgram warhammer-dgram.o $(LIBS)
|
||||
|
||||
#
|
||||
# Cleanup rules
|
||||
#
|
||||
|
||||
clean:
|
||||
-rm -f *.o *.exe dgram-client dgram-server warhammer-dgram
|
130
apps/sam/c/examples/dgram-client.c
Normal file
130
apps/sam/c/examples/dgram-client.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sam.h"
|
||||
|
||||
static void dgramback(sam_pubkey_t dest, void *data, size_t size);
|
||||
static void diedback(void);
|
||||
static void logback(char *s);
|
||||
static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result);
|
||||
|
||||
/*
|
||||
* This is an extremely simple echo client which shows you how LibSAM
|
||||
* datagrams work. We lookup the name 'dgram-server' then send some data to
|
||||
* him. If everything works, we should get the same data back.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE!!!!!!!! This is currently broken!
|
||||
*/
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
samerr_t rc;
|
||||
|
||||
/* Hook up the callback functions */
|
||||
sam_dgramback = &dgramback;
|
||||
sam_diedback = &diedback;
|
||||
sam_logback = &logback;
|
||||
sam_namingback = &namingback;
|
||||
|
||||
/* Connect to the SAM server -- you can use either an IP or DNS name */
|
||||
rc = sam_connect("localhost", 7656, "dgram-client", SAM_DGRAM, 0);
|
||||
if (rc != SAM_OK) {
|
||||
fprintf(stderr, "SAM connection failed: %s\n", sam_strerror(rc));
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* This is equivalent to doing a DNS lookup on the normal internet. Note
|
||||
* that the dgram-server must already be running for this to work.
|
||||
* When the lookup completes, we send them some data (see namingback()).
|
||||
*/
|
||||
sam_naming_lookup("dgram-server");
|
||||
|
||||
/*
|
||||
* Wait for something to happen, then invoke the appropriate callback
|
||||
*/
|
||||
while (true)
|
||||
sam_read_buffer();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we receive some data, print it out to the screen
|
||||
*/
|
||||
static void dgramback(sam_pubkey_t dest, void *data, size_t size)
|
||||
{
|
||||
printf("Datagram received: %s\n", (char *)data);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called whenever the SAM connection fails (like if the I2P router is
|
||||
* shut down)
|
||||
*/
|
||||
static void diedback(void)
|
||||
{
|
||||
fprintf(stderr, "Lost SAM connection!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The logging callback prints any logging messages from LibSAM
|
||||
*/
|
||||
static void logback(char *s)
|
||||
{
|
||||
fprintf(stderr, "LibSAM: %s\n", s);
|
||||
}
|
||||
|
||||
/*
|
||||
* When a name is resolved, send data to that destination address
|
||||
*/
|
||||
static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result)
|
||||
{
|
||||
char *data = "Hello, invisible world!";
|
||||
|
||||
printf("I got %s's base 64 destination, so now I will send him some " \
|
||||
"data...\n", name);
|
||||
sam_dgram_send(pubkey, data, strlen(data));
|
||||
/*
|
||||
* ^^^ An extra NUL is appended to the data by LibSAM, so it is not
|
||||
* necessary to send trailing NULs over the wire for strings. This doesn't
|
||||
* cause problems with binary data, because the NUL isn't included in `size'
|
||||
* in sam_dgramback().
|
||||
* That is why we use strlen(data) instead of strlen(data) + 1.
|
||||
*/
|
||||
puts("Datagram sent");
|
||||
}
|
108
apps/sam/c/examples/dgram-server.c
Normal file
108
apps/sam/c/examples/dgram-server.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "sam.h"
|
||||
|
||||
static void dgramback(sam_pubkey_t dest, void *data, size_t size);
|
||||
static void diedback(void);
|
||||
static void logback(char *s);
|
||||
static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result);
|
||||
|
||||
/*
|
||||
* This is an extremely simple echo server which shows you how LibSAM
|
||||
* datagrams work. We echo back every datagram that is sent to us.
|
||||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
samerr_t rc;
|
||||
|
||||
/* Hook up the callback functions */
|
||||
sam_dgramback = &dgramback;
|
||||
sam_diedback = &diedback;
|
||||
sam_logback = &logback;
|
||||
sam_namingback = &namingback;
|
||||
|
||||
/* Connect to the SAM server -- you can use either an IP or DNS name */
|
||||
rc = sam_connect("127.0.0.1", 7656, "dgram-server", SAM_DGRAM, 0);
|
||||
if (rc != SAM_OK) {
|
||||
fprintf(stderr, "SAM connection failed: %s\n", sam_strerror(rc));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point we just keep polling the buffer, which causes the
|
||||
* appropriate callbacks to be called whenever something happens
|
||||
*/
|
||||
while (true)
|
||||
sam_read_buffer();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* When we receive some data, we just ECHO the exact same data back to them
|
||||
*/
|
||||
static void dgramback(sam_pubkey_t dest, void *data, size_t size)
|
||||
{
|
||||
puts("Echoing datagram");
|
||||
sam_dgram_send(dest, data, size);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called whenever the SAM connection fails (like if the I2P router is
|
||||
* shut down)
|
||||
*/
|
||||
static void diedback(void)
|
||||
{
|
||||
fprintf(stderr, "Lost SAM connection!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The logging callback prints any logging messages from LibSAM
|
||||
*/
|
||||
static void logback(char *s)
|
||||
{
|
||||
fprintf(stderr, "LibSAM: %s\n", s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Not used, but the function has to be in the program anyway
|
||||
*/
|
||||
static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result)
|
||||
{
|
||||
assert(false); /* we don't do any naming lookups in this program */
|
||||
}
|
123
apps/sam/c/examples/warhammer-dgram.c
Normal file
123
apps/sam/c/examples/warhammer-dgram.c
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Warhammer-dgram: a simple denial of service tool which uses datagrams, and
|
||||
* illustrates how LibSAM works.
|
||||
* Use only with the utmost courtesy.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "sam.h"
|
||||
|
||||
static void dgramback(sam_pubkey_t dest, void *data, size_t size);
|
||||
static void diedback(void);
|
||||
static void logback(char *s);
|
||||
static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result);
|
||||
|
||||
bool gotdest = false;
|
||||
sam_pubkey_t dest;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Syntax: %s <b64dest|name>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sam_dgramback = &dgramback;
|
||||
sam_diedback = &diedback;
|
||||
sam_logback = &logback;
|
||||
sam_namingback = &namingback;
|
||||
|
||||
/* a tunnel length of 2 is the default - adjust to your preference vv */
|
||||
samerr_t rc = sam_connect("localhost", 7656, "TRANSIENT", SAM_DGRAM, 2);
|
||||
if (rc != SAM_OK) {
|
||||
fprintf(stderr, "SAM connection failed: %s\n", sam_strerror(rc));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strlen(argv[1]) == 516) {
|
||||
memcpy(dest, argv[1], SAM_PUBKEY_LEN);
|
||||
gotdest = true;
|
||||
}
|
||||
else
|
||||
sam_naming_lookup(argv[1]);
|
||||
|
||||
while (!gotdest)
|
||||
sam_read_buffer();
|
||||
|
||||
char data[SAM_DGRAM_PAYLOAD_MAX];
|
||||
memset(data, '#', SAM_DGRAM_PAYLOAD_MAX);
|
||||
size_t sentbytes = 0;
|
||||
while (true) {
|
||||
rc = sam_dgram_send(dest, data, SAM_DGRAM_PAYLOAD_MAX);
|
||||
if (rc != SAM_OK) {
|
||||
fprintf(stderr, "sam_dgram_send() failed: %s\n", sam_strerror(rc));
|
||||
return 1;
|
||||
}
|
||||
sentbytes += SAM_DGRAM_PAYLOAD_MAX;
|
||||
printf("Bombs away! (%u kbytes sent so far)\n", sentbytes / 1024);
|
||||
sam_read_buffer();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dgramback(sam_pubkey_t dest, void *data, size_t size)
|
||||
{
|
||||
puts("Received a datagram (ignored)");
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void diedback(void)
|
||||
{
|
||||
fprintf(stderr, "Lost SAM connection!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void logback(char *s)
|
||||
{
|
||||
fprintf(stderr, "LibSAM: %s\n", s);
|
||||
}
|
||||
|
||||
static void namingback(char *name, sam_pubkey_t pubkey, samerr_t result)
|
||||
{
|
||||
if (result != SAM_OK) {
|
||||
fprintf(stderr, "Naming lookup failed: %s\n", sam_strerror(result));
|
||||
exit(1);
|
||||
}
|
||||
memcpy(dest, pubkey, SAM_PUBKEY_LEN);
|
||||
gotdest = true;
|
||||
}
|
140
apps/sam/c/inc/platform.h
Normal file
140
apps/sam/c/inc/platform.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_H
|
||||
#define PLATFORM_H
|
||||
|
||||
/*
|
||||
* Operating system
|
||||
*/
|
||||
#define FREEBSD 0 // FreeBSD (untested)
|
||||
#define MINGW 1 // Windows native (Mingw)
|
||||
#define LINUX 2 // Linux
|
||||
#define CYGWIN 3 // Cygwin
|
||||
|
||||
#if OS == MINGW
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#define NO_GETHOSTBYNAME2
|
||||
#define NO_INET_ATON /* implies NO_INET_PTON */
|
||||
#define NO_INET_NTOP
|
||||
#define NO_STRL
|
||||
#define NO_Z_FORMAT
|
||||
#define WINSOCK
|
||||
#endif
|
||||
|
||||
#if OS == LINUX
|
||||
#define NO_GETHOSTBYNAME2
|
||||
#define NO_STRL
|
||||
#define NO_Z_FORMAT
|
||||
#endif
|
||||
|
||||
#if OS == CYGWIN
|
||||
#define FAST32_IS_LONG
|
||||
#define INET_ADDRSTRLEN 16
|
||||
#define NO_GETHOSTBYNAME2
|
||||
#define NO_INET_NTOP
|
||||
#define NO_INET_PTON
|
||||
#define NO_SNPRINTF
|
||||
#define NO_STRL
|
||||
#define NO_VSNPRINTF
|
||||
#define NO_Z_FORMAT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Standard C99 includes - if your compiler doesn't have these, it's time to
|
||||
* upgrade
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* System includes
|
||||
*/
|
||||
#ifdef WINSOCK
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#ifndef WINSOCK
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#if defined NO_SNPRINTF || defined NO_VSNPRINTF
|
||||
#include "snprintf.h"
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef NO_STRL
|
||||
#include "strl.h"
|
||||
#endif
|
||||
#ifdef WINSOCK
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Platform-dependent variable types
|
||||
*/
|
||||
#ifdef WINSOCK
|
||||
typedef SOCKET socket_t;
|
||||
typedef signed long ssize_t;
|
||||
#else
|
||||
typedef int socket_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prints out the file name, line number, and function name before log message
|
||||
*/
|
||||
#define SAMLOG(format, ...) sam_log("%s:%d:%s: " \
|
||||
format, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
|
||||
/*
|
||||
* This is the same as above, except that it doesn't accept any va args
|
||||
*/
|
||||
#define SAMLOGS(str) sam_log("%s:%d:%s: " str, __FILE__, __LINE__, __func__)
|
||||
|
||||
/*
|
||||
* Set this to '1' if you want the raw SAM commands to be printed on stdout
|
||||
* (useful for debugging). Otherwise, set it to '0'.
|
||||
*/
|
||||
#define SAM_WIRETAP 0
|
||||
#if SAM_WIRETAP
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#endif /* PLATFORM_H */
|
123
apps/sam/c/inc/sam.h
Normal file
123
apps/sam/c/inc/sam.h
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SAM_H
|
||||
#define SAM_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Lengths
|
||||
*/
|
||||
#define SAM_CMD_LEN 128 /* the maximum length a SAM command can be */
|
||||
#define SAM_DGRAM_PAYLOAD_MAX ((31 * 1024) - 30) /* max size of a single datagram packet (-30 temporary bug fix for SAM) */
|
||||
#define SAM_ERRMSG_LEN 23 /* the longest message returned from sam_strerror */
|
||||
#define SAM_LOGMSG_LEN 256 /* the longest log message */
|
||||
#define SAM_NAME_LEN 256 /* the longest `name' arg for naming lookup callback*/
|
||||
#define SAM_STREAM_PAYLOAD_MAX 32768 /* max size of a single stream packet */
|
||||
#define SAM_PKCMD_LEN (SAM_PUBKEY_LEN + SAM_CMD_LEN)/*a public key SAM command*/
|
||||
#define SAM_PUBKEY_LEN 517 /* it's actually 516, but +1 for '\0' */
|
||||
#define SAM_REPLY_LEN 1024 /* the maximum length a SAM non-data reply can be */
|
||||
|
||||
/*
|
||||
* Shorten some standard variable types
|
||||
*/
|
||||
typedef signed char schar_t;
|
||||
typedef unsigned char uchar_t;
|
||||
typedef unsigned int uint_t;
|
||||
typedef unsigned long ulong_t;
|
||||
typedef unsigned short ushort_t;
|
||||
|
||||
typedef enum {SAM_STREAM, SAM_DGRAM, SAM_RAW} sam_conn_t; /* SAM connection */
|
||||
|
||||
typedef char sam_pubkey_t[SAM_PUBKEY_LEN]; /* base 64 public key */
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
size_t size;
|
||||
} sam_sendq_t; /* sending queue to encourage large stream packet sizes */
|
||||
|
||||
typedef int_fast32_t sam_sid_t; /* stream id number */
|
||||
|
||||
typedef enum { /* see sam_strerror() for detailed descriptions of these */
|
||||
/* error codes from SAM itself (SAM_OK is not an actual "error") */
|
||||
SAM_OK, SAM_CANT_REACH_PEER, SAM_DUPLICATED_DEST, SAM_I2P_ERROR,
|
||||
SAM_INVALID_KEY, SAM_KEY_NOT_FOUND, SAM_PEER_NOT_FOUND, SAM_TIMEOUT,
|
||||
SAM_UNKNOWN,
|
||||
/* error codes from libsam */
|
||||
SAM_BAD_VERSION, SAM_CALLBACKS_UNSET, SAM_SOCKET_ERROR, SAM_TOO_BIG
|
||||
} samerr_t;
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
|
||||
/* SAM controls */
|
||||
extern bool sam_close(void);
|
||||
extern samerr_t sam_connect(const char *samhost, uint16_t samport,
|
||||
const char *destname, sam_conn_t style, uint_t tunneldepth);
|
||||
extern void sam_naming_lookup(const char *name);
|
||||
extern bool sam_read_buffer(void);
|
||||
extern char *sam_strerror(samerr_t code);
|
||||
/* SAM controls - callbacks */
|
||||
extern void (*sam_diedback)(void);
|
||||
extern void (*sam_logback)(char *str);
|
||||
extern void (*sam_namingback)(char *name, sam_pubkey_t pubkey,
|
||||
samerr_t result);
|
||||
|
||||
/* Stream commands */
|
||||
extern void sam_stream_close(sam_sid_t stream_id);
|
||||
extern sam_sid_t sam_stream_connect(const sam_pubkey_t dest);
|
||||
extern samerr_t sam_stream_send(sam_sid_t stream_id, const void *data,
|
||||
size_t size);
|
||||
/* Stream commands - callbacks */
|
||||
extern void (*sam_closeback)(sam_sid_t stream_id, samerr_t reason);
|
||||
extern void (*sam_connectback)(sam_sid_t stream_id, sam_pubkey_t dest);
|
||||
extern void (*sam_databack)(sam_sid_t stream_id, void *data, size_t size);
|
||||
extern void (*sam_statusback)(sam_sid_t stream_id, samerr_t result);
|
||||
|
||||
/* Stream send queue */
|
||||
extern samerr_t sam_sendq_add(sam_sendq_t *sendq, const void *data,
|
||||
size_t dsize);
|
||||
extern sam_sendq_t *sam_sendq_create(void);
|
||||
extern void sam_sendq_send(sam_sendq_t *sendq, sam_sid_t stream_id);
|
||||
|
||||
/* Datagram commands */
|
||||
extern samerr_t sam_dgram_send(const sam_pubkey_t dest, const void *data,
|
||||
size_t size);
|
||||
|
||||
/* Datagram commands - callbacks */
|
||||
extern void (*sam_dgramback)(sam_pubkey_t dest, void *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* SAM_H */
|
49
apps/sam/c/inc/snprintf.h
Normal file
49
apps/sam/c/inc/snprintf.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: The snprintf.c file retains its original license (at the top of
|
||||
* snprintf.c)
|
||||
*/
|
||||
|
||||
#ifndef SNPRINTF_H
|
||||
#define SNPRINTF_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h> /* for va_list */
|
||||
int snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* SNPRINTF_H */
|
47
apps/sam/c/inc/strl.h
Normal file
47
apps/sam/c/inc/strl.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2004, Matthew P. Cashdollar <mpc@innographx.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: The strl.c file retains its original license (at the top of strl.c)
|
||||
*/
|
||||
|
||||
#ifndef STRL_H
|
||||
#define STRL_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern size_t strlcat(char *dst, const char *src, size_t siz);
|
||||
extern size_t strlcpy(char *dst, const char *src, size_t siz);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* STRL_H */
|
1048
apps/sam/c/src/sam.c
Normal file
1048
apps/sam/c/src/sam.c
Normal file
File diff suppressed because it is too large
Load Diff
851
apps/sam/c/src/snprintf.c
Normal file
851
apps/sam/c/src/snprintf.c
Normal file
@ -0,0 +1,851 @@
|
||||
/*
|
||||
* Copyright Patrick Powell 1995
|
||||
* This code is based on code written by Patrick Powell (papowell@astart.com)
|
||||
* It may be used for any purpose as long as this notice remains intact
|
||||
* on all source code distributions
|
||||
*/
|
||||
|
||||
/**************************************************************
|
||||
* Original:
|
||||
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
|
||||
* A bombproof version of doprnt (dopr) included.
|
||||
* Sigh. This sort of thing is always nasty do deal with. Note that
|
||||
* the version here does not include floating point...
|
||||
*
|
||||
* snprintf() is used instead of sprintf() as it does limit checks
|
||||
* for string length. This covers a nasty loophole.
|
||||
*
|
||||
* The other functions are there to prevent NULL pointers from
|
||||
* causing nast effects.
|
||||
*
|
||||
* More Recently:
|
||||
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
|
||||
* This was ugly. It is still ugly. I opted out of floating point
|
||||
* numbers, but the formatter understands just about everything
|
||||
* from the normal C string format, at least as far as I can tell from
|
||||
* the Solaris 2.5 printf(3S) man page.
|
||||
*
|
||||
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
|
||||
* Ok, added some minimal floating point support, which means this
|
||||
* probably requires libm on most operating systems. Don't yet
|
||||
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
|
||||
* was pretty badly broken, it just wasn't being exercised in ways
|
||||
* which showed it, so that's been fixed. Also, formated the code
|
||||
* to mutt conventions, and removed dead code left over from the
|
||||
* original. Also, there is now a builtin-test, just compile with:
|
||||
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
|
||||
* and run snprintf for results.
|
||||
*
|
||||
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
|
||||
* The PGP code was using unsigned hexadecimal formats.
|
||||
* Unfortunately, unsigned formats simply didn't work.
|
||||
*
|
||||
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
|
||||
* The original code assumed that both snprintf() and vsnprintf() were
|
||||
* missing. Some systems only have snprintf() but not vsnprintf(), so
|
||||
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
|
||||
*
|
||||
* Andrew Tridgell (tridge@samba.org) Oct 1998
|
||||
* fixed handling of %.0f
|
||||
* added test for HAVE_LONG_DOUBLE
|
||||
*
|
||||
* Russ Allbery <rra@stanford.edu> 2000-08-26
|
||||
* fixed return value to comply with C99
|
||||
* fixed handling of snprintf(NULL, ...)
|
||||
*
|
||||
* Hrvoje Niksic <hniksic@arsdigita.com> 2000-11-04
|
||||
* include <stdio.h> for NULL.
|
||||
* added support for long long.
|
||||
* don't declare argument types to (v)snprintf if stdarg is not used.
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef NULL
|
||||
# define NULL 0
|
||||
#endif
|
||||
|
||||
/* varargs declarations: */
|
||||
|
||||
#include <stdarg.h>
|
||||
#define HAVE_STDARGS /* let's hope that works everywhere (mj) */
|
||||
#define VA_LOCAL_DECL va_list ap
|
||||
#define VA_START(f) va_start(ap, f)
|
||||
#define VA_SHIFT(v,t) ; /* no-op for ANSI */
|
||||
#define VA_END va_end(ap)
|
||||
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#define LDOUBLE long double
|
||||
#else
|
||||
#define LDOUBLE double
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
# define LLONG long long
|
||||
#else
|
||||
# define LLONG long
|
||||
#endif
|
||||
|
||||
int snprintf (char *str, size_t count, const char *fmt, ...);
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
|
||||
|
||||
static int dopr (char *buffer, size_t maxlen, const char *format,
|
||||
va_list args);
|
||||
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
|
||||
char *value, int flags, int min, int max);
|
||||
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
|
||||
LLONG value, int base, int min, int max, int flags);
|
||||
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
LDOUBLE fvalue, int min, int max, int flags);
|
||||
static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
|
||||
|
||||
/*
|
||||
* dopr(): poor man's version of doprintf
|
||||
*/
|
||||
|
||||
/* format read states */
|
||||
#define DP_S_DEFAULT 0
|
||||
#define DP_S_FLAGS 1
|
||||
#define DP_S_MIN 2
|
||||
#define DP_S_DOT 3
|
||||
#define DP_S_MAX 4
|
||||
#define DP_S_MOD 5
|
||||
#define DP_S_MOD_L 6
|
||||
#define DP_S_CONV 7
|
||||
#define DP_S_DONE 8
|
||||
|
||||
/* format flags - Bits */
|
||||
#define DP_F_MINUS (1 << 0)
|
||||
#define DP_F_PLUS (1 << 1)
|
||||
#define DP_F_SPACE (1 << 2)
|
||||
#define DP_F_NUM (1 << 3)
|
||||
#define DP_F_ZERO (1 << 4)
|
||||
#define DP_F_UP (1 << 5)
|
||||
#define DP_F_UNSIGNED (1 << 6)
|
||||
|
||||
/* Conversion Flags */
|
||||
#define DP_C_SHORT 1
|
||||
#define DP_C_LONG 2
|
||||
#define DP_C_LLONG 3
|
||||
#define DP_C_LDOUBLE 4
|
||||
|
||||
#define char_to_int(p) (p - '0')
|
||||
#define MAX(p,q) ((p >= q) ? p : q)
|
||||
#define MIN(p,q) ((p <= q) ? p : q)
|
||||
|
||||
static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
|
||||
{
|
||||
char ch;
|
||||
LLONG value;
|
||||
LDOUBLE fvalue;
|
||||
char *strvalue;
|
||||
int min;
|
||||
int max;
|
||||
int state;
|
||||
int flags;
|
||||
int cflags;
|
||||
int total;
|
||||
size_t currlen;
|
||||
|
||||
state = DP_S_DEFAULT;
|
||||
currlen = flags = cflags = min = 0;
|
||||
max = -1;
|
||||
ch = *format++;
|
||||
total = 0;
|
||||
|
||||
while (state != DP_S_DONE)
|
||||
{
|
||||
if (ch == '\0')
|
||||
state = DP_S_DONE;
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case DP_S_DEFAULT:
|
||||
if (ch == '%')
|
||||
state = DP_S_FLAGS;
|
||||
else
|
||||
total += dopr_outch (buffer, &currlen, maxlen, ch);
|
||||
ch = *format++;
|
||||
break;
|
||||
case DP_S_FLAGS:
|
||||
switch (ch)
|
||||
{
|
||||
case '-':
|
||||
flags |= DP_F_MINUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '+':
|
||||
flags |= DP_F_PLUS;
|
||||
ch = *format++;
|
||||
break;
|
||||
case ' ':
|
||||
flags |= DP_F_SPACE;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '#':
|
||||
flags |= DP_F_NUM;
|
||||
ch = *format++;
|
||||
break;
|
||||
case '0':
|
||||
flags |= DP_F_ZERO;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
state = DP_S_MIN;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DP_S_MIN:
|
||||
if (isdigit((unsigned char)ch))
|
||||
{
|
||||
min = 10*min + char_to_int (ch);
|
||||
ch = *format++;
|
||||
}
|
||||
else if (ch == '*')
|
||||
{
|
||||
min = va_arg (args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_DOT;
|
||||
}
|
||||
else
|
||||
state = DP_S_DOT;
|
||||
break;
|
||||
case DP_S_DOT:
|
||||
if (ch == '.')
|
||||
{
|
||||
state = DP_S_MAX;
|
||||
ch = *format++;
|
||||
}
|
||||
else
|
||||
state = DP_S_MOD;
|
||||
break;
|
||||
case DP_S_MAX:
|
||||
if (isdigit((unsigned char)ch))
|
||||
{
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
max = 10*max + char_to_int (ch);
|
||||
ch = *format++;
|
||||
}
|
||||
else if (ch == '*')
|
||||
{
|
||||
max = va_arg (args, int);
|
||||
ch = *format++;
|
||||
state = DP_S_MOD;
|
||||
}
|
||||
else
|
||||
state = DP_S_MOD;
|
||||
break;
|
||||
case DP_S_MOD:
|
||||
switch (ch)
|
||||
{
|
||||
case 'h':
|
||||
cflags = DP_C_SHORT;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'l':
|
||||
cflags = DP_C_LONG;
|
||||
ch = *format++;
|
||||
break;
|
||||
case 'L':
|
||||
cflags = DP_C_LDOUBLE;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (cflags != DP_C_LONG)
|
||||
state = DP_S_CONV;
|
||||
else
|
||||
state = DP_S_MOD_L;
|
||||
break;
|
||||
case DP_S_MOD_L:
|
||||
switch (ch)
|
||||
{
|
||||
case 'l':
|
||||
cflags = DP_C_LLONG;
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
state = DP_S_CONV;
|
||||
break;
|
||||
case DP_S_CONV:
|
||||
switch (ch)
|
||||
{
|
||||
case 'd':
|
||||
case 'i':
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = (short int) va_arg (args, int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg (args, long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = va_arg (args, LLONG);
|
||||
else
|
||||
value = va_arg (args, int);
|
||||
total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
|
||||
break;
|
||||
case 'o':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = (unsigned short int) va_arg (args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg (args, unsigned long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = va_arg (args, unsigned LLONG);
|
||||
else
|
||||
value = va_arg (args, unsigned int);
|
||||
total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
|
||||
break;
|
||||
case 'u':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = (unsigned short int) va_arg (args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg (args, unsigned long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = va_arg (args, unsigned LLONG);
|
||||
else
|
||||
value = va_arg (args, unsigned int);
|
||||
total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
|
||||
break;
|
||||
case 'X':
|
||||
flags |= DP_F_UP;
|
||||
case 'x':
|
||||
flags |= DP_F_UNSIGNED;
|
||||
if (cflags == DP_C_SHORT)
|
||||
value = (unsigned short int) va_arg (args, unsigned int);
|
||||
else if (cflags == DP_C_LONG)
|
||||
value = va_arg (args, unsigned long int);
|
||||
else if (cflags == DP_C_LLONG)
|
||||
value = va_arg (args, unsigned LLONG);
|
||||
else
|
||||
value = va_arg (args, unsigned int);
|
||||
total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
|
||||
break;
|
||||
case 'f':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
/* um, floating point? */
|
||||
total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
|
||||
break;
|
||||
case 'E':
|
||||
flags |= DP_F_UP;
|
||||
case 'e':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
break;
|
||||
case 'G':
|
||||
flags |= DP_F_UP;
|
||||
case 'g':
|
||||
if (cflags == DP_C_LDOUBLE)
|
||||
fvalue = va_arg (args, LDOUBLE);
|
||||
else
|
||||
fvalue = va_arg (args, double);
|
||||
break;
|
||||
case 'c':
|
||||
total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
|
||||
break;
|
||||
case 's':
|
||||
strvalue = va_arg (args, char *);
|
||||
total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
|
||||
break;
|
||||
case 'p':
|
||||
strvalue = va_arg (args, void *);
|
||||
total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
|
||||
max, flags);
|
||||
break;
|
||||
case 'n':
|
||||
if (cflags == DP_C_SHORT)
|
||||
{
|
||||
short int *num;
|
||||
num = va_arg (args, short int *);
|
||||
*num = currlen;
|
||||
}
|
||||
else if (cflags == DP_C_LONG)
|
||||
{
|
||||
long int *num;
|
||||
num = va_arg (args, long int *);
|
||||
*num = currlen;
|
||||
}
|
||||
else if (cflags == DP_C_LLONG)
|
||||
{
|
||||
LLONG *num;
|
||||
num = va_arg (args, LLONG *);
|
||||
*num = currlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
int *num;
|
||||
num = va_arg (args, int *);
|
||||
*num = currlen;
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
total += dopr_outch (buffer, &currlen, maxlen, ch);
|
||||
break;
|
||||
case 'w':
|
||||
/* not supported yet, treat as next char */
|
||||
ch = *format++;
|
||||
break;
|
||||
default:
|
||||
/* Unknown, skip */
|
||||
break;
|
||||
}
|
||||
ch = *format++;
|
||||
state = DP_S_DEFAULT;
|
||||
flags = cflags = min = 0;
|
||||
max = -1;
|
||||
break;
|
||||
case DP_S_DONE:
|
||||
break;
|
||||
default:
|
||||
/* hmm? */
|
||||
break; /* some picky compilers need this */
|
||||
}
|
||||
}
|
||||
if (buffer != NULL)
|
||||
{
|
||||
if (currlen < maxlen - 1)
|
||||
buffer[currlen] = '\0';
|
||||
else
|
||||
buffer[maxlen - 1] = '\0';
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
|
||||
char *value, int flags, int min, int max)
|
||||
{
|
||||
int padlen, strln; /* amount to pad */
|
||||
int cnt = 0;
|
||||
int total = 0;
|
||||
char null[] = "<NULL>";
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
|
||||
for (strln = 0; value[strln]; ++strln); /* strlen */
|
||||
if (max >= 0 && max < strln)
|
||||
strln = max;
|
||||
padlen = min - strln;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen; /* Left Justify */
|
||||
|
||||
while (padlen > 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
}
|
||||
while (*value && ((max < 0) || (cnt < max)))
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, *value++);
|
||||
++cnt;
|
||||
}
|
||||
while (padlen < 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
|
||||
|
||||
static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
|
||||
LLONG value, int base, int min, int max, int flags)
|
||||
{
|
||||
int signvalue = 0;
|
||||
unsigned LLONG uvalue;
|
||||
char convert[24];
|
||||
unsigned int place = 0;
|
||||
int spadlen = 0; /* amount to space pad */
|
||||
int zpadlen = 0; /* amount to zero pad */
|
||||
const char *digits;
|
||||
int total = 0;
|
||||
|
||||
if (max < 0)
|
||||
max = 0;
|
||||
|
||||
uvalue = value;
|
||||
|
||||
if(!(flags & DP_F_UNSIGNED))
|
||||
{
|
||||
if( value < 0 ) {
|
||||
signvalue = '-';
|
||||
uvalue = -value;
|
||||
}
|
||||
else
|
||||
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
||||
signvalue = '+';
|
||||
else
|
||||
if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
}
|
||||
|
||||
if (flags & DP_F_UP)
|
||||
/* Should characters be upper case? */
|
||||
digits = "0123456789ABCDEF";
|
||||
else
|
||||
digits = "0123456789abcdef";
|
||||
|
||||
do {
|
||||
convert[place++] = digits[uvalue % (unsigned)base];
|
||||
uvalue = (uvalue / (unsigned)base );
|
||||
} while(uvalue && (place < sizeof (convert)));
|
||||
if (place == sizeof (convert)) place--;
|
||||
convert[place] = 0;
|
||||
|
||||
zpadlen = max - place;
|
||||
spadlen = min - MAX ((unsigned int)max, place) - (signvalue ? 1 : 0);
|
||||
if (zpadlen < 0) zpadlen = 0;
|
||||
if (spadlen < 0) spadlen = 0;
|
||||
if (flags & DP_F_ZERO)
|
||||
{
|
||||
zpadlen = MAX(zpadlen, spadlen);
|
||||
spadlen = 0;
|
||||
}
|
||||
if (flags & DP_F_MINUS)
|
||||
spadlen = -spadlen; /* Left Justifty */
|
||||
|
||||
#ifdef DEBUG_SNPRINTF
|
||||
dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
|
||||
zpadlen, spadlen, min, max, place));
|
||||
#endif
|
||||
|
||||
/* Spaces */
|
||||
while (spadlen > 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
--spadlen;
|
||||
}
|
||||
|
||||
/* Sign */
|
||||
if (signvalue)
|
||||
total += dopr_outch (buffer, currlen, maxlen, signvalue);
|
||||
|
||||
/* Zeros */
|
||||
if (zpadlen > 0)
|
||||
{
|
||||
while (zpadlen > 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
}
|
||||
|
||||
/* Digits */
|
||||
while (place > 0)
|
||||
total += dopr_outch (buffer, currlen, maxlen, convert[--place]);
|
||||
|
||||
/* Left Justified spaces */
|
||||
while (spadlen < 0) {
|
||||
total += dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++spadlen;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static LDOUBLE abs_val (LDOUBLE value)
|
||||
{
|
||||
LDOUBLE result = value;
|
||||
|
||||
if (value < 0)
|
||||
result = -value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static LDOUBLE pow10 (int exp)
|
||||
{
|
||||
LDOUBLE result = 1;
|
||||
|
||||
while (exp)
|
||||
{
|
||||
result *= 10;
|
||||
exp--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static long round (LDOUBLE value)
|
||||
{
|
||||
long intpart;
|
||||
|
||||
intpart = value;
|
||||
value = value - intpart;
|
||||
if (value >= 0.5)
|
||||
intpart++;
|
||||
|
||||
return intpart;
|
||||
}
|
||||
|
||||
static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||
LDOUBLE fvalue, int min, int max, int flags)
|
||||
{
|
||||
int signvalue = 0;
|
||||
LDOUBLE ufvalue;
|
||||
char iconvert[20];
|
||||
char fconvert[20];
|
||||
int iplace = 0;
|
||||
int fplace = 0;
|
||||
int padlen = 0; /* amount to pad */
|
||||
int zpadlen = 0;
|
||||
int caps = 0;
|
||||
int total = 0;
|
||||
LLONG intpart;
|
||||
LLONG fracpart;
|
||||
|
||||
/*
|
||||
* AIX manpage says the default is 0, but Solaris says the default
|
||||
* is 6, and sprintf on AIX defaults to 6
|
||||
*/
|
||||
if (max < 0)
|
||||
max = 6;
|
||||
|
||||
ufvalue = abs_val (fvalue);
|
||||
|
||||
if (fvalue < 0)
|
||||
signvalue = '-';
|
||||
else
|
||||
if (flags & DP_F_PLUS) /* Do a sign (+/i) */
|
||||
signvalue = '+';
|
||||
else
|
||||
if (flags & DP_F_SPACE)
|
||||
signvalue = ' ';
|
||||
|
||||
#if 0
|
||||
if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
|
||||
#endif
|
||||
|
||||
intpart = ufvalue;
|
||||
|
||||
/*
|
||||
* Sorry, we only support 9 digits past the decimal because of our
|
||||
* conversion method
|
||||
*/
|
||||
if (max > 9)
|
||||
max = 9;
|
||||
|
||||
/* We "cheat" by converting the fractional part to integer by
|
||||
* multiplying by a factor of 10
|
||||
*/
|
||||
fracpart = round ((pow10 (max)) * (ufvalue - intpart));
|
||||
|
||||
if (fracpart >= pow10 (max))
|
||||
{
|
||||
intpart++;
|
||||
fracpart -= pow10 (max);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SNPRINTF
|
||||
dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
|
||||
#endif
|
||||
|
||||
/* Convert integer part */
|
||||
do {
|
||||
iconvert[iplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
|
||||
intpart = (intpart / 10);
|
||||
} while(intpart && (iplace < 20));
|
||||
if (iplace == 20) iplace--;
|
||||
iconvert[iplace] = 0;
|
||||
|
||||
/* Convert fractional part */
|
||||
do {
|
||||
fconvert[fplace++] =
|
||||
(caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
|
||||
fracpart = (fracpart / 10);
|
||||
} while(fracpart && (fplace < 20));
|
||||
if (fplace == 20) fplace--;
|
||||
fconvert[fplace] = 0;
|
||||
|
||||
/* -1 for decimal point, another -1 if we are printing a sign */
|
||||
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
|
||||
zpadlen = max - fplace;
|
||||
if (zpadlen < 0)
|
||||
zpadlen = 0;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (flags & DP_F_MINUS)
|
||||
padlen = -padlen; /* Left Justifty */
|
||||
|
||||
if ((flags & DP_F_ZERO) && (padlen > 0))
|
||||
{
|
||||
if (signvalue)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, signvalue);
|
||||
--padlen;
|
||||
signvalue = 0;
|
||||
}
|
||||
while (padlen > 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--padlen;
|
||||
}
|
||||
}
|
||||
while (padlen > 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
--padlen;
|
||||
}
|
||||
if (signvalue)
|
||||
total += dopr_outch (buffer, currlen, maxlen, signvalue);
|
||||
|
||||
while (iplace > 0)
|
||||
total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
|
||||
|
||||
/*
|
||||
* Decimal point. This should probably use locale to find the correct
|
||||
* char to print out.
|
||||
*/
|
||||
if (max > 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, '.');
|
||||
|
||||
while (fplace > 0)
|
||||
total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
|
||||
}
|
||||
|
||||
while (zpadlen > 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, '0');
|
||||
--zpadlen;
|
||||
}
|
||||
|
||||
while (padlen < 0)
|
||||
{
|
||||
total += dopr_outch (buffer, currlen, maxlen, ' ');
|
||||
++padlen;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
|
||||
{
|
||||
if (*currlen + 1 < maxlen)
|
||||
buffer[(*currlen)++] = c;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
|
||||
{
|
||||
if (str != NULL)
|
||||
str[0] = 0;
|
||||
return dopr(str, count, fmt, args);
|
||||
}
|
||||
|
||||
/* VARARGS3 */
|
||||
#ifdef HAVE_STDARGS
|
||||
int snprintf (char *str,size_t count,const char *fmt,...)
|
||||
#else
|
||||
int snprintf (va_alist) va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifndef HAVE_STDARGS
|
||||
char *str;
|
||||
size_t count;
|
||||
char *fmt;
|
||||
#endif
|
||||
VA_LOCAL_DECL;
|
||||
int total;
|
||||
|
||||
VA_START (fmt);
|
||||
VA_SHIFT (str, char *);
|
||||
VA_SHIFT (count, size_t );
|
||||
VA_SHIFT (fmt, char *);
|
||||
total = vsnprintf(str, count, fmt, ap);
|
||||
VA_END;
|
||||
return total;
|
||||
}
|
||||
|
||||
#ifdef TEST_SNPRINTF
|
||||
#ifndef LONG_STRING
|
||||
#define LONG_STRING 1024
|
||||
#endif
|
||||
int main (void)
|
||||
{
|
||||
char buf1[LONG_STRING];
|
||||
char buf2[LONG_STRING];
|
||||
char *fp_fmt[] = {
|
||||
"%-1.5f",
|
||||
"%1.5f",
|
||||
"%123.9f",
|
||||
"%10.5f",
|
||||
"% 10.5f",
|
||||
"%+22.9f",
|
||||
"%+4.9f",
|
||||
"%01.3f",
|
||||
"%4f",
|
||||
"%3.1f",
|
||||
"%3.2f",
|
||||
"%.0f",
|
||||
"%.1f",
|
||||
NULL
|
||||
};
|
||||
double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
|
||||
0.9996, 1.996, 4.136, 0};
|
||||
char *int_fmt[] = {
|
||||
"%-1.5d",
|
||||
"%1.5d",
|
||||
"%123.9d",
|
||||
"%5.5d",
|
||||
"%10.5d",
|
||||
"% 10.5d",
|
||||
"%+22.33d",
|
||||
"%01.3d",
|
||||
"%4d",
|
||||
NULL
|
||||
};
|
||||
long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
|
||||
int x, y;
|
||||
int fail = 0;
|
||||
int num = 0;
|
||||
|
||||
printf ("Testing snprintf format codes against system sprintf...\n");
|
||||
|
||||
for (x = 0; fp_fmt[x] != NULL ; x++)
|
||||
for (y = 0; fp_nums[y] != 0 ; y++)
|
||||
{
|
||||
snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
|
||||
sprintf (buf2, fp_fmt[x], fp_nums[y]);
|
||||
if (strcmp (buf1, buf2))
|
||||
{
|
||||
printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
|
||||
fp_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
|
||||
for (x = 0; int_fmt[x] != NULL ; x++)
|
||||
for (y = 0; int_nums[y] != 0 ; y++)
|
||||
{
|
||||
snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
|
||||
sprintf (buf2, int_fmt[x], int_nums[y]);
|
||||
if (strcmp (buf1, buf2))
|
||||
{
|
||||
printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
|
||||
int_fmt[x], buf1, buf2);
|
||||
fail++;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
printf ("%d tests failed out of %d.\n", fail, num);
|
||||
}
|
||||
#endif /* SNPRINTF_TEST */
|
84
apps/sam/c/src/strl.c
Normal file
84
apps/sam/c/src/strl.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
register char *d = dst;
|
||||
register const char *s = src;
|
||||
register size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
58
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/AssemblyInfo.cs
Normal file
58
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/AssemblyInfo.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly: AssemblyTitle("")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
//
|
||||
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||
//
|
||||
// Use the attributes below to control which key is used for signing.
|
||||
//
|
||||
// Notes:
|
||||
// (*) If no key is specified, the assembly is not signed.
|
||||
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||
// a key.
|
||||
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||
// following processing occurs:
|
||||
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||
// in the KeyFile is installed into the CSP and used.
|
||||
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||
// When specifying the KeyFile, the location of the KeyFile should be
|
||||
// relative to the project output directory which is
|
||||
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||
// located in the project directory, you would specify the AssemblyKeyFile
|
||||
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||
// documentation for more information on this.
|
||||
//
|
||||
[assembly: AssemblyDelaySign(false)]
|
||||
[assembly: AssemblyKeyFile("")]
|
||||
[assembly: AssemblyKeyName("")]
|
50
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/SAM.NET.Test.cs
Normal file
50
apps/sam/csharp/src/SAM.NET/SAM.NET.Test/SAM.NET.Test.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
|
||||
namespace SAM.NET
|
||||
{
|
||||
class SAMTester
|
||||
{
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
new SAMTester();
|
||||
}
|
||||
public SAMTester ()
|
||||
{
|
||||
SAMConnection connection1 = new SAMConnection(IPAddress.Parse("127.0.0.1"),7656);
|
||||
SAMSession session1 = new SAMSession(connection1,SAM.NET.SamSocketType.Stream,"alice");
|
||||
|
||||
SAMConnection connection2 = new SAMConnection(IPAddress.Parse("127.0.0.1"),7656);
|
||||
SAMSession session2 = new SAMSession(connection2,SAM.NET.SamSocketType.Stream,"bob");
|
||||
|
||||
SAMStream stream1 = new SAMStream(connection1,session1,233);
|
||||
stream1.Connect(session2.getKey());
|
||||
|
||||
//Wait till we are connected to destination
|
||||
while (!stream1.isConnected)
|
||||
Thread.Sleep(1000);
|
||||
|
||||
//Send some bytes
|
||||
stream1.Write(Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString() + "Hi!!!!!!"));
|
||||
|
||||
//Wait till a stream magically appears on the other side
|
||||
while (session2.getStreams().Count == 0) Thread.Sleep(1000);
|
||||
|
||||
Thread.Sleep(1000);
|
||||
foreach (SAMStream stream in session2.getStreams().Values)
|
||||
{
|
||||
Console.WriteLine("Text received on " + stream.getID() + " at " + DateTime.Now.ToLongTimeString());
|
||||
Console.WriteLine(Encoding.ASCII.GetString(stream.ReadToEnd()));
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
stream1.Close();
|
||||
connection1.Close();
|
||||
connection2.Close();
|
||||
}
|
||||
}
|
||||
}
|
58
apps/sam/csharp/src/SAM.NET/SAM.NET/AssemblyInfo.cs
Normal file
58
apps/sam/csharp/src/SAM.NET/SAM.NET/AssemblyInfo.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly: AssemblyTitle("")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
//
|
||||
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||
//
|
||||
// Use the attributes below to control which key is used for signing.
|
||||
//
|
||||
// Notes:
|
||||
// (*) If no key is specified, the assembly is not signed.
|
||||
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||
// a key.
|
||||
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||
// following processing occurs:
|
||||
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||
// in the KeyFile is installed into the CSP and used.
|
||||
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||
// When specifying the KeyFile, the location of the KeyFile should be
|
||||
// relative to the project output directory which is
|
||||
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||
// located in the project directory, you would specify the AssemblyKeyFile
|
||||
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||
// documentation for more information on this.
|
||||
//
|
||||
[assembly: AssemblyDelaySign(false)]
|
||||
[assembly: AssemblyKeyFile("")]
|
||||
[assembly: AssemblyKeyName("")]
|
271
apps/sam/csharp/src/SAM.NET/SAM.NET/SAM.NET.cs
Normal file
271
apps/sam/csharp/src/SAM.NET/SAM.NET/SAM.NET.cs
Normal file
@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
|
||||
namespace SAM.NET
|
||||
{
|
||||
public enum SamSocketType
|
||||
{
|
||||
Stream,
|
||||
Datagram,
|
||||
Raw
|
||||
}
|
||||
|
||||
public class SAMConnection
|
||||
{
|
||||
private const string propertyMinVersion = "1.0";
|
||||
private const string propertyMaxVersion = "1.0";
|
||||
|
||||
private Socket _sock;
|
||||
private NetworkStream _sockStream;
|
||||
private StreamReader _sockStreamIn;
|
||||
private StreamWriter _sockStreamOut;
|
||||
|
||||
public SAMConnection(IPAddress routerIP, int port)
|
||||
{
|
||||
_sock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
|
||||
IPEndPoint rEP = new IPEndPoint(routerIP,port);
|
||||
_sock.Connect(rEP);
|
||||
_sockStream = new NetworkStream(_sock);
|
||||
_sockStreamIn = new StreamReader(_sockStream);
|
||||
_sockStreamOut = new StreamWriter(_sockStream);
|
||||
try
|
||||
{
|
||||
sendVersion(propertyMinVersion,propertyMinVersion);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_sock.Close();
|
||||
throw (new Exception("No SAM for you :("));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendVersion(string min, string max)
|
||||
{
|
||||
_sockStreamOut.WriteLine("HELLO VERSION MIN=" + propertyMinVersion + " MAX=" + propertyMaxVersion);
|
||||
_sockStreamOut.Flush();
|
||||
Hashtable response = SAMUtil.parseKeyValues(_sockStreamIn.ReadLine(),2);
|
||||
if (response["RESULT"].ToString() != "OK") throw (new Exception("Version mismatch"));
|
||||
}
|
||||
|
||||
public StreamWriter getOutputStream()
|
||||
{
|
||||
return _sockStreamOut;
|
||||
}
|
||||
|
||||
public StreamReader getInputStream()
|
||||
{
|
||||
return _sockStreamIn;
|
||||
}
|
||||
|
||||
public NetworkStream getStream()
|
||||
{
|
||||
return _sockStream;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_sock.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Creating a SAMSession object will automatically:
|
||||
* 1) create a sesion on SAM
|
||||
* 1) query for the base64key
|
||||
* 2) start a listening thread to catch all stream commands
|
||||
*/
|
||||
public class SAMSession
|
||||
{
|
||||
private Hashtable _streams;
|
||||
private string _sessionKey;
|
||||
|
||||
public SAMSession (SAMConnection connection, SamSocketType type, string destination)
|
||||
{
|
||||
_streams = new Hashtable();
|
||||
StreamWriter writer = connection.getOutputStream();
|
||||
StreamReader reader = connection.getInputStream();
|
||||
writer.WriteLine("SESSION CREATE STYLE=STREAM DESTINATION=" + destination);
|
||||
writer.Flush();
|
||||
Hashtable response = SAMUtil.parseKeyValues(reader.ReadLine(),2);
|
||||
if (response["RESULT"].ToString() != "OK")
|
||||
{
|
||||
throw (new Exception(response["MESSAGE"].ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteLine("NAMING LOOKUP NAME=ME");
|
||||
writer.Flush();
|
||||
response = SAMUtil.parseKeyValues(reader.ReadLine(),2);
|
||||
_sessionKey = response["VALUE"].ToString();
|
||||
SAMSessionListener listener = new SAMSessionListener(connection,this,_streams);
|
||||
new Thread(new ThreadStart(listener.startListening)).Start();
|
||||
}
|
||||
}
|
||||
public void addStream(SAMStream stream)
|
||||
{
|
||||
_streams.Add(stream.getID(),stream);
|
||||
}
|
||||
public string getKey()
|
||||
{
|
||||
return _sessionKey;
|
||||
}
|
||||
public Hashtable getStreams()
|
||||
{
|
||||
return _streams;
|
||||
}
|
||||
}
|
||||
|
||||
public class SAMSessionListener
|
||||
{
|
||||
private Hashtable _streams;
|
||||
private SAMConnection _connection;
|
||||
private SAMSession _session;
|
||||
private bool stayAlive = true;
|
||||
|
||||
public SAMSessionListener(SAMConnection connection,SAMSession session, Hashtable streams)
|
||||
{
|
||||
_streams = streams;
|
||||
_connection = connection;
|
||||
_session = session;
|
||||
}
|
||||
public void startListening()
|
||||
{
|
||||
StreamReader reader = _connection.getInputStream();
|
||||
while (stayAlive)
|
||||
{
|
||||
string response = reader.ReadLine();
|
||||
if (response.StartsWith("STREAM STATUS"))
|
||||
{
|
||||
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||
SAMStream theStream = (SAMStream)_streams[int.Parse(values["ID"].ToString())];
|
||||
if (theStream != null) theStream.ReceivedStatus(values);
|
||||
}
|
||||
if (response.StartsWith("STREAM CONNECTED"))
|
||||
{
|
||||
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||
SAMStream theStream = (SAMStream)_streams[int.Parse(values["ID"].ToString())];
|
||||
if (theStream != null) theStream.isConnected = true;
|
||||
}
|
||||
if (response.StartsWith("STREAM RECEIVED"))
|
||||
{
|
||||
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||
int streamID = int.Parse(values["ID"].ToString());
|
||||
SAMStream theStream = (SAMStream)_streams[streamID];
|
||||
if (theStream == null) new SAMStream(_connection,_session,streamID);
|
||||
theStream = (SAMStream)_streams[streamID];
|
||||
theStream.ReceivedData(int.Parse(values["SIZE"].ToString()));
|
||||
}
|
||||
if (response.StartsWith("STREAM CLOSE"))
|
||||
{
|
||||
Hashtable values = SAMUtil.parseKeyValues(response,2);
|
||||
SAMStream theStream = (SAMStream)_streams[int.Parse(values["ID"].ToString())];
|
||||
if (theStream != null) theStream.isConnected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SAMStream
|
||||
{
|
||||
private int _ID;
|
||||
private byte[] _data;
|
||||
private int _position=0;
|
||||
private int _size=0;
|
||||
private SAMSession _session;
|
||||
private SAMConnection _connection;
|
||||
public bool isConnected=false;
|
||||
|
||||
public SAMStream (SAMConnection connection,SAMSession session, int ID)
|
||||
{
|
||||
_data = new byte[100000]; //FIXME: change to non-static structure for storing stream data
|
||||
_ID = ID;
|
||||
_connection = connection;
|
||||
_session = session;
|
||||
_session.addStream(this);
|
||||
}
|
||||
|
||||
public void Connect(string destination)
|
||||
{
|
||||
StreamWriter writer = _connection.getOutputStream();
|
||||
writer.WriteLine("STREAM CONNECT ID=" + _ID.ToString() + " DESTINATION=" + destination);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
public void ReceivedData(int size) //FIXME: WTF is going on when reading the payload here? All zeros and way too many of them.
|
||||
{
|
||||
NetworkStream stream = _connection.getStream();
|
||||
int bytesRead = stream.Read(_data,_size,size);
|
||||
_size = _size + bytes;
|
||||
}
|
||||
|
||||
public void ReceivedStatus(Hashtable response)
|
||||
{
|
||||
if (response["RESULT"].ToString() != "OK")
|
||||
{
|
||||
throw (new Exception(response["RESULT"].ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
isConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int getID() {return _ID;}
|
||||
|
||||
public bool DataAvailable()
|
||||
{
|
||||
return _position != _size;
|
||||
}
|
||||
|
||||
public void Write(byte[] buf)
|
||||
{
|
||||
NetworkStream stream = _connection.getStream();
|
||||
int sent = 0;
|
||||
while (sent < buf.Length)
|
||||
{
|
||||
int toSend = Math.Min(buf.Length - sent,32768);
|
||||
string header = "STREAM SEND ID=" + _ID.ToString() + " SIZE=" + toSend.ToString() + "\n";
|
||||
byte[] headerbytes = Encoding.ASCII.GetBytes(header);
|
||||
stream.Write(headerbytes,0,headerbytes.Length);
|
||||
stream.Write(buf,sent,toSend);
|
||||
sent = sent + toSend;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ReadToEnd()
|
||||
{
|
||||
byte[] ret = new byte[_size - _position];
|
||||
Array.Copy(_data,_position,ret,0,_size - _position);
|
||||
_position = _size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
StreamWriter writer = _connection.getOutputStream();
|
||||
writer.WriteLine("STREAM CLOSE " + _ID.ToString());
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public class SAMUtil
|
||||
{
|
||||
public static Hashtable parseKeyValues(string str, int startingWord)
|
||||
{
|
||||
Hashtable hash = new Hashtable();
|
||||
string strTruncated = string.Join(" ",str.Split(' '),startingWord,str.Split(' ').Length - startingWord);
|
||||
string[] sets = strTruncated.Split('=',' ');
|
||||
for (int i=0; i<sets.Length; i=i+2)
|
||||
{
|
||||
hash.Add(sets[i],sets[i+1]);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,12 +8,23 @@ package net.i2p.sam;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@ -23,15 +34,25 @@ import net.i2p.util.Log;
|
||||
* @author human
|
||||
*/
|
||||
public class SAMBridge implements Runnable {
|
||||
|
||||
private final static Log _log = new Log(SAMBridge.class);
|
||||
private ServerSocket serverSocket;
|
||||
private Properties i2cpProps;
|
||||
/**
|
||||
* filename in which the name to private key mapping should
|
||||
* be stored (and loaded from)
|
||||
*/
|
||||
private String persistFilename;
|
||||
/**
|
||||
* app designated destination name to the base64 of the I2P formatted
|
||||
* destination keys (Destination+PrivateKey+SigningPrivateKey)
|
||||
*/
|
||||
private Map nameToPrivKeys = Collections.synchronizedMap(new HashMap(8));
|
||||
|
||||
private boolean acceptConnections = true;
|
||||
|
||||
private final static int SAM_LISTENPORT = 7656;
|
||||
|
||||
private static final int SAM_LISTENPORT = 7656;
|
||||
public static final String DEFAULT_SAM_KEYFILE = "sam.keys";
|
||||
|
||||
private SAMBridge() {}
|
||||
|
||||
/**
|
||||
@ -40,8 +61,11 @@ public class SAMBridge implements Runnable {
|
||||
* @param listenHost hostname to listen for SAM connections on ("0.0.0.0" for all)
|
||||
* @param listenPort port number to listen for SAM connections on
|
||||
* @param i2cpProps set of I2CP properties for finding and communicating with the router
|
||||
* @param persistFile location to store/load named keys to/from
|
||||
*/
|
||||
public SAMBridge(String listenHost, int listenPort, Properties i2cpProps) {
|
||||
public SAMBridge(String listenHost, int listenPort, Properties i2cpProps, String persistFile) {
|
||||
persistFilename = persistFile;
|
||||
loadKeys();
|
||||
try {
|
||||
if ( (listenHost != null) && !("0.0.0.0".equals(listenHost)) ) {
|
||||
serverSocket = new ServerSocket(listenPort, 0, InetAddress.getByName(listenHost));
|
||||
@ -63,6 +87,97 @@ public class SAMBridge implements Runnable {
|
||||
this.i2cpProps = i2cpProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the destination associated with the given name
|
||||
*
|
||||
* @return null if the name does not exist, or if it is improperly formatted
|
||||
*/
|
||||
public Destination getDestination(String name) {
|
||||
String val = (String)nameToPrivKeys.get(name);
|
||||
if (val == null) return null;
|
||||
try {
|
||||
Destination d = new Destination();
|
||||
d.fromBase64(val);
|
||||
return d;
|
||||
} catch (DataFormatException dfe) {
|
||||
_log.error("Error retrieving the destination from " + name, dfe);
|
||||
nameToPrivKeys.remove(name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the I2P private keystream for the given name, formatted
|
||||
* as a base64 string (Destination+PrivateKey+SessionPrivateKey, as I2CP
|
||||
* stores it).
|
||||
*
|
||||
* @return null if the name does not exist, else the stream
|
||||
*/
|
||||
public String getKeystream(String name) {
|
||||
String val = (String)nameToPrivKeys.get(name);
|
||||
if (val == null) return null;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that the given keystream should be used for the given name
|
||||
*
|
||||
*/
|
||||
public void addKeystream(String name, String stream) {
|
||||
nameToPrivKeys.put(name, stream);
|
||||
storeKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load up the keys from the persistFilename
|
||||
*
|
||||
*/
|
||||
private synchronized void loadKeys() {
|
||||
Map keys = new HashMap(16);
|
||||
FileInputStream in = null;
|
||||
try {
|
||||
in = new FileInputStream(persistFilename);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
|
||||
String line = null;
|
||||
while ( (line = reader.readLine()) != null) {
|
||||
int eq = line.indexOf('=');
|
||||
String name = line.substring(0, eq);
|
||||
String privKeys = line.substring(eq+1);
|
||||
keys.put(name, privKeys);
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
_log.warn("Key file does not exist at " + persistFilename);
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Unable to read the keys from " + persistFilename, ioe);
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
nameToPrivKeys = Collections.synchronizedMap(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the current keys to disk in the location specified on creation
|
||||
*
|
||||
*/
|
||||
private synchronized void storeKeys() {
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream(persistFilename);
|
||||
for (Iterator iter = nameToPrivKeys.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
String privKeys = (String)nameToPrivKeys.get(name);
|
||||
out.write(name.getBytes());
|
||||
out.write('=');
|
||||
out.write(privKeys.getBytes());
|
||||
out.write('\n');
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error writing out the SAM keys to " + persistFilename, ioe);
|
||||
} finally {
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
* <pre>SAMBridge [[listenHost ]listenPort[ name=val]*]</pre>
|
||||
@ -72,15 +187,17 @@ public class SAMBridge implements Runnable {
|
||||
* depth, etc.
|
||||
*/
|
||||
public static void main(String args[]) {
|
||||
String keyfile = DEFAULT_SAM_KEYFILE;
|
||||
int port = SAM_LISTENPORT;
|
||||
String host = "0.0.0.0";
|
||||
Properties opts = null;
|
||||
if (args.length > 0) {
|
||||
int portIndex = 0;
|
||||
keyfile = args[0];
|
||||
int portIndex = 1;
|
||||
try {
|
||||
port = Integer.parseInt(args[portIndex]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
host = args[0];
|
||||
host = args[1];
|
||||
portIndex++;
|
||||
try {
|
||||
port = Integer.parseInt(args[portIndex]);
|
||||
@ -91,7 +208,7 @@ public class SAMBridge implements Runnable {
|
||||
}
|
||||
opts = parseOptions(args, portIndex+1);
|
||||
}
|
||||
SAMBridge bridge = new SAMBridge(host, port, opts);
|
||||
SAMBridge bridge = new SAMBridge(host, port, opts, keyfile);
|
||||
I2PThread t = new I2PThread(bridge, "SAMListener");
|
||||
t.start();
|
||||
}
|
||||
@ -114,7 +231,8 @@ public class SAMBridge implements Runnable {
|
||||
}
|
||||
|
||||
private static void usage() {
|
||||
System.err.println("Usage: SAMBridge [listenHost listenPortNum[ name=val]*]");
|
||||
System.err.println("Usage: SAMBridge [keyfile [listenHost] listenPortNum[ name=val]*]");
|
||||
System.err.println(" keyfile: location to persist private keys (default sam.keys)");
|
||||
System.err.println(" listenHost: interface to listen on (0.0.0.0 for all interfaces)");
|
||||
System.err.println(" listenPort: port to listen for SAM connections on (default 7656)");
|
||||
System.err.println(" name=val: options to pass when connecting via I2CP, such as ");
|
||||
@ -140,10 +258,18 @@ public class SAMBridge implements Runnable {
|
||||
} catch (IOException e) {}
|
||||
continue;
|
||||
}
|
||||
handler.setBridge(this);
|
||||
handler.startHandling();
|
||||
} catch (SAMException e) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("SAM error: " + e.getMessage(), e);
|
||||
try {
|
||||
String reply = "HELLO REPLY RESULT=I2P_ERROR MESSAGE=\"" + e.getMessage() + "\"\n";
|
||||
s.getOutputStream().write(reply.getBytes("ISO-8859-1"));
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
_log.error("SAM Error sending error reply", ioe);
|
||||
}
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,14 @@ package net.i2p.sam;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.datagram.I2PDatagramDissector;
|
||||
import net.i2p.client.datagram.I2PDatagramMaker;
|
||||
import net.i2p.client.datagram.I2PInvalidDatagramException;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
@ -30,6 +28,7 @@ import net.i2p.util.Log;
|
||||
public class SAMDatagramSession extends SAMMessageSession {
|
||||
|
||||
private final static Log _log = new Log(SAMDatagramSession.class);
|
||||
public static int DGRAM_SIZE_MAX = 31*1024;
|
||||
|
||||
private SAMDatagramReceiver recv = null;
|
||||
|
||||
@ -43,7 +42,8 @@ public class SAMDatagramSession extends SAMMessageSession {
|
||||
* @param recv Object that will receive incoming data
|
||||
*/
|
||||
public SAMDatagramSession(String dest, Properties props,
|
||||
SAMDatagramReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
||||
SAMDatagramReceiver recv) throws IOException,
|
||||
DataFormatException, I2PSessionException {
|
||||
super(dest, props);
|
||||
|
||||
this.recv = recv;
|
||||
@ -58,7 +58,8 @@ public class SAMDatagramSession extends SAMMessageSession {
|
||||
* @param recv Object that will receive incoming data
|
||||
*/
|
||||
public SAMDatagramSession(InputStream destStream, Properties props,
|
||||
SAMDatagramReceiver recv) throws IOException, DataFormatException, I2PSessionException {
|
||||
SAMDatagramReceiver recv) throws IOException,
|
||||
DataFormatException, I2PSessionException {
|
||||
super(destStream, props);
|
||||
|
||||
this.recv = recv;
|
||||
@ -73,6 +74,9 @@ public class SAMDatagramSession extends SAMMessageSession {
|
||||
* @return True if the data was sent, false otherwise
|
||||
*/
|
||||
public boolean sendBytes(String dest, byte[] data) throws DataFormatException {
|
||||
if (data.length > DGRAM_SIZE_MAX)
|
||||
throw new DataFormatException("Datagram size exceeded (" + data.length + ")");
|
||||
|
||||
byte[] dgram = dgramMaker.makeI2PDatagram(data);
|
||||
|
||||
return sendBytesThroughMessageSession(dest, dgram);
|
||||
|
@ -12,7 +12,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.util.I2PThread;
|
||||
@ -30,6 +29,7 @@ public abstract class SAMHandler implements Runnable {
|
||||
private final static Log _log = new Log(SAMHandler.class);
|
||||
|
||||
protected I2PThread thread = null;
|
||||
protected SAMBridge bridge = null;
|
||||
|
||||
private Object socketWLock = new Object(); // Guards writings on socket
|
||||
private Socket socket = null;
|
||||
@ -71,6 +71,8 @@ public abstract class SAMHandler implements Runnable {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
public void setBridge(SAMBridge bridge) { this.bridge = bridge; }
|
||||
|
||||
/**
|
||||
* Actually handle the SAM protocol.
|
||||
*
|
||||
@ -124,7 +126,9 @@ public abstract class SAMHandler implements Runnable {
|
||||
*
|
||||
*/
|
||||
protected final void closeClientSocket() throws IOException {
|
||||
socket.close();
|
||||
if (socket != null)
|
||||
socket.close();
|
||||
socket = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,8 +9,8 @@ package net.i2p.sam;
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
@ -32,8 +32,8 @@ public class SAMHandlerFactory {
|
||||
*
|
||||
* @param s Socket attached to SAM client
|
||||
* @param i2cpProps config options for our i2cp connection
|
||||
*
|
||||
* @return A SAM protocol handler
|
||||
* @throws SAMException if the connection handshake (HELLO message) was malformed
|
||||
* @return A SAM protocol handler, or null if the client closed before the handshake
|
||||
*/
|
||||
public static SAMHandler createSAMHandler(Socket s, Properties i2cpProps) throws SAMException {
|
||||
BufferedReader br;
|
||||
@ -66,8 +66,8 @@ public class SAMHandlerFactory {
|
||||
{
|
||||
String opcode;
|
||||
if (!(opcode = tok.nextToken()).equals("VERSION")) {
|
||||
throw new SAMException("Unrecognized HELLO message opcode: \""
|
||||
+ opcode + "\"");
|
||||
throw new SAMException("Unrecognized HELLO message opcode: '"
|
||||
+ opcode + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,22 +88,8 @@ public class SAMHandlerFactory {
|
||||
}
|
||||
|
||||
String ver = chooseBestVersion(minVer, maxVer);
|
||||
if (ver == null) {
|
||||
// Let's answer negatively
|
||||
try {
|
||||
OutputStream out = s.getOutputStream();
|
||||
out.write("HELLO REPLY RESULT=NOVERSION\n".getBytes("ISO-8859-1"));
|
||||
return null;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
_log.error("Caught UnsupportedEncodingException ("
|
||||
+ e.getMessage() + ")");
|
||||
throw new SAMException("Character encoding error: "
|
||||
+ e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new SAMException("Error reading from socket: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
if (ver == null)
|
||||
throw new SAMException("No version specified");
|
||||
|
||||
// Let's answer positively
|
||||
try {
|
||||
@ -135,8 +121,8 @@ public class SAMHandlerFactory {
|
||||
throw new SAMException("BUG! (in handler instantiation)");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
_log.error("IOException caught during SAM handler instantiation");
|
||||
return null;
|
||||
_log.error("Error creating the v1 handler", e);
|
||||
throw new SAMException("IOException caught during SAM handler instantiation");
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
@ -9,9 +9,8 @@ package net.i2p.sam;
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.I2PClient;
|
||||
|
@ -8,10 +8,8 @@ package net.i2p.sam;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.client.I2PSessionException;
|
||||
@ -26,6 +24,7 @@ import net.i2p.util.Log;
|
||||
public class SAMRawSession extends SAMMessageSession {
|
||||
|
||||
private final static Log _log = new Log(SAMRawSession.class);
|
||||
public static final int RAW_SIZE_MAX = 32*1024;
|
||||
|
||||
private SAMRawReceiver recv = null;
|
||||
/**
|
||||
@ -64,6 +63,8 @@ public class SAMRawSession extends SAMMessageSession {
|
||||
* @return True if the data was sent, false otherwise
|
||||
*/
|
||||
public boolean sendBytes(String dest, byte[] data) throws DataFormatException {
|
||||
if (data.length > RAW_SIZE_MAX)
|
||||
throw new DataFormatException("Data size limit exceeded (" + data.length + ")");
|
||||
return sendBytesThroughMessageSession(dest, data);
|
||||
}
|
||||
|
||||
|
@ -9,18 +9,19 @@ package net.i2p.sam;
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.util.HashMap;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
@ -29,8 +30,6 @@ import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.util.HexDump;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@ -100,11 +99,23 @@ public class SAMStreamSession {
|
||||
allprops.putAll(System.getProperties());
|
||||
allprops.putAll(props);
|
||||
|
||||
// FIXME: we should setup I2CP host and port, too
|
||||
String i2cpHost = allprops.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
|
||||
int i2cpPort = 7654;
|
||||
String port = allprops.getProperty(I2PClient.PROP_TCP_PORT, "7654");
|
||||
try {
|
||||
i2cpPort = Integer.parseInt(port);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new SAMException("Invalid I2CP port specified [" + port + "]");
|
||||
}
|
||||
// streams MUST be mode=guaranteed (though i think the socket manager
|
||||
// enforces this anyway...
|
||||
allprops.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED);
|
||||
|
||||
_log.debug("Creating I2PSocketManager...");
|
||||
socketMgr = I2PSocketManagerFactory.createManager(destStream,
|
||||
"127.0.0.1",
|
||||
7654, allprops);
|
||||
i2cpHost,
|
||||
i2cpPort,
|
||||
allprops);
|
||||
if (socketMgr == null) {
|
||||
throw new SAMException("Error creating I2PSocketManager");
|
||||
}
|
||||
|
@ -8,18 +8,17 @@ package net.i2p.sam;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
@ -84,7 +83,7 @@ public class SAMUtils {
|
||||
* @return the Destination for the specified hostname, or null if not found
|
||||
*/
|
||||
public static Destination lookupHost(String name, OutputStream pubKey) {
|
||||
NamingService ns = NamingService.getInstance();
|
||||
NamingService ns = I2PAppContext.getGlobalContext().namingService();
|
||||
Destination dest = ns.lookup(name);
|
||||
|
||||
if ((pubKey != null) && (dest != null)) {
|
||||
@ -107,9 +106,10 @@ public class SAMUtils {
|
||||
*
|
||||
* @param tok A StringTokenizer pointing to the SAM parameters
|
||||
*
|
||||
* @return Properties with the parsed SAM params, or null if none is found
|
||||
* @throws SAMException if the data was formatted incorrectly
|
||||
* @return Properties with the parsed SAM params
|
||||
*/
|
||||
public static Properties parseParams(StringTokenizer tok) {
|
||||
public static Properties parseParams(StringTokenizer tok) throws SAMException {
|
||||
int pos, nprops = 0, ntoks = tok.countTokens();
|
||||
String token, param, value;
|
||||
Properties props = new Properties();
|
||||
@ -120,7 +120,7 @@ public class SAMUtils {
|
||||
pos = token.indexOf("=");
|
||||
if (pos == -1) {
|
||||
_log.debug("Error in params format");
|
||||
return null;
|
||||
throw new SAMException("Bad formatting for param [" + token + "]");
|
||||
}
|
||||
param = token.substring(0, pos);
|
||||
value = token.substring(pos + 1);
|
||||
@ -133,22 +133,18 @@ public class SAMUtils {
|
||||
_log.debug("Parsed properties: " + dumpProperties(props));
|
||||
}
|
||||
|
||||
if (nprops != 0) {
|
||||
return props;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
/* Dump a Properties object in an human-readable form */
|
||||
private static String dumpProperties(Properties props) {
|
||||
Enumeration enum = props.propertyNames();
|
||||
Enumeration names = props.propertyNames();
|
||||
String msg = "";
|
||||
String key, val;
|
||||
boolean firstIter = true;
|
||||
|
||||
while (enum.hasMoreElements()) {
|
||||
key = (String)enum.nextElement();
|
||||
while (names.hasMoreElements()) {
|
||||
key = (String)names.nextElement();
|
||||
val = props.getProperty(key);
|
||||
|
||||
if (!firstIter) {
|
||||
|
@ -8,27 +8,24 @@ package net.i2p.sam;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.util.Enumeration;
|
||||
import java.net.Socket;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@ -108,7 +105,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
break;
|
||||
}
|
||||
|
||||
msg = buf.toString("ISO-8859-1");
|
||||
msg = buf.toString("ISO-8859-1").trim();
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug("New message received: " + msg);
|
||||
}
|
||||
@ -127,8 +124,6 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
+ "\"; opcode: \"" + opcode + "\")");
|
||||
}
|
||||
props = SAMUtils.parseParams(tok);
|
||||
if (i2cpProps != null)
|
||||
props.putAll(i2cpProps); // make sure we've got the i2cp settings
|
||||
|
||||
if (domain.equals("STREAM")) {
|
||||
canContinue = execStreamMessage(opcode, props);
|
||||
@ -137,6 +132,8 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
} else if (domain.equals("RAW")) {
|
||||
canContinue = execRawMessage(opcode, props);
|
||||
} else if (domain.equals("SESSION")) {
|
||||
if (i2cpProps != null)
|
||||
props.putAll(i2cpProps); // make sure we've got the i2cp settings
|
||||
canContinue = execSessionMessage(opcode, props);
|
||||
} else if (domain.equals("DEST")) {
|
||||
canContinue = execDestMessage(opcode, props);
|
||||
@ -154,10 +151,10 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
_log.error("Caught UnsupportedEncodingException ("
|
||||
+ e.getMessage() + ")");
|
||||
+ e.getMessage() + ")", e);
|
||||
} catch (IOException e) {
|
||||
_log.debug("Caught IOException ("
|
||||
+ e.getMessage() + ")");
|
||||
+ e.getMessage() + ")", e);
|
||||
} catch (Exception e) {
|
||||
_log.error("Unexpected exception", e);
|
||||
} finally {
|
||||
@ -189,76 +186,91 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
if ((rawSession != null) || (datagramSession != null)
|
||||
|| (streamSession != null)) {
|
||||
_log.debug("Trying to create a session, but one still exists");
|
||||
return false;
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Session already exists\"\n");
|
||||
}
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in SESSION CREATE message");
|
||||
return false;
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No parameters for SESSION CREATE\"\n");
|
||||
}
|
||||
|
||||
dest = props.getProperty("DESTINATION");
|
||||
if (dest == null) {
|
||||
_log.debug("SESSION DESTINATION parameter not specified");
|
||||
return false;
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"DESTINATION not specified\"\n");
|
||||
}
|
||||
props.remove("DESTINATION");
|
||||
|
||||
|
||||
String destKeystream = null;
|
||||
|
||||
if (dest.equals("TRANSIENT")) {
|
||||
_log.debug("TRANSIENT destination requested");
|
||||
ByteArrayOutputStream priv = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream priv = new ByteArrayOutputStream(640);
|
||||
SAMUtils.genRandomKey(priv, null);
|
||||
|
||||
dest = Base64.encode(priv.toByteArray());
|
||||
destKeystream = Base64.encode(priv.toByteArray());
|
||||
} else {
|
||||
destKeystream = bridge.getKeystream(dest);
|
||||
if (destKeystream == null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Custom destination specified [" + dest + "] but it isnt know, creating a new one");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(640);
|
||||
SAMUtils.genRandomKey(baos, null);
|
||||
destKeystream = Base64.encode(baos.toByteArray());
|
||||
bridge.addKeystream(dest, destKeystream);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Custom destination specified [" + dest + "] and it is already known");
|
||||
}
|
||||
}
|
||||
|
||||
String style = props.getProperty("STYLE");
|
||||
if (style == null) {
|
||||
_log.debug("SESSION STYLE parameter not specified");
|
||||
return false;
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"No SESSION STYLE specified\"\n");
|
||||
}
|
||||
props.remove("STYLE");
|
||||
|
||||
if (style.equals("RAW")) {
|
||||
rawSession = new SAMRawSession(dest, props, this);
|
||||
rawSession = new SAMRawSession(destKeystream, props, this);
|
||||
} else if (style.equals("DATAGRAM")) {
|
||||
datagramSession = new SAMDatagramSession(dest, props,this);
|
||||
datagramSession = new SAMDatagramSession(destKeystream, props,this);
|
||||
} else if (style.equals("STREAM")) {
|
||||
String dir = props.getProperty("DIRECTION");
|
||||
if (dir == null) {
|
||||
_log.debug("No DIRECTION parameter in STREAM session");
|
||||
return false;
|
||||
_log.debug("No DIRECTION parameter in STREAM session, defaulting to BOTH");
|
||||
dir = "BOTH";
|
||||
}
|
||||
if (!dir.equals("CREATE") && !dir.equals("RECEIVE")
|
||||
&& !dir.equals("BOTH")) {
|
||||
_log.debug("Unknow DIRECTION parameter value: " + dir);
|
||||
return false;
|
||||
_log.debug("Unknow DIRECTION parameter value: [" + dir + "]");
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unknown DIRECTION parameter\"\n");
|
||||
}
|
||||
props.remove("DIRECTION");
|
||||
|
||||
streamSession = new SAMStreamSession(dest, dir,props,this);
|
||||
streamSession = new SAMStreamSession(destKeystream, dir,props,this);
|
||||
} else {
|
||||
_log.debug("Unrecognized SESSION STYLE: \"" + style +"\"");
|
||||
return false;
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized SESSION STYLE\"\n");
|
||||
}
|
||||
return writeString("SESSION STATUS RESULT=OK DESTINATION="
|
||||
+ dest + "\n");
|
||||
} else {
|
||||
_log.debug("Unrecognized SESSION message opcode: \""
|
||||
+ opcode + "\"");
|
||||
return false;
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR MESSAGE=\"Unrecognized opcode\"\n");
|
||||
}
|
||||
} catch (DataFormatException e) {
|
||||
_log.debug("Invalid destination specified");
|
||||
return writeString("SESSION STATUS RESULT=INVALID_KEY DESTINATION=" + dest + "\n");
|
||||
return writeString("SESSION STATUS RESULT=INVALID_KEY DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
|
||||
} catch (I2PSessionException e) {
|
||||
_log.debug("I2P error when instantiating session", e);
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + "\n");
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
|
||||
} catch (SAMException e) {
|
||||
_log.error("Unexpected SAM error", e);
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + "\n");
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
|
||||
} catch (IOException e) {
|
||||
_log.error("Unexpected IOException", e);
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + "\n");
|
||||
return writeString("SESSION STATUS RESULT=I2P_ERROR DESTINATION=" + dest + " MESSAGE=\"" + e.getMessage() + "\"\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +278,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
private boolean execDestMessage(String opcode, Properties props) {
|
||||
|
||||
if (opcode.equals("GENERATE")) {
|
||||
if (props != null) {
|
||||
if (props.size() > 0) {
|
||||
_log.debug("Properties specified in DEST GENERATE message");
|
||||
return false;
|
||||
}
|
||||
@ -318,7 +330,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
|
||||
if (dest == null) {
|
||||
return writeString("NAMING REPLY RESULT=KEY_NOT_FOUND\n");
|
||||
return writeString("NAMING REPLY RESULT=KEY_NOT_FOUND NAME=" + name + "\n");
|
||||
}
|
||||
|
||||
return writeString("NAMING REPLY RESULT=OK NAME=" + name
|
||||
@ -380,7 +392,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
|
||||
if (!datagramSession.sendBytes(dest, data)) {
|
||||
_log.error("DATAGRAM SEND failed");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -451,7 +463,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
|
||||
if (!rawSession.sendBytes(dest, data)) {
|
||||
_log.error("RAW SEND failed");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -483,159 +495,173 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
}
|
||||
|
||||
if (opcode.equals("SEND")) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
|
||||
int id;
|
||||
{
|
||||
String strid = props.getProperty("ID");
|
||||
if (strid == null) {
|
||||
_log.debug("ID not specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
id = Integer.parseInt(strid);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM SEND ID specified: " + strid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int size;
|
||||
{
|
||||
String strsize = props.getProperty("SIZE");
|
||||
if (strsize == null) {
|
||||
_log.debug("Size not specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
size = Integer.parseInt(strsize);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM SEND size specified: "+strsize);
|
||||
return false;
|
||||
}
|
||||
if (!checkSize(size)) {
|
||||
_log.debug("Specified size (" + size
|
||||
+ ") is out of protocol limits");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
DataInputStream in = new DataInputStream(getClientSocketInputStream());
|
||||
byte[] data = new byte[size];
|
||||
|
||||
in.readFully(data);
|
||||
|
||||
if (!streamSession.sendBytes(id, data)) {
|
||||
_log.error("STREAM SEND failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (EOFException e) {
|
||||
_log.debug("Too few bytes with RAW SEND message (expected: "
|
||||
+ size);
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
_log.debug("Caught IOException while parsing RAW SEND message",
|
||||
e);
|
||||
return false;
|
||||
}
|
||||
return execStreamSend(props);
|
||||
} else if (opcode.equals("CONNECT")) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM CONNECT message");
|
||||
return false;
|
||||
}
|
||||
|
||||
int id;
|
||||
{
|
||||
String strid = props.getProperty("ID");
|
||||
if (strid == null) {
|
||||
_log.debug("ID not specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
id = Integer.parseInt(strid);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM CONNECT ID specified: " +strid);
|
||||
return false;
|
||||
}
|
||||
if (id < 1) {
|
||||
_log.debug("Invalid STREAM CONNECT ID specified: " +strid);
|
||||
return false;
|
||||
}
|
||||
props.remove("ID");
|
||||
}
|
||||
|
||||
String dest = props.getProperty("DESTINATION");
|
||||
if (dest == null) {
|
||||
_log.debug("Destination not specified in RAW SEND message");
|
||||
return false;
|
||||
}
|
||||
props.remove("DESTINATION");
|
||||
|
||||
try {
|
||||
if (!streamSession.connect(id, dest, props)) {
|
||||
_log.debug("STREAM connection failed");
|
||||
return false;
|
||||
}
|
||||
return writeString("STREAM STATUS RESULT=OK ID=" + id + "\n");
|
||||
} catch (DataFormatException e) {
|
||||
_log.debug("Invalid destination in STREAM CONNECT message");
|
||||
return writeString("STREAM STATUS RESULT=INVALID_KEY ID="
|
||||
+ id + "\n");
|
||||
} catch (SAMInvalidDirectionException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=INVALID_DIRECTION ID="
|
||||
+ id + "\n");
|
||||
} catch (ConnectException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=CONNECTION_REFUSED ID="
|
||||
+ id + "\n");
|
||||
} catch (NoRouteToHostException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=CANT_REACH_PEER ID="
|
||||
+ id + "\n");
|
||||
} catch (InterruptedIOException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=TIMEOUT ID="
|
||||
+ id + "\n");
|
||||
} catch (I2PException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=I2P_ERROR ID="
|
||||
+ id + "\n");
|
||||
}
|
||||
return execStreamConnect(props);
|
||||
} else if (opcode.equals("CLOSE")) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM CLOSE message");
|
||||
return false;
|
||||
}
|
||||
|
||||
int id;
|
||||
{
|
||||
String strid = props.getProperty("ID");
|
||||
if (strid == null) {
|
||||
_log.debug("ID not specified in STREAM CLOSE message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
id = Integer.parseInt(strid);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM CLOSE ID specified: " +strid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return streamSession.closeConnection(id);
|
||||
return execStreamClose(props);
|
||||
} else {
|
||||
_log.debug("Unrecognized RAW message opcode: \""
|
||||
+ opcode + "\"");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean execStreamSend(Properties props) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
|
||||
int id;
|
||||
{
|
||||
String strid = props.getProperty("ID");
|
||||
if (strid == null) {
|
||||
_log.debug("ID not specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
id = Integer.parseInt(strid);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM SEND ID specified: " + strid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int size;
|
||||
{
|
||||
String strsize = props.getProperty("SIZE");
|
||||
if (strsize == null) {
|
||||
_log.debug("Size not specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
size = Integer.parseInt(strsize);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM SEND size specified: "+strsize);
|
||||
return false;
|
||||
}
|
||||
if (!checkSize(size)) {
|
||||
_log.debug("Specified size (" + size
|
||||
+ ") is out of protocol limits");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
DataInputStream in = new DataInputStream(getClientSocketInputStream());
|
||||
byte[] data = new byte[size];
|
||||
|
||||
in.readFully(data);
|
||||
|
||||
if (!streamSession.sendBytes(id, data)) {
|
||||
_log.error("STREAM SEND failed");
|
||||
boolean rv = writeString("STREAM CLOSED RESULT=CANT_REACH_PEER ID=" + id + " MESSAGE=\"Send of " + size + " bytes failed\"\n");
|
||||
streamSession.closeConnection(id);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (EOFException e) {
|
||||
_log.debug("Too few bytes with RAW SEND message (expected: "
|
||||
+ size);
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
_log.debug("Caught IOException while parsing RAW SEND message",
|
||||
e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean execStreamConnect(Properties props) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM CONNECT message");
|
||||
return false;
|
||||
}
|
||||
|
||||
int id;
|
||||
{
|
||||
String strid = props.getProperty("ID");
|
||||
if (strid == null) {
|
||||
_log.debug("ID not specified in STREAM SEND message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
id = Integer.parseInt(strid);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM CONNECT ID specified: " +strid);
|
||||
return false;
|
||||
}
|
||||
if (id < 1) {
|
||||
_log.debug("Invalid STREAM CONNECT ID specified: " +strid);
|
||||
return false;
|
||||
}
|
||||
props.remove("ID");
|
||||
}
|
||||
|
||||
String dest = props.getProperty("DESTINATION");
|
||||
if (dest == null) {
|
||||
_log.debug("Destination not specified in RAW SEND message");
|
||||
return false;
|
||||
}
|
||||
props.remove("DESTINATION");
|
||||
|
||||
try {
|
||||
if (!streamSession.connect(id, dest, props)) {
|
||||
_log.debug("STREAM connection failed");
|
||||
return false;
|
||||
}
|
||||
return writeString("STREAM STATUS RESULT=OK ID=" + id + "\n");
|
||||
} catch (DataFormatException e) {
|
||||
_log.debug("Invalid destination in STREAM CONNECT message");
|
||||
return writeString("STREAM STATUS RESULT=INVALID_KEY ID="
|
||||
+ id + "\n");
|
||||
} catch (SAMInvalidDirectionException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=INVALID_DIRECTION ID="
|
||||
+ id + "\n");
|
||||
} catch (ConnectException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=CONNECTION_REFUSED ID="
|
||||
+ id + "\n");
|
||||
} catch (NoRouteToHostException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=CANT_REACH_PEER ID="
|
||||
+ id + "\n");
|
||||
} catch (InterruptedIOException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=TIMEOUT ID="
|
||||
+ id + "\n");
|
||||
} catch (I2PException e) {
|
||||
_log.debug("STREAM CONNECT failed: " + e.getMessage());
|
||||
return writeString("STREAM STATUS RESULT=I2P_ERROR ID="
|
||||
+ id + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean execStreamClose(Properties props) {
|
||||
if (props == null) {
|
||||
_log.debug("No parameters specified in STREAM CLOSE message");
|
||||
return false;
|
||||
}
|
||||
|
||||
int id;
|
||||
{
|
||||
String strid = props.getProperty("ID");
|
||||
if (strid == null) {
|
||||
_log.debug("ID not specified in STREAM CLOSE message");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
id = Integer.parseInt(strid);
|
||||
} catch (NumberFormatException e) {
|
||||
_log.debug("Invalid STREAM CLOSE ID specified: " +strid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return streamSession.closeConnection(id);
|
||||
}
|
||||
|
||||
/* Check whether a size is inside the limits allowed by this protocol */
|
||||
private boolean checkSize(int size) {
|
||||
@ -734,7 +760,7 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
|
||||
|
||||
msg.write(("STREAM RECEIVED ID=" + id
|
||||
+" SIZE=" + len + "\n").getBytes("ISO-8859-1"));
|
||||
msg.write(data);
|
||||
msg.write(data, 0, len);
|
||||
|
||||
writeBytes(msg.toByteArray());
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user