Compare commits

...

77 Commits

Author SHA1 Message Date
5d4bdc5697 0.3.4 NOT BACKWARDS COMPATIBLE
(0.3.4 and not 0.3.3.1 since its got some major revamps)
to be released later today.  dont upgrade until the release announcement comes out
2004-07-29 21:37:18 +00:00
0fdb286005 added some comments wrt rate limiting and getting the proxies to be reachable remotely 2004-07-29 21:34:55 +00:00
59a8493aa7 fixed some URLs, and the irc proxy is loaded on startup 2004-07-29 21:29:02 +00:00
25378e894b less aggressive removal of peer references
logging
2004-07-29 20:36:44 +00:00
3b9fea20b6 added files.hypercubus.i2p 2004-07-29 20:07:54 +00:00
c6bb8f09ca avoid the race that could corrupt local transfers by using a single thread to receive notifications of message availability (and in turn fetch that data)
the old way fired off a new (very short lived) thread for each message received, and if two happened really really quickly, they'd both lock on the mutex and the order would be undefined
this avoids that.  thanks to oOo et al for pestering me and sending in logs :)
2004-07-29 20:02:12 +00:00
4a9bd84bf0 check the delivery order and call out an error if a pong comes back in the wrong order 2004-07-29 16:12:36 +00:00
c02522b0fe * track the message progress through the send process more carefully
* drop the outbound message as soon as it expires rather than transferring an expired message
* drop hard any outbound message that takes us over 5 seconds to process (if we have a 5s message processing time, we do no one any good)
* don't try to resend (only useful when dealing with multiple transports - aka insufficiently tested code)
* don't republish netDb messages as often
2004-07-29 05:37:10 +00:00
c2a71ef756 include stats on bytes wasted (overflow from the buckets) 2004-07-28 23:35:48 +00:00
e669110cf4 be sure to allow for clock skew 2004-07-28 23:34:42 +00:00
f4cf31c13d less aggressive passive publishing 2004-07-28 23:34:02 +00:00
7b23a5dcce keep track of wasted bytes (overflow from the bucket) 2004-07-28 23:32:51 +00:00
b2fda0c79d catch errors earlier 2004-07-28 23:29:21 +00:00
5af96f5ccb when we really need tunnels, always build them 2004-07-28 23:28:55 +00:00
ca445ac178 when we need tunnels, always build 2, not the exact quantity required (so that its a bit smoother) 2004-07-28 23:27:46 +00:00
mpc
16fb31b6eb doc update 2004-07-28 04:50:44 +00:00
mpc
a1ff325b7b Improve sendq to always send big packets for better network performance 2004-07-28 04:48:35 +00:00
5eaec4c841 only recurse one time 2004-07-28 03:51:38 +00:00
ffcc34c4f9 heh, if it expires, we probably don't want to forward it (duh) 2004-07-28 03:50:30 +00:00
2dbe33e769 * cleaned up the tunnelCreate reply timeout
* reduced the number of tags passed when garlic routing a tunnelCreate
* catch timeout on a tunnel message quicker
* give a tunnel message a new messageId per hop
* added some more infrastructure for per-hop tunnelId
2004-07-28 00:08:15 +00:00
60c7db0733 if I'm making this backwards incompatible, I might as well clean up the rest, 'eh?
* removed SourceRouteBlock & SourceRouteReplyMessage, as they're a redundant concept
that 1) takes up bandwidth 2) takes up CPU 3) smell funny.
now the TunnelCreateMessage includes a replyTag, replyKey, replyTunnel, and
replyGateway that they garlic encrypt their ACK/NACK through and with.

* tunnelCreateMessage doesn't need a seperate ACK - either we get a
TunnelCreateStatusMessage back or we don't.

* message structure mods for unique tunnel ID per hop (though currently all hops have
the same tunnel ID)
2004-07-27 22:04:02 +00:00
0ed95bbdf1 new helper to read/write 2004-07-27 21:45:56 +00:00
c901bcf9b7 javadoc warning fix 2004-07-27 17:41:40 +00:00
0ccf915a18 ewps 2004-07-27 17:39:52 +00:00
52b1c0a926 * netDb searchReply and lookup messages now contain H(peer), not the peer's full RouterInfo
(making a searchReply message ~100 bytes, down from ~30KB, and the lookup message ~64 bytes, down from ~10KB)
* when we get the netDb searchReply or lookup message referencing someone we don't know,
we fire off a lookup for them
* reduced some excessive padding
* dropped the DbSearchReplyMessageHandler, since it shouldn't be used (all search replies
should be handled by a MessageSelector built by the original search message)
* removed some oddball constructors from the SendMessageDirectJob and SendTunnelMessageJob (always must specify a timeout)
* refactored SendTunnelMessageJob main handler method into smaller logical methods
2004-07-27 17:34:36 +00:00
399865e6c8 increase the replenish frequency to occur every .1s
logging
2004-07-27 17:20:42 +00:00
54aeab1524 send the full RouterInfo in the STS validation, not just the RouterIdentity (and in turn, store that RouterInfo in the local netDb)
logging
2004-07-27 17:17:16 +00:00
91f83277e2 made incompatible with previous releases - the remaining commits before the next rev are NOT BACKWARDS COMPATIBLE
do NOT update until the next release
2004-07-27 17:15:55 +00:00
c937cb2f07 no need to test a peer that we already know is up 2004-07-27 06:34:30 +00:00
ebd150e473 we don't need to build a tunnel so often (just enough to keep things fresh)
cleaned up rebuild / verification process so that the select*TunnelIds will always return what is necessary
for the moment, don't automatically kill all tunnels of a peer who fails just once (they can recover)
logging
2004-07-27 06:19:44 +00:00
9218f7b82c deal with not having tunnels a bit earlier 2004-07-25 23:51:07 +00:00
edaf7aee5d * for the moment, remove the 'isFailing' check for peers who have failing tunnels
(we need a more sophisticated algorithm than the one in place for it to be effective)
* fix for the profileOrganizer to work safely in the sim
2004-07-25 23:46:55 +00:00
43c18d0f4d (techincally) reduced the minimum bandwidth rate to 1KBps, but NO ONE SHOULD SET IT THAT LOW. do not reduce your limits below 6KBps until More Stuff Gets Done.
logging
2004-07-25 23:43:13 +00:00
65d85f7479 the vast majority of messages on the live net are under 2KB 2004-07-25 23:40:08 +00:00
476e23db5b new stat monitoring the netDb search reply message sizes 2004-07-25 23:35:50 +00:00
abaa5d87f6 more efficient mem alloc & usage 2004-07-25 23:33:54 +00:00
ce3e7e623c handle disconnect while there are still requests pending 2004-07-24 17:54:49 +00:00
mpc
3fd35a9c18 *** empty log message *** 2004-07-24 03:31:24 +00:00
f170ae741e 0.3.3, backwards compatible, to be released Real Soon 2004-07-24 02:13:37 +00:00
03562b037d added (commented out) hooks for the 0.4 web arch 2004-07-24 02:11:22 +00:00
472312709a added ref for the 0.4 routerconsole stuff, but its not ready for use, so, er, dont use it 2004-07-24 02:08:21 +00:00
b68463249e first pass at the 0.4 architecture. not ready for use or integration yet, but is functional with some manual build/config work 2004-07-24 02:06:07 +00:00
740a2da702 more consistent html 2004-07-24 01:59:27 +00:00
85c8e56417 fixed a strange bug when the .wait delay is really accurate (too accurrate..). thanks ZeroCool for help debugging this! 2004-07-24 01:10:11 +00:00
481ef56e74 added www1.squid.i2p 2004-07-23 21:22:51 +00:00
008795770f allow the timestamper to be started up while disabled 2004-07-23 18:19:40 +00:00
834fb7e317 allow the timestamper to be controlled by env properties (and, in turn, safe to always run)
if/when the property "timestamper.enabled" is set, the timestamper will query the sntp server(s) and update the clock accordingly
if/when it is not set (or set to something other than "true"), it will pause with its standard delay before checking again
in addition, it has a guard to help running the timestamper multiple times in the same JVM
2004-07-23 17:43:45 +00:00
da4827f287 expose some data for the router console to query 2004-07-23 17:39:31 +00:00
9f4439583d expose some data points for the new console, and cleaned up some html
new piece of data exposed and maintained is a list of router contexts - shown as a singleton off RouterContext - allowing an app in the same JVM to find the routers (and chose between which one they want)
2004-07-23 17:36:29 +00:00
mpc
69981e4d78 *** empty log message *** 2004-07-23 03:08:20 +00:00
mpc
a857c6a88f *** empty log message *** 2004-07-23 00:10:59 +00:00
mpc
e8d19439f8 *** empty log message *** 2004-07-22 08:54:01 +00:00
56216250a7 Added doc sources (public domain) 2004-07-21 12:02:56 +00:00
bea331db26 Fixed typo (public domain) 2004-07-21 11:56:36 +00:00
bc4e833a47 Fix install path 2004-07-21 11:36:23 +00:00
mpc
83f399fffc hopefully i'll have time to work on this socket stuff tomorrow 2004-07-21 10:24:22 +00:00
5214436d18 initial import of Connelly's public domain I2P python lib 2004-07-21 07:42:29 +00:00
8603250d73 updated the readme to reference the current specs and implementations
removed the old out of date jython and python code
2004-07-21 06:25:44 +00:00
9a8a099701 javadoc fix 2004-07-20 21:43:42 +00:00
a5a0c8c837 moved minimal I2CP info to the I2PSession docs (since it is the one that implements it) 2004-07-20 21:31:57 +00:00
604bcd5874 initial impl 2004-07-20 21:28:28 +00:00
d29f9409bf include some basic I2CP info 2004-07-20 21:16:30 +00:00
b5a0f5910d first pass 2004-07-20 21:08:04 +00:00
ccb2600e67 when measuring capacity, consider data updated within the last hour as good, not just the last 5 minutes 2004-07-20 04:11:33 +00:00
f06e21ff5a null check (oops) 2004-07-20 04:10:33 +00:00
bb0817a2ec erg, expose the capacity calculator
(the last Router commit is a mod that ugha requested, but i think its ugly so its disabled atm)
2004-07-20 03:35:36 +00:00
6911f865ca expose the capacity calculator 2004-07-20 03:34:52 +00:00
fe28b2732c simple error condition check 2004-07-20 03:28:43 +00:00
e8e8c37496 * implement new 'capacity' concept, which replaces the old 'reliability'
one for peer selection and organization.  reliability is kept around
  for the moment and shown on the router console, but only to provide a
  comparison (it is not used in any way)
