fix up structure

This commit is contained in:
Jeff Becker
2016-08-17 09:19:56 -04:00
parent b3f8b208cd
commit f1094c0ffe
16 changed files with 244 additions and 89 deletions

View File

@ -0,0 +1,13 @@
package bootstrap
import "github.com/hkparker/go-i2p/lib/common"
// interface defining a way to bootstrap into the i2p network
type Bootstrap interface {
// get more peers for bootstrap
// try obtaining at most n router infos
// if n is 0 then try obtaining as many router infos as possible
// returns nil and error if we cannot fetch ANY router infos
// returns a channel that yields 1 slice of router infos containing n or fewer router infos, caller must close channel after use
GetPeers(n int) (chan []common.RouterInfo, error)
}

4
lib/bootstrap/doc.go Normal file
View File

@ -0,0 +1,4 @@
//
// provides generic interfaces for initial bootstrap into network and network reseeding
//
package bootstrap

View File

@ -7,7 +7,11 @@ import (
b64 "encoding/base64"
)
var I2PEncoding *b64.Encoding = b64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~")
// i2p base64 alphabet
const Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~"
// i2p base64 encoding
var I2PEncoding *b64.Encoding = b64.NewEncoding(Alphabet)
//
// Return a go string of the I2P base64
@ -16,3 +20,11 @@ var I2PEncoding *b64.Encoding = b64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde
func EncodeToString(data []byte) string {
return I2PEncoding.EncodeToString(data)
}
//
// decode string using i2p base64 encoding
// returns error if data is malfromed
//
func DecodeFromString(str string) (d []byte, err error) {
return I2PEncoding.DecodeString(str)
}

View File

@ -1,3 +1,27 @@
package common
import (
"crypto/sha256"
"io"
)
// sha256 hash of some data
type Hash [32]byte
// calculate sha256 of a byte slice
func HashData(data []byte) (h Hash) {
h = sha256.Sum256(data)
return
}
// calulate sha256 of all data being read from an io.Reader
// return error if one occurs while reading from reader
func HashReader(r io.Reader) (h Hash, err error) {
sha := sha256.New()
_, err = io.Copy(sha, r)
if err == nil {
d := sha.Sum(nil)
copy(h[:], d)
}
return
}

View File

