Files
i2p.itoopie/apps/sam/code.leo

3431 lines
105 KiB
Plaintext
Raw Normal View History

<?xml version="1.0" encoding="UTF-8"?>
<leo_file>
<leo_header file_format="2" tnodes="0" max_tnode_index="216" clone_windows="0"/>
<globals body_outline_ratio="0.37624999999999997">
<global_window_position top="155" left="108" height="585" width="890"/>
<global_log_window_position top="0" left="0" height="0" width="0"/>
</globals>
<preferences>
</preferences>
<find_panel_settings>
<find_string></find_string>
<change_string></change_string>
</find_panel_settings>
<vnodes>
<v t="davidmcnab.041004143447" a="E"><vh>I2P SAM Server and Client</vh>
<v t="davidmcnab.041004144338" tnodeList="davidmcnab.041004144338,davidmcnab.041004144338.1,davidmcnab.041004144338.2,davidmcnab.041004144338.4,davidmcnab.041004144338.5,davidmcnab.041004144338.6,davidmcnab.041004144338.8,davidmcnab.041004144338.9,davidmcnab.041004144338.10,davidmcnab.041004144338.11,davidmcnab.041004144338.12,davidmcnab.041004144338.13,davidmcnab.041004144338.14,davidmcnab.041004144338.15,davidmcnab.041004144338.17,davidmcnab.041004144338.18,davidmcnab.041004144338.19,davidmcnab.041004144338.20,davidmcnab.041004144338.21,davidmcnab.041004144338.22,davidmcnab.041004144338.23,davidmcnab.041004144338.24,davidmcnab.041004144338.26,davidmcnab.041004144338.27,davidmcnab.041004144338.29,davidmcnab.041004144338.30,davidmcnab.041004144338.31,davidmcnab.041004144338.32,davidmcnab.041004144338.33,davidmcnab.041004144338.34,davidmcnab.041004144338.35,davidmcnab.041004144338.36,davidmcnab.041004144338.37,davidmcnab.041004144338.38,davidmcnab.041004144338.39,davidmcnab.041004144338.40,davidmcnab.041004144338.41,davidmcnab.041004144338.42,davidmcnab.041004144338.43,davidmcnab.041004144338.44,davidmcnab.041004144338.45,davidmcnab.041004144338.46,davidmcnab.041004144338.47,davidmcnab.041004144338.49,davidmcnab.041004144338.50,davidmcnab.041004144338.51,davidmcnab.041004144338.52,davidmcnab.041004144338.53,davidmcnab.041004144338.54,davidmcnab.041004144338.55,davidmcnab.041004144338.56,davidmcnab.041004144338.57,davidmcnab.041004144338.58,davidmcnab.041004144338.59,davidmcnab.041004144338.60,davidmcnab.041004144338.62,davidmcnab.041004144338.63,davidmcnab.041004144338.64,davidmcnab.041004144338.65,davidmcnab.041004144338.66,davidmcnab.041004144338.67,davidmcnab.041004144338.68,davidmcnab.041004144338.69,davidmcnab.041004144338.70,davidmcnab.041004144338.71,davidmcnab.041004144338.72,davidmcnab.041004144338.73,davidmcnab.041004144338.74,davidmcnab.041004144338.75,davidmcnab.041004144338.76,davidmcnab.041004144338.77,davidmcnab.041004144338.78,davidmcnab.041004144338.79,davidmcnab.041004144338.80,davidmcnab.041004144338.81,davidmcnab.041004144338.82,davidmcnab.041004144338.83,davidmcnab.041004144338.84,davidmcnab.041004144338.85,davidmcnab.041004144338.86,davidmcnab.041004144338.87,davidmcnab.041004144338.88,davidmcnab.041004144338.89,davidmcnab.041004144338.90,davidmcnab.041004144338.92,davidmcnab.041004144338.93,davidmcnab.041004144338.94,davidmcnab.041004144338.95,davidmcnab.041004144338.96,davidmcnab.041004144338.97,davidmcnab.041004144338.98,davidmcnab.041004144338.99,davidmcnab.041004144338.100,davidmcnab.041004144338.101,davidmcnab.041004144338.102,davidmcnab.041004144338.103,davidmcnab.041004144338.105,davidmcnab.041004144338.106,davidmcnab.041004144338.107,davidmcnab.041004144338.108,davidmcnab.041004144338.109"><vh>@file jython/src/i2psam.py</vh>
<v t="davidmcnab.041004144338.1"><vh>imports</vh></v>
<v t="davidmcnab.041004144338.2"><vh>globals</vh></v>
<v t="davidmcnab.041004144338.3" a="E"><vh>I2CP Interface Classes</vh>
<v t="davidmcnab.041004144338.4"><vh>class JavaWrapper</vh></v>
<v t="davidmcnab.041004144338.5" a="E"><vh>class I2PDestination</vh>
<v t="davidmcnab.041004144338.6"><vh>__init__</vh></v>
<v t="davidmcnab.041004144338.7" a="E"><vh>Exporting Methods</vh>
<v t="davidmcnab.041004144338.8"><vh>toBin</vh></v>
<v t="davidmcnab.041004144338.9"><vh>toBinFile</vh></v>
<v t="davidmcnab.041004144338.10"><vh>toBinPrivate</vh></v>
<v t="davidmcnab.041004144338.11"><vh>toBinFilePrivate</vh></v>
<v t="davidmcnab.041004144338.12"><vh>toBase64</vh></v>
<v t="davidmcnab.041004144338.13"><vh>toBase64Private</vh></v>
<v t="davidmcnab.041004144338.14"><vh>toBase64File</vh></v>
<v t="davidmcnab.041004144338.15"><vh>toBase64FilePrivate</vh></v>
</v>
<v t="davidmcnab.041004144338.16" a="E"><vh>Importing Methods</vh>
<v t="davidmcnab.041004144338.17"><vh>fromBin</vh></v>
<v t="davidmcnab.041004144338.18"><vh>fromBinFile</vh></v>
<v t="davidmcnab.041004144338.19"><vh>fromBinPrivate</vh></v>
<v t="davidmcnab.041004144338.20"><vh>fromBinFilePrivate</vh></v>
<v t="davidmcnab.041004144338.21"><vh>fromBase64</vh></v>
<v t="davidmcnab.041004144338.22"><vh>fromBase64File</vh></v>
<v t="davidmcnab.041004144338.23"><vh>fromBase64Private</vh></v>
<v t="davidmcnab.041004144338.24"><vh>fromBase64PrivateFile</vh></v>
</v>
<v t="davidmcnab.041004144338.25" a="E"><vh>Signature Methods</vh>
<v t="davidmcnab.041004144338.26"><vh>sign</vh></v>
<v t="davidmcnab.041004144338.27"><vh>verify</vh></v>
</v>
<v t="davidmcnab.041004144338.28" a="E"><vh>Sanity Methods</vh>
<v t="davidmcnab.041004144338.29"><vh>hasPrivate</vh></v>
</v>
</v>
<v t="davidmcnab.041004144338.30" a="E"><vh>class I2PClient</vh>
<v t="davidmcnab.041004144338.31" a="E"><vh>__init__</vh></v>
<v t="davidmcnab.041004144338.32"><vh>createDestination</vh></v>
<v t="davidmcnab.041004144338.33"><vh>createSession</vh></v>
</v>
<v t="davidmcnab.041004144338.34" a="E"><vh>class I2PSession</vh>
<v t="davidmcnab.041004144338.35"><vh>attributes</vh></v>
<v t="davidmcnab.041004144338.36"><vh>__init__</vh></v>
<v t="davidmcnab.041004144338.37"><vh>sendMessage</vh></v>
<v t="davidmcnab.041004144338.38"><vh>numMessages</vh></v>
<v t="davidmcnab.041004144338.39"><vh>getMessage</vh></v>
<v t="davidmcnab.041004144338.40"><vh>setSessionListener</vh></v>
<v t="davidmcnab.041004144338.41"><vh>destroySession</vh></v>
<v t="davidmcnab.041004144338.42" a="E"><vh>CALLBACKS</vh>
<v t="davidmcnab.041004144338.43"><vh>on_message</vh></v>
<v t="davidmcnab.041004144338.44"><vh>on_abuse</vh></v>
<v t="davidmcnab.041004144338.45"><vh>on_disconnected</vh></v>
<v t="davidmcnab.041004144338.46"><vh>on_error</vh></v>
</v>
</v>
<v t="davidmcnab.041004144338.47"><vh>class I2PSessionListener</vh></v>
</v>
<v t="davidmcnab.041004144338.48" a="E"><vh>Streaming Interface Classes</vh>
<v t="davidmcnab.041004144338.49" a="E"><vh>class I2PSocket</vh>
<v t="davidmcnab.041004144338.50"><vh>attributes</vh></v>
<v t="davidmcnab.041004144338.51"><vh>__init__</vh></v>
<v t="davidmcnab.041004144338.52"><vh>bind</vh></v>
<v t="davidmcnab.041004144338.53"><vh>listen</vh></v>
<v t="davidmcnab.041004144338.54"><vh>accept</vh></v>
<v t="davidmcnab.041004144338.55"><vh>connect</vh></v>
<v t="davidmcnab.041004144338.56"><vh>recv</vh></v>
<v t="davidmcnab.041004144338.57"><vh>send</vh></v>
<v t="davidmcnab.041004144338.58"><vh>available</vh></v>
<v t="davidmcnab.041004144338.59"><vh>close</vh></v>
<v t="davidmcnab.041004144338.60"><vh>_createSockmgr</vh></v>
</v>
</v>
<v t="davidmcnab.041004144338.61" a="E"><vh>I2P SAM Server</vh>
<v t="davidmcnab.041004144338.62" a="E"><vh>class I2PSamServer</vh>
<v t="davidmcnab.041004144338.63"><vh>attributes</vh></v>
<v t="davidmcnab.041004144338.64"><vh>__init__</vh></v>
<v t="davidmcnab.041004144338.65"><vh>run</vh></v>
<v t="davidmcnab.041004144338.66"><vh>finish_request</vh></v>
<v t="davidmcnab.041004144338.67"><vh>samAllocId</vh></v>
</v>
<v t="davidmcnab.041004144338.68" a="E"><vh>class I2PSamClientHandler</vh>
<v t="davidmcnab.041004144338.69"><vh>handle</vh></v>
<v t="davidmcnab.041004144338.70"><vh>on_genkeys</vh></v>
<v t="davidmcnab.041004144338.71"><vh>on_createsession</vh></v>
<v t="davidmcnab.041004144338.72"><vh>on_destroysession</vh></v>
<v t="davidmcnab.041004144338.73"><vh>on_send</vh></v>
<v t="davidmcnab.041004144338.74"><vh>on_receive</vh></v>
<v t="davidmcnab.041004144338.75"><vh>on_HELLO</vh></v>
<v t="davidmcnab.041004144338.76"><vh>on_SESSION</vh></v>
<v t="davidmcnab.041004144338.77"><vh>on_SESSION_CREATE</vh></v>
<v t="davidmcnab.041004144338.78"><vh>on_STREAM</vh></v>
<v t="davidmcnab.041004144338.79"><vh>on_DATAGRAM</vh></v>
<v t="davidmcnab.041004144338.80"><vh>on_RAW</vh></v>
<v t="davidmcnab.041004144338.81"><vh>on_NAMING</vh></v>
<v t="davidmcnab.041004144338.82"><vh>on_DEST</vh></v>
<v t="davidmcnab.041004144338.83"><vh>on_message</vh></v>
<v t="davidmcnab.041004144338.84"><vh>threadSocketListener</vh></v>
<v t="davidmcnab.041004144338.85"><vh>samParse</vh></v>
<v t="davidmcnab.041004144338.86"><vh>samSend</vh></v>
<v t="davidmcnab.041004144338.87"><vh>samCreateArgsList</vh></v>
<v t="davidmcnab.041004144338.88"><vh>_sendbytes</vh></v>
<v t="davidmcnab.041004144338.89"><vh>_recvbytes</vh></v>
</v>
</v>
<v t="davidmcnab.041004144338.90"><vh>Exceptions</vh></v>
<v t="davidmcnab.041004144338.91" a="E"><vh>Functions</vh>
<v t="davidmcnab.041004144338.92"><vh>shahash</vh></v>
<v t="davidmcnab.041004144338.93"><vh>base64enc</vh></v>
<v t="davidmcnab.041004144338.94"><vh>base64dec</vh></v>
<v t="davidmcnab.041004144338.95"><vh>str2bytearray</vh></v>
<v t="davidmcnab.041004144338.96"><vh>bytearray2str</vh></v>
<v t="davidmcnab.041004144338.97"><vh>byteoutstream2str</vh></v>
<v t="davidmcnab.041004144338.98"><vh>dict2props</vh></v>
<v t="davidmcnab.041004144338.99"><vh>takeKey</vh></v>
<v t="davidmcnab.041004144338.100"><vh>log</vh></v>
<v t="davidmcnab.041004144338.101"><vh>logException</vh></v>
<v t="davidmcnab.041004144338.102"><vh>usage</vh></v>
<v t="davidmcnab.041004144338.103"><vh>main</vh></v>
</v>
<v t="davidmcnab.041004144338.104" a="E"><vh>Tests</vh>
<v t="davidmcnab.041004144338.105" tnodeList="davidmcnab.041004144338.105"><vh>testdests</vh></v>
<v t="davidmcnab.041004144338.106"><vh>testsigs</vh></v>
<v t="davidmcnab.041004144338.107"><vh>testsession</vh></v>
<v t="davidmcnab.041004144338.108"><vh>testsocket</vh></v>
</v>
<v t="davidmcnab.041004144338.109"><vh>MAINLINE</vh></v>
</v>
<v t="davidmcnab.041004144551" a="EV" tnodeList="davidmcnab.041004144551,davidmcnab.041004144551.1,davidmcnab.041004144551.2,davidmcnab.041004144551.3,davidmcnab.041004144551.4,davidmcnab.041004144551.5,davidmcnab.041004144551.6,davidmcnab.041004144551.7,davidmcnab.041004144551.8,davidmcnab.041004144551.9,davidmcnab.041004144551.10,davidmcnab.041004144551.12,davidmcnab.041004144551.13,davidmcnab.041004144551.14,davidmcnab.041004144551.15,davidmcnab.041004144551.16,davidmcnab.041004144551.17,davidmcnab.041004144551.18,davidmcnab.041004144551.19,davidmcnab.041004144551.20,davidmcnab.041004144551.21,davidmcnab.041004144551.22,davidmcnab.041004144551.23,davidmcnab.041004144551.24,davidmcnab.041004144551.26,davidmcnab.041004144551.27,davidmcnab.041004144551.28,davidmcnab.041004144551.29,davidmcnab.041004144551.30,davidmcnab.041004144551.31,davidmcnab.041004144551.32,davidmcnab.041004144551.33,davidmcnab.041004144551.35,davidmcnab.041004144551.36,davidmcnab.041004144551.37,davidmcnab.041004144551.38,davidmcnab.041004144551.39,davidmcnab.041004144551.40,davidmcnab.041004144551.41,davidmcnab.041004144551.42,davidmcnab.041004144551.43,davidmcnab.041004144551.45,davidmcnab.041004144551.46,davidmcnab.041004144551.47,davidmcnab.041004144551.48,davidmcnab.041004144551.49,davidmcnab.041004144551.50,davidmcnab.041004144551.51,davidmcnab.041004144551.52"><vh>@file python/src/i2psamclient.py</vh>
<v t="davidmcnab.041004144551.1"><vh>imports</vh></v>
<v t="davidmcnab.041004144551.2"><vh>globals</vh></v>
<v t="davidmcnab.041004144551.3"><vh>exceptions</vh></v>
<v t="davidmcnab.041004144551.4" a="E"><vh>class I2PSamClient</vh>
<v t="davidmcnab.041004144551.5"><vh>attributes</vh></v>
<v t="davidmcnab.041004144551.6"><vh>__init__</vh></v>
<v t="davidmcnab.041004144551.7"><vh>createSession</vh></v>
<v t="davidmcnab.041004144551.8"><vh>destroySession</vh></v>
<v t="davidmcnab.041004144551.9"><vh>send</vh></v>
<v t="davidmcnab.041004144551.10"><vh>receive</vh></v>
<v t="davidmcnab.041004144551.11" a="E"><vh>SAM methods</vh>
<v t="davidmcnab.041004144551.12"><vh>samHello</vh></v>
<v t="davidmcnab.041004144551.13"><vh>samSessionCreate</vh></v>
<v t="davidmcnab.041004144551.14"><vh>samDestGenerate</vh></v>
<v t="davidmcnab.041004144551.15"><vh>samRawSend</vh></v>
<v t="davidmcnab.041004144551.16"><vh>samRawCheck</vh></v>
<v t="davidmcnab.041004144551.17"><vh>samRawReceive</vh></v>
<v t="davidmcnab.041004144551.18"><vh>samDatagramSend</vh></v>
<v t="davidmcnab.041004144551.19"><vh>samDatagramCheck</vh></v>
<v t="davidmcnab.041004144551.20"><vh>samDatagramReceive</vh></v>
<v t="davidmcnab.041004144551.21"><vh>samNamingLookup</vh></v>
<v t="davidmcnab.041004144551.22"><vh>samParse</vh></v>
<v t="davidmcnab.041004144551.23"><vh>samSend</vh></v>
<v t="davidmcnab.041004144551.24"><vh>samCreateArgsList</vh></v>
</v>
<v t="davidmcnab.041004144551.25" a="E"><vh>Receiver Side</vh>
<v t="davidmcnab.041004144551.26"><vh>threadRx</vh></v>
<v t="davidmcnab.041004144551.27"><vh>on_HELLO</vh></v>
<v t="davidmcnab.041004144551.28"><vh>on_SESSION</vh></v>
<v t="davidmcnab.041004144551.29"><vh>on_STREAM</vh></v>
<v t="davidmcnab.041004144551.30"><vh>on_DATAGRAM</vh></v>
<v t="davidmcnab.041004144551.31"><vh>on_RAW</vh></v>
<v t="davidmcnab.041004144551.32"><vh>on_NAMING</vh></v>
<v t="davidmcnab.041004144551.33"><vh>on_DEST</vh></v>
</v>
<v t="davidmcnab.041004144551.34" a="E"><vh>Utility Methods</vh>
<v t="davidmcnab.041004144551.35"><vh>_recvline</vh></v>
<v t="davidmcnab.041004144551.36"><vh>_recvbytes</vh></v>
<v t="davidmcnab.041004144551.37"><vh>_sendbytes</vh></v>
<v t="davidmcnab.041004144551.38"><vh>_sendline</vh></v>
</v>
</v>
<v t="davidmcnab.041004144551.39" a="E"><vh>class I2PRemoteSession</vh>
<v t="davidmcnab.041004144551.40"><vh>__init__</vh></v>
<v t="davidmcnab.041004144551.41"><vh>send</vh></v>
<v t="davidmcnab.041004144551.42"><vh>recv</vh></v>
<v t="davidmcnab.041004144551.43"><vh>destroy</vh></v>
</v>
<v t="davidmcnab.041004144551.44" a="E"><vh>Functions</vh>
<v t="davidmcnab.041004144551.45"><vh>log</vh></v>
<v t="davidmcnab.041004144551.46"><vh>logException</vh></v>
<v t="davidmcnab.041004144551.47"><vh>demoNAMING</vh></v>
<v t="davidmcnab.041004144551.48"><vh>demoRAW</vh></v>
<v t="davidmcnab.041004144551.49"><vh>demoDATAGRAM</vh></v>
<v t="davidmcnab.041004144551.50"><vh>demoSTREAM</vh></v>
<v t="davidmcnab.041004144551.51"><vh>demo</vh></v>
</v>
<v t="davidmcnab.041004144551.52"><vh>MAINLINE</vh></v>
</v>
</v>
</vnodes>
<tnodes>
<t tx="davidmcnab.041004143447"></t>
<t tx="davidmcnab.041004144338">@first #!/usr/bin/env jython
r"""
Implements I2P SAM Server. (refer U{http://drupal.i2p.net/node/view/144})
Also contains useful classes for jython programs,
which wrap the I2P java classes into more python-compatible
paradigms.
If you run this module (or the i2psam.jar file created from it)
without arguments, it'll run an I2P SAM server bridge, listening
on port 7656.
The file i2psamclient.py contains python client classes and a
demo program.
Latest vers of this file is available from U{http://www.freenet.org.nz/i2p/i2psam.py}
Latest epydoc-generated doco at U{http://www.freenet.org.nz/i2p/i2pjyDoc}
The i2psam.jar file is built from this module with the following
command (requires jython and java 1.4.x+ to be installed)::
CLASSPATH=/path/to/i2p.jar:/path/to/mstreaming.jar \
jythonc -jar i2psam.jar --all -A net.invisiblenet i2psam.py
"""
@others
</t>
<t tx="davidmcnab.041004144338.1"># python imports
import sys, os, time, Queue, thread, threading, StringIO, traceback, getopt
from SocketServer import ThreadingTCPServer, StreamRequestHandler
# java imports
import java
# i2p-specific imports
import net.i2p
import net.i2p.client # to shut up epydoc
# shut up java with a few more imports
import net.i2p.client.streaming
import net.i2p.crypto
import net.i2p.data
import net.i2p.client.I2PClient
import net.i2p.client.I2PClientFactory
import net.i2p.client.naming
#import net.i2p.client.I2PSessionListener
# handy shorthand refs
i2p = net.i2p
jI2PClient = i2p.client.I2PClient
# import my own helper hack module
#import I2PHelper
</t>
<t tx="davidmcnab.041004144338.2">clientFactory = i2p.client.I2PClientFactory
#i2phelper = I2PHelper()
PROP_RELIABILITY_BEST_EFFORT = i2p.client.I2PClient.PROP_RELIABILITY_BEST_EFFORT
PROP_RELIABILITY_GUARANTEED = i2p.client.I2PClient.PROP_RELIABILITY_GUARANTEED
version = "0.1.0"
# host/port that our socketserver listens on
i2psamhost = "127.0.0.1"
i2psamport = 7656
# host/port that I2P's I2CP listens on
i2cpHost = "127.0.0.1"
i2cpPort = 7654
#print "i2cpPort=%s" % repr(i2cpPort)
# ------------------------------------------
# logging settings
# 1=v.quiet, 2=normal, 3=verbose, 4=debug, 5=painful
verbosity = 5
# change to a filename to log there instead
logfile = sys.stdout
# when set to 1, and when logfile != sys.stdout, log msgs are written
# both to logfile and console stdout
log2console = 1
# don't touch this!
loglock = threading.Lock()
</t>
<t tx="davidmcnab.041004144338.3"></t>
<t tx="davidmcnab.041004144338.4">class JavaWrapper:
"""
Wraps a java object as attribute '_item', and forwards
__getattr__ to it.
All the classes here derive from this
"""
def __init__(self, item):
self._item = item
def __getattr__(self, attr):
return getattr(self._item, attr)
</t>
<t tx="davidmcnab.041004144338.5">class I2PDestination(JavaWrapper):
"""
Wraps java I2P destination objects, with a big difference - these
objects store the private parts.
"""
@others
</t>
<t tx="davidmcnab.041004144338.6">def __init__(self, **kw):
"""
Versatile constructor
Keywords (choose only one option):
- (none) - create a whole new dest
- dest, private - wrap an existing I2P java dest with private stream
(private is a byte array)
- bin - reconstitute a public-only dest from a binary string
- binfile - reconstitute public-only from a binary file
- binprivate - reconsistitute private dest from binary string
- binfileprivate - reconsistitute private dest from binary file pathname
- base64 - reconstitute public-only from base64 string
- base64file - reconstitute public-only from file containing base64
- base64private - reconstitute private from string containing base64
- base64fileprivate - reconstitute private from file containing base64
also:
- client - a java net.i2p.client.I2PClient object
(avoids need for temporary client object when creating new dests)
"""
dest = i2p.data.Destination()
JavaWrapper.__init__(self, dest)
self._private = None
if kw.has_key('dest'):
self._item = kw['dest']
if kw.has_key('private'):
self._private = kw['private']
elif kw.has_key('bin'):
self.fromBin(kw['bin'])
elif kw.has_key('binfile'):
self.fromBinFilePrivate(kw['binfile'])
elif kw.has_key('binprivate'):
self.fromBinPrivate(kw['binprivate'])
elif kw.has_key('binfileprivate'):
self.fromBinFilePrivate(kw['binfileprivate'])
elif kw.has_key('base64'):
self.fromBase64(kw['base64'])
elif kw.has_key('base64file'):
self.fromBase64File(kw['base64file'])
elif kw.has_key('base64private'):
self.fromBase64Private(kw['base64private'])
elif kw.has_key('base64fileprivate'):
self.fromBase64FilePrivate(kw['base64fileprivate'])
else:
# create a whole new one, with a temporary client object (if needed)
if kw.has_key('client'):
client = kw['client']
else:
client = clientFactory.createClient()
bytestream = java.io.ByteArrayOutputStream()
self._item = client.createDestination(bytestream)
self._private = bytestream.toByteArray()
</t>
<t tx="davidmcnab.041004144338.7"></t>
<t tx="davidmcnab.041004144338.8">def toBin(self):
"""
Returns a binary string of dest
"""
return bytearray2str(self.toByteArray())
</t>
<t tx="davidmcnab.041004144338.9">def toBinFile(self, path):
"""
Writes out public binary to a file
"""
f = open(path, "wb")
f.write(self.toBin())
f.flush()
f.close()
</t>
<t tx="davidmcnab.041004144338.10">def toBinPrivate(self):
"""
Returns the private key string as binary
"""
if self._private == None:
raise NoPrivateKey
return bytearray2str(self._private)
</t>
<t tx="davidmcnab.041004144338.11">def toBinFilePrivate(self, path):
"""
Writes out a binary file with the dest info
"""
f = open(path, "wb")
f.write(self.toBinPrivate())
f.flush()
f.close()
</t>
<t tx="davidmcnab.041004144338.12">def toBase64(self):
"""
Returns base64 string of public part
"""
return self._item.toBase64()
</t>
<t tx="davidmcnab.041004144338.13">def toBase64Private(self):
"""
Exports dest as base64, including private stuff
"""
if self._private == None:
raise NoPrivateKey
return i2p.data.Base64.encode(self._private)
</t>
<t tx="davidmcnab.041004144338.14">def toBase64File(self, path):
"""
Exports dest to file as base64
"""
f = open(path, "wb")
f.write(self.toBase64())
f.flush()
f.close()
</t>
<t tx="davidmcnab.041004144338.15">def toBase64FilePrivate(self, path):
"""
Writes out a base64 file with the private dest info
"""
f = open(path, "wb")
f.write(self.toBase64Private())
f.flush()
f.close()
</t>
<t tx="davidmcnab.041004144338.16"></t>
<t tx="davidmcnab.041004144338.17">def fromBin(self, bin):
"""
Loads this dest from a binary string
"""
self._item.fromByteArray(str2bytearray(bin))
self._private = None
</t>
<t tx="davidmcnab.041004144338.18">def fromBinFile(self, path):
"""
Loads public part from file containing binary
"""
f = open(path, "rb")
self.fromBin(f.read())
f.close()
</t>
<t tx="davidmcnab.041004144338.19">def fromBinPrivate(self, s):
"""
Loads this dest object from a base64 private key string
"""
bytes = str2bytearray(s)
self._private = bytes
stream = java.io.ByteArrayInputStream(bytes)
self._item.readBytes(stream)
</t>
<t tx="davidmcnab.041004144338.20">def fromBinFilePrivate(self, path):
"""
Loads this dest object, given the pathname of a file containing
a binary destkey
"""
self.fromBinPrivate(open(path, "rb").read())
</t>
<t tx="davidmcnab.041004144338.21">def fromBase64(self, b64):
"""
Loads this dest from a base64 string
"""
self._item.fromBase64(b64)
self._private = None
</t>
<t tx="davidmcnab.041004144338.22">def fromBase64File(self, path):
"""
Loads public part from file containing base64
"""
f = open(path, "rb")
self.fromBase64(f.read())
f.close()
</t>
<t tx="davidmcnab.041004144338.23">def fromBase64Private(self, s):
"""
Loads this dest object from a base64 private key string
"""
bytes = i2p.data.Base64.decode(s)
self._private = bytes
stream = java.io.ByteArrayInputStream(bytes)
self._item.readBytes(stream)
</t>
<t tx="davidmcnab.041004144338.24">def fromBase64FilePrivate(self, path):
"""
Loads this dest from a base64 file containing private key
"""
self.fromBase64Private(open(path, "rb").read())
</t>
<t tx="davidmcnab.041004144338.25"></t>
<t tx="davidmcnab.041004144338.26">def sign(self, s):
"""
Signs a string using this dest's priv key
"""
# get byte stream
bytes = str2bytearray(s)
# stream up our private bytes
stream = java.io.ByteArrayInputStream(self._private)
# temporary dest object
d = i2p.data.Destination()
# suck the public part off the stream
d.readBytes(stream)
# temporary private key object
privkey = i2p.data.PrivateKey()
privkey.readBytes(stream)
# now we should just have the signing key portion left in the stream
signingkey = i2p.data.SigningPrivateKey()
signingkey.readBytes(stream)
# create DSA engine
dsa = i2p.crypto.DSAEngine()
sig = dsa.sign(bytes, signingkey)
rawsig = bytearray2str(sig.getData())
return rawsig
</t>
<t tx="davidmcnab.041004144338.27">def verify(self, s, sig):
"""
Verifies a string against this dest, to test if it was actually
signed by whoever has the dest privkey
"""
# get byte stream from data
databytes = str2bytearray(s)
# get signature stream from sig
sigstream = java.io.ByteArrayInputStream(str2bytearray(sig))
# make a signature object
signature = i2p.data.Signature()
signature.readBytes(sigstream)
# get signature verify key
pubkey = self.getSigningPublicKey()
#log(4, "databytes=%s, pubkey=%s" % (repr(databytes), repr(pubkey)))
# now get a verification
dsa = i2p.crypto.DSAEngine()
result = dsa.verifySignature(signature, databytes, pubkey)
return result
</t>
<t tx="davidmcnab.041004144338.28"></t>
<t tx="davidmcnab.041004144338.29">def hasPrivate(self):
"""
Returns True if this dest has private parts, False if not
"""
if self._private:
return 1
else:
return 0
</t>
<t tx="davidmcnab.041004144338.30">class I2PClient(JavaWrapper):
"""
jython-comfortable wrapper for java I2P client class
"""
@others
</t>
<t tx="davidmcnab.041004144338.31">def __init__(self, **kw):
"""
I2PClient constructor
No args or keywords as yet
"""
client = clientFactory.createClient()
JavaWrapper.__init__(self, client)
</t>
<t tx="davidmcnab.041004144338.32">def createDestination(self, **kw):
"""
Creates a destination, either a new one, or from a bin or base64 file
Keywords:
- see L{I2PDestination} constructor
"""
return I2PDestination(**kw)
</t>
<t tx="davidmcnab.041004144338.33">def createSession(self, dest, sessionClass=None, **kw):
"""
Create a session
Arguments:
- dest - an L{I2PDestination} object which MUST contain a private portion
- sessionClass - if given, this should be a subclass
of I2PSession. This allows you to implement your own handlers.
Keywords:
- session options (refer javadocs)
"""
if sessionClass is None:
sessionClass = I2PSession
if not dest.hasPrivate():
raise NoPrivateKey("Dest object has no private key")
#print kw
#session = self._item.createSession(destStream, dict2props(kw))
session = sessionClass(client=self, dest=dest, **kw)
return session
#return sessionClass(session=session)
</t>
<t tx="davidmcnab.041004144338.34">class I2PSession(JavaWrapper):
"""
Wraps an I2P client session
You can subclass this, overriding the on_* handler callbacks,
and pass it as an argument to I2PClient.createSession
In the default 'on_message' callback, message retrieval is
synchronous - inbound messages get written to an internal queue,
which you can checked with numMessages() and retrieved from via
getMessage(). You may override on_message() if you
want to handle incoming messages asynchronously yourself.
Note - as far as I can tell, this class should be thread-safe.
"""
@others
</t>
<t tx="davidmcnab.041004144338.35">host = i2cpHost
port = i2cpPort
</t>
<t tx="davidmcnab.041004144338.36">def __init__(self, **kw):
"""
I2PSession constructor
Keywords:
- either:
- session - a java i2p session object
- or:
- client - an L{I2PClient} object
- dest - an L{I2PDestination} object
Also:
- listener - an L{I2PSessionListener} object.
Router-level options:
- reliability - one of 'guaranteed' and 'besteffort' (default 'besteffort')
- host - host on which router is running
- port - port on which router is listening
"""
#
# grab options destined for java class
#
options = {}
reliability = takeKey(kw, 'reliability', 'besteffort')
if reliability == 'guaranteed':
reliability = jI2PClient.PROP_RELIABILITY_GUARANTEED
else:
reliability = jI2PClient.PROP_RELIABILITY_BEST_EFFORT
options[jI2PClient.PROP_RELIABILITY] = reliability
host = takeKey(kw, 'host', self.host)
options[jI2PClient.PROP_TCP_HOST] = host
port = takeKey(kw, 'port', self.port)
options[jI2PClient.PROP_TCP_PORT] = str(port)
if kw.has_key('reliability'):
reliability = kw['reliability']
if kw.has_key('listener'):
listener = kw['listener']
del kw['listener']
else:
listener = I2PSessionListener()
#print options
#
# other keywords handled locally
#
if kw.has_key('session'):
session = kw['session']
del kw['session']
JavaWrapper.__init__(self, session)
elif kw.has_key('client') and kw.has_key('dest'):
client = kw['client']
dest = kw['dest']
del kw['client']
del kw['dest']
destStream = java.io.ByteArrayInputStream(dest._private)
session = self._item = client._item.createSession(destStream, dict2props(options))
#client.createSession(dest, dict2props(options))
else:
raise Exception("implementation incomplete")
# set up a listener
self.setSessionListener(listener)
# set up a queue for inbound msgs
self.qInbound = Queue.Queue()
self.lockInbound = threading.Lock()
self.nInboundMessages = 0
self.lockOutbound = threading.Lock()
</t>
<t tx="davidmcnab.041004144338.37">def sendMessage(self, dest, payload):
"""
Sends a message to another dest
Arguments:
- dest - an L{I2PDestination} object
- payload - a string to send
"""
dest = dest._item
payload = str2bytearray(payload)
self.lockOutbound.acquire()
try:
res = self._item.sendMessage(dest, payload)
except:
self.lockOutbound.release()
raise
self.lockOutbound.release()
return res
</t>
<t tx="davidmcnab.041004144338.38">def numMessages(self):
"""
Returns the number of unretrieved inbound messages
"""
self.lockInbound.acquire()
n = self.nInboundMessages
self.lockInbound.release()
return n
</t>
<t tx="davidmcnab.041004144338.39">def getMessage(self, blocking=1):
"""
Returns the next available inbound message.
If blocking is set to 1 (default), blocks
till another message comes in.
If blocking is set to 0, returns None if there
are no available messages.
"""
if blocking:
msg = self.qInbound.get()
#print "getMessage: acquiring lock"
self.lockInbound.acquire()
#print "getMessage: got lock"
self.nInboundMessages -= 1
else:
#print "getMessage: acquiring lock"
self.lockInbound.acquire()
#print "getMessage: got lock"
if self.nInboundMessages &gt; 0:
msg = self.qInbound.get()
self.nInboundMessages -= 1
else:
msg = None
self.lockInbound.release()
#print "getMessage: released lock"
return msg
</t>
<t tx="davidmcnab.041004144338.40">def setSessionListener(self, listener):
"""
Designates an L{I2PSessionListener} object to listen to this session
"""
self.listener = listener
listener.addSession(self)
self._item.setSessionListener(listener)
</t>
<t tx="davidmcnab.041004144338.41">def destroySession(self):
"""
Destroys an existing session
Note that due to a jython quirk, calls to destroySession might
trigger a TypeError relating to arg mismatch - we ignore such
errors here because by the time the exception happens, the
session has already been successfully closed
"""
try:
self._item.destroySession()
except TypeError:
pass
</t>
<t tx="davidmcnab.041004144338.42">#
# handler methods which you should override
#
@others
</t>
<t tx="davidmcnab.041004144338.43">def on_message(self, msg):
"""
Callback for when a message arrives.
Appends the message to the inbound queue, which you can check
with the numMessages() method, and read with getMessage()
You should override this if you want to handle inbound messages
asynchronously.
Arguments:
- msg - a string that was sent by peer
"""
#print "on_message: msg=%s" % msg
self.lockInbound.acquire()
#print "on_message: got lock"
self.qInbound.put(msg)
self.nInboundMessages += 1
self.lockInbound.release()
#print "on_message: released lock"
</t>
<t tx="davidmcnab.041004144338.44">def on_abuse(self, severity):
"""
Callback indicating abuse is happening
Arguments:
- severity - an int of abuse level, 1-100
"""
print "on_abuse: severity=%s" % severity
</t>
<t tx="davidmcnab.041004144338.45">def on_disconnected(self):
"""
Callback indicating remote peer disconnected
"""
print "on_disconnected"
</t>
<t tx="davidmcnab.041004144338.46">def on_error(self, message, error):
"""
Callback indicating an error occurred
"""
print "on_error: message=%s error=%s" % (message, error)
</t>
<t tx="davidmcnab.041004144338.47">class I2PSessionListener(i2p.client.I2PSessionListener):
"""
Wraps a java i2p.client.I2PSessionListener object
"""
def __init__(self, *sessions):
self.sessions = list(sessions)
def addSession(self, session):
"""
Adds an L{I2PSession} object to the list of sessions to listen on
Note - you must also invoke the session's setSessionListener() method
(see I2PSession.setSessionListener)
"""
if session not in self.sessions:
self.sessions.append(session)
def delSession(self, session):
"""
Stop listening to a given session
"""
if session in self.sessions:
del self.sessions.index[session]
def messageAvailable(self, session, msgId, size):
"""
Callback from java::
public void messageAvailable(
I2PSession session,
int msgId,
long size)
"""
#print "listener - messageAvailable"
# try to find session in our sessions table
sessions = filter(lambda s, session=session: s._item == session, self.sessions)
if sessions:
#print "compare to self.session-&gt;%s" % (session == self.session._item)
# found a matching session - retrieve it
session = sessions[0]
# retrieve message and pass to callback
msg = session.receiveMessage(msgId)
msgStr = bytearray2str(msg)
session.on_message(msgStr)
else:
print "messageAvailable: unknown session=%s msgId=%s size=%s" % (session, msgId, size)
def reportAbuse(self, session, severity):
"""
Callback from java::
public void reportAbuse(
I2PSession session,
int severity)
"""
if self.session:
self.session.on_abuse(severity)
else:
print "reportAbuse: unknown session=%s severity=%s" % (session, severity)
def disconnected(self, session):
"""
Callback from java::
public void disconnected(I2PSession session)
"""
if self.session:
self.session.on_disconnected()
else:
print "disconnected: unknown session=%s" % session
def errorOccurred(session, message, error):
"""
Callback from java::
public void errorOccurred(
I2PSession session,
java.lang.String message,
java.lang.Throwable error)
"""
if self.session:
self.session.on_error(message, error)
else:
print "errorOccurred: message=%s error=%s" % (message, error)
</t>
<t tx="davidmcnab.041004144338.48"></t>
<t tx="davidmcnab.041004144338.49">class I2PSocket:
"""
Wraps I2P streaming API into a form resembling python sockets
"""
@others
</t>
<t tx="davidmcnab.041004144338.50">host = i2cpHost
port = i2cpPort
</t>
<t tx="davidmcnab.041004144338.51">def __init__(self, dest=None, **kw):
"""
Create an I2P streaming socket
Arguments:
- dest - a private destination to associate with this socket
Keywords:
- host - hostname on which i2cp is listening (default self.host)
- port - port on which i2cp listens (default self.port)
Internally used keywords (used for wrapping an accept()ed connection):
- dest
- remdest
- sock
- instream
- outstream
"""
# set up null attribs
self.sockmgr = None
self.instream = None
self.outstream = None
self.sock = None
self._connected = 0
self._blocking = 1
# save dest (or lack thereof)
self.dest = dest
if kw.has_key('sock') \
and kw.has_key('dest') \
and kw.has_key('remdest') \
and kw.has_key('instream') \
and kw.has_key('outstream'):
# wrapping an accept()'ed connection
self.sock = kw['sock']
self.dest = kw['dest']
self.remdest = kw['remdest']
self.instream = kw['instream']
self.outstream = kw['outstream']
else:
# process keywords
self.host = kw.get('host', self.host)
self.port = int(kw.get('port', self.port))
# we need a factory, don't we?
self.sockmgrFact = i2p.client.streaming.I2PSocketManagerFactory()
</t>
<t tx="davidmcnab.041004144338.52">def bind(self, dest=None):
"""
'binds' the socket to a dest
dest is an I2PDestination object, which you may specify in the constructor
instead of here. However, we give you the option of specifying here for
some semantic compatibility with python sockets.
"""
if dest is not None:
self.dest = dest
elif not self.dest:
# create new dest, client should interrogate it at some time
self.dest = Destination()
</t>
<t tx="davidmcnab.041004144338.53">def listen(self, *args, **kw):
"""
Sets up the object to receive connections
"""
# sanity checks
if self.sockmgr:
raise I2PSocketError(".sockmgr already present - have you already called listen?")
if not self.dest:
raise I2PSocketError("socket is not bound to a destination")
# create the socket manager
self._createSockmgr()
</t>
<t tx="davidmcnab.041004144338.54">def accept(self):
"""
Waits for incoming connections, and returns a new I2PSocket object
with the connection
"""
# sanity check
if not self.sockmgr:
raise I2PSocketError(".listen() has not been called on this socket")
# accept a conn and get its streams
sock = self.sockmgr.getServerSocket().accept()
instream = sock.getInputStream()
outstream = sock.getOutputStream()
remdest = I2PDestination(dest=sock.getPeerDestination())
# wrap it and return it
sockobj = I2PSocket(dest=self.dest,
remdest=remdest,
sock=sock,
instream=instream,
outstream=outstream)
self._connected = 1
return sockobj
</t>
<t tx="davidmcnab.041004144338.55">def connect(self, remdest):
"""
Connects to a remote destination
"""
# sanity check
if self.sockmgr:
raise I2PSocketError(".sockmgr already present - have you already called listen/connect?")
# create whole new dest if none was provided to constructor
if self.dest is None:
self.dest = I2PDestination()
# create the socket manager
self._createSockmgr()
# do the connect
#print "remdest._item = %s" % repr(remdest._item)
opts = net.i2p.client.streaming.I2PSocketOptions()
try:
self.sock = self.sockmgr.connect(remdest._item, opts)
self.remdest = remdest
except:
logException(2, "apparent exception, continuing...")
self.instream = self.sock.getInputStream()
self.outstream = self.sock.getOutputStream()
self._connected = 1
</t>
<t tx="davidmcnab.041004144338.56">def recv(self, nbytes):
"""
Reads nbytes of data from socket
"""
# sanity check
if not self.instream:
raise I2PSocketError("Socket is not connected")
# for want of better methods, read bytewise
chars = []
while nbytes &gt; 0:
byte = self.instream.read()
if byte &lt; 0:
break # got all we're gonna get
char = chr(byte)
chars.append(char)
#print "read: got a byte %s (%s)" % (byte, repr(char))
nbytes -= 1
# got it all
buf = "".join(chars)
#print "recv: buf=%s" % repr(buf)
return buf
</t>
<t tx="davidmcnab.041004144338.57">def send(self, buf):
"""
Sends buf thru socket
"""
# sanity check
if not self.outstream:
raise I2PSocketError("Socket is not connected")
# and write it out
#print "send: writing '%s' to outstream..." % repr(buf)
outstream = self.outstream
for c in buf:
outstream.write(ord(c))
# flush just in case
#print "send: flushing..."
self.outstream.flush()
#print "send: done"
</t>
<t tx="davidmcnab.041004144338.58">def available(self):
"""
Returns the number of bytes available for recv()
"""
return self.sock.available()
</t>
<t tx="davidmcnab.041004144338.59">def close(self):
"""
Closes the socket
"""
# sanity check
#if not self._connected:
# raise I2PSocketError("Socket is not connected")
# shut up everything
try:
self.instream.close()
except:
pass
try:
self.outstream.close()
except:
pass
try:
self.sock.close()
except:
pass
</t>
<t tx="davidmcnab.041004144338.60">def _createSockmgr(self):
#options = {jI2PClient.PROP_TCP_HOST: self.host,
# jI2PClient.PROP_TCP_PORT: self.port}
options = {}
props = dict2props(options)
# get a java stream thing from dest
stream = java.io.ByteArrayInputStream(self.dest._private)
# create socket manager thing
self.sockmgr = self.sockmgrFact.createManager(stream, self.host, self.port, props)
</t>
<t tx="davidmcnab.041004144338.61"></t>
<t tx="davidmcnab.041004144338.62">class I2PSamServer(ThreadingTCPServer):
"""
A server which makes I2CP available via a socket
"""
@others
</t>
<t tx="davidmcnab.041004144338.63">host = i2psamhost
port = i2psamport
i2cphost = i2cpHost
i2cpport = i2cpPort
version = version
</t>
<t tx="davidmcnab.041004144338.64">def __init__(self, i2pclient=None, **kw):
"""
Create the client listener object
Arguments:
- i2pclient - an I2PClient object - optional - if not
given, one will be created
Keywords:
- host - host to listen on for client conns (default self.host ('127.0.0.1')
- port - port to listen on for client conns (default self.port (7656)
- i2cphost - host to talk to i2cp on (default self.i2cphost ('127.0.0.1'))
- i2cpport - port to talk to i2cp on (default self.i2cphost ('127.0.0.1'))
"""
# create an I2PClient object if none given
if i2pclient is None:
i2pclient = I2PClient()
self.i2pclient = i2pclient
# get optional host/port for client and i2cp
self.host = kw.get('host', self.host)
self.port = int(kw.get('port', self.port))
self.i2cphost = kw.get('i2cphost', self.i2cphost)
self.i2cpport = int(kw.get('i2cpport', self.i2cpport))
# create record of current sessions, and a lock for it
self.sessions = {}
self.sessionsLock = threading.Lock()
self.streams = {}
self.streamsLock = threading.Lock()
self.samNextId = 1
self.samNextIdLock = threading.Lock()
# and create the server
try:
ThreadingTCPServer.__init__(
self,
(self.host, self.port),
I2PSamClientHandler)
except:
log(4, "crashed with host=%s, port=%s" % (self.host, self.port))
raise
</t>
<t tx="davidmcnab.041004144338.65">def run(self):
"""
Run the SAM server.
when connections come in, they are automatically
accepted, and an L{I2PClientHandler} object created,
and its L{handle} method invoked.
"""
log(4, "Listening for client requests on %s:%s" % (self.host, self.port))
self.serve_forever()
</t>
<t tx="davidmcnab.041004144338.66">def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
try:
self.RequestHandlerClass(request, client_address, self)
except:
pass
log(3, "Client session terminated")
</t>
<t tx="davidmcnab.041004144338.67">def samAllocId(self):
"""
Allocates a new unique id as required by SAM protocol
"""
self.samNextIdLock.acquire()
id = self.samNextId
self.samNextId += 1
self.samNextIdLock.release()
return id
</t>
<t tx="davidmcnab.041004144338.68">class I2PSamClientHandler(StreamRequestHandler):
r"""
Manages a single socket connection from a client.
When a client connects to the SAM server, the I2PSamServer
object creates an instance of this class, and invokes its
handle method. See L{handle}.
Note that if a client terminates its connection to the server, the server
will destroy all current connections initiated by that client
Size values are decimal
Connection is persistent
"""
@others</t>
<t tx="davidmcnab.041004144338.69">def handle(self):
"""
Reads command/data messages from SAM Client, executes these,
and sends back responses.
Plants callback hooks into I2PSession objects, so that when
data arrives via I2P, it can be immediately sent to the client.
"""
self.localsessions = {}
self.globalsessions = self.server.sessions
self.localstreams = {} # keyed by sam stream id
self.globalstreams = self.server.streams
self.samSessionIsOpen = 0
self.samSessionStyle = ''
# need a local sending lock
self.sendLock = threading.Lock()
log(5, "Got req from %s" % repr(self.client_address))
try:
self.namingService = i2p.client.naming.HostsTxtNamingService()
except:
logException(2, "Failed to create naming service object")
try:
while 1:
# get req
req = self.rfile.readline().strip()
flds = [s.strip() for s in req.split(" ")]
cmd = flds[0]
if cmd in ['HELLO', 'SESSION', 'STREAM', 'DATAGRAM', 'RAW', 'NAMING', 'DEST']:
topic, subtopic, args = self.samParse(flds)
method = getattr(self, "on_"+cmd, None)
method(topic, subtopic, args)
else:
method = getattr(self, "on_"+cmd, None)
if method:
method(flds)
else:
# bad shit
self.wfile.write("error unknown command '%s'\n" % cmd)
except IOError:
log(3, "Client connection terminated")
except ValueError:
pass
except:
logException(4, "Client req handler crashed")
self.wfile.write("error\n")
# clean up sessions
for dest in self.localsessions.keys():
if dest in self.globalsessions.keys():
log(4, "forgetting global dest %s" % dest[:30])
del self.globalsessions[dest]
self.finish()
#thread.exit()
</t>
<t tx="davidmcnab.041004144338.70">def on_genkeys(self, flds):
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
# genkeys
try:
dest = I2PDestination()
priv = dest.toBase64Private()
pub = dest.toBase64()
write("ok %s %s\n" % (pub, priv))
except:
write("error exception\n")
</t>
<t tx="davidmcnab.041004144338.71">def on_createsession(self, flds):
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
sessionsLock.acquire()
try:
b64priv = flds[1]
# spit if someone else already has this dest
if b64priv in globalsessions.keys():
write("error dest in use\n")
elif b64priv in self.localsessions.keys():
# duh, already open locally, treat as ok
write("ok\n")
else:
# whole new session - set it up
dest = I2PDestination(base64private=b64priv)
log(4, "Creating session on dest '%s'" % b64priv[:40])
session = client.createSession(dest)
log(4, "Connecting session on dest '%s'" % b64priv[:40])
session.connect()
log(4, "Session on dest '%s' now live" % b64priv[:40])
# and remember it
self.localsessions[b64priv] = session
globalsessions[b64priv] = session
# and tell the client the good news
write("ok\n")
except:
logException(4, "createsession fail")
write("error exception\n")
sessionsLock.release()
</t>
<t tx="davidmcnab.041004144338.72">def on_destroysession(self, flds):
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
sessionsLock.acquire()
try:
b64priv = flds[1]
# spit if session not known
if not globalsessions.has_key(b64priv):
# no such session presently exists anywhere
write("error nosuchsession\n")
elif not self.localsessions.has_key(b64priv):
# session exists, but another client owns it
write("error notyoursession\n")
else:
# session exists and we own it
session = self.localsessions[b64priv]
del self.localsessions[b64priv]
del globalsessions[b64priv]
try:
session.destroySession()
write("ok\n")
except:
raise
except:
logException(4, "destroy session failed")
write("error exception\n")
sessionsLock.release()
log(4, "done")
</t>
<t tx="davidmcnab.041004144338.73">def on_send(self, flds):
#log(4, "entered: %s" % repr(flds))
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
sessionsLock.acquire()
session = None
try:
size = int(flds[1])
b64priv = flds[2]
b64peer = flds[3]
msg = self._recvbytes(size)
# spit if session not known
if not globalsessions.has_key(b64priv):
# no such session presently exists anywhere
log(4, "no such session")
write("error nosuchsession\n")
elif not self.localsessions.has_key(b64priv):
# session exists, but another client owns it
write("error notyoursession\n")
else:
session = self.localsessions[b64priv]
except:
logException(2, "Send exception")
write("error exception on send command\n")
sessionsLock.release()
if not session:
return
# now get/instantiate the remote dest
try:
peerDest = I2PDestination(base64=b64peer)
except:
peerDest = None
logException(2, "Send: bad remote dest")
write("error bad remote dest\n")
if not peerDest:
return
# and do the send
try:
res = session.sendMessage(peerDest, msg)
except:
logException(2, "Send: failed")
write("error exception on send\n")
res = None
if res is None:
return
# report result
if res:
write("ok\n")
else:
write("error send failed\n")
log(4, "done")
</t>
<t tx="davidmcnab.041004144338.74">def on_receive(self, flds):
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
sessionsLock.acquire()
session = None
try:
b64priv = flds[1]
# spit if session not known
if not globalsessions.has_key(b64priv):
# no such session presently exists anywhere
write("error nosuchsession\n")
elif not self.localsessions.has_key(b64priv):
# session exists, but another client owns it
write("error notyoursession\n")
else:
session = self.localsessions[b64priv]
except:
logException(4, "receive command error")
write("error exception on receive command\n")
sessionsLock.release()
if not session:
log(4, "no session matching privdest %s" % b64priv[:30])
return
# does this session have any received data?
if session.numMessages() &gt; 0:
msg = session.getMessage()
write("ok %s\n%s" % (len(msg), msg))
else:
write("ok 0\n")
log(4, "done")
return
</t>
<t tx="davidmcnab.041004144338.75">def on_HELLO(self, topic, subtopic, args):
"""
Responds to client PING
"""
log(4, "entered")
self.samSend("HELLO", "PONG")
log(4, "responded to HELLO")
</t>
<t tx="davidmcnab.041004144338.76">def on_SESSION(self, topic, subtopic, args):
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
localsessions = self.localsessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
if subtopic == 'CREATE':
if self.samSessionIsOpen:
self.samSend("SESSION", "STATUS",
RESULT="I2P_ERROR",
MESSAGE="Session_already_created",
)
return
# get/validate STYLE arg
style = self.samSessionStyle = args.get('STYLE', None)
if style is None:
self.samSend("SESSION", "STATUS",
RESULT="I2P_ERROR",
MESSAGE="Missing_STYLE_argument",
)
return
elif style not in ['STREAM', 'DATAGRAM', 'RAW']:
self.samSend("SESSION", "STATUS",
RESULT="I2P_ERROR",
MESSAGE="Invalid_STYLE_argument_'%s'" % style,
)
return
# get/validate DESTINATION arg
dest = args.get('DESTINATION', None)
if dest == 'TRANSIENT':
# create new temporary dest
dest = self.samDest = I2PDestination()
destb64 = dest.toBase64Private()
else:
# make sure dest isn't globally or locally known
if dest in globalsessions.keys() or dest in localsessions.keys():
self.samSend("SESSION", "STATUS",
RESULT="DUPLICATED_DEST",
MESSAGE="Destination_'%s...'_already_in_use" % dest[:20],
)
return
# try to reconstitute dest from given base64
try:
destb64 = dest
dest = I2PDestination(base64private=dest)
except:
self.samSend("SESSION", "STATUS",
RESULT="INVALID_KEY",
MESSAGE="Bad_destination_base64_string_'%s...'" % destb64[:20],
)
return
# got valid dest now
self.dest = dest
self.samDestPub = dest.toBase64()
if style in ['RAW', 'DATAGRAM']:
if style == 'DATAGRAM':
# we need to know how big binary pub dests and sigs
self.samDestPubBin = dest.toBin()
self.samDestPubBinLen = len(self.samDestPubBin)
self.samSigLen = len(self.dest.sign("nothing"))
log(4, "binary pub dests are %s bytes, sigs are %s bytes" % (
self.samDestPubBinLen, self.samSigLen))
i2cpHost = args.get('I2CP.HOST', server.i2cphost)
i2cpPort = int(args.get('I2CP.PORT', server.i2cpport))
# both these styles require an I2PSession object
session = client.createSession(dest, host=i2cpHost, port=i2cpPort)
# plug in our inbound message handler
session.on_message = self.on_message
log(4, "Connecting session on dest '%s'" % destb64[:40])
try:
session.connect()
except net.i2p.client.I2PSessionException:
self.samSend("SESSION", "STATUS",
RESULT="I2P_ERROR",
MESSAGE="Failed_to_connect_to_i2cp_port",
)
logException(3, "Failed to connect I2PSession")
return
log(4, "Session on dest '%s' now live" % destb64[:40])
# and remember it
localsessions[destb64] = session
globalsessions[destb64] = session
self.samSession = session
else: # STREAM
# no need to create session object, because we're using streaming api
# but we do need to mark it as being in use
localsessions[destb64] = globalsessions[destb64] = None
# make a local socket
sock = self.samSock = I2PSocket(dest)
# and we also need to fire up a socket listener
thread.start_new_thread(self.threadSocketListener, (sock, dest))
# finally, we can reply with the good news
self.samSend("SESSION", "STATUS",
RESULT="OK",
)
else: # subtopic != CREATE
self.samSend("SESSION", "STATUS",
RESULT="I2P_ERROR",
MESSAGE="Invalid_command_'SESSION_%s'" % subtopic,
)
return
</t>
<t tx="davidmcnab.041004144338.77">def on_SESSION_CREATE(self, topic, subtopic, args):
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
localsessions = self.localsessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
</t>
<t tx="davidmcnab.041004144338.78">def on_STREAM(self, topic, subtopic, args):
log(4, "entered")
server = self.server
client = server.i2pclient
globalsessions = server.sessions
sessionsLock = server.sessionsLock
read = self.rfile.read
readline = self.rfile.readline
write = self.wfile.write
flush = self.wfile.flush
if subtopic == 'CONNECT':
# who are we connecting to again?
remdest = I2PDestionation(b64=args['DESTINATION'])
id = args['ID']
try:
self.samSock.connect(remdest)
self.samSend("STREAM", "STATUS",
RESULT='OK',
ID=id,
)
except:
self.samSend("STREAM", "STATUS",
RESULT='I2P_ERROR',
MESSAGE='exception on connect',
)
</t>
<t tx="davidmcnab.041004144338.79">def on_DATAGRAM(self, topic, subtopic, args):
r"""
DATAGRAM SEND
DESTINATION=$base64key
SIZE=$numBytes\n[$numBytes of data]
All datagram messages have a signature/hash header, formatted as:
- sender's binary public dest
- S(H(sender_bin_pubdest + recipient_bin_pubdest + msg))
"""
log(4, "entered")
# at this stage of things, we don't know how to handle anything except SEND
if subtopic != 'SEND':
log(3, "Got illegal subtopic '%s' in DATAGRAM command" % subtopic)
return
# get the details
peerdestb64 = args['DESTINATION']
peerdest = I2PDestination(base64=peerdestb64)
peerdestBin = base64dec(peerdestb64)
data = args['DATA']
# make up the header
log(4, "samDestPubBin (%s) %s" % (type(self.samDestPubBin), repr(self.samDestPubBin)))
log(4, "peerdestBin (%s) %s" % (type(peerdestBin), repr(peerdestBin)))
log(4, "data (%s) %s" % (type(data), repr(data)))
hashed = shahash(self.samDestPubBin + peerdestBin + data)
log(4, "hashed=%s" % repr(hashed))
sig = self.dest.sign(hashed)
log(4, "sig=%s" % repr(sig))
hdr = self.samDestPubBin + sig
# send the thing
self.samSession.sendMessage(peerdest, hdr + data)
</t>
<t tx="davidmcnab.041004144338.80">def on_RAW(self, topic, subtopic, args):
r"""
RAW SEND
DESTINATION=$base64key
SIZE=$numBytes\n[$numBytes of data]
"""
log(4, "entered")
# at this stage of things, we don't know how to handle anything except SEND
if subtopic != 'SEND':
return
# get the details
peerdest = I2PDestination(base64=args['DESTINATION'])
msg = args['DATA']
# send the thing
self.samSession.sendMessage(peerdest, msg)
</t>
<t tx="davidmcnab.041004144338.81">def on_NAMING(self, topic, subtopic, args):
log(4, "entered: %s %s %s" % (repr(topic), repr(subtopic), repr(args)))
# at this stage of things, we don't know how to handle anything except LOOKUP
if subtopic != 'LOOKUP':
return
# get the details
host = args['NAME']
log(4, "looking up host %s" % host)
# try to lookup
jdest = self.namingService.lookup(host)
if not jdest:
log(4, "host %s not found" % host)
self.samSend("NAMING", "REPLY",
RESULT="KEY_NOT_FOUND",
NAME=host,
)
return
try:
b64 = I2PDestination(dest=jdest).toBase64()
self.samSend("NAMING", "REPLY",
RESULT="OK",
NAME=host,
VALUE=b64,
)
log(4, "host %s found and valid key returned" % host)
return
except:
log(4, "host %s found but key invalid" % host)
self.samSend("NAMING", "REPLY",
RESULT="INVALID_KEY",
NAME=host,
)
</t>
<t tx="davidmcnab.041004144338.82">def on_DEST(self, topic, subtopic, args):
log(4, "Generating dest")
dest = I2PDestination()
priv = dest.toBase64Private()
pub = dest.toBase64()
log(4, "Sending dest to client")
self.samSend("DEST", "REPLY", PUB=pub, PRIV=priv)
log(4, "done")
</t>
<t tx="davidmcnab.041004144338.83">def on_message(self, msg):
"""
This callback gets plugged into the I2PSession object,
so we can asychronously notify our client when stuff arrives
"""
if self.samSessionStyle == 'RAW':
self.samSend("RAW", "RECEIVE", msg)
elif self.samSessionStyle == 'DATAGRAM':
# ain't so simple, we gotta rip and validate the header
remdestBin = msg[:self.samDestPubBinLen]
log(4, "remdestBin=%s" % repr(remdestBin))
sig = msg[self.samDestPubBinLen:self.samDestPubBinLen+self.samSigLen]
log(4, "sig=%s" % repr(sig))
data = msg[self.samDestPubBinLen+self.samSigLen:]
log(4, "data=%s" % repr(data))
# now try to verify
hashed = shahash(remdestBin + self.samDestPubBin + data)
log(4, "hashed=%s" % repr(hashed))
remdest = I2PDestination(bin=remdestBin)
if remdest.verify(hashed, sig):
# fine - very good, pass it on
log(4, "sig from peer is valid")
self.samSend("DATAGRAM", "RECEIVE", data,
DESTINATION=remdest.toBase64(),
)
else:
log(4, "DATAGRAM sig from peer is invalid")
</t>
<t tx="davidmcnab.041004144338.84">def threadSocketListener(self, sock, dest):
"""
Listens for incoming socket connections, and
notifies the client accordingly
"""
destb64 = dest.toBase64()
log(4, "Listening for connections to %s..." % destb64[:40])
while 1:
newsock = sock.accept()
# need an id, negative
id = - self.server.samAllocId()
# register it in local and global streams
self.localstreams[id] = self.globalstreams[id] = newsock
# who is connected to us?
remdest = newsock.remdest
remdest_b64 = remdest.toBase64()
# and notify the client
self.samSend("STREAM", "CONNECTED",
DESTINATION=remdest_b64,
ID=id)
</t>
<t tx="davidmcnab.041004144338.85">def samParse(self, flds):
"""
carves up a SAM command, returns it as a 3-tuple:
- cmd - command string
- subcmd - subcommand string
- dargs - dict of args
"""
cmd = flds[0]
subcmd = flds[1]
args = flds[2:]
dargs = {}
for arg in args:
try:
name, val = arg.split("=", 1)
except:
logException(3, "failed to process %s" % repr(arg))
raise
dargs[name] = val
# read and add data if any
if dargs.has_key('SIZE'):
size = dargs['SIZE'] = int(dargs['SIZE'])
dargs['DATA'] = self._recvbytes(size)
#log(4, "\n".join([cmd+" "+subcmd] + [("%s=%s (...)" % (k,v[:40])) for k,v in dargs.items()]))
log(4, "\n".join([cmd+" "+subcmd] + [("%s=%s (...)" % (k,v)) for k,v in dargs.items()]))
return cmd, subcmd, dargs
</t>
<t tx="davidmcnab.041004144338.86">def samSend(self, topic, subtopic, data=None, **kw):
"""
Sends a SAM message (reply?) back to client
Arguments:
- topic - the first word in the reply, eg 'STREAM'
- subtopic - the second word of the reply, eg 'CONNECTED'
- data - a string of raw data to send back (optional)
Keywords:
- extra 'name=value' items to pass back.
Notes:
1. SIZE is not required. If sending back data, it will
be sized and a SIZE arg inserted automatically.
2. a dict of values can be passed to the 'args' keyword, in lieu
of direct keywords. This allows for cases where arg names would
cause python syntax clashes, eg 'tunnels.depthInbound'
"""
items = [topic, subtopic]
# stick in SIZE if needed
if data is not None:
kw['SIZE'] = str(len(data))
else:
data = '' # for later
self.samCreateArgsList(kw, items)
# and whack it together
buf = " ".join(items) + '\n' + data
# and ship it
self.sendLock.acquire()
try:
self._sendbytes(buf)
except:
self.sendLock.release()
raise
self.sendLock.release()
</t>
<t tx="davidmcnab.041004144338.87">def samCreateArgsList(self, kw1, lst):
for k,v in kw1.items():
if k == 'args':
self.samCreateArgsList(v, lst)
else:
lst.append("=".join([str(k), str(v)]))
</t>
<t tx="davidmcnab.041004144338.88">def _sendbytes(self, raw):
self.wfile.write(raw)
self.wfile.flush()
</t>
<t tx="davidmcnab.041004144338.89">def _recvbytes(self, count):
"""
Does a guaranteed read of n bytes
"""
read = self.rfile.read
chunks = []
needed = count
while needed &gt; 0:
chunk = read(needed)
chunklen = len(chunk)
needed -= chunklen
chunks.append(chunk)
raw = "".join(chunks)
# done
return raw
</t>
<t tx="davidmcnab.041004144338.90">class NoPrivateKey(Exception):
"""Destination object has no private key"""
class I2PSocketError(Exception):
"""Error working with I2PSocket objects"""
</t>
<t tx="davidmcnab.041004144338.91"></t>
<t tx="davidmcnab.041004144338.92">def shahash(s):
"""
Calculates SHA Hash of a string, as a string, using
I2P hashing facility
"""
h = net.i2p.crypto.SHA256Generator().calculateHash(s)
h = bytearray2str(h.getData())
return h
</t>
<t tx="davidmcnab.041004144338.93">def base64enc(s):
return net.i2p.data.Base64.encode(s)
</t>
<t tx="davidmcnab.041004144338.94">def base64dec(s):
return bytearray2str(net.i2p.data.Base64.decode(s))
</t>
<t tx="davidmcnab.041004144338.95">def str2bytearray(s):
"""
Convenience - converts python string to java-friendly byte array
"""
a = []
for c in s:
n = ord(c)
if n &gt;= 128:
n = n - 256
a.append(n)
return a
</t>
<t tx="davidmcnab.041004144338.96">def bytearray2str(a):
"""
Convenience - converts java-friendly byte array to python string
"""
chars = []
for n in a:
if n &lt; 0:
n += 256
chars.append(chr(n))
return "".join(chars)
</t>
<t tx="davidmcnab.041004144338.97">def byteoutstream2str(bs):
"""
Convenience - converts java-friendly byteoutputstream to python string
"""
chars = []
while 1:
c = bs.read()
if c &gt;= 0:
chars.append(chr(c))
else:
break
return "".join(chars)
</t>
<t tx="davidmcnab.041004144338.98">def dict2props(d):
"""
Converts a python dict d into a java.util.Properties object
"""
props = java.util.Properties()
for k,v in d.items():
props[k] = str(v)
return props
</t>
<t tx="davidmcnab.041004144338.99">def takeKey(somedict, keyname, default=None):
"""
Utility function to destructively read a key from a given dict.
Same as the dict's 'takeKey' method, except that the key (if found)
sill be deleted from the dictionary.
"""
if somedict.has_key(keyname):
val = somedict[keyname]
del somedict[keyname]
else:
val = default
return val
</t>
<t tx="davidmcnab.041004144338.100">def log(level, msg, nPrev=0):
# ignore messages that are too trivial for chosen verbosity
if level &gt; verbosity:
return
loglock.acquire()
try:
# rip the stack
caller = traceback.extract_stack()[-(2+nPrev)]
path, line, func = caller[:3]
path = os.path.split(path)[1]
full = "%s:%s:%s():\n* %s" % (
path,
line,
func,
msg.replace("\n", "\n + "))
now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
msg = "%s %s\n" % (now, full)
if logfile == sys.stdout:
print msg
else:
file(logfile, "a").write(msg+"\n")
except:
s = StringIO.StringIO()
traceback.print_exc(file=s)
print s.getvalue()
print "Logger crashed"
loglock.release()</t>
<t tx="davidmcnab.041004144338.101">def logException(level, msg=''):
s = StringIO.StringIO()
traceback.print_exc(file=s)
log(level, "%s\n%s" % (s.getvalue(), msg), 1)
</t>
<t tx="davidmcnab.041004144338.102">def usage(detailed=0):
print "Usage: %s &lt;options&gt; [&lt;command&gt;]" % sys.argv[0]
if not detailed:
print "Run with '-h' to get detailed help"
sys.exit(0)
print "I2PSAM is a bridge that allows I2P client programs to access the"
print "I2P network by talking over a plaintext socket connection."
print "References:"
print " - http://www.freenet.org.nz/i2p - source, doco, downloadables"
print " - http://drupal.i2p.net/node/view/144 - I2P SAM specification"
print
print "Options:"
print " -h, -?, --help - display this help"
print " -v, --version - print program version"
print " -V, --verbosity=n - set verbosity to n, default 2, 1==quiet, 4==noisy"
print " -H, --listenhost=host - specify host to listen on for client connections"
print " -P, --listenport=port - port to listen on for client connections"
print " --i2cphost=host - hostname of I2P router's I2CP interface"
print " --i2cpport=port - port of I2P router's I2CP interface"
print
print "Commands:"
print " (run with no commands to launch SAM server)"
print " samserver - runs as a SAM server"
print " test - run a suite of self-tests"
print
sys.exit(0)
</t>
<t tx="davidmcnab.041004144338.103">def main():
argv = sys.argv
argc = len(argv)
try:
opts, args = getopt.getopt(sys.argv[1:],
"h?vV:H:P:",
['help', 'version', 'verbosity=',
'listenhost=', 'listenport=',
'i2cphost=', 'i2cpport=',
])
except:
traceback.print_exc(file=sys.stdout)
usage("You entered an invalid option")
cmd = 'samserver'
# we prolly should pass all these parms in constructor call, but
# what the heck!
#global verbosity, i2psamhost, i2psamport, i2cpHost, i2cpPort
serveropts = {}
for opt, val in opts:
if opt in ['-h', '-?', '--help']:
usage(1)
elif opt in ['-v', '--version']:
print "I2P SAM version %s" % version
sys.exit(0)
elif opt in ['-V', '--verbosity']:
serveropts['verbosity'] = int(val)
elif opt in ['-H', '--listenhost']:
serveropts['host'] = val
elif opt in ['-P', '--listenport']:
serveropts['port'] = int(val)
elif opt in ['--i2cphost']:
serveropts['i2cphost'] = val
elif opt in ['--i2cpport']:
serveropts['i2cpport'] = int(val)
else:
usage(0)
if len(args) == 0:
cmd = 'samserver'
else:
cmd = args[0]
if cmd == 'samserver':
log(2, "Running I2P SAM Server...")
server = I2PSamServer(**serveropts)
server.run()
elif cmd == 'test':
print "RUNNING I2P Jython TESTS"
testsigs()
testdests()
testsession()
testsocket()
else:
usage(0)
</t>
<t tx="davidmcnab.041004144338.104"></t>
<t tx="davidmcnab.041004144338.105">def testdests():
"""
Demo function which tests out dest generation and import/export
"""
print
print "********************************************"
print "Testing I2P destination create/export/import"
print "********************************************"
print
print "Generating a destination"
d1 = I2PDestination()
print "Exporting and importing dest1 in several forms"
print "public binary string..."
d1_bin = d1.toBin()
d2_bin = I2PDestination(bin=d1_bin)
print "public binary file..."
d1.toBinFile("temp-d1-bin")
d2_binfile = I2PDestination(binfile="temp-d1-bin")
print "private binary string..."
d1_binprivate = d1.toBinPrivate()
d2_binprivate = I2PDestination(binprivate=d1_binprivate)
print "private binary file..."
d1.toBinFilePrivate("temp-d1-bin-private")
d2_binfileprivate = I2PDestination(binfileprivate="temp-d1-bin-private")
print "public base64 string..."
d1_b64 = d1.toBase64()
d2_b64 = I2PDestination(base64=d1_b64)
print "public base64 file..."
d1.toBase64File("temp-d1-b64")
d2_b64file = I2PDestination(base64file="temp-d1-b64")
print "private base64 string..."
d1_base64private = d1.toBase64Private()
d2_b64private = I2PDestination(base64private=d1_base64private)
print "private base64 file..."
d1.toBase64FilePrivate("temp-d1-b64-private")
d2_b64fileprivate = I2PDestination(base64fileprivate="temp-d1-b64-private")
print "All destination creation/import/export tests passed!"
</t>
<t tx="davidmcnab.041004144338.106">def testsigs():
global d1, d1pub, d1sig, d1res
print
print "********************************************"
print "Testing I2P dest-based signatures"
print "********************************************"
print
print "Creating dest..."
d1 = I2PDestination()
s_good = "original stuff that we're signing"
s_bad = "non-original stuff we're trying to forge"
print "Signing some shit against d1..."
d1sig = d1.sign(s_good)
print "Creating public dest d1pub"
d1pub = I2PDestination(bin=d1.toBin())
print "Verifying original data with d1pub"
res = d1pub.verify(s_good, d1sig)
print "Result: %s (should be 1)" % repr(res)
print "Trying to verify on a different string"
res1 = d1pub.verify(s_bad, d1sig)
print "Result: %s (should be 0)" % repr(res1)
if res and not res1:
print "signing/verifying test passed"
else:
print "SIGNING/VERIFYING TEST FAILED"
</t>
<t tx="davidmcnab.041004144338.107">def testsession():
global c, d1, d2, s1, s2
print
print "********************************************"
print "Testing I2P dest-&gt;dest messaging"
print "********************************************"
print
print "Creating I2P client..."
c = I2PClient()
print "Creating destination d1..."
d1 = c.createDestination()
print "Creating destination d2..."
d2 = c.createDestination()
print "Creating destination d3..."
d3 = c.createDestination()
print "Creating session s1 on dest d1..."
s1 = c.createSession(d1, host='localhost', port=7654)
print "Creating session s2 on dest d2..."
s2 = c.createSession(d2)
print "Connecting session s1..."
s1.connect()
print "Connecting session s2..."
s2.connect()
print "Sending message from s1 to d2..."
s1.sendMessage(d2, "Hi there, s2!!")
print "Retrieving message from s2..."
print "got: %s" % repr(s2.getMessage())
print "Sending second message from s1 to d2..."
s1.sendMessage(d2, "Hi there again, s2!!")
print "Retrieving message from s2..."
print "got: %s" % repr(s2.getMessage())
print "Sending message from s1 to d3 (should take ages then fail)..."
res = s1.sendMessage(d3, "This is futile!!")
print "result of that send was %s (should have been 0)" % res
print "Destroying session s1..."
s1.destroySession()
print "Destroying session s2..."
s2.destroySession()
print "session tests passed!"
</t>
<t tx="davidmcnab.041004144338.108">def testsocket():
global d1, d2, s1, s2
print
print "********************************************"
print "Testing I2P streaming interface"
print "********************************************"
print
print "Creating destinations..."
dServer = I2PDestination()
dClient = I2PDestination()
print "Creating sockets..."
sServer = I2PSocket(dServer)
sClient = I2PSocket(dClient)
# server thread which simply reads a line at a time, then echoes
# that line back to the client
def servThread(s):
print "server: binding socket"
s.bind()
print "server: setting socket to listen"
s.listen()
print "server: awaiting connection"
sock = s.accept()
print "server: got connection"
sock.send("Hello, echoing...\n")
buf = ''
while 1:
c = sock.recv(1)
if c == '':
sock.close()
print "server: socket closed"
break
buf += c
if c == '\n':
sock.send("SERVER: "+buf)
buf = ''
# client thread which reads lines and prints them to stdout
def clientThread(s):
buf = ''
while 1:
c = s.recv(1)
if c == '':
s.close()
print "client: socket closed"
break
buf += c
if c == '\n':
print "client: got %s" % repr(buf)
buf = ''
print "launching server thread..."
thread.start_new_thread(servThread, (sServer,))
print "client: trying to connect"
sClient.connect(dServer)
print "client: connected, launching rx thread"
thread.start_new_thread(clientThread, (sClient,))
while 1:
line = raw_input("Enter something (q to quit)&gt; ")
if line == 'q':
print "closing client socket"
sClient.close()
break
sClient.send(line+"\n")
print "I2PSocket test apparently succeeded"
</t>
<t tx="davidmcnab.041004144338.109">if __name__ == '__main__':
main()
</t>
<t tx="davidmcnab.041004144551">@first #!/usr/bin/env python
"""
Implements a client API for I2CP messaging via SAM
Very simple I2P messaging interface, which should prove easy
to reimplement in your language of choice
This module can be used from cpython or jython
Run this module without arguments to see a demo in action
(requires SAM server to be already running)
"""
@others
</t>
<t tx="davidmcnab.041004144551.1">import sys, os, socket, thread, threading, Queue, traceback, StringIO, time
</t>
<t tx="davidmcnab.041004144551.2"># -----------------------------------------
# server access settings
i2psamhost = '127.0.0.1'
i2psamport = 7656
# ------------------------------------------
# logging settings
# 1=v.quiet, 2=normal, 3=verbose, 4=debug, 5=painful
verbosity = 5
# change to a filename to log there instead
logfile = sys.stdout
# when set to 1, and when logfile != sys.stdout, log msgs are written
# both to logfile and console stdout
log2console = 1
# don't touch this!
loglock = threading.Lock()
</t>
<t tx="davidmcnab.041004144551.3">class I2PServerFail(Exception):
"""
A failure in connecting to the I2CP server
"""
class I2PCommandFail(Exception):
"""
A failure in an I2CP command
"""
pass
</t>
<t tx="davidmcnab.041004144551.4">class I2PSamClient:
"""
Implements a reference client for accessing I2CP via i2psam
Connects to i2psam's I2PSamServer, sends commands
and receives results
The primitives should be reasonably self-explanatory
Usage summary:
1. create one or more I2PSamClient instances per process (1 should be fine)
2. invoke the L{genkeys} method to create destination keypairs
3. create sessions objects via the L{createSession} method
4. use these session objects to send and receive data
5. destroy the session objects when you're done
Refer to the function L{demo} for a simple example
"""
@others
</t>
<t tx="davidmcnab.041004144551.5"># server host/port settings exist here in case you might
# have a reason for overriding in a subclass
host = i2psamhost
port = i2psamport
i2cpHost = None
i2cpPort = None
</t>
<t tx="davidmcnab.041004144551.6">def __init__(self, **kw):
"""
Creates a client connection to i2psam listener
Keywords:
- host - host to connect to (default 127.0.0.1)
- port - port to connect to (default 7656)
"""
# get optional host/port
log(4, "entered")
self.host = kw.get('host', self.host)
self.port = int(kw.get('port', self.port))
self.cmdLock = threading.Lock()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.lockHello = threading.Lock()
self.sendLock = threading.Lock()
self.qNewDests = Queue.Queue()
self.qSession = Queue.Queue()
self.qDatagrams = Queue.Queue()
self.qRawMessages = Queue.Queue()
self.namingReplies = {}
self.namingCache = {}
self.isRunning = 1
log(4, "trying connection to SAM server...")
try:
self.sock.connect((self.host, self.port))
except:
raise I2PServerFail(
"Connection to i2psam server failed\n"
"(are you sure your I2P router is running, and\n"
"listening for I2CP connections on %s:%s?)" % (self.host, self.port)
)
# fire up receiver thread
thread.start_new_thread(self.threadRx, ())
# ping the server
try:
log(4, "trying to ping SAM server...")
self.samHello()
except:
logException(4, "Exception on handshaking")
raise I2PServerFail("Failed to handshake with i2psam server")
# connected fine
log(2, "I2CP Client successfully connected")
</t>
<t tx="davidmcnab.041004144551.7">def createSession(self, privdest):
"""
DEPRECATED - use sam* methods instead!
Creates a session using private destkey
"""
#3. createsession:
# - client-&gt;server:
# - createsession &lt;base64private&gt;\n
# - server-&gt;client:
# - ok\n OR
# - error[ &lt;reason&gt;]\n
self.cmdLock.acquire()
try:
self._sendline("createsession %s" % privdest)
respitems = self._recvline().split(" ", 1)
if respitems[0] == 'ok':
res = None
else:
res = respitems[1]
except:
logException(2, "createsession fail")
self.cmdLock.release()
raise
self.cmdLock.release()
if res:
raise I2PCommandFail("createsession fail: "+res)
return I2PRemoteSession(self, privdest)
</t>
<t tx="davidmcnab.041004144551.8">def destroySession(self, privdest):
"""
DEPRECATED - use sam* methods instead!
Destrlys a session using private destkey
"""
#4. destroysession:
# - client-&gt;server:
# - destroysession &lt;base64private&gt;\n
# - server-&gt;client:
# - ok\n OR
# - error[ &lt;reason&gt;]\n
self.cmdLock.acquire()
try:
self._sendline("destroysession %s" % privdest)
respitems = self._recvline().split(" ", 1)
if respitems[0] == 'ok':
res = None
else:
res = respitems[1]
except:
logException(2, "destroysession fail")
self.cmdLock.release()
raise
self.cmdLock.release()
if res:
raise I2PCommandFail("destroysession fail: " + res)
return res
</t>
<t tx="davidmcnab.041004144551.9">def send(self, privdest, peerdest, msg):
"""
DEPRECATED - use sam* methods instead!
Sends a block of data from local dest to remote dest
"""
#5. send:
# - client-&gt;server:
# - send &lt;size&gt; &lt;localbase64private&gt; &lt;remotebase64dest&gt;\ndata
# - server-&gt;client:
# - ok\n OR
# - error[ &lt;reason&gt;]\n
self.cmdLock.acquire()
try:
self._sendline("send %s %s %s" % (len(msg), privdest, peerdest))
self._sendbytes(msg)
line = self._recvline()
#print "** %s" % line
respitems = line.split(" ", 1)
if respitems[0] == 'ok':
res = None
else:
res = " ".join(respitems[1:])
except:
logException(2, "send fail")
self.cmdLock.release()
raise
self.cmdLock.release()
if res:
raise I2PCommandFail("send fail: " + res)
return res
</t>
<t tx="davidmcnab.041004144551.10">def receive(self, privdest):
"""
DEPRECATED - use sam* methods instead!
receives a block of data, returning string, or None if no data available
"""
#6. receive:
# - client-&gt;server:
# - receive &lt;localbase64private&gt;\n
# - server-&gt;client:
# - ok &lt;size&gt;\ndata OR
# - error[ &lt;reason&gt;]\n
self.cmdLock.acquire()
try:
self._sendline("receive %s" % privdest)
respitems = self._recvline().split(" ", 1)
if respitems[0] == 'ok':
res = None
size = int(respitems[1])
msg = self._recvbytes(size)
res = None
else:
res = respitems[1]
except:
logException(2, "receive fail")
self.cmdLock.release()
raise
self.cmdLock.release()
if res:
raise I2PCommandFail("destroysession fail: " + res)
return msg
</t>
<t tx="davidmcnab.041004144551.11"></t>
<t tx="davidmcnab.041004144551.12">def samHello(self):
"""
Sends a quick HELLO PING to SAM server and awaits response
Arguments:
- none
Keywords:
- none
Returns:
- nothing (None) if ping sent and pong received, or raises an exception if
failed
"""
self.lockHello.acquire()
self.samSend("HELLO", "PING")
self.lockHello.acquire()
self.lockHello.release()
</t>
<t tx="davidmcnab.041004144551.13">def samSessionCreate(self, style, dest, **kw):
"""
Creates a SAM session
Arguments:
- style - one of 'STREAM', 'DATAGRAM' or 'RAW'
- dest - base64 private destination
Keywords:
- i2cphost - hostname for the SAM bridge to contact i2p router on
- i2cpport - port for the SAM bridge to contact i2p router on
Returns:
- 'OK' if session was created successfully, or a tuple
(keyword, message) if not
"""
kw1 = dict(kw)
kw1['STYLE'] = self.samStyle = style
kw1['DESTINATION'] = dest
# stick in i2cp host/port if specified
if kw.has_key('i2cphost'):
kw1['I2CP.HOST'] = kw['i2cphost']
if kw.has_key('i2cpport'):
kw1['I2CP.PORT'] = kw['i2cpport']
self.samSend("SESSION", "CREATE",
**kw1)
subtopic, args = self.qSession.get()
if args['RESULT'] == 'OK':
return 'OK'
else:
return (args['RESULT'], args['MESSAGE'])
</t>
<t tx="davidmcnab.041004144551.14">def samDestGenerate(self):
"""
Creates a whole new dest and returns an tuple pub, priv as
base64 public and private destination keys
"""
self.samSend("DEST", "GENERATE")
pub, priv = self.qNewDests.get()
return pub, priv
</t>
<t tx="davidmcnab.041004144551.15">def samRawSend(self, peerdest, msg):
"""
Sends a raw anon message to another peer
peerdest is the public base64 destination key of the peer
"""
self.samSend("RAW", "SEND", msg,
DESTINATION=peerdest,
)
</t>
<t tx="davidmcnab.041004144551.16">def samRawCheck(self):
"""
Returns 1 if there are received raw messages available, 0 if not
"""
return not self.qRawMessages.empty()
</t>
<t tx="davidmcnab.041004144551.17">def samRawReceive(self, blocking=1):
"""
Returns the next raw message available,
blocking if none is available and the blocking arg is set to 0
If blocking is 0, and no messages are available, returns None.
Remember that you can check for availability with
the .samRawCheck() method
"""
if not blocking:
if self.qRawMessages.empty():
return None
return self.qRawMessages.get()
</t>
<t tx="davidmcnab.041004144551.18">def samDatagramSend(self, peerdest, msg):
"""
Sends a repliable datagram message to another peer
peerdest is the public base64 destination key of the peer
"""
self.samSend("DATAGRAM", "SEND", msg,
DESTINATION=peerdest,
)
</t>
<t tx="davidmcnab.041004144551.19">def samDatagramCheck(self):
"""
Returns 1 if there are datagram messages received messages available, 0 if not
"""
return not self.qDatagrams.empty()
</t>
<t tx="davidmcnab.041004144551.20">def samDatagramReceive(self, blocking=1):
"""
Returns the next datagram message available,
blocking if none is available.
If blocking is set to 0, and no messages are available,
returns None.
Remember that you can check for availability with
the .samRawCheck() method
Returns 2-tuple: dest, msg
where dest is the base64 destination of the peer from
whom the message was received
"""
if not blocking:
if self.qDatagrams.empty():
return None
return self.qDatagrams.get()
</t>
<t tx="davidmcnab.041004144551.21">def samNamingLookup(self, host):
"""
Looks up a host in hosts.txt
"""
# try the cache first
if self.namingCache.has_key(host):
log(4, "found host %s in cache" % host)
return self.namingCache[host]
# make a queue for reply
q = self.namingReplies[host] = Queue.Queue()
# send off req
self.samSend("NAMING", "LOOKUP",
NAME=host,
)
# get resp
resp = q.get()
result = resp.get('RESULT', 'none')
if result == 'OK':
log(4, "adding host %s to cache" % host)
val = resp['VALUE']
self.namingCache[host] = val
return val
else:
raise I2PCommandFail("Error looking up '%s': %s %s" % (
host, result, resp.get('MESSAGE', '')))
</t>
<t tx="davidmcnab.041004144551.22">def samParse(self, flds):
"""
carves up a SAM command, returns it as a 3-tuple:
- cmd - command string
- subcmd - subcommand string
- dargs - dict of args
"""
cmd = flds[0]
subcmd = flds[1]
args = flds[2:]
dargs = {}
for arg in args:
try:
name, val = arg.split("=", 1)
except:
logException(3, "failed to process %s" % repr(arg))
raise
dargs[name] = val
# read and add data if any
if dargs.has_key('SIZE'):
size = dargs['SIZE'] = int(dargs['SIZE'])
dargs['DATA'] = self._recvbytes(size)
#log(4, "\n".join([cmd+" "+subcmd] + [("%s=%s (...)" % (k,v[:40])) for k,v in dargs.items()]))
log(4, "\n".join([cmd+" "+subcmd] + [("%s=%s (...)" % (k,v)) for k,v in dargs.items()]))
return cmd, subcmd, dargs
</t>
<t tx="davidmcnab.041004144551.23">def samSend(self, topic, subtopic, data=None, **kw):
"""
Sends a SAM message (reply?) back to client
Arguments:
- topic - the first word in the reply, eg 'STREAM'
- subtopic - the second word of the reply, eg 'CONNECTED'
- data - a string of raw data to send back (optional)
Keywords:
- extra 'name=value' items to pass back.
Notes:
1. SIZE is not required. If sending back data, it will
be sized and a SIZE arg inserted automatically.
2. a dict of values can be passed to the 'args' keyword, in lieu
of direct keywords. This allows for cases where arg names would
cause python syntax clashes, eg 'tunnels.depthInbound'
"""
items = [topic, subtopic]
# stick in SIZE if needed
if data is not None:
kw['SIZE'] = str(len(data))
else:
data = '' # for later
self.samCreateArgsList(kw, items)
# and whack it together
buf = " ".join(items) + '\n' + data
# and ship it
self.sendLock.acquire()
try:
self._sendbytes(buf)
except:
self.sendLock.release()
raise
self.sendLock.release()
</t>
<t tx="davidmcnab.041004144551.24">def samCreateArgsList(self, kw1, lst):
for k,v in kw1.items():
if k == 'args':
self.samCreateArgsList(v, lst)
else:
lst.append("=".join([str(k), str(v)]))
</t>
<t tx="davidmcnab.041004144551.25"></t>
<t tx="davidmcnab.041004144551.26">def threadRx(self):
"""
Handles all incoming stuff from SAM, storing in
local queues as appropriate
"""
while self.isRunning:
try:
log(4, "Awaiting next message from server")
line = self._recvline()
if line == '':
log(3, "I2P server socket closed")
return
flds = line.split(" ")
topic, subtopic, args = self.samParse(flds)
log(4, "Got %s %s %s" % (topic, subtopic, args))
handleMsg = getattr(self, "on_"+topic, None)
if handleMsg:
handleMsg(topic, subtopic, args)
else:
log(2, "No handler for '%s' message" % topic)
except:
#logException(3, "Exception handling %s %s\n%s" % (topic, subtopic, args))
logException(3, "Exception handling %s" % repr(line))
</t>
<t tx="davidmcnab.041004144551.27">def on_HELLO(self, topic, subtopic, args):
"""
Handles HELLO PONG messages from server
"""
# just wake up the caller
log(4, "got HELLO")
self.lockHello.release()
</t>
<t tx="davidmcnab.041004144551.28">def on_SESSION(self, topic, subtopic, args):
"""
Handles SESSION messages from server
"""
# just stick whatever on the queue and wake up the caller
res = subtopic, args
self.qSession.put(res)
</t>
<t tx="davidmcnab.041004144551.29">def on_STREAM(self, topic, subtopic, args):
"""
Handles STREAM messages from server
"""
</t>
<t tx="davidmcnab.041004144551.30">def on_DATAGRAM(self, topic, subtopic, args):
"""
Handles DATAGRAM messages from server
"""
remdest = args['DESTINATION']
data = args['DATA']
self.qDatagrams.put((remdest, data))
</t>
<t tx="davidmcnab.041004144551.31">def on_RAW(self, topic, subtopic, args):
"""
Handles RAW messages from server
"""
data = args['DATA']
log(3, "Got anonymous datagram %s" % repr(data))
self.qRawMessages.put(data)
</t>
<t tx="davidmcnab.041004144551.32">def on_NAMING(self, topic, subtopic, args):
"""
Handles NAMING messages from server
"""
# just find out hostname, and stick it on resp q
host = args['NAME']
self.namingReplies[host].put(args)
</t>
<t tx="davidmcnab.041004144551.33">def on_DEST(self, topic, subtopic, args):
"""
Handles DEST messages from server
"""
pubkey = args['PUB']
privkey = args['PRIV']
res = pubkey, privkey
self.qNewDests.put(res)
</t>
<t tx="davidmcnab.041004144551.34"></t>
<t tx="davidmcnab.041004144551.35">def _recvline(self):
"""
Guaranteed read of a full line
"""
chars = []
while 1:
c = self.sock.recv(1)
if c in ['', '\n']:
break
chars.append(c)
return "".join(chars)
</t>
<t tx="davidmcnab.041004144551.36">def _recvbytes(self, num):
"""
Guaranteed read of num bytes
"""
if num &lt;= 0:
return ""
reqd = num
chunks = []
while reqd &gt; 0:
chunk = self.sock.recv(reqd)
if not chunk:
raise I2PServerFail("Buffer read fail")
chunks.append(chunk)
reqd -= len(chunk)
return "".join(chunks)
</t>
<t tx="davidmcnab.041004144551.37">def _sendbytes(self, buf):
"""
Guaranteed complete send of a buffer
"""
reqd = len(buf)
while reqd &gt; 0:
nsent = self.sock.send(buf)
if nsent == 0:
raise I2PServerFail("Send to server failed")
buf = buf[nsent:]
reqd -= nsent
</t>
<t tx="davidmcnab.041004144551.38">def _sendline(self, line):
"""
just tacks on a newline and sends
"""
self._sendbytes(line+"\n")
</t>
<t tx="davidmcnab.041004144551.39">class I2PRemoteSession:
"""
DEPRECATED
Wrapper for I2CP connections
Do not instantiate this directly - it gets created by
I2PSamClient.createSession()
"""
@others
</t>
<t tx="davidmcnab.041004144551.40">def __init__(self, client, dest):
"""
Do not instantiate this directly
"""
self.client = client
self.dest = dest
</t>
<t tx="davidmcnab.041004144551.41">def send(self, peerdest, msg):
return self.client.send(self.dest, peerdest, msg)
</t>
<t tx="davidmcnab.041004144551.42">def receive(self):
return self.client.receive(self.dest)
</t>
<t tx="davidmcnab.041004144551.43">def destroy(self):
return self.client.destroySession(self.dest)
</t>
<t tx="davidmcnab.041004144551.44"></t>
<t tx="davidmcnab.041004144551.45">def log(level, msg, nPrev=0):
# ignore messages that are too trivial for chosen verbosity
if level &gt; verbosity:
return
loglock.acquire()
try:
# rip the stack
caller = traceback.extract_stack()[-(2+nPrev)]
path, line, func = caller[:3]
path = os.path.split(path)[1]
full = "%s:%s:%s():\n* %s" % (
path,
line,
func,
msg.replace("\n", "\n + "))
now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
msg = "%s %s\n" % (now, full)
if logfile == sys.stdout:
print msg
else:
file(logfile, "a").write(msg+"\n")
except:
s = StringIO.StringIO()
traceback.print_exc(file=s)
print s.getvalue()
print "Logger crashed"
loglock.release()</t>
<t tx="davidmcnab.041004144551.46">def logException(level, msg=''):
s = StringIO.StringIO()
traceback.print_exc(file=s)
log(level, "%s\n%s" % (s.getvalue(), msg), 1)
</t>
<t tx="davidmcnab.041004144551.47">def demoNAMING():
"""
Demonstrates the NAMING service
"""
print "Starting SAM NAMING demo..."
print
print "Instantiating client connection..."
c0 = I2PSamClient()
print "Client connection created"
for host in ['duck.i2p', 'nonexistent.i2p']:
print "Sending query for host '%s'..." % host
try:
res = c0.samNamingLookup(host)
print "query for %s returned:" % host
print repr(res)
except I2PCommandFail, e:
print "got exception: %s" % repr(e.args)
print
print "---------------------------------"
print "NAMING service tests succeeded"
print "---------------------------------"
print
</t>
<t tx="davidmcnab.041004144551.48">def demoRAW():
"""
Runs a demo of SAM RAW messaging
"""
print "Starting SAM RAW demo..."
print
print "Instantiating client connections..."
c1 = I2PSamClient()
c2 = I2PSamClient()
print "Creating dests via SAM"
pub1, priv1 = c1.samDestGenerate()
pub2, priv2 = c2.samDestGenerate()
print "SAM Dests generated ok"
print "Creating SAM RAW SESSION on connection c1..."
res = c1.samSessionCreate("RAW", priv1)
if res != 'OK':
print "Failed to create session on connection c1: %s" % repr(res)
return
print "Session on connection c1 created successfully"
print "Creating SAM SESSION on connection c2..."
res = c2.samSessionCreate("RAW", priv2)
if res != 'OK':
print "Failed to create session on connection c2: %s" % repr(res)
return
print "Session on connection c2 created successfully"
msg = "Hi there!"
print "sending from c1 to c2: %s" % repr(msg)
c1.samRawSend(pub2, msg)
print "now try to receive from c2 (will block)..."
msg1 = c2.samRawReceive()
print "Connection c2 got %s" % repr(msg1)
print
print "---------------------------------"
print "RAW data transfer tests succeeded"
print "---------------------------------"
print
</t>
<t tx="davidmcnab.041004144551.49">def demoDATAGRAM():
"""
Runs a demo of SAM DATAGRAM messaging
"""
print "Starting SAM DATAGRAM demo..."
print
print "Instantiating 2 more client connections..."
c3 = I2PSamClient()
c4 = I2PSamClient()
print "Creating more dests via SAM"
pub3, priv3 = c3.samDestGenerate()
pub4, priv4 = c4.samDestGenerate()
print "Creating SAM DATAGRAM SESSION on connection c3..."
res = c3.samSessionCreate("DATAGRAM", priv3)
if res != 'OK':
print "Failed to create DATAGRAM session on connection c3: %s" % repr(res)
return
print "DATAGRAM Session on connection c3 created successfully"
print "Creating SAM DATAGRAM SESSION on connection c4..."
res = c4.samSessionCreate("DATAGRAM", priv4)
if res != 'OK':
print "Failed to create DATAGRAM session on connection c4: %s" % repr(res)
return
print "Session on connection c4 created successfully"
msg = "Hi there, this is a datagram!"
print "sending from c3 to c4: %s" % repr(msg)
c3.samDatagramSend(pub4, msg)
print "now try to receive from c4 (will block)..."
remdest, msg1 = c4.samDatagramReceive()
print "Connection c4 got %s from %s..." % (repr(msg1), repr(remdest))
print
print "--------------------------------------"
print "DATAGRAM data transfer tests succeeded"
print "--------------------------------------"
print
</t>
<t tx="davidmcnab.041004144551.50">def demoSTREAM():
"""
Runs a demo of SAM STREAM messaging
"""
print "Starting SAM STREAM demo..."
print
print "Instantiating 2 more client connections..."
c5 = I2PSamClient()
c6 = I2PSamClient()
print "Creating more dests via SAM"
pub5, priv5 = c5.samDestGenerate()
pub6, priv6 = c6.samDestGenerate()
print "Creating SAM STREAM SESSION on connection c3..."
res = c5.samSessionCreate("STREAM", priv5)
if res != 'OK':
print "Failed to create STREAM session on connection c5: %s" % repr(res)
return
print "STREAM Session on connection c5 created successfully"
print "Creating SAM STREAM SESSION on connection c6..."
res = c6.samSessionCreate("STREAM", priv6)
if res != 'OK':
print "Failed to create STREAM session on connection c4: %s" % repr(res)
return
print "STREAM Session on connection c4 created successfully"
msg = "Hi there, this is a datagram!"
print "sending from c5 to c6: %s" % repr(msg)
c5.samStreamSend(pub6, msg)
print "now try to receive from c6 (will block)..."
msg1 = c6.samStreamReceive()
print "Connection c6 got %s from %s..." % (repr(msg1), repr(remdest))
print
print "--------------------------------------"
print "DATAGRAM data transfer tests succeeded"
print "--------------------------------------"
print
</t>
<t tx="davidmcnab.041004144551.51">def demo():
"""
This is a simple and straightforward demo of talking to
the i2psam server socket via the I2PSamClient class.
Read the source, Luke, it's never been so easy...
"""
print
print "-----------------------------------------"
print "Running i2psamclient demo..."
print "-----------------------------------------"
print
demoNAMING()
demoRAW()
demoDATAGRAM()
#demoSTREAM()
print
print "-----------------------------------------"
print "Demo Finished"
print "-----------------------------------------"
return
</t>
<t tx="davidmcnab.041004144551.52">if __name__ == '__main__':
demo()
</t>
</tnodes>
</leo_file>