* new stat in the TunnelHistory: failRate
* coallesce TunnelHistory stats (duh!)
* new ProfileOrganizer CLI ("ProfileOrganizer[ filename]*"
* implement reasonable 'failure' logic - if they are actively rejecting
  tunnels or tunnels they've agreed to are failing, mark them as failing
* when choosing peers to test, exclude all fast ones
2004-07-20 03:27:34 +00:00
ef0f1ca1e7 include a lil more eye candy on the console (how active each tunnel is and last test time) 2004-07-20 02:57:55 +00:00
31ca34b954 rate.getAverageValue returns the average of the last fully completed period, but we want to include the current partial period as well 2004-07-20 02:53:41 +00:00
c4e6a2f0a8 if the log pattern/path referenced doesn't exist, create all necessary parent directories (killing the JVM if it fails, rather than silently gobble the log messages to /dev/null) 2004-07-19 17:18:49 +00:00
b56845e200 added quadn.i2p 2004-07-18 21:35:13 +00:00
d7a1fee781 closing a stream multiple times shouldn't kill the SAM session (thanks for the bug report Connelly) 2004-07-18 15:02:54 +00:00
mpc
b1f802c42d Add id tag to strl 2004-07-17 08:18:16 +00:00
mpc
5f022e6e1f minor code cleanup 2004-07-17 04:54:45 +00:00
mpc
392cbb817e cleaned up time class 2004-07-17 03:11:20 +00:00
200 changed files with 9071 additions and 10469 deletions

View File

@ -26,13 +26,11 @@
* 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.
*
* $Id$
*/
#include <cstdarg>
#include <cstdio>
#include <iostream>
#include <string>
using namespace std;
#include "platform.hpp"
#include "mutex.hpp"
#include "time.hpp"
#include "logger.hpp"
@ -41,10 +39,10 @@ using namespace Libsockthread;
/*
* Closes the log file
*/
void Logger::close(void)
void Logger::close()
{
logf_m.lock();
if (logf == 0) {
if (logf == NULL) {
logf_m.unlock();
return;
}
@ -53,7 +51,7 @@ void Logger::close(void)
cerr << "fclose() failed: " << strerror(errno) << '\n';
cerr_m.unlock();
}
logf = 0;
logf = NULL;
logf_m.unlock();
}
@ -88,15 +86,14 @@ void Logger::log(priority_t priority, const char* format, ...)
va_list ap;
va_start(ap, format);
string s;
Time t;
logf_m.lock();
if (logf != 0) {
if (logf != NULL) {
/*
* Remember! If you change the format here, change it in the else too
*/
fprintf(logf, "%c %s ", ll, t.utc(s).c_str());
fprintf(logf, "%c %s ", ll, t.utc().c_str());
vfprintf(logf, format, ap);
fputc('\n', logf);
if (fflush(logf) == EOF) {
@ -106,7 +103,7 @@ void Logger::log(priority_t priority, const char* format, ...)
}
} else {
// if they don't have an open log file, just use stderr
fprintf(stderr, "%c %s ", ll, t.utc(s).c_str());
fprintf(stderr, "%c %s ", ll, t.utc().c_str());
vfprintf(stderr, format, ap);
fputc('\n', stderr);
}
@ -118,8 +115,8 @@ void Logger::log(priority_t priority, const char* format, ...)
}
/*
* Opens a log file for appending. If there already is an open log file, then
* it is closed and the new one is opened.
* Opens a log file for appending. If a log file is already open, then it is
* closed and the new one is opened.
*
* file - file location to open
*/
@ -145,8 +142,8 @@ bool Logger::open(const string& file)
// g++ -Wall -c mutex.cpp -o mutex.o
// g++ -Wall -c time.cpp -o time.o
// g++ -Wall -DUNIT_TEST -c logger.cpp -o logger.o
// g++ -Wall -DUNIT_TEST logger.o mutex.o thread.o time.o -o logger -lpthread
int main(void)
// g++ -Wall -DUNIT_TEST logger.o mutex.o thread.o time.o -o logger -pthread
int main()
{
Logger logger;

View File

@ -26,6 +26,8 @@
* 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.
*
* $Id$
*/
#ifndef LIBSOCKTHREAD_LOGGER_HPP
@ -40,8 +42,7 @@
* LWARN - errors we automatically recover from
* LERROR - major, important errors
*
* Obviously, these only work if your Logger object is called "logger" and is
* global
* These only work if your Logger object is called "logger"
*/
// Prints out the file name, function name, and line number before the message
#define LDEBUG(format, ...) logger.log(Logger::DEBUG, "%s:%s:%d:" \
@ -69,16 +70,17 @@
namespace Libsockthread {
class Logger {
public:
typedef enum {DEBUG = 0, MINOR = 1, INFO = 2, WARN = 3, ERROR = 4}
priority_t;
enum priority_t {DEBUG = 0, MINOR = 1, INFO = 2, WARN = 3,
ERROR = 4};
Logger(void)
: logf(0), loglevel(Logger::DEBUG) { }
~Logger(void) { close(); }
Logger()
: logf(NULL), loglevel(Logger::DEBUG) { }
~Logger()
{ close(); }
void close(void);
void close();
void log(priority_t priority, const char* format, ...);
priority_t get_loglevel(void)
priority_t get_loglevel()
{ loglevel_m.lock(); priority_t ll = loglevel;
loglevel_m.unlock(); return ll; }
bool open(const string& file);

View File

@ -26,31 +26,28 @@
* 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.
*
* $Id$
*/
// Modelled after JThread by Jori Liesenborgs
/*
* Modelled after JThread by Jori Liesenborgs
*/
#include <cassert>
#include "platform.hpp"
#ifdef WINTHREAD
#include <windows.h>
#else
#include <pthread.h>
#endif
using namespace std;
#include "mutex.hpp"
using namespace Libsockthread;
/*
* Creates a mutex
*/
Mutex::Mutex(void)
Mutex::Mutex()
{
#ifdef WINTHREAD
mutex = CreateMutex(0, false, 0);
assert(mutex != 0);
mutex = CreateMutex(NULL, false, NULL);
assert(mutex != NULL);
#else
int rc = pthread_mutex_init(&mutex, 0);
int rc = pthread_mutex_init(&mutex, NULL);
assert(rc == 0);
#endif
}
@ -58,7 +55,7 @@ Mutex::Mutex(void)
/*
* Destroys a mutex
*/
Mutex::~Mutex(void)
Mutex::~Mutex()
{
#ifdef WINTHREAD
BOOL rc = CloseHandle(mutex);
@ -72,7 +69,7 @@ Mutex::~Mutex(void)
/*
* Locks the mutex
*/
void Mutex::lock(void)
void Mutex::lock()
{
#ifdef WINTHREAD
DWORD rc = WaitForSingleObject(mutex, INFINITE);
@ -86,7 +83,7 @@ void Mutex::lock(void)
/*
* Unlocks the mutex
*/
void Mutex::unlock(void)
void Mutex::unlock()
{
#ifdef WINTHREAD
BOOL rc = ReleaseMutex(mutex);
@ -100,13 +97,12 @@ void Mutex::unlock(void)
#ifdef UNIT_TEST
// g++ -Wall -c thread.cpp -o thread.o
// g++ -Wall -DUNIT_TEST -c mutex.cpp -o mutex.o
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o mutex -lpthread
#include <iostream>
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o mutex -pthread
#include "thread.hpp"
Mutex widget;
int main(void)
int main()
{
class Mutex_test : public Thread
{
@ -114,7 +110,7 @@ int main(void)
Mutex_test(int n)
: testval(n) {}
void* thread(void)
void* thread()
{
widget.lock();
cout << "I got it! thread #" << testval << '\n';
@ -122,9 +118,11 @@ int main(void)
// widget, since it is never unlocked
return 0;
}
private:
int testval;
};
Mutex_test t1(1);
Mutex_test t2(2);
Mutex_test t3(3);

View File

@ -26,9 +26,13 @@
* 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.
*
* $Id$
*/
// Modelled after JThread by Jori Liesenborgs
/*
* Modelled after JThread by Jori Liesenborgs
*/
#ifndef LIBSOCKTHREAD_MUTEX_HPP
#define LIBSOCKTHREAD_MUTEX_HPP
@ -36,11 +40,11 @@
namespace Libsockthread {
class Mutex {
public:
Mutex(void);
~Mutex(void);
Mutex();
~Mutex();
void lock(void);
void unlock(void);
void lock();
void unlock();
private:
#ifdef WINTHREAD
HANDLE mutex;

View File

@ -26,6 +26,14 @@
* 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.
*
* $Id: platform.hpp,v 1.5 2004/07/22 03:54:01 mpc Exp $
*/
/*
* Global includes and platform configuration. This is used to compile the
* library, but is not intended for use by users of the library in their
* own programs.
*/
#ifndef LIBSOCKTHREAD_PLATFORM_HPP
@ -34,30 +42,36 @@
/*
* Operating system
*/
#define FREEBSD 0 // FreeBSD (untested)
#define MINGW 1 // Windows native (Mingw)
#define FREEBSD 0 // FreeBSD
#define WIN32 1 // Windows
#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
#if OS == WIN32
#define WINSOCK
#define WINTHREAD
#endif
#if OS == LINUX
#define NO_GETHOSTBYNAME2
#ifndef WINSOCK
#include <arpa/inet.h>
#endif
#if OS == CYGWIN
#define FAST32_IS_LONG
#define INET_ADDRSTRLEN 16
#define NO_GETHOSTBYNAME2
#define NO_INET_NTOP
#define NO_INET_PTON
#include <cassert>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <ctime>
#include <iostream>
#ifndef WINSOCK
#include <netdb.h>
#endif
#ifndef WINTHREAD
#include <pthread.h>
#endif
#include <stdint.h> // TODO replace with Boost's version
#include <string>
#if defined WINSOCK || defined WINTHREAD
#include <windows.h>
#endif
using namespace std;
#include "types.hpp"
#endif // LIBSOCKTHREAD_PLATFORM_HPP

View File

@ -26,252 +26,47 @@
* 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.
*
* $Id: socket.cpp,v 1.8 2004/07/22 22:08:20 mpc Exp $
*/
#include <cassert>
using namespace std;
#include "platform.hpp"
#include "socket_error.hpp"
#include "socket.hpp"
using namespace Libsockthread;
size_t Socket::total = 0; // the total number of sockets in use
/*
* Constructs an IPv4 TCP socket
*/
Socket::Socket(void)
{
++total;
try {
#ifdef WINSOCK
if (total == 1)
winsock_startup();
#endif
create_socket(PF_INET, SOCK_STREAM);
} catch (const Socket_error& x) {
--total;
throw;
}
}
/*
* Constructs the socket
*
* domain - either PF_INET or PF_INET6
* type - either SOCK_STREAM or SOCK_DGRAM
*/
Socket::Socket(int domain, int type)
{
++total;
try {
#ifdef WINSOCK
if (total == 1)
winsock_startup();
#endif
create_socket(domain, type);
} catch {const Socket_error& x) {
--total;
throw;
}
}
/*
* Destroys the socket
*/
Socket::~Socket(void)
{
close();
--total;
assert(total >= 0);
#ifdef WINSOCK
if (total == 0)
winsock_cleanup();
#endif
}
/*
* Closes the socket
*/
void Socket::close(void)
void Socket::close()
{
#ifdef WINSOCK
if (closesocket(sock) == SOCKET_ERROR) {
LERROR("closesocket() failed: %s", winsock_strerror(WSAGetLastError()));
if (sock != SERR) {
if (close(sock) == -1)
; // FIXME log the error
}
#else
if (close(sock) == -1) {
LERROR("close() failed: %s", strerror(errno));
}
#endif
sock = SERR;
}
/*
* Creates the socket
*
* domain - either PF_INET or PF_INET6
* type - either SOCK_STREAM or SOCK_DGRAM
* Changes the address associated with the socket
*/
void Socket::create_socket(int domain, int type)
void Socket::set_addr(Socket_addr& addr)
{
assert((domain == PF_INET || domain == PF_INET6) &&
(type == SOCK_STREAM || type == SOCK_DGRAM));
sock = socket(domain, type, 0);
#ifdef WINSOCK
if (sock == INVALID_SOCKET)
throw Socket_error(sam_winsock_strerror(WSAGetLastError()));
#else
if (sock == -1)
close();
this->addr = addr;
setup_socket();
}
/*
* Prepares the socket for use
*/
void Socket::setup_socket()
{
assert(sock == SERR); // the descriptor shouldn't be active
if (!addr.is_ready())
throw Socket_error("Couldn't create socket: address isn't ready");
sock = socket(addr.get_family(), addr.get_type(), 0);
if (sock == SERR)
throw Socket_error(strerror(errno));
#endif
}
#ifdef WINSOCK
/*
* Unloads the Winsock network subsystem
*/
void Socket::winsock_cleanup(void)
{
int rc = WSACleanup();
assert(rc != SOCKET_ERROR);
}
/*
* Loads the Winsock network sucksystem
*/
void Socket::winsock_startup(void)
{
WORD wVersionRequested = MAKEWORD(2, 2);
WSADATA wsaData;
int rc = WSAStartup(wVersionRequested, &wsaData);
if (rc != 0)
throw Socket_error(winsock_strerror(rc));
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
winsock_cleanup();
throw Socket_error("Bad Winsock version");
}
}
/*
* Apparently Winsock does not have a strerror() equivalent for its functions
*
* code - code from WSAGetLastError()
*
* Returns: error string (from http://msdn.microsoft.com/library/default.asp?
* url=/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp)
*/
const char* Socket::winsock_strerror(int code)
{
switch (code) {
case WSAEINTR:
return "Interrupted function call";
case WSAEACCES: // yes, that is the correct spelling
return "Permission denied";
case WSAEFAULT:
return "Bad address";
case WSAEINVAL:
return "Invalid argument";
case WSAEMFILE:
return "Too many open files";
case WSAEWOULDBLOCK:
return "Resource temporarily unavailable";
case WSAEINPROGRESS:
return "Operation now in progress";
case WSAEALREADY:
return "Operation already in progress";
case WSAENOTSOCK:
return "Socket operations on nonsocket";
case WSAEDESTADDRREQ:
return "Destination address required";
case WSAEMSGSIZE:
return "Message too long";
case WSAEPROTOTYPE:
return "Protocol wrong type for socket";
case WSAENOPROTOOPT:
return "Bad protocol option";
case WSAEPROTONOSUPPORT:
return "Protocol not supported";
case WSAESOCKTNOSUPPORT:
return "Socket type not supported";
case WSAEOPNOTSUPP:
return "Operation not supported";
case WSAEPFNOSUPPORT:
return "Protocol family not supported";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family";
case WSAEADDRINUSE:
return "Address already in use";
case WSAEADDRNOTAVAIL:
return "Cannot assign requested address";
case WSAENETDOWN:
return "Network is down";
case WSAENETUNREACH:
return "Network is unreachable";
case WSAENETRESET:
return "Network dropped connection on reset";
case WSAECONNABORTED:
return "Software caused connection abort";
case WSAECONNRESET:
return "Connection reset by peer";
case WSAENOBUFS:
return "No buffer space available";
case WSAEISCONN:
return "Socket is already connected";
case WSAENOTCONN:
return "Socket is not connected";
case WSAESHUTDOWN:
return "Cannot send after socket shutdown";
case WSAETIMEDOUT:
return "Connection timed out";
case WSAECONNREFUSED:
return "Connection refused";
case WSAEHOSTDOWN:
return "Host is down";
case WSAEHOSTUNREACH:
return "No route to host";
case WSAEPROCLIM:
return "Too many processes";
case WSASYSNOTREADY:
return "Network subsystem is unavailable";
case WSAVERNOTSUPPORTED:
return "Winsock.dll version out of range";
case WSANOTINITIALISED:
return "Successful WSAStartup not yet performed";
case WSAEDISCON:
return "Graceful shutdown in progress";
case WSATYPE_NOT_FOUND:
return "Class type not found";
case WSAHOST_NOT_FOUND:
return "Host not found";
case WSATRY_AGAIN:
return "Nonauthoritative host not found";
case WSANO_RECOVERY:
return "This is a nonrecoverable error";
case WSANO_DATA:
return "Valid name, no data record of requested type";
/* None of this shit compiles under Mingw - who knows why...
case WSA_INVALID_HANDLE:
return "Specified event object handle is invalid";
case WSA_INVALID_PARAMETER:
return "One or more parameters are invalid";
case WSA_IO_INCOMPLETE:
return "Overlapped I/O event object not in signaled state";
case WSA_IO_PENDING:
return "Overlapped operations will complete later";
case WSA_NOT_ENOUGH_MEMORY:
return "Insufficient memory available";
case WSA_OPERATION_ABORTED:
return "Overlapped operation aborted";
case WSAINVALIDPROCTABLE:
return "Invalid procedure table from service provider";
case WSAINVALIDPROVIDER:
return "Invalid service provider version number";
case WSAPROVIDERFAILEDINIT:
return "Unable to initialize a service provider";
*/
case WSASYSCALLFAILURE:
return "System call failure";
default:
return "Unknown error";
}
}
#endif // WINSOCK

View File

@ -26,38 +26,42 @@
* 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.
*
* $Id: socket.hpp,v 1.8 2004/07/22 22:08:20 mpc Exp $
*/
#ifndef LIBSOCKTHREAD_SOCKET_HPP
#define LIBSOCKTHREAD_SOCKET_HPP
namespace Libsockthread {
class Socket_error : public runtime_error {
public:
Socket_error(const string& s)
: runtime_error(s) { }
};
class Socket {
public:
Socket(void); // throws Socket_error
Socket(int domain, int type); // throws Socket_error
~Socket(void);
#ifdef WINSOCK
typedef SOCKET socket_t;
enum { SERR = SOCKET_ERROR };
#else
typedef int socket_t;
enum { SERR = -1 };
#endif
void close(void);
Socket()
: addr(), sock(SERR) {}
Socket(Socket_addr& addr) // throws Socket_error
: addr(addr), sock(SERR) { setup_socket(); }
void close();
size_t read(vector<uchar_t>& buf, size_t max = 0);
size_t read_until(vector<uchar_t>& buf, uchar_t delim = '\n');
void set_addr(Socket_addr& addr); // throws Socket_error
void set_blocking(bool blocking);
size_t write(vector<uchar_t>& buf);
void write_all(vector<uchar_t>& buf);
size_t write_until(vector<uchar_t& buf, uchar_t delim = '\n');
private:
#ifdef WINSOCK
typedef SOCKET socket_t;
void winsock_cleanup(void);
void winsock_startup(void); // throws Socket_error
const char* winsock_strerror(int code);
#else
typedef int socket_t;
#endif
void create_socket(int domain, int type); // throws Socket_error
void setup_socket(); // throws Socket_error
Socket_addr addr;
socket_t sock;
static size_t total; // the total number of sockets in memory
};
}

View File

@ -26,58 +26,83 @@
* 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.
*
* $Id: socket_addr.cpp,v 1.4 2004/07/22 19:10:59 mpc Exp $
*/
#include <arpa/inet.h>
#include <cassert>
using namespace std;
#include "platform.hpp"
#include "socket.hpp"
#include "socket_error.hpp"
#include "socket_addr.hpp"
using namespace Libsockthread;
Socket_addr::Socket_addr(int domain, const string& host, uint16_t port)
: domain(domain), host(host), port(port)
Socket_addr::Socket_addr(Socket_addr& rhs)
{
memset(&hostaddr, 0, sizeof hostaddr);
hostaddr.sin_family = domain;
hostaddr.sin_port = htons(port);
resolve(host.c_str(), ipaddr);
int rc;
#ifdef NO_INET_ATON
rc = hostaddr.sin_addr.s_addr = inet_addr(ipaddr);
#elif defined NO_INET_PTON
rc = inet_aton(ipaddr, &hostaddr.sin_addr);
#else
rc = inet_pton(AF_INET, ipaddr, &hostaddr.sin_addr);
#endif
assert(rc != 0 && rc != -1);
delete[] ip;
if (rhs.resolved) {
if (rhs.family == AF_INET) {
ip = new char[INET_ADDRSTRLEN];
else
ip = new char[INET6_ADDRSTRLEN];
strcpy(ip, rhs.ip);
}
family = rhs.family;
host = rhs.host;
port = rhs.port;
resolved = rhs.resolved;
type = rhs.type;
}
Socket_addr& Socket_addr::operator=(const Socket_addr& rhs)
{
if (this == &rhs) // check for self-assignment: a = a
return *this;
delete[] ip;
if (rhs.resolved) {
if (rhs.family == AF_INET)
ip = new char[INET_ADDRSTRLEN];
else
ip = new char[INET6_ADDRSTRLEN];
strcpy(ip, rhs.ip);
}
family = rhs.family;
host = rhs.host;
port = rhs.port;
type = rhs.type;
return *this;
}
/*
* Performs a DNS lookup on `hostname' and puts the result in `ipaddr'
* Performs a DNS lookup
*/
bool Socket::resolve(const char* hostname, char* ipaddr)
void Socket_addr::resolve()
{
struct hostent *h;
#ifdef NO_GETHOSTBYNAME2
h = gethostbyname(hostname);
#else
h = gethostbyname2(hostname, domain);
#endif
if (h == 0) {
LWARN("DNS resolution failed for %s", hostname);
throw Socket_error("DNS resolution failed");
}
struct in_addr a;
a.s_addr = ((struct in_addr *)h->h_addr)->s_addr;
#ifdef NO_INET_NTOP
char *tmp;
tmp = inet_ntoa(a);
assert(tmp != 0);
strlcpy(ipaddr, tmp, INET_ADDRSTRLEN); // inet_ntoa() was very poorly designed
#else
int rc = inet_ntop(domain, &a, ipaddr, INET_ADDRSTRLEN);
assert(rc != 0);
#endif
resolved = false; // in case they already had a host name but just set a
// new one with set_host()
hostent* hent = gethostbyname(host.c_str());
if (hent == NULL)
throw Dns_error(hstrerror(h_errno));
assert(hent->h_addrtype == AF_INET || hent->h_addrtype == AF_INET6);
family = hent->h_addrtype;
delete[] ip;
if (family == AF_INET) {
ip = new char[INET_ADDRSTRLEN];
else
ip = new char[INET6_ADDRSTRLEN];
strcpy(ip, hent->h_addr_list[0]);
resolved = true;
}
bool Socket_addr::operator==(const Socket_addr& rhs)
{
if (rhs.family == family
&& rhs.host == host
&& strcmp(rhs.ip, ip) == 0
&& rhs.port == port
&& rhs.resolved == resolved
&& rhs.type == type)
return true;
else
return false;
}

View File

@ -26,6 +26,8 @@
* 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.
*
* $Id: socket_addr.hpp,v 1.4 2004/07/22 19:10:59 mpc Exp $
*/
#ifndef LIBSOCKTHREAD_SOCKET_ADDR_HPP
@ -34,15 +36,42 @@
namespace Libsockthread {
class Socket_addr {
public:
Socket_addr(int domain, const string& host, uint16_t port);
private:
bool resolve(const char* hostname, char* ipaddr);
Socket_addr()
: family(AF_INET), resolved(false) { }
Socket_addr(Socket_addr& rhs);
Socket_addr(int type, string& host, uint16_t port)
: family(AF_INET), host(host), type(type), port(port)
{ resolve(); } // throws Dns_error
~Socket_addr()
{ delete[] ip; }
int domain; // PF_INET or PF_INET6
int get_family() const
{ return family; }
const char* get_ip() const // Warning! This can be NULL!
{ return ip; }
uint16_t get_port() const
{ return port; }
int get_type() const
{ return type;
bool is_ready() const
{ return resolved; }
Socket_addr& operator=(const Socket_addr& rhs);
bool operator==(const Socket_addr& rhs);
void set_host(string& host) // throws Dns_error
{ this->host = host; resolve(); }
void set_port(uint16_t port)
{ this->port = port; }
void set_type(int type)
{ this->type = type; }
private:
void resolve(); // throws Dns_error
int family; // AF_INET or AF_INET6
string host;
char ipaddr[INET_ADDRSTRLEN];
struct sockaddr_in hostaddr;
char* ip;
uint16_t port;
bool resolved;
int type; // SOCK_STREAM or SOCK_DGRAM
};
}

View File

@ -0,0 +1,35 @@
/*
* 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.
*
* $Id$
*/
#include "platform.hpp"
#include "socket_connector.hpp"
using namespace Libsockthread;

View 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.
*
* $Id$
*/
#ifndef LIBSOCKTHREAD_SOCKET_CONNECTOR_HPP
#define LIBSOCKTHREAD_SOCKET_CONNECTOR_HPP
namespace Libsockthread {
class Socket_connector : public Socket {
public:
Socket_connector(Socket_addr& addr)
: Socket(addr);
void connect();
};
}
#endif // LIBSOCKTHREAD_SOCKET_CONNECTOR_HPP

View 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.
*/
#ifndef LIBSOCKTHREAD_SOCKET_ERROR_HPP
#define LIBSOCKTHREAD_SOCKET_ERROR_HPP
namespace Libsockthread {
class Socket_error : public runtime_error {
public:
Socket_error(const string& s)
: runtime_error(s) { }
};
class Dns_error : public Socket_error {
public:
Dns_error(const string& s)
: Socket_error(s) { }
};
}
#endif // LIBSOCKTHREAD_SOCKET_ERROR_HPP

View File

@ -0,0 +1,35 @@
/*
* 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.
*
* $Id$
*/
#include "platform.hpp"
#include "socket_listener.hpp"
using namespace Libsockthread;

View 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.
*
* $Id$
*/
#ifndef LIBSOCKTHREAD_SOCKET_LISTENER_HPP
#define LIBSOCKTHREAD_SOCKET_LISTENER_HPP
namespace Libsockthread {
class Socket_listener {
public:
Socket_listener(Socket_addr& addr)
: Socket(addr);
void accept();
void listen();
};
}
#endif // LIBSOCKTHREAD_SOCKET_LISTENER_HPP

View File

@ -12,6 +12,8 @@
* 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.
*
* $Id$
*/
#include <stddef.h>

View File

@ -26,6 +26,8 @@
* 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.
*
* $Id$
*/
/*

View File

@ -26,18 +26,15 @@
* 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.
*
* $Id$
*/
// Modelled after JThread by Jori Liesenborgs
/*
* Modelled after JThread by Jori Liesenborgs
*/
#include <cassert>
#include "platform.hpp"
#ifdef WINTHREAD
#include <windows.h>
#else
#include <pthread.h>
#endif
using namespace std;
#include "mutex.hpp"
#include "thread.hpp"
using namespace Libsockthread;
@ -45,12 +42,12 @@ using namespace Libsockthread;
/*
* Gets the return value of a finished thread
*/
void* Thread::get_retval(void)
void* Thread::get_retval()
{
void* val;
running_m.lock();
if (running)
val = 0;
val = NULL;
else
val = retval;
running_m.unlock();
@ -60,7 +57,7 @@ void* Thread::get_retval(void)
/*
* Checks whether the thread is running
*/
bool Thread::is_running(void)
bool Thread::is_running()
{
running_m.lock();
bool r = running;
@ -72,7 +69,7 @@ bool Thread::is_running(void)
* Stops the thread
* Generally NOT a good idea
*/
void Thread::kill(void)
void Thread::kill()
{
running_m.lock();
#ifndef NDEBUG
@ -83,7 +80,7 @@ void Thread::kill(void)
}
#endif
#ifdef WINTHREAD
BOOL rc = TerminateThread(handle, 0);
BOOL rc = TerminateThread(handle, NULL);
assert(rc);
#else
int rc = pthread_cancel(id);
@ -96,7 +93,7 @@ void Thread::kill(void)
/*
* Starts the thread
*/
void Thread::start(void)
void Thread::start()
{
#ifndef NDEBUG
// check whether the thread is already running
@ -106,8 +103,8 @@ void Thread::start(void)
#endif
continue_m.lock();
#ifdef WINTHREAD
handle = CreateThread(0, 0, &the_thread, this, 0, &id);
assert(handle != 0);
handle = CreateThread(NULL, 0, &the_thread, this, 0, &id);
assert(handle != NULL);
#else
int rc = pthread_create(&id, 0, &the_thread, this);
assert(rc == 0);
@ -145,10 +142,8 @@ void* Thread::the_thread(void *param)
#ifdef UNIT_TEST
// g++ -Wall -c mutex.cpp -o mutex.o
// g++ -Wall -DUNIT_TEST -c thread.cpp -o thread.o
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o thread -lpthread
#include <iostream>
int main(void)
// g++ -Wall -DUNIT_TEST mutex.o thread.o -o thread -pthread
int main()
{
class Thread_test : public Thread
{
@ -156,15 +151,14 @@ int main(void)
Thread_test(int testval)
: testval(testval) { }
int get_testval(void)
int get_testval()
{
testval_m.lock();
int rc = testval;
testval_m.unlock();
return rc;
}
void *thread(void)
void *thread()
{
// just do something
while (true) {
@ -174,6 +168,7 @@ int main(void)
}
return 0;
}
private:
int testval;
Mutex testval_m;

View File

@ -26,9 +26,13 @@
* 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.
*
* $Id$
*/
// Modelled after JThread by Jori Liesenborgs
/*
* Modelled after JThread by Jori Liesenborgs
*/
#ifndef LIBSOCKTHREAD_THREAD_HPP
#define LIBSOCKTHREAD_THREAD_HPP
@ -36,16 +40,16 @@
namespace Libsockthread {
class Thread {
public:
Thread(void)
: retval(0), running(false) { }
virtual ~Thread(void)
Thread()
: retval(NULL), running(false) { }
virtual ~Thread()
{ kill(); }
void* get_retval(void);
bool is_running(void);
void kill(void);
void start(void);
virtual void *thread(void) = 0;
void* get_retval();
bool is_running();
void kill();
void start();
virtual void* thread() = 0;
private:
#ifdef WINTHREAD
static DWORD WINAPI the_thread(void* param);
@ -56,7 +60,7 @@ namespace Libsockthread {
pthread_t id;
#endif
Mutex continue_m;
void *retval;
void* retval;
bool running;
Mutex running_m;
};

View File

@ -26,68 +26,59 @@
* 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.
*
* $Id$
*/
#include <ctime>
#include <string>
using namespace std;
#include "platform.hpp"
#include "time.hpp"
using namespace Libsockthread;
/*
* Converts the time to an ISO 8601 standard time and date and puts it in a
* string
* Converts the time to an ISO 8601 standard date and time
* Example: 2004-07-01T19:03:47Z
*/
string& Time::utc(string &s) const
string& Time::utc()
{
struct tm* tm;
tm = gmtime(&unixtime);
struct tm* tm = gmtime(&unixtime);
char t[21];
strftime(t, sizeof t, "%Y-%m-%dT%H:%M:%SZ", tm);
return s = t;
return formatted = t;
}
/*
* Converts the time to an ISO 8601 standard date and puts it in a string
* Converts the time to an ISO 8601 standard date
* Example: 2004-07-01Z
*/
string& Time::utc_date(string &s) const
string& Time::utc_date()
{
struct tm* tm;
tm = gmtime(&unixtime);
struct tm* tm = gmtime(&unixtime);
char t[12];
strftime(t, sizeof t, "%Y-%m-%dZ", tm);
return s = t;
return formatted = t;
}
/*
* Converts the time to an ISO 8601 standard time and puts it in a string
* Converts the time to an ISO 8601 standard time
* Example: 19:03:47Z
*/
string& Time::utc_time(string &s) const
string& Time::utc_time()
{
struct tm* tm;
tm = gmtime(&unixtime);
struct tm* tm = gmtime(&unixtime);
char t[10];
strftime(t, sizeof t, "%H:%M:%SZ", tm);
return s = t;
return formatted = t;
}
#ifdef UNIT_TEST
// g++ -Wall -DUNIT_TEST time.cpp -o time
#include <iostream>
int main(void)
int main()
{
Time t;
string s;
cout << "Current date and time is " << t.utc(s) << '\n';
cout << "Current date is " << t.utc_date(s) << '\n';
cout << "Current time is " << t.utc_time(s) << '\n';
cout << "Current date and time is " << t.utc() << '\n';
cout << "Current date is " << t.utc_date() << '\n';
cout << "Current time is " << t.utc_time() << '\n';
cout << "Formatted time is " << t.get_formatted() << " (should be the same)\n";
return 0;
}

View File

@ -26,6 +26,8 @@
* 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.
*
* $Id$
*/
#ifndef LIBSOCKTHREAD_TIME_HPP
@ -34,13 +36,18 @@
namespace Libsockthread {
class Time {
public:
Time(void) { now(); }
Time()
{ now(); }
void now(void) { unixtime = time(0); }
string& utc(string &s) const;
string& utc_date(string &s) const;
string& utc_time(string &s) const;
string& get_formatted()
{ return formatted; }
void now()
{ unixtime = time(0); }
string& utc();
string& utc_date();
string& utc_time();
private:
string formatted;
time_t unixtime;
};
}

View 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.
*
* $Id$
*/
#ifndef LIBSOCKTHREAD_TYPES_HPP
#define LIBSOCKTHREAD_TYPES_HPP
/*
* 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;
#endif // LIBSOCKTHREAD_TYPES_HPP

View File

@ -27,7 +27,7 @@ public class PeerData {
/** date sent (Long) to EventDataPoint containing the datapoints sent in the current period */
private Map _dataPoints;
/** date sent (Long) to EventDataPoint containing pings that haven't yet timed out or been ponged */
private Map _pendingPings;
private TreeMap _pendingPings;
private long _sessionStart;
private long _lifetimeSent;
private long _lifetimeReceived;
@ -208,14 +208,32 @@ public class PeerData {
public void pongReceived(long dateSent, long pongSent) {
long now = Clock.getInstance().now();
synchronized (_updateLock) {
EventDataPoint data = (EventDataPoint) _pendingPings.remove(new Long(dateSent));
if (_pendingPings.size() <= 0) {
_log.warn("Pong received (sent at " + dateSent + ", " + (now-dateSent)
+ "ms ago, pong delay " + (pongSent-dateSent) + "ms, pong receive delay "
+ (now-pongSent) + "ms)");
return;
}
Long first = (Long)_pendingPings.firstKey();
EventDataPoint data = (EventDataPoint)_pendingPings.remove(new Long(dateSent));
if (data != null) {
data.setPongReceived(now);
data.setPongSent(pongSent);
data.setWasPonged(true);
locked_addDataPoint(data);
if (dateSent != first.longValue()) {
_log.error("Out of order delivery: received " + dateSent
+ " but the first pending is " + first.longValue()
+ " (delta " + (dateSent - first.longValue()) + ")");
} else {
_log.info("In order delivery for " + dateSent + " in ping "
+ _peer.getComment());
}
} else {
_log.warn("Pong received, but no matching ping? ping sent at = " + dateSent);
return;
}
}
_sendRate.addData(pongSent - dateSent, 0);

View File

@ -0,0 +1,18 @@
<html><body>
<p>Implements a TCP-like (reliable, authenticated, in order) set of sockets for
communicating over the IP-like (unreliable, unauthenticated, unordered) I2P
messages.</p>
<p>When an application wants to use streams, it must fetch an {@link
net.i2p.client.streaming.I2PSocketManager} from the {@link
net.i2p.client.streaming.I2PSocketManagerFactory}, which in turn builds its own
{@link net.i2p.client.I2PSession} internally. All communication over that
{@link net.i2p.client.I2PSession} is handled by the {@link
net.i2p.client.streaming.I2PSocketManager}, as it imposes its own formatting on
the raw messages sent and received. If an application wants to receive streams
from other clients on the network, it should access the blocking {@link
net.i2p.client.streaming.I2PServerSocket#accept} method, which will provide an
{@link net.i2p.client.streaming.I2PSocket} when a new one is available. If an
application wants to create a new stream to a peer, it should do so with the
appropriate {@link net.i2p.client.streaming.I2PSocketManager#connect} call.</p>
</body></html>

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="routerconsole">
<target name="all" depends="clean, build" />
<target name="build" depends="builddep, jar" />
<target name="builddep" depends="jetty" >
<ant dir="../../../router/java/" target="build" />
<!-- router will build core -->
</target>
<target name="jetty">
<untar src="jetty-4.2.21-min.tar.bz2" compression="bzip2" dest="." />
<ant dir="jetty-4.2.21-min/extra/jdk1.2/" target="all" />
</target>
<target name="compile">
<mkdir dir="./build" />
<mkdir dir="./build/obj" />
<javac
srcdir="./src"
debug="true" deprecation="on" source="1.3" target="1.3"
destdir="./build/obj"
classpath="../../../core/java/build/i2p.jar:../../../router/java/build/router.jar:jetty-4.2.21-min/extra/lib/org.mortbay.jetty-jdk1.2.jar" />
</target>
<target name="jar" depends="compile">
<jar destfile="./build/routerconsole.jar" basedir="./build/obj" includes="**/*.class">
<manifest>
<attribute name="Class-Path" value="i2p.jar router.jar" />
</manifest>
</jar>
<ant target="war" />
</target>
<target name="war">
<war destfile="build/routerconsole.war" webxml="../jsp/web.xml"
basedir="../jsp/" excludes="web.xml">
</war>
</target>
<target name="javadoc">
<mkdir dir="./build" />
<mkdir dir="./build/javadoc" />
<javadoc
sourcepath="./src:../../../core/java/src:../../router/java/src" destdir="./build/javadoc"
packagenames="*"
use="true"
splitindex="true"
windowtitle="Router Console" />
</target>
<target name="clean">
<delete dir="./build" />
</target>
<target name="cleandep" depends="clean">
<!-- router will clean core -->
<ant dir="../../../router/java/" target="distclean" />
</target>
<target name="distclean" depends="clean">
<!-- router will clean core -->
<ant dir="../../../router/java/" target="distclean" />
<delete dir="./jetty-4.2.21-min" />
</target>
</project>

View File

@ -0,0 +1,38 @@
package net.i2p.router.web;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import net.i2p.router.RouterContext;
public class ConfigAdvancedHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
public ConfigAdvancedHelper() {}
public String getSettings() {
StringBuffer buf = new StringBuffer(4*1024);
Set names = _context.router().getConfigSettings();
TreeSet sortedNames = new TreeSet(names);
for (Iterator iter = sortedNames.iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
String val = _context.router().getConfigSetting(name);
buf.append(name).append('=').append(val).append('\n');
}
return buf.toString();
}
}

View File

@ -0,0 +1,117 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
import java.util.TreeMap;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
import net.i2p.router.ClientTunnelSettings;
public class ConfigClientsHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
/** copied from the package private {@link net.i2p.router.tunnelmanager.TunnelPool} */
public final static String TARGET_CLIENTS_PARAM = "router.targetClients";
/** copied from the package private {@link net.i2p.router.tunnelmanager.TunnelPool} */
public final static int TARGET_CLIENTS_DEFAULT = 3;
public ConfigClientsHelper() {}
public String getClientCountSelectBox() {
int count = TARGET_CLIENTS_DEFAULT;
String val = _context.router().getConfigSetting(TARGET_CLIENTS_PARAM);
if (val != null) {
try {
count = Integer.parseInt(val);
} catch (NumberFormatException nfe) {
// ignore, use default from above
}
}
StringBuffer buf = new StringBuffer(1024);
buf.append("<select name=\"clientcount\">\n");
for (int i = 0; i < 5; i++) {
buf.append("<option value=\"").append(i).append("\" ");
if (count == i)
buf.append("selected=\"true\" ");
buf.append(">").append(i).append("</option>\n");
}
if (count >= 5) {
buf.append("<option value=\"").append(count);
buf.append("\" selected>").append(count);
buf.append("</option>\n");
}
buf.append("</select>\n");
return buf.toString();
}
public String getTunnelCountSelectBox() {
int count = ClientTunnelSettings.DEFAULT_NUM_INBOUND;
String val = _context.router().getConfigSetting(ClientTunnelSettings.PROP_NUM_INBOUND);
if (val != null) {
try {
count = Integer.parseInt(val);
} catch (NumberFormatException nfe) {
// ignore, use default from above
}
}
StringBuffer buf = new StringBuffer(1024);
buf.append("<select name=\"tunnelcount\">\n");
for (int i = 0; i < 4; i++) {
buf.append("<option value=\"").append(i).append("\" ");
if (count == i)
buf.append("selected=\"true\" ");
buf.append(">").append(i).append("</option>\n");
}
if (count >= 4) {
buf.append("<option value=\"").append(count);
buf.append("\" selected>").append(count);
buf.append("</option>\n");
}
buf.append("</select>\n");
return buf.toString();
}
public String getTunnelDepthSelectBox() {
int count = ClientTunnelSettings.DEFAULT_DEPTH_INBOUND;
String val = _context.router().getConfigSetting(ClientTunnelSettings.PROP_DEPTH_INBOUND);
if (val != null) {
try {
count = Integer.parseInt(val);
} catch (NumberFormatException nfe) {
// ignore, use default from above
}
}
StringBuffer buf = new StringBuffer(1024);
buf.append("<select name=\"tunneldepth\">\n");
for (int i = 0; i < 4; i++) {
buf.append("<option value=\"").append(i).append("\" ");
if (count == i)
buf.append("selected=\"true\" ");
buf.append(">").append(i).append("</option>\n");
}
if (count >= 4) {
buf.append("<option value=\"").append(count);
buf.append("\" selected>").append(count);
buf.append("</option>\n");
}
buf.append("</select>\n");
return buf.toString();
}
}

View File

@ -0,0 +1,113 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
import java.util.TreeMap;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
public class ConfigLoggingHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
public ConfigLoggingHelper() {}
public String getLogFilePattern() {
return _context.logManager().getBaseLogfilename();
}
public String getRecordPattern() {
return new String(_context.logManager().getFormat());
}
public String getDatePattern() {
return _context.logManager().getDateFormatPattern();
}
public String getMaxFileSize() {
int bytes = _context.logManager().getFileSize();
if (bytes == 0) return "1m";
if (bytes > 1024*1024*1024)
return (bytes/(1024*1024*1024)) + "g";
else if (bytes > 1024*1024)
return (bytes/(1024*1024)) + "m";
else
return (bytes/(1024)) + "k";
}
public String getLogLevelTable() {
StringBuffer buf = new StringBuffer(32*1024);
buf.append("<textarea rows=\"20\" cols=\"80\">");
List logs = _context.logManager().getLogs();
TreeMap sortedLogs = new TreeMap();
for (int i = 0; i < logs.size(); i++) {
Log l = (Log)logs.get(i);
sortedLogs.put(l.getName(), l);
}
int i = 0;
for (Iterator iter = sortedLogs.values().iterator(); iter.hasNext(); i++) {
Log l = (Log)iter.next();
buf.append(l.getName()).append('=');
buf.append(Log.toLevelString(l.getMinimumPriority()));
buf.append("\n");
}
buf.append("</textarea><br />\n");
buf.append("<i>Valid levels are DEBUG, INFO, WARN, ERROR, CRIT</i>\n");
return buf.toString();
}
public String getLogLevelTableDetail() {
StringBuffer buf = new StringBuffer(8*1024);
buf.append("<table border=\"1\">\n");
buf.append("<tr><td>Package/class</td><td>Level</td></tr>\n");
List logs = _context.logManager().getLogs();
TreeMap sortedLogs = new TreeMap();
for (int i = 0; i < logs.size(); i++) {
Log l = (Log)logs.get(i);
sortedLogs.put(l.getName(), l);
}
int i = 0;
for (Iterator iter = sortedLogs.values().iterator(); iter.hasNext(); i++) {
Log l = (Log)iter.next();
buf.append("<tr>\n <td><input size=\"50\" type=\"text\" name=\"logrecord.");
buf.append(i).append(".package\" value=\"").append(l.getName());
buf.append("\" /></td>\n");
buf.append("<td><select name=\"logrecord.").append(i);
buf.append(".level\">\n\t");
buf.append("<option value=\"DEBUG\" ");
if (l.getMinimumPriority() == Log.DEBUG)
buf.append("selected=\"true\" ");
buf.append(">Debug</option>\n\t");
buf.append("<option value=\"INFO\" ");
if (l.getMinimumPriority() == Log.INFO)
buf.append("selected=\"true\" ");
buf.append(">Info</option>\n\t");
buf.append("<option value=\"WARN\" ");
if (l.getMinimumPriority() == Log.WARN)
buf.append("selected=\"true\" ");
buf.append(">Warn</option>\n\t");
buf.append("<option value=\"ERROR\" ");
if (l.getMinimumPriority() == Log.ERROR)
buf.append("selected=\"true\" ");
buf.append(">Error</option>\n\t");
buf.append("<option value=\"CRIT\" ");
if (l.getMinimumPriority() == Log.CRIT)
buf.append("selected=\"true\" ");
buf.append(">Critical</option>\n\t");
buf.append("</select></td>\n</tr>\n");
}
buf.append("</table>\n");
return buf.toString();
}
}

View File

@ -0,0 +1,135 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
import java.util.TreeMap;
import net.i2p.util.Log;
import net.i2p.router.RouterContext;
import net.i2p.router.ClientTunnelSettings;
public class ConfigNetHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
public ConfigNetHelper() {}
/** copied from various private TCP components */
private final static String PROP_I2NP_TCP_HOSTNAME = "i2np.tcp.hostname";
private final static String PROP_I2NP_TCP_PORT = "i2np.tcp.port";
public String getHostname() {
return _context.getProperty(PROP_I2NP_TCP_HOSTNAME);
}
public String getPort() {
int port = 8887;
String val = _context.getProperty(PROP_I2NP_TCP_PORT);
if (val != null) {
try {
port = Integer.parseInt(val);
} catch (NumberFormatException nfe) {
// ignore, use default from above
}
}
return "" + port;
}
public String getEnableTimeSyncChecked() {
String enabled = System.getProperty("timestamper.enabled");
if ( (enabled == null) || (!"true".equals(enabled)) )
return "";
else
return " checked ";
}
public static final String PROP_INBOUND_KBPS = "i2np.bandwidth.inboundKBytesPerSecond";
public static final String PROP_OUTBOUND_KBPS = "i2np.bandwidth.outboundKBytesPerSecond";
public static final String PROP_INBOUND_BURST = "i2np.bandwidth.inboundBurstKBytes";
public static final String PROP_OUTBOUND_BURST = "i2np.bandwidth.outboundBurstKBytes";
public String getInboundRate() {
String rate = _context.getProperty(PROP_INBOUND_KBPS);
if (rate != null)
return rate;
else
return "-1";
}
public String getOutboundRate() {
String rate = _context.getProperty(PROP_OUTBOUND_KBPS);
if (rate != null)
return rate;
else
return "Unlimited";
}
public String getInboundBurstFactorBox() {
String rate = _context.getProperty(PROP_INBOUND_KBPS);
String burst = _context.getProperty(PROP_INBOUND_BURST);
int numSeconds = 1;
if ( (burst != null) && (rate != null) ) {
int rateKBps = 0;
int burstKB = 0;
try {
rateKBps = Integer.parseInt(rate);
burstKB = Integer.parseInt(burst);
} catch (NumberFormatException nfe) {
// ignore
}
if ( (rateKBps > 0) && (burstKB > 0) ) {
numSeconds = burstKB / rateKBps;
}
}
return getBurstFactor(numSeconds, "inboundburstfactor");
}
public String getOutboundBurstFactorBox() {
String rate = _context.getProperty(PROP_OUTBOUND_KBPS);
String burst = _context.getProperty(PROP_OUTBOUND_BURST);
int numSeconds = 1;
if ( (burst != null) && (rate != null) ) {
int rateKBps = 0;
int burstKB = 0;
try {
rateKBps = Integer.parseInt(rate);
burstKB = Integer.parseInt(burst);
} catch (NumberFormatException nfe) {
// ignore
}
if ( (rateKBps > 0) && (burstKB > 0) ) {
numSeconds = burstKB / rateKBps;
}
}
return getBurstFactor(numSeconds, "outboundburstfactor");
}
private static String getBurstFactor(int numSeconds, String name) {
StringBuffer buf = new StringBuffer(256);
buf.append("<select name=\"").append(name).append("\">\n");
for (int i = 1; i < 10; i++) {
buf.append("<option value=\"").append(i).append("\" ");
if ( (i == numSeconds) || (i == 10) )
buf.append("selected ");
buf.append(">");
if (i == 1)
buf.append("1 second (no burst)</option>\n");
else
buf.append(i).append(" seconds</option>\n");
}
buf.append("</select>\n");
return buf.toString();
}
}

View File

@ -0,0 +1,24 @@
package net.i2p.router.web;
import java.util.List;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
class ContextHelper {
public static RouterContext getContext(String contextId) {
List contexts = RouterContext.listContexts();
if ( (contexts == null) || (contexts.size() <= 0) )
throw new IllegalStateException("No contexts? wtf");
if ( (contextId == null) || (contextId.trim().length() <= 0) )
return (RouterContext)contexts.get(0);
for (int i = 0; i < contexts.size(); i++) {
RouterContext context = (RouterContext)contexts.get(i);
Hash hash = context.routerHash();
if (hash == null) continue;
if (hash.toBase64().startsWith(contextId))
return context;
}
// not found, so just give them the first we can find
return (RouterContext)contexts.get(0);
}
}

View File

@ -0,0 +1,42 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import net.i2p.router.RouterContext;
public class LogsHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
public LogsHelper() {}
public String getLogs() {
List msgs = _context.logManager().getBuffer().getMostRecentMessages();
StringBuffer buf = new StringBuffer(16*1024);
buf.append("<h2>Most recent console messages:</h2><ul>");
buf.append("<code>\n");
for (int i = 0; i < msgs.size(); i++) {
String msg = (String)msgs.get(i);
buf.append("<li>");
buf.append(msg);
buf.append("</li>\n");
}
buf.append("</code></ul>\n");
return buf.toString();
}
}

View File

@ -0,0 +1,53 @@
package net.i2p.router.web;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.i2p.router.RouterContext;
public class NavHelper {
private static Map _apps = new HashMap();
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
public NavHelper() {}
/**
* To register a new client application so that it shows up on the router
* console's nav bar, it should be registered with this singleton.
*
* @param name pretty name the app will be called in the link
* @param path full path pointing to the application's root
* (e.g. /i2ptunnel/index.jsp)
*/
public static void registerApp(String name, String path) {
_apps.put(name, path);
}
public static void unregisterApp(String name) {
_apps.remove(name);
}
public String getClientAppLinks() {
StringBuffer buf = new StringBuffer(1024);
for (Iterator iter = _apps.keySet().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
String path = (String)_apps.get(name);
buf.append("<a href=\"").append(path).append("\">");
buf.append(name).append("</a> |");
}
return buf.toString();
}
}

View File

@ -0,0 +1,35 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import net.i2p.router.RouterContext;
public class NetDbHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
public NetDbHelper() {}
public String getNetDbSummary() {
ByteArrayOutputStream baos = new ByteArrayOutputStream(32*1024);
try {
_context.netDb().renderStatusHTML(baos);
} catch (IOException ioe) {
ioe.printStackTrace();
}
return new String(baos.toByteArray());
}
}

View File

@ -0,0 +1,35 @@
package net.i2p.router.web;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import net.i2p.router.RouterContext;
public class ProfilesHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
public ProfilesHelper() {}
public String getProfileSummary() {
ByteArrayOutputStream baos = new ByteArrayOutputStream(16*1024);
try {
_context.profileOrganizer().renderStatusHTML(baos);
} catch (IOException ioe) {
ioe.printStackTrace();
}
return new String(baos.toByteArray());
}
}

View File

@ -0,0 +1,50 @@
package net.i2p.router.web;
import java.io.IOException;
import org.mortbay.jetty.Server;
import org.mortbay.util.MultiException;
public class RouterConsoleRunner {
private Server _server;
private String _listenPort = "7657";
private String _listenHost = "0.0.0.0";
private String _webAppsDir = "./webapps/";
public RouterConsoleRunner(String args[]) {
if (args.length == 3) {
_listenPort = args[0].trim();
_listenHost = args[1].trim();
_webAppsDir = args[2].trim();
}
}
public static void main(String args[]) {
RouterConsoleRunner runner = new RouterConsoleRunner(args);
runner.startConsole();
}
public void startConsole() {
_server = new Server();
try {
_server.addListener(_listenHost + ':' + _listenPort);
_server.setRootWebApp("routerconsole");
_server.addWebApplications(_webAppsDir);
} catch (IOException ioe) {
ioe.printStackTrace();
}
try {
_server.start();
} catch (MultiException me) {
me.printStackTrace();
}
}
public void stopConsole() {
try {
_server.stop();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}

View File

@ -0,0 +1,377 @@
package net.i2p.router.web;
import java.text.DecimalFormat;
import net.i2p.data.DataHelper;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
import net.i2p.router.RouterVersion;
/**
* Simple helper to query the appropriate router for data necessary to render
* the summary sections on the router console.
*/
public class SummaryHelper {
private RouterContext _context;
/**
* Configure this bean to query a particular router context
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public void setContextId(String contextId) {
try {
_context = ContextHelper.getContext(contextId);
} catch (Throwable t) {
t.printStackTrace();
}
}
/**
* Retrieve the shortened 4 character ident for the router located within
* the current JVM at the given context.
*
*/
public String getIdent() {
if (_context == null) return "[no router]";
if (_context.routerHash() != null)
return _context.routerHash().toBase64().substring(0, 4);
else
return "[unknown]";
}
/**
* Retrieve the version number of the router.
*
*/
public String getVersion() {
return RouterVersion.VERSION;
}
/**
* Retrieve a pretty printed uptime count (ala 4d or 7h or 39m)
*
*/
public String getUptime() {
if (_context == null) return "[no router]";
Router router = _context.router();
if (router == null)
return "[not up]";
else
return DataHelper.formatDuration(router.getUptime());
}
/**
* How many active peers the router has.
*
*/
public int getActivePeers() {
if (_context == null)
return 0;
else
return _context.profileOrganizer().countActivePeers();
}
/**
* How many active peers the router ranks as fast.
*
*/
public int getFastPeers() {
if (_context == null)
return 0;
else
return _context.profileOrganizer().countFastPeers();
}
/**
* How many active peers the router ranks as having a high capacity.
*
*/
public int getHighCapacityPeers() {
if (_context == null)
return 0;
else
return _context.profileOrganizer().countHighCapacityPeers();
}
/**
* How many active peers the router ranks as well integrated.
*
*/
public int getWellIntegratedPeers() {
if (_context == null)
return 0;
else
return _context.profileOrganizer().countWellIntegratedPeers();
}
/**
* How many peers the router ranks as failing.
*
*/
public int getFailingPeers() {
if (_context == null)
return 0;
else
return _context.profileOrganizer().countFailingPeers();
}
/**
* How many peers totally suck.
*
*/
public int getShitlistedPeers() {
if (_context == null)
return 0;
else
return _context.shitlist().getRouterCount();
}
/**
* How fast we have been receiving data over the last minute (pretty printed
* string with 2 decimal places representing the KBps)
*
*/
public String getInboundMinuteKBps() {
if (_context == null)
return "0.0";
RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
Rate rate = receiveRate.getRate(60*1000);
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
DecimalFormat fmt = new DecimalFormat("##0.00");
return fmt.format(bps);
}
/**
* How fast we have been sending data over the last minute (pretty printed
* string with 2 decimal places representing the KBps)
*
*/
public String getOutboundMinuteKBps() {
if (_context == null)
return "0.0";
RateStat receiveRate = _context.statManager().getRate("transport.sendMessageSize");
Rate rate = receiveRate.getRate(60*1000);
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
DecimalFormat fmt = new DecimalFormat("##0.00");
return fmt.format(bps);
}
/**
* How fast we have been receiving data over the last 5 minutes (pretty printed
* string with 2 decimal places representing the KBps)
*
*/
public String getInboundFiveMinuteKBps() {
if (_context == null)
return "0.0";
RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
Rate rate = receiveRate.getRate(5*60*1000);
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
DecimalFormat fmt = new DecimalFormat("##0.00");
return fmt.format(bps);
}
/**
* How fast we have been sending data over the last 5 minutes (pretty printed
* string with 2 decimal places representing the KBps)
*
*/
public String getOutboundFiveMinuteKBps() {
if (_context == null)
return "0.0";
RateStat receiveRate = _context.statManager().getRate("transport.sendMessageSize");
Rate rate = receiveRate.getRate(5*60*1000);
double bytes = rate.getLastTotalValue();
double bps = (bytes*1000.0d)/(rate.getPeriod()*1024.0d);
DecimalFormat fmt = new DecimalFormat("##0.00");
return fmt.format(bps);
}
/**
* How fast we have been receiving data since the router started (pretty printed
* string with 2 decimal places representing the KBps)
*
*/
public String getInboundLifetimeKBps() {
if (_context == null)
return "0.0";
long received = _context.bandwidthLimiter().getTotalAllocatedInboundBytes();
DecimalFormat fmt = new DecimalFormat("##0.00");
// we use the unadjusted time, since thats what getWhenStarted is based off
long lifetime = _context.clock().now()-_context.clock().getOffset()
- _context.router().getWhenStarted();
lifetime /= 1000;
if (received > 0) {
double receivedKBps = received / (lifetime*1024.0);
return fmt.format(receivedKBps);
} else {
return "0.0";
}
}
/**
* How fast we have been sending data since the router started (pretty printed
* string with 2 decimal places representing the KBps)
*
*/
public String getOutboundLifetimeKBps() {
if (_context == null)
return "0.0";
long sent = _context.bandwidthLimiter().getTotalAllocatedOutboundBytes();
DecimalFormat fmt = new DecimalFormat("##0.00");
// we use the unadjusted time, since thats what getWhenStarted is based off
long lifetime = _context.clock().now()-_context.clock().getOffset()
- _context.router().getWhenStarted();
lifetime /= 1000;
if (sent > 0) {
double sendKBps = sent / (lifetime*1024.0);
return fmt.format(sendKBps);
} else {
return "0.0";
}
}
/**
* How much data have we received since the router started (pretty printed
* string with 2 decimal places and the appropriate units - GB/MB/KB/bytes)
*
*/
public String getInboundTransferred() {
if (_context == null)
return "0.0";
long received = _context.bandwidthLimiter().getTotalAllocatedInboundBytes();
return getTransferred(received);
}
/**
* How much data have we sent since the router started (pretty printed
* string with 2 decimal places and the appropriate units - GB/MB/KB/bytes)
*
*/
public String getOutboundTransferred() {
if (_context == null)
return "0.0";
long sent = _context.bandwidthLimiter().getTotalAllocatedOutboundBytes();
return getTransferred(sent);
}
private static String getTransferred(long bytes) {
int scale = 0;
if (bytes > 1024*1024*1024) {
// gigs transferred
scale = 3;
bytes /= (1024*1024*1024);
} else if (bytes > 1024*1024) {
// megs transferred
scale = 2;
bytes /= (1024*1024);
} else if (bytes > 1024) {
// kbytes transferred
scale = 1;
bytes /= 1024;
} else {
scale = 0;
}
DecimalFormat fmt = new DecimalFormat("##0.00");
String str = fmt.format(bytes);
switch (scale) {
case 1: return str + "KB";
case 2: return str + "MB";
case 3: return str + "GB";
default: return bytes + "bytes";
}
}
/**
* How many free inbound tunnels we have.
*
* @param contextId begging few characters of the routerHash, or null to pick
* the first one we come across.
*/
public int getInboundTunnels() {
if (_context == null)
return 0;
else
return _context.tunnelManager().getFreeTunnelCount();
}
/**
* How many active outbound tunnels we have.
*
*/
public int getOutboundTunnels() {
if (_context == null)
return 0;
else
return _context.tunnelManager().getOutboundTunnelCount();
}
/**
* How many tunnels we are participating in.
*
*/
public int getParticipatingTunnels() {
if (_context == null)
return 0;
else
return _context.tunnelManager().getParticipatingCount();
}
/**
* How lagged our job queue is over the last minute (pretty printed with
* the units attached)
*
*/
public String getJobLag() {
if (_context == null)
return "0ms";
Rate lagRate = _context.statManager().getRate("jobQueue.jobLag").getRate(60*1000);
return ((int)lagRate.getAverageValue()) + "ms";
}
/**
* How long it takes us to pump out a message, averaged over the last minute
* (pretty printed with the units attached)
*
*/
public String getMessageDelay() {
if (_context == null)
return "0ms";
Rate delayRate = _context.statManager().getRate("transport.sendProcessingTime").getRate(60*1000);
return ((int)delayRate.getAverageValue()) + "ms";
}
/**
* How long it takes us to test our tunnels, averaged over the last 10 minutes
* (pretty printed with the units attached)
*
*/
public String getTunnelLag() {
if (_context == null)
return "0ms";
Rate lagRate = _context.statManager().getRate("tunnel.testSuccessTime").getRate(10*60*1000);
return ((int)lagRate.getAverageValue()) + "ms";
}
}

View File

@ -0,0 +1,53 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - logs</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<jsp:useBean class="net.i2p.router.web.ConfigNetHelper" id="nethelper" scope="request" />
<jsp:setProperty name="nethelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<div class="main" id="main">
<%@include file="confignav.jsp" %>
<form action="config.jsp" method="POST">
<b>External hostname/IP address:</b>
<input name="hostname" type="text" size="32" value="<jsp:getProperty name="nethelper" property="hostname" />" />
<input type="submit" name="guesshost" value="Guess" /><br />
<b>Externally reachable TCP port:</b>
<input name="port" type="text" size="4" value="<jsp:getProperty name="nethelper" property="port" />" /> <br />
<i>The hostname/IP address and TCP port must be reachable from the outside world. If
you are behind a firewall or NAT, this means you must poke a hole for this port. If
you are using DHCP and do not have a static IP address, you must use a service like
<a href="http://dyndns.org/">dyndns</a>. The "guess" functionality makes an HTTP request
to <a href="http://www.whatismyip.com/">www.whatismyip.com</a>.</i>
<hr />
<b>Enable internal time synchronization?</b> <input type="checkbox" <jsp:getProperty name="nethelper" property="enableTimeSyncChecked" /> name="enabletimesync" /><br />
<i>If disabled, your machine <b>must</b> be NTP synchronized</i>
<hr />
<b>Bandwidth limiter</b><br />
<b>Inbound rate</b>:
<input name="inboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="inboundRate" />" /> KBytes per second<br />
<b>Inbound burst duration:</b>
<jsp:getProperty name="nethelper" property="inboundBurstFactorBox" /><br />
<b>Outbound rate:</b>
<input name="outboundrate" type="text" size="2" value="<jsp:getProperty name="nethelper" property="outboundRate" />" /> KBytes per second<br />
<b>Outbound burst duration:</b>
<jsp:getProperty name="nethelper" property="outboundBurstFactorBox" /><br />
<i>A negative rate means there is no limit</i><br />
<hr />
<b>Reseed</b> (from <input name="reseedfrom" type="text" size="40" value="http://dev.i2p.net/i2pdb/" />):
<input type="submit" name="reseed" value="now" /><br />
<hr />
<input type="submit" value="Save changes" /> <input type="reset" value="Cancel" />
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - config advanced</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<jsp:useBean class="net.i2p.router.web.ConfigAdvancedHelper" id="advancedhelper" scope="request" />
<jsp:setProperty name="advancedhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<div class="main" id="main">
<%@include file="confignav.jsp" %>
<form action="configadvanced.jsp" method="POST">
<textarea rows="20" cols="80" name="config"><jsp:getProperty name="advancedhelper" property="settings" /></textarea><br />
<input type="submit" value="Apply" /> <input type="reset" value="Cancel" />
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,32 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - config clients</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<jsp:useBean class="net.i2p.router.web.ConfigClientsHelper" id="clientshelper" scope="request" />
<jsp:setProperty name="clientshelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<div class="main" id="main">
<%@include file="confignav.jsp" %>
<form action="configclients.jsp" method="POST">
<b>Estimated number of clients/destinations:</b>
<jsp:getProperty name="clientshelper" property="clientCountSelectBox" /><br />
<b>Default number of inbound tunnels per client:</b>
<jsp:getProperty name="clientshelper" property="tunnelCountSelectBox" /><br />
<b>Default number of hops per tunnel:</b>
<jsp:getProperty name="clientshelper" property="tunnelDepthSelectBox" /><br />
<hr />
<input type="submit" value="Save changes" /> <input type="reset" value="Cancel" />
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,39 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - config clients</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<jsp:useBean class="net.i2p.router.web.ConfigLoggingHelper" id="logginghelper" scope="request" />
<jsp:setProperty name="logginghelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<%@include file="confignav.jsp" %>
<form action="configlogging.jsp" method="POST">
<b>Logging filename:</b>
<input type="text" name="logfilename" size="40" value="<jsp:getProperty name="logginghelper" property="logFilePattern" />" /><br />
<i>(the symbol '#' will be replaced during log rotation)</i><br />
<b>Log record format:</b>
<input type="text" name="logformat" size="20" value="<jsp:getProperty name="logginghelper" property="recordPattern" />" /><br />
<i>(use 'd' = date, 'c' = class, 't' = thread, 'p' = priority, 'm' = message)</i><br />
<b>Log date format:</b>
<input type="text" name="logdateformat" size="20" value="<jsp:getProperty name="logginghelper" property="datePattern" />" /><br />
<i>('MM' = month, 'dd' = day, 'HH' = hour, 'mm' = minute, 'ss' = second, 'SSS' = millisecond)</i><br />
<b>Max log file size:</b>
<input type="text" name="logfilesize" size="4" value="<jsp:getProperty name="logginghelper" property="maxFileSize" />" /><br />
<hr />
<b>Log levels:</b> <br />
<jsp:getProperty name="logginghelper" property="logLevelTable" />
<hr />
<input type="submit" value="Apply changes" /> <input type="submit" value="Apply and Save" /> <input type="reset" value="Cancel" />
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,8 @@
<h4><% if (request.getRequestURI().indexOf("config.jsp") != -1) {
%>Network | <% } else { %><a href="config.jsp">Network</a> | <% }
if (request.getRequestURI().indexOf("configclients.jsp") != -1) {
%>Clients | <% } else { %><a href="configclients.jsp">Clients</a> | <% }
if (request.getRequestURI().indexOf("configlogging.jsp") != -1) {
%>Logging | <% } else { %><a href="configlogging.jsp">Logging</a> | <% }
if (request.getRequestURI().indexOf("configadvanced.jsp") != -1) {
%>Advanced | <% } else { %><a href="configadvanced.jsp">Advanced</a> | <% } %></h4>

View File

@ -0,0 +1,60 @@
body {
font-family: Verdana, Tahoma, Helvetica, sans-serif;
margin: 1em 0em;
padding: 0em;
text-align: center;
background-color: white;
color: black;
}
.hide {
display: none;
}
img {
border: none;
}
div.logo {
float: left;
left: 1em;
top: 1em;
margin: 0em;
padding: .5em;
text-align: left;
}
div.routersummary {
/* width: 8em; */
/* height: 5em; */
/* position: fixed; */
float: left;
/* left: 1em; */
/* top: 1em; */
margin: 0em;
padding: .5em;
text-align: left;
border: medium solid #efefff;
background-color: #fafaff;
color: inherit;
font-size: small;
clear: left; /* fixes a bug in Opera */
}
div.warning {
margin: 0em 1em 1em 12em;
padding: .5em 1em;
background-color: #ffefef;
border: medium solid #ffafaf;
text-align: left;
color: inherit;
}
div.main {
margin: 0em 1em 1em 12em;
padding: .5em 1em;
background-color: #ffffef;
border: medium solid #ffffd0;
text-align: left;
color: inherit;
}

View File

@ -0,0 +1,26 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - logs</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
hmm. we should probably have some help text here.<br />
This "routerconsole" application runs on top of a trimmed down <a href="jetty.mortbay.com/jetty/index.html">Jetty</a>
instance (trimmed down, as in, we do not include the demo apps or other add-ons), allowing you to deploy standard
JSP/Servlet web applications into your router. Jetty in turn makes use of Apache's javax.servlet (javax.servlet.jar)
implementation, as well as their xerces-j XML parser (xerces.jar). Their XML parser requires the Sun XML
APIs (JAXP) which is included in binary form (xml-apis.jar) as required by their binary code license.
This product includes software developed by the Apache Software Foundation (http://www.apache.org/). See the
<a href="http://www.i2p.net/">I2P</a> site or the source for more license details.
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

View File

@ -0,0 +1,19 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - home</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<h2>Welcome to your router console</h2>
</div>
</body>
</html>

View File

@ -0,0 +1,21 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - logs</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" />
<jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<jsp:getProperty name="logsHelper" property="logs" />
</div>
</body>
</html>

View File

@ -0,0 +1,18 @@
<%
if (request.getParameter("i2p.contextId") != null) {
session.setAttribute("i2p.contextId", request.getParameter("i2p.contextId"));
}%>
<div class="logo">
<a href="index.jsp"><img src="i2plogo.png" alt="Router Console" width="187" height="35" /></a><br />
[<a href="config.jsp">configuration</a> | <a href="help.jsp">help</a>]
</div>
<h3>
<a href="profiles.jsp">Profiles</a> |
<a href="netdb.jsp">Network Database</a> |
<a href="logs.jsp">Logs</a>
<jsp:useBean class="net.i2p.router.web.NavHelper" id="navhelper" scope="request" />
<jsp:setProperty name="navhelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<jsp:getProperty name="navhelper" property="clientAppLinks" />
</h3>

View File

@ -0,0 +1,21 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - network database summary</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<jsp:useBean class="net.i2p.router.web.NetDbHelper" id="netdbHelper" scope="request" />
<jsp:setProperty name="netdbHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<jsp:getProperty name="netdbHelper" property="netDbSummary" />
</div>
</body>
</html>

View File

@ -0,0 +1 @@
<%=(null != request.getParameter("i2p.console.notice") ? request.getParameter("i2p.console.notice") : "")%>

View File

@ -0,0 +1,21 @@
<%@page contentType="text/html"%>
<%@page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
<title>I2P Router Console - peer profiles</title>
<link rel="stylesheet" href="default.css" type="text/css" />
</head><body>
<%@include file="nav.jsp" %>
<%@include file="summary.jsp" %>
<%@include file="notice.jsp" %>
<div class="main" id="main">
<jsp:useBean class="net.i2p.router.web.ProfilesHelper" id="profilesHelper" scope="request" />
<jsp:setProperty name="profilesHelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<jsp:getProperty name="profilesHelper" property="profileSummary" />
</div>
</body>
</html>

View File

@ -0,0 +1,40 @@
<%@page import="net.i2p.router.web.SummaryHelper" %>
<jsp:useBean class="net.i2p.router.web.SummaryHelper" id="helper" scope="request" />
<jsp:setProperty name="helper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" />
<div class="routersummary">
<u><b>General</b></u><br />
<b>Ident:</b> <jsp:getProperty name="helper" property="ident" /><br />
<b>Version:</b> <jsp:getProperty name="helper" property="version" /><br />
<b>Uptime:</b> <jsp:getProperty name="helper" property="uptime" /><br />
<hr />
<u><b>Peers</b></u><br />
<b>Active:</b> <jsp:getProperty name="helper" property="activePeers" /><br />
<b>Fast:</b> <jsp:getProperty name="helper" property="fastPeers" /><br />
<b>High capacity:</b> <jsp:getProperty name="helper" property="highCapacityPeers" /><br />
<b>Well integrated:</b> <jsp:getProperty name="helper" property="wellIntegratedPeers" /><br />
<b>Failing:</b> <jsp:getProperty name="helper" property="failingPeers" /><br />
<b>Shitlisted:</b> <jsp:getProperty name="helper" property="shitlistedPeers" /><br />
<hr />
<u><b>Bandwidth in/out</b></u><br />
<b>1m:</b> <jsp:getProperty name="helper" property="inboundMinuteKBps" />/<jsp:getProperty name="helper" property="outboundMinuteKBps" />KBps<br />
<b>5m:</b> <jsp:getProperty name="helper" property="inboundFiveMinuteKBps" />/<jsp:getProperty name="helper" property="outboundFiveMinuteKBps" />KBps<br />
<b>Total:</b> <jsp:getProperty name="helper" property="inboundLifetimeKBps" />/<jsp:getProperty name="helper" property="outboundLifetimeKBps" />KBps<br />
<b>Used:</b> <jsp:getProperty name="helper" property="inboundTransferred" />/<jsp:getProperty name="helper" property="outboundTransferred" /><br />
<hr />
<u><b>Tunnels</b></u><br />
<b>Inbound:</b> <jsp:getProperty name="helper" property="inboundTunnels" /><br />
<b>Outbound:</b> <jsp:getProperty name="helper" property="outboundTunnels" /><br />
<b>Participating:</b> <jsp:getProperty name="helper" property="participatingTunnels" /><br />
<hr />
<u><b>Congestion</b></u><br />
<b>Job lag:</b> <jsp:getProperty name="helper" property="jobLag" /><br />
<b>Message delay:</b> <jsp:getProperty name="helper" property="messageDelay" /><br />
<b>Tunnel lag:</b> <jsp:getProperty name="helper" property="tunnelLag" /><br />
<hr />
</div>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
</web-app>

View File

@ -0,0 +1,25 @@
The routerconsole application is an embedable web server / servlet container.
In it there is a bundled routerconsole.war containing JSPs (per jsp/*) that
implement a web based control panel for the router. This console gives the user
a quick view into how their router is operating and exposes some pages to
configure it.
The web server itself is Jetty [1] and is contained within the various jar files
under lib/. To embed this web server and the included router console, the
startRouter script needs to be updated to include those jar files in the
class path, plus the router.config needs appropriate entries to start up the
server:
clientApp.3.main=net.i2p.router.web.RouterConsoleRunner
clientApp.3.name=webConsole
clientApp.3.args=7657 0.0.0.0 ./webapps/
That instructs the router to fire up the webserver listening on port 7657 on
all of its interfaces (0.0.0.0), loading up any .war files under the ./webapps/
directory. The RouterConsoleRunner itself configures the Jetty server to give
the ./webapps/routerconsole.war control over the root context, directing a
request to http://localhost:7657/index.jsp to the routerconsole.war's index.jsp.
Any other .war file will be mounted under their filename's context (e.g.
myi2p.war would be reachable at http://localhost:7657/myi2p/index.jsp).
[1] http://jetty.mortbay.com/jetty/index.html

View File

@ -1,3 +1,7 @@
v1.25
* Rewrote sendq functions to automatically send big packets, for better
network performance
v1.20 2004-07-11
* Ported to FreeBSD (Makefile.freebsd)
* Full winsock compatibility - all Windows functions now return appropriate

View File

@ -34,18 +34,28 @@
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
/*
* 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 */
/* The maximum length a SAM command can be */
#define SAM_CMD_LEN 128
/*The maximum size of a single datagram packet (-30 temporary bug fix for SAM)*/
#define SAM_DGRAM_PAYLOAD_MAX ((31 * 1024) - 30)
/* The longest log message */
#define SAM_LOGMSG_LEN 256
/* The longest `name' arg for the naming lookup callback */
#define SAM_NAME_LEN 256
/* The max size of a single stream packet */
#define SAM_STREAM_PAYLOAD_MAX (32 * 1024)
/* The length of a base 64 public key - it's actually 516, but +1 for '\0' */
#define SAM_PUBKEY_LEN 517
/* A public key SAM command's length */
#define SAM_PKCMD_LEN (SAM_PUBKEY_LEN + SAM_CMD_LEN)
/* The maximum length a SAM non-data reply can be */
#define SAM_REPLY_LEN 1024
/*
* Shorten some standard variable types
@ -81,14 +91,14 @@ typedef enum { /* see sam_strerror() for detailed descriptions of these */
*/
/* SAM controls */
extern bool sam_close(void);
extern bool sam_close();
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 bool sam_read_buffer();
extern const char *sam_strerror(samerr_t code);
/* SAM controls - callbacks */
extern void (*sam_diedback)(void);
extern void (*sam_diedback)();
extern void (*sam_logback)(char *str);
extern void (*sam_namingback)(char *name, sam_pubkey_t pubkey,
samerr_t result);
@ -105,10 +115,9 @@ 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);
extern void sam_sendq_add(sam_sid_t stream_id, sam_sendq_t **sendq,
const void *data, size_t dsize);
extern void sam_sendq_flush(sam_sid_t stream_id, sam_sendq_t **sendq);
/* Datagram commands */
extern samerr_t sam_dgram_send(const sam_pubkey_t dest, const void *data,

View File

@ -31,19 +31,20 @@
#include "platform.h"
#include "sam.h"
static bool sam_hello(void);
static bool sam_hello();
static void sam_log(const char *format, ...);
static void sam_parse(char *s);
static ssize_t sam_read1(char *buf, size_t n);
static ssize_t sam_read2(void *buf, size_t n);
static bool sam_readable(void);
static bool sam_readable();
static sam_sendq_t *sam_sendq_create();
static samerr_t sam_session_create(const char *destname, sam_conn_t style,
uint_t tunneldepth);
static bool sam_socket_connect(const char *host, uint16_t port);
static bool sam_socket_resolve(const char *hostname, char *ipaddr);
#ifdef WINSOCK
static samerr_t sam_winsock_cleanup(void);
static samerr_t sam_winsock_startup(void);
static samerr_t sam_winsock_cleanup();
static samerr_t sam_winsock_startup();
static const char *sam_winsock_strerror(int code);
#endif
static ssize_t sam_write(const void *buf, size_t n);
@ -61,7 +62,7 @@ void (*sam_databack)(sam_sid_t stream_id, void *data, size_t size) = NULL;
/* a peer sent some datagram data (`data' MUST be freed) */
void (*sam_dgramback)(sam_pubkey_t dest, void *data, size_t size) = NULL;
/* we lost the connection to the SAM host */
void (*sam_diedback)(void) = NULL;
void (*sam_diedback)() = NULL;
/* logging callback */
void (*sam_logback)(char *str) = NULL;
/* naming lookup reply - `pubkey' will be NULL if `result' isn't SAM_OK */
@ -79,7 +80,7 @@ static bool samd_connected = false; /* Whether we're connected with SAM */
*
* Returns: true on success, false on failure
*/
bool sam_close(void)
bool sam_close()
{
if (!samd_connected)
return true;
@ -119,7 +120,7 @@ bool sam_close(void)
* Returns: true on success, false on failure
*/
samerr_t sam_connect(const char *samhost, uint16_t samport,
const char *destname, sam_conn_t style, uint_t tunneldepth)
const char *destname, sam_conn_t style, uint_t tunneldepth)
{
samerr_t rc;
@ -212,7 +213,7 @@ samerr_t sam_dgram_send(const sam_pubkey_t dest, const void *data, size_t size)
*
* Returns: true on success, false on reply failure
*/
static bool sam_hello(void)
static bool sam_hello()
{
#define SAM_HELLO_CMD "HELLO VERSION MIN=1.0 MAX=1.0\n"
#define SAM_HELLO_REPLY "HELLO REPLY RESULT=OK VERSION=1.0"
@ -491,7 +492,7 @@ static void sam_parse(char *s)
*
* Returns: true if we read anything, or false if nothing was there
*/
bool sam_read_buffer(void)
bool sam_read_buffer()
{
bool read_something = false;
char reply[SAM_REPLY_LEN];
@ -639,7 +640,7 @@ static ssize_t sam_read2(void *buf, size_t n)
*
* Returns: true if data is waiting, false otherwise
*/
static bool sam_readable(void)
static bool sam_readable()
{
fd_set rset; /* set of readable descriptors */
struct timeval tv;
@ -679,36 +680,58 @@ static bool sam_readable(void)
*
* Returns: true on success, false on error
*/
samerr_t sam_sendq_add(sam_sendq_t *sendq, const void *data, size_t dsize)
void sam_sendq_add(sam_sid_t stream_id, sam_sendq_t **sendq, const void *data,
size_t dsize)
{
assert(dsize >= 0);
if (dsize == 0) {
SAMLOGS("dsize is 0 - adding nothing");
return SAM_OK;
} else if (sendq->size + dsize > SAM_STREAM_PAYLOAD_MAX) {
SAMLOGS("The queue size would exceed the maximum SAM payload size -" \
" will not add to the queue");
return SAM_TOO_BIG;
SAMLOGS("dsize is 0 - doing nothing");
return;
}
sendq->data = realloc(sendq->data, sendq->size + dsize);
memcpy(sendq->data + sendq->size, data, dsize);
sendq->size += dsize;
/* if the sendq pointer is set to NULL, create a sendq */
if (*sendq == NULL)
*sendq = sam_sendq_create();
return SAM_OK;
/* the added data doesn't fill the queue - add but don't send */
if ((*sendq)->size + dsize < SAM_STREAM_PAYLOAD_MAX) {
memcpy((*sendq)->data + (*sendq)->size, data, dsize);
(*sendq)->size += dsize;
return;
}
/* what luck! - an exact fit - send the packet */
if ((*sendq)->size + dsize == SAM_STREAM_PAYLOAD_MAX) {
memcpy((*sendq)->data + (*sendq)->size, data, dsize);
(*sendq)->size = SAM_STREAM_PAYLOAD_MAX;
sam_sendq_flush(stream_id, sendq);
return;
}
/* they have more data than the queue can hold, so we'll have to send some*/
size_t s = SAM_STREAM_PAYLOAD_MAX - (*sendq)->size; // space free in packet
memcpy((*sendq)->data + (*sendq)->size, data, s); //append as much as we can
dsize -= s; /* update dsize to the size of whatever data hasn't been sent*/
(*sendq)->size = SAM_STREAM_PAYLOAD_MAX; /* it's a full packet */
sam_sendq_flush(stream_id, sendq); /* send the queued data */
sam_sendq_add(stream_id, sendq, data + s, dsize); /* recurse the rest */
return;
}
/*
* Creates a data queue for use with sam_stream_send
* Creates a data queue for use with sam_sendq_add()
*
* Returns: pointer to the newly created send queue
*/
sam_sendq_t *sam_sendq_create(void)
static sam_sendq_t *sam_sendq_create()
{
sam_sendq_t *sendq;
sendq = malloc(sizeof(sam_sendq_t));
sendq->data = NULL;
sendq->data = malloc(SAM_STREAM_PAYLOAD_MAX);
/* ^^ a waste of memory perhaps, but more efficient than realloc'ing every
* time data is added the to queue */
sendq->size = 0;
return sendq;
@ -720,10 +743,13 @@ sam_sendq_t *sam_sendq_create(void)
* sendq - the send queue
* stream_id - stream number to send to
*/
void sam_sendq_send(sam_sendq_t *sendq, sam_sid_t stream_id)
void sam_sendq_flush(sam_sid_t stream_id, sam_sendq_t **sendq)
{
sam_stream_send(stream_id, sendq->data, sendq->size);
free(sendq);
sam_stream_send(stream_id, (*sendq)->data, (*sendq)->size);
/* we now free it in case they aren't going to use it anymore */
free((*sendq)->data);
free(*sendq);
*sendq = NULL;
return;
}
@ -738,7 +764,7 @@ void sam_sendq_send(sam_sendq_t *sendq, sam_sid_t stream_id)
* Returns: SAM error code
*/
static samerr_t sam_session_create(const char *destname, sam_conn_t style,
uint_t tunneldepth)
uint_t tunneldepth)
{
#define SAM_SESSTATUS_REPLY_OK "SESSION STATUS RESULT=OK"
#define SAM_SESSTATUS_REPLY_DD "SESSION STATUS RESULT=DUPLICATED_DEST"
@ -1034,7 +1060,7 @@ const char *sam_strerror(samerr_t code)
*
* Returns: SAM error code
*/
samerr_t sam_winsock_cleanup(void)
samerr_t sam_winsock_cleanup()
{
if (WSACleanup() == SOCKET_ERROR) {
SAMLOG("WSACleanup() failed: %s",
@ -1050,7 +1076,7 @@ samerr_t sam_winsock_cleanup(void)
*
* Returns: SAM error code
*/
samerr_t sam_winsock_startup(void)
samerr_t sam_winsock_startup()
{
/*
* Is Windows retarded or what?

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,8 @@
SAM - Simple Anonymous Messaging - is a protocol which allows
I2P applications to access the I2P network via an unencrypted
TCP socket connection.
Interim SAM protocol specification can be found at:
http://drupal.i2p.net/node/view/144
At time of first writing this README, an implementation of the SAM
server has been implemented in Jython (www.jython.org).
You can find the server code, and build files, in the ../jython
directory.
A python client implementation, containing demo functions,
can be found in the ../python directory.
I2P developers are strongly encouraged to create SAM
client implementations in other languages, most importantly,
popular portable languages like C/C++, Perl and Ruby.
The 'code.leo' file in this directory is used by the Leo
code editor (http://leo.sf.net), to manage the source in a
flexible tree format. While I can't insist on it, I'd
massively appreciate it if you could use this editor when
making additions and changes to the files herein, because
it will save me a lot of maintenance effort.
The Simple Anonymous Messaging protocol provides a way for
client applications to communicate anonymously over I2P without
having to deal with the complexities of I2CP. More information can
be found at http://www.i2p.net/sam and a comparison of the various
client access techniques is up at http://www.i2p.net/applications
There are a few SAM libraries available in this package, as well as
a Java implementation of the SAM bridge.

View File

@ -660,7 +660,10 @@ public class SAMv1Handler extends SAMHandler implements SAMRawReceiver, SAMDatag
}
}
return streamSession.closeConnection(id);
boolean closed = streamSession.closeConnection(id);
if ( (!closed) && (_log.shouldLog(Log.WARN)) )
_log.warn("Stream unable to be closed, but this is non fatal");
return true;
}
/* Check whether a size is inside the limits allowed by this protocol */

View File

@ -1,54 +0,0 @@
-----------------------------------
Instructions for building i2psam.jar
------------------------------------
1) Requirements
You will need:
- jython - www.jython.org
Note that you don't need python to build the SAM server
IMPORTANT - when you're installing jython, and running
'java on jython_n.n.class',
make sure you run the java.exe that's in your SDK, not the one in your
JRE.
---------------------------------------------------------
2) Preparation
- add the main jython directory to your PATH. Test this by typing
'jythonc' from a shell prompt.
----------------------------------------------------------
3) Building
- type 'ant build'
----------------------------------------------------------
4) Installing
Copy i2psam.jar to wherever the jar files live on your i2p installation,
usually <i2pbasedir>/lib
Find jython.jar, and copy it there too
----------------------------------------------------------
5) Running
(assuming that you're putting the start script into your main i2p
runtime directory, where the I2P jars live in a 'lib' subdirectory)
You will need to launch i2psam.jar with a command like:
java -cp lib/jython.jar:lib/i2p.jar:lib/mstreaming.jar:lib/i2psam.jar i2psam
or on windows,
java -cp lib\jython.jar;lib\i2p.jar;lib\mstreaming.jar;lib\i2psam.jar i2psam

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="sam">
<target name="all" depends="build" />
<target name="build" depends="builddep, jar" />
<target name="builddep">
<ant dir="../../../core/java/" target="build" />
<ant dir="../../ministreaming/java/" target="build" />
</target>
<target name="jar">
<condition property="jythonext" value=".bat">
<os family="windows" />
</condition>
<condition property="jythonext" value="">
<not>
<os family="windows" />
</not>
</condition>
<exec executable="jythonc${jythonext}" dir=".">
<env key="CLASSPATH" path="../../../core/java/build/i2p.jar:../../ministreaming/java/build/mstreaming.jar"/>
<arg value="--jar"/><arg path="./i2psam.jar"/>
<arg path="./src/i2psam.py"/>
</exec>
</target>
<target name="clean">
<delete file="i2psam.jar" />
<delete dir="./jpywork" />
</target>
</project>

File diff suppressed because it is too large Load Diff

18
apps/sam/python/bugs.txt Normal file
View File

@ -0,0 +1,18 @@
Known Bugs:
* TunnelServer may crash the I2P router in the following
ways when a large file is downloaded:
* Out of memory exception (for large files)
* Mysterious router death with no errors in the router logs
(more recently)
* BUG! in SAM proxy
See http://oregonstate.edu/~barnesc/temp/sam_crash.txt
* A small number of datagram packets sent are lost (even in a local
loopback). This is apparently a bug in I2P.
* Errors raised for sockets are non entirely consistent.
See todo.txt for how to fix this.
* A session does not close until a program exits.
This should be fine once I2P is patched to allow multiple
programs to use a single session at once.
* i2p.router.start() does not work.

View File

@ -0,0 +1,33 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title>Eeproxy - Wikipedia</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.ico">
<script type="text/javascript" src="/~barnesc/wiki/stylesheets/wikibits.js"></script>
<style type='text/css'><!--
@import url("/~barnesc/wiki/stylesheets/wikiprintable.css");
/*/*/
a.new, #quickbar a.new { color: #CC2200; }
#quickbar { position: absolute; top: 4px; left: 4px; border-right: 1px solid gray; }
#article { margin-left: 152px; margin-right: 4px; }
/* */
//--></style>
</head>
<body bgcolor='#FFFFFF' onload=''>
<h1 class='pagetitle'>Eeproxy</h1><p class='subtitle'>From Python-I2P.
<div class='bodytext'>
The <strong>Eeproxy</strong> is run by the I2P router. The proxy is normally used for web browsers, as a means of accessing eepsites.
<p>
The eeproxy is usually available at <a href="http://127.0.0.1:4444/" class='printable' title="http://127.0.0.1:4444/">http://127.0.0.1:4444/</a>.
<p>
</div>
<p><em>
</em><!-- Time since request: 0.77 secs. -->
</body></html>

View File

@ -0,0 +1,55 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title>User's Guide:i2p.eep - Wikipedia</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.ico">
<script type="text/javascript" src="/~barnesc/wiki/stylesheets/wikibits.js"></script>
<style type='text/css'><!--
@import url("/~barnesc/wiki/stylesheets/wikiprintable.css");
/*/*/
a.new, #quickbar a.new { color: #CC2200; }
#quickbar { position: absolute; top: 4px; left: 4px; border-right: 1px solid gray; }
#article { margin-left: 152px; margin-right: 4px; }
/* */
//--></style>
</head>
<body bgcolor='#FFFFFF' onload=''>
<h1 class='pagetitle'>User's Guide:i2p.eep</h1><p class='subtitle'>From Python-I2P.
<div class='bodytext'>
Module <code >i2p.eep</code > allows Python programs to access the <a href="./eeproxy.html" class='printable' title ="Eeproxy">Eeproxy</a>.
<p>
With this module, a program can easily download eepsites.
<p>
<h2><a name="Functions"> Functions </a></h2>
<p>
<strong>urlopen</strong>(url, eepaddr='127.0.0.1:4444')
<ul >
<pre> Like urllib2.urlopen(url), but only works for eep-sites.
Example: f = urlopen('<a href="http://duck.i2p/index.html" class='printable' title="http://duck.i2p/index.html">http://duck.i2p/index.html</a>')
</pre>
</ul >
<strong>urlget</strong>(url, eepaddr='127.0.0.1:4444')
<ul >
<pre> Get contents of an eepsite.
Example: urlget('<a href="http://duck.i2p/" class='printable' title="http://duck.i2p/">http://duck.i2p/</a>').
</pre>
</ul >
<p>
</div>
<p><em>
</em><!-- Time since request: 0.78 secs. -->
</body></html>

View File

@ -0,0 +1,61 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title>User's Guide:i2p - Wikipedia</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.ico">
<script type="text/javascript" src="/~barnesc/wiki/stylesheets/wikibits.js"></script>
<style type='text/css'><!--
@import url("/~barnesc/wiki/stylesheets/wikiprintable.css");
/*/*/
a.new, #quickbar a.new { color: #CC2200; }
#quickbar { position: absolute; top: 4px; left: 4px; border-right: 1px solid gray; }
#article { margin-left: 152px; margin-right: 4px; }
/* */
//--></style>
</head>
<body bgcolor='#FFFFFF' onload=''>
<h1 class='pagetitle'>User's Guide:i2p</h1><p class='subtitle'>From Python-I2P.
<div class='bodytext'>
Package <code >i2p</code > is a container package for more specific modules.
<p>
It exports the following names:
<ul >
<pre> <a href="./i2p.sam.html" class='printable' title ="User's Guide:i2p.sam">sam</a>
<a href="./i2p.eep.html" class='printable' title ="User's Guide:i2p.eep">eep</a>
<a href="./i2p.router.html" class='printable' title ="User's Guide:i2p.router">router</a>
<a href="#Error" class='printable' title ="User's Guide:i2p">Error</a>
<a href="#RouterError" class='printable' title ="User's Guide:i2p">RouterError</a>
</pre>
</ul >
<p>
class <strong>Error</strong>(Exception):
<ul >
<pre> Base class for all I2P errors.
</pre>
</ul >
<p>
class <strong>RouterError</strong>(Error):
<ul >
<pre> Could not connect to router.
</pre>
</ul >
<p>
</div>
<p><em>
</em><!-- Time since request: 0.85 secs. -->
</body></html>

View File

@ -0,0 +1,87 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title>User's Guide:i2p.router - Wikipedia</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.ico">
<script type="text/javascript" src="/~barnesc/wiki/stylesheets/wikibits.js"></script>
<style type='text/css'><!--
@import url("/~barnesc/wiki/stylesheets/wikiprintable.css");
/*/*/
a.new, #quickbar a.new { color: #CC2200; }
#quickbar { position: absolute; top: 4px; left: 4px; border-right: 1px solid gray; }
#article { margin-left: 152px; margin-right: 4px; }
/* */
//--></style>
</head>
<body bgcolor='#FFFFFF' onload=''>
<h1 class='pagetitle'>User's Guide:i2p.router</h1><p class='subtitle'>From Python-I2P.
<div class='bodytext'>
Module <code >i2p.router</code > allows Python programs to control the I2P router.
<p>
<h2><a name="Functions"> Functions </a></h2>
<p>
<strong>check</strong>(dir=None)
<ul ><pre>
Checks whether a locally installed router is running. Does
nothing if successful, otherwise raises i2p.RouterError.
An I2P installation is located by using find(dir).
The router.config file is parsed for 'router.adminPort'.
This port is queried to determine whether the router is
running.
</pre>
</ul >
<strong>find</strong>(dir=None)
<ul ><pre>
Find the absolute path to a locally installed I2P router.
An I2P installation is located by looking in the
environment I2P, then in PATH, then in the dir argument
given to the function. It looks for startRouter.sh or
startRouter.bat. Raises ValueError if an I2P installation
could not be located.
</pre>
</ul >
<strong>start</strong>(dir=None, hidden=False)
<ul ><pre>
Start a locally installed I2P router. Does nothing if
the router has already been started.
An I2P installation is located by using find(dir).
If hidden is True, do not show a terminal for the router.
</pre>
</ul >
<strong>stop</strong>(dir=None, force=False)
<ul ><pre>
Stop a locally installed I2P router, if it was started by
the current Python program. If force is True, stop the
router even if it was started by another process. Do nothing
if force is False and the router was started by another program.
The file 'router.config' is located using the same search
process used for find(dir). It is parsed for
'router.shutdownPassword' and 'router.adminPort'. The
router is shut down through the admin port.
Raises i2p.RouterError if the I2P router is running but cannot
be stopped. You must uncomment the
'router.shutdownPassword' line for this command to work.
</pre>
</ul >
<p>
</div>
<p><em>
</em><!-- Time since request: 0.77 secs. -->
</body></html>

View File

@ -0,0 +1,308 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title>User's Guide:i2p.sam - Wikipedia</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.ico">
<script type="text/javascript" src="/~barnesc/wiki/stylesheets/wikibits.js"></script>
<style type='text/css'><!--
@import url("/~barnesc/wiki/stylesheets/wikiprintable.css");
/*/*/
a.new, #quickbar a.new { color: #CC2200; }
#quickbar { position: absolute; top: 4px; left: 4px; border-right: 1px solid gray; }
#article { margin-left: 152px; margin-right: 4px; }
/* */
//--></style>
</head>
<body bgcolor='#FFFFFF' onload=''>
<h1 class='pagetitle'>User's Guide:i2p.sam</h1><p class='subtitle'>From Python-I2P.
<div class='bodytext'><a name="top"></a>
Module <code >i2p.sam</code > allows Python programs to access the <a href="./samproxy.html" class='printable' title ="SAM proxy">SAM proxy</a>.
<p>
With this module, a program can send stream data, datagrams, and raw packets across the I2P network.
<p>
<p><table border="0" id="toc"><tr><td align="center">
<b>Table of contents</b></td></tr><tr id='tocinside'><td>
<div style="margin-bottom:0px;">
<A CLASS="internal" HREF="#Sockets">1 Sockets</A><BR>
</div>
<div style="margin-bottom:0px;">
<A CLASS="internal" HREF="#Tunnels">2 Tunnels</A><BR>
</div>
<div style="margin-left:2em;">
<A CLASS="internal" HREF="#Tunnel_Server">2.1 Tunnel Server</A><BR>
<A CLASS="internal" HREF="#Tunnel_Client">2.2 Tunnel Client</A><BR>
</div>
<div style="margin-bottom:0px;">
<A CLASS="internal" HREF="#Errors">3 Errors</A><BR>
</div>
<div style="margin-bottom:0px;">
<A CLASS="internal" HREF="#Constants">4 Constants</A><BR>
</div>
</td></tr></table><P>
<h2><a name="Sockets"> Sockets </a></h2>
<p>
<strong>socket</strong>(session, type, samaddr='127.0.0.1:7656', **kwargs)
<ul ><pre>
Create a new socket. Argument session should be a session
name -- if the name has not yet been used, an I2P
Destination will be created for it, otherwise, the
existing Destination will be re-used. An empty session
string causes a transient session to be created. Argument
type is one of SOCK_STREAM, SOCK_DGRAM, or SOCK_RAW.
I2P configuration keyword arguments:
* in_depth - depth of incoming tunnel (default 2)
* out_depth - depth of outgoing tunnel (default 2)
A single session may be shared by more than one socket, if
the sockets are the same type, and if the sockets are
created within the same Python process. The socket
objects are multithread-safe.
Examples:
a = i2p.socket('Alice', i2p.SOCK_STREAM)
b = i2p.socket('Bob', i2p.SOCK_DGRAM,
in_depth=2, out_depth=5)
The created object behaves identically to a socket from
module socket, with the following exceptions:
* I2P Destinations are used as address arguments [1].
* bind is a no-op: sockets are always bound.
* send* methods send all data and are non-blocking.
A given session name can only be open in a single Python
program at a time. If you need to overcome this
limitation, consider patching I2P.
[1]. Alternatively, a host name can be used as an address.
It will be resolved using hosts.txt.
For details on how to use socket objects, see
http://www.python.org/doc/current/lib/socket-objects.html
See the examples directory for code examples.
</pre>
</ul >
<strong>socket()</strong> object properties:
<ul >
<pre> dest - Local I2P Destination of socket
session - Session name
type - Socket type: SOCK_STREAM, SOCK_DGRAM, or SOCK_RAW.
</pre>
</ul >
<strong>poll</strong>()
<ul >
<pre> Returns a polling object. Works on SAM sockets and Python sockets.
See <a href='http://www.python.org/doc/current/lib/module-select.html' class='printable' title="http://www.python.org/doc/current/lib/module-select.html">select.poll()</a> in the Python library for more information.
</pre>
</ul >
<p>
<strong>resolve</strong>(host, samaddr='127.0.0.1:7656')
<ul >
<pre> Resolve I2P host name --&gt; I2P Destination.
Returns the same string if host is already a Destination.
</pre>
</ul >
<p>
<strong>select</strong>(readlist, writelist, errlist, timeout=None)
<ul >
<pre> Performs a select call. Works on SAM sockets and Python sockets.
See <a href='http://www.python.org/doc/current/lib/module-select.html' class='printable' title="http://www.python.org/doc/current/lib/module-select.html">select.select()</a> in the Python library for more information.
</pre>
</ul >
<p>
<h2><a name="Tunnels"> Tunnels </a></h2>
<p>
Tunnels allow stream sockets to be joined, so that connections to a listening socket are relayed to one or more sending sockets. This allows an ordinary web server to be exposed as an I2P Destination, or an I2P Destination to be bound as a local port, and so on.
<p>
class <strong>Tunnel</strong>(self, receive, make_send, nconnect=-1, timeout=60.0)
<ul ><pre>
A Tunnel relays connections from a 'receive' socket to one
or more 'send' sockets. The receive socket must be bound
and listening. For each incoming connection, a new send
socket is created by calling make_send(). Data is then
exchanged between the created streams until one socket is
closed. nconnect is the maximum number of simultaneous
connections (-1 for infinite), and timeout is the time that
a single connection can last for (None allows a connection
to last forever).
Sockets must accept stream traffic and support the Python
socket interface. A separate daemonic thread is created to
manage the tunnel. For high performance, make_send() should
make a socket and connect in non-blocking mode (you should
catch and discard the sam.BlockError or socket.error due to
executing connect on a non-blocking socket).
Security Note:
A firewall is needed to maintain the end user's anonymity.
An attacker could keep a tunnel socket open by pinging it
regularly. The accepted sockets from 'receive' must prevent
this by closing down eventually.
Socket errors do not cause the Tunnel to shut down.
</pre>
</ul >
<p>
<strong>close</strong>()
<ul >
<pre> Close all connections made for this tunnel.
</pre>
</ul >
<p>
<h3><a name="Tunnel_Server"> Tunnel Server </a></h3>
<p>
class <strong>TunnelServer</strong>(session, port, samaddr='127.0.0.1:7656', nconnect=-1, timeout=None, **kwargs)
<ul ><pre>
Tunnels incoming SAM streams --&gt; localhost:port.
nconnect and timeout are the maximum number of connections
and maximum time per connection. All other arguments are
passed to sam.socket(). This call blocks until the tunnel
is ready.
</pre>
</ul >
<p>
<strong>TunnelServer</strong> properties:
<ul ><pre>
dest - I2P Destination of server.
session - Session name for server.
</pre>
</ul >
<p>
<h3><a name="Tunnel_Client"> Tunnel Client </a></h3>
<p>
class <strong>TunnelClient</strong>(session, port, dest, samaddr='127.0.0.1:7656', nconnect=-1, timeout=None, **kwargs)
<ul ><pre>
Derived from Tunnel.
Tunnels localhost:port --&gt; I2P Destination dest.
A session named 'session' is created locally, for purposes
of routing to 'dest'. nconnect and timeout are the maximum
number of connections and maximum time per connection. All
other arguments are passed to sam.socket(). This call blocks
until the tunnel is ready.
</pre>
</ul >
<p>
<strong>TunnelClient</strong> properties:
<ul ><pre>
dest - Local Destination used for routing.
remotedest - Remote Destination.
session - Session name for local Destination.
</pre>
</ul >
<p>
<h2><a name="Errors"> Errors </a></h2>
<p>
class <strong>Error</strong>(i2p.Error)
<ul ><pre>
Base class for all SAM errors.
</pre>
</ul >
class <strong>BlockError</strong>(Error)
<ul ><pre>
Socket call would have blocked.
</pre>
</ul >
class <strong>ClosedError</strong>(Error)
<ul ><pre>
A command was used on a socket that closed gracefully.
</pre>
</ul >
class <strong>NetworkError</strong>(Error)
<ul ><pre>
Network error occurred within I2P.
The error object is a 2-tuple: (errtag, errdesc).
errtag is a SAM error string,
errdesc is a human readable error description.
</pre>
</ul >
<p>
<h2><a name="Constants"> Constants </a></h2>
<p>
<strong>Socket types</strong>
<ul ><pre>
SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
</pre>
</ul >
<strong>Packet sizes</strong>
<ul ><pre>
MAX_DGRAM = 31744 # Maximum size for datagram packet
MAX_RAW = 32768 # Maximum size for raw packet
</pre>
</ul >
<strong>Flags for recv()</strong>
<ul ><pre>
MSG_DONTWAIT = 128 # Don't block
MSG_PEEK = 2 # Peek at incoming data
MSG_WAITALL = 64 # Wait for all data or error
</pre>
</ul >
<strong>Polling flags</strong>
<ul ><pre>
POLLIN = 1
POLLOUT = 4
POLLERR = 8
POLLHUP = 16
POLLNVAL = 32
POLLPRI = 1
</pre>
</ul >
<p>
</div>
<p><em>
</em><!-- Time since request: 0.86 secs. -->
</body></html>

View File

@ -0,0 +1,76 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title>Main Page - Wikipedia</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.ico">
<script type="text/javascript" src="/~barnesc/wiki/stylesheets/wikibits.js"></script>
<style type='text/css'><!--
@import url("/~barnesc/wiki/stylesheets/wikiprintable.css");
/*/*/
a.new, #quickbar a.new { color: #CC2200; }
#quickbar { position: absolute; top: 4px; left: 4px; border-right: 1px solid gray; }
#article { margin-left: 152px; margin-right: 4px; }
/* */
//--></style>
</head>
<body bgcolor='#FFFFFF' onload=''>
<h1 class='pagetitle'>Main Page</h1><p class='subtitle'>From Python-I2P.
<div class='bodytext'>
<strong>Python-I2P</strong> is a Python interface to <a href='http://www.i2p.net' class='printable' title="http://www.i2p.net">I2P</a>.
<p>
<h2><a name="Quick_Start"> Quick Start </a></h2>
<p>
Install:
<p>
<ul ><pre>
python setup.py install
</pre>
</ul >
<p>
Use:
<p>
<ul ><pre>
&gt;&gt;&gt; from i2p import sam
&gt;&gt;&gt; s = sam.socket('Alice', sam.SOCK_STREAM)
&gt;&gt;&gt; s.connect('duck.i2p')
&gt;&gt;&gt; s.send('GET / HTTP/1.0\r\n\r\n')
&gt;&gt;&gt; s.recv(1000)
(HTTP response from duck.i2p)
</pre>
</ul >
<p>
<h2><a name="User's_Guide"> User's Guide </a></h2>
<p>
The following modules are available:
<p>
<ul >
<pre> <a href="./i2p.html" class='printable' title ="User's Guide:i2p">i2p</a> (Container package)
<a href="./i2p.sam.html" class='printable' title ="User's Guide:i2p.sam">i2p.sam</a> (Send and receive across the I2P network)
<a href="./i2p.eep.html" class='printable' title ="User's Guide:i2p.eep">i2p.eep</a> (Retrieve eepsites)
<a href="./i2p.router.html" class='printable' title ="User's Guide:i2p.router">i2p.router</a> (Manage the I2P router)
</pre>
</ul >
<p>
</div>
<p><em>
</em><!-- Time since request: 0.78 secs. -->
</body></html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html lang="en"><head><title>SAM proxy - Wikipedia</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="robots" content="index,follow">
<link rel="shortcut icon" href="/favicon.ico">
<script type="text/javascript" src="/~barnesc/wiki/stylesheets/wikibits.js"></script>
<style type='text/css'><!--
@import url("/~barnesc/wiki/stylesheets/wikiprintable.css");
/*/*/
a.new, #quickbar a.new { color: #CC2200; }
#quickbar { position: absolute; top: 4px; left: 4px; border-right: 1px solid gray; }
#article { margin-left: 152px; margin-right: 4px; }
/* */
//--></style>
</head>
<body bgcolor='#FFFFFF' onload=''>
<h1 class='pagetitle'>SAM proxy</h1><p class='subtitle'>From Python-I2P.
<div class='bodytext'>
A <strong>SAM proxy</strong> is run by the I2P router. The proxy allows streams, datagrams, and raw packets to be sent through the I2P network. A client application uses a telnet-like session to communicate with the proxy. In this way, the core features of the I2P library can be used by any language.
<p>
The protocol used for SAM is described in <a href='http://dev.i2p.net/pipermail/i2p/2004-July/000353.html' class='printable' title="http://dev.i2p.net/pipermail/i2p/2004-July/000353.html">SAM 1.0</a>.
<p>
In practice, a <em>SAM library</em> is usually written, so that client applications do not need to use the low-level SAM commands.
<p>
</div>
<p><em>
</em><!-- Time since request: 0.77 secs. -->
</body></html>

View File

@ -0,0 +1,5 @@
Title: Eeproxy
The '''Eeproxy''' is run by the I2P router. The proxy is normally used for web browsers, as a means of accessing eepsites.
The eeproxy is usually available at http://127.0.0.1:4444/.

View File

@ -0,0 +1,18 @@
Title: User's Guide:i2p.eep
Module <code>i2p.eep</code> allows Python programs to access the [[Eeproxy]].
With this module, a program can easily download eepsites.
== Functions ==
'''urlopen'''(url, eepaddr='127.0.0.1:4444')
<ul>
Like urllib2.urlopen(url), but only works for eep-sites.
Example: f = urlopen('http://duck.i2p/index.html')
</ul>
'''urlget'''(url, eepaddr='127.0.0.1:4444')
<ul>
Get contents of an eepsite.
Example: urlget('http://duck.i2p/').
</ul>

View File

@ -0,0 +1,51 @@
Title: User's Guide:i2p.router
Module <code>i2p.router</code> allows Python programs to control the I2P router.
== Functions ==
'''check'''(dir=None)
<ul><pre>
Checks whether a locally installed router is running. Does
nothing if successful, otherwise raises i2p.RouterError.
An I2P installation is located by using find(dir).
The router.config file is parsed for 'router.adminPort'.
This port is queried to determine whether the router is
running.
</pre></ul>
'''find'''(dir=None)
<ul><pre>
Find the absolute path to a locally installed I2P router.
An I2P installation is located by looking in the
environment I2P, then in PATH, then in the dir argument
given to the function. It looks for startRouter.sh or
startRouter.bat. Raises ValueError if an I2P installation
could not be located.
</pre></ul>
'''start'''(dir=None, hidden=False)
<ul><pre>
Start a locally installed I2P router. Does nothing if
the router has already been started.
An I2P installation is located by using find(dir).
If hidden is True, do not show a terminal for the router.
</pre></ul>
'''stop'''(dir=None, force=False)
<ul><pre>
Stop a locally installed I2P router, if it was started by
the current Python program. If force is True, stop the
router even if it was started by another process. Do nothing
if force is False and the router was started by another program.
The file 'router.config' is located using the same search
process used for find(dir). It is parsed for
'router.shutdownPassword' and 'router.adminPort'. The
router is shut down through the admin port.
Raises i2p.RouterError if the I2P router is running but cannot
be stopped. You must uncomment the
'router.shutdownPassword' line for this command to work.
</pre></ul>

View File

@ -0,0 +1,202 @@
Title: User's Guide:i2p.sam
Module <code>i2p.sam</code> allows Python programs to access the [[SAM proxy]].
With this module, a program can send stream data, datagrams, and raw packets across the I2P network.
== Sockets ==
'''socket'''(session, type, samaddr='127.0.0.1:7656', **kwargs)
<ul><pre>
Create a new socket. Argument session should be a session
name -- if the name has not yet been used, an I2P
Destination will be created for it, otherwise, the
existing Destination will be re-used. An empty session
string causes a transient session to be created. Argument
type is one of SOCK_STREAM, SOCK_DGRAM, or SOCK_RAW.
I2P configuration keyword arguments:
* in_depth - depth of incoming tunnel (default 2)
* out_depth - depth of outgoing tunnel (default 2)
A single session may be shared by more than one socket, if
the sockets are the same type, and if the sockets are
created within the same Python process. The socket
objects are multithread-safe.
Examples:
a = i2p.socket('Alice', i2p.SOCK_STREAM)
b = i2p.socket('Bob', i2p.SOCK_DGRAM,
in_depth=2, out_depth=5)
The created object behaves identically to a socket from
module socket, with the following exceptions:
* I2P Destinations are used as address arguments [1].
* bind is a no-op: sockets are always bound.
* send* methods send all data and are non-blocking.
A given session name can only be open in a single Python
program at a time. If you need to overcome this
limitation, consider patching I2P.
[1]. Alternatively, a host name can be used as an address.
It will be resolved using hosts.txt.
For details on how to use socket objects, see
http://www.python.org/doc/current/lib/socket-objects.html
See the examples directory for code examples.
</pre></ul>
'''socket()''' object properties:
<ul>
dest - Local I2P Destination of socket
session - Session name
type - Socket type: SOCK_STREAM, SOCK_DGRAM, or SOCK_RAW.
</ul>
'''poll'''()
<ul>
Returns a polling object. Works on SAM sockets and Python sockets.
See [http://www.python.org/doc/current/lib/module-select.html select.poll()] in the Python library for more information.
</ul>
'''resolve'''(host, samaddr='127.0.0.1:7656')
<ul>
Resolve I2P host name --> I2P Destination.
Returns the same string if host is already a Destination.
</ul>
'''select'''(readlist, writelist, errlist, timeout=None)
<ul>
Performs a select call. Works on SAM sockets and Python sockets.
See [http://www.python.org/doc/current/lib/module-select.html select.select()] in the Python library for more information.
</ul>
== Tunnels ==
Tunnels allow stream sockets to be joined, so that connections to a listening socket are relayed to one or more sending sockets. This allows an ordinary web server to be exposed as an I2P Destination, or an I2P Destination to be bound as a local port, and so on.
class '''Tunnel'''(self, receive, make_send, nconnect=-1, timeout=60.0)
<ul><pre>
A Tunnel relays connections from a 'receive' socket to one
or more 'send' sockets. The receive socket must be bound
and listening. For each incoming connection, a new send
socket is created by calling make_send(). Data is then
exchanged between the created streams until one socket is
closed. nconnect is the maximum number of simultaneous
connections (-1 for infinite), and timeout is the time that
a single connection can last for (None allows a connection
to last forever).
Sockets must accept stream traffic and support the Python
socket interface. A separate daemonic thread is created to
manage the tunnel. For high performance, make_send() should
make a socket and connect in non-blocking mode (you should
catch and discard the sam.BlockError or socket.error due to
executing connect on a non-blocking socket).
Security Note:
A firewall is needed to maintain the end user's anonymity.
An attacker could keep a tunnel socket open by pinging it
regularly. The accepted sockets from 'receive' must prevent
this by closing down eventually.
Socket errors do not cause the Tunnel to shut down.
</pre></ul>
'''close'''()
<ul>
Close all connections made for this tunnel.
</ul>
=== Tunnel Server ===
class '''TunnelServer'''(session, port, samaddr='127.0.0.1:7656', nconnect=-1, timeout=None, **kwargs)
<ul><pre>
Tunnels incoming SAM streams --> localhost:port.
nconnect and timeout are the maximum number of connections
and maximum time per connection. All other arguments are
passed to sam.socket(). This call blocks until the tunnel
is ready.
</pre></ul>
'''TunnelServer''' properties:
<ul><pre>
dest - I2P Destination of server.
session - Session name for server.
</pre></ul>
=== Tunnel Client ===
class '''TunnelClient'''(session, port, dest, samaddr='127.0.0.1:7656', nconnect=-1, timeout=None, **kwargs)
<ul><pre>
Derived from Tunnel.
Tunnels localhost:port --> I2P Destination dest.
A session named 'session' is created locally, for purposes
of routing to 'dest'. nconnect and timeout are the maximum
number of connections and maximum time per connection. All
other arguments are passed to sam.socket(). This call blocks
until the tunnel is ready.
</pre></ul>
'''TunnelClient''' properties:
<ul><pre>
dest - Local Destination used for routing.
remotedest - Remote Destination.
session - Session name for local Destination.
</pre></ul>
== Errors ==
class '''Error'''(i2p.Error)
<ul><pre>
Base class for all SAM errors.
</pre></ul>
class '''BlockError'''(Error)
<ul><pre>
Socket call would have blocked.
</pre></ul>
class '''ClosedError'''(Error)
<ul><pre>
A command was used on a socket that closed gracefully.
</pre></ul>
class '''NetworkError'''(Error)
<ul><pre>
Network error occurred within I2P.
The error object is a 2-tuple: (errtag, errdesc).
errtag is a SAM error string,
errdesc is a human readable error description.
</pre></ul>
== Constants ==
'''Socket types'''
<ul><pre>
SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
</pre></ul>
'''Packet sizes'''
<ul><pre>
MAX_DGRAM = 31744 # Maximum size for datagram packet
MAX_RAW = 32768 # Maximum size for raw packet
</pre></ul>
'''Flags for recv()'''
<ul><pre>
MSG_DONTWAIT = 128 # Don't block
MSG_PEEK = 2 # Peek at incoming data
MSG_WAITALL = 64 # Wait for all data or error
</pre></ul>
'''Polling flags'''
<ul><pre>
POLLIN = 1
POLLOUT = 4
POLLERR = 8
POLLHUP = 16
POLLNVAL = 32
POLLPRI = 1
</pre></ul>

View File

@ -0,0 +1,22 @@
Title: User's Guide:i2p
Package <code>i2p</code> is a container package for more specific modules.
It exports the following names:
<ul>
[[:User's Guide:i2p.sam|sam]]
[[:User's Guide:i2p.eep|eep]]
[[:User's Guide:i2p.router|router]]
[[:User's Guide:i2p#Error|Error]]
[[:User's Guide:i2p#RouterError|RouterError]]
</ul>
class '''Error'''(Exception):
<ul>
Base class for all I2P errors.
</ul>
class '''RouterError'''(Error):
<ul>
Could not connect to router.
</ul>

View File

@ -0,0 +1,33 @@
Title: Main Page
'''Python-I2P''' is a Python interface to [http://www.i2p.net I2P].
== Quick Start ==
Install:
<ul><pre>
python setup.py install
</pre></ul>
Use:
<ul><pre>
>>> from i2p import sam
>>> s = sam.socket('Alice', sam.SOCK_STREAM)
>>> s.connect('duck.i2p')
>>> s.send('GET / HTTP/1.0\r\n\r\n')
>>> s.recv(1000)
(HTTP response from duck.i2p)
</pre></ul>
== User's Guide ==
The following modules are available:
<ul>
[[:User's Guide:i2p|i2p]] (Container package)
[[:User's Guide:i2p.sam|i2p.sam]] (Send and receive across the I2P network)
[[:User's Guide:i2p.eep|i2p.eep]] (Retrieve eepsites)
[[:User's Guide:i2p.router|i2p.router]] (Manage the I2P router)
</ul>

View File

@ -0,0 +1,18 @@
The documentation was created by using MediaWiki software.
This directory houses the wiki text sources.
Feel free to move to any other documentation system, if
it is efficient and easy to maintain.
Ideally, one could patch pydoc to export only certain
names, in a certain order, like so:
__pydoc__ = ['f', 'g'] # f() and g() documented in order
This could proceed recursively for all namespaces.
Combine this with a second patch to make pydoc create
nice CSS, and this whole guide could be generated
directly from the sources.

View File

@ -0,0 +1,7 @@
Title: SAM proxy
A '''SAM proxy''' is run by the I2P router. The proxy allows streams, datagrams, and raw packets to be sent through the I2P network. A client application uses a telnet-like session to communicate with the proxy. In this way, the core features of the I2P library can be used by any language.
The protocol used for SAM is described in [http://dev.i2p.net/pipermail/i2p/2004-July/000353.html SAM 1.0].
In practice, a ''SAM library'' is usually written, so that client applications do not need to use the low-level SAM commands.

View File

@ -0,0 +1,14 @@
<html>
<body bgcolor=#ffffff text=#000000 link=#0000ff alink=#0000ff vlink=#0000ff>
<h1>Python-I2P</h1>
Documentation:
<ul>
<li><a href="./guide/index.html">User's Guide</a><br>
<li><a href="./pydoc/i2p.html">Pydoc Documentation</a><br>
</ul>
</body>
</html>

View File

@ -0,0 +1,40 @@
<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module i2p.eep</title>
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="i2p.html"><font color="#ffffff">i2p</font></a>.eep</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:///D|/code/i2p/i2p/eep.py">d:\code\i2p\i2p\eep.py</a></font></td></tr></table>
<p><tt>Eeproxy&nbsp;Python&nbsp;API</tt></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#fffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="urllib2.html">urllib2</a><br>
</td><td width="25%" valign=top></td><td width="25%" valign=top></td><td width="25%" valign=top></td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#eeaa77">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Functions</strong></big></font></td></tr>
<tr><td bgcolor="#eeaa77"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl><dt><a name="-urlget"><strong>urlget</strong></a>(url, eepaddr<font color="#909090">='127.0.0.1:4444'</font>)</dt><dd><tt>Get&nbsp;contents&nbsp;of&nbsp;an&nbsp;eepsite.<br>
Example:&nbsp;<a href="#-urlget">urlget</a>('<a href="http://duck.i2p/">http://duck.i2p/</a>').</tt></dd></dl>
<dl><dt><a name="-urlopen"><strong>urlopen</strong></a>(url, eepaddr<font color="#909090">='127.0.0.1:4444'</font>)</dt><dd><tt>Like&nbsp;urllib2.<a href="#-urlopen">urlopen</a>(url),&nbsp;but&nbsp;only&nbsp;works&nbsp;for&nbsp;eep-sites.<br>
Example:&nbsp;f&nbsp;=&nbsp;<a href="#-urlopen">urlopen</a>('<a href="http://duck.i2p/index.html">http://duck.i2p/index.html</a>')</tt></dd></dl>
</td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><strong>eepaddr</strong> = '127.0.0.1:4444'</td></tr></table>
</body></html>

View File

@ -0,0 +1,90 @@
<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: package i2p</title>
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong>i2p</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:///D|/code/i2p/i2p/__init__.py">d:\code\i2p\i2p\__init__.py</a></font></td></tr></table>
<p><tt>i2p&nbsp;--&nbsp;I2P&nbsp;Python&nbsp;interface</tt></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Package Contents</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="i2p.eep.html">eep</a><br>
</td><td width="25%" valign=top><a href="i2p.router.html">router</a><br>
</td><td width="25%" valign=top><a href="i2p.sam.html">sam</a><br>
</td><td width="25%" valign=top><a href="i2p.samclasses.html">samclasses</a><br>
</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl>
<dt><font face="helvetica, arial"><a href="exceptions.html#Exception">exceptions.Exception</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="i2p.html#Error">Error</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="i2p.html#RouterError">RouterError</a>
</font></dt></dl>
</dd>
</dl>
</dd>
</dl>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Error">class <strong>Error</strong></a>(<a href="exceptions.html#Exception">exceptions.Exception</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Base&nbsp;class&nbsp;for&nbsp;all&nbsp;I2P&nbsp;errors.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
<dl><dt><a name="Error-__getitem__"><strong>__getitem__</strong></a>(...)</dt></dl>
<dl><dt><a name="Error-__init__"><strong>__init__</strong></a>(...)</dt></dl>
<dl><dt><a name="Error-__str__"><strong>__str__</strong></a>(...)</dt></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="RouterError">class <strong>RouterError</strong></a>(<a href="i2p.html#Error">Error</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Could&nbsp;not&nbsp;connect&nbsp;to&nbsp;router.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="i2p.html#RouterError">RouterError</a></dd>
<dd><a href="i2p.html#Error">Error</a></dd>
<dd><a href="exceptions.html#Exception">exceptions.Exception</a></dd>
</dl>
<hr>
Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
<dl><dt><a name="RouterError-__getitem__"><strong>__getitem__</strong></a>(...)</dt></dl>
<dl><dt><a name="RouterError-__init__"><strong>__init__</strong></a>(...)</dt></dl>
<dl><dt><a name="RouterError-__str__"><strong>__str__</strong></a>(...)</dt></dl>
</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><strong>__all__</strong> = ['Error', 'RouterError', 'sam', 'eep', 'router']</td></tr></table>
</body></html>

View File

@ -0,0 +1,38 @@
<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module i2p.router</title>
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="i2p.html"><font color="#ffffff">i2p</font></a>.router</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:///D|/code/i2p/i2p/router.py">d:\code\i2p\i2p\router.py</a></font></td></tr></table>
<p><tt>Router&nbsp;Control&nbsp;API&nbsp;for&nbsp;Python</tt></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#fffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="i2p.html">i2p</a><br>
<a href="os.html">os</a><br>
</td><td width="25%" valign=top><a href="socket.html">socket</a><br>
<a href="sys.html">sys</a><br>
</td><td width="25%" valign=top><a href="threading.html">threading</a><br>
<a href="time.html">time</a><br>
</td><td width="25%" valign=top><a href="urllib2.html">urllib2</a><br>
</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><strong>check_addrlist</strong> = ['127.0.0.1:7656', '127.0.0.1:4444']<br>
<strong>our_router</strong> = False<br>
<strong>our_router_lock</strong> = &lt;thread.lock object at 0x008AD0F0&gt;<br>
<strong>router_config</strong> = 'router.config'</td></tr></table>
</body></html>

View File

@ -0,0 +1,374 @@
<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module i2p.sam</title>
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="i2p.html"><font color="#ffffff">i2p</font></a>.sam</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:///D|/code/i2p/i2p/sam.py">d:\code\i2p\i2p\sam.py</a></font></td></tr></table>
<p><tt>SAM&nbsp;Python&nbsp;API</tt></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#fffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="Queue.html">Queue</a><br>
<a href="copy.html">copy</a><br>
<a href="i2p.html">i2p</a><br>
</td><td width="25%" valign=top><a href="select.html">select</a><br>
<a href="socket.html">socket</a><br>
<a href="i2p.samclasses.html">i2p.samclasses</a><br>
</td><td width="25%" valign=top><a href="thread.html">thread</a><br>
<a href="threading.html">threading</a><br>
<a href="time.html">time</a><br>
</td><td width="25%" valign=top></td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl>
<dt><font face="helvetica, arial"><a href="i2p.html#Error">i2p.Error</a>(<a href="exceptions.html#Exception">exceptions.Exception</a>)
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="i2p.sam.html#Error">Error</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="i2p.sam.html#BlockError">BlockError</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.sam.html#ClosedError">ClosedError</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.sam.html#NetworkError">NetworkError</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.sam.html#Timeout">Timeout</a>
</font></dt></dl>
</dd>
</dl>
</dd>
<dt><font face="helvetica, arial"><a href="i2p.sam.html#Poll">Poll</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.sam.html#Socket">Socket</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.sam.html#Tunnel">Tunnel</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="i2p.sam.html#TunnelClient">TunnelClient</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.sam.html#TunnelServer">TunnelServer</a>
</font></dt></dl>
</dd>
</dl>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="BlockError">class <strong>BlockError</strong></a>(<a href="i2p.sam.html#Error">Error</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt><a href="#Socket">Socket</a>&nbsp;call&nbsp;would&nbsp;have&nbsp;blocked.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="i2p.sam.html#BlockError">BlockError</a></dd>
<dd><a href="i2p.sam.html#Error">Error</a></dd>
<dd><a href="i2p.html#Error">i2p.Error</a></dd>
<dd><a href="exceptions.html#Exception">exceptions.Exception</a></dd>
</dl>
<hr>
Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
<dl><dt><a name="BlockError-__getitem__"><strong>__getitem__</strong></a>(...)</dt></dl>
<dl><dt><a name="BlockError-__init__"><strong>__init__</strong></a>(...)</dt></dl>
<dl><dt><a name="BlockError-__str__"><strong>__str__</strong></a>(...)</dt></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="ClosedError">class <strong>ClosedError</strong></a>(<a href="i2p.sam.html#Error">Error</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>A&nbsp;command&nbsp;was&nbsp;used&nbsp;on&nbsp;a&nbsp;socket&nbsp;that&nbsp;closed&nbsp;gracefully.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="i2p.sam.html#ClosedError">ClosedError</a></dd>
<dd><a href="i2p.sam.html#Error">Error</a></dd>
<dd><a href="i2p.html#Error">i2p.Error</a></dd>
<dd><a href="exceptions.html#Exception">exceptions.Exception</a></dd>
</dl>
<hr>
Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
<dl><dt><a name="ClosedError-__getitem__"><strong>__getitem__</strong></a>(...)</dt></dl>
<dl><dt><a name="ClosedError-__init__"><strong>__init__</strong></a>(...)</dt></dl>
<dl><dt><a name="ClosedError-__str__"><strong>__str__</strong></a>(...)</dt></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Error">class <strong>Error</strong></a>(<a href="i2p.html#Error">i2p.Error</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Base&nbsp;class&nbsp;for&nbsp;all&nbsp;SAM&nbsp;errors.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="i2p.sam.html#Error">Error</a></dd>
<dd><a href="i2p.html#Error">i2p.Error</a></dd>
<dd><a href="exceptions.html#Exception">exceptions.Exception</a></dd>
</dl>
<hr>
Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
<dl><dt><a name="Error-__getitem__"><strong>__getitem__</strong></a>(...)</dt></dl>
<dl><dt><a name="Error-__init__"><strong>__init__</strong></a>(...)</dt></dl>
<dl><dt><a name="Error-__str__"><strong>__str__</strong></a>(...)</dt></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="NetworkError">class <strong>NetworkError</strong></a>(<a href="i2p.sam.html#Error">Error</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Network&nbsp;error&nbsp;occurred&nbsp;within&nbsp;I2P.<br>
The&nbsp;error&nbsp;object&nbsp;is&nbsp;a&nbsp;2-tuple:&nbsp;(errtag,&nbsp;errdesc).<br>
errtag&nbsp;is&nbsp;a&nbsp;SAM&nbsp;error&nbsp;string,<br>
errdesc&nbsp;is&nbsp;a&nbsp;human&nbsp;readable&nbsp;error&nbsp;description.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="i2p.sam.html#NetworkError">NetworkError</a></dd>
<dd><a href="i2p.sam.html#Error">Error</a></dd>
<dd><a href="i2p.html#Error">i2p.Error</a></dd>
<dd><a href="exceptions.html#Exception">exceptions.Exception</a></dd>
</dl>
<hr>
Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
<dl><dt><a name="NetworkError-__getitem__"><strong>__getitem__</strong></a>(...)</dt></dl>
<dl><dt><a name="NetworkError-__init__"><strong>__init__</strong></a>(...)</dt></dl>
<dl><dt><a name="NetworkError-__str__"><strong>__str__</strong></a>(...)</dt></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Poll">class <strong>Poll</strong></a></font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Class&nbsp;implementing&nbsp;poll&nbsp;interface.&nbsp;&nbsp;Works&nbsp;for&nbsp;Python&nbsp;sockets<br>
and&nbsp;SAM&nbsp;sockets.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="Poll-__init__"><strong>__init__</strong></a>(self)</dt></dl>
<dl><dt><a name="Poll-poll"><strong>poll</strong></a>(self, timeout<font color="#909090">=None</font>)</dt></dl>
<dl><dt><a name="Poll-register"><strong>register</strong></a>(self, fd, eventmask<font color="#909090">=13</font>)</dt></dl>
<dl><dt><a name="Poll-unregister"><strong>unregister</strong></a>(self, fd)</dt></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Socket">class <strong>Socket</strong></a></font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>A&nbsp;socket&nbsp;object.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="Socket-__deepcopy__"><strong>__deepcopy__</strong></a>(self, memo)</dt></dl>
<dl><dt><a name="Socket-__init__"><strong>__init__</strong></a>(self, session, type, samaddr<font color="#909090">='127.0.0.1:7656'</font>, **kwargs)</dt><dd><tt>Equivalent&nbsp;to&nbsp;socket().</tt></dd></dl>
<dl><dt><a name="Socket-accept"><strong>accept</strong></a>(self)</dt></dl>
<dl><dt><a name="Socket-bind"><strong>bind</strong></a>(self, address)</dt></dl>
<dl><dt><a name="Socket-close"><strong>close</strong></a>(self)</dt></dl>
<dl><dt><a name="Socket-connect"><strong>connect</strong></a>(self, address)</dt></dl>
<dl><dt><a name="Socket-connect_ex"><strong>connect_ex</strong></a>(self, address)</dt></dl>
<dl><dt><a name="Socket-getpeername"><strong>getpeername</strong></a>(self)</dt></dl>
<dl><dt><a name="Socket-getsockname"><strong>getsockname</strong></a>(self)</dt></dl>
<dl><dt><a name="Socket-gettimeout"><strong>gettimeout</strong></a>(self)</dt></dl>
<dl><dt><a name="Socket-listen"><strong>listen</strong></a>(self, backlog)</dt></dl>
<dl><dt><a name="Socket-makefile"><strong>makefile</strong></a>(self, mode<font color="#909090">='r'</font>, bufsize<font color="#909090">=-1</font>)</dt></dl>
<dl><dt><a name="Socket-recv"><strong>recv</strong></a>(self, bufsize, flags<font color="#909090">=0</font>)</dt></dl>
<dl><dt><a name="Socket-recvfrom"><strong>recvfrom</strong></a>(self, bufsize, flags<font color="#909090">=0</font>)</dt><dd><tt>For&nbsp;a&nbsp;datagram&nbsp;or&nbsp;raw&nbsp;socket,&nbsp;bufsize&nbsp;=&nbsp;-1&nbsp;indicates&nbsp;that&nbsp;the<br>
entire&nbsp;packet&nbsp;should&nbsp;be&nbsp;retrieved.</tt></dd></dl>
<dl><dt><a name="Socket-send"><strong>send</strong></a>(self, string, flags<font color="#909090">=0</font>)</dt></dl>
<dl><dt><a name="Socket-sendall"><strong>sendall</strong></a>(self, string, flags<font color="#909090">=0</font>)</dt></dl>
<dl><dt><a name="Socket-sendto"><strong>sendto</strong></a>(self, string, flags, address)</dt></dl>
<dl><dt><a name="Socket-setblocking"><strong>setblocking</strong></a>(self, flag)</dt></dl>
<dl><dt><a name="Socket-settimeout"><strong>settimeout</strong></a>(self, value)</dt></dl>
<hr>
Properties defined here:<br>
<dl><dt><strong>dest</strong></dt>
<dd><tt>Local&nbsp;I2P&nbsp;Destination&nbsp;of&nbsp;socket</tt></dd>
</dl>
<dl><dt><strong>session</strong></dt>
<dd><tt>Session&nbsp;name</tt></dd>
</dl>
<dl><dt><strong>type</strong></dt>
<dd><tt><a href="#Socket">Socket</a>&nbsp;type:&nbsp;SOCK_STREAM,&nbsp;SOCK_DGRAM,&nbsp;or&nbsp;SOCK_RAW.</tt></dd>
</dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Timeout">class <strong>Timeout</strong></a>(<a href="i2p.sam.html#Error">Error</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Time&nbsp;out&nbsp;occurred&nbsp;for&nbsp;a&nbsp;socket&nbsp;which&nbsp;had&nbsp;timeouts&nbsp;enabled<br>
via&nbsp;a&nbsp;prior&nbsp;call&nbsp;to&nbsp;settimeout().<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%"><dl><dt>Method resolution order:</dt>
<dd><a href="i2p.sam.html#Timeout">Timeout</a></dd>
<dd><a href="i2p.sam.html#Error">Error</a></dd>
<dd><a href="i2p.html#Error">i2p.Error</a></dd>
<dd><a href="exceptions.html#Exception">exceptions.Exception</a></dd>
</dl>
<hr>
Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
<dl><dt><a name="Timeout-__getitem__"><strong>__getitem__</strong></a>(...)</dt></dl>
<dl><dt><a name="Timeout-__init__"><strong>__init__</strong></a>(...)</dt></dl>
<dl><dt><a name="Timeout-__str__"><strong>__str__</strong></a>(...)</dt></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Tunnel">class <strong>Tunnel</strong></a></font></td></tr>
<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="Tunnel-__init__"><strong>__init__</strong></a>(self, receive, make_send, nconnect<font color="#909090">=-1</font>, timeout<font color="#909090">=60.0</font>)</dt><dd><tt>A&nbsp;<a href="#Tunnel">Tunnel</a>&nbsp;relays&nbsp;connections&nbsp;from&nbsp;a&nbsp;'receive'&nbsp;socket&nbsp;to&nbsp;one<br>
or&nbsp;more&nbsp;'send'&nbsp;sockets.&nbsp;&nbsp;The&nbsp;receive&nbsp;socket&nbsp;must&nbsp;be&nbsp;bound<br>
and&nbsp;listening.&nbsp;&nbsp;For&nbsp;each&nbsp;incoming&nbsp;connection,&nbsp;a&nbsp;new&nbsp;send<br>
socket&nbsp;is&nbsp;created&nbsp;by&nbsp;calling&nbsp;make_send().&nbsp;&nbsp;Data&nbsp;is&nbsp;then<br>
exchanged&nbsp;between&nbsp;the&nbsp;created&nbsp;streams&nbsp;until&nbsp;one&nbsp;socket&nbsp;is<br>
closed.&nbsp;&nbsp;nconnect&nbsp;is&nbsp;the&nbsp;maximum&nbsp;number&nbsp;of&nbsp;simultaneous<br>
connections&nbsp;(-1&nbsp;for&nbsp;infinite),&nbsp;and&nbsp;timeout&nbsp;is&nbsp;the&nbsp;time&nbsp;that<br>
a&nbsp;single&nbsp;connection&nbsp;can&nbsp;last&nbsp;for&nbsp;(None&nbsp;allows&nbsp;a&nbsp;connection<br>
to&nbsp;last&nbsp;forever).<br>
&nbsp;<br>
Sockets&nbsp;must&nbsp;accept&nbsp;stream&nbsp;traffic&nbsp;and&nbsp;support&nbsp;the&nbsp;Python<br>
socket&nbsp;interface.&nbsp;&nbsp;A&nbsp;separate&nbsp;daemonic&nbsp;thread&nbsp;is&nbsp;created&nbsp;to<br>
manage&nbsp;the&nbsp;tunnel.&nbsp;&nbsp;For&nbsp;high&nbsp;performance,&nbsp;make_send()&nbsp;should<br>
make&nbsp;a&nbsp;socket&nbsp;and&nbsp;connect&nbsp;in&nbsp;non-blocking&nbsp;mode&nbsp;(you&nbsp;should<br>
catch&nbsp;and&nbsp;discard&nbsp;the&nbsp;sam.<a href="#BlockError">BlockError</a>&nbsp;or&nbsp;socket.error&nbsp;due&nbsp;to<br>
executing&nbsp;connect&nbsp;on&nbsp;a&nbsp;non-blocking&nbsp;socket).<br>
&nbsp;<br>
Security&nbsp;Note:<br>
A&nbsp;firewall&nbsp;is&nbsp;needed&nbsp;to&nbsp;maintain&nbsp;the&nbsp;end&nbsp;user's&nbsp;anonymity.<br>
An&nbsp;attacker&nbsp;could&nbsp;keep&nbsp;a&nbsp;tunnel&nbsp;socket&nbsp;open&nbsp;by&nbsp;pinging&nbsp;it<br>
regularly.&nbsp;&nbsp;The&nbsp;accepted&nbsp;sockets&nbsp;from&nbsp;'receive'&nbsp;must&nbsp;prevent<br>
this&nbsp;by&nbsp;closing&nbsp;down&nbsp;eventually.<br>
&nbsp;<br>
<a href="#Socket">Socket</a>&nbsp;errors&nbsp;do&nbsp;not&nbsp;cause&nbsp;the&nbsp;<a href="#Tunnel">Tunnel</a>&nbsp;to&nbsp;shut&nbsp;down.</tt></dd></dl>
<dl><dt><a name="Tunnel-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;all&nbsp;connections&nbsp;made&nbsp;for&nbsp;this&nbsp;tunnel.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="TunnelClient">class <strong>TunnelClient</strong></a>(<a href="i2p.sam.html#Tunnel">Tunnel</a>)</font></td></tr>
<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="TunnelClient-__init__"><strong>__init__</strong></a>(self, session, port, dest, samaddr<font color="#909090">='127.0.0.1:7656'</font>, nconnect<font color="#909090">=-1</font>, timeout<font color="#909090">=None</font>, **kwargs)</dt><dd><tt>Tunnels&nbsp;localhost:port&nbsp;--&gt;&nbsp;I2P&nbsp;Destination&nbsp;dest.<br>
&nbsp;<br>
A&nbsp;session&nbsp;named&nbsp;'session'&nbsp;is&nbsp;created&nbsp;locally,&nbsp;for&nbsp;purposes<br>
of&nbsp;routing&nbsp;to&nbsp;'dest'.&nbsp;&nbsp;nconnect&nbsp;and&nbsp;timeout&nbsp;are&nbsp;the&nbsp;maximum<br>
number&nbsp;of&nbsp;connections&nbsp;and&nbsp;maximum&nbsp;time&nbsp;per&nbsp;connection.&nbsp;&nbsp;All<br>
other&nbsp;arguments&nbsp;are&nbsp;passed&nbsp;to&nbsp;sam.socket().&nbsp;&nbsp;This&nbsp;call&nbsp;blocks<br>
until&nbsp;the&nbsp;tunnel&nbsp;is&nbsp;ready.</tt></dd></dl>
<hr>
Properties defined here:<br>
<dl><dt><strong>dest</strong></dt>
<dd><strong><em>get</em></strong> = 'Local Destination used for routing.'</dd>
</dl>
<dl><dt><strong>remotedest</strong></dt>
<dd><tt>Remote&nbsp;Destination.</tt></dd>
</dl>
<dl><dt><strong>session</strong></dt>
<dd><strong><em>get</em></strong> = 'Session name for local Destination.'</dd>
</dl>
<hr>
Methods inherited from <a href="i2p.sam.html#Tunnel">Tunnel</a>:<br>
<dl><dt><a name="TunnelClient-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;all&nbsp;connections&nbsp;made&nbsp;for&nbsp;this&nbsp;tunnel.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="TunnelServer">class <strong>TunnelServer</strong></a>(<a href="i2p.sam.html#Tunnel">Tunnel</a>)</font></td></tr>
<tr><td bgcolor="#ffc8d8"><tt>&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="TunnelServer-__init__"><strong>__init__</strong></a>(self, session, port, samaddr<font color="#909090">='127.0.0.1:7656'</font>, nconnect<font color="#909090">=-1</font>, timeout<font color="#909090">=None</font>, **kwargs)</dt><dd><tt>Tunnels&nbsp;incoming&nbsp;SAM&nbsp;streams&nbsp;--&gt;&nbsp;localhost:port.<br>
&nbsp;<br>
nconnect&nbsp;and&nbsp;timeout&nbsp;are&nbsp;the&nbsp;maximum&nbsp;number&nbsp;of&nbsp;connections<br>
and&nbsp;maximum&nbsp;time&nbsp;per&nbsp;connection.&nbsp;&nbsp;All&nbsp;other&nbsp;arguments&nbsp;are<br>
passed&nbsp;to&nbsp;sam.socket().&nbsp;&nbsp;This&nbsp;call&nbsp;blocks&nbsp;until&nbsp;the&nbsp;tunnel<br>
is&nbsp;ready.</tt></dd></dl>
<hr>
Properties defined here:<br>
<dl><dt><strong>dest</strong></dt>
<dd><tt>I2P&nbsp;Destination&nbsp;of&nbsp;server.</tt></dd>
</dl>
<dl><dt><strong>session</strong></dt>
<dd><tt>Session&nbsp;name&nbsp;for&nbsp;server.</tt></dd>
</dl>
<hr>
Methods inherited from <a href="i2p.sam.html#Tunnel">Tunnel</a>:<br>
<dl><dt><a name="TunnelServer-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;all&nbsp;connections&nbsp;made&nbsp;for&nbsp;this&nbsp;tunnel.</tt></dd></dl>
</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><strong>MAX_DGRAM</strong> = 31744<br>
<strong>MAX_RAW</strong> = 32768<br>
<strong>MSG_DONTWAIT</strong> = 128<br>
<strong>MSG_PEEK</strong> = 2<br>
<strong>MSG_WAITALL</strong> = 64<br>
<strong>POLLERR</strong> = 8<br>
<strong>POLLHUP</strong> = 16<br>
<strong>POLLIN</strong> = 1<br>
<strong>POLLNVAL</strong> = 32<br>
<strong>POLLOUT</strong> = 4<br>
<strong>POLLPRI</strong> = 1<br>
<strong>SOCK_DGRAM</strong> = 2<br>
<strong>SOCK_RAW</strong> = 3<br>
<strong>SOCK_STREAM</strong> = 1<br>
<strong>samaddr</strong> = '127.0.0.1:7656'<br>
<strong>samver</strong> = 1.0</td></tr></table>
</body></html>

View File

@ -0,0 +1,314 @@
<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: module i2p.samclasses</title>
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial">&nbsp;<br><big><big><strong><a href="i2p.html"><font color="#ffffff">i2p</font></a>.samclasses</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:///D|/code/i2p/i2p/samclasses.py">d:\code\i2p\i2p\samclasses.py</a></font></td></tr></table>
<p><tt>Lower-level&nbsp;SAM&nbsp;API,&nbsp;interfaces&nbsp;with&nbsp;SAM&nbsp;Bridge.<br>
&nbsp;<br>
For&nbsp;internal&nbsp;use&nbsp;only.<br>
&nbsp;<br>
Use&nbsp;the&nbsp;higher&nbsp;level&nbsp;i2p.sam&nbsp;module&nbsp;for&nbsp;your&nbsp;own&nbsp;programs.<br>
&nbsp;<br>
For&nbsp;details&nbsp;on&nbsp;SAM,&nbsp;see&nbsp;"Simple&nbsp;Anonymous&nbsp;Messaging&nbsp;(SAM)&nbsp;v1.0,"<br>
as&nbsp;published&nbsp;by&nbsp;jrandom.<br>
&nbsp;<br>
Class&nbsp;Overview:<br>
&nbsp;<br>
&nbsp;&nbsp;<a href="#SAMTerminal">SAMTerminal</a>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Message&nbsp;sender/reader,&nbsp;talks&nbsp;to&nbsp;SAM&nbsp;Bridge<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;through&nbsp;a&nbsp;single&nbsp;socket.<br>
&nbsp;&nbsp;<a href="#StringBuffer">StringBuffer</a>:&nbsp;&nbsp;&nbsp;&nbsp;Queue&nbsp;for&nbsp;character&nbsp;data.<br>
&nbsp;&nbsp;<a href="#BaseSession">BaseSession</a>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAM&nbsp;session&nbsp;classes&nbsp;are&nbsp;derived&nbsp;from&nbsp;this.<br>
&nbsp;&nbsp;<a href="#StreamSession">StreamSession</a>:&nbsp;&nbsp;&nbsp;Manipulate&nbsp;a&nbsp;SAM&nbsp;stream&nbsp;session&nbsp;through&nbsp;a<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;threadsafe,&nbsp;high-level&nbsp;interface.<br>
&nbsp;&nbsp;<a href="#DatagramSession">DatagramSession</a>:&nbsp;SAM&nbsp;datagram&nbsp;session,&nbsp;threadsafe,&nbsp;high&nbsp;level.<br>
&nbsp;&nbsp;<a href="#RawSession">RawSession</a>:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SAM&nbsp;raw&nbsp;session,&nbsp;threadsafe,&nbsp;high&nbsp;level.<br>
&nbsp;<br>
Note&nbsp;that&nbsp;a&nbsp;'None'&nbsp;timeout&nbsp;is&nbsp;an&nbsp;infinite&nbsp;timeout:&nbsp;it<br>
blocks&nbsp;forever&nbsp;if&nbsp;necessary.<br>
&nbsp;<br>
Todo:<br>
&nbsp;&nbsp;*&nbsp;Error&nbsp;handling&nbsp;is&nbsp;a&nbsp;huge&nbsp;mess.&nbsp;&nbsp;Neaten&nbsp;it&nbsp;up.<br>
&nbsp;&nbsp;&nbsp;&nbsp;Subclass&nbsp;a&nbsp;ErrorMixin&nbsp;class,&nbsp;then&nbsp;use&nbsp;set_error(e),<br>
&nbsp;&nbsp;&nbsp;&nbsp;check_error(),&nbsp;get_error().<br>
&nbsp;&nbsp;*&nbsp;Streams&nbsp;are&nbsp;a&nbsp;huge&nbsp;mess.&nbsp;&nbsp;Neaten&nbsp;them&nbsp;up.<br>
&nbsp;&nbsp;*&nbsp;This&nbsp;whole&nbsp;interface&nbsp;is&nbsp;a&nbsp;tad&nbsp;confusing.&nbsp;&nbsp;Neaten&nbsp;it&nbsp;up.</tt></p>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#aa55cc">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#fffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
<tr><td bgcolor="#aa55cc"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="Queue.html">Queue</a><br>
<a href="i2p.html">i2p</a><br>
<a href="random.html">random</a><br>
</td><td width="25%" valign=top><a href="shlex.html">shlex</a><br>
<a href="socket.html">socket</a><br>
<a href="string.html">string</a><br>
</td><td width="25%" valign=top><a href="sys.html">sys</a><br>
<a href="thread.html">thread</a><br>
<a href="threading.html">threading</a><br>
</td><td width="25%" valign=top><a href="time.html">time</a><br>
<a href="traceback.html">traceback</a><br>
</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ee77aa">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Classes</strong></big></font></td></tr>
<tr><td bgcolor="#ee77aa"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><dl>
<dt><font face="helvetica, arial"><a href="i2p.samclasses.html#BaseSession">BaseSession</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="i2p.samclasses.html#DatagramSession">DatagramSession</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.samclasses.html#RawSession">RawSession</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.samclasses.html#StreamSession">StreamSession</a>
</font></dt></dl>
</dd>
<dt><font face="helvetica, arial"><a href="i2p.samclasses.html#Deque">Deque</a>
</font></dt><dd>
<dl>
<dt><font face="helvetica, arial"><a href="i2p.samclasses.html#StringBuffer">StringBuffer</a>
</font></dt></dl>
</dd>
<dt><font face="helvetica, arial"><a href="i2p.samclasses.html#SAMTerminal">SAMTerminal</a>
</font></dt><dt><font face="helvetica, arial"><a href="i2p.samclasses.html#Stream">Stream</a>
</font></dt></dl>
<p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="BaseSession">class <strong>BaseSession</strong></a></font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Base&nbsp;session,&nbsp;from&nbsp;which&nbsp;<a href="#StreamSession">StreamSession</a>,&nbsp;<a href="#DatagramSession">DatagramSession</a>,<br>
and&nbsp;<a href="#RawSession">RawSession</a>&nbsp;are&nbsp;derived.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="BaseSession-__init__"><strong>__init__</strong></a>(self, addr<font color="#909090">=''</font>)</dt></dl>
<dl><dt><a name="BaseSession-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;the&nbsp;session.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="DatagramSession">class <strong>DatagramSession</strong></a>(<a href="i2p.samclasses.html#BaseSession">BaseSession</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Datagram&nbsp;session.&nbsp;&nbsp;All&nbsp;methods&nbsp;are&nbsp;blocking&nbsp;and&nbsp;threadsafe.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="DatagramSession-__init__"><strong>__init__</strong></a>(self, name, addr<font color="#909090">=''</font>, **kwargs)</dt></dl>
<dl><dt><a name="DatagramSession-__len__"><strong>__len__</strong></a>(self)</dt><dd><tt>Number&nbsp;of&nbsp;packets&nbsp;in&nbsp;read&nbsp;buffer.</tt></dd></dl>
<dl><dt><a name="DatagramSession-recv"><strong>recv</strong></a>(self, timeout<font color="#909090">=None</font>, peek<font color="#909090">=False</font>)</dt><dd><tt>Get&nbsp;a&nbsp;single&nbsp;packet.&nbsp;&nbsp;Blocks&nbsp;for&nbsp;up&nbsp;to&nbsp;timeout&nbsp;seconds&nbsp;if<br>
n&nbsp;&gt;&nbsp;0&nbsp;and&nbsp;no&nbsp;packet&nbsp;is&nbsp;available&nbsp;(timeout=None&nbsp;means&nbsp;wait<br>
forever).&nbsp;&nbsp;If&nbsp;still&nbsp;no&nbsp;packet&nbsp;is&nbsp;available,&nbsp;raises&nbsp;BlockError<br>
or&nbsp;Timeout.&nbsp;&nbsp;Returns&nbsp;the&nbsp;pair&nbsp;(data,&nbsp;address).&nbsp;&nbsp;If&nbsp;peek&nbsp;is<br>
True,&nbsp;the&nbsp;data&nbsp;is&nbsp;not&nbsp;removed.</tt></dd></dl>
<dl><dt><a name="DatagramSession-send"><strong>send</strong></a>(self, s, dest)</dt><dd><tt>Send&nbsp;packet&nbsp;with&nbsp;contents&nbsp;s&nbsp;to&nbsp;given&nbsp;destination.</tt></dd></dl>
<hr>
Methods inherited from <a href="i2p.samclasses.html#BaseSession">BaseSession</a>:<br>
<dl><dt><a name="DatagramSession-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;the&nbsp;session.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Deque">class <strong>Deque</strong></a></font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>A&nbsp;double-ended&nbsp;queue.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="Deque-__init__"><strong>__init__</strong></a>(self)</dt></dl>
<dl><dt><a name="Deque-__len__"><strong>__len__</strong></a>(self)</dt><dd><tt>Number&nbsp;of&nbsp;items&nbsp;in&nbsp;the&nbsp;deque.</tt></dd></dl>
<dl><dt><a name="Deque-pop_first"><strong>pop_first</strong></a>(self)</dt><dd><tt>Pop&nbsp;an&nbsp;item&nbsp;off&nbsp;the&nbsp;beginning&nbsp;of&nbsp;the&nbsp;deque,&nbsp;and&nbsp;return&nbsp;it.</tt></dd></dl>
<dl><dt><a name="Deque-pop_last"><strong>pop_last</strong></a>(self)</dt><dd><tt>Pop&nbsp;an&nbsp;item&nbsp;off&nbsp;the&nbsp;end&nbsp;of&nbsp;the&nbsp;deque,&nbsp;and&nbsp;return&nbsp;it.</tt></dd></dl>
<dl><dt><a name="Deque-push_first"><strong>push_first</strong></a>(self, obj)</dt><dd><tt>Prepend&nbsp;obj&nbsp;to&nbsp;the&nbsp;beginning&nbsp;of&nbsp;the&nbsp;deque.</tt></dd></dl>
<dl><dt><a name="Deque-push_last"><strong>push_last</strong></a>(self, obj)</dt><dd><tt>Append&nbsp;obj&nbsp;to&nbsp;the&nbsp;end&nbsp;of&nbsp;the&nbsp;deque.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="RawSession">class <strong>RawSession</strong></a>(<a href="i2p.samclasses.html#BaseSession">BaseSession</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Raw&nbsp;session.&nbsp;&nbsp;All&nbsp;methods&nbsp;are&nbsp;blocking&nbsp;and&nbsp;threadsafe.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="RawSession-__init__"><strong>__init__</strong></a>(self, name, addr<font color="#909090">=''</font>, **kwargs)</dt></dl>
<dl><dt><a name="RawSession-__len__"><strong>__len__</strong></a>(self)</dt><dd><tt>Number&nbsp;of&nbsp;packets&nbsp;in&nbsp;read&nbsp;buffer.</tt></dd></dl>
<dl><dt><a name="RawSession-recv"><strong>recv</strong></a>(self, timeout<font color="#909090">=None</font>, peek<font color="#909090">=False</font>)</dt><dd><tt>Identical&nbsp;to&nbsp;DatagramSocket.recv.&nbsp;&nbsp;The&nbsp;from&nbsp;address&nbsp;is&nbsp;an<br>
empty&nbsp;string.</tt></dd></dl>
<dl><dt><a name="RawSession-send"><strong>send</strong></a>(self, s, dest)</dt><dd><tt>Send&nbsp;packet&nbsp;with&nbsp;contents&nbsp;s&nbsp;to&nbsp;given&nbsp;destination.</tt></dd></dl>
<hr>
Methods inherited from <a href="i2p.samclasses.html#BaseSession">BaseSession</a>:<br>
<dl><dt><a name="RawSession-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;the&nbsp;session.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="SAMTerminal">class <strong>SAMTerminal</strong></a></font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Message-by-message&nbsp;communication&nbsp;with&nbsp;SAM&nbsp;through&nbsp;a&nbsp;single<br>
socket.&nbsp;&nbsp;_on_*&nbsp;messages&nbsp;are&nbsp;dispatched&nbsp;to&nbsp;msgobj.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="SAMTerminal-__init__"><strong>__init__</strong></a>(self, addr, msgobj)</dt></dl>
<dl><dt><a name="SAMTerminal-check"><strong>check</strong></a>(self)</dt><dd><tt>Raise&nbsp;an&nbsp;error&nbsp;if&nbsp;terminal&nbsp;was&nbsp;closed,&nbsp;otherwise&nbsp;do<br>
nothing.</tt></dd></dl>
<dl><dt><a name="SAMTerminal-check_message"><strong>check_message</strong></a>(self, kwargs)</dt><dd><tt>Raises&nbsp;an&nbsp;error&nbsp;if&nbsp;kwargs['RESULT']&nbsp;!=&nbsp;'OK'.</tt></dd></dl>
<dl><dt><a name="SAMTerminal-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;the&nbsp;SAM&nbsp;terminal.</tt></dd></dl>
<dl><dt><a name="SAMTerminal-on_message"><strong>on_message</strong></a>(self, msg, kwargs)</dt><dd><tt>Process&nbsp;a&nbsp;SAM&nbsp;message&nbsp;that&nbsp;was&nbsp;received.&nbsp;&nbsp;Dispatch&nbsp;to<br>
_on_MESSAGE_NAME(**kwargs).</tt></dd></dl>
<dl><dt><a name="SAMTerminal-queue_get"><strong>queue_get</strong></a>(self, q)</dt><dd><tt>Identical&nbsp;to&nbsp;q.get()&nbsp;unless&nbsp;a&nbsp;call&nbsp;to&nbsp;<a href="#SAMTerminal-check">check</a>()&nbsp;fails,<br>
in&nbsp;which&nbsp;case&nbsp;the&nbsp;waiting&nbsp;is&nbsp;cut&nbsp;short&nbsp;with&nbsp;an&nbsp;error.</tt></dd></dl>
<dl><dt><a name="SAMTerminal-send_message"><strong>send_message</strong></a>(self, msg)</dt><dd><tt>Send&nbsp;a&nbsp;message&nbsp;to&nbsp;the&nbsp;SAM&nbsp;bridge.&nbsp;&nbsp;A&nbsp;newline&nbsp;will&nbsp;be<br>
automatically&nbsp;added&nbsp;if&nbsp;none&nbsp;is&nbsp;present.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="Stream">class <strong>Stream</strong></a></font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>Receives&nbsp;and&nbsp;sends&nbsp;data&nbsp;for&nbsp;an&nbsp;individual&nbsp;stream.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="Stream-__del__"><strong>__del__</strong></a>(self)</dt></dl>
<dl><dt><a name="Stream-__init__"><strong>__init__</strong></a>(self, parent, remotedest, id, didconnect<font color="#909090">=True</font>)</dt></dl>
<dl><dt><a name="Stream-__len__"><strong>__len__</strong></a>(self)</dt><dd><tt>Current&nbsp;length&nbsp;of&nbsp;read&nbsp;buffer.</tt></dd></dl>
<dl><dt><a name="Stream-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;the&nbsp;stream.&nbsp;&nbsp;Threadsafe.</tt></dd></dl>
<dl><dt><a name="Stream-on_close"><strong>on_close</strong></a>(self, e)</dt></dl>
<dl><dt><a name="Stream-on_receive"><strong>on_receive</strong></a>(self, s)</dt></dl>
<dl><dt><a name="Stream-recv"><strong>recv</strong></a>(self, n, timeout<font color="#909090">=None</font>, peek<font color="#909090">=False</font>, waitall<font color="#909090">=False</font>)</dt><dd><tt>Reads&nbsp;up&nbsp;to&nbsp;n&nbsp;bytes&nbsp;in&nbsp;a&nbsp;manner&nbsp;identical&nbsp;to&nbsp;socket.recv.<br>
Blocks&nbsp;for&nbsp;up&nbsp;to&nbsp;timeout&nbsp;seconds&nbsp;if&nbsp;n&nbsp;&gt;&nbsp;0&nbsp;and&nbsp;no&nbsp;data&nbsp;is<br>
available&nbsp;(timeout=None&nbsp;means&nbsp;wait&nbsp;forever).&nbsp;&nbsp;If&nbsp;still&nbsp;no&nbsp;data<br>
is&nbsp;available,&nbsp;raises&nbsp;BlockError&nbsp;or&nbsp;Timeout.&nbsp;&nbsp;For&nbsp;a&nbsp;closed<br>
stream,&nbsp;recv&nbsp;will&nbsp;read&nbsp;the&nbsp;data&nbsp;stored&nbsp;in&nbsp;the&nbsp;buffer&nbsp;until<br>
EOF,&nbsp;at&nbsp;which&nbsp;point&nbsp;the&nbsp;read&nbsp;data&nbsp;will&nbsp;be&nbsp;truncated.&nbsp;&nbsp;If&nbsp;peek<br>
is&nbsp;True,&nbsp;the&nbsp;data&nbsp;is&nbsp;not&nbsp;removed.&nbsp;&nbsp;If&nbsp;waitall&nbsp;is&nbsp;True,&nbsp;reads<br>
exactly&nbsp;n&nbsp;bytes,&nbsp;or&nbsp;raises&nbsp;BlockError&nbsp;or&nbsp;Timeout&nbsp;as<br>
appropriate.&nbsp;&nbsp;Returns&nbsp;data.</tt></dd></dl>
<dl><dt><a name="Stream-send"><strong>send</strong></a>(self, s)</dt><dd><tt>Sends&nbsp;the&nbsp;string&nbsp;s,&nbsp;blocking&nbsp;if&nbsp;necessary.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="StreamSession">class <strong>StreamSession</strong></a>(<a href="i2p.samclasses.html#BaseSession">BaseSession</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt><a href="#Stream">Stream</a>&nbsp;session.&nbsp;&nbsp;All&nbsp;methods&nbsp;are&nbsp;blocking&nbsp;and&nbsp;threadsafe.<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="StreamSession-__init__"><strong>__init__</strong></a>(self, name, addr<font color="#909090">=''</font>, **kwargs)</dt></dl>
<dl><dt><a name="StreamSession-__len__"><strong>__len__</strong></a>(self)</dt><dd><tt>Unconnected&nbsp;session;&nbsp;has&nbsp;no&nbsp;read&nbsp;data&nbsp;available.</tt></dd></dl>
<dl><dt><a name="StreamSession-accept"><strong>accept</strong></a>(self, timeout<font color="#909090">=None</font>)</dt><dd><tt>Wait&nbsp;for&nbsp;incoming&nbsp;connection,&nbsp;and&nbsp;return&nbsp;a&nbsp;<a href="#Stream">Stream</a>&nbsp;object<br>
for&nbsp;it.</tt></dd></dl>
<dl><dt><a name="StreamSession-connect"><strong>connect</strong></a>(self, dest, timeout<font color="#909090">=None</font>)</dt><dd><tt>Create&nbsp;a&nbsp;stream&nbsp;connected&nbsp;to&nbsp;remote&nbsp;destination&nbsp;'dest'.&nbsp;&nbsp;The<br>
id&nbsp;is&nbsp;random.&nbsp;&nbsp;If&nbsp;the&nbsp;timeout&nbsp;is&nbsp;exceeded,&nbsp;do&nbsp;NOT&nbsp;raise&nbsp;an<br>
error;&nbsp;rather,&nbsp;return&nbsp;a&nbsp;<a href="#Stream">Stream</a>&nbsp;object&nbsp;with&nbsp;.didconnect&nbsp;set<br>
to&nbsp;False.</tt></dd></dl>
<dl><dt><a name="StreamSession-listen"><strong>listen</strong></a>(self, backlog)</dt><dd><tt>Set&nbsp;maximum&nbsp;number&nbsp;of&nbsp;queued&nbsp;connections.</tt></dd></dl>
<hr>
Methods inherited from <a href="i2p.samclasses.html#BaseSession">BaseSession</a>:<br>
<dl><dt><a name="StreamSession-close"><strong>close</strong></a>(self)</dt><dd><tt>Close&nbsp;the&nbsp;session.</tt></dd></dl>
</td></tr></table> <p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#ffc8d8">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#000000" face="helvetica, arial"><a name="StringBuffer">class <strong>StringBuffer</strong></a>(<a href="i2p.samclasses.html#Deque">Deque</a>)</font></td></tr>
<tr bgcolor="#ffc8d8"><td rowspan=2><tt>&nbsp;&nbsp;&nbsp;</tt></td>
<td colspan=2><tt>A&nbsp;FIFO&nbsp;for&nbsp;characters.&nbsp;&nbsp;Strings&nbsp;can&nbsp;be&nbsp;efficiently<br>
appended&nbsp;to&nbsp;the&nbsp;end,&nbsp;and&nbsp;read&nbsp;from&nbsp;the&nbsp;beginning.<br>
&nbsp;<br>
Example:<br>
&nbsp;&nbsp;B&nbsp;=&nbsp;<a href="#StringBuffer">StringBuffer</a>('Hello&nbsp;W')<br>
&nbsp;&nbsp;B.<a href="#StringBuffer-append">append</a>('orld!')<br>
&nbsp;&nbsp;print&nbsp;B.<a href="#StringBuffer-read">read</a>(5)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;'Hello'<br>
&nbsp;&nbsp;print&nbsp;B.<a href="#StringBuffer-read">read</a>()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;'World!'<br>&nbsp;</tt></td></tr>
<tr><td>&nbsp;</td>
<td width="100%">Methods defined here:<br>
<dl><dt><a name="StringBuffer-__init__"><strong>__init__</strong></a>(self, s<font color="#909090">=''</font>)</dt></dl>
<dl><dt><a name="StringBuffer-__len__"><strong>__len__</strong></a>(self)</dt></dl>
<dl><dt><a name="StringBuffer-__repr__"><strong>__repr__</strong></a>(self)</dt></dl>
<dl><dt><a name="StringBuffer-__str__"><strong>__str__</strong></a>(self)</dt></dl>
<dl><dt><a name="StringBuffer-append"><strong>append</strong></a>(self, s)</dt><dd><tt>Append&nbsp;string&nbsp;data&nbsp;to&nbsp;the&nbsp;end&nbsp;of&nbsp;the&nbsp;buffer.</tt></dd></dl>
<dl><dt><a name="StringBuffer-peek"><strong>peek</strong></a>(self, n<font color="#909090">=None</font>)</dt><dd><tt>Like&nbsp;<a href="#StringBuffer-read">read</a>(),&nbsp;but&nbsp;do&nbsp;not&nbsp;remove&nbsp;the&nbsp;data&nbsp;that&nbsp;is&nbsp;returned.</tt></dd></dl>
<dl><dt><a name="StringBuffer-prepend"><strong>prepend</strong></a>(self, s)</dt><dd><tt>Prepend&nbsp;string&nbsp;data&nbsp;to&nbsp;the&nbsp;beginning&nbsp;of&nbsp;the&nbsp;buffer.</tt></dd></dl>
<dl><dt><a name="StringBuffer-read"><strong>read</strong></a>(self, n<font color="#909090">=None</font>)</dt><dd><tt>Read&nbsp;n&nbsp;bytes&nbsp;of&nbsp;data&nbsp;(or&nbsp;less&nbsp;if&nbsp;less&nbsp;data&nbsp;available)&nbsp;from&nbsp;the<br>
beginning&nbsp;of&nbsp;the&nbsp;buffer.&nbsp;&nbsp;The&nbsp;data&nbsp;is&nbsp;removed.&nbsp;&nbsp;If&nbsp;n&nbsp;is<br>
omitted,&nbsp;read&nbsp;the&nbsp;entire&nbsp;buffer.</tt></dd></dl>
<hr>
Methods inherited from <a href="i2p.samclasses.html#Deque">Deque</a>:<br>
<dl><dt><a name="StringBuffer-pop_first"><strong>pop_first</strong></a>(self)</dt><dd><tt>Pop&nbsp;an&nbsp;item&nbsp;off&nbsp;the&nbsp;beginning&nbsp;of&nbsp;the&nbsp;deque,&nbsp;and&nbsp;return&nbsp;it.</tt></dd></dl>
<dl><dt><a name="StringBuffer-pop_last"><strong>pop_last</strong></a>(self)</dt><dd><tt>Pop&nbsp;an&nbsp;item&nbsp;off&nbsp;the&nbsp;end&nbsp;of&nbsp;the&nbsp;deque,&nbsp;and&nbsp;return&nbsp;it.</tt></dd></dl>
<dl><dt><a name="StringBuffer-push_first"><strong>push_first</strong></a>(self, obj)</dt><dd><tt>Prepend&nbsp;obj&nbsp;to&nbsp;the&nbsp;beginning&nbsp;of&nbsp;the&nbsp;deque.</tt></dd></dl>
<dl><dt><a name="StringBuffer-push_last"><strong>push_last</strong></a>(self, obj)</dt><dd><tt>Append&nbsp;obj&nbsp;to&nbsp;the&nbsp;end&nbsp;of&nbsp;the&nbsp;deque.</tt></dd></dl>
</td></tr></table></td></tr></table><p>
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
<tr bgcolor="#55aa55">
<td colspan=3 valign=bottom>&nbsp;<br>
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
<tr><td bgcolor="#55aa55"><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</tt></td><td>&nbsp;</td>
<td width="100%"><strong>sam_log</strong> = False</td></tr></table>
</body></html>

View File

@ -0,0 +1,36 @@
# -------------------------------------------------------------
# makedoc.py: Make pydoc documentation for Python SAM API
# -------------------------------------------------------------
import os, inspect
import pydoc as pydoc_
def pydoc(args):
"""Run pydoc (command line) with given argument string."""
filename = inspect.getsourcefile(pydoc_)
os.system('python ' + filename + ' ' + args)
def move(f1, f2):
"""Moves filename f1 to filename f2, overwriting if f2 already exists."""
try: os.remove(f2)
except: pass
os.rename(f1, f2)
def makedoc():
"""Make all HTML documentation for Python I2P library."""
modules = ['i2p', 'i2p.sam', 'i2p.eep', 'i2p.router', 'i2p.samclasses']
origdir = os.getcwd()
os.chdir('../..')
for m in modules:
pydoc('-w ' + m)
os.chdir(origdir)
for m in modules:
move('../../' + m + '.html', './' + m + '.html')
if __name__ == '__main__':
makedoc()

View File

@ -0,0 +1,34 @@
----------------------------------------
Python-I2P v0.9
----------------------------------------
Python-I2P is a Python interface to I2P.
All files in this directory and subdirectories
have been placed in the public domain by
Connelly Barnes.
----------------------------------------
Quick Start
----------------------------------------
Install:
python setup.py install
Use:
>>> from i2p import sam
>>> s = sam.socket('Alice', sam.SOCK_STREAM)
>>> s.connect('duck.i2p')
>>> s.send('GET / HTTP/1.0\r\n\r\n')
>>> s.recv(1000)
(Response from duck.i2p)
----------------------------------------
Full Start
----------------------------------------
See the docs directory for HTML documentation.

14
apps/sam/python/setup.py Normal file
View File

@ -0,0 +1,14 @@
from distutils.core import setup
import os
os.chdir('./src')
setup(name="Python I2P API",
version="0.9",
description="Python Interface to I2P",
author="Connelly Barnes",
author_email="'Y29ubmVsbHliYXJuZXNAeWFob28uY29t\n'.decode('base64')",
url="http://www.i2p.net/",
packages=['i2p'],
)

View File

@ -0,0 +1,15 @@
# -----------------------------------------------
# datagram.py: Datagram client
# -----------------------------------------------
from i2p import sam
dest = sam.resolve('yourserver.i2p')
S = sam.socket('Bob', sam.SOCK_DGRAM)
S.sendto('Hello packet', 0, dest)
# Get packet up to 1000 bytes -- the rest is discarded.
(data, dest) = S.recvfrom(1000)
print data

View File

@ -0,0 +1,20 @@
# ---------------------------------------------------
# datagram_noblock.py: Non-blocking datagram server
# ---------------------------------------------------
from i2p import sam
import time
S = sam.socket('Eve', sam.SOCK_DGRAM)
print 'Serving at:', S.dest
S.setblocking(False)
while True:
try:
(data, dest) = S.recvfrom(1000) # Read packet
print 'Got', data, 'from', dest
S.sendto('Hi client!', 0, dest)
except sam.BlockError: # No data available
pass
time.sleep(0.01) # Reduce CPU usage

View File

@ -0,0 +1,14 @@
# -----------------------------------------------
# datagram_server.py: Datagram server
# -----------------------------------------------
from i2p import sam
S = sam.socket('Eve', sam.SOCK_DGRAM)
print 'Serving at:', S.dest
while True:
(data, dest) = S.recvfrom(1000) # Read packet
print 'Got', data, 'from', dest
S.sendto('Hi client!', 0, dest)

View File

@ -0,0 +1,33 @@
# -----------------------------------------------
# dos.py: Noneffective denial of service tool
# -----------------------------------------------
from i2p import sam
import threading, sys
def dos_stream(dest):
"""Perform a DOS attack on a stream server."""
dest = sam.resolve(dest)
# DOS code, runs in n separate threads.
def f():
while True:
S = sam.socket(dest, sam.SOCK_STREAM)
S.connect(dest)
S.send('GET / HTTP/1.0\r\n\r\n')
S.close()
# Start up the threads.
for i in range(128):
T = threading.Thread(target=f)
T.start()
def syntax():
print "Usage: python dos.py Destination"
if __name__ == '__main__':
if len(sys.argv) == 2:
dos_stream(sys.argv[1])
else:
syntax()

View File

@ -0,0 +1,14 @@
Examples:
datagram.py - Datagram client
datagram_noblock.py - Non-blocking datagram server
datagram_server.py - Blocking datagram server
dos.py - Denial of service tool
raw.py - Raw client
raw_noblock.py - Non-blocking raw server
raw_server.py - Raw server
stream.py - Stream client
stream_eepget.py - Get an eepsite using sockets
stream_noblock.py - Non-blocking stream server
stream_server.py - Blocking stream server

View File

@ -0,0 +1,10 @@
# -----------------------------------------------
# raw.py: Raw client
# -----------------------------------------------
from i2p import sam
dest = sam.resolve('yourserver.i2p') # Send to dest
S = sam.socket('Carol', sam.SOCK_RAW)
S.sendto('Hello packet', 0, dest)

View File

@ -0,0 +1,19 @@
# ---------------------------------------------------
# raw_noblock.py: Non-blocking raw server
# ---------------------------------------------------
from i2p import sam
import time
S = sam.socket('Eve', sam.SOCK_RAW)
print 'Serving at:', S.dest
S.setblocking(False)
while True:
try:
data = S.recv(1000) # Read packet
print 'Got', data
except sam.BlockError: # No data available
pass
time.sleep(0.01) # Reduce CPU usage

View File

@ -0,0 +1,13 @@
# -----------------------------------------------
# raw_server.py: Raw server
# -----------------------------------------------
from i2p import sam
S = sam.socket('Eve', sam.SOCK_RAW)
print 'Serving at:', S.dest
while True:
data = S.recv(1000) # Read packet
print 'Got', data

View File

@ -0,0 +1,11 @@
# -----------------------------------------------
# stream.py: Simple stream client
# -----------------------------------------------
from i2p import sam
S = sam.socket('Alice', sam.SOCK_STREAM)
S.connect('duck.i2p')
S.send('GET / HTTP/1.0\r\n\r\n') # Send request
print S.recv(1000) # Read up to 1000 bytes

View File

@ -0,0 +1,17 @@
# -----------------------------------------------
# stream_eepget.py: Get an eepsite using sockets
# -----------------------------------------------
from i2p import sam
S = sam.socket('Alice', sam.SOCK_STREAM)
S.connect('duck.i2p')
S.send('GET / HTTP/1.0\r\n\r\n') # Send request
f = S.makefile() # File object
while True: # Read header
line = f.readline().strip() # Read a line
if line == '': break # Content begins
print f.read() # Read file object

View File

@ -0,0 +1,39 @@
# -----------------------------------------------
# stream_noblock.py: Non-blocking stream server
# -----------------------------------------------
import i2p
from i2p import sam
import thread, time
S = sam.socket('Dave', sam.SOCK_STREAM)
S.listen(10) # Queue up to 10 connections
S.setblocking(False) # Non-blocking
print 'Serving at:', S.dest
def handle_connection(C):
"""Handle a single connection in a thread of its own."""
try:
f = C.makefile() # File object
req = f.readline() # Read HTTP request
s = '<h1>Hello!</h1>' # String to send back
f.write('HTTP/1.0 200 OK\r\nContent-Type: text/html' +
'\r\nContent-Length: ' + str(int(len(s))) + '\r\n\r\n' + s)
f.close() # Close file
C.close() # Close connection
except sam.Error, e:
# Recover from SAM errors
print 'Warning:', str(e)
while True:
try:
(C, remotedest) = S.accept() # Get a connection
thread.start_new_thread(handle_connection, (C,))
except sam.BlockError:
# Ignore 'command would have blocked' errors
pass
time.sleep(0.01) # Reduce CPU usage

View File

@ -0,0 +1,28 @@
# -----------------------------------------------
# stream_server.py: Simple stream server
# -----------------------------------------------
import i2p
from i2p import sam
S = sam.socket('Dave', sam.SOCK_STREAM)
S.listen(10) # Queue up to 10 connections
print 'Serving at:', S.dest
while True:
try:
(C, remotedest) = S.accept() # Get a connection
f = C.makefile() # File object
req = f.readline() # Read HTTP request
s = '<h1>Hello!</h1>' # String to send back
f.write('HTTP/1.0 200 OK\r\nContent-Type: text/html' +
'\r\nContent-Length: ' + str(int(len(s))) + '\r\n\r\n' + s)
f.close() # Close file
C.close() # Close connection
except sam.Error, e:
# Recover from SAM errors
print 'Warning:', str(e)

View File

@ -0,0 +1,20 @@
"""
i2p -- I2P Python interface
"""
__all__ = ['Error', 'RouterError', 'sam', 'eep', 'router']
class Error(Exception):
"""Base class for all I2P errors."""
class RouterError(Error):
"""Could not connect to router."""
import sam
import eep
import router
# Internal use only
#import samclasses as _samclasses

View File

@ -0,0 +1,47 @@
# -------------------------------------------------------------
# eep.py: I2P Project -- Eeproxy Python API
# -------------------------------------------------------------
"""
Eeproxy Python API
"""
import urllib2
eepaddr = '127.0.0.1:4444' # Default port for eeproxy
# --------------------------------------------------
# Functions
# --------------------------------------------------
def urlopen(url, eepaddr=eepaddr):
"""Like urllib2.urlopen(url), but only works for eep-sites.
Example: f = urlopen('http://duck.i2p/index.html')"""
if url.find('http://') != 0: url = 'http://' + url
# Handle I2P Destination
if len(url) >= 256:
suffix = url[len('http://'):]
if suffix[:4] != 'i2p/': url = 'http://i2p/' + suffix
# Add trailing slash
if url.find('/', len('http://')) < 0: url = url + '/'
# Remove http:// and trailing slash from eepaddr.
if eepaddr.find('http://') == 0: eepaddr = eepaddr[len('http://'):]
eepaddr = eepaddr.rstrip('/')
proxy = urllib2.ProxyHandler( \
{'http': 'http://anonymous:passwd@' + eepaddr})
opener = urllib2.build_opener(proxy, \
urllib2.HTTPBasicAuthHandler(), urllib2.HTTPHandler)
return opener.open(url)
def urlget(url, eepaddr=eepaddr):
"""Get contents of an eepsite.
Example: urlget('http://duck.i2p/')."""
f = urlopen(url, eepaddr=eepaddr)
ans = f.read()
f.close()
return ans

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