@ -89,6 +89,19 @@ func (router_info RouterInfo) RouterIdentity() (router_identity RouterIdentity,
return
}
//
// Calculate this RouterInfo's Identity Hash (the sha256 of the RouterIdentity)
// returns error if the RouterIdentity is malformed
//
func (router_info RouterInfo) IdentHash() (h Hash, err error) {
var ri RouterIdentity
ri, err = router_info.RouterIdentity()
if err == nil {
h = HashData(ri)
}
return
}
//
// Return the Date the RouterInfo was published and any errors encountered parsing the RouterInfo.
//
@ -196,6 +209,7 @@ func (router_info RouterInfo) Options() (mapping Mapping) {
func (router_info RouterInfo) Signature() (signature Signature) {
head := router_info.optionsLocation()
size := head + router_info.optionsSize()
// TODO: signature is not always 40 bytes, is 40 bytes for DSA only
signature = Signature(router_info[size : size+40])
return
}

View File

@ -1,5 +1,23 @@
package config
type BootstrapConfig struct {
LowPeerThreshold int
// configuration for 1 reseed server
type ReseedConfig struct {
// url of reseed server
Url string
// fingerprint of reseed su3 signing key
SU3Fingerprint string
}
type BootstrapConfig struct {
// if we have less than this many peers we should reseed
LowPeerThreshold int
// reseed servers
ReseedServers []*ReseedConfig
}
// default configuration for network bootstrap
var DefaultBootstrapConfig = BootstrapConfig{
LowPeerThreshold: 10,
// TODO: add reseed servers
ReseedServers: []*ReseedConfig{},
}

View File

@ -2,12 +2,14 @@ package config
// router.config options
type RouterConfig struct {
NetDbDir string
Bootstrap BootstrapConfig
// netdb configuration
NetDb *NetDbConfig
// configuration for bootstrapping into the network
Bootstrap *BootstrapConfig
}
// defaults for router
var Router = &RouterConfig{
NetDbDir: "./netDb",
var DefaultRouterConfig = &RouterConfig{
NetDb: &DefaultNetDbConfig,
Bootstrap: &DefaultBootstrapConfig,
}

4
lib/crypto/doc.go Normal file
View File

@ -0,0 +1,4 @@
//
// package for i2p specific crpytography
//
package crypto

View File

@ -1,13 +0,0 @@
package netdb
type Reseed interface {
// do reseed, return nil on success otherwise error
// sends down all Netdb entries down chan
// closes channel when done
Reseed(chnl chan *Entry) error
}
func GetRandomReseed() Reseed {
// TODO: hardcoded value
return HTTPSReseed("https://i2p.rocks:445/")
}

View File

@ -1,16 +1,14 @@
package netdb
import (
"github.com/hkparker/go-i2p/lib/common"
"io"
"path/filepath"
)
// netdb entry
// wraps a router info and provides serialization
type Entry struct {
fname string
}
func (e *Entry) FilePath(n StdNetDB) (str string) {
return filepath.Join(string(n), e.fname)
ri common.RouterInfo
}
func (e *Entry) WriteTo(w io.Writer) (err error) {

32
lib/netdb/kad.go Normal file
View File

@ -0,0 +1,32 @@
package netdb
import (
"github.com/hkparker/go-i2p/lib/common"
"github.com/hkparker/go-i2p/lib/tunnel"
"time"
)
// resolves router infos with recursive kademlia lookup
type kadResolver struct {
// netdb to store result into
netDB NetworkDatabase
// what tunnel pool to use when doing lookup
// if nil the lookup will be done directly
pool *tunnel.Pool
}
// TODO: implement
func (kr *kadResolver) Lookup(h common.Hash, timeout time.Duration) (chnl chan common.RouterInfo) {
return
}
// create a new resolver that stores result into a NetworkDatabase and uses a tunnel pool for the lookup
func KademliaResolver(netDb NetworkDatabase, pool *tunnel.Pool) (r Resolver) {
if pool != nil && netDb != nil {
r = &kadResolver{
netDB: netDb,
pool: pool,
}
}
return
}

View File

@ -1,14 +1,35 @@
package netdb
import (
"github.com/hkparker/go-i2p/lib/bootstrap"
"github.com/hkparker/go-i2p/lib/common"
"time"
)
// resolves unknown RouterInfos given the hash of their RouterIdentity
type Resolver interface {
// resolve a router info by hash
// return a chan that yields the found RouterInfo or nil if it could not be found after timeout
Lookup(hash common.Hash, timeout time.Duration) chan common.RouterInfo
}
// i2p network database, storage of i2p RouterInfos
type NetworkDatabase interface {
// obtain a RouterInfo by its hash
// return a channel that gives 1 RouterInfo or nil if the RouterInfo cannot be found
GetRouterInfo(hash common.Hash) chan *common.RouterInfo
// obtain a RouterInfo by its hash locally
// return a RouterInfo if we found it locally
// return nil if the RouterInfo cannot be found locally
GetRouterInfo(hash common.Hash) common.RouterInfo
// store a router info locally
StoreRouterInfo(ri *common.RouterInfo)
StoreRouterInfo(ri common.RouterInfo)
// try obtaining more peers with a bootstrap instance until we get minRouters number of router infos
// returns error if bootstrap.GetPeers returns an error otherwise returns nil
Reseed(b bootstrap.Bootstrap, minRouters int) error
// return how many router infos we have
Size() int
// ensure underlying resources exist , i.e. directories, files, configs
Ensure() error
}

View File

@ -1,8 +0,0 @@
package netdb
type HTTPSReseed string
func (r HTTPSReseed) Reseed(chnl chan *Entry) (err error) {
close(chnl)
return
}

View File

@ -1,14 +1,41 @@
package netdb
import (
log "github.com/golang/glog"
"bytes"
"fmt"
log "github.com/Sirupsen/logrus"
"github.com/hkparker/go-i2p/lib/bootstrap"
"github.com/hkparker/go-i2p/lib/common"
"github.com/hkparker/go-i2p/lib/common/base64"
"io"
"os"
"path/filepath"
)
// standard network database implementation
// standard network database implementation using local filesystem skiplist
type StdNetDB string
func (db StdNetDB) GetRouterInfo(hash common.Hash) (chnl chan common.RouterInfo) {
fname := db.SkiplistFile(hash)
f, err := os.Open(fname)
if err != nil {
return nil
}
buff := new(bytes.Buffer)
_, err = io.Copy(buff, f)
f.Close()
chnl = make(chan common.RouterInfo)
chnl <- common.RouterInfo(buff.Bytes())
return
}
// get the skiplist file that a RouterInfo with this hash would go in
func (db StdNetDB) SkiplistFile(hash common.Hash) (fpath string) {
fname := base64.EncodeToString(hash[:])
fpath = filepath.Join(db.Path(), fmt.Sprintf("r%s", fname[0]), fmt.Sprintf("routerInfo-%s.dat", fname))
return
}
// get netdb path
func (db StdNetDB) Path() string {
return string(db)
@ -17,26 +44,38 @@ func (db StdNetDB) Path() string {
//
// return how many routers we know about in our network database
//
func (db StdNetDB) KnownPeerCount() (routers int) {
func (db StdNetDB) Size() (routers int) {
return
}
// return true if the network db directory exists and is writable
func (db StdNetDB) Exists() bool {
_, err := os.Stat(db.Path())
return err != nil
p := db.Path()
// check root directory
_, err := os.Stat(p)
if err == nil {
// check subdirectories for skiplist
for _, c := range base64.Alphabet {
if _, err = os.Stat(filepath.Join(p, fmt.Sprintf("r%s", c))); err != nil {
return false
}
}
}
return err == nil
}
func (db StdNetDB) SaveEntry(e *Entry) (err error) {
var f io.WriteCloser
f, err = os.OpenFile(e.FilePath(db), os.O_WRONLY, 0600)
var h common.Hash
h, err = e.ri.IdentHash()
if err == nil {
err = e.WriteTo(f)
if err != nil {
log.Errorf("failed to write netdb entry: %s", err.Error())
f, err = os.OpenFile(db.SkiplistFile(h), os.O_WRONLY|os.O_CREATE, 0700)
if err == nil {
err = e.WriteTo(f)
f.Close()
}
f.Close()
} else {
}
if err != nil {
log.Errorf("failed to save netdb entry: %s", err.Error())
}
return
@ -44,49 +83,34 @@ func (db StdNetDB) SaveEntry(e *Entry) (err error) {
// reseed if we have less than minRouters known routers
// returns error if reseed failed
func (db StdNetDB) Reseed(minRouters int) (err error) {
current := db.KnownPeerCount()
if current <= minRouters {
// we need to reseed
rs := GetRandomReseed()
log.Infof("Reseeding from %s", rs)
chnl := make(chan *Entry)
// receive entries from reseed
go func(c chan *Entry) {
count := 0
for {
e, ok := <-c
if ok {
// got an entry
// save it to our netdb
err := db.SaveEntry(e)
if err == nil {
count++
}
}
}
}(chnl) // call
err = rs.Reseed(chnl)
}
func (db StdNetDB) Reseed(b bootstrap.Bootstrap, minRouters int) (err error) {
return
}
// ensure that the network database exists and is seeded with a minimum number of routers
func (db StdNetDB) Ensure(minRouters int) (err error) {
// ensure that the network database exists
func (db StdNetDB) Ensure() (err error) {
if !db.Exists() {
err = db.Create()
}
if err == nil {
// database directory ensured
// try to reseed
err = db.Reseed(minRouters)
}
return
}
// create base network database directory
func (db StdNetDB) Create() (err error) {
log.Infof("Create network database in %s", db.Path())
err = os.Mkdir(db.Path(), 0600)
mode := os.FileMode(0600)
p := db.Path()
log.Infof("Create network database in %s", p)
// create root for skiplist
err = os.Mkdir(p, mode)
if err == nil {
// create all subdirectories for skiplist
for _, c := range base64.Alphabet {
err = os.Mkdir(filepath.Join(p, fmt.Sprintf("r%s", c)), mode)
if err != nil {
return
}
}
}
return
}

View File

@ -11,19 +11,24 @@ type Router struct {
ndb netdb.StdNetDB
}
// create router with default configuration
func CreateRouter() (r *Router, err error) {
cfg := config.Router
r = &Router{
cfg: cfg,
ndb: netdb.StdNetDB(cfg.NetDbDir),
}
cfg := config.DefaultRouterConfig
r, err = FromConfig(cfg)
return
}
// create router from configuration
func FromConfig(c *config.RouterConfig) (r *Router, err error) {
r = new(Router)
return
}
// run i2p router mainloop
func (r *Router) Run() {
// make sure the netdb is ready
err := r.ndb.Ensure(r.cfg.Bootstrap.LowPeerThreshold)
err := r.ndb.Ensure()
if err == nil {
// netdb ready
}

5
lib/tunnel/pool.go Normal file
View File

@ -0,0 +1,5 @@
package tunnel
// a pool of tunnels which we have created
type Pool struct {